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.

603 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: si.cpp
  8. //
  9. // This file contains the implementation of the CSecurityInformation
  10. // base class.
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "rshx32.h"
  14. #include <shlapip.h>
  15. #include <dsrole.h>
  16. BOOL IsStandalone(LPCTSTR pszMachine, PBOOL pbIsDC)
  17. {
  18. BOOL bStandalone = TRUE;
  19. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  20. //
  21. // Find out if target machine is a standalone machine or joined to
  22. // an NT domain.
  23. //
  24. __try
  25. {
  26. if (pbIsDC)
  27. *pbIsDC = FALSE;
  28. DsRoleGetPrimaryDomainInformation(pszMachine,
  29. DsRolePrimaryDomainInfoBasic,
  30. (PBYTE*)&pDsRole);
  31. }
  32. __finally
  33. {
  34. }
  35. if (NULL != pDsRole)
  36. {
  37. if (pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation ||
  38. pDsRole->MachineRole == DsRole_RoleStandaloneServer)
  39. {
  40. bStandalone = TRUE;
  41. }
  42. else
  43. bStandalone = FALSE;
  44. if (pbIsDC)
  45. {
  46. if (pDsRole->MachineRole == DsRole_RolePrimaryDomainController ||
  47. pDsRole->MachineRole == DsRole_RoleBackupDomainController)
  48. {
  49. *pbIsDC = TRUE;
  50. }
  51. }
  52. DsRoleFreeMemory(pDsRole);
  53. }
  54. return bStandalone;
  55. }
  56. void
  57. ProtectACLs(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  58. {
  59. SECURITY_DESCRIPTOR_CONTROL wSDControl;
  60. DWORD dwRevision;
  61. PACL pAcl;
  62. BOOL bDefaulted;
  63. BOOL bPresent;
  64. PACE_HEADER pAce;
  65. UINT cAces;
  66. TraceEnter(TRACE_SI, "ProtectACLs");
  67. if (0 == si || NULL == pSD)
  68. TraceLeaveVoid(); // Nothing to do
  69. // Get the ACL protection control bits
  70. GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
  71. wSDControl &= SE_DACL_PROTECTED | SE_SACL_PROTECTED;
  72. if ((si & DACL_SECURITY_INFORMATION) && !(wSDControl & SE_DACL_PROTECTED))
  73. {
  74. wSDControl |= SE_DACL_PROTECTED;
  75. pAcl = NULL;
  76. GetSecurityDescriptorDacl(pSD, &bPresent, &pAcl, &bDefaulted);
  77. // Theoretically, modifying the DACL in this way can cause it to be
  78. // no longer canonical. However, the only way this can happen is if
  79. // there is an inherited Deny ACE and a non-inherited Allow ACE.
  80. // Since this function is only called for root objects, this means
  81. // a) the server DACL must have a Deny ACE and b) the DACL on this
  82. // object must have been modified later. But if the DACL was
  83. // modified through the UI, then we would have eliminated all of the
  84. // Inherited ACEs already. Therefore, it must have been modified
  85. // through some other means. Considering that the DACL originally
  86. // inherited from the server never has a Deny ACE, this situation
  87. // should be extrememly rare. If it ever does happen, the ACL
  88. // Editor will just tell the user that the DACL is non-canonical.
  89. //
  90. // Therefore, let's ignore the possibility here.
  91. if (NULL != pAcl)
  92. {
  93. for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
  94. cAces > 0;
  95. --cAces, pAce = (PACE_HEADER)NextAce(pAce))
  96. {
  97. pAce->AceFlags &= ~INHERITED_ACE;
  98. }
  99. }
  100. }
  101. if ((si & SACL_SECURITY_INFORMATION) && !(wSDControl & SE_SACL_PROTECTED))
  102. {
  103. wSDControl |= SE_SACL_PROTECTED;
  104. pAcl = NULL;
  105. GetSecurityDescriptorSacl(pSD, &bPresent, &pAcl, &bDefaulted);
  106. if (NULL != pAcl)
  107. {
  108. for (cAces = pAcl->AceCount, pAce = (PACE_HEADER)FirstAce(pAcl);
  109. cAces > 0;
  110. --cAces, pAce = (PACE_HEADER)NextAce(pAce))
  111. {
  112. pAce->AceFlags &= ~INHERITED_ACE;
  113. }
  114. }
  115. }
  116. SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED | SE_SACL_PROTECTED, wSDControl);
  117. TraceLeaveVoid();
  118. }
  119. CSecurityInformation::CSecurityInformation(SE_OBJECT_TYPE seType)
  120. : m_cRef(1), m_seType(seType), m_hwndOwner(NULL),m_ResourceManager(NULL),m_bIsStandAlone(FALSE)
  121. {
  122. InterlockedIncrement(&g_cRefThisDll);
  123. AuthzInitializeResourceManager(AUTHZ_RM_FLAG_NO_AUDIT,
  124. NULL,
  125. NULL,
  126. NULL,
  127. L"Dummy",
  128. &m_ResourceManager );
  129. }
  130. CSecurityInformation::~CSecurityInformation()
  131. {
  132. LocalFreeDPA(m_hItemList);
  133. LocalFreeString(&m_pszObjectName);
  134. LocalFreeString(&m_pszServerName);
  135. AuthzFreeResourceManager(m_ResourceManager);
  136. ASSERT( 0 != g_cRefThisDll );
  137. InterlockedDecrement(&g_cRefThisDll);
  138. }
  139. STDMETHODIMP
  140. CSecurityInformation::Initialize(HDPA hItemList,
  141. DWORD dwFlags,
  142. LPTSTR pszServer,
  143. LPTSTR pszObject)
  144. {
  145. TraceEnter(TRACE_SI, "CSecurityInformation::Initialize");
  146. TraceAssert(hItemList != NULL);
  147. TraceAssert(DPA_GetPtrCount(hItemList) > 0);
  148. TraceAssert(pszObject != NULL);
  149. TraceAssert(m_pszObjectName == NULL); // only initialize once
  150. m_hItemList = hItemList;
  151. m_dwSIFlags = dwFlags;
  152. m_pszServerName = pszServer;
  153. m_pszObjectName = pszObject;
  154. m_bIsStandAlone = IsStandalone(pszServer, NULL);
  155. TraceLeaveResult(S_OK);
  156. }
  157. ///////////////////////////////////////////////////////////
  158. //
  159. // IUnknown methods
  160. //
  161. ///////////////////////////////////////////////////////////
  162. STDMETHODIMP_(ULONG)
  163. CSecurityInformation::AddRef()
  164. {
  165. return ++m_cRef;
  166. }
  167. STDMETHODIMP_(ULONG)
  168. CSecurityInformation::Release()
  169. {
  170. if (--m_cRef == 0)
  171. {
  172. delete this;
  173. return 0;
  174. }
  175. return m_cRef;
  176. }
  177. STDMETHODIMP
  178. CSecurityInformation::QueryInterface(REFIID riid, LPVOID FAR* ppv)
  179. {
  180. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ISecurityInformation))
  181. {
  182. *ppv = (LPSECURITYINFO)this;
  183. m_cRef++;
  184. return S_OK;
  185. }
  186. else if (IsEqualIID(riid, IID_IEffectivePermission))
  187. {
  188. *ppv = (LPEFFECTIVEPERMISSION)this;
  189. m_cRef++;
  190. return S_OK;
  191. }
  192. else if((m_seType != SE_PRINTER) && IsEqualIID(riid, IID_ISecurityObjectTypeInfo))
  193. {
  194. *ppv = (LPSecurityObjectTypeInfo)this;
  195. m_cRef++;
  196. return S_OK;
  197. }
  198. else
  199. {
  200. *ppv = NULL;
  201. return E_NOINTERFACE;
  202. }
  203. }
  204. ///////////////////////////////////////////////////////////
  205. //
  206. // ISecurityInformation methods
  207. //
  208. ///////////////////////////////////////////////////////////
  209. STDMETHODIMP
  210. CSecurityInformation::GetObjectInformation(PSI_OBJECT_INFO pObjectInfo)
  211. {
  212. TraceEnter(TRACE_SI, "CSecurityInformation::GetObjectInformation");
  213. TraceAssert(pObjectInfo != NULL &&
  214. !IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo)));
  215. pObjectInfo->dwFlags = m_dwSIFlags;
  216. pObjectInfo->hInstance = g_hInstance;
  217. pObjectInfo->pszServerName = m_pszServerName;
  218. pObjectInfo->pszObjectName = m_pszObjectName;
  219. TraceLeaveResult(S_OK);
  220. }
  221. STDMETHODIMP
  222. CSecurityInformation::GetSecurity(SECURITY_INFORMATION si,
  223. PSECURITY_DESCRIPTOR *ppSD,
  224. BOOL fDefault)
  225. {
  226. HRESULT hr = S_OK;
  227. LPTSTR pszItem;
  228. TraceEnter(TRACE_SI, "CSecurityInformation::GetSecurity");
  229. TraceAssert(si != 0);
  230. TraceAssert(ppSD != NULL);
  231. *ppSD = NULL;
  232. //Default security descriptor not supported
  233. if (fDefault)
  234. ExitGracefully(hr, E_NOTIMPL, "Default security descriptor not supported");
  235. // Get the name of the first item
  236. pszItem = (LPTSTR)DPA_GetPtr(m_hItemList, 0);
  237. if (NULL == pszItem)
  238. ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
  239. hr = ReadObjectSecurity(pszItem, si, ppSD);
  240. // If this is a Root object, then we pretend that the ACLs are
  241. // always protected and no ACEs are inherited.
  242. if (SUCCEEDED(hr) && (m_dwSIFlags & SI_NO_ACL_PROTECT))
  243. ProtectACLs(si & (DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION), *ppSD);
  244. exit_gracefully:
  245. TraceLeaveResult(hr);
  246. }
  247. STDMETHODIMP
  248. CSecurityInformation::SetSecurity(SECURITY_INFORMATION si,
  249. PSECURITY_DESCRIPTOR pSD)
  250. {
  251. HRESULT hr = S_OK;
  252. HCURSOR hcurPrevious = (HCURSOR)INVALID_HANDLE_VALUE;
  253. UINT cItems;
  254. int i;
  255. TraceEnter(TRACE_SI, "CSecurityInformation::SetSecurity");
  256. TraceAssert(si != 0);
  257. TraceAssert(pSD != NULL);
  258. if (NULL == m_hItemList)
  259. ExitGracefully(hr, E_UNEXPECTED, "CSecurityInformation not initialized");
  260. hcurPrevious = SetCursor(LoadCursor(NULL, IDC_WAIT));
  261. //
  262. // Apply the new permissions to every item in the list
  263. //
  264. for (i = 0; i < DPA_GetPtrCount(m_hItemList); i++)
  265. {
  266. LPTSTR pszItem = (LPTSTR)DPA_FastGetPtr(m_hItemList, i);
  267. hr = WriteObjectSecurity(pszItem, si, pSD);
  268. FailGracefully(hr, "Unable to write new security descriptor");
  269. if (IsFile()) // If this is a file, delete it's thumbnail from the database, it will get put back if appropriate
  270. {
  271. DeleteFileThumbnail(pszItem);
  272. }
  273. }
  274. exit_gracefully:
  275. // Restore previous cursor
  276. if (hcurPrevious != INVALID_HANDLE_VALUE)
  277. SetCursor(hcurPrevious);
  278. TraceLeaveResult(hr);
  279. }
  280. STDMETHODIMP
  281. CSecurityInformation::PropertySheetPageCallback(HWND hwnd,
  282. UINT uMsg,
  283. SI_PAGE_TYPE uPage)
  284. {
  285. if (SI_PAGE_PERM == uPage)
  286. {
  287. switch (uMsg)
  288. {
  289. case PSPCB_SI_INITDIALOG:
  290. do
  291. {
  292. m_hwndOwner = hwnd;
  293. } while (hwnd = GetParent(hwnd));
  294. break;
  295. case PSPCB_RELEASE:
  296. m_hwndOwner = NULL;
  297. break;
  298. }
  299. }
  300. return S_OK;
  301. }
  302. STDMETHODIMP
  303. CSecurityInformation::ReadObjectSecurity(LPCTSTR pszObject,
  304. SECURITY_INFORMATION si,
  305. PSECURITY_DESCRIPTOR *ppSD)
  306. {
  307. DWORD dwErr;
  308. TraceEnter(TRACE_SI, "CSecurityInformation::ReadObjectSecurity");
  309. TraceAssert(pszObject != NULL);
  310. TraceAssert(si != 0);
  311. TraceAssert(ppSD != NULL);
  312. //
  313. // This is kinda screwy. The new APIs are being removed from NT5, but have
  314. // already been added to NT4 SP4. The old APIs have new functionality on NT5,
  315. // but not on NT4 SPx. Since we need the new functionality (auto-inheritance),
  316. // we have to call the new (defunct) API on NT4 and the old API on NT5.
  317. //
  318. dwErr = GetNamedSecurityInfo((LPTSTR)pszObject,
  319. m_seType,
  320. si,
  321. NULL,
  322. NULL,
  323. NULL,
  324. NULL,
  325. ppSD);
  326. TraceLeaveResult(HRESULT_FROM_WIN32(dwErr));
  327. }
  328. STDMETHODIMP
  329. CSecurityInformation::WriteObjectSecurity(LPCTSTR pszObject,
  330. SECURITY_INFORMATION si,
  331. PSECURITY_DESCRIPTOR pSD)
  332. {
  333. DWORD dwErr;
  334. TraceEnter(TRACE_SI, "CSecurityInformation::WriteObjectSecurity");
  335. TraceAssert(pszObject != NULL);
  336. TraceAssert(si != 0);
  337. TraceAssert(pSD != NULL);
  338. //
  339. // This is kinda screwy. The new APIs are being removed from NT5, but have
  340. // already been added to NT4 SP4. The old APIs have new functionality on NT5,
  341. // but not on NT4 SPx. Since we need the new functionality (auto-inheritance),
  342. // we have to call the new (defunct) API on NT4 and the old API on NT5.
  343. //
  344. SECURITY_DESCRIPTOR_CONTROL wSDControl = 0;
  345. DWORD dwRevision;
  346. PSID psidOwner = NULL;
  347. PSID psidGroup = NULL;
  348. PACL pDacl = NULL;
  349. PACL pSacl = NULL;
  350. BOOL bDefaulted;
  351. BOOL bPresent;
  352. //
  353. // Get pointers to various security descriptor parts for
  354. // calling SetNamedSecurityInfo
  355. //
  356. GetSecurityDescriptorControl(pSD, &wSDControl, &dwRevision);
  357. GetSecurityDescriptorOwner(pSD, &psidOwner, &bDefaulted);
  358. GetSecurityDescriptorGroup(pSD, &psidGroup, &bDefaulted);
  359. GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted);
  360. GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted);
  361. if (si & DACL_SECURITY_INFORMATION)
  362. {
  363. if (wSDControl & SE_DACL_PROTECTED)
  364. si |= PROTECTED_DACL_SECURITY_INFORMATION;
  365. else
  366. si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
  367. }
  368. if (si & SACL_SECURITY_INFORMATION)
  369. {
  370. if (wSDControl & SE_SACL_PROTECTED)
  371. si |= PROTECTED_SACL_SECURITY_INFORMATION;
  372. else
  373. si |= UNPROTECTED_SACL_SECURITY_INFORMATION;
  374. }
  375. dwErr = SetNamedSecurityInfo((LPTSTR)pszObject,
  376. m_seType,
  377. si,
  378. psidOwner,
  379. psidGroup,
  380. pDacl,
  381. pSacl);
  382. TraceLeaveResult(HRESULT_FROM_WIN32(dwErr));
  383. }
  384. OBJECT_TYPE_LIST g_DefaultOTL[] = {
  385. {0, 0, (LPGUID)&GUID_NULL},
  386. };
  387. BOOL SkipLocalGroup(LPCWSTR pszServerName, PSID psid)
  388. {
  389. SID_NAME_USE use;
  390. WCHAR szAccountName[MAX_PATH];
  391. WCHAR szDomainName[MAX_PATH];
  392. DWORD dwAccountLen = MAX_PATH;
  393. DWORD dwDomainLen = MAX_PATH;
  394. if(LookupAccountSid(pszServerName,
  395. psid,
  396. szAccountName,
  397. &dwAccountLen,
  398. szDomainName,
  399. &dwDomainLen,
  400. &use))
  401. {
  402. if(use == SidTypeWellKnownGroup)
  403. return TRUE;
  404. }
  405. //Built In sids have first subauthority of 32 ( s-1-5-32 )
  406. //
  407. if((*(GetSidSubAuthorityCount(psid)) >= 1 ) && (*(GetSidSubAuthority(psid,0)) == 32))
  408. return TRUE;
  409. return FALSE;
  410. }
  411. STDMETHODIMP
  412. CSecurityInformation::GetEffectivePermission(const GUID* pguidObjectType,
  413. PSID pUserSid,
  414. LPCWSTR pszServerName,
  415. PSECURITY_DESCRIPTOR pSD,
  416. POBJECT_TYPE_LIST *ppObjectTypeList,
  417. ULONG *pcObjectTypeListLength,
  418. PACCESS_MASK *ppGrantedAccessList,
  419. ULONG *pcGrantedAccessListLength)
  420. {
  421. AUTHZ_RESOURCE_MANAGER_HANDLE RM = NULL; //Used for access check
  422. AUTHZ_CLIENT_CONTEXT_HANDLE CC = NULL;
  423. LUID luid = {0xdead,0xbeef};
  424. AUTHZ_ACCESS_REQUEST AReq;
  425. AUTHZ_ACCESS_REPLY AReply;
  426. HRESULT hr = S_OK;
  427. DWORD dwFlags;
  428. TraceEnter(TRACE_SI, "CDSSecurityInfo::GetEffectivePermission");
  429. TraceAssert(pUserSid && IsValidSecurityDescriptor(pSD));
  430. TraceAssert(ppObjectTypeList != NULL);
  431. TraceAssert(pcObjectTypeListLength != NULL);
  432. TraceAssert(ppGrantedAccessList != NULL);
  433. TraceAssert(pcGrantedAccessListLength != NULL);
  434. AReq.ObjectTypeList = g_DefaultOTL;
  435. AReq.ObjectTypeListLength = ARRAYSIZE(g_DefaultOTL);
  436. AReply.GrantedAccessMask = NULL;
  437. AReply.Error = NULL;
  438. //Get RM
  439. if( (RM = GetAUTHZ_RM()) == NULL )
  440. ExitGracefully(hr, E_UNEXPECTED, "LocalAlloc failed");
  441. //Initialize the client context
  442. BOOL bSkipLocalGroup = SkipLocalGroup(pszServerName, pUserSid);
  443. if( !AuthzInitializeContextFromSid(bSkipLocalGroup? AUTHZ_SKIP_TOKEN_GROUPS :0,
  444. pUserSid,
  445. RM,
  446. NULL,
  447. luid,
  448. NULL,
  449. &CC) )
  450. {
  451. DWORD dwErr = GetLastError();
  452. ExitGracefully(hr,
  453. HRESULT_FROM_WIN32(dwErr),
  454. "AuthzInitializeContextFromSid Failed");
  455. }
  456. //Do the Access Check
  457. AReq.DesiredAccess = MAXIMUM_ALLOWED;
  458. AReq.PrincipalSelfSid = NULL;
  459. AReq.OptionalArguments = NULL;
  460. AReply.ResultListLength = AReq.ObjectTypeListLength;
  461. AReply.SaclEvaluationResults = NULL;
  462. if( (AReply.GrantedAccessMask = (PACCESS_MASK)LocalAlloc(LPTR, sizeof(ACCESS_MASK)*AReply.ResultListLength) ) == NULL )
  463. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to LocalAlloc");
  464. if( (AReply.Error = (PDWORD)LocalAlloc(LPTR, sizeof(DWORD)*AReply.ResultListLength)) == NULL )
  465. ExitGracefully(hr, E_OUTOFMEMORY, "Unable to LocalAlloc");
  466. if( !AuthzAccessCheck(0,
  467. CC,
  468. &AReq,
  469. NULL,
  470. pSD,
  471. NULL,
  472. 0,
  473. &AReply,
  474. NULL) )
  475. {
  476. DWORD dwErr = GetLastError();
  477. ExitGracefully(hr,
  478. HRESULT_FROM_WIN32(dwErr),
  479. "AuthzAccessCheck Failed");
  480. }
  481. exit_gracefully:
  482. if(CC)
  483. AuthzFreeContext(CC);
  484. if(!SUCCEEDED(hr))
  485. {
  486. if(AReply.GrantedAccessMask)
  487. LocalFree(AReply.GrantedAccessMask);
  488. if(AReply.Error)
  489. LocalFree(AReply.Error);
  490. AReply.Error = NULL;
  491. AReply.GrantedAccessMask = NULL;
  492. }
  493. else
  494. {
  495. *ppObjectTypeList = AReq.ObjectTypeList;
  496. *pcObjectTypeListLength = AReq.ObjectTypeListLength;
  497. *ppGrantedAccessList = AReply.GrantedAccessMask;
  498. *pcGrantedAccessListLength = AReq.ObjectTypeListLength;
  499. }
  500. TraceLeaveResult(hr);
  501. }