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.

458 lines
13 KiB

  1. /*****************************************************************************/
  2. /* Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved /
  3. /*****************************************************************************/
  4. //=================================================================
  5. //
  6. // AccessRights.CPP -- Base class for obtaining effective access
  7. // rights.
  8. //
  9. // Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved
  10. //
  11. // Revisions: 6/11/99 a-kevhu Created
  12. //
  13. //=================================================================
  14. #include "precomp.h"
  15. #ifdef NTONLY
  16. #include <assertbreak.h>
  17. #include "AdvApi32Api.h"
  18. #include "accctrl.h"
  19. #include "sid.h"
  20. #include "AccessEntryList.h"
  21. #include "AccessRights.h"
  22. //==============================================================================
  23. // CONSTRUCTORS AND DESTRUCTORS
  24. //==============================================================================
  25. // Default initialization...
  26. CAccessRights::CAccessRights(bool fUseCurThrTok /* = false */)
  27. : m_dwError(ERROR_SUCCESS)
  28. {
  29. if(fUseCurThrTok)
  30. {
  31. // Initialize using the current thread token...
  32. InitTrustee(true);
  33. }
  34. }
  35. // Initialization specifying user only. Sid domain/account
  36. // not resolved. ACL uninitialized.
  37. CAccessRights::CAccessRights(const USER user, USER_SPECIFIER usp)
  38. : m_dwError(ERROR_SUCCESS)
  39. {
  40. if(usp == USER_IS_PSID)
  41. {
  42. m_csid = CSid((PSID)user, NULL, false);
  43. InitTrustee(false);
  44. }
  45. else if(usp == USER_IS_HANDLE)
  46. {
  47. ASSERT_BREAK(user != NULL);
  48. InitTrustee(false, (HANDLE)user);
  49. }
  50. }
  51. // Initialization of user and acl. Sid domain/account
  52. // not resolved. ACL initialized.
  53. CAccessRights::CAccessRights(const USER user, const PACL pacl, USER_SPECIFIER usp)
  54. : m_ael(pacl, false),
  55. m_dwError(ERROR_SUCCESS)
  56. {
  57. if(usp == USER_IS_PSID)
  58. {
  59. m_csid = CSid((PSID)user, NULL, false);
  60. InitTrustee(false);
  61. }
  62. else if(usp == USER_IS_HANDLE)
  63. {
  64. ASSERT_BREAK(user != NULL);
  65. InitTrustee(false, (HANDLE)user);
  66. }
  67. }
  68. // Initialization of acl only. ACL Sids not resolved.
  69. CAccessRights::CAccessRights(const PACL pacl, bool fUseCurThrTok /* = false */)
  70. : m_ael(pacl, false),
  71. m_dwError(ERROR_SUCCESS)
  72. {
  73. if(fUseCurThrTok)
  74. {
  75. // Initialize using the current thread token...
  76. InitTrustee(true);
  77. }
  78. }
  79. // Copy constructor
  80. /* Not complete yet
  81. CAccessRights::CAccessRights(const CAccessRights &RAccessRights)
  82. {
  83. // Copy members. We may or may not have either.
  84. if(RAccessRights.m_csid.IsValid() && RAccessRights.m_csid.IsOK())
  85. {
  86. m_csid = RAccessRights.m_csid;
  87. }
  88. m_ael.Clear();
  89. if(!RAccessRights.m_ael.IsEmpty())
  90. {
  91. // The best way to do this, to guarentee that the sids are not
  92. // resolved into domain/name, is to gat a PACL, then reinitialize
  93. // ourselves from it.
  94. PACL paclNew = NULL;
  95. try
  96. {
  97. if(RAccessRights.FillEmptyPACL(paclNew))
  98. {
  99. if(paclNew != NULL)
  100. {
  101. if(!m_ael.InitFromWin32ACL(paclNew, ALL_ACE_TYPES, false))
  102. {
  103. // If something went wrong, clean
  104. // up after ourselves.
  105. m_ael.Clear();
  106. }
  107. delete paclNew;
  108. paclNew = NULL;
  109. }
  110. }
  111. }
  112. catch(...)
  113. {
  114. if(paclNew != NULL)
  115. {
  116. delete paclNew;
  117. paclNew = NULL;
  118. }
  119. throw;
  120. }
  121. }
  122. }
  123. */
  124. // Destructor - members destruct themselves.
  125. CAccessRights::~CAccessRights()
  126. {
  127. }
  128. //==============================================================================
  129. // UTILITY FUNCTIONS
  130. //==============================================================================
  131. AR_RET_CODE CAccessRights::GetEffectiveAccessRights(PACCESS_MASK pAccessMask)
  132. {
  133. DWORD dwRet = AR_GENERIC_FAILURE;
  134. CAdvApi32Api *pAdvApi32 = NULL;
  135. PACL pacl = NULL;
  136. try
  137. {
  138. pAdvApi32 = (CAdvApi32Api*) CResourceManager::sm_TheResourceManager.GetResource(g_guidAdvApi32Api, NULL);
  139. if(pAdvApi32 != NULL)
  140. {
  141. if((dwRet = FillEmptyPACL(&pacl)) == ERROR_SUCCESS)
  142. {
  143. ASSERT_BREAK(pacl != NULL);
  144. if(pacl != NULL)
  145. {
  146. if(m_csid.IsValid() && m_csid.IsOK())
  147. {
  148. pAdvApi32->GetEffectiveRightsFromAclW(pacl,
  149. &m_trustee,
  150. pAccessMask,
  151. &dwRet);
  152. }
  153. else
  154. {
  155. dwRet = AR_BAD_SID;
  156. }
  157. delete pacl;
  158. pacl = NULL;
  159. }
  160. }
  161. CResourceManager::sm_TheResourceManager.ReleaseResource(g_guidAdvApi32Api, pAdvApi32);
  162. pAdvApi32 = NULL;
  163. }
  164. }
  165. catch(...)
  166. {
  167. if(pacl != NULL)
  168. {
  169. delete pacl;
  170. pacl = NULL;
  171. }
  172. if(pAdvApi32 != NULL)
  173. {
  174. CResourceManager::sm_TheResourceManager.ReleaseResource(g_guidAdvApi32Api, pAdvApi32);
  175. pAdvApi32 = NULL;
  176. }
  177. throw;
  178. }
  179. return dwRet;
  180. }
  181. bool CAccessRights::InitTrustee(bool fInitFromCurrentThread, const HANDLE hToken)
  182. {
  183. bool fRet = false;
  184. // The main thing done here is a sid is obtained and the TRUSTEE struct
  185. // filled in.
  186. if(fInitFromCurrentThread)
  187. {
  188. // Get the sid of the user/group of the current thread...
  189. SmartCloseHandle hThreadToken;
  190. if(::OpenThreadToken(::GetCurrentThread(), TOKEN_READ, FALSE, &hThreadToken))
  191. {
  192. InitSidFromToken(hThreadToken);
  193. }
  194. }
  195. else
  196. {
  197. // If we were given a hToken, use it instead...
  198. if(hToken != NULL)
  199. {
  200. InitSidFromToken(hToken);
  201. }
  202. }
  203. // We should now have a valid sid in our member CSid (either from the
  204. // InitSidFromToken calls or from construction).
  205. // Now we need to initialize the TRUSTEE object. Check again that our sid
  206. // is in good standing...
  207. if(m_csid.IsValid() && m_csid.IsOK())
  208. {
  209. m_trustee.pMultipleTrustee = NULL;
  210. m_trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  211. m_trustee.TrusteeForm = TRUSTEE_IS_SID;
  212. m_trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; // we could be operating
  213. // on behalf of a user,
  214. // group, well-known-group,
  215. // who knows.
  216. m_trustee.ptstrName = (LPWSTR)m_csid.GetPSid();
  217. fRet = true;
  218. }
  219. else
  220. {
  221. m_dwError = AR_BAD_SID;
  222. }
  223. return fRet;
  224. }
  225. bool CAccessRights::InitSidFromToken(const HANDLE hThreadToken)
  226. {
  227. bool fRet = false;
  228. if(hThreadToken != NULL)
  229. {
  230. DWORD dwLength = 0L;
  231. DWORD dwReqLength = 0L;
  232. PSID psid = NULL;
  233. LPVOID pBuff = NULL;
  234. if(!::GetTokenInformation(hThreadToken, TokenUser, NULL, 0, &dwReqLength))
  235. {
  236. if(::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  237. {
  238. // Allocate a buffer to hold the token info...
  239. try
  240. {
  241. pBuff = new BYTE[dwReqLength];
  242. if(pBuff != NULL)
  243. {
  244. dwLength = dwReqLength;
  245. // Now that we have the right size buffer, call again...
  246. if(::GetTokenInformation(hThreadToken,
  247. TokenUser,
  248. pBuff,
  249. dwLength,
  250. &dwReqLength))
  251. {
  252. if(pBuff != NULL)
  253. {
  254. TOKEN_USER *pTokUsr = (TOKEN_USER*)pBuff;
  255. psid = pTokUsr->User.Sid;
  256. ASSERT_BREAK((psid != NULL) && ::IsValidSid(psid));
  257. if((psid != NULL) && ::IsValidSid(psid))
  258. {
  259. m_csid = CSid(psid, NULL, false);
  260. fRet = true;
  261. }
  262. else
  263. {
  264. m_dwError = AR_BAD_SID;
  265. }
  266. }
  267. }
  268. delete pBuff;
  269. pBuff = NULL;
  270. }
  271. }
  272. catch(...)
  273. {
  274. if(pBuff != NULL)
  275. {
  276. delete pBuff;
  277. pBuff = NULL;
  278. }
  279. throw;
  280. }
  281. }
  282. }
  283. }
  284. return fRet;
  285. }
  286. // Resets the user to the user to whom the current thread token belongs.
  287. bool CAccessRights::SetUserToThisThread()
  288. {
  289. return InitTrustee(true, NULL);
  290. }
  291. // Resets the user to the user specified by psid or handle
  292. bool CAccessRights::SetUser(const USER user, USER_SPECIFIER usp)
  293. {
  294. bool fRet = false;
  295. if(usp == USER_IS_PSID)
  296. {
  297. CSid csidTemp((PSID)user);
  298. if(csidTemp.IsValid() && csidTemp.IsOK())
  299. {
  300. m_csid = csidTemp;
  301. fRet = true;
  302. }
  303. }
  304. else if(usp == USER_IS_HANDLE)
  305. {
  306. fRet = InitSidFromToken((HANDLE)user);
  307. }
  308. return fRet;
  309. }
  310. // Resets the acl to the passed in PACL
  311. bool CAccessRights::SetAcl(const PACL pacl)
  312. {
  313. bool fRet = false;
  314. if(pacl != NULL)
  315. {
  316. m_ael.Clear();
  317. if(m_ael.InitFromWin32ACL(pacl, ALL_ACE_TYPES, false) == ERROR_SUCCESS)
  318. {
  319. fRet = true;
  320. }
  321. }
  322. return fRet;
  323. }
  324. // Gets us a filled out PACL, which must be freed by the caller, using delete.
  325. AR_RET_CODE CAccessRights::FillEmptyPACL(PACL *paclOut)
  326. {
  327. DWORD dwRet = AR_GENERIC_FAILURE;
  328. if(paclOut != NULL)
  329. {
  330. // The best way to do this, to guarentee that the sids are not
  331. // resolved into domain/name, is to get a PACL, then reinitialize
  332. // ourselves from it.
  333. DWORD dwAclSize = 0L;
  334. if(m_ael.NumEntries() > 0)
  335. {
  336. if(m_ael.CalculateWin32ACLSize(&dwAclSize))
  337. {
  338. if(dwAclSize > sizeof(ACL))
  339. {
  340. PACL paclTemp = NULL;
  341. try
  342. {
  343. paclTemp = (PACL) new BYTE[dwAclSize];
  344. if(paclTemp != NULL)
  345. {
  346. ::InitializeAcl(paclTemp, dwAclSize, ACL_REVISION);
  347. if((dwRet = m_ael.FillWin32ACL(paclTemp)) == ERROR_SUCCESS)
  348. {
  349. *paclOut = paclTemp;
  350. dwRet = ERROR_SUCCESS;
  351. }
  352. }
  353. }
  354. catch(...)
  355. {
  356. if(paclTemp != NULL)
  357. {
  358. delete paclTemp;
  359. paclTemp = NULL;
  360. }
  361. throw;
  362. }
  363. }
  364. else
  365. {
  366. dwRet = AR_ACL_EMPTY;
  367. }
  368. }
  369. else
  370. {
  371. dwRet = AR_BAD_ACL;
  372. }
  373. }
  374. else
  375. {
  376. dwRet = AR_ACL_EMPTY;
  377. }
  378. }
  379. return dwRet;
  380. }
  381. bool CAccessRights::GetCSid(CSid &csid, bool fResolve)
  382. {
  383. bool fRet = false;
  384. if(m_dwError == ERROR_SUCCESS)
  385. {
  386. if(m_csid.IsValid() && m_csid.IsOK())
  387. {
  388. if(fResolve)
  389. {
  390. // Need to create a new one since ours doesn't
  391. // have account or domain name resolved.
  392. CSid csidTemp(m_csid.GetPSid());
  393. if(csidTemp.IsValid() && csidTemp.IsOK())
  394. {
  395. csid = csidTemp;
  396. fRet = true;
  397. }
  398. }
  399. else
  400. {
  401. csid = m_csid;
  402. fRet = true;
  403. }
  404. }
  405. }
  406. return fRet;
  407. }
  408. #endif