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.

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