access_token.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 <utility>
  7. #include "base/strings/stringprintf.h"
  8. namespace base {
  9. namespace win {
  10. namespace {
  11. Sid UnwrapSid(absl::optional<Sid>&& sid) {
  12. DCHECK(sid);
  13. return std::move(*sid);
  14. }
  15. absl::optional<std::vector<char>> GetTokenInfo(
  16. HANDLE token,
  17. TOKEN_INFORMATION_CLASS info_class) {
  18. // Get the buffer size. The call to GetTokenInformation should never succeed.
  19. DWORD size = 0;
  20. if (::GetTokenInformation(token, info_class, nullptr, 0, &size) || !size)
  21. return absl::nullopt;
  22. std::vector<char> temp_buffer(size);
  23. if (!::GetTokenInformation(token, info_class, temp_buffer.data(), size,
  24. &size)) {
  25. return absl::nullopt;
  26. }
  27. return std::move(temp_buffer);
  28. }
  29. template <typename T>
  30. absl::optional<T> GetTokenInfoFixed(HANDLE token,
  31. TOKEN_INFORMATION_CLASS info_class) {
  32. T result;
  33. DWORD size = sizeof(T);
  34. if (!::GetTokenInformation(token, info_class, &result, size, &size))
  35. return absl::nullopt;
  36. return result;
  37. }
  38. template <typename T>
  39. T* GetType(absl::optional<std::vector<char>>& info) {
  40. DCHECK(info);
  41. DCHECK(info->size() >= sizeof(T));
  42. return reinterpret_cast<T*>(info->data());
  43. }
  44. std::vector<AccessToken::Group> GetGroupsFromToken(
  45. HANDLE token,
  46. TOKEN_INFORMATION_CLASS info_class) {
  47. absl::optional<std::vector<char>> groups = GetTokenInfo(token, info_class);
  48. // Sometimes only the GroupCount field is returned which indicates an empty
  49. // group set. If the buffer is smaller than the TOKEN_GROUPS structure then
  50. // just return an empty vector.
  51. if (!groups || (groups->size() < sizeof(TOKEN_GROUPS)))
  52. return {};
  53. TOKEN_GROUPS* groups_ptr = GetType<TOKEN_GROUPS>(groups);
  54. std::vector<AccessToken::Group> ret;
  55. ret.reserve(groups_ptr->GroupCount);
  56. for (DWORD index = 0; index < groups_ptr->GroupCount; ++index) {
  57. ret.emplace_back(UnwrapSid(Sid::FromPSID(groups_ptr->Groups[index].Sid)),
  58. groups_ptr->Groups[index].Attributes);
  59. }
  60. return ret;
  61. }
  62. TOKEN_STATISTICS GetTokenStatistics(HANDLE token) {
  63. absl::optional<TOKEN_STATISTICS> value =
  64. GetTokenInfoFixed<TOKEN_STATISTICS>(token, TokenStatistics);
  65. if (!value)
  66. return {};
  67. return *value;
  68. }
  69. CHROME_LUID ConvertLuid(const LUID& luid) {
  70. CHROME_LUID ret;
  71. ret.LowPart = luid.LowPart;
  72. ret.HighPart = luid.HighPart;
  73. return ret;
  74. }
  75. } // namespace
  76. bool AccessToken::Group::IsIntegrity() const {
  77. return !!(attributes_ & SE_GROUP_INTEGRITY);
  78. }
  79. bool AccessToken::Group::IsEnabled() const {
  80. return !!(attributes_ & SE_GROUP_ENABLED);
  81. }
  82. bool AccessToken::Group::IsDenyOnly() const {
  83. return !!(attributes_ & SE_GROUP_USE_FOR_DENY_ONLY);
  84. }
  85. bool AccessToken::Group::IsLogonId() const {
  86. return (attributes_ & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID;
  87. }
  88. AccessToken::Group::Group(Sid&& sid, DWORD attributes)
  89. : sid_(std::move(sid)), attributes_(attributes) {}
  90. AccessToken::Group::Group(Group&&) = default;
  91. AccessToken::Group::Group::~Group() = default;
  92. std::wstring AccessToken::Privilege::GetName() const {
  93. WCHAR name[128];
  94. LUID luid;
  95. luid.LowPart = luid_.LowPart;
  96. luid.HighPart = luid_.HighPart;
  97. DWORD size = std::size(name);
  98. if (!::LookupPrivilegeName(nullptr, &luid, name, &size))
  99. return base::StringPrintf(L"%08X-%08X", luid.HighPart, luid.LowPart);
  100. return name;
  101. }
  102. bool AccessToken::Privilege::IsEnabled() const {
  103. return !!(attributes_ & SE_PRIVILEGE_ENABLED);
  104. }
  105. AccessToken::Privilege::Privilege(CHROME_LUID luid, DWORD attributes)
  106. : luid_(luid), attributes_(attributes) {}
  107. AccessToken::Dacl::Dacl(const ACL* dacl)
  108. : acl_buffer_(reinterpret_cast<const char*>(dacl),
  109. reinterpret_cast<const char*>(dacl) + dacl->AclSize) {}
  110. AccessToken::Dacl::Dacl(Dacl&&) = default;
  111. AccessToken::Dacl::~Dacl() {}
  112. ACL* AccessToken::Dacl::GetAcl() const {
  113. return const_cast<ACL*>(reinterpret_cast<const ACL*>(acl_buffer_.data()));
  114. }
  115. absl::optional<AccessToken> AccessToken::FromToken(HANDLE token) {
  116. HANDLE new_token;
  117. if (!::DuplicateHandle(::GetCurrentProcess(), token, ::GetCurrentProcess(),
  118. &new_token, TOKEN_QUERY, FALSE, 0)) {
  119. return absl::nullopt;
  120. }
  121. return AccessToken(new_token);
  122. }
  123. absl::optional<AccessToken> AccessToken::FromProcess(HANDLE process,
  124. bool impersonation) {
  125. HANDLE token = nullptr;
  126. if (impersonation) {
  127. if (!::OpenProcessToken(process, TOKEN_DUPLICATE, &token))
  128. return absl::nullopt;
  129. ScopedHandle primary_token(token);
  130. if (!::DuplicateToken(primary_token.get(), SecurityIdentification, &token))
  131. return absl::nullopt;
  132. } else {
  133. if (!::OpenProcessToken(process, TOKEN_QUERY, &token))
  134. return absl::nullopt;
  135. }
  136. return AccessToken(token);
  137. }
  138. absl::optional<AccessToken> AccessToken::FromCurrentProcess(
  139. bool impersonation) {
  140. return FromProcess(::GetCurrentProcess(), impersonation);
  141. }
  142. absl::optional<AccessToken> AccessToken::FromThread(HANDLE thread,
  143. bool open_as_self) {
  144. HANDLE token;
  145. if (!::OpenThreadToken(thread, TOKEN_QUERY, open_as_self, &token))
  146. return absl::nullopt;
  147. return AccessToken(token);
  148. }
  149. absl::optional<AccessToken> AccessToken::FromCurrentThread(bool open_as_self) {
  150. return FromThread(::GetCurrentThread(), open_as_self);
  151. }
  152. absl::optional<AccessToken> AccessToken::FromEffective() {
  153. absl::optional<AccessToken> token = FromCurrentThread();
  154. if (token)
  155. return token;
  156. if (::GetLastError() != ERROR_NO_TOKEN)
  157. return absl::nullopt;
  158. return FromCurrentProcess();
  159. }
  160. AccessToken::AccessToken(AccessToken&&) = default;
  161. AccessToken& AccessToken::operator=(AccessToken&&) = default;
  162. AccessToken::~AccessToken() = default;
  163. Sid AccessToken::User() const {
  164. return UserGroup().GetSid().Clone();
  165. }
  166. AccessToken::Group AccessToken::UserGroup() const {
  167. absl::optional<std::vector<char>> buffer =
  168. GetTokenInfo(token_.get(), TokenUser);
  169. SID_AND_ATTRIBUTES& user = GetType<TOKEN_USER>(buffer)->User;
  170. return {UnwrapSid(Sid::FromPSID(user.Sid)), user.Attributes};
  171. }
  172. Sid AccessToken::Owner() const {
  173. absl::optional<std::vector<char>> buffer =
  174. GetTokenInfo(token_.get(), TokenOwner);
  175. return UnwrapSid(Sid::FromPSID(GetType<TOKEN_OWNER>(buffer)->Owner));
  176. }
  177. Sid AccessToken::PrimaryGroup() const {
  178. absl::optional<std::vector<char>> buffer =
  179. GetTokenInfo(token_.get(), TokenPrimaryGroup);
  180. return UnwrapSid(
  181. Sid::FromPSID(GetType<TOKEN_PRIMARY_GROUP>(buffer)->PrimaryGroup));
  182. }
  183. absl::optional<Sid> AccessToken::LogonId() const {
  184. std::vector<AccessToken::Group> groups =
  185. GetGroupsFromToken(token_.get(), TokenLogonSid);
  186. for (const AccessToken::Group& group : groups) {
  187. if (group.IsLogonId())
  188. return group.GetSid().Clone();
  189. }
  190. return absl::nullopt;
  191. }
  192. DWORD AccessToken::IntegrityLevel() const {
  193. absl::optional<std::vector<char>> buffer =
  194. GetTokenInfo(token_.get(), TokenIntegrityLevel);
  195. if (!buffer)
  196. return MAXDWORD;
  197. PSID il_sid = GetType<TOKEN_MANDATORY_LABEL>(buffer)->Label.Sid;
  198. return *::GetSidSubAuthority(
  199. il_sid, static_cast<DWORD>(*::GetSidSubAuthorityCount(il_sid) - 1));
  200. }
  201. DWORD AccessToken::SessionId() const {
  202. absl::optional<DWORD> value =
  203. GetTokenInfoFixed<DWORD>(token_.get(), TokenSessionId);
  204. if (!value)
  205. return MAXDWORD;
  206. return *value;
  207. }
  208. std::vector<AccessToken::Group> AccessToken::Groups() const {
  209. return GetGroupsFromToken(token_.get(), TokenGroups);
  210. }
  211. bool AccessToken::IsRestricted() const {
  212. return !!::IsTokenRestricted(token_.get());
  213. }
  214. std::vector<AccessToken::Group> AccessToken::RestrictedSids() const {
  215. return GetGroupsFromToken(token_.get(), TokenRestrictedSids);
  216. }
  217. bool AccessToken::IsAppContainer() const {
  218. absl::optional<DWORD> value =
  219. GetTokenInfoFixed<DWORD>(token_.get(), TokenIsAppContainer);
  220. if (!value)
  221. return false;
  222. return !!*value;
  223. }
  224. absl::optional<Sid> AccessToken::AppContainerSid() const {
  225. absl::optional<std::vector<char>> buffer =
  226. GetTokenInfo(token_.get(), TokenAppContainerSid);
  227. if (!buffer)
  228. return absl::nullopt;
  229. TOKEN_APPCONTAINER_INFORMATION* info =
  230. GetType<TOKEN_APPCONTAINER_INFORMATION>(buffer);
  231. if (!info->TokenAppContainer)
  232. return absl::nullopt;
  233. return Sid::FromPSID(info->TokenAppContainer);
  234. }
  235. std::vector<AccessToken::Group> AccessToken::Capabilities() const {
  236. return GetGroupsFromToken(token_.get(), TokenCapabilities);
  237. }
  238. absl::optional<AccessToken> AccessToken::LinkedToken() const {
  239. absl::optional<TOKEN_LINKED_TOKEN> value =
  240. GetTokenInfoFixed<TOKEN_LINKED_TOKEN>(token_.get(), TokenLinkedToken);
  241. if (!value)
  242. return absl::nullopt;
  243. return AccessToken(value->LinkedToken);
  244. }
  245. absl::optional<AccessToken::Dacl> AccessToken::DefaultDacl() const {
  246. absl::optional<std::vector<char>> dacl_buffer =
  247. GetTokenInfo(token_.get(), TokenDefaultDacl);
  248. if (!dacl_buffer)
  249. return absl::nullopt;
  250. TOKEN_DEFAULT_DACL* dacl_ptr = GetType<TOKEN_DEFAULT_DACL>(dacl_buffer);
  251. if (!dacl_ptr->DefaultDacl)
  252. return absl::nullopt;
  253. DCHECK(::IsValidAcl(dacl_ptr->DefaultDacl));
  254. DCHECK_GE(dacl_buffer->size(), dacl_ptr->DefaultDacl->AclSize);
  255. return AccessToken::Dacl{dacl_ptr->DefaultDacl};
  256. }
  257. CHROME_LUID AccessToken::Id() const {
  258. return ConvertLuid(GetTokenStatistics(token_.get()).TokenId);
  259. }
  260. CHROME_LUID AccessToken::AuthenticationId() const {
  261. return ConvertLuid(GetTokenStatistics(token_.get()).AuthenticationId);
  262. }
  263. std::vector<AccessToken::Privilege> AccessToken::Privileges() const {
  264. absl::optional<std::vector<char>> privileges =
  265. GetTokenInfo(token_.get(), TokenPrivileges);
  266. if (!privileges)
  267. return {};
  268. TOKEN_PRIVILEGES* privileges_ptr = GetType<TOKEN_PRIVILEGES>(privileges);
  269. std::vector<AccessToken::Privilege> ret;
  270. ret.reserve(privileges_ptr->PrivilegeCount);
  271. for (DWORD index = 0; index < privileges_ptr->PrivilegeCount; ++index) {
  272. ret.emplace_back(ConvertLuid(privileges_ptr->Privileges[index].Luid),
  273. privileges_ptr->Privileges[index].Attributes);
  274. }
  275. return ret;
  276. }
  277. bool AccessToken::IsElevated() const {
  278. absl::optional<TOKEN_ELEVATION> value =
  279. GetTokenInfoFixed<TOKEN_ELEVATION>(token_.get(), TokenElevation);
  280. if (!value)
  281. return false;
  282. return !!value->TokenIsElevated;
  283. }
  284. bool AccessToken::IsMember(const Sid& sid) const {
  285. BOOL is_member = FALSE;
  286. return ::CheckTokenMembership(token_.get(), sid.GetPSID(), &is_member) &&
  287. !!is_member;
  288. }
  289. bool AccessToken::IsMember(WellKnownSid known_sid) const {
  290. absl::optional<Sid> sid = Sid::FromKnownSid(known_sid);
  291. if (!sid)
  292. return false;
  293. return IsMember(*sid);
  294. }
  295. bool AccessToken::IsImpersonation() const {
  296. return GetTokenStatistics(token_.get()).TokenType == TokenImpersonation;
  297. }
  298. bool AccessToken::IsIdentification() const {
  299. TOKEN_STATISTICS stats = GetTokenStatistics(token_.get());
  300. if (stats.TokenType != TokenImpersonation)
  301. return false;
  302. return stats.ImpersonationLevel < SecurityImpersonation;
  303. }
  304. AccessToken::AccessToken(HANDLE token) : token_(token) {}
  305. } // namespace win
  306. } // namespace base