xref: /aosp_15_r20/external/cronet/base/win/access_token.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/win/access_token.h"
6 
7 #include <windows.h>
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "base/containers/span.h"
13 #include "base/numerics/checked_math.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 
17 namespace base::win {
18 
19 namespace {
20 
21 // The SECURITY_IMPERSONATION_LEVEL type is an enum and therefore can't be
22 // forward declared in windows_types.h. Ensure our separate definition matches
23 // the existing values for simplicity.
24 static_assert(static_cast<int>(SecurityImpersonationLevel::kAnonymous) ==
25               SecurityAnonymous);
26 static_assert(static_cast<int>(SecurityImpersonationLevel::kIdentification) ==
27               SecurityIdentification);
28 static_assert(static_cast<int>(SecurityImpersonationLevel::kImpersonation) ==
29               SecurityImpersonation);
30 static_assert(static_cast<int>(SecurityImpersonationLevel::kDelegation) ==
31               SecurityDelegation);
32 
33 typedef BOOL(WINAPI* CreateAppContainerTokenFunction)(
34     HANDLE TokenHandle,
35     PSECURITY_CAPABILITIES SecurityCapabilities,
36     PHANDLE OutToken);
37 
UnwrapSid(std::optional<Sid> && sid)38 Sid UnwrapSid(std::optional<Sid>&& sid) {
39   DCHECK(sid);
40   return std::move(*sid);
41 }
42 
GetTokenInfo(HANDLE token,TOKEN_INFORMATION_CLASS info_class)43 std::optional<std::vector<char>> GetTokenInfo(
44     HANDLE token,
45     TOKEN_INFORMATION_CLASS info_class) {
46   // Get the buffer size. The call to GetTokenInformation should never succeed.
47   DWORD size = 0;
48   if (::GetTokenInformation(token, info_class, nullptr, 0, &size) || !size)
49     return std::nullopt;
50 
51   std::vector<char> temp_buffer(size);
52   if (!::GetTokenInformation(token, info_class, temp_buffer.data(), size,
53                              &size)) {
54     return std::nullopt;
55   }
56 
57   return std::move(temp_buffer);
58 }
59 
60 template <typename T>
GetTokenInfoFixed(HANDLE token,TOKEN_INFORMATION_CLASS info_class)61 std::optional<T> GetTokenInfoFixed(HANDLE token,
62                                    TOKEN_INFORMATION_CLASS info_class) {
63   T result;
64   DWORD size = sizeof(T);
65   if (!::GetTokenInformation(token, info_class, &result, size, &size))
66     return std::nullopt;
67 
68   return result;
69 }
70 
71 template <typename T>
GetType(std::optional<std::vector<char>> & info)72 T* GetType(std::optional<std::vector<char>>& info) {
73   DCHECK(info);
74   DCHECK(info->size() >= sizeof(T));
75   return reinterpret_cast<T*>(info->data());
76 }
77 
GetGroupsFromToken(HANDLE token,TOKEN_INFORMATION_CLASS info_class)78 std::vector<AccessToken::Group> GetGroupsFromToken(
79     HANDLE token,
80     TOKEN_INFORMATION_CLASS info_class) {
81   std::optional<std::vector<char>> groups = GetTokenInfo(token, info_class);
82   // Sometimes only the GroupCount field is returned which indicates an empty
83   // group set. If the buffer is smaller than the TOKEN_GROUPS structure then
84   // just return an empty vector.
85   if (!groups || (groups->size() < sizeof(TOKEN_GROUPS)))
86     return {};
87 
88   TOKEN_GROUPS* groups_ptr = GetType<TOKEN_GROUPS>(groups);
89   std::vector<AccessToken::Group> ret;
90   ret.reserve(groups_ptr->GroupCount);
91   for (DWORD index = 0; index < groups_ptr->GroupCount; ++index) {
92     ret.emplace_back(UnwrapSid(Sid::FromPSID(groups_ptr->Groups[index].Sid)),
93                      groups_ptr->Groups[index].Attributes);
94   }
95   return ret;
96 }
97 
GetTokenStatistics(HANDLE token)98 TOKEN_STATISTICS GetTokenStatistics(HANDLE token) {
99   std::optional<TOKEN_STATISTICS> value =
100       GetTokenInfoFixed<TOKEN_STATISTICS>(token, TokenStatistics);
101   if (!value)
102     return {};
103   return *value;
104 }
105 
ConvertLuid(const LUID & luid)106 CHROME_LUID ConvertLuid(const LUID& luid) {
107   CHROME_LUID ret;
108   ret.LowPart = luid.LowPart;
109   ret.HighPart = luid.HighPart;
110   return ret;
111 }
112 
DuplicateToken(HANDLE token,ACCESS_MASK desired_access,SECURITY_IMPERSONATION_LEVEL imp_level,TOKEN_TYPE type)113 HANDLE DuplicateToken(HANDLE token,
114                       ACCESS_MASK desired_access,
115                       SECURITY_IMPERSONATION_LEVEL imp_level,
116                       TOKEN_TYPE type) {
117   HANDLE new_token;
118   if (!::DuplicateTokenEx(token, TOKEN_QUERY | desired_access, nullptr,
119                           imp_level, type, &new_token)) {
120     return nullptr;
121   }
122   return new_token;
123 }
124 
ConvertSids(const std::vector<Sid> & sids,DWORD attributes)125 std::vector<SID_AND_ATTRIBUTES> ConvertSids(const std::vector<Sid>& sids,
126                                             DWORD attributes) {
127   std::vector<SID_AND_ATTRIBUTES> ret;
128   ret.reserve(sids.size());
129   for (const Sid& sid : sids) {
130     SID_AND_ATTRIBUTES entry = {};
131     entry.Sid = sid.GetPSID();
132     entry.Attributes = attributes;
133     ret.push_back(entry);
134   }
135   return ret;
136 }
137 
LookupPrivilege(const std::wstring & name)138 std::optional<LUID> LookupPrivilege(const std::wstring& name) {
139   LUID luid;
140   if (!::LookupPrivilegeValue(nullptr, name.c_str(), &luid)) {
141     return std::nullopt;
142   }
143   return luid;
144 }
145 
ConvertPrivileges(const std::vector<std::wstring> & privs,DWORD attributes)146 std::vector<LUID_AND_ATTRIBUTES> ConvertPrivileges(
147     const std::vector<std::wstring>& privs,
148     DWORD attributes) {
149   std::vector<LUID_AND_ATTRIBUTES> ret;
150   ret.reserve(privs.size());
151   for (const std::wstring& priv : privs) {
152     std::optional<LUID> luid = LookupPrivilege(priv);
153     if (!luid) {
154       return {};
155     }
156     LUID_AND_ATTRIBUTES entry = {};
157     entry.Luid = *luid;
158     entry.Attributes = attributes;
159     ret.push_back(entry);
160   }
161   return ret;
162 }
163 
164 template <typename T>
GetPointer(std::vector<T> & values)165 T* GetPointer(std::vector<T>& values) {
166   if (values.empty()) {
167     return nullptr;
168   }
169   return values.data();
170 }
171 
172 template <typename T>
Set(const ScopedHandle & token,TOKEN_INFORMATION_CLASS info_class,T & value)173 bool Set(const ScopedHandle& token,
174          TOKEN_INFORMATION_CLASS info_class,
175          T& value) {
176   return !!::SetTokenInformation(token.get(), info_class, &value,
177                                  sizeof(value));
178 }
179 
AdjustPrivilege(const ScopedHandle & token,const std::wstring & priv,DWORD attributes)180 std::optional<DWORD> AdjustPrivilege(const ScopedHandle& token,
181                                      const std::wstring& priv,
182                                      DWORD attributes) {
183   TOKEN_PRIVILEGES token_privs = {};
184   token_privs.PrivilegeCount = 1;
185   std::optional<LUID> luid = LookupPrivilege(priv);
186   if (!luid) {
187     return std::nullopt;
188   }
189   token_privs.Privileges[0].Luid = *luid;
190   token_privs.Privileges[0].Attributes = attributes;
191 
192   TOKEN_PRIVILEGES out_privs = {};
193   DWORD out_length = 0;
194   if (!::AdjustTokenPrivileges(token.get(), FALSE, &token_privs,
195                                sizeof(out_privs), &out_privs, &out_length)) {
196     return std::nullopt;
197   }
198   if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
199     return std::nullopt;
200   }
201   if (out_privs.PrivilegeCount == 1) {
202     return out_privs.Privileges[0].Attributes;
203   }
204   return attributes;
205 }
206 }  // namespace
207 
IsIntegrity() const208 bool AccessToken::Group::IsIntegrity() const {
209   return !!(attributes_ & SE_GROUP_INTEGRITY);
210 }
211 
IsEnabled() const212 bool AccessToken::Group::IsEnabled() const {
213   return !!(attributes_ & SE_GROUP_ENABLED);
214 }
215 
IsDenyOnly() const216 bool AccessToken::Group::IsDenyOnly() const {
217   return !!(attributes_ & SE_GROUP_USE_FOR_DENY_ONLY);
218 }
219 
IsLogonId() const220 bool AccessToken::Group::IsLogonId() const {
221   return (attributes_ & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID;
222 }
223 
Group(Sid && sid,DWORD attributes)224 AccessToken::Group::Group(Sid&& sid, DWORD attributes)
225     : sid_(std::move(sid)), attributes_(attributes) {}
226 AccessToken::Group::Group(Group&&) = default;
227 AccessToken::Group::Group::~Group() = default;
228 
GetName() const229 std::wstring AccessToken::Privilege::GetName() const {
230   WCHAR name[128];
231   LUID luid;
232   luid.LowPart = luid_.LowPart;
233   luid.HighPart = luid_.HighPart;
234   DWORD size = std::size(name);
235   return ::LookupPrivilegeName(nullptr, &luid, name, &size)
236              ? name
237              : ASCIIToWide(
238                    StringPrintf("%08lX-%08lX", luid.HighPart, luid.LowPart));
239 }
240 
IsEnabled() const241 bool AccessToken::Privilege::IsEnabled() const {
242   return !!(attributes_ & SE_PRIVILEGE_ENABLED);
243 }
244 
Privilege(CHROME_LUID luid,DWORD attributes)245 AccessToken::Privilege::Privilege(CHROME_LUID luid, DWORD attributes)
246     : luid_(luid), attributes_(attributes) {}
247 
FromToken(HANDLE token,ACCESS_MASK desired_access)248 std::optional<AccessToken> AccessToken::FromToken(HANDLE token,
249                                                   ACCESS_MASK desired_access) {
250   HANDLE new_token;
251   if (!::DuplicateHandle(::GetCurrentProcess(), token, ::GetCurrentProcess(),
252                          &new_token, TOKEN_QUERY | desired_access, FALSE, 0)) {
253     return std::nullopt;
254   }
255   return AccessToken(new_token);
256 }
257 
FromToken(ScopedHandle && token)258 std::optional<AccessToken> AccessToken::FromToken(ScopedHandle&& token) {
259   if (!token.is_valid()) {
260     ::SetLastError(ERROR_INVALID_HANDLE);
261     return std::nullopt;
262   }
263   if (!GetTokenInfoFixed<TOKEN_STATISTICS>(token.get(), TokenStatistics)) {
264     return std::nullopt;
265   }
266   return AccessToken(token.release());
267 }
268 
FromProcess(HANDLE process,bool impersonation,ACCESS_MASK desired_access)269 std::optional<AccessToken> AccessToken::FromProcess(
270     HANDLE process,
271     bool impersonation,
272     ACCESS_MASK desired_access) {
273   HANDLE token = nullptr;
274   if (impersonation) {
275     if (!::OpenProcessToken(process, TOKEN_DUPLICATE, &token))
276       return std::nullopt;
277     ScopedHandle primary_token(token);
278     token = DuplicateToken(primary_token.get(), desired_access,
279                            SecurityIdentification, TokenImpersonation);
280     if (!token) {
281       return std::nullopt;
282     }
283   } else {
284     if (!::OpenProcessToken(process, TOKEN_QUERY | desired_access, &token))
285       return std::nullopt;
286   }
287   return AccessToken(token);
288 }
289 
FromCurrentProcess(bool impersonation,ACCESS_MASK desired_access)290 std::optional<AccessToken> AccessToken::FromCurrentProcess(
291     bool impersonation,
292     ACCESS_MASK desired_access) {
293   return FromProcess(::GetCurrentProcess(), impersonation, desired_access);
294 }
295 
FromThread(HANDLE thread,bool open_as_self,ACCESS_MASK desired_access)296 std::optional<AccessToken> AccessToken::FromThread(HANDLE thread,
297                                                    bool open_as_self,
298                                                    ACCESS_MASK desired_access) {
299   HANDLE token;
300   if (!::OpenThreadToken(thread, TOKEN_QUERY | desired_access, open_as_self,
301                          &token))
302     return std::nullopt;
303   return AccessToken(token);
304 }
305 
FromCurrentThread(bool open_as_self,ACCESS_MASK desired_access)306 std::optional<AccessToken> AccessToken::FromCurrentThread(
307     bool open_as_self,
308     ACCESS_MASK desired_access) {
309   return FromThread(::GetCurrentThread(), open_as_self, desired_access);
310 }
311 
FromEffective(ACCESS_MASK desired_access)312 std::optional<AccessToken> AccessToken::FromEffective(
313     ACCESS_MASK desired_access) {
314   std::optional<AccessToken> token = FromCurrentThread(true, desired_access);
315   if (token)
316     return token;
317   if (::GetLastError() != ERROR_NO_TOKEN)
318     return std::nullopt;
319   return FromCurrentProcess(false, desired_access);
320 }
321 
322 AccessToken::AccessToken(AccessToken&&) = default;
323 AccessToken& AccessToken::operator=(AccessToken&&) = default;
324 AccessToken::~AccessToken() = default;
325 
User() const326 Sid AccessToken::User() const {
327   return UserGroup().GetSid().Clone();
328 }
329 
UserGroup() const330 AccessToken::Group AccessToken::UserGroup() const {
331   std::optional<std::vector<char>> buffer =
332       GetTokenInfo(token_.get(), TokenUser);
333   SID_AND_ATTRIBUTES& user = GetType<TOKEN_USER>(buffer)->User;
334   return {UnwrapSid(Sid::FromPSID(user.Sid)), user.Attributes};
335 }
336 
Owner() const337 Sid AccessToken::Owner() const {
338   std::optional<std::vector<char>> buffer =
339       GetTokenInfo(token_.get(), TokenOwner);
340   return UnwrapSid(Sid::FromPSID(GetType<TOKEN_OWNER>(buffer)->Owner));
341 }
342 
PrimaryGroup() const343 Sid AccessToken::PrimaryGroup() const {
344   std::optional<std::vector<char>> buffer =
345       GetTokenInfo(token_.get(), TokenPrimaryGroup);
346   return UnwrapSid(
347       Sid::FromPSID(GetType<TOKEN_PRIMARY_GROUP>(buffer)->PrimaryGroup));
348 }
349 
LogonId() const350 std::optional<Sid> AccessToken::LogonId() const {
351   std::vector<AccessToken::Group> groups =
352       GetGroupsFromToken(token_.get(), TokenLogonSid);
353   for (const AccessToken::Group& group : groups) {
354     if (group.IsLogonId())
355       return group.GetSid().Clone();
356   }
357   return std::nullopt;
358 }
359 
IntegrityLevel() const360 DWORD AccessToken::IntegrityLevel() const {
361   std::optional<std::vector<char>> buffer =
362       GetTokenInfo(token_.get(), TokenIntegrityLevel);
363   if (!buffer)
364     return MAXDWORD;
365 
366   PSID il_sid = GetType<TOKEN_MANDATORY_LABEL>(buffer)->Label.Sid;
367   return *::GetSidSubAuthority(
368       il_sid, static_cast<DWORD>(*::GetSidSubAuthorityCount(il_sid) - 1));
369 }
370 
SetIntegrityLevel(DWORD integrity_level)371 bool AccessToken::SetIntegrityLevel(DWORD integrity_level) {
372   std::optional<base::win::Sid> sid = Sid::FromIntegrityLevel(integrity_level);
373   if (!sid) {
374     ::SetLastError(ERROR_INVALID_SID);
375     return false;
376   }
377 
378   TOKEN_MANDATORY_LABEL label = {};
379   label.Label.Attributes = SE_GROUP_INTEGRITY;
380   label.Label.Sid = sid->GetPSID();
381   return Set(token_, TokenIntegrityLevel, label);
382 }
383 
SessionId() const384 DWORD AccessToken::SessionId() const {
385   std::optional<DWORD> value =
386       GetTokenInfoFixed<DWORD>(token_.get(), TokenSessionId);
387   if (!value)
388     return MAXDWORD;
389   return *value;
390 }
391 
Groups() const392 std::vector<AccessToken::Group> AccessToken::Groups() const {
393   return GetGroupsFromToken(token_.get(), TokenGroups);
394 }
395 
IsRestricted() const396 bool AccessToken::IsRestricted() const {
397   return !!::IsTokenRestricted(token_.get());
398 }
399 
RestrictedSids() const400 std::vector<AccessToken::Group> AccessToken::RestrictedSids() const {
401   return GetGroupsFromToken(token_.get(), TokenRestrictedSids);
402 }
403 
IsAppContainer() const404 bool AccessToken::IsAppContainer() const {
405   std::optional<DWORD> value =
406       GetTokenInfoFixed<DWORD>(token_.get(), TokenIsAppContainer);
407   if (!value)
408     return false;
409   return !!*value;
410 }
411 
AppContainerSid() const412 std::optional<Sid> AccessToken::AppContainerSid() const {
413   std::optional<std::vector<char>> buffer =
414       GetTokenInfo(token_.get(), TokenAppContainerSid);
415   if (!buffer)
416     return std::nullopt;
417 
418   TOKEN_APPCONTAINER_INFORMATION* info =
419       GetType<TOKEN_APPCONTAINER_INFORMATION>(buffer);
420   if (!info->TokenAppContainer)
421     return std::nullopt;
422   return Sid::FromPSID(info->TokenAppContainer);
423 }
424 
Capabilities() const425 std::vector<AccessToken::Group> AccessToken::Capabilities() const {
426   return GetGroupsFromToken(token_.get(), TokenCapabilities);
427 }
428 
LinkedToken() const429 std::optional<AccessToken> AccessToken::LinkedToken() const {
430   std::optional<TOKEN_LINKED_TOKEN> value =
431       GetTokenInfoFixed<TOKEN_LINKED_TOKEN>(token_.get(), TokenLinkedToken);
432   if (!value)
433     return std::nullopt;
434   return AccessToken(value->LinkedToken);
435 }
436 
DefaultDacl() const437 std::optional<AccessControlList> AccessToken::DefaultDacl() const {
438   std::optional<std::vector<char>> dacl_buffer =
439       GetTokenInfo(token_.get(), TokenDefaultDacl);
440   if (!dacl_buffer)
441     return std::nullopt;
442   TOKEN_DEFAULT_DACL* dacl_ptr = GetType<TOKEN_DEFAULT_DACL>(dacl_buffer);
443   return AccessControlList::FromPACL(dacl_ptr->DefaultDacl);
444 }
445 
SetDefaultDacl(const AccessControlList & default_dacl)446 bool AccessToken::SetDefaultDacl(const AccessControlList& default_dacl) {
447   TOKEN_DEFAULT_DACL set_default_dacl = {};
448   set_default_dacl.DefaultDacl = default_dacl.get();
449   return Set(token_, TokenDefaultDacl, set_default_dacl);
450 }
451 
Id() const452 CHROME_LUID AccessToken::Id() const {
453   return ConvertLuid(GetTokenStatistics(token_.get()).TokenId);
454 }
455 
AuthenticationId() const456 CHROME_LUID AccessToken::AuthenticationId() const {
457   return ConvertLuid(GetTokenStatistics(token_.get()).AuthenticationId);
458 }
459 
Privileges() const460 std::vector<AccessToken::Privilege> AccessToken::Privileges() const {
461   std::optional<std::vector<char>> privileges =
462       GetTokenInfo(token_.get(), TokenPrivileges);
463   if (!privileges)
464     return {};
465   TOKEN_PRIVILEGES* privileges_ptr = GetType<TOKEN_PRIVILEGES>(privileges);
466   std::vector<AccessToken::Privilege> ret;
467   ret.reserve(privileges_ptr->PrivilegeCount);
468   for (DWORD index = 0; index < privileges_ptr->PrivilegeCount; ++index) {
469     ret.emplace_back(ConvertLuid(privileges_ptr->Privileges[index].Luid),
470                      privileges_ptr->Privileges[index].Attributes);
471   }
472   return ret;
473 }
474 
IsElevated() const475 bool AccessToken::IsElevated() const {
476   std::optional<TOKEN_ELEVATION> value =
477       GetTokenInfoFixed<TOKEN_ELEVATION>(token_.get(), TokenElevation);
478   if (!value)
479     return false;
480   return !!value->TokenIsElevated;
481 }
482 
IsMember(const Sid & sid) const483 bool AccessToken::IsMember(const Sid& sid) const {
484   BOOL is_member = FALSE;
485   return ::CheckTokenMembership(token_.get(), sid.GetPSID(), &is_member) &&
486          !!is_member;
487 }
488 
IsMember(WellKnownSid known_sid) const489 bool AccessToken::IsMember(WellKnownSid known_sid) const {
490   return IsMember(Sid(known_sid));
491 }
492 
IsImpersonation() const493 bool AccessToken::IsImpersonation() const {
494   return GetTokenStatistics(token_.get()).TokenType == TokenImpersonation;
495 }
496 
IsIdentification() const497 bool AccessToken::IsIdentification() const {
498   return ImpersonationLevel() < SecurityImpersonationLevel::kImpersonation;
499 }
500 
ImpersonationLevel() const501 SecurityImpersonationLevel AccessToken::ImpersonationLevel() const {
502   TOKEN_STATISTICS stats = GetTokenStatistics(token_.get());
503   if (stats.TokenType != TokenImpersonation) {
504     return SecurityImpersonationLevel::kImpersonation;
505   }
506 
507   return static_cast<SecurityImpersonationLevel>(
508       GetTokenStatistics(token_.get()).ImpersonationLevel);
509 }
510 
DuplicatePrimary(ACCESS_MASK desired_access) const511 std::optional<AccessToken> AccessToken::DuplicatePrimary(
512     ACCESS_MASK desired_access) const {
513   HANDLE token = DuplicateToken(token_.get(), desired_access, SecurityAnonymous,
514                                 TokenPrimary);
515   if (!token) {
516     return std::nullopt;
517   }
518   return AccessToken{token};
519 }
520 
DuplicateImpersonation(SecurityImpersonationLevel impersonation_level,ACCESS_MASK desired_access) const521 std::optional<AccessToken> AccessToken::DuplicateImpersonation(
522     SecurityImpersonationLevel impersonation_level,
523     ACCESS_MASK desired_access) const {
524   HANDLE token = DuplicateToken(
525       token_.get(), desired_access,
526       static_cast<SECURITY_IMPERSONATION_LEVEL>(impersonation_level),
527       TokenImpersonation);
528   if (!token) {
529     return std::nullopt;
530   }
531   return AccessToken(token);
532 }
533 
CreateRestricted(DWORD flags,const std::vector<Sid> & sids_to_disable,const std::vector<std::wstring> & privileges_to_delete,const std::vector<Sid> & sids_to_restrict,ACCESS_MASK desired_access) const534 std::optional<AccessToken> AccessToken::CreateRestricted(
535     DWORD flags,
536     const std::vector<Sid>& sids_to_disable,
537     const std::vector<std::wstring>& privileges_to_delete,
538     const std::vector<Sid>& sids_to_restrict,
539     ACCESS_MASK desired_access) const {
540   std::vector<SID_AND_ATTRIBUTES> sids_to_disable_buf =
541       ConvertSids(sids_to_disable, 0);
542   std::vector<SID_AND_ATTRIBUTES> sids_to_restrict_buf =
543       ConvertSids(sids_to_restrict, 0);
544   std::vector<LUID_AND_ATTRIBUTES> privileges_to_delete_buf =
545       ConvertPrivileges(privileges_to_delete, 0);
546   if (privileges_to_delete_buf.size() != privileges_to_delete.size()) {
547     return std::nullopt;
548   }
549 
550   HANDLE token;
551   if (!::CreateRestrictedToken(
552           token_.get(), flags, checked_cast<DWORD>(sids_to_disable_buf.size()),
553           GetPointer(sids_to_disable_buf),
554           checked_cast<DWORD>(privileges_to_delete_buf.size()),
555           GetPointer(privileges_to_delete_buf),
556           checked_cast<DWORD>(sids_to_restrict_buf.size()),
557           GetPointer(sids_to_restrict_buf), &token)) {
558     return std::nullopt;
559   }
560 
561   ScopedHandle token_handle(token);
562   return FromToken(token_handle.get(), desired_access);
563 }
564 
CreateAppContainer(const Sid & appcontainer_sid,const std::vector<Sid> & capabilities,ACCESS_MASK desired_access) const565 std::optional<AccessToken> AccessToken::CreateAppContainer(
566     const Sid& appcontainer_sid,
567     const std::vector<Sid>& capabilities,
568     ACCESS_MASK desired_access) const {
569   static const CreateAppContainerTokenFunction CreateAppContainerToken =
570       reinterpret_cast<CreateAppContainerTokenFunction>(::GetProcAddress(
571           ::GetModuleHandle(L"kernelbase.dll"), "CreateAppContainerToken"));
572   if (!CreateAppContainerToken) {
573     ::SetLastError(ERROR_PROC_NOT_FOUND);
574     return std::nullopt;
575   }
576 
577   std::vector<SID_AND_ATTRIBUTES> capabilities_buf =
578       ConvertSids(capabilities, SE_GROUP_ENABLED);
579   SECURITY_CAPABILITIES security_capabilities = {};
580   security_capabilities.AppContainerSid = appcontainer_sid.GetPSID();
581   security_capabilities.Capabilities = GetPointer(capabilities_buf);
582   security_capabilities.CapabilityCount =
583       checked_cast<DWORD>(capabilities_buf.size());
584 
585   HANDLE token = nullptr;
586   if (!CreateAppContainerToken(token_.get(), &security_capabilities, &token)) {
587     return std::nullopt;
588   }
589 
590   ScopedHandle token_handle(token);
591   return FromToken(token_handle.get(), desired_access);
592 }
593 
SetPrivilege(const std::wstring & name,bool enable)594 std::optional<bool> AccessToken::SetPrivilege(const std::wstring& name,
595                                               bool enable) {
596   std::optional<DWORD> attrs =
597       AdjustPrivilege(token_, name.c_str(), enable ? SE_PRIVILEGE_ENABLED : 0);
598   if (!attrs) {
599     return std::nullopt;
600   }
601   return !!(*attrs & SE_PRIVILEGE_ENABLED);
602 }
603 
RemovePrivilege(const std::wstring & name)604 bool AccessToken::RemovePrivilege(const std::wstring& name) {
605   return AdjustPrivilege(token_, name.c_str(), SE_PRIVILEGE_REMOVED)
606       .has_value();
607 }
608 
RemoveAllPrivileges()609 bool AccessToken::RemoveAllPrivileges() {
610   std::optional<std::vector<char>> privileges_buffer =
611       GetTokenInfo(token_.get(), TokenPrivileges);
612   if (!privileges_buffer ||
613       (privileges_buffer->size() < sizeof(TOKEN_PRIVILEGES))) {
614     return false;
615   }
616   auto* const token_privileges = GetType<TOKEN_PRIVILEGES>(privileges_buffer);
617   if (privileges_buffer->size() <
618       (offsetof(TOKEN_PRIVILEGES, Privileges) +
619        sizeof(LUID_AND_ATTRIBUTES) * token_privileges->PrivilegeCount)) {
620     return false;
621   }
622 
623   for (auto privileges = base::make_span(&token_privileges->Privileges[0],
624                                          token_privileges->PrivilegeCount);
625        auto& privilege : privileges) {
626     privilege.Attributes = SE_PRIVILEGE_REMOVED;
627   }
628   return ::AdjustTokenPrivileges(
629       token_.get(), /*DisableAllPrivileges=*/FALSE, token_privileges,
630       static_cast<DWORD>(privileges_buffer->size()),
631       /*PreviousState=*/nullptr, /*ReturnLength=*/nullptr);
632 }
633 
is_valid() const634 bool AccessToken::is_valid() const {
635   return token_.is_valid();
636 }
637 
get() const638 HANDLE AccessToken::get() const {
639   return token_.get();
640 }
641 
release()642 ScopedHandle AccessToken::release() {
643   return ScopedHandle(token_.release());
644 }
645 
AccessToken(HANDLE token)646 AccessToken::AccessToken(HANDLE token) : token_(token) {}
647 
648 }  // namespace base::win
649