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

2612 lines
84 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: dssi.cpp
  8. //
  9. // This file contains the implementation of the CDSSecurityInfo object,
  10. // which provides the ISecurityInformation interface for invoking
  11. // the ACL Editor.
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "pch.h"
  15. #include <dssec.h>
  16. #include "exnc.h"
  17. #include "ntsecapi.h"
  18. TCHAR const c_szDomainClass[] = DOMAIN_CLASS_NAME; // adsnms.h
  19. #define CLASS_COMPUTER L"computer"
  20. BOOL
  21. IsRootObject(IDirectoryObject * pDirObject);
  22. GENERIC_MAPPING g_DSMap =
  23. {
  24. DS_GENERIC_READ,
  25. DS_GENERIC_WRITE,
  26. DS_GENERIC_EXECUTE,
  27. DS_GENERIC_ALL
  28. };
  29. #define DSSI_LOCAL_NO_CREATE_DELETE 0x00000001
  30. //
  31. //Function Declarations
  32. //
  33. HRESULT
  34. GetDomainSid(LPCWSTR pszServer, PSID *ppSid);
  35. HRESULT
  36. GetRootDomainSid(LPCWSTR pszServer, PSID *ppSid);
  37. //
  38. // CDSSecurityInfo (ISecurityInformation) class definition
  39. //
  40. class CDSSecurityInfo : public ISecurityInformation,
  41. IEffectivePermission,
  42. ISecurityObjectTypeInfo,
  43. CUnknown
  44. {
  45. protected:
  46. GUID m_guidObjectType;
  47. BSTR m_strServerName;
  48. BSTR m_strObjectPath;
  49. BSTR m_strObjectClass;
  50. BSTR m_strDisplayName;
  51. BSTR m_strSchemaRootPath;
  52. AUTHZ_RESOURCE_MANAGER_HANDLE m_ResourceManager;
  53. //
  54. //List of Aux Clasess Attached to the object
  55. //
  56. HDPA m_hAuxClasses;
  57. IDirectoryObject *m_pDsObject;
  58. PSECURITY_DESCRIPTOR m_pSD;
  59. PSID m_pDomainSid;
  60. PSID m_pRootDomainSid;
  61. PSECURITY_DESCRIPTOR m_pDefaultSD;
  62. DWORD m_dwSIFlags;
  63. DWORD m_dwInitFlags; // DSSI_*
  64. DWORD m_dwLocalFlags; //DSSI_LOCAL_*
  65. HANDLE m_hInitThread;
  66. HANDLE m_hLoadLibWaitEvent;
  67. volatile BOOL m_bThreadAbort;
  68. PFNREADOBJECTSECURITY m_pfnReadSD;
  69. PFNWRITEOBJECTSECURITY m_pfnWriteSD;
  70. LPARAM m_lpReadContext;
  71. LPARAM m_lpWriteContext;
  72. //
  73. //Access Information
  74. //
  75. PACCESS_INFO m_pAIGeneral; //For First Page and Object Page on Advanced
  76. PACCESS_INFO m_pAIProperty; //For Property Page on Advanced
  77. PACCESS_INFO m_pAIEffective; //For Effective Page on Advanced
  78. //
  79. //Object Type List Info
  80. //
  81. POBJECT_TYPE_LIST m_pOTL;
  82. ULONG m_cCountOTL;
  83. public:
  84. virtual ~CDSSecurityInfo();
  85. STDMETHODIMP Init(LPCWSTR pszObjectPath,
  86. LPCWSTR pszObjectClass,
  87. LPCWSTR pszServer,
  88. LPCWSTR pszUserName,
  89. LPCWSTR pszPassword,
  90. DWORD dwFlags,
  91. PFNREADOBJECTSECURITY pfnReadSD,
  92. PFNWRITEOBJECTSECURITY pfnWriteSD,
  93. LPARAM lpContext);
  94. // IUnknown
  95. STDMETHODIMP QueryInterface(REFIID, LPVOID *);
  96. STDMETHODIMP_(ULONG) AddRef();
  97. STDMETHODIMP_(ULONG) Release();
  98. // ISecurityInformation
  99. STDMETHODIMP GetObjectInformation(PSI_OBJECT_INFO pObjectInfo);
  100. STDMETHODIMP GetSecurity(SECURITY_INFORMATION si,
  101. PSECURITY_DESCRIPTOR *ppSD,
  102. BOOL fDefault);
  103. STDMETHODIMP SetSecurity(SECURITY_INFORMATION si,
  104. PSECURITY_DESCRIPTOR pSD);
  105. STDMETHODIMP GetAccessRights(const GUID* pguidObjectType,
  106. DWORD dwFlags,
  107. PSI_ACCESS *ppAccess,
  108. ULONG *pcAccesses,
  109. ULONG *piDefaultAccess);
  110. STDMETHODIMP MapGeneric(const GUID *pguidObjectType,
  111. UCHAR *pAceFlags,
  112. ACCESS_MASK *pmask);
  113. STDMETHODIMP GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  114. ULONG *pcInheritTypes);
  115. STDMETHODIMP PropertySheetPageCallback(HWND hwnd,
  116. UINT uMsg,
  117. SI_PAGE_TYPE uPage);
  118. //IEffectivePermission
  119. STDMETHODIMP GetEffectivePermission(const GUID* pguidObjectType,
  120. PSID pUserSid,
  121. LPCWSTR pszServerName,
  122. PSECURITY_DESCRIPTOR pSD,
  123. POBJECT_TYPE_LIST *ppObjectTypeList,
  124. ULONG *pcObjectTypeListLength,
  125. PACCESS_MASK *ppGrantedAccessList,
  126. ULONG *pcGrantedAccessListLength);
  127. //ISecurityObjectTypeInfo
  128. STDMETHOD(GetInheritSource)(SECURITY_INFORMATION si,
  129. PACL pACL,
  130. PINHERITED_FROM *ppInheritArray);
  131. private:
  132. HRESULT Init2(LPCWSTR pszUserName, LPCWSTR pszPassword);
  133. HRESULT Init3();
  134. HRESULT GetAuxClassList();
  135. DWORD CheckObjectAccess();
  136. void WaitOnInitThread(void)
  137. { WaitOnThread(&m_hInitThread); }
  138. static DWORD WINAPI InitThread(LPVOID pvThreadData);
  139. static HRESULT WINAPI DSReadObjectSecurity(LPCWSTR pszObjectPath,
  140. SECURITY_INFORMATION si,
  141. PSECURITY_DESCRIPTOR *ppSD,
  142. LPARAM lpContext);
  143. static HRESULT WINAPI DSWriteObjectSecurity(LPCWSTR pszObjectPath,
  144. SECURITY_INFORMATION si,
  145. PSECURITY_DESCRIPTOR pSD,
  146. LPARAM lpContext);
  147. };
  148. //
  149. // CDSSecurityInfo (ISecurityInformation) implementation
  150. //
  151. CDSSecurityInfo::~CDSSecurityInfo()
  152. {
  153. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::~CDSSecurityInfo");
  154. m_bThreadAbort = TRUE;
  155. if (m_hInitThread != NULL)
  156. {
  157. WaitForSingleObject(m_hInitThread, INFINITE);
  158. CloseHandle(m_hInitThread);
  159. }
  160. DoRelease(m_pDsObject);
  161. SysFreeString(m_strServerName);
  162. SysFreeString(m_strObjectPath);
  163. SysFreeString(m_strObjectClass);
  164. SysFreeString(m_strDisplayName);
  165. SysFreeString(m_strSchemaRootPath);
  166. if (m_pSD != NULL)
  167. LocalFree(m_pSD);
  168. if( m_pDefaultSD != NULL )
  169. LocalFree(m_pDefaultSD);
  170. if(m_pDomainSid)
  171. LocalFree(m_pDomainSid);
  172. if(m_pRootDomainSid)
  173. LocalFree(m_pRootDomainSid);
  174. DestroyDPA(m_hAuxClasses);
  175. if(m_pAIGeneral && m_pAIGeneral->bLocalFree)
  176. {
  177. LocalFree(m_pAIGeneral->pAccess);
  178. LocalFree(m_pAIGeneral);
  179. }
  180. if(m_pAIProperty && m_pAIProperty->bLocalFree)
  181. {
  182. LocalFree(m_pAIProperty->pAccess);
  183. LocalFree(m_pAIProperty);
  184. }
  185. if(m_pAIEffective && m_pAIEffective->bLocalFree)
  186. {
  187. LocalFree(m_pAIEffective->pAccess);
  188. LocalFree(m_pAIEffective);
  189. }
  190. if(m_pOTL)
  191. LocalFree(m_pOTL);
  192. if(m_ResourceManager)
  193. AuthzFreeResourceManager(m_ResourceManager);
  194. TraceLeaveVoid();
  195. }
  196. //+--------------------------------------------------------------------------
  197. //
  198. // Function: DeleteParents
  199. //
  200. // Synopsis: Delete the parent of pszClassName from the list.
  201. // And recursively calls the function to delete the
  202. // parent of parent of pszClassName from the list.
  203. // History: 06-22-2000 DavidMun Created
  204. //
  205. //---------------------------------------------------------------------------
  206. HRESULT DeleteParents(HDPA hListAux,
  207. LPWSTR pszClassName,
  208. LPWSTR pszSchemaRootPath)
  209. {
  210. TraceEnter(TRACE_DSSI, "DeleteParents");
  211. if(!hListAux || !pszSchemaRootPath)
  212. return E_INVALIDARG;
  213. HRESULT hr = S_OK;
  214. IADsClass *pDsClass = NULL;
  215. VARIANT varDerivedFrom;
  216. int cCount = DPA_GetPtrCount(hListAux);
  217. if(cCount > 1)
  218. {
  219. hr = Schema_BindToObject(pszSchemaRootPath,
  220. pszClassName,
  221. IID_IADsClass,
  222. (LPVOID*)&pDsClass);
  223. FailGracefully(hr, "Schema_BindToObject failed");
  224. //
  225. //Find out the parent
  226. //
  227. hr = pDsClass->get_DerivedFrom(&varDerivedFrom);
  228. if(hr == E_ADS_PROPERTY_NOT_FOUND)
  229. {
  230. //
  231. //This error will come for TOP which doesn't
  232. //have any parent
  233. //
  234. hr = S_OK;
  235. goto exit_gracefully;
  236. }
  237. FailGracefully(hr, "IADsClass get_DerivedFrom failed");
  238. LPWSTR pszParent= NULL;
  239. LPWSTR pszTemp = NULL;
  240. if( V_VT(&varDerivedFrom) == VT_BSTR)
  241. {
  242. pszParent = V_BSTR(&varDerivedFrom);
  243. int i;
  244. //
  245. //Remove all the pszParent entry from the
  246. //hListAux
  247. //
  248. for(i = 0; i < cCount; ++i)
  249. {
  250. pszTemp = (LPWSTR)DPA_FastGetPtr(hListAux,i);
  251. if(wcscmp(pszTemp, pszParent) == 0)
  252. {
  253. DPA_DeletePtr(hListAux,i);
  254. --cCount;
  255. --i;
  256. }
  257. }
  258. }
  259. VariantClear(&varDerivedFrom);
  260. }
  261. exit_gracefully:
  262. if(pDsClass)
  263. DoRelease(pDsClass);
  264. return hr;
  265. }
  266. HRESULT
  267. CDSSecurityInfo::GetAuxClassList()
  268. {
  269. TraceEnter(TRACE_DSSI, "GetAuxClassList");
  270. if(!m_pDsObject || !m_strSchemaRootPath)
  271. {
  272. return S_FALSE;
  273. }
  274. HRESULT hr = S_OK;
  275. PADS_ATTR_INFO pAtrrInfoObject = NULL;
  276. DWORD dwAttrCountObject = 0;
  277. PADS_ATTR_INFO pAttrInfoStruct = NULL;
  278. DWORD dwAttrCountStruct= 0;
  279. HDPA hListAux = NULL;
  280. HDPA hListCopy = NULL;
  281. //ObjectClass is list of "class hierarchy of StructuralClass" and "class hierarchy of AuxClass"
  282. //for the object.
  283. //So ObjectClass MINUS StructurcalClass is the list of AuxClass.
  284. //This list after subtraction may conatin the inheritance hierarchy.
  285. //We only want the mostsignificant classes for the purpose of aclui.
  286. //
  287. //Get the ObjectClass Attribute
  288. //
  289. LPWSTR pszTemp = (LPWSTR)c_szObjectClass;
  290. hr = m_pDsObject->GetObjectAttributes(&pszTemp,
  291. 1,
  292. &pAtrrInfoObject,
  293. &dwAttrCountObject);
  294. FailGracefully(hr, "Failed to get ObjectClass Attribute");
  295. if(!pAtrrInfoObject || !dwAttrCountObject)
  296. ExitGracefully(hr, S_OK, "Couldn't get ObjectClass, Assume no AuxClass");
  297. //
  298. //Get the StructuralObjectClass Attribute
  299. //
  300. pszTemp = (LPWSTR)c_szStructuralObjectClass;
  301. hr = m_pDsObject->GetObjectAttributes(&pszTemp,
  302. 1,
  303. &pAttrInfoStruct,
  304. &dwAttrCountStruct);
  305. FailGracefully(hr, "Failed to get StructuralObjectClass Attribute");
  306. if(!pAttrInfoStruct || !dwAttrCountStruct)
  307. ExitGracefully(hr, S_OK, "Couldn't get Structural Object Class Attribute, Assume no Aux Class");
  308. if(pAtrrInfoObject->dwNumValues == pAttrInfoStruct->dwNumValues)
  309. {
  310. Trace((L"No Auxillary Class Attached to this object\n"));
  311. goto exit_gracefully;
  312. }
  313. hListAux = DPA_Create(4);
  314. UINT i,j;
  315. BOOL bAuxClass;
  316. for(i = 0; i < pAtrrInfoObject->dwNumValues; ++i)
  317. {
  318. bAuxClass = TRUE;
  319. for(j = 0; j < pAttrInfoStruct->dwNumValues; ++j)
  320. {
  321. if( wcscmp(pAtrrInfoObject->pADsValues[i].CaseIgnoreString,
  322. pAttrInfoStruct->pADsValues[j].CaseExactString) == 0 )
  323. {
  324. bAuxClass = FALSE;
  325. break;
  326. }
  327. }
  328. if(bAuxClass)
  329. {
  330. DPA_AppendPtr(hListAux,pAtrrInfoObject->pADsValues[i].CaseExactString);
  331. }
  332. }
  333. UINT cCount;
  334. cCount = DPA_GetPtrCount(hListAux);
  335. if(cCount)
  336. {
  337. if(cCount > 1)
  338. {
  339. //
  340. //Make a copy of hListAux
  341. //
  342. HDPA hListCopy2 = DPA_Create(cCount);
  343. for(i = 0; i < cCount; ++i)
  344. DPA_AppendPtr(hListCopy2,DPA_FastGetPtr(hListAux, i));
  345. //
  346. //For each item in hListCopy2 remove its parent from
  347. //hListAux
  348. //
  349. for(i = 0; i < cCount; ++i)
  350. {
  351. hr = DeleteParents(hListAux,
  352. (LPWSTR)DPA_FastGetPtr(hListCopy2, i),
  353. m_strSchemaRootPath);
  354. FailGracefully(hr, "DeleteParents Failed");
  355. //
  356. //if only one item is left we are done.
  357. //
  358. if( 1 == DPA_GetPtrCount(hListAux))
  359. break;
  360. }
  361. }
  362. //
  363. // What we have left is list of mostsignificant AuxClass[es]
  364. //
  365. LPWSTR pszItem;
  366. cCount = DPA_GetPtrCount(hListAux);
  367. TraceAssert(cCount);
  368. if(!m_hAuxClasses)
  369. {
  370. m_hAuxClasses = DPA_Create(cCount);
  371. }
  372. //
  373. //Copy AuxClasses into class member
  374. //
  375. while(cCount)
  376. {
  377. pszItem = (LPWSTR)DPA_FastGetPtr(hListAux,--cCount);
  378. PAUX_INFO pAI = (PAUX_INFO)LocalAlloc(LPTR,sizeof(AUX_INFO) + StringByteSize(pszItem));
  379. if(!pAI)
  380. ExitGracefully(hr, E_OUTOFMEMORY, "Out of memory");
  381. wcscpy(pAI->pszClassName,pszItem);
  382. pAI->guid = GUID_NULL;
  383. DPA_AppendPtr(m_hAuxClasses, pAI);
  384. }
  385. }
  386. exit_gracefully:
  387. if(hListAux)
  388. DPA_Destroy(hListAux);
  389. if(hListCopy)
  390. DPA_Destroy(hListCopy);
  391. if(pAttrInfoStruct)
  392. FreeADsMem(pAttrInfoStruct);
  393. if(pAtrrInfoObject)
  394. FreeADsMem(pAtrrInfoObject);
  395. return S_OK;
  396. }
  397. STDMETHODIMP
  398. CDSSecurityInfo::Init(LPCWSTR pszObjectPath,
  399. LPCWSTR pszObjectClass,
  400. LPCWSTR pszServer,
  401. LPCWSTR pszUserName,
  402. LPCWSTR pszPassword,
  403. DWORD dwFlags,
  404. PFNREADOBJECTSECURITY pfnReadSD,
  405. PFNWRITEOBJECTSECURITY pfnWriteSD,
  406. LPARAM lpContext)
  407. {
  408. HRESULT hr = S_OK;
  409. DWORD dwThreadID;
  410. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::Init");
  411. TraceAssert(pszObjectPath != NULL);
  412. TraceAssert(m_strObjectPath == NULL); // only initialize once
  413. m_dwInitFlags = dwFlags;
  414. m_ResourceManager = NULL;
  415. m_pfnReadSD = DSReadObjectSecurity;
  416. m_pfnWriteSD = DSWriteObjectSecurity;
  417. m_lpReadContext = (LPARAM)this;
  418. m_lpWriteContext = (LPARAM)this;
  419. m_hLoadLibWaitEvent = NULL;
  420. m_hAuxClasses = NULL;
  421. m_pAIGeneral = NULL; //For First Page and Object Page on Advanced
  422. m_pAIProperty = NULL; //For Property Page on Advanced
  423. m_pAIEffective = NULL; //For Effective Page on Advanced
  424. m_pOTL = NULL;
  425. m_cCountOTL = 0;
  426. m_pDomainSid = NULL;
  427. m_pRootDomainSid = NULL;
  428. if (pfnReadSD)
  429. {
  430. m_pfnReadSD = pfnReadSD;
  431. m_lpReadContext = lpContext;
  432. }
  433. if (pfnWriteSD)
  434. {
  435. m_pfnWriteSD = pfnWriteSD;
  436. m_lpWriteContext = lpContext;
  437. }
  438. m_pDefaultSD = NULL;
  439. m_pSD = NULL;
  440. m_strObjectPath = SysAllocString(pszObjectPath);
  441. if (m_strObjectPath == NULL)
  442. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to copy the object path");
  443. if (pszObjectClass && *pszObjectClass)
  444. m_strObjectClass = SysAllocString(pszObjectClass);
  445. if (pszServer)
  446. {
  447. // Skip any preceding backslashes
  448. while (L'\\' == *pszServer)
  449. pszServer++;
  450. if (*pszServer)
  451. m_strServerName = SysAllocString(pszServer);
  452. }
  453. // Init2 cracks the path, binds to the object, checks access to
  454. // the object and gets the schema path. This used to be done on
  455. // the other thread below, but is faster now than it used to be.
  456. //
  457. // It's preferable to do it here where we can fail and prevent the
  458. // page from being created if, for example, the user has no access
  459. // to the object's security descriptor. This is better than always
  460. // creating the Security page and having it show a message
  461. // when initialization fails.
  462. hr = Init2(pszUserName, pszPassword);
  463. if (SUCCEEDED(hr))
  464. {
  465. //
  466. //Get the domain sid
  467. //
  468. GetDomainSid(m_strServerName, &m_pDomainSid);
  469. GetRootDomainSid(m_strServerName,&m_pRootDomainSid);
  470. if( !m_strObjectClass || !m_strSchemaRootPath )
  471. {
  472. // We evidently don't have read_property access to the object,
  473. // so just assume it's not a container, so we don't have to deal
  474. // with inherit types.
  475. //
  476. // We need to struggle on as best as we can. If someone removes
  477. // all access to an object, this is the only way an admin can
  478. // restore it.
  479. //
  480. m_guidObjectType = GUID_NULL;
  481. //don't show effective permission tab
  482. m_dwSIFlags &= (~SI_EDIT_EFFECTIVE);
  483. }
  484. else
  485. {
  486. //
  487. //Get the list of Dynamic Auxillary Classes attached to this Object.
  488. //
  489. hr = GetAuxClassList();
  490. }
  491. //Create event to make sure load library is called by InitThread before
  492. //function returns
  493. m_hLoadLibWaitEvent = CreateEvent( NULL,
  494. TRUE,
  495. FALSE,
  496. NULL );
  497. if( m_hLoadLibWaitEvent != NULL )
  498. {
  499. m_hInitThread = CreateThread(NULL,
  500. 0,
  501. InitThread,
  502. this,
  503. 0,
  504. &dwThreadID);
  505. WaitForSingleObject( m_hLoadLibWaitEvent, INFINITE );
  506. }
  507. }
  508. exit_gracefully:
  509. if( m_hLoadLibWaitEvent )
  510. CloseHandle( m_hLoadLibWaitEvent );
  511. TraceLeaveResult(hr);
  512. }
  513. char const c_szDsGetDcNameProc[] = "DsGetDcNameW";
  514. char const c_szNetApiBufferFreeProc[] = "NetApiBufferFree";
  515. typedef DWORD (WINAPI *PFN_DSGETDCNAME)(LPCWSTR, LPCWSTR, GUID*, LPCWSTR, ULONG, PDOMAIN_CONTROLLER_INFOW*);
  516. typedef DWORD (WINAPI *PFN_NETAPIFREE)(LPVOID);
  517. HRESULT
  518. GetDsDcAddress(BSTR *pbstrDcAddress)
  519. {
  520. HRESULT hr = E_FAIL;
  521. HMODULE hNetApi32 = LoadLibrary(c_szNetApi32);
  522. if (hNetApi32)
  523. {
  524. PFN_DSGETDCNAME pfnDsGetDcName = (PFN_DSGETDCNAME)GetProcAddress(hNetApi32, c_szDsGetDcNameProc);
  525. PFN_NETAPIFREE pfnNetApiFree = (PFN_NETAPIFREE)GetProcAddress(hNetApi32, c_szNetApiBufferFreeProc);
  526. if (pfnDsGetDcName && pfnNetApiFree)
  527. {
  528. PDOMAIN_CONTROLLER_INFOW pDCI;
  529. DWORD dwErr = (*pfnDsGetDcName)(NULL, NULL, NULL, NULL,
  530. DS_DIRECTORY_SERVICE_REQUIRED | DS_IP_REQUIRED,
  531. &pDCI);
  532. hr = HRESULT_FROM_WIN32(dwErr);
  533. if (SUCCEEDED(hr))
  534. {
  535. LPCWSTR pszAddress = pDCI->DomainControllerAddress;
  536. // Skip any preceding backslashes
  537. while (L'\\' == *pszAddress)
  538. pszAddress++;
  539. *pbstrDcAddress = SysAllocString(pszAddress);
  540. if (NULL == *pbstrDcAddress)
  541. hr = E_OUTOFMEMORY;
  542. (*pfnNetApiFree)(pDCI);
  543. }
  544. }
  545. FreeLibrary(hNetApi32);
  546. }
  547. return hr;
  548. }
  549. HRESULT
  550. CDSSecurityInfo::Init2(LPCWSTR pszUserName, LPCWSTR pszPassword)
  551. {
  552. HRESULT hr = S_OK;
  553. DWORD dwAccessGranted;
  554. PADS_OBJECT_INFO pObjectInfo = NULL;
  555. IADsPathname *pPath = NULL;
  556. LPWSTR pszTemp;
  557. DWORD dwPrivs[] = { SE_SECURITY_PRIVILEGE, SE_TAKE_OWNERSHIP_PRIVILEGE };
  558. HANDLE hToken = INVALID_HANDLE_VALUE;
  559. PADS_ATTR_INFO pAttributeInfo = NULL;
  560. DWORD dwAttributesReturned;
  561. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::Init2");
  562. TraceAssert(m_strObjectPath != NULL);
  563. TraceAssert(m_pDsObject == NULL); // only do this one time
  564. //
  565. // Create an ADsPathname object to parse the path and get the
  566. // leaf name (for display) and server name (if necessary)
  567. //
  568. hr = CoCreateInstance(CLSID_Pathname,
  569. NULL,
  570. CLSCTX_INPROC_SERVER,
  571. IID_IADsPathname,
  572. (LPVOID*)&pPath);
  573. if (pPath)
  574. {
  575. if (FAILED(pPath->Set(m_strObjectPath, ADS_SETTYPE_FULL)))
  576. DoRelease(pPath); // sets pPath to NULL
  577. }
  578. if (NULL == m_strServerName)
  579. {
  580. // The path may or may not specify a server. If not, call DsGetDcName
  581. if (pPath)
  582. hr = pPath->Retrieve(ADS_FORMAT_SERVER, &m_strServerName);
  583. if (!pPath || FAILED(hr))
  584. hr = GetDsDcAddress(&m_strServerName);
  585. FailGracefully(hr, "Unable to get server name");
  586. }
  587. Trace((TEXT("Server \"%s\""), m_strServerName));
  588. // Enable privileges before binding so CheckObjectAccess
  589. // and DSRead/WriteObjectSecurity work correctly.
  590. hToken = EnablePrivileges(dwPrivs, ARRAYSIZE(dwPrivs));
  591. // Bind to the object and get the schema path, etc.
  592. Trace((TEXT("Calling OpenDSObject(%s)"), m_strObjectPath));
  593. hr = OpenDSObject(m_strObjectPath,
  594. (LPWSTR)pszUserName,
  595. (LPWSTR)pszPassword,
  596. ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND,
  597. IID_IDirectoryObject,
  598. (LPVOID*)&m_pDsObject);
  599. FailGracefully(hr, "Failed to get the DS object");
  600. // Assume certain access by default
  601. if (m_dwInitFlags & DSSI_READ_ONLY)
  602. dwAccessGranted = READ_CONTROL;
  603. else
  604. dwAccessGranted = READ_CONTROL | WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY;
  605. if (!(m_dwInitFlags & DSSI_NO_ACCESS_CHECK))
  606. {
  607. // Check whether the user has permission to do anything to
  608. // the security descriptor on this object.
  609. dwAccessGranted = CheckObjectAccess();
  610. Trace((TEXT("AccessGranted = 0x%08x"), dwAccessGranted));
  611. if (!(dwAccessGranted & (READ_CONTROL | WRITE_DAC | WRITE_OWNER | ACCESS_SYSTEM_SECURITY | SI_MAY_WRITE)))
  612. ExitGracefully(hr, E_ACCESSDENIED, "No access");
  613. }
  614. // Translate the access into SI_* flags, starting with this:
  615. m_dwSIFlags = SI_EDIT_ALL | SI_ADVANCED | SI_EDIT_PROPERTIES | SI_SERVER_IS_DC |SI_EDIT_EFFECTIVE;
  616. if (!(dwAccessGranted & WRITE_DAC))
  617. {
  618. if( !(dwAccessGranted & SI_MAY_WRITE) )
  619. m_dwSIFlags |= SI_READONLY;
  620. else
  621. m_dwSIFlags |= SI_MAY_WRITE;
  622. }
  623. if (!(dwAccessGranted & WRITE_OWNER))
  624. {
  625. if (!(dwAccessGranted & READ_CONTROL))
  626. m_dwSIFlags &= ~SI_EDIT_OWNER;
  627. else
  628. m_dwSIFlags |= SI_OWNER_READONLY;
  629. }
  630. if (!(dwAccessGranted & ACCESS_SYSTEM_SECURITY) || (m_dwInitFlags & DSSI_NO_EDIT_SACL))
  631. m_dwSIFlags &= ~SI_EDIT_AUDITS;
  632. if (m_dwInitFlags & DSSI_NO_EDIT_OWNER)
  633. m_dwSIFlags &= ~SI_EDIT_OWNER;
  634. // If this is a root object (ex. domain), hide the ACL protect checkbox
  635. if ((m_dwInitFlags & DSSI_IS_ROOT) || IsRootObject(m_pDsObject))
  636. {
  637. m_dwSIFlags |= SI_NO_ACL_PROTECT;
  638. }
  639. // Get the class name and schema path
  640. m_pDsObject->GetObjectInformation(&pObjectInfo);
  641. if (pObjectInfo)
  642. {
  643. //
  644. // Note that m_strObjectClass, if provided, can be different
  645. // than pObjectInfo->pszClassName. This is true when editing default
  646. // ACLs on schema class objects, for example, in which case
  647. // pObjectInfo->pszClassName will be "attributeSchema" but m_strObjectClass
  648. // will be something else such as "computer" or "user". Be
  649. // careful to only use pObjectInfo->pszClassName for getting the path of
  650. // the schema root, and use m_strObjectClass for everything else.
  651. //
  652. // If m_strObjectClass is not provided, use pObjectInfo->pszClassName.
  653. //
  654. if (m_strObjectClass == NULL)
  655. m_strObjectClass = SysAllocString(pObjectInfo->pszClassName);
  656. // Get the the path of the schema root
  657. int nClassLen;
  658. nClassLen = lstrlenW(pObjectInfo->pszClassName);
  659. pszTemp = pObjectInfo->pszSchemaDN + lstrlenW(pObjectInfo->pszSchemaDN) - nClassLen;
  660. if (CSTR_EQUAL == CompareString(LOCALE_SYSTEM_DEFAULT,
  661. NORM_IGNORECASE,
  662. pszTemp,
  663. nClassLen,
  664. pObjectInfo->pszClassName,
  665. nClassLen))
  666. {
  667. *pszTemp = L'\0';
  668. }
  669. // Save the schema root path
  670. m_strSchemaRootPath = SysAllocString(pObjectInfo->pszSchemaDN);
  671. }
  672. //For computer objects only use CN as display name doesn't get updated
  673. //when name of computer is changed which results in displaying old name.
  674. //see bug 104186
  675. if(!m_strObjectClass || lstrcmpi(m_strObjectClass,CLASS_COMPUTER))
  676. {
  677. //
  678. // Get the displayName property
  679. //
  680. pszTemp = (LPWSTR)c_szDisplayName;
  681. HRESULT hr1 = m_pDsObject->GetObjectAttributes(&pszTemp,
  682. 1,
  683. &pAttributeInfo,
  684. &dwAttributesReturned);
  685. //NTRAID#NTBUG9-68903-2002/08/07-hiteshr
  686. //Under certain conditions where underlying AD is host, and ADSI fails to
  687. //to get any schema information from AD, this can fail or return information
  688. //in provider specific format.
  689. if (SUCCEEDED(hr1) &&
  690. pAttributeInfo &&
  691. pAttributeInfo->pADsValues->dwType == ADSTYPE_CASE_EXACT_STRING )
  692. {
  693. m_strDisplayName = SysAllocString(pAttributeInfo->pADsValues->CaseExactString);
  694. FreeADsMem(pAttributeInfo);
  695. pAttributeInfo = NULL;
  696. }
  697. }
  698. // If that failed, try the leaf name.
  699. if (!m_strDisplayName && pPath)
  700. {
  701. // Retrieve the display name
  702. pPath->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  703. pPath->Retrieve(ADS_FORMAT_LEAF, &m_strDisplayName);
  704. pPath->SetDisplayType(ADS_DISPLAY_FULL);
  705. }
  706. // If we still don't have a display name, just copy the RDN.
  707. // Ugly, but better than nothing.
  708. if (!m_strDisplayName && pObjectInfo)
  709. m_strDisplayName = SysAllocString(pObjectInfo->pszRDN);
  710. exit_gracefully:
  711. if (pObjectInfo)
  712. FreeADsMem(pObjectInfo);
  713. DoRelease(pPath);
  714. ReleasePrivileges(hToken);
  715. TraceLeaveResult(hr);
  716. }
  717. HRESULT
  718. CDSSecurityInfo::Init3()
  719. {
  720. HRESULT hr = S_OK;
  721. IADsClass *pDsClass = NULL;
  722. VARIANT var = {0};
  723. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::Init3");
  724. TraceAssert(m_strSchemaRootPath != NULL);
  725. TraceAssert(m_strObjectClass != NULL);
  726. if (m_bThreadAbort)
  727. goto exit_gracefully;
  728. // Create the schema cache
  729. // Sandwich this SchemaCache_Create call with refcounting. In the event that
  730. // the threads created therein take a long time to return, this allows the
  731. // release on the CDSSecurityInfo object in the invoking application to simply
  732. // return instead of waiting potentially a very long time for the schema cache
  733. // creation threads to complete. This is because the last release on the
  734. // CDSSecurityInfo calls its destructor (duh!) and the destructor waits on the
  735. // threads.
  736. AddRef ();
  737. hr = SchemaCache_Create(m_strServerName);
  738. Release();
  739. FailGracefully(hr, "Unable to create schema cache");
  740. if( m_strSchemaRootPath && m_strObjectClass )
  741. {
  742. // Bind to the schema class object
  743. hr = Schema_BindToObject(m_strSchemaRootPath,
  744. m_strObjectClass,
  745. IID_IADsClass,
  746. (LPVOID*)&pDsClass);
  747. FailGracefully(hr, "Failed to get the Schema class object");
  748. // Get the class GUID
  749. Schema_GetObjectID(pDsClass, &m_guidObjectType);
  750. if (m_bThreadAbort)
  751. goto exit_gracefully;
  752. // See if this object is a container, by getting the list of possible
  753. // child classes. If this fails, treat it as a non-container.
  754. pDsClass->get_Containment(&var);
  755. //set m_dwLocalFlags to DSSI_LOCAL_NO_CREATE_DELETE if object is not
  756. // a container. If this flag is set, CREATE_DELETE permission which are
  757. // inherited from parents but meaning less for leaf object will not be shown.
  758. // In most cases presence of this flag is same as absence of SI_CONTAINER in m_dwSIFlags,
  759. // however in some cases its not possible to determine if the object is container or not.
  760. // there object is treated as non-container but we still must show all the aces.
  761. if (V_VT(&var) == (VT_ARRAY | VT_VARIANT))
  762. {
  763. LPSAFEARRAY psa = V_ARRAY(&var);
  764. TraceAssert(psa && psa->cDims == 1);
  765. if (psa->rgsabound[0].cElements > 0)
  766. {
  767. m_dwSIFlags |= SI_CONTAINER;
  768. }
  769. else
  770. m_dwLocalFlags |= DSSI_LOCAL_NO_CREATE_DELETE;
  771. }
  772. else if (V_VT(&var) == VT_BSTR) // single entry
  773. {
  774. TraceAssert(V_BSTR(&var));
  775. m_dwSIFlags |= SI_CONTAINER;
  776. }
  777. else
  778. m_dwLocalFlags |= DSSI_LOCAL_NO_CREATE_DELETE;
  779. if( !IsEqualGUID( m_guidObjectType, GUID_NULL ) )
  780. {
  781. hr = Schema_GetDefaultSD( &m_guidObjectType, m_pDomainSid, m_pRootDomainSid, &m_pDefaultSD );
  782. FailGracefully(hr, "Failed to get the Schema class object");
  783. m_dwSIFlags |= SI_RESET_DACL;
  784. }
  785. }
  786. exit_gracefully:
  787. VariantClear(&var);
  788. DoRelease(pDsClass);
  789. TraceLeaveResult(hr);
  790. }
  791. ///////////////////////////////////////////////////////////
  792. //
  793. // IUnknown methods
  794. //
  795. ///////////////////////////////////////////////////////////
  796. #undef CLASS_NAME
  797. #define CLASS_NAME CDSSecurityInfo
  798. #include "unknown.inc"
  799. STDMETHODIMP
  800. CDSSecurityInfo::QueryInterface(REFIID riid, LPVOID FAR* ppv)
  801. {
  802. INTERFACES iface[] =
  803. {
  804. &IID_ISecurityInformation, static_cast<LPSECURITYINFO>(this),
  805. &IID_IEffectivePermission, static_cast<LPEFFECTIVEPERMISSION>(this),
  806. &IID_ISecurityObjectTypeInfo, static_cast<LPSecurityObjectTypeInfo>(this),
  807. };
  808. return HandleQueryInterface(riid, ppv, iface, ARRAYSIZE(iface));
  809. }
  810. ///////////////////////////////////////////////////////////
  811. //
  812. // ISecurityInformation methods
  813. //
  814. ///////////////////////////////////////////////////////////
  815. STDMETHODIMP
  816. CDSSecurityInfo::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
  817. {
  818. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::GetObjectInformation");
  819. TraceAssert(pObjectInfo != NULL &&
  820. !IsBadWritePtr(pObjectInfo, SIZEOF(*pObjectInfo)));
  821. pObjectInfo->hInstance = GLOBAL_HINSTANCE;
  822. pObjectInfo->dwFlags = m_dwSIFlags ;
  823. pObjectInfo->pszServerName = m_strServerName;
  824. pObjectInfo->pszObjectName = m_strDisplayName ? m_strDisplayName : m_strObjectPath;
  825. if (!IsEqualGUID(m_guidObjectType, GUID_NULL))
  826. {
  827. pObjectInfo->dwFlags |= SI_OBJECT_GUID;
  828. pObjectInfo->guidObjectType = m_guidObjectType;
  829. }
  830. TraceLeaveResult(S_OK);
  831. }
  832. //IF object is leaf object which cannot have create/detele object
  833. //permissions, this function removes those aces from SD, so that
  834. //they are not displayed. It only removes inherited aces, if ace is
  835. //explicit, it better get displayed so that user can remove it.
  836. //This is done to fix bug 14793
  837. DWORD
  838. RemoveRedundantPermissions( PSECURITY_DESCRIPTOR *ppSD, GUID *pGuidObjectType )
  839. {
  840. PACL pAcl = NULL;
  841. PACE_HEADER pAce= NULL;
  842. UINT cAces = 0;
  843. BOOL *pBoolArray = NULL;
  844. TraceEnter(TRACE_DSSI, "RemoveRedundantPermissions");
  845. if ( NULL == ppSD || NULL == *ppSD )
  846. TraceLeaveResult(ERROR_SUCCESS); // Nothing to do
  847. BOOL bDefaulted;
  848. BOOL bPresent;
  849. GetSecurityDescriptorDacl(*ppSD, &bPresent, &pAcl, &bDefaulted);
  850. if (NULL != pAcl)
  851. {
  852. if(pAcl->AceCount)
  853. {
  854. //pBoolArray is initialzied to FALSE
  855. pBoolArray = (PBOOL)LocalAlloc(LPTR,sizeof(BOOL)*pAcl->AceCount);
  856. if(!pBoolArray)
  857. return ERROR_NOT_ENOUGH_MEMORY;
  858. }
  859. for (cAces = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
  860. cAces < pAcl->AceCount;
  861. ++cAces, pAce = (PACE_HEADER)NextAce(pAce))
  862. {
  863. if( pAce->AceFlags & INHERITED_ACE )
  864. {
  865. //If Only Create Child/Delete Child don't show it
  866. if((((ACCESS_ALLOWED_ACE*)pAce)->Mask & (~(ACTRL_DS_CREATE_CHILD |ACTRL_DS_DELETE_CHILD))) == 0 )
  867. {
  868. pBoolArray[cAces] = TRUE;
  869. continue;
  870. }
  871. //If the ace is inherited and inherit only and inherited object type
  872. //is not same as this object type bug 22559
  873. if( (((ACCESS_ALLOWED_ACE*)pAce)->Header.AceFlags & INHERIT_ONLY_ACE )
  874. && IsObjectAceType(pAce) )
  875. {
  876. GUID *pGuid = RtlObjectAceInheritedObjectType(pAce);
  877. if(pGuid && pGuidObjectType && !IsEqualGUID(*pGuid,*pGuidObjectType))
  878. {
  879. pBoolArray[cAces] = TRUE;
  880. continue;
  881. }
  882. }
  883. }
  884. }
  885. //Now Delete the Aces
  886. UINT cAceCount = pAcl->AceCount;
  887. UINT cAdjust = 0;
  888. for( cAces = 0; cAces < cAceCount; ++cAces)
  889. {
  890. if(pBoolArray[cAces])
  891. {
  892. DeleteAce(pAcl, cAces - cAdjust);
  893. cAdjust++;
  894. }
  895. }
  896. LocalFree(pBoolArray);
  897. }
  898. TraceLeaveResult(ERROR_SUCCESS);
  899. }
  900. STDMETHODIMP
  901. CDSSecurityInfo::GetSecurity(SECURITY_INFORMATION si,
  902. PSECURITY_DESCRIPTOR *ppSD,
  903. BOOL fDefault)
  904. {
  905. HRESULT hr = S_OK;
  906. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::GetSecurity");
  907. TraceAssert(si != 0);
  908. TraceAssert(ppSD != NULL);
  909. *ppSD = NULL;
  910. if (fDefault)
  911. {
  912. if( m_pDefaultSD )
  913. {
  914. ULONG nLength = GetSecurityDescriptorLength(m_pDefaultSD);
  915. *ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, nLength);
  916. if (*ppSD != NULL)
  917. CopyMemory(*ppSD, m_pDefaultSD, nLength);
  918. else
  919. hr = E_OUTOFMEMORY;
  920. }
  921. else
  922. hr = E_NOTIMPL;
  923. }
  924. else if (!(si & SACL_SECURITY_INFORMATION) && m_pSD != NULL)
  925. {
  926. ULONG nLength = GetSecurityDescriptorLength(m_pSD);
  927. *ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, nLength);
  928. if (*ppSD != NULL)
  929. CopyMemory(*ppSD, m_pSD, nLength);
  930. else
  931. hr = E_OUTOFMEMORY;
  932. }
  933. else
  934. {
  935. TraceAssert(m_strObjectPath != NULL);
  936. TraceAssert(m_pfnReadSD != NULL)
  937. hr = (*m_pfnReadSD)(m_strObjectPath, si, ppSD, m_lpReadContext);
  938. }
  939. if( si & DACL_SECURITY_INFORMATION && (m_dwLocalFlags & DSSI_LOCAL_NO_CREATE_DELETE ) )
  940. RemoveRedundantPermissions(ppSD, &m_guidObjectType);
  941. TraceLeaveResult(hr);
  942. }
  943. STDMETHODIMP
  944. CDSSecurityInfo::SetSecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  945. {
  946. HRESULT hr = S_OK;
  947. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::SetSecurity");
  948. TraceAssert(si != 0);
  949. TraceAssert(pSD != NULL);
  950. TraceAssert(m_strObjectPath != NULL);
  951. TraceAssert(m_pfnWriteSD != NULL)
  952. hr = (*m_pfnWriteSD)(m_strObjectPath, si, pSD, m_lpWriteContext);
  953. if (SUCCEEDED(hr) && m_pSD != NULL && (si != SACL_SECURITY_INFORMATION))
  954. {
  955. // The initial security descriptor is no longer valid.
  956. LocalFree(m_pSD);
  957. m_pSD = NULL;
  958. }
  959. TraceLeaveResult(hr);
  960. }
  961. STDMETHODIMP
  962. CDSSecurityInfo::GetAccessRights(const GUID* pguidObjectType,
  963. DWORD dwFlags,
  964. PSI_ACCESS *ppAccesses,
  965. ULONG *pcAccesses,
  966. ULONG *piDefaultAccess)
  967. {
  968. HRESULT hr = S_OK;
  969. LPCTSTR pszClassName = NULL;
  970. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::GetAccessRights");
  971. TraceAssert(ppAccesses != NULL);
  972. TraceAssert(pcAccesses != NULL);
  973. TraceAssert(piDefaultAccess != NULL);
  974. *ppAccesses = NULL;
  975. *pcAccesses = 0;
  976. *piDefaultAccess = 0;
  977. WaitOnInitThread();
  978. //
  979. //If we are getting the access rights for GUID which is selected in the
  980. //Apply onto combobox of permission page, we don't need to worry about
  981. //aux class. Only get the permission for the object type
  982. //
  983. BOOL bInheritGuid = TRUE;
  984. if (pguidObjectType == NULL || IsEqualGUID(*pguidObjectType, GUID_NULL))
  985. {
  986. bInheritGuid = FALSE;
  987. pguidObjectType = &m_guidObjectType;
  988. pszClassName = m_strObjectClass;
  989. }
  990. if (m_dwInitFlags & DSSI_NO_FILTER)
  991. dwFlags |= SCHEMA_NO_FILTER;
  992. // No schema path means we don't have read_property access to the object.
  993. // This limits what we can do.
  994. if (NULL == m_strSchemaRootPath)
  995. dwFlags |= SCHEMA_COMMON_PERM;
  996. PACCESS_INFO *ppAI = NULL;
  997. PACCESS_INFO pAI = NULL;
  998. if(!bInheritGuid)
  999. {
  1000. if(dwFlags & SI_EDIT_PROPERTIES)
  1001. ppAI = &m_pAIProperty;
  1002. else if(dwFlags & SI_EDIT_EFFECTIVE)
  1003. ppAI = &m_pAIEffective;
  1004. else
  1005. ppAI = &m_pAIGeneral;
  1006. }
  1007. else
  1008. {
  1009. ppAI = &pAI;
  1010. }
  1011. if(!*ppAI)
  1012. {
  1013. hr = SchemaCache_GetAccessRights(pguidObjectType,
  1014. pszClassName,
  1015. !bInheritGuid ? m_hAuxClasses : NULL,
  1016. m_strSchemaRootPath,
  1017. dwFlags,
  1018. ppAI);
  1019. if(FAILED(hr))
  1020. {
  1021. return hr;
  1022. }
  1023. }
  1024. if(*ppAI)
  1025. {
  1026. *ppAccesses = (*ppAI)->pAccess;
  1027. *pcAccesses = (*ppAI)->cAccesses;
  1028. *piDefaultAccess = (*ppAI)->iDefaultAccess;
  1029. }
  1030. TraceLeaveResult(hr);
  1031. }
  1032. STDMETHODIMP
  1033. CDSSecurityInfo::MapGeneric(const GUID* /*pguidObjectType*/,
  1034. UCHAR *pAceFlags,
  1035. ACCESS_MASK *pmask)
  1036. {
  1037. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::MapGeneric");
  1038. TraceAssert(pAceFlags != NULL);
  1039. TraceAssert(pmask != NULL);
  1040. // Only CONTAINER_INHERIT_ACE has meaning for DS
  1041. *pAceFlags &= ~OBJECT_INHERIT_ACE;
  1042. MapGenericMask(pmask, &g_DSMap);
  1043. // We don't expose SYNCHRONIZE, so don't pass it through
  1044. // to the UI. 192389
  1045. *pmask &= ~SYNCHRONIZE;
  1046. TraceLeaveResult(S_OK);
  1047. }
  1048. STDMETHODIMP
  1049. CDSSecurityInfo::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  1050. ULONG *pcInheritTypes)
  1051. {
  1052. HRESULT hr;
  1053. DWORD dwFlags = 0;
  1054. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::GetInheritTypes");
  1055. if (m_dwInitFlags & DSSI_NO_FILTER)
  1056. dwFlags |= SCHEMA_NO_FILTER;
  1057. hr = SchemaCache_GetInheritTypes(&m_guidObjectType, dwFlags, ppInheritTypes, pcInheritTypes);
  1058. TraceLeaveResult(hr);
  1059. }
  1060. STDMETHODIMP
  1061. CDSSecurityInfo::PropertySheetPageCallback(HWND hwnd,
  1062. UINT uMsg,
  1063. SI_PAGE_TYPE uPage)
  1064. {
  1065. if (PSPCB_SI_INITDIALOG == uMsg && uPage == SI_PAGE_PERM)
  1066. {
  1067. WaitOnInitThread();
  1068. //
  1069. // HACK ALERT!!!
  1070. //
  1071. // Exchange Platinum is required to hide membership of some groups
  1072. // (distribution lists) for legal reasons. The only way they found
  1073. // to do this is with non-canonical ACLs which look roughly like
  1074. // Allow Admins access
  1075. // Deny Everyone access
  1076. // <normal ACL>
  1077. //
  1078. // Since ACLUI always generates ACLs in NT Canonical Order, we can't
  1079. // allow these funky ACLs to be modified. If we did, the DL's would
  1080. // either become visible or Admins would get locked out.
  1081. //
  1082. if (!(SI_READONLY & m_dwSIFlags))
  1083. {
  1084. DWORD dwAclType = IsSpecificNonCanonicalSD(m_pSD);
  1085. if (ENC_RESULT_NOT_PRESENT != dwAclType)
  1086. {
  1087. // It's a funky ACL so don't allow changes
  1088. m_dwSIFlags |= SI_READONLY;
  1089. // Tell the user what's going on
  1090. MsgPopup(hwnd,
  1091. MAKEINTRESOURCE(IDS_SPECIAL_ACL_WARNING),
  1092. MAKEINTRESOURCE(IDS_SPECIAL_SECURITY_TITLE),
  1093. MB_OK | MB_ICONWARNING | MB_SETFOREGROUND,
  1094. g_hInstance,
  1095. m_strDisplayName);
  1096. // S_FALSE suppresses further popups from aclui ("The ACL
  1097. // is not ordered correctly, etc.")
  1098. return S_FALSE;
  1099. }
  1100. }
  1101. if( (SI_READONLY & m_dwSIFlags) && (DSSI_NO_READONLY_MESSAGE & m_dwSIFlags) )
  1102. return S_FALSE;
  1103. }
  1104. return S_OK;
  1105. }
  1106. DWORD WINAPI
  1107. CDSSecurityInfo::InitThread(LPVOID pvThreadData)
  1108. {
  1109. CDSSecurityInfo *psi;
  1110. HINSTANCE hInstThisDll = LoadLibrary(c_szDllName);
  1111. psi = (CDSSecurityInfo*)pvThreadData;
  1112. SetEvent(psi->m_hLoadLibWaitEvent);
  1113. InterlockedIncrement(&GLOBAL_REFCOUNT);
  1114. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::InitThread");
  1115. TraceAssert(psi != NULL);
  1116. #if DBG
  1117. DWORD dwTime = GetTickCount();
  1118. #endif
  1119. ThreadCoInitialize();
  1120. psi->Init3();
  1121. ThreadCoUninitialize();
  1122. #if DBG
  1123. Trace((TEXT("InitThread complete, elapsed time: %d ms"), GetTickCount() - dwTime));
  1124. #endif
  1125. TraceLeave();
  1126. ASSERT( 0 != GLOBAL_REFCOUNT );
  1127. InterlockedDecrement(&GLOBAL_REFCOUNT);
  1128. FreeLibraryAndExitThread(hInstThisDll, 0);
  1129. }
  1130. HRESULT
  1131. SetSecurityInfoMask(LPUNKNOWN punk, SECURITY_INFORMATION si)
  1132. {
  1133. HRESULT hr = E_INVALIDARG;
  1134. if (punk)
  1135. {
  1136. IADsObjectOptions *pOptions;
  1137. hr = punk->QueryInterface(IID_IADsObjectOptions, (void**)&pOptions);
  1138. if (SUCCEEDED(hr))
  1139. {
  1140. VARIANT var;
  1141. VariantInit(&var);
  1142. V_VT(&var) = VT_I4;
  1143. V_I4(&var) = si;
  1144. hr = pOptions->SetOption(ADS_OPTION_SECURITY_MASK, var);
  1145. pOptions->Release();
  1146. }
  1147. }
  1148. return hr;
  1149. }
  1150. //+---------------------------------------------------------------------------
  1151. //
  1152. // Function: CDSSecurityInfo::DSReadObjectSecurity
  1153. //
  1154. // Synopsis: Reads the security descriptor from the specied DS object
  1155. //
  1156. // Arguments: [IN pszObjectPath] -- ADS path of DS object
  1157. // [IN SeInfo] -- Security descriptor parts requested
  1158. // [OUT ppSD] -- Security descriptor returned here
  1159. // [IN lpContext] -- CDSSecurityInfo*
  1160. //
  1161. // Notes: The returned security descriptor must be freed with LocalFree
  1162. //
  1163. //----------------------------------------------------------------------------
  1164. HRESULT WINAPI
  1165. CDSSecurityInfo::DSReadObjectSecurity(LPCWSTR /*pszObjectPath*/,
  1166. SECURITY_INFORMATION SeInfo,
  1167. PSECURITY_DESCRIPTOR *ppSD,
  1168. LPARAM lpContext)
  1169. {
  1170. HRESULT hr = S_OK;
  1171. LPWSTR pszSDProperty = (LPWSTR)c_szSDProperty;
  1172. PADS_ATTR_INFO pSDAttributeInfo = NULL;
  1173. DWORD dwAttributesReturned;
  1174. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::DSReadObjectSecurity");
  1175. TraceAssert(SeInfo != 0);
  1176. TraceAssert(ppSD != NULL);
  1177. TraceAssert(lpContext != 0);
  1178. *ppSD = NULL;
  1179. CDSSecurityInfo *pThis = reinterpret_cast<CDSSecurityInfo*>(lpContext);
  1180. TraceAssert(pThis != NULL);
  1181. TraceAssert(pThis->m_pDsObject != NULL);
  1182. // Set the SECURITY_INFORMATION mask
  1183. hr = SetSecurityInfoMask(pThis->m_pDsObject, SeInfo);
  1184. FailGracefully(hr, "Unable to set ADS_OPTION_SECURITY_MASK");
  1185. // Read the security descriptor
  1186. hr = pThis->m_pDsObject->GetObjectAttributes(&pszSDProperty,
  1187. 1,
  1188. &pSDAttributeInfo,
  1189. &dwAttributesReturned);
  1190. if (SUCCEEDED(hr) && !pSDAttributeInfo)
  1191. hr = E_ACCESSDENIED; // This happens for SACL if no SecurityPrivilege
  1192. FailGracefully(hr, "Unable to read nTSecurityDescriptor attribute");
  1193. TraceAssert(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->dwADsType);
  1194. TraceAssert(ADSTYPE_NT_SECURITY_DESCRIPTOR == pSDAttributeInfo->pADsValues->dwType);
  1195. *ppSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, pSDAttributeInfo->pADsValues->SecurityDescriptor.dwLength);
  1196. if (!*ppSD)
  1197. ExitGracefully(hr, E_OUTOFMEMORY, "LocalAlloc failed");
  1198. CopyMemory(*ppSD,
  1199. pSDAttributeInfo->pADsValues->SecurityDescriptor.lpValue,
  1200. pSDAttributeInfo->pADsValues->SecurityDescriptor.dwLength);
  1201. exit_gracefully:
  1202. if (pSDAttributeInfo)
  1203. FreeADsMem(pSDAttributeInfo);
  1204. TraceLeaveResult(hr);
  1205. }
  1206. //+---------------------------------------------------------------------------
  1207. //
  1208. // Function: CDSSecurityInfo::DSWriteObjectSecurity
  1209. //
  1210. // Synopsis: Writes the security descriptor to the specied DS object
  1211. //
  1212. // Arguments: [IN pszObjectPath] -- ADS path of DS object
  1213. // [IN SeInfo] -- Security descriptor parts provided
  1214. // [IN pSD] -- The new security descriptor
  1215. // [IN lpContext] -- CDSSecurityInfo*
  1216. //
  1217. //----------------------------------------------------------------------------
  1218. HRESULT WINAPI
  1219. CDSSecurityInfo::DSWriteObjectSecurity(LPCWSTR /*pszObjectPath*/,
  1220. SECURITY_INFORMATION SeInfo,
  1221. PSECURITY_DESCRIPTOR pSD,
  1222. LPARAM lpContext)
  1223. {
  1224. HRESULT hr = S_OK;
  1225. ADSVALUE attributeValue;
  1226. ADS_ATTR_INFO attributeInfo;
  1227. DWORD dwAttributesModified;
  1228. DWORD dwSDLength;
  1229. PSECURITY_DESCRIPTOR psd = NULL;
  1230. SECURITY_DESCRIPTOR_CONTROL sdControl = 0;
  1231. DWORD dwRevision;
  1232. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::DSWriteObjectSecurity");
  1233. TraceAssert(pSD && IsValidSecurityDescriptor(pSD));
  1234. TraceAssert(SeInfo != 0);
  1235. TraceAssert(lpContext != 0);
  1236. CDSSecurityInfo *pThis = reinterpret_cast<CDSSecurityInfo*>(lpContext);
  1237. TraceAssert(pThis != NULL);
  1238. TraceAssert(pThis->m_pDsObject != NULL);
  1239. // Set the SECURITY_INFORMATION mask
  1240. hr = SetSecurityInfoMask(pThis->m_pDsObject, SeInfo);
  1241. FailGracefully(hr, "Unable to set ADS_OPTION_SECURITY_MASK");
  1242. // Need the total size
  1243. dwSDLength = GetSecurityDescriptorLength(pSD);
  1244. //
  1245. // If necessary, make a self-relative copy of the security descriptor
  1246. //
  1247. GetSecurityDescriptorControl(pSD, &sdControl, &dwRevision);
  1248. if (!(sdControl & SE_SELF_RELATIVE))
  1249. {
  1250. psd = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, dwSDLength);
  1251. if (psd == NULL ||
  1252. !MakeSelfRelativeSD(pSD, psd, &dwSDLength))
  1253. {
  1254. DWORD dwErr = GetLastError();
  1255. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "Unable to make self-relative SD copy");
  1256. }
  1257. // Point to the self-relative copy
  1258. pSD = psd;
  1259. }
  1260. attributeValue.dwType = ADSTYPE_NT_SECURITY_DESCRIPTOR;
  1261. attributeValue.SecurityDescriptor.dwLength = dwSDLength;
  1262. attributeValue.SecurityDescriptor.lpValue = (LPBYTE)pSD;
  1263. attributeInfo.pszAttrName = (LPWSTR)c_szSDProperty;
  1264. attributeInfo.dwControlCode = ADS_ATTR_UPDATE;
  1265. attributeInfo.dwADsType = ADSTYPE_NT_SECURITY_DESCRIPTOR;
  1266. attributeInfo.pADsValues = &attributeValue;
  1267. attributeInfo.dwNumValues = 1;
  1268. // Write the security descriptor
  1269. hr = pThis->m_pDsObject->SetObjectAttributes(&attributeInfo,
  1270. 1,
  1271. &dwAttributesModified);
  1272. if (HRESULT_FROM_WIN32(ERROR_DS_CONSTRAINT_VIOLATION) == hr
  1273. && OWNER_SECURITY_INFORMATION == SeInfo)
  1274. {
  1275. hr = HRESULT_FROM_WIN32(ERROR_INVALID_OWNER);
  1276. }
  1277. exit_gracefully:
  1278. if (psd != NULL)
  1279. LocalFree(psd);
  1280. TraceLeaveResult(hr);
  1281. }
  1282. //+---------------------------------------------------------------------------
  1283. //
  1284. // Function: CheckObjectAccess
  1285. //
  1286. // Synopsis: Checks access to the security descriptor of a DS object.
  1287. // In particular, determines whether the user has READ_CONTROL,
  1288. // WRITE_DAC, WRITE_OWNER, and/or ACCESS_SYSTEM_SECURITY access.
  1289. // If it cannot determine for sure about WRITE_DAC permission,
  1290. // it returns SI_MAY_WRITE which helps aclui to put a better warning
  1291. // Arguments: none
  1292. //
  1293. // Return: DWORD (Access Mask)
  1294. //
  1295. // Notes: The check for READ_CONTROL involves reading the Owner,
  1296. // Group, and DACL. This security descriptor is saved
  1297. // in m_pSD.
  1298. //
  1299. // The checks for WRITE_DAC, WRITE_OWNER, and
  1300. // ACCESS_SYSTEM_SECURITY involve getting sDRightsEffective
  1301. // from the object.
  1302. //
  1303. //----------------------------------------------------------------------------
  1304. DWORD
  1305. CDSSecurityInfo::CheckObjectAccess()
  1306. {
  1307. DWORD dwAccessGranted = 0;
  1308. HRESULT hr;
  1309. SECURITY_INFORMATION si = 0;
  1310. LPWSTR pProp = (LPWSTR)c_szSDRightsProp;
  1311. PADS_ATTR_INFO pSDRightsInfo = NULL;
  1312. DWORD dwAttributesReturned;
  1313. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::CheckObjectAccess");
  1314. #ifdef DSSEC_PRIVATE_DEBUG
  1315. // FOR DEBUGGING ONLY
  1316. // Turn this on to prevent the dialogs from being read-only. This is
  1317. // useful for testing the object picker against NTDEV (for example).
  1318. TraceMsg("Returning all access for debugging");
  1319. dwAccessGranted = (READ_CONTROL | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY);
  1320. #endif
  1321. // Test for READ_CONTROL by trying to read the Owner, Group, and DACL
  1322. TraceAssert(NULL == m_pSD); // shouldn't get here twice
  1323. TraceAssert(m_strObjectPath != NULL);
  1324. TraceAssert(m_pfnReadSD != NULL);
  1325. hr = (*m_pfnReadSD)(m_strObjectPath,
  1326. OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
  1327. &m_pSD,
  1328. m_lpReadContext);
  1329. if (SUCCEEDED(hr))
  1330. {
  1331. TraceAssert(NULL != m_pSD);
  1332. dwAccessGranted |= READ_CONTROL;
  1333. }
  1334. // If we're in read-only mode, there's no need to check anything else.
  1335. if (m_dwInitFlags & DSSI_READ_ONLY)
  1336. TraceLeaveValue(dwAccessGranted);
  1337. // Read the sDRightsEffective property to determine writability
  1338. m_pDsObject->GetObjectAttributes(&pProp,
  1339. 1,
  1340. &pSDRightsInfo,
  1341. &dwAttributesReturned);
  1342. if (pSDRightsInfo)
  1343. {
  1344. TraceAssert(ADSTYPE_INTEGER == pSDRightsInfo->dwADsType);
  1345. si = pSDRightsInfo->pADsValues->Integer;
  1346. FreeADsMem(pSDRightsInfo);
  1347. }
  1348. else
  1349. {
  1350. //
  1351. // Note that GetObjectAttributes commonly returns S_OK even when
  1352. // it fails, so the HRESULT is basically useless here.
  1353. //
  1354. // This can fail if we don't have read_property access, which can
  1355. // happen when an admin is trying to restore access to an object
  1356. // that has had all access removed or denied
  1357. //
  1358. // Assume we can write the Owner and DACL. If not, the worst that
  1359. // happens is the user gets an "Access Denied" message when trying
  1360. // to save changes.
  1361. //
  1362. //Instead of add SI_MAY_WRITE to dwAccessGranted . This helps
  1363. //ACLUI to putup a better error message. bug 411843
  1364. TraceMsg("GetObjectAttributes failed to read sDRightsEffective");
  1365. dwAccessGranted |= SI_MAY_WRITE;
  1366. si = OWNER_SECURITY_INFORMATION ;
  1367. }
  1368. // The resulting SECURITY_INFORMATION mask indicates the
  1369. // security descriptor parts that may be modified by the user.
  1370. Trace((TEXT("sDRightsEffective = 0x%08x"), si));
  1371. if (OWNER_SECURITY_INFORMATION & si)
  1372. dwAccessGranted |= WRITE_OWNER;
  1373. if (DACL_SECURITY_INFORMATION & si)
  1374. dwAccessGranted |= WRITE_DAC;
  1375. if (SACL_SECURITY_INFORMATION & si)
  1376. dwAccessGranted |= ACCESS_SYSTEM_SECURITY;
  1377. TraceLeaveValue(dwAccessGranted);
  1378. }
  1379. BOOL SkipLocalGroup(LPCWSTR pszServerName, PSID psid)
  1380. {
  1381. SID_NAME_USE use;
  1382. WCHAR szAccountName[MAX_PATH];
  1383. WCHAR szDomainName[MAX_PATH];
  1384. DWORD dwAccountLen = MAX_PATH;
  1385. DWORD dwDomainLen = MAX_PATH;
  1386. if(LookupAccountSid(pszServerName,
  1387. psid,
  1388. szAccountName,
  1389. &dwAccountLen,
  1390. szDomainName,
  1391. &dwDomainLen,
  1392. &use))
  1393. {
  1394. if(use == SidTypeWellKnownGroup)
  1395. return TRUE;
  1396. }
  1397. //
  1398. //Built In sids have first subauthority of 32 ( s-1-5-32 )
  1399. //
  1400. if((*(GetSidSubAuthorityCount(psid)) >= 1 ) && (*(GetSidSubAuthority(psid,0)) == 32))
  1401. return TRUE;
  1402. return FALSE;
  1403. }
  1404. STDMETHODIMP
  1405. CDSSecurityInfo::GetEffectivePermission(const GUID* pguidObjectType,
  1406. PSID pUserSid,
  1407. LPCWSTR pszServerName,
  1408. PSECURITY_DESCRIPTOR pSD,
  1409. POBJECT_TYPE_LIST *ppObjectTypeList,
  1410. ULONG *pcObjectTypeListLength,
  1411. PACCESS_MASK *ppGrantedAccessList,
  1412. ULONG *pcGrantedAccessListLength)
  1413. {
  1414. AUTHZ_CLIENT_CONTEXT_HANDLE CC = NULL;
  1415. LUID luid = {0xdead,0xbeef};
  1416. AUTHZ_ACCESS_REQUEST AReq;
  1417. AUTHZ_ACCESS_REPLY AReply;
  1418. HRESULT hr = S_OK;
  1419. DWORD dwFlags = 0;
  1420. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::GetEffectivePermission");
  1421. TraceAssert(pUserSid && IsValidSecurityDescriptor(pSD));
  1422. TraceAssert(ppObjectTypeList != NULL);
  1423. TraceAssert(pcObjectTypeListLength != NULL);
  1424. TraceAssert(ppGrantedAccessList != NULL);
  1425. TraceAssert(pcGrantedAccessListLength != NULL);
  1426. AReply.GrantedAccessMask = NULL;
  1427. AReply.Error = NULL;
  1428. AReq.ObjectTypeList = NULL;
  1429. AReq.ObjectTypeListLength = 0;
  1430. if( m_ResourceManager == NULL )
  1431. {
  1432. //Initilize RM for Access check
  1433. AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
  1434. NULL,
  1435. NULL,
  1436. NULL,
  1437. L"Dummy",
  1438. &m_ResourceManager );
  1439. if( m_ResourceManager == NULL )
  1440. ExitGracefully(hr, E_UNEXPECTED, "Could Not Get Resource Manager");
  1441. }
  1442. //Initialize the client context
  1443. BOOL bSkipLocalGroup = SkipLocalGroup(pszServerName, pUserSid);
  1444. if( !AuthzInitializeContextFromSid(bSkipLocalGroup?AUTHZ_SKIP_TOKEN_GROUPS:0 ,
  1445. pUserSid,
  1446. m_ResourceManager,
  1447. NULL,
  1448. luid,
  1449. NULL,
  1450. &CC) )
  1451. {
  1452. DWORD dwErr = GetLastError();
  1453. ExitGracefully(hr,
  1454. HRESULT_FROM_WIN32(dwErr),
  1455. "AuthzInitializeContextFromSid Failed");
  1456. }
  1457. if (NULL == m_strSchemaRootPath)
  1458. dwFlags = SCHEMA_COMMON_PERM;
  1459. if(!m_pOTL)
  1460. {
  1461. //Get ObjectTypeList
  1462. hr = Schema_GetObjectTypeList((LPGUID)pguidObjectType,
  1463. m_hAuxClasses,
  1464. m_strSchemaRootPath,
  1465. dwFlags,
  1466. &(AReq.ObjectTypeList),
  1467. &(AReq.ObjectTypeListLength));
  1468. FailGracefully( hr, "Schema_GetObjectTypeList Failed");
  1469. m_pOTL = AReq.ObjectTypeList;
  1470. m_cCountOTL = AReq.ObjectTypeListLength;
  1471. }
  1472. else
  1473. {
  1474. AReq.ObjectTypeList = m_pOTL;
  1475. AReq.ObjectTypeListLength = m_cCountOTL;
  1476. }
  1477. //Do the Access Check
  1478. AReq.DesiredAccess = MAXIMUM_ALLOWED;
  1479. AReq.PrincipalSelfSid = NULL;
  1480. AReq.OptionalArguments = NULL;
  1481. AReply.ResultListLength = AReq.ObjectTypeListLength;
  1482. AReply.SaclEvaluationResults = NULL;
  1483. if( (AReply.GrantedAccessMask = (PACCESS_MASK)LocalAlloc(LPTR, sizeof(ACCESS_MASK)*AReply.ResultListLength) ) == NULL )
  1484. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to LocalAlloc");
  1485. if( (AReply.Error = (PDWORD)LocalAlloc(LPTR, sizeof(DWORD)*AReply.ResultListLength)) == NULL )
  1486. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to LocalAlloc");
  1487. if( !AuthzAccessCheck(0,
  1488. CC,
  1489. &AReq,
  1490. NULL,
  1491. pSD,
  1492. NULL,
  1493. 0,
  1494. &AReply,
  1495. NULL) )
  1496. {
  1497. DWORD dwErr = GetLastError();
  1498. ExitGracefully(hr,
  1499. HRESULT_FROM_WIN32(dwErr),
  1500. "AuthzAccessCheck Failed");
  1501. }
  1502. exit_gracefully:
  1503. if(CC)
  1504. AuthzFreeContext(CC);
  1505. if(!SUCCEEDED(hr))
  1506. {
  1507. if(AReply.GrantedAccessMask)
  1508. LocalFree(AReply.GrantedAccessMask);
  1509. if(AReply.Error)
  1510. LocalFree(AReply.Error);
  1511. AReply.Error = NULL;
  1512. AReply.GrantedAccessMask = NULL;
  1513. }
  1514. else
  1515. {
  1516. *ppObjectTypeList = AReq.ObjectTypeList;
  1517. *pcObjectTypeListLength = AReq.ObjectTypeListLength;
  1518. *ppGrantedAccessList = AReply.GrantedAccessMask;
  1519. *pcGrantedAccessListLength = AReq.ObjectTypeListLength;
  1520. }
  1521. TraceLeaveResult(hr);
  1522. }
  1523. STDMETHODIMP
  1524. CDSSecurityInfo::GetInheritSource(SECURITY_INFORMATION si,
  1525. PACL pACL,
  1526. PINHERITED_FROM *ppInheritArray)
  1527. {
  1528. HRESULT hr = S_OK;
  1529. DWORD dwErr = ERROR_SUCCESS;
  1530. PINHERITED_FROM pTempInherit = NULL;
  1531. PINHERITED_FROM pTempInherit2 = NULL;
  1532. LPWSTR pStrTemp = NULL;
  1533. IADsPathname *pPath = NULL;
  1534. BSTR strObjectPath = NULL;
  1535. BSTR strServerName = NULL;
  1536. BSTR strParentPath = NULL;
  1537. LPGUID *ppGuid = NULL;
  1538. BOOL bFreeInheritFromArray = FALSE;
  1539. TraceEnter(TRACE_DSSI, "CDSSecurityInfo::GetInheritSource");
  1540. TraceAssert(pACL != 0);
  1541. TraceAssert(ppInheritArray != NULL);
  1542. //
  1543. // Create an ADsPathname object to parse the path and get the
  1544. // the objectname in ADS_FORMAT_X500_DN
  1545. //
  1546. hr = CoCreateInstance(CLSID_Pathname,
  1547. NULL,
  1548. CLSCTX_INPROC_SERVER,
  1549. IID_IADsPathname,
  1550. (LPVOID*)&pPath);
  1551. if (pPath)
  1552. {
  1553. if (SUCCEEDED(pPath->Set(m_strObjectPath, ADS_SETTYPE_FULL)))
  1554. {
  1555. hr = pPath->Retrieve(ADS_FORMAT_SERVER, &strServerName);
  1556. if(!strServerName)
  1557. {
  1558. pPath->Set(m_strServerName,ADS_SETTYPE_SERVER );
  1559. hr = pPath->Retrieve(ADS_FORMAT_X500 ,&strObjectPath);
  1560. }
  1561. else
  1562. strObjectPath = m_strObjectPath;
  1563. }
  1564. }
  1565. if(strObjectPath == NULL)
  1566. strObjectPath = m_strObjectPath;
  1567. if( pACL == NULL || ppInheritArray == NULL )
  1568. ExitGracefully(hr, E_POINTER, "CDSSecurityInfo::GetInheritSource Invalid Parameters");
  1569. pTempInherit = (PINHERITED_FROM)LocalAlloc( LPTR, sizeof(INHERITED_FROM)*pACL->AceCount);
  1570. if(pTempInherit == NULL)
  1571. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1572. UINT cGuidCount;
  1573. cGuidCount = 1;
  1574. if(m_hAuxClasses)
  1575. cGuidCount += DPA_GetPtrCount(m_hAuxClasses);
  1576. ppGuid = (LPGUID*)LocalAlloc(LPTR,sizeof(LPGUID)*cGuidCount);
  1577. if(!ppGuid)
  1578. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1579. ppGuid[0] = &m_guidObjectType;
  1580. for(UINT i = 1; i < cGuidCount ; ++i)
  1581. {
  1582. PAUX_INFO pAI = (PAUX_INFO)DPA_FastGetPtr(m_hAuxClasses, i-1);
  1583. if(IsEqualGUID(pAI->guid, GUID_NULL))
  1584. {
  1585. hr = Schema_GetObjectTypeGuid(pAI->pszClassName,&pAI->guid);
  1586. FailGracefully( hr, "Schema_GetObjectTypeGuid Failed");
  1587. }
  1588. ppGuid[i] = &pAI->guid;
  1589. }
  1590. dwErr = GetInheritanceSource(strObjectPath,
  1591. SE_DS_OBJECT_ALL,
  1592. si,
  1593. //m_dwSIFlags & SI_CONTAINER,
  1594. TRUE,
  1595. ppGuid,
  1596. cGuidCount,
  1597. pACL,
  1598. NULL,
  1599. &g_DSMap,
  1600. pTempInherit);
  1601. hr = HRESULT_FROM_WIN32(dwErr);
  1602. FailGracefully( hr, "GetInheritanceSource Failed");
  1603. bFreeInheritFromArray = TRUE;
  1604. DWORD nSize;
  1605. nSize = sizeof(INHERITED_FROM)*pACL->AceCount;
  1606. for(UINT i = 0; i < pACL->AceCount; ++i)
  1607. {
  1608. if(pTempInherit[i].AncestorName)
  1609. nSize += StringByteSize(pTempInherit[i].AncestorName);
  1610. }
  1611. pTempInherit2 = (PINHERITED_FROM)LocalAlloc( LPTR, nSize );
  1612. if(pTempInherit2 == NULL)
  1613. ExitGracefully(hr, E_OUTOFMEMORY,"OUT of Memory");
  1614. pStrTemp = (LPWSTR)(pTempInherit2 + pACL->AceCount);
  1615. for(i = 0; i < pACL->AceCount; ++i)
  1616. {
  1617. pTempInherit2[i].GenerationGap = pTempInherit[i].GenerationGap;
  1618. if(pTempInherit[i].AncestorName)
  1619. {
  1620. if (SUCCEEDED(pPath->Set(pTempInherit[i].AncestorName, ADS_SETTYPE_FULL)))
  1621. {
  1622. hr = pPath->Retrieve(ADS_FORMAT_X500_DN, &strParentPath);
  1623. }
  1624. pTempInherit2[i].AncestorName = pStrTemp;
  1625. if(strParentPath)
  1626. {
  1627. wcscpy(pStrTemp,strParentPath);
  1628. pStrTemp += (wcslen(pStrTemp)+1);
  1629. SysFreeString(strParentPath);
  1630. strParentPath = NULL;
  1631. }
  1632. else
  1633. {
  1634. wcscpy(pStrTemp,pTempInherit[i].AncestorName);
  1635. pStrTemp += (wcslen(pTempInherit[i].AncestorName)+1);
  1636. }
  1637. }
  1638. }
  1639. exit_gracefully:
  1640. if(bFreeInheritFromArray)
  1641. FreeInheritedFromArray(pTempInherit, pACL->AceCount,NULL);
  1642. if(SUCCEEDED(hr))
  1643. {
  1644. *ppInheritArray = pTempInherit2;
  1645. }
  1646. if(pTempInherit)
  1647. LocalFree(pTempInherit);
  1648. if(ppGuid)
  1649. LocalFree(ppGuid);
  1650. DoRelease(pPath);
  1651. if(strObjectPath != m_strObjectPath)
  1652. SysFreeString(strObjectPath);
  1653. if(strServerName)
  1654. SysFreeString(strServerName);
  1655. TraceLeaveResult(hr);
  1656. }
  1657. //+---------------------------------------------------------------------------
  1658. //
  1659. // Function: DSCreateISecurityInfoObjectEx
  1660. //
  1661. // Synopsis: Instantiates an ISecurityInfo interface for a DS object
  1662. //
  1663. // Arguments: [IN pwszObjectPath] -- Full ADS path of DS object
  1664. // [IN pwszObjectClass] -- Class of the object (optional)
  1665. // [IN pwszServer] -- Name/address of DS DC (optional)
  1666. // [IN pwszUserName] -- User name for validation (optional)
  1667. // [IN pwszPassword] -- Password for validation (optional)
  1668. // [IN dwFlags] -- Combination of DSSI_* flags
  1669. // [OUT ppSI] -- Interface pointer returned here
  1670. // [IN pfnReadSD] -- Optional function for reading SD
  1671. // [IN pfnWriteSD] -- Optional function for writing SD
  1672. // [IN lpContext] -- Passed to pfnReadSD/pfnWriteSD
  1673. //
  1674. // Return: HRESULT
  1675. //
  1676. //----------------------------------------------------------------------------
  1677. STDAPI
  1678. DSCreateISecurityInfoObjectEx(LPCWSTR pwszObjectPath,
  1679. LPCWSTR pwszObjectClass,
  1680. LPCWSTR pwszServer,
  1681. LPCWSTR pwszUserName,
  1682. LPCWSTR pwszPassword,
  1683. DWORD dwFlags,
  1684. LPSECURITYINFO *ppSI,
  1685. PFNREADOBJECTSECURITY pfnReadSD,
  1686. PFNWRITEOBJECTSECURITY pfnWriteSD,
  1687. LPARAM lpContext)
  1688. {
  1689. HRESULT hr;
  1690. CDSSecurityInfo* pSI = NULL;
  1691. TraceEnter(TRACE_SECURITY, "DSCreateISecurityInfoObjectEx");
  1692. if (pwszObjectPath == NULL || ppSI == NULL)
  1693. TraceLeaveResult(E_INVALIDARG);
  1694. *ppSI = NULL;
  1695. //
  1696. // Create and initialize the ISecurityInformation object.
  1697. //
  1698. pSI = new CDSSecurityInfo(); // ref == 0
  1699. if (!pSI)
  1700. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to create CDSSecurityInfo object");
  1701. pSI->AddRef(); // ref == 1
  1702. hr = pSI->Init(pwszObjectPath,
  1703. pwszObjectClass,
  1704. pwszServer,
  1705. pwszUserName,
  1706. pwszPassword,
  1707. dwFlags,
  1708. pfnReadSD,
  1709. pfnWriteSD,
  1710. lpContext);
  1711. if (FAILED(hr))
  1712. {
  1713. DoRelease(pSI);
  1714. }
  1715. *ppSI = (LPSECURITYINFO)pSI;
  1716. exit_gracefully:
  1717. TraceLeaveResult(hr);
  1718. }
  1719. STDAPI
  1720. DSCreateISecurityInfoObject(LPCWSTR pwszObjectPath,
  1721. LPCWSTR pwszObjectClass,
  1722. DWORD dwFlags,
  1723. LPSECURITYINFO *ppSI,
  1724. PFNREADOBJECTSECURITY pfnReadSD,
  1725. PFNWRITEOBJECTSECURITY pfnWriteSD,
  1726. LPARAM lpContext)
  1727. {
  1728. return DSCreateISecurityInfoObjectEx(pwszObjectPath,
  1729. pwszObjectClass,
  1730. NULL, //pwszServer,
  1731. NULL, //pwszUserName,
  1732. NULL, //pwszPassword,
  1733. dwFlags,
  1734. ppSI,
  1735. pfnReadSD,
  1736. pfnWriteSD,
  1737. lpContext);
  1738. }
  1739. //+---------------------------------------------------------------------------
  1740. //
  1741. // Function: DSCreateSecurityPage
  1742. //
  1743. // Synopsis: Creates a Security property page for a DS object
  1744. //
  1745. // Arguments: [IN pwszObjectPath] -- Full ADS path of DS object
  1746. // [IN pwszObjectClass] -- Class of the object (optional)
  1747. // [IN dwFlags] -- Combination of DSSI_* flags
  1748. // [OUT phPage] -- HPROPSHEETPAGE returned here
  1749. // [IN pfnReadSD] -- Optional function for reading SD
  1750. // [IN pfnWriteSD] -- Optional function for writing SD
  1751. // [IN lpContext] -- Passed to pfnReadSD/pfnWriteSD
  1752. //
  1753. // Return: HRESULT
  1754. //
  1755. //----------------------------------------------------------------------------
  1756. STDAPI
  1757. DSCreateSecurityPage(LPCWSTR pwszObjectPath,
  1758. LPCWSTR pwszObjectClass,
  1759. DWORD dwFlags,
  1760. HPROPSHEETPAGE *phPage,
  1761. PFNREADOBJECTSECURITY pfnReadSD,
  1762. PFNWRITEOBJECTSECURITY pfnWriteSD,
  1763. LPARAM lpContext)
  1764. {
  1765. HRESULT hr;
  1766. LPSECURITYINFO pSI = NULL;
  1767. TraceEnter(TRACE_SECURITY, "DSCreateSecurityPage");
  1768. if (NULL == phPage || NULL == pwszObjectPath || !*pwszObjectPath)
  1769. TraceLeaveResult(E_INVALIDARG);
  1770. *phPage = NULL;
  1771. hr = DSCreateISecurityInfoObject(pwszObjectPath,
  1772. pwszObjectClass,
  1773. dwFlags,
  1774. &pSI,
  1775. pfnReadSD,
  1776. pfnWriteSD,
  1777. lpContext);
  1778. if (SUCCEEDED(hr))
  1779. {
  1780. hr = _CreateSecurityPage(pSI, phPage);
  1781. DoRelease(pSI);
  1782. }
  1783. TraceLeaveResult(hr);
  1784. }
  1785. //+---------------------------------------------------------------------------
  1786. //
  1787. // Function: DSEditSecurity
  1788. //
  1789. // Synopsis: Displays a modal dialog for editing security on a DS object
  1790. //
  1791. // Arguments: [IN hwndOwner] -- Dialog owner window
  1792. // [IN pwszObjectPath] -- Full ADS path of DS object
  1793. // [IN pwszObjectClass] -- Class of the object (optional)
  1794. // [IN dwFlags] -- Combination of DSSI_* flags
  1795. // [IN pwszCaption -- Optional dialog caption
  1796. // [IN pfnReadSD] -- Optional function for reading SD
  1797. // [IN pfnWriteSD] -- Optional function for writing SD
  1798. // [IN lpContext] -- Passed to pfnReadSD/pfnWriteSD
  1799. //
  1800. // Return: HRESULT
  1801. //
  1802. //----------------------------------------------------------------------------
  1803. STDAPI
  1804. DSEditSecurity(HWND hwndOwner,
  1805. LPCWSTR pwszObjectPath,
  1806. LPCWSTR pwszObjectClass,
  1807. DWORD dwFlags,
  1808. LPCWSTR pwszCaption,
  1809. PFNREADOBJECTSECURITY pfnReadSD,
  1810. PFNWRITEOBJECTSECURITY pfnWriteSD,
  1811. LPARAM lpContext)
  1812. {
  1813. HRESULT hr;
  1814. LPSECURITYINFO pSI = NULL;
  1815. TraceEnter(TRACE_SECURITY, "DSCreateSecurityPage");
  1816. if (NULL == pwszObjectPath || !*pwszObjectPath)
  1817. TraceLeaveResult(E_INVALIDARG);
  1818. if (pwszCaption && *pwszCaption)
  1819. {
  1820. // Use the provided caption
  1821. HPROPSHEETPAGE hPage = NULL;
  1822. hr = DSCreateSecurityPage(pwszObjectPath,
  1823. pwszObjectClass,
  1824. dwFlags,
  1825. &hPage,
  1826. pfnReadSD,
  1827. pfnWriteSD,
  1828. lpContext);
  1829. if (SUCCEEDED(hr))
  1830. {
  1831. PROPSHEETHEADERW psh;
  1832. psh.dwSize = SIZEOF(psh);
  1833. psh.dwFlags = PSH_DEFAULT;
  1834. psh.hwndParent = hwndOwner;
  1835. psh.hInstance = GLOBAL_HINSTANCE;
  1836. psh.pszCaption = pwszCaption;
  1837. psh.nPages = 1;
  1838. psh.nStartPage = 0;
  1839. psh.phpage = &hPage;
  1840. PropertySheetW(&psh);
  1841. }
  1842. }
  1843. else
  1844. {
  1845. // This method creates a caption like "Permissions for Foo"
  1846. hr = DSCreateISecurityInfoObject(pwszObjectPath,
  1847. pwszObjectClass,
  1848. dwFlags,
  1849. &pSI,
  1850. pfnReadSD,
  1851. pfnWriteSD,
  1852. lpContext);
  1853. if (SUCCEEDED(hr))
  1854. {
  1855. hr = _EditSecurity(hwndOwner, pSI);
  1856. DoRelease(pSI);
  1857. }
  1858. }
  1859. TraceLeaveResult(hr);
  1860. }
  1861. /*******************************************************************
  1862. NAME: GetLSAConnection
  1863. SYNOPSIS: Wrapper for LsaOpenPolicy
  1864. ENTRY: pszServer - the server on which to make the connection
  1865. EXIT:
  1866. RETURNS: LSA_HANDLE if successful, NULL otherwise
  1867. NOTES:
  1868. HISTORY:
  1869. JeffreyS 08-Oct-1996 Created
  1870. ********************************************************************/
  1871. LSA_HANDLE
  1872. GetLSAConnection(LPCTSTR pszServer, DWORD dwAccessDesired)
  1873. {
  1874. LSA_HANDLE hPolicy = NULL;
  1875. LSA_UNICODE_STRING uszServer = {0};
  1876. LSA_UNICODE_STRING *puszServer = NULL;
  1877. LSA_OBJECT_ATTRIBUTES oa;
  1878. SECURITY_QUALITY_OF_SERVICE sqos;
  1879. sqos.Length = SIZEOF(sqos);
  1880. sqos.ImpersonationLevel = SecurityImpersonation;
  1881. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1882. sqos.EffectiveOnly = FALSE;
  1883. InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
  1884. oa.SecurityQualityOfService = &sqos;
  1885. if (pszServer &&
  1886. *pszServer &&
  1887. RtlCreateUnicodeString(&uszServer, pszServer))
  1888. {
  1889. puszServer = &uszServer;
  1890. }
  1891. LsaOpenPolicy(puszServer, &oa, dwAccessDesired, &hPolicy);
  1892. if (puszServer)
  1893. RtlFreeUnicodeString(puszServer);
  1894. return hPolicy;
  1895. }
  1896. HRESULT
  1897. GetDomainSid(LPCWSTR pszServer, PSID *ppSid)
  1898. {
  1899. HRESULT hr = S_OK;
  1900. NTSTATUS nts = STATUS_SUCCESS;
  1901. PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo = NULL;
  1902. if(!pszServer || !ppSid)
  1903. return E_INVALIDARG;
  1904. *ppSid = NULL;
  1905. LSA_HANDLE hLSA = GetLSAConnection(pszServer, POLICY_VIEW_LOCAL_INFORMATION);
  1906. if (!hLSA)
  1907. {
  1908. hr = E_FAIL;
  1909. goto exit_gracefully;
  1910. }
  1911. nts = LsaQueryInformationPolicy(hLSA,
  1912. PolicyAccountDomainInformation,
  1913. (PVOID*)&pDomainInfo);
  1914. if(nts != STATUS_SUCCESS)
  1915. {
  1916. hr = E_FAIL;
  1917. goto exit_gracefully;
  1918. }
  1919. if (pDomainInfo && pDomainInfo->DomainSid)
  1920. {
  1921. ULONG cbSid = GetLengthSid(pDomainInfo->DomainSid);
  1922. *ppSid = (PSID) LocalAlloc(LPTR, cbSid);
  1923. if (!*ppSid)
  1924. {
  1925. hr = E_OUTOFMEMORY;
  1926. goto exit_gracefully;
  1927. }
  1928. CopyMemory(*ppSid, pDomainInfo->DomainSid, cbSid);
  1929. }
  1930. exit_gracefully:
  1931. if(pDomainInfo)
  1932. LsaFreeMemory(pDomainInfo);
  1933. if(hLSA)
  1934. LsaClose(hLSA);
  1935. return hr;
  1936. }
  1937. //
  1938. // include and defines for ldap calls
  1939. //
  1940. #include <winldap.h>
  1941. #include <ntldap.h>
  1942. typedef LDAP * (LDAPAPI *PFN_LDAP_OPEN)( PWCHAR, ULONG );
  1943. typedef ULONG (LDAPAPI *PFN_LDAP_UNBIND)( LDAP * );
  1944. typedef ULONG (LDAPAPI *PFN_LDAP_SEARCH)(LDAP *, PWCHAR, ULONG, PWCHAR, PWCHAR *, ULONG,PLDAPControlA *, PLDAPControlA *, struct l_timeval *, ULONG, LDAPMessage **);
  1945. typedef LDAPMessage * (LDAPAPI *PFN_LDAP_FIRST_ENTRY)( LDAP *, LDAPMessage * );
  1946. typedef PWCHAR * (LDAPAPI *PFN_LDAP_GET_VALUE)(LDAP *, LDAPMessage *, PWCHAR );
  1947. typedef ULONG (LDAPAPI *PFN_LDAP_MSGFREE)( LDAPMessage * );
  1948. typedef ULONG (LDAPAPI *PFN_LDAP_VALUE_FREE)( PWCHAR * );
  1949. typedef ULONG (LDAPAPI *PFN_LDAP_MAP_ERROR)( ULONG );
  1950. HRESULT
  1951. GetRootDomainSid(LPCWSTR pszServer, PSID *ppSid)
  1952. {
  1953. //
  1954. // get root domain sid, save it in RootDomSidBuf (global)
  1955. // this function is called within the critical section
  1956. //
  1957. // 1) ldap_open to the DC of interest.
  1958. // 2) you do not need to ldap_connect - the following step works anonymously
  1959. // 3) read the operational attribute rootDomainNamingContext and provide the
  1960. // operational control LDAP_SERVER_EXTENDED_DN_OID as defined in sdk\inc\ntldap.h.
  1961. DWORD Win32rc=NO_ERROR;
  1962. HINSTANCE hLdapDll=NULL;
  1963. PFN_LDAP_OPEN pfnLdapOpen=NULL;
  1964. PFN_LDAP_UNBIND pfnLdapUnbind=NULL;
  1965. PFN_LDAP_SEARCH pfnLdapSearch=NULL;
  1966. PFN_LDAP_FIRST_ENTRY pfnLdapFirstEntry=NULL;
  1967. PFN_LDAP_GET_VALUE pfnLdapGetValue=NULL;
  1968. PFN_LDAP_MSGFREE pfnLdapMsgFree=NULL;
  1969. PFN_LDAP_VALUE_FREE pfnLdapValueFree=NULL;
  1970. PFN_LDAP_MAP_ERROR pfnLdapMapError=NULL;
  1971. PLDAP phLdap=NULL;
  1972. LDAPControlW serverControls = { LDAP_SERVER_EXTENDED_DN_OID_W,
  1973. { 0, NULL },
  1974. TRUE
  1975. };
  1976. LPWSTR Attribs[] = { LDAP_OPATT_ROOT_DOMAIN_NAMING_CONTEXT_W, NULL };
  1977. PLDAPControlW rServerControls[] = { &serverControls, NULL };
  1978. PLDAPMessage pMessage = NULL;
  1979. LDAPMessage *pEntry = NULL;
  1980. PWCHAR *ppszValues=NULL;
  1981. LPWSTR pSidStart, pSidEnd, pParse;
  1982. BYTE *pDest = NULL;
  1983. BYTE OneByte;
  1984. DWORD RootDomSidBuf[sizeof(SID)/sizeof(DWORD)+5];
  1985. hLdapDll = LoadLibraryA("wldap32.dll");
  1986. if ( hLdapDll)
  1987. {
  1988. pfnLdapOpen = (PFN_LDAP_OPEN)GetProcAddress(hLdapDll,
  1989. "ldap_openW");
  1990. pfnLdapUnbind = (PFN_LDAP_UNBIND)GetProcAddress(hLdapDll,
  1991. "ldap_unbind");
  1992. pfnLdapSearch = (PFN_LDAP_SEARCH)GetProcAddress(hLdapDll,
  1993. "ldap_search_ext_sW");
  1994. pfnLdapFirstEntry = (PFN_LDAP_FIRST_ENTRY)GetProcAddress(hLdapDll,
  1995. "ldap_first_entry");
  1996. pfnLdapGetValue = (PFN_LDAP_GET_VALUE)GetProcAddress(hLdapDll,
  1997. "ldap_get_valuesW");
  1998. pfnLdapMsgFree = (PFN_LDAP_MSGFREE)GetProcAddress(hLdapDll,
  1999. "ldap_msgfree");
  2000. pfnLdapValueFree = (PFN_LDAP_VALUE_FREE)GetProcAddress(hLdapDll,
  2001. "ldap_value_freeW");
  2002. pfnLdapMapError = (PFN_LDAP_MAP_ERROR)GetProcAddress(hLdapDll,
  2003. "LdapMapErrorToWin32");
  2004. }
  2005. if ( pfnLdapOpen == NULL ||
  2006. pfnLdapUnbind == NULL ||
  2007. pfnLdapSearch == NULL ||
  2008. pfnLdapFirstEntry == NULL ||
  2009. pfnLdapGetValue == NULL ||
  2010. pfnLdapMsgFree == NULL ||
  2011. pfnLdapValueFree == NULL ||
  2012. pfnLdapMapError == NULL )
  2013. {
  2014. Win32rc = ERROR_PROC_NOT_FOUND;
  2015. } else
  2016. {
  2017. //
  2018. // bind to ldap
  2019. //
  2020. phLdap = (*pfnLdapOpen)((PWCHAR)pszServer, LDAP_PORT);
  2021. if ( phLdap == NULL )
  2022. Win32rc = ERROR_FILE_NOT_FOUND;
  2023. }
  2024. if ( NO_ERROR == Win32rc )
  2025. {
  2026. //
  2027. // now get the ldap handle,
  2028. //
  2029. Win32rc = (*pfnLdapSearch)(
  2030. phLdap,
  2031. L"",
  2032. LDAP_SCOPE_BASE,
  2033. L"(objectClass=*)",
  2034. Attribs,
  2035. 0,
  2036. (PLDAPControlA *)&rServerControls,
  2037. NULL,
  2038. NULL,
  2039. 10000,
  2040. &pMessage);
  2041. if( Win32rc == NO_ERROR && pMessage )
  2042. {
  2043. Win32rc = ERROR_SUCCESS;
  2044. pEntry = (*pfnLdapFirstEntry)(phLdap, pMessage);
  2045. if(pEntry == NULL)
  2046. {
  2047. Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
  2048. } else
  2049. {
  2050. //
  2051. // Now, we'll have to get the values
  2052. //
  2053. ppszValues = (*pfnLdapGetValue)(phLdap,
  2054. pEntry,
  2055. Attribs[0]);
  2056. if( ppszValues == NULL)
  2057. {
  2058. Win32rc = (*pfnLdapMapError)( phLdap->ld_errno );
  2059. } else if ( ppszValues[0] && ppszValues[0][0] != '\0' )
  2060. {
  2061. //
  2062. // ppszValues[0] is the value to parse.
  2063. // The data will be returned as something like:
  2064. // <GUID=278676f8d753d211a61ad7e2dfa25f11>;<SID=010400000000000515000000828ba6289b0bc11e67c2ef7f>;DC=colinbrdom1,DC=nttest,DC=microsoft,DC=com
  2065. // Parse through this to find the <SID=xxxxxx> part. Note that it may be missing, but the GUID= and trailer should not be.
  2066. // The xxxxx represents the hex nibbles of the SID. Translate to the binary form and case to a SID.
  2067. pSidStart = wcsstr(ppszValues[0], L"<SID=");
  2068. if ( pSidStart )
  2069. {
  2070. //
  2071. // find the end of this SID
  2072. //
  2073. pSidEnd = wcsstr(pSidStart, L">");
  2074. if ( pSidEnd )
  2075. {
  2076. pParse = pSidStart + 5;
  2077. pDest = (BYTE *)RootDomSidBuf;
  2078. while ( pParse < pSidEnd-1 )
  2079. {
  2080. if ( *pParse >= '0' && *pParse <= '9' )
  2081. {
  2082. OneByte = (BYTE) ((*pParse - '0') * 16);
  2083. }
  2084. else
  2085. {
  2086. OneByte = (BYTE) ( (tolower(*pParse) - 'a' + 10) * 16 );
  2087. }
  2088. if ( *(pParse+1) >= '0' && *(pParse+1) <= '9' )
  2089. {
  2090. OneByte = OneByte + (BYTE) ( (*(pParse+1)) - '0' ) ;
  2091. }
  2092. else
  2093. {
  2094. OneByte = OneByte + (BYTE) ( tolower(*(pParse+1)) - 'a' + 10 ) ;
  2095. }
  2096. *pDest = OneByte;
  2097. pDest++;
  2098. pParse += 2;
  2099. }
  2100. ULONG cbSid = GetLengthSid((PSID)RootDomSidBuf);
  2101. *ppSid = (PSID) LocalAlloc(LPTR, cbSid);
  2102. if (!*ppSid)
  2103. {
  2104. Win32rc = ERROR_NOT_ENOUGH_MEMORY;
  2105. }
  2106. CopyMemory(*ppSid, (PSID)RootDomSidBuf, cbSid);
  2107. ASSERT(IsValidSid(*ppSid));
  2108. } else
  2109. {
  2110. Win32rc = ERROR_OBJECT_NOT_FOUND;
  2111. }
  2112. } else
  2113. {
  2114. Win32rc = ERROR_OBJECT_NOT_FOUND;
  2115. }
  2116. (*pfnLdapValueFree)(ppszValues);
  2117. } else
  2118. {
  2119. Win32rc = ERROR_OBJECT_NOT_FOUND;
  2120. }
  2121. }
  2122. (*pfnLdapMsgFree)(pMessage);
  2123. }
  2124. }
  2125. //
  2126. // even though it's not binded, use unbind to close
  2127. //
  2128. if ( phLdap != NULL && pfnLdapUnbind )
  2129. (*pfnLdapUnbind)(phLdap);
  2130. if ( hLdapDll )
  2131. {
  2132. FreeLibrary(hLdapDll);
  2133. }
  2134. return HRESULT_FROM_WIN32(Win32rc);
  2135. }
  2136. BOOL
  2137. IsRootObject(IDirectoryObject * pDirObject)
  2138. {
  2139. if(!pDirObject)
  2140. {
  2141. ASSERT(pDirObject);
  2142. return FALSE;
  2143. }
  2144. LPWSTR pAttrNames[]={L"instanceType"};
  2145. DWORD dwNumAttr= ARRAYSIZE(pAttrNames);
  2146. ADS_ATTR_INFO *pAttrInfo=NULL;
  2147. DWORD dwReturn = 0;
  2148. HRESULT hr = pDirObject->GetObjectAttributes( pAttrNames,
  2149. dwNumAttr,
  2150. &pAttrInfo,
  2151. &dwReturn );
  2152. if(FAILED(hr) || dwReturn != 1 )
  2153. return FALSE;
  2154. ASSERT(ADSTYPE_INTEGER == pAttrInfo->dwADsType);
  2155. int InstanceType = pAttrInfo[0].pADsValues->Integer;
  2156. FreeADsMem( pAttrInfo );
  2157. if(InstanceType & DS_INSTANCETYPE_IS_NC_HEAD)
  2158. return TRUE;
  2159. else
  2160. return FALSE;
  2161. }