access_token_unittest.cc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/win/access_token.h"
  5. #include <windows.h>
  6. #include <algorithm>
  7. #include <cstdint>
  8. #include <map>
  9. #include "base/win/atl.h"
  10. #include "base/win/scoped_handle.h"
  11. #include "base/win/windows_version.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. #include "third_party/abseil-cpp/absl/types/optional.h"
  14. namespace base {
  15. namespace win {
  16. namespace {
  17. bool CompareLuid(const CHROME_LUID& left, const LUID& right) {
  18. return left.HighPart == right.HighPart && left.LowPart == right.LowPart;
  19. }
  20. int64_t ConvertLuid(const AccessToken::Privilege& priv) {
  21. CHROME_LUID luid = priv.GetLuid();
  22. return (static_cast<int64_t>(luid.HighPart) << 32) | luid.LowPart;
  23. }
  24. int64_t ConvertLuid(const LUID& luid) {
  25. return (static_cast<int64_t>(luid.HighPart) << 32) | luid.LowPart;
  26. }
  27. bool EqualSid(const Sid& left, const ATL::CSid& right) {
  28. return left.Equal(const_cast<SID*>(right.GetPSID()));
  29. }
  30. void CompareGroups(const std::vector<AccessToken::Group>& groups,
  31. const ATL::CSid::CSidArray& sids,
  32. const ATL::CAtlArray<DWORD>& attrs) {
  33. ASSERT_EQ(groups.size(), sids.GetCount());
  34. ASSERT_EQ(sids.GetCount(), attrs.GetCount());
  35. std::map<std::wstring, DWORD> group_map;
  36. for (const AccessToken::Group& group : groups) {
  37. absl::optional<std::wstring> sddl = group.GetSid().ToSddlString();
  38. ASSERT_TRUE(sddl);
  39. group_map.insert({*sddl, group.GetAttributes()});
  40. }
  41. for (size_t index = 0; index < sids.GetCount(); ++index) {
  42. auto found_group = group_map.find(sids[index].Sid());
  43. ASSERT_NE(found_group, group_map.end());
  44. EXPECT_EQ(found_group->second, attrs[index]);
  45. }
  46. }
  47. void CompareGroups(const std::vector<AccessToken::Group>& groups,
  48. const CTokenGroups& atl_groups) {
  49. ATL::CSid::CSidArray sids;
  50. ATL::CAtlArray<DWORD> attrs;
  51. atl_groups.GetSidsAndAttributes(&sids, &attrs);
  52. CompareGroups(groups, sids, attrs);
  53. }
  54. void ComparePrivileges(const std::vector<AccessToken::Privilege>& privs,
  55. const ATL::CTokenPrivileges& atl_privs) {
  56. CLUIDArray luids;
  57. ATL::CTokenPrivileges::CAttributes attrs;
  58. atl_privs.GetLuidsAndAttributes(&luids, &attrs);
  59. ATL::CTokenPrivileges::CNames names;
  60. atl_privs.GetNamesAndAttributes(&names);
  61. ASSERT_EQ(privs.size(), luids.GetCount());
  62. ASSERT_EQ(privs.size(), attrs.GetCount());
  63. ASSERT_EQ(privs.size(), names.GetCount());
  64. std::map<int64_t, const AccessToken::Privilege&> priv_map;
  65. for (const AccessToken::Privilege& priv : privs) {
  66. priv_map.insert({ConvertLuid(priv), priv});
  67. }
  68. for (size_t index = 0; index < luids.GetCount(); ++index) {
  69. auto found_priv = priv_map.find(ConvertLuid(luids[index]));
  70. ASSERT_NE(found_priv, priv_map.end());
  71. EXPECT_TRUE(CompareLuid(found_priv->second.GetLuid(), luids[index]));
  72. EXPECT_EQ(found_priv->second.GetAttributes(), attrs[index]);
  73. EXPECT_EQ(found_priv->second.GetName().c_str(), names[index]);
  74. }
  75. }
  76. void CompareIntegrityLevel(const AccessToken& token,
  77. const ATL::CAccessToken& atl_token) {
  78. char buffer[sizeof(TOKEN_MANDATORY_LABEL) + SECURITY_MAX_SID_SIZE];
  79. DWORD size = sizeof(buffer);
  80. ASSERT_TRUE(::GetTokenInformation(atl_token.GetHandle(), TokenIntegrityLevel,
  81. buffer, size, &size));
  82. TOKEN_MANDATORY_LABEL* label =
  83. reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buffer);
  84. ASSERT_TRUE(label->Label.Sid);
  85. absl::optional<Sid> il_sid = Sid::FromIntegrityLevel(token.IntegrityLevel());
  86. ASSERT_TRUE(il_sid);
  87. EXPECT_TRUE(il_sid->Equal(label->Label.Sid));
  88. }
  89. void CompareElevated(const AccessToken& token,
  90. const ATL::CAccessToken& atl_token) {
  91. TOKEN_ELEVATION elevation;
  92. DWORD size = sizeof(elevation);
  93. ASSERT_TRUE(::GetTokenInformation(atl_token.GetHandle(), TokenElevation,
  94. &elevation, size, &size));
  95. EXPECT_EQ(token.IsElevated(), !!elevation.TokenIsElevated);
  96. }
  97. bool GetLinkedToken(const ATL::CAccessToken& token,
  98. ATL::CAccessToken* linked_token) {
  99. TOKEN_LINKED_TOKEN value;
  100. DWORD size = sizeof(value);
  101. if (!::GetTokenInformation(token.GetHandle(), TokenLinkedToken, &value, size,
  102. &size)) {
  103. return false;
  104. }
  105. linked_token->Attach(value.LinkedToken);
  106. return true;
  107. }
  108. void CompareDefaultDacl(const AccessToken& token,
  109. const ATL::CAccessToken& atl_token) {
  110. CDacl atl_dacl;
  111. ASSERT_TRUE(atl_token.GetDefaultDacl(&atl_dacl));
  112. ATL::CSid::CSidArray sids;
  113. CAcl::CAccessMaskArray access;
  114. CAcl::CAceTypeArray types;
  115. CAcl::CAceFlagArray flags;
  116. atl_dacl.GetAclEntries(&sids, &access, &types, &flags);
  117. absl::optional<AccessToken::Dacl> dacl = token.DefaultDacl();
  118. ASSERT_TRUE(dacl);
  119. ACL* acl_ptr = dacl->GetAcl();
  120. ASSERT_TRUE(acl_ptr);
  121. DWORD ace_count = acl_ptr->AceCount;
  122. ASSERT_EQ(ace_count, sids.GetCount());
  123. ASSERT_EQ(ace_count, access.GetCount());
  124. ASSERT_EQ(ace_count, types.GetCount());
  125. ASSERT_EQ(ace_count, flags.GetCount());
  126. for (DWORD index = 0; index < ace_count; ++index) {
  127. ACE_HEADER* ace_header;
  128. ASSERT_TRUE(GetAce(acl_ptr, index, reinterpret_cast<LPVOID*>(&ace_header)));
  129. ASSERT_EQ(ace_header->AceType, types[index]);
  130. ASSERT_EQ(ace_header->AceFlags, flags[index]);
  131. // We only do a full comparison for these types of ACE.
  132. if (ace_header->AceType == ACCESS_ALLOWED_ACE_TYPE ||
  133. ace_header->AceType == ACCESS_DENIED_ACE_TYPE) {
  134. // ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACE have the same layout.
  135. ACCESS_ALLOWED_ACE* ace =
  136. reinterpret_cast<ACCESS_ALLOWED_ACE*>(ace_header);
  137. EXPECT_EQ(ace->Mask, access[index]);
  138. absl::optional<Sid> sid = Sid::FromPSID(&ace->SidStart);
  139. ASSERT_TRUE(sid);
  140. EXPECT_TRUE(EqualSid(*sid, sids[index]));
  141. }
  142. }
  143. }
  144. void CompareTokens(const AccessToken& token,
  145. const ATL::CAccessToken& atl_token,
  146. bool compare_linked_token = true) {
  147. LUID luid;
  148. // Only compare IDs if we're not comparing a token's linked token as the ID
  149. // will be different.
  150. if (compare_linked_token) {
  151. ASSERT_TRUE(atl_token.GetTokenId(&luid));
  152. EXPECT_TRUE(CompareLuid(token.Id(), luid));
  153. }
  154. ASSERT_TRUE(atl_token.GetLogonSessionId(&luid));
  155. EXPECT_TRUE(CompareLuid(token.AuthenticationId(), luid));
  156. ATL::CSid user_sid;
  157. ASSERT_TRUE(atl_token.GetUser(&user_sid));
  158. EXPECT_TRUE(EqualSid(token.User(), user_sid));
  159. AccessToken::Group user_group = token.UserGroup();
  160. EXPECT_TRUE(EqualSid(user_group.GetSid(), user_sid));
  161. EXPECT_EQ(0U, user_group.GetAttributes());
  162. ATL::CSid owner_sid;
  163. ASSERT_TRUE(atl_token.GetOwner(&owner_sid));
  164. EXPECT_TRUE(EqualSid(token.Owner(), owner_sid));
  165. ATL::CSid primary_group;
  166. ASSERT_TRUE(atl_token.GetPrimaryGroup(&primary_group));
  167. EXPECT_TRUE(EqualSid(token.PrimaryGroup(), primary_group));
  168. absl::optional<Sid> logon_sid = token.LogonId();
  169. if (!logon_sid) {
  170. EXPECT_EQ(DWORD{ERROR_NOT_FOUND}, ::GetLastError());
  171. }
  172. ATL::CSid atl_logon_sid;
  173. if (!atl_token.GetLogonSid(&atl_logon_sid)) {
  174. EXPECT_FALSE(logon_sid);
  175. } else {
  176. ASSERT_TRUE(logon_sid);
  177. EXPECT_TRUE(EqualSid(*logon_sid, atl_logon_sid));
  178. }
  179. DWORD session_id;
  180. ASSERT_TRUE(atl_token.GetTerminalServicesSessionId(&session_id));
  181. EXPECT_EQ(token.SessionId(), session_id);
  182. CompareIntegrityLevel(token, atl_token);
  183. CompareElevated(token, atl_token);
  184. EXPECT_EQ(token.IsRestricted(), atl_token.IsTokenRestricted());
  185. TOKEN_TYPE token_type;
  186. ASSERT_TRUE(atl_token.GetType(&token_type));
  187. EXPECT_EQ(token.IsImpersonation(), token_type == TokenImpersonation);
  188. if (token_type == TokenImpersonation) {
  189. SECURITY_IMPERSONATION_LEVEL imp_level;
  190. ASSERT_TRUE(atl_token.GetImpersonationLevel(&imp_level));
  191. EXPECT_EQ(token.IsIdentification(), imp_level < SecurityImpersonation);
  192. }
  193. CTokenGroups atl_groups;
  194. ASSERT_TRUE(atl_token.GetGroups(&atl_groups));
  195. CompareGroups(token.Groups(), atl_groups);
  196. ATL::CTokenPrivileges atl_privs;
  197. ASSERT_TRUE(atl_token.GetPrivileges(&atl_privs));
  198. ComparePrivileges(token.Privileges(), atl_privs);
  199. CompareDefaultDacl(token, atl_token);
  200. absl::optional<AccessToken> linked_token = token.LinkedToken();
  201. ATL::CAccessToken atl_linked_token;
  202. bool result = GetLinkedToken(atl_token, &atl_linked_token);
  203. if (!linked_token) {
  204. EXPECT_FALSE(result);
  205. } else {
  206. ASSERT_TRUE(result);
  207. if (compare_linked_token)
  208. CompareTokens(*linked_token, atl_linked_token, false);
  209. }
  210. }
  211. bool DuplicateTokenWithSecurityDescriptor(const ATL::CAccessToken& token,
  212. DWORD desired_access,
  213. LPCWSTR security_descriptor,
  214. ATL::CAccessToken* new_token) {
  215. ATL::CSecurityDesc sd;
  216. if (!sd.FromString(security_descriptor))
  217. return false;
  218. ATL::CSecurityAttributes sa;
  219. sa.Set(sd);
  220. return token.CreatePrimaryToken(new_token, desired_access, &sa);
  221. }
  222. bool CreateImpersonationToken(SECURITY_IMPERSONATION_LEVEL impersonation_level,
  223. ATL::CAccessToken* imp_token) {
  224. ATL::CAccessToken token;
  225. if (!token.GetProcessToken(MAXIMUM_ALLOWED))
  226. return false;
  227. return token.CreateImpersonationToken(imp_token, impersonation_level);
  228. }
  229. void CheckTokenError(const absl::optional<AccessToken>& token,
  230. DWORD expected_error) {
  231. DWORD error = ::GetLastError();
  232. EXPECT_FALSE(token);
  233. EXPECT_EQ(expected_error, error);
  234. }
  235. void CheckError(bool result, DWORD expected_error) {
  236. DWORD error = ::GetLastError();
  237. EXPECT_FALSE(result);
  238. EXPECT_EQ(expected_error, error);
  239. }
  240. void CheckAccessTokenGroup(DWORD attributes,
  241. bool integrity,
  242. bool enabled,
  243. bool deny_only,
  244. bool logon_id) {
  245. AccessToken::Group group(*Sid::FromKnownSid(WellKnownSid::kWorld),
  246. attributes);
  247. EXPECT_EQ(L"S-1-1-0", *group.GetSid().ToSddlString());
  248. EXPECT_EQ(integrity, group.IsIntegrity());
  249. EXPECT_EQ(enabled, group.IsEnabled());
  250. EXPECT_EQ(deny_only, group.IsDenyOnly());
  251. EXPECT_EQ(logon_id, group.IsLogonId());
  252. }
  253. void CheckAccessTokenPrivilege(LPCWSTR name, DWORD attributes, bool enabled) {
  254. LUID luid;
  255. ASSERT_TRUE(::LookupPrivilegeValue(nullptr, name, &luid));
  256. CHROME_LUID chrome_luid;
  257. chrome_luid.LowPart = luid.LowPart;
  258. chrome_luid.HighPart = luid.HighPart;
  259. AccessToken::Privilege priv(chrome_luid, attributes);
  260. EXPECT_TRUE(CompareLuid(priv.GetLuid(), luid));
  261. EXPECT_EQ(name, priv.GetName());
  262. EXPECT_EQ(attributes, priv.GetAttributes());
  263. EXPECT_EQ(enabled, priv.IsEnabled());
  264. }
  265. typedef NTSTATUS(WINAPI* NtCreateLowBoxToken)(OUT PHANDLE token,
  266. IN HANDLE original_handle,
  267. IN ACCESS_MASK access,
  268. IN PVOID object_attribute,
  269. IN PSID appcontainer_sid,
  270. IN DWORD capabilityCount,
  271. IN PSID_AND_ATTRIBUTES
  272. capabilities,
  273. IN DWORD handle_count,
  274. IN PHANDLE handles);
  275. void CompareAppContainer(const Sid& package_sid, const std::vector<Sid>& caps) {
  276. static NtCreateLowBoxToken pNtCreateLowBoxToken =
  277. reinterpret_cast<NtCreateLowBoxToken>(::GetProcAddress(
  278. ::GetModuleHandle(L"ntdll.dll"), "NtCreateLowBoxToken"));
  279. ASSERT_TRUE(pNtCreateLowBoxToken);
  280. ATL::CTokenGroups capabilities;
  281. for (const Sid& cap : caps) {
  282. capabilities.Add(ATL::CSid(static_cast<SID*>(cap.GetPSID())),
  283. SE_GROUP_ENABLED);
  284. }
  285. ATL::CAccessToken process_token;
  286. ASSERT_TRUE(process_token.GetProcessToken(TOKEN_ALL_ACCESS));
  287. UINT cap_count = capabilities.GetCount();
  288. PTOKEN_GROUPS cap_groups =
  289. const_cast<PTOKEN_GROUPS>(capabilities.GetPTOKEN_GROUPS());
  290. HANDLE tmp_token;
  291. NTSTATUS status = pNtCreateLowBoxToken(
  292. &tmp_token, process_token.GetHandle(), TOKEN_ALL_ACCESS, nullptr,
  293. package_sid.GetPSID(), cap_count,
  294. cap_count > 0 ? cap_groups->Groups : nullptr, 0, nullptr);
  295. ASSERT_EQ(0, status);
  296. ScopedHandle scoped_tmp_token(tmp_token);
  297. absl::optional<AccessToken> ac_token =
  298. AccessToken::FromToken(scoped_tmp_token.get());
  299. ASSERT_TRUE(ac_token);
  300. EXPECT_TRUE(ac_token->IsAppContainer());
  301. EXPECT_EQ(ac_token->AppContainerSid(), package_sid);
  302. CompareGroups(ac_token->Capabilities(), capabilities);
  303. }
  304. } // namespace
  305. TEST(AccessTokenTest, FromToken) {
  306. ATL::CAccessToken atl_token;
  307. ASSERT_TRUE(atl_token.GetProcessToken(TOKEN_QUERY));
  308. absl::optional<AccessToken> token =
  309. AccessToken::FromToken(atl_token.GetHandle());
  310. ASSERT_TRUE(token);
  311. CompareTokens(*token, atl_token);
  312. // Check that we duplicated the handle.
  313. LUID luid;
  314. ASSERT_TRUE(atl_token.GetTokenId(&luid));
  315. ::CloseHandle(atl_token.Detach());
  316. LUID temp_luid;
  317. ASSERT_FALSE(atl_token.GetTokenId(&temp_luid));
  318. EXPECT_TRUE(CompareLuid(token->Id(), luid));
  319. // Check that we duplicate with the correct access rights.
  320. ASSERT_TRUE(atl_token.GetProcessToken(TOKEN_QUERY_SOURCE));
  321. ASSERT_FALSE(atl_token.GetTokenId(&temp_luid));
  322. absl::optional<AccessToken> token2 =
  323. AccessToken::FromToken(atl_token.GetHandle());
  324. ASSERT_TRUE(token2);
  325. EXPECT_TRUE(CompareLuid(token2->Id(), luid));
  326. // Check that we fail if we don't have access to the token object.
  327. ASSERT_TRUE(atl_token.GetProcessToken(TOKEN_DUPLICATE));
  328. ATL::CAccessToken pri_token;
  329. ASSERT_TRUE(DuplicateTokenWithSecurityDescriptor(
  330. atl_token, TOKEN_QUERY_SOURCE, L"D:", &pri_token));
  331. CheckTokenError(AccessToken::FromToken(pri_token.GetHandle()),
  332. ERROR_ACCESS_DENIED);
  333. }
  334. TEST(AccessTokenTest, FromProcess) {
  335. ScopedHandle process(
  336. ::OpenProcess(PROCESS_TERMINATE, FALSE, ::GetCurrentProcessId()));
  337. ASSERT_TRUE(process.is_valid());
  338. CheckTokenError(AccessToken::FromProcess(process.get()), ERROR_ACCESS_DENIED);
  339. process.Set(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
  340. ::GetCurrentProcessId()));
  341. ASSERT_TRUE(process.is_valid());
  342. absl::optional<AccessToken> token = AccessToken::FromProcess(process.get());
  343. ASSERT_TRUE(token);
  344. ASSERT_FALSE(token->IsImpersonation());
  345. ATL::CAccessToken atl_token;
  346. ASSERT_TRUE(atl_token.GetProcessToken(TOKEN_QUERY, process.get()));
  347. CompareTokens(*token, atl_token);
  348. absl::optional<AccessToken> imp_token =
  349. AccessToken::FromProcess(process.get(), true);
  350. ASSERT_TRUE(imp_token);
  351. ASSERT_TRUE(imp_token->IsImpersonation());
  352. ASSERT_TRUE(imp_token->IsIdentification());
  353. }
  354. TEST(AccessTokenTest, FromCurrentProcess) {
  355. absl::optional<AccessToken> token = AccessToken::FromCurrentProcess();
  356. ASSERT_TRUE(token);
  357. ASSERT_FALSE(token->IsImpersonation());
  358. ATL::CAccessToken atl_token;
  359. ASSERT_TRUE(atl_token.GetProcessToken(TOKEN_QUERY));
  360. CompareTokens(*token, atl_token);
  361. absl::optional<AccessToken> imp_token = AccessToken::FromCurrentProcess(true);
  362. ASSERT_TRUE(imp_token);
  363. ASSERT_TRUE(imp_token->IsImpersonation());
  364. ASSERT_TRUE(imp_token->IsIdentification());
  365. }
  366. TEST(AccessTokenTest, FromThread) {
  367. // Make sure we have no impersonation token before starting.
  368. ::RevertToSelf();
  369. // Check we
  370. CheckTokenError(AccessToken::FromThread(::GetCurrentThread()),
  371. ERROR_NO_TOKEN);
  372. ScopedHandle thread(
  373. ::OpenThread(THREAD_TERMINATE, FALSE, ::GetCurrentThreadId()));
  374. ASSERT_TRUE(thread.is_valid());
  375. CheckTokenError(AccessToken::FromThread(thread.get()), ERROR_ACCESS_DENIED);
  376. ATL::CAccessToken atl_imp_token;
  377. ASSERT_TRUE(CreateImpersonationToken(SecurityImpersonation, &atl_imp_token));
  378. ASSERT_TRUE(atl_imp_token.Impersonate());
  379. CAutoRevertImpersonation scoped_imp(&atl_imp_token);
  380. thread.Set(::OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE,
  381. ::GetCurrentThreadId()));
  382. ASSERT_TRUE(thread.is_valid());
  383. absl::optional<AccessToken> imp_token = AccessToken::FromThread(thread.get());
  384. atl_imp_token.Revert();
  385. ASSERT_TRUE(imp_token);
  386. ASSERT_TRUE(imp_token->IsImpersonation());
  387. EXPECT_FALSE(imp_token->IsIdentification());
  388. CompareTokens(*imp_token, atl_imp_token);
  389. ATL::CAccessToken atl_id_token;
  390. ASSERT_TRUE(CreateImpersonationToken(SecurityIdentification, &atl_id_token));
  391. ASSERT_TRUE(atl_id_token.Impersonate());
  392. CAutoRevertImpersonation scoped_imp2(&atl_id_token);
  393. CheckTokenError(AccessToken::FromThread(thread.get(), false),
  394. ERROR_BAD_IMPERSONATION_LEVEL);
  395. absl::optional<AccessToken> id_token =
  396. AccessToken::FromThread(thread.get(), true);
  397. atl_id_token.Revert();
  398. ASSERT_TRUE(id_token);
  399. EXPECT_TRUE(id_token->IsIdentification());
  400. CompareTokens(*id_token, atl_id_token);
  401. }
  402. TEST(AccessTokenTest, FromCurrentThread) {
  403. // Make sure we have no impersonation token before starting.
  404. ::RevertToSelf();
  405. // Check we
  406. CheckTokenError(AccessToken::FromCurrentThread(), ERROR_NO_TOKEN);
  407. ATL::CAccessToken atl_imp_token;
  408. ASSERT_TRUE(CreateImpersonationToken(SecurityImpersonation, &atl_imp_token));
  409. ASSERT_TRUE(atl_imp_token.Impersonate());
  410. CAutoRevertImpersonation scoped_imp(&atl_imp_token);
  411. absl::optional<AccessToken> imp_token = AccessToken::FromCurrentThread();
  412. atl_imp_token.Revert();
  413. ASSERT_TRUE(imp_token);
  414. ASSERT_TRUE(imp_token->IsImpersonation());
  415. EXPECT_FALSE(imp_token->IsIdentification());
  416. CompareTokens(*imp_token, atl_imp_token);
  417. ATL::CAccessToken atl_id_token;
  418. ASSERT_TRUE(CreateImpersonationToken(SecurityIdentification, &atl_id_token));
  419. ASSERT_TRUE(atl_id_token.Impersonate());
  420. ATL::CAutoRevertImpersonation scoped_imp2(&atl_id_token);
  421. CheckTokenError(AccessToken::FromCurrentThread(false),
  422. ERROR_BAD_IMPERSONATION_LEVEL);
  423. absl::optional<AccessToken> id_token = AccessToken::FromCurrentThread(true);
  424. atl_id_token.Revert();
  425. ASSERT_TRUE(id_token);
  426. EXPECT_TRUE(id_token->IsIdentification());
  427. CompareTokens(*id_token, atl_id_token);
  428. }
  429. TEST(AccessTokenTest, FromEffective) {
  430. // Make sure we have no impersonation token before starting.
  431. ::RevertToSelf();
  432. absl::optional<base::win::AccessToken> primary_token =
  433. AccessToken::FromEffective();
  434. ASSERT_TRUE(primary_token);
  435. EXPECT_FALSE(primary_token->IsImpersonation());
  436. ATL::CAccessToken atl_primary_token;
  437. ASSERT_TRUE(atl_primary_token.GetProcessToken(TOKEN_QUERY));
  438. CompareTokens(*primary_token, atl_primary_token);
  439. ATL::CAccessToken atl_imp_token;
  440. ASSERT_TRUE(CreateImpersonationToken(SecurityImpersonation, &atl_imp_token));
  441. ASSERT_TRUE(atl_imp_token.Impersonate());
  442. CAutoRevertImpersonation scoped_imp(&atl_imp_token);
  443. absl::optional<AccessToken> imp_token = AccessToken::FromEffective();
  444. atl_imp_token.Revert();
  445. ASSERT_TRUE(imp_token);
  446. ASSERT_TRUE(imp_token->IsImpersonation());
  447. EXPECT_FALSE(imp_token->IsIdentification());
  448. CompareTokens(*imp_token, atl_imp_token);
  449. }
  450. TEST(AccessTokenTest, AccessTokenGroup) {
  451. CheckAccessTokenGroup(0, false, false, false, false);
  452. CheckAccessTokenGroup(SE_GROUP_INTEGRITY, true, false, false, false);
  453. CheckAccessTokenGroup(SE_GROUP_ENABLED, false, true, false, false);
  454. CheckAccessTokenGroup(SE_GROUP_USE_FOR_DENY_ONLY, false, false, true, false);
  455. CheckAccessTokenGroup(SE_GROUP_LOGON_ID, false, false, false, true);
  456. CheckAccessTokenGroup(0xFFFFFFFF, true, true, true, true);
  457. }
  458. TEST(AccessTokenTest, AccessTokenPrivilege) {
  459. CheckAccessTokenPrivilege(SE_DEBUG_NAME, 0, false);
  460. CheckAccessTokenPrivilege(SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED_BY_DEFAULT,
  461. false);
  462. CheckAccessTokenPrivilege(SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED, true);
  463. CheckAccessTokenPrivilege(
  464. SE_DEBUG_NAME, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT,
  465. true);
  466. CheckAccessTokenPrivilege(SE_IMPERSONATE_NAME, 0, false);
  467. CHROME_LUID luid{0x8181, 0x5656};
  468. AccessToken::Privilege priv(luid, 0);
  469. EXPECT_EQ(L"00005656-00008181", priv.GetName());
  470. }
  471. TEST(AccessTokenTest, IsMember) {
  472. absl::optional<AccessToken> token = AccessToken::FromCurrentProcess();
  473. ASSERT_TRUE(token);
  474. ASSERT_FALSE(token->IsImpersonation());
  475. CheckError(token->IsMember(WellKnownSid::kWorld),
  476. ERROR_NO_IMPERSONATION_TOKEN);
  477. absl::optional<Sid> sid = Sid::FromSddlString(L"S-1-1-2-3-4-5-6-7-8");
  478. ASSERT_TRUE(sid);
  479. CheckError(token->IsMember(*sid), ERROR_NO_IMPERSONATION_TOKEN);
  480. absl::optional<AccessToken> imp_token = AccessToken::FromCurrentProcess(true);
  481. EXPECT_TRUE(imp_token->IsMember(WellKnownSid::kWorld));
  482. EXPECT_FALSE(imp_token->IsMember(WellKnownSid::kNull));
  483. EXPECT_TRUE(imp_token->IsMember(imp_token->User()));
  484. EXPECT_FALSE(imp_token->IsMember(*sid));
  485. }
  486. TEST(AccessTokenTest, Restricted) {
  487. ATL::CAccessToken atl_token;
  488. ASSERT_TRUE(atl_token.GetProcessToken(MAXIMUM_ALLOWED));
  489. ATL::CTokenGroups disable_groups;
  490. disable_groups.Add(ATL::Sids::World(), 0);
  491. ATL::CTokenGroups restrict_groups;
  492. restrict_groups.Add(ATL::Sids::RestrictedCode(), 0);
  493. restrict_groups.Add(ATL::Sids::Users(), 0);
  494. ATL::CAccessToken atl_restricted;
  495. ASSERT_TRUE(atl_token.CreateRestrictedToken(&atl_restricted, disable_groups,
  496. restrict_groups));
  497. absl::optional<AccessToken> restricted =
  498. AccessToken::FromToken(atl_restricted.GetHandle());
  499. ASSERT_TRUE(restricted);
  500. EXPECT_TRUE(restricted->IsRestricted());
  501. CompareTokens(*restricted, atl_restricted, false);
  502. ATL::CSid::CSidArray sids;
  503. restrict_groups.GetSidsAndAttributes(&sids);
  504. ATL::CAtlArray<DWORD> attrs;
  505. for (UINT index = 0; index < sids.GetCount(); ++index) {
  506. attrs.Add(SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT |
  507. SE_GROUP_ENABLED);
  508. }
  509. CompareGroups(restricted->RestrictedSids(), sids, attrs);
  510. }
  511. TEST(AccessTokenTest, AppContainer) {
  512. if (GetVersion() < Version::WIN8)
  513. return;
  514. absl::optional<Sid> package_sid =
  515. Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-7");
  516. ASSERT_TRUE(package_sid);
  517. absl::optional<std::vector<Sid>> caps =
  518. Sid::FromKnownCapabilityVector({WellKnownCapability::kInternetClient,
  519. WellKnownCapability::kDocumentsLibrary});
  520. ASSERT_TRUE(caps);
  521. CompareAppContainer(*package_sid, *caps);
  522. CompareAppContainer(*package_sid, {});
  523. }
  524. TEST(AccessTokenTest, Anonymous) {
  525. ATL::CAccessToken atl_anon_token;
  526. ASSERT_TRUE(::ImpersonateAnonymousToken(::GetCurrentThread()));
  527. bool result = atl_anon_token.GetThreadToken(TOKEN_ALL_ACCESS);
  528. ::RevertToSelf();
  529. ASSERT_TRUE(result);
  530. absl::optional<AccessToken> anon_token =
  531. AccessToken::FromToken(atl_anon_token.GetHandle());
  532. ASSERT_TRUE(anon_token);
  533. CompareTokens(*anon_token, atl_anon_token);
  534. EXPECT_EQ(*Sid::FromKnownSid(WellKnownSid::kAnonymous), anon_token->User());
  535. absl::optional<Sid> logon_sid = anon_token->LogonId();
  536. EXPECT_FALSE(anon_token->LogonId());
  537. EXPECT_EQ(DWORD{ERROR_NOT_FOUND}, ::GetLastError());
  538. }
  539. } // namespace win
  540. } // namespace base