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.

779 lines
15 KiB

  1. /*++
  2. Copyright (c) 1994-1999 Microsoft Corporation
  3. Module Name :
  4. accentry.cpp
  5. Abstract:
  6. CAccessEntry class implementation
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Project:
  10. Internet Services Manager
  11. Revision History:
  12. 1/9/2000 sergeia Cleaned out from usrbrows.cpp
  13. --*/
  14. //
  15. // Include Files
  16. //
  17. #include "stdafx.h"
  18. #include <iiscnfgp.h>
  19. #include "common.h"
  20. #include "objpick.h"
  21. #include "accentry.h"
  22. #ifdef _DEBUG
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif
  26. #define new DEBUG_NEW
  27. #define SZ_USER_CLASS _T("user")
  28. #define SZ_GROUP_CLASS _T("group")
  29. BOOL
  30. CAccessEntry::LookupAccountSid(
  31. OUT CString & strFullUserName,
  32. OUT int & nPictureID,
  33. IN PSID pSid,
  34. IN LPCTSTR lpstrSystemName /* OPTIONAL */
  35. )
  36. /*++
  37. Routine Description:
  38. Get a full user name and picture ID from the SID
  39. Arguments:
  40. CString &strFullUserName : Returns the user name
  41. int & nPictureID : Returns offset into the imagemap that
  42. represents the account type.
  43. PSID pSid : Input SID pointer
  44. LPCTSTR lpstrSystemName : System name or NULL
  45. Return Value:
  46. TRUE for success, FALSE for failure.
  47. --*/
  48. {
  49. DWORD cbUserName = PATHLEN * sizeof(TCHAR);
  50. DWORD cbRefDomainName = PATHLEN * sizeof(TCHAR);
  51. CString strUserName;
  52. CString strRefDomainName;
  53. SID_NAME_USE SidToNameUse;
  54. LPTSTR lpUserName = strUserName.GetBuffer(PATHLEN);
  55. LPTSTR lpRefDomainName = strRefDomainName.GetBuffer(PATHLEN);
  56. BOOL fLookUpOK = ::LookupAccountSid(
  57. lpstrSystemName,
  58. pSid,
  59. lpUserName,
  60. &cbUserName,
  61. lpRefDomainName,
  62. &cbRefDomainName,
  63. &SidToNameUse
  64. );
  65. strUserName.ReleaseBuffer();
  66. strRefDomainName.ReleaseBuffer();
  67. strFullUserName.Empty();
  68. if (fLookUpOK)
  69. {
  70. if (!strRefDomainName.IsEmpty()
  71. && strRefDomainName.CompareNoCase(_T("BUILTIN")))
  72. {
  73. strFullUserName += strRefDomainName;
  74. strFullUserName += "\\";
  75. }
  76. strFullUserName += strUserName;
  77. nPictureID = SidToNameUse;
  78. }
  79. else
  80. {
  81. strFullUserName.LoadString(IDS_UNKNOWN_USER);
  82. nPictureID = SidTypeUnknown;
  83. }
  84. //
  85. // SID_NAME_USE is 1-based
  86. //
  87. --nPictureID ;
  88. return fLookUpOK;
  89. }
  90. CAccessEntry::CAccessEntry(
  91. IN LPVOID pAce,
  92. IN BOOL fResolveSID
  93. )
  94. /*++
  95. Routine Description:
  96. Construct from an ACE
  97. Arguments:
  98. LPVOID pAce : Pointer to ACE object
  99. BOOL fResolveSID : TRUE to resolve the SID immediately
  100. Return Value:
  101. N/A
  102. --*/
  103. : m_pSid(NULL),
  104. m_fSIDResolved(FALSE),
  105. m_fDeletable(TRUE),
  106. m_fInvisible(FALSE),
  107. m_nPictureID(SidTypeUnknown-1), // SID_NAME_USE is 1-based
  108. m_lpstrSystemName(NULL),
  109. m_accMask(0L),
  110. m_fDeleted(FALSE),
  111. m_strUserName()
  112. {
  113. MarkEntryAsClean();
  114. PACE_HEADER ph = (PACE_HEADER)pAce;
  115. PSID pSID = NULL;
  116. switch(ph->AceType)
  117. {
  118. case ACCESS_ALLOWED_ACE_TYPE:
  119. pSID = (PSID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
  120. m_accMask = ((PACCESS_ALLOWED_ACE)pAce)->Mask;
  121. break;
  122. case ACCESS_DENIED_ACE_TYPE:
  123. case SYSTEM_AUDIT_ACE_TYPE:
  124. case SYSTEM_ALARM_ACE_TYPE:
  125. default:
  126. //
  127. // Not supported!
  128. //
  129. ASSERT_MSG("Unsupported ACE type");
  130. break;
  131. }
  132. if (pSID == NULL)
  133. {
  134. return;
  135. }
  136. //
  137. // Allocate a new copy of the sid.
  138. //
  139. DWORD cbSize = ::RtlLengthSid(pSID);
  140. m_pSid = (PSID)AllocMem(cbSize);
  141. if (m_pSid != NULL)
  142. {
  143. DWORD err = ::RtlCopySid(cbSize, m_pSid, pSID);
  144. ASSERT(err == ERROR_SUCCESS);
  145. }
  146. //
  147. // Only the non-deletable administrators have execute
  148. // privileges
  149. //
  150. m_fDeletable = (m_accMask & FILE_EXECUTE) == 0L;
  151. //
  152. // Enum_keys is a special access right that literally "everyone"
  153. // has, but it doesn't designate an operator, so it should not
  154. // show up in the operator list if this is the only right it has.
  155. //
  156. m_fInvisible = (m_accMask == MD_ACR_ENUM_KEYS);
  157. //SetAccessMask(lpAccessEntry);
  158. if (fResolveSID)
  159. {
  160. ResolveSID();
  161. }
  162. }
  163. CAccessEntry::CAccessEntry(
  164. IN ACCESS_MASK accPermissions,
  165. IN PSID pSid,
  166. IN LPCTSTR lpstrSystemName, OPTIONAL
  167. IN BOOL fResolveSID
  168. )
  169. /*++
  170. Routine Description:
  171. Constructor from access permissions and SID.
  172. Arguments:
  173. ACCESS_MASK accPermissions : Access mask
  174. PSID pSid : Pointer to SID
  175. LPCTSTR lpstrSystemName : Optional system name
  176. BOOL fResolveSID : TRUE to resolve SID immediately
  177. Return Value:
  178. N/A
  179. --*/
  180. : m_pSid(NULL),
  181. m_fSIDResolved(FALSE),
  182. m_fDeletable(TRUE),
  183. m_fInvisible(FALSE),
  184. m_fDeleted(FALSE),
  185. m_nPictureID(SidTypeUnknown-1), // SID_NAME_USE is 1-based
  186. m_strUserName(),
  187. m_lpstrSystemName(NULL),
  188. m_accMask(accPermissions)
  189. {
  190. MarkEntryAsClean();
  191. //
  192. // Allocate a new copy of the sid.
  193. //
  194. DWORD cbSize = ::RtlLengthSid(pSid);
  195. m_pSid = (PSID)AllocMem(cbSize);
  196. if (m_pSid != NULL)
  197. {
  198. DWORD err = ::RtlCopySid(cbSize, m_pSid, pSid);
  199. ASSERT(err == ERROR_SUCCESS);
  200. }
  201. if (lpstrSystemName != NULL)
  202. {
  203. m_lpstrSystemName = AllocTString(::lstrlen(lpstrSystemName) + 1);
  204. if (m_lpstrSystemName != NULL)
  205. {
  206. ::lstrcpy(m_lpstrSystemName, lpstrSystemName);
  207. }
  208. }
  209. if (fResolveSID)
  210. {
  211. TRACEEOLID("Bogus SID");
  212. ResolveSID();
  213. }
  214. }
  215. CAccessEntry::CAccessEntry(
  216. IN PSID pSid,
  217. IN LPCTSTR pszUserName,
  218. IN LPCTSTR pszClassName
  219. )
  220. /*++
  221. Routine Description:
  222. Constructor from access sid and user/class name.
  223. Arguments:
  224. PSID pSid, Pointer to SID
  225. LPCTSTR pszUserName User name
  226. LPCTSTR pszClassName User Class name
  227. Return Value:
  228. N/A
  229. --*/
  230. : m_pSid(NULL),
  231. m_fSIDResolved(pszUserName != NULL),
  232. m_fDeletable(TRUE),
  233. m_fInvisible(FALSE),
  234. m_fDeleted(FALSE),
  235. m_nPictureID(SidTypeUnknown-1), // SID_NAME_USE is 1-based
  236. m_strUserName(pszUserName),
  237. m_lpstrSystemName(NULL),
  238. m_accMask(0)
  239. {
  240. MarkEntryAsClean();
  241. //
  242. // Allocate a new copy of the sid.
  243. //
  244. DWORD cbSize = ::RtlLengthSid(pSid);
  245. m_pSid = (PSID)AllocMem(cbSize);
  246. if (m_pSid != NULL)
  247. {
  248. DWORD err = ::RtlCopySid(cbSize, m_pSid, pSid);
  249. ASSERT(err == ERROR_SUCCESS);
  250. }
  251. if (lstrcmpi(SZ_USER_CLASS, pszClassName) == 0)
  252. {
  253. m_nPictureID = SidTypeUser - 1;
  254. }
  255. else if (lstrcmpi(SZ_GROUP_CLASS, pszClassName) == 0)
  256. {
  257. m_nPictureID = SidTypeGroup - 1;
  258. }
  259. }
  260. CAccessEntry::CAccessEntry(
  261. IN CAccessEntry & ae
  262. )
  263. /*++
  264. Routine Description:
  265. Copy constructor
  266. Arguments:
  267. CAccessEntry & ae : Source to copy from
  268. Return Value:
  269. N/A
  270. --*/
  271. : m_fSIDResolved(ae.m_fSIDResolved),
  272. m_fDeletable(ae.m_fDeletable),
  273. m_fInvisible(ae.m_fInvisible),
  274. m_fDeleted(ae.m_fDeleted),
  275. m_fDirty(ae.m_fDirty),
  276. m_nPictureID(ae.m_nPictureID),
  277. m_strUserName(ae.m_strUserName),
  278. m_lpstrSystemName(ae.m_lpstrSystemName),
  279. m_accMask(ae.m_accMask)
  280. {
  281. DWORD cbSize = ::RtlLengthSid(ae.m_pSid);
  282. m_pSid = (PSID)AllocMem(cbSize);
  283. if (m_pSid != NULL)
  284. {
  285. DWORD err = ::RtlCopySid(cbSize, m_pSid, ae.m_pSid);
  286. ASSERT(err == ERROR_SUCCESS);
  287. }
  288. }
  289. CAccessEntry::~CAccessEntry()
  290. /*++
  291. Routine Description:
  292. Destructor
  293. Arguments:
  294. N/A
  295. Return Value:
  296. N/A
  297. --*/
  298. {
  299. TRACEEOLID(_T("Destroying local copy of the SID"));
  300. ASSERT_PTR(m_pSid);
  301. FreeMem(m_pSid);
  302. if (m_lpstrSystemName != NULL)
  303. {
  304. FreeMem(m_lpstrSystemName);
  305. }
  306. }
  307. BOOL
  308. CAccessEntry::ResolveSID()
  309. /*++
  310. Routine Description:
  311. Look up the user name and type.
  312. Arguments:
  313. None
  314. Return Value:
  315. TRUE for success, FALSE for failure.
  316. Notes:
  317. This could take some time.
  318. --*/
  319. {
  320. //
  321. // Even if it fails, it will be considered
  322. // resolved
  323. //
  324. m_fSIDResolved = TRUE;
  325. return CAccessEntry::LookupAccountSid(
  326. m_strUserName,
  327. m_nPictureID,
  328. m_pSid,
  329. m_lpstrSystemName
  330. );
  331. }
  332. void
  333. CAccessEntry::AddPermissions(
  334. IN ACCESS_MASK accNewPermissions
  335. )
  336. /*++
  337. Routine Description:
  338. Add permissions to this entry.
  339. Arguments:
  340. ACCESS_MASK accNewPermissions : New access permissions to be added
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. m_accMask |= accNewPermissions;
  346. m_fInvisible = (m_accMask == MD_ACR_ENUM_KEYS);
  347. m_fDeletable = (m_accMask & FILE_EXECUTE) == 0L;
  348. MarkEntryAsChanged();
  349. }
  350. void
  351. CAccessEntry::RemovePermissions(
  352. IN ACCESS_MASK accPermissions
  353. )
  354. /*++
  355. Routine Description:
  356. Remove permissions from this entry.
  357. Arguments:
  358. ACCESS_MASK accPermissions : Access permissions to be taken away
  359. --*/
  360. {
  361. m_accMask &= ~accPermissions;
  362. MarkEntryAsChanged();
  363. }
  364. //
  365. // Helper Functions
  366. //
  367. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  368. PSID
  369. GetOwnerSID()
  370. /*++
  371. Routine Description:
  372. Return a pointer to the primary owner SID we're using.
  373. Arguments:
  374. None
  375. Return Value:
  376. Pointer to owner SID.
  377. --*/
  378. {
  379. PSID pSID = NULL;
  380. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  381. if (!::AllocateAndInitializeSid(
  382. &NtAuthority,
  383. 2,
  384. SECURITY_BUILTIN_DOMAIN_RID,
  385. DOMAIN_ALIAS_RID_ADMINS,
  386. 0, 0, 0, 0, 0, 0,
  387. &pSID
  388. ))
  389. {
  390. TRACEEOLID("Unable to get primary SID " << ::GetLastError());
  391. }
  392. return pSID;
  393. }
  394. BOOL
  395. BuildAclBlob(
  396. IN CObListPlus & oblSID,
  397. OUT CBlob & blob
  398. )
  399. /*++
  400. Routine Description:
  401. Build a security descriptor blob from the access entries in the oblist
  402. Arguments:
  403. CObListPlus & oblSID : Input list of access entries
  404. CBlob & blob : Output blob
  405. Return Value:
  406. TRUE if the list is dirty. If the list had no entries marked
  407. as dirty, the blob generated will be empty, and this function will
  408. return FALSE.
  409. Notes:
  410. Entries marked as deleted will not be added to the list.
  411. --*/
  412. {
  413. ASSERT(blob.IsEmpty());
  414. BOOL fAclDirty = FALSE;
  415. CAccessEntry * pEntry;
  416. DWORD dwAclSize = sizeof(ACL) - sizeof(DWORD);
  417. CObListIter obli(oblSID);
  418. int cItems = 0;
  419. while(NULL != (pEntry = (CAccessEntry *)obli.Next()))
  420. {
  421. if (!pEntry->IsDeleted())
  422. {
  423. dwAclSize += GetLengthSid(pEntry->GetSid());
  424. dwAclSize += sizeof(ACCESS_ALLOWED_ACE);
  425. ++cItems;
  426. }
  427. if (pEntry->IsDirty())
  428. {
  429. fAclDirty = TRUE;
  430. }
  431. }
  432. if (fAclDirty)
  433. {
  434. //
  435. // Build the acl
  436. //
  437. PACL pacl = NULL;
  438. if (cItems > 0 && dwAclSize > 0)
  439. {
  440. pacl = (PACL)AllocMem(dwAclSize);
  441. if (pacl != NULL)
  442. {
  443. if (InitializeAcl(pacl, dwAclSize, ACL_REVISION))
  444. {
  445. obli.Reset();
  446. while(NULL != (pEntry = (CAccessEntry *)obli.Next()))
  447. {
  448. if (!pEntry->IsDeleted())
  449. {
  450. VERIFY(AddAccessAllowedAce(
  451. pacl,
  452. ACL_REVISION,
  453. pEntry->QueryAccessMask(),
  454. pEntry->GetSid()
  455. ));
  456. }
  457. }
  458. }
  459. }
  460. else
  461. {
  462. return FALSE;
  463. }
  464. }
  465. //
  466. // Build the security descriptor
  467. //
  468. PSECURITY_DESCRIPTOR pSD =
  469. (PSECURITY_DESCRIPTOR)AllocMem(SECURITY_DESCRIPTOR_MIN_LENGTH);
  470. if (pSD != NULL)
  471. {
  472. VERIFY(InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION));
  473. VERIFY(SetSecurityDescriptorDacl(pSD, TRUE, pacl, FALSE));
  474. }
  475. else
  476. {
  477. return FALSE;
  478. }
  479. //
  480. // Set owner and primary group
  481. //
  482. PSID pSID = GetOwnerSID();
  483. ASSERT(pSID);
  484. VERIFY(SetSecurityDescriptorOwner(pSD, pSID, TRUE));
  485. VERIFY(SetSecurityDescriptorGroup(pSD, pSID, TRUE));
  486. //
  487. // Convert to self-relative
  488. //
  489. PSECURITY_DESCRIPTOR pSDSelfRelative = NULL;
  490. DWORD dwSize = 0L;
  491. MakeSelfRelativeSD(pSD, pSDSelfRelative, &dwSize);
  492. pSDSelfRelative = AllocMem(dwSize);
  493. if (pSDSelfRelative != NULL)
  494. {
  495. MakeSelfRelativeSD(pSD, pSDSelfRelative, &dwSize);
  496. //
  497. // Blob takes ownership
  498. //
  499. blob.SetValue(dwSize, (PBYTE)pSDSelfRelative, FALSE);
  500. }
  501. //
  502. // Clean up
  503. //
  504. FreeMem(pSD);
  505. FreeSid(pSID);
  506. }
  507. return fAclDirty;
  508. }
  509. DWORD
  510. BuildAclOblistFromBlob(
  511. IN CBlob & blob,
  512. OUT CObListPlus & oblSID
  513. )
  514. /*++
  515. Routine Description:
  516. Build an oblist of access entries from a security descriptor blob
  517. Arguments:
  518. CBlob & blob : Input blob
  519. CObListPlus & oblSID : Output oblist of access entries
  520. Return Value:
  521. Error return code
  522. --*/
  523. {
  524. PSECURITY_DESCRIPTOR pSD = NULL;
  525. if (!blob.IsEmpty())
  526. {
  527. pSD = (PSECURITY_DESCRIPTOR)blob.GetData();
  528. }
  529. if (pSD == NULL)
  530. {
  531. //
  532. // Empty...
  533. //
  534. return ERROR_SUCCESS;
  535. }
  536. if (!IsValidSecurityDescriptor(pSD))
  537. {
  538. return ::GetLastError();
  539. }
  540. ASSERT(GetSecurityDescriptorLength(pSD) == blob.GetSize());
  541. PACL pacl = NULL;
  542. BOOL fDaclPresent = FALSE;
  543. BOOL fDaclDef= FALSE;
  544. VERIFY(GetSecurityDescriptorDacl(pSD, &fDaclPresent, &pacl, &fDaclDef));
  545. if (!fDaclPresent || pacl == NULL)
  546. {
  547. return ERROR_SUCCESS;
  548. }
  549. if (!IsValidAcl(pacl))
  550. {
  551. return GetLastError();
  552. }
  553. CError err;
  554. for (WORD w = 0; w < pacl->AceCount; ++w)
  555. {
  556. PVOID pAce;
  557. if (GetAce(pacl, w, &pAce))
  558. {
  559. CAccessEntry * pEntry = new CAccessEntry(pAce, TRUE);
  560. if (pEntry)
  561. {
  562. oblSID.AddTail(pEntry);
  563. }
  564. else
  565. {
  566. TRACEEOLID("BuildAclOblistFromBlob: OOM");
  567. err = ERROR_NOT_ENOUGH_MEMORY;
  568. break;
  569. }
  570. }
  571. else
  572. {
  573. //
  574. // Save last error, but continue
  575. //
  576. err.GetLastWinError();
  577. }
  578. }
  579. //
  580. // Return last error
  581. //
  582. return err;
  583. }