tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

access_token.cc (19629B)


      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/numerics/checked_math.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 
     16 namespace base::win {
     17 
     18 namespace {
     19 
     20 // The SECURITY_IMPERSONATION_LEVEL type is an enum and therefore can't be
     21 // forward declared in windows_types.h. Ensure our separate definition matches
     22 // the existing values for simplicity.
     23 static_assert(static_cast<int>(SecurityImpersonationLevel::kAnonymous) ==
     24              SecurityAnonymous);
     25 static_assert(static_cast<int>(SecurityImpersonationLevel::kIdentification) ==
     26              SecurityIdentification);
     27 static_assert(static_cast<int>(SecurityImpersonationLevel::kImpersonation) ==
     28              SecurityImpersonation);
     29 static_assert(static_cast<int>(SecurityImpersonationLevel::kDelegation) ==
     30              SecurityDelegation);
     31 
     32 typedef BOOL(WINAPI* CreateAppContainerTokenFunction)(
     33    HANDLE TokenHandle,
     34    PSECURITY_CAPABILITIES SecurityCapabilities,
     35    PHANDLE OutToken);
     36 
     37 Sid UnwrapSid(absl::optional<Sid>&& sid) {
     38  DCHECK(sid);
     39  return std::move(*sid);
     40 }
     41 
     42 absl::optional<std::vector<char>> GetTokenInfo(
     43    HANDLE token,
     44    TOKEN_INFORMATION_CLASS info_class) {
     45  // Get the buffer size. The call to GetTokenInformation should never succeed.
     46  DWORD size = 0;
     47  if (::GetTokenInformation(token, info_class, nullptr, 0, &size) || !size)
     48    return absl::nullopt;
     49 
     50  std::vector<char> temp_buffer(size);
     51  if (!::GetTokenInformation(token, info_class, temp_buffer.data(), size,
     52                             &size)) {
     53    return absl::nullopt;
     54  }
     55 
     56  return std::move(temp_buffer);
     57 }
     58 
     59 template <typename T>
     60 absl::optional<T> GetTokenInfoFixed(HANDLE token,
     61                                    TOKEN_INFORMATION_CLASS info_class) {
     62  T result;
     63  DWORD size = sizeof(T);
     64  if (!::GetTokenInformation(token, info_class, &result, size, &size))
     65    return absl::nullopt;
     66 
     67  return result;
     68 }
     69 
     70 template <typename T>
     71 T* GetType(absl::optional<std::vector<char>>& info) {
     72  DCHECK(info);
     73  DCHECK(info->size() >= sizeof(T));
     74  return reinterpret_cast<T*>(info->data());
     75 }
     76 
     77 std::vector<AccessToken::Group> GetGroupsFromToken(
     78    HANDLE token,
     79    TOKEN_INFORMATION_CLASS info_class) {
     80  absl::optional<std::vector<char>> groups = GetTokenInfo(token, info_class);
     81  // Sometimes only the GroupCount field is returned which indicates an empty
     82  // group set. If the buffer is smaller than the TOKEN_GROUPS structure then
     83  // just return an empty vector.
     84  if (!groups || (groups->size() < sizeof(TOKEN_GROUPS)))
     85    return {};
     86 
     87  TOKEN_GROUPS* groups_ptr = GetType<TOKEN_GROUPS>(groups);
     88  std::vector<AccessToken::Group> ret;
     89  ret.reserve(groups_ptr->GroupCount);
     90  for (DWORD index = 0; index < groups_ptr->GroupCount; ++index) {
     91    ret.emplace_back(UnwrapSid(Sid::FromPSID(groups_ptr->Groups[index].Sid)),
     92                     groups_ptr->Groups[index].Attributes);
     93  }
     94  return ret;
     95 }
     96 
     97 TOKEN_STATISTICS GetTokenStatistics(HANDLE token) {
     98  absl::optional<TOKEN_STATISTICS> value =
     99      GetTokenInfoFixed<TOKEN_STATISTICS>(token, TokenStatistics);
    100  if (!value)
    101    return {};
    102  return *value;
    103 }
    104 
    105 CHROME_LUID ConvertLuid(const LUID& luid) {
    106  CHROME_LUID ret;
    107  ret.LowPart = luid.LowPart;
    108  ret.HighPart = luid.HighPart;
    109  return ret;
    110 }
    111 
    112 HANDLE DuplicateToken(HANDLE token,
    113                      ACCESS_MASK desired_access,
    114                      SECURITY_IMPERSONATION_LEVEL imp_level,
    115                      TOKEN_TYPE type) {
    116  HANDLE new_token;
    117  if (!::DuplicateTokenEx(token, TOKEN_QUERY | desired_access, nullptr,
    118                          imp_level, type, &new_token)) {
    119    return nullptr;
    120  }
    121  return new_token;
    122 }
    123 
    124 std::vector<SID_AND_ATTRIBUTES> ConvertSids(const std::vector<Sid>& sids,
    125                                            DWORD attributes) {
    126  std::vector<SID_AND_ATTRIBUTES> ret;
    127  ret.reserve(sids.size());
    128  for (const Sid& sid : sids) {
    129    SID_AND_ATTRIBUTES entry = {};
    130    entry.Sid = sid.GetPSID();
    131    entry.Attributes = attributes;
    132    ret.push_back(entry);
    133  }
    134  return ret;
    135 }
    136 
    137 absl::optional<LUID> LookupPrivilege(const std::wstring& name) {
    138  LUID luid;
    139  if (!::LookupPrivilegeValue(nullptr, name.c_str(), &luid)) {
    140    return absl::nullopt;
    141  }
    142  return luid;
    143 }
    144 
    145 std::vector<LUID_AND_ATTRIBUTES> ConvertPrivileges(
    146    const std::vector<std::wstring>& privs,
    147    DWORD attributes) {
    148  std::vector<LUID_AND_ATTRIBUTES> ret;
    149  ret.reserve(privs.size());
    150  for (const std::wstring& priv : privs) {
    151    absl::optional<LUID> luid = LookupPrivilege(priv);
    152    if (!luid) {
    153      return {};
    154    }
    155    LUID_AND_ATTRIBUTES entry = {};
    156    entry.Luid = *luid;
    157    entry.Attributes = attributes;
    158    ret.push_back(entry);
    159  }
    160  return ret;
    161 }
    162 
    163 template <typename T>
    164 T* GetPointer(std::vector<T>& values) {
    165  if (values.empty()) {
    166    return nullptr;
    167  }
    168  return values.data();
    169 }
    170 
    171 template <typename T>
    172 bool Set(const ScopedHandle& token,
    173         TOKEN_INFORMATION_CLASS info_class,
    174         T& value) {
    175  return !!::SetTokenInformation(token.get(), info_class, &value,
    176                                 sizeof(value));
    177 }
    178 
    179 absl::optional<DWORD> AdjustPrivilege(const ScopedHandle& token,
    180                                      const std::wstring& priv,
    181                                      DWORD attributes) {
    182  TOKEN_PRIVILEGES token_privs = {};
    183  token_privs.PrivilegeCount = 1;
    184  absl::optional<LUID> luid = LookupPrivilege(priv);
    185  if (!luid) {
    186    return absl::nullopt;
    187  }
    188  token_privs.Privileges[0].Luid = *luid;
    189  token_privs.Privileges[0].Attributes = attributes;
    190 
    191  TOKEN_PRIVILEGES out_privs = {};
    192  DWORD out_length = 0;
    193  if (!::AdjustTokenPrivileges(token.get(), FALSE, &token_privs,
    194                               sizeof(out_privs), &out_privs, &out_length)) {
    195    return absl::nullopt;
    196  }
    197  if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
    198    return absl::nullopt;
    199  }
    200  if (out_privs.PrivilegeCount == 1) {
    201    return out_privs.Privileges[0].Attributes;
    202  }
    203  return attributes;
    204 }
    205 }  // namespace
    206 
    207 bool AccessToken::Group::IsIntegrity() const {
    208  return !!(attributes_ & SE_GROUP_INTEGRITY);
    209 }
    210 
    211 bool AccessToken::Group::IsEnabled() const {
    212  return !!(attributes_ & SE_GROUP_ENABLED);
    213 }
    214 
    215 bool AccessToken::Group::IsDenyOnly() const {
    216  return !!(attributes_ & SE_GROUP_USE_FOR_DENY_ONLY);
    217 }
    218 
    219 bool AccessToken::Group::IsLogonId() const {
    220  return (attributes_ & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID;
    221 }
    222 
    223 AccessToken::Group::Group(Sid&& sid, DWORD attributes)
    224    : sid_(std::move(sid)), attributes_(attributes) {}
    225 AccessToken::Group::Group(Group&&) = default;
    226 AccessToken::Group::Group::~Group() = default;
    227 
    228 std::wstring AccessToken::Privilege::GetName() const {
    229  WCHAR name[128];
    230  LUID luid;
    231  luid.LowPart = luid_.LowPart;
    232  luid.HighPart = luid_.HighPart;
    233  DWORD size = std::size(name);
    234  return ::LookupPrivilegeName(nullptr, &luid, name, &size)
    235             ? name
    236             : ASCIIToWide(
    237                   StringPrintf("%08lX-%08lX", luid.HighPart, luid.LowPart));
    238 }
    239 
    240 bool AccessToken::Privilege::IsEnabled() const {
    241  return !!(attributes_ & SE_PRIVILEGE_ENABLED);
    242 }
    243 
    244 AccessToken::Privilege::Privilege(CHROME_LUID luid, DWORD attributes)
    245    : luid_(luid), attributes_(attributes) {}
    246 
    247 absl::optional<AccessToken> AccessToken::FromToken(HANDLE token,
    248                                                   ACCESS_MASK desired_access) {
    249  HANDLE new_token;
    250  if (!::DuplicateHandle(::GetCurrentProcess(), token, ::GetCurrentProcess(),
    251                         &new_token, TOKEN_QUERY | desired_access, FALSE, 0)) {
    252    return absl::nullopt;
    253  }
    254  return AccessToken(new_token);
    255 }
    256 
    257 absl::optional<AccessToken> AccessToken::FromToken(ScopedHandle&& token) {
    258  if (!token.is_valid()) {
    259    ::SetLastError(ERROR_INVALID_HANDLE);
    260    return absl::nullopt;
    261  }
    262  if (!GetTokenInfoFixed<TOKEN_STATISTICS>(token.get(), TokenStatistics)) {
    263    return absl::nullopt;
    264  }
    265  return AccessToken(token.release());
    266 }
    267 
    268 absl::optional<AccessToken> AccessToken::FromProcess(
    269    HANDLE process,
    270    bool impersonation,
    271    ACCESS_MASK desired_access) {
    272  HANDLE token = nullptr;
    273  if (impersonation) {
    274    if (!::OpenProcessToken(process, TOKEN_DUPLICATE, &token))
    275      return absl::nullopt;
    276    ScopedHandle primary_token(token);
    277    token = DuplicateToken(primary_token.get(), desired_access,
    278                           SecurityIdentification, TokenImpersonation);
    279    if (!token) {
    280      return absl::nullopt;
    281    }
    282  } else {
    283    if (!::OpenProcessToken(process, TOKEN_QUERY | desired_access, &token))
    284      return absl::nullopt;
    285  }
    286  return AccessToken(token);
    287 }
    288 
    289 absl::optional<AccessToken> AccessToken::FromCurrentProcess(
    290    bool impersonation,
    291    ACCESS_MASK desired_access) {
    292  return FromProcess(::GetCurrentProcess(), impersonation, desired_access);
    293 }
    294 
    295 absl::optional<AccessToken> AccessToken::FromThread(
    296    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 absl::nullopt;
    303  return AccessToken(token);
    304 }
    305 
    306 absl::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 
    312 absl::optional<AccessToken> AccessToken::FromEffective(
    313    ACCESS_MASK desired_access) {
    314  absl::optional<AccessToken> token = FromCurrentThread(true, desired_access);
    315  if (token)
    316    return token;
    317  if (::GetLastError() != ERROR_NO_TOKEN)
    318    return absl::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 
    326 Sid AccessToken::User() const {
    327  return UserGroup().GetSid().Clone();
    328 }
    329 
    330 AccessToken::Group AccessToken::UserGroup() const {
    331  absl::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 
    337 Sid AccessToken::Owner() const {
    338  absl::optional<std::vector<char>> buffer =
    339      GetTokenInfo(token_.get(), TokenOwner);
    340  return UnwrapSid(Sid::FromPSID(GetType<TOKEN_OWNER>(buffer)->Owner));
    341 }
    342 
    343 Sid AccessToken::PrimaryGroup() const {
    344  absl::optional<std::vector<char>> buffer =
    345      GetTokenInfo(token_.get(), TokenPrimaryGroup);
    346  return UnwrapSid(
    347      Sid::FromPSID(GetType<TOKEN_PRIMARY_GROUP>(buffer)->PrimaryGroup));
    348 }
    349 
    350 absl::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 absl::nullopt;
    358 }
    359 
    360 DWORD AccessToken::IntegrityLevel() const {
    361  absl::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 
    371 bool AccessToken::SetIntegrityLevel(DWORD integrity_level) {
    372  absl::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 
    384 DWORD AccessToken::SessionId() const {
    385  absl::optional<DWORD> value =
    386      GetTokenInfoFixed<DWORD>(token_.get(), TokenSessionId);
    387  if (!value)
    388    return MAXDWORD;
    389  return *value;
    390 }
    391 
    392 std::vector<AccessToken::Group> AccessToken::Groups() const {
    393  return GetGroupsFromToken(token_.get(), TokenGroups);
    394 }
    395 
    396 bool AccessToken::IsRestricted() const {
    397  return !!::IsTokenRestricted(token_.get());
    398 }
    399 
    400 std::vector<AccessToken::Group> AccessToken::RestrictedSids() const {
    401  return GetGroupsFromToken(token_.get(), TokenRestrictedSids);
    402 }
    403 
    404 bool AccessToken::IsAppContainer() const {
    405  absl::optional<DWORD> value =
    406      GetTokenInfoFixed<DWORD>(token_.get(), TokenIsAppContainer);
    407  if (!value)
    408    return false;
    409  return !!*value;
    410 }
    411 
    412 absl::optional<Sid> AccessToken::AppContainerSid() const {
    413  absl::optional<std::vector<char>> buffer =
    414      GetTokenInfo(token_.get(), TokenAppContainerSid);
    415  if (!buffer)
    416    return absl::nullopt;
    417 
    418  TOKEN_APPCONTAINER_INFORMATION* info =
    419      GetType<TOKEN_APPCONTAINER_INFORMATION>(buffer);
    420  if (!info->TokenAppContainer)
    421    return absl::nullopt;
    422  return Sid::FromPSID(info->TokenAppContainer);
    423 }
    424 
    425 std::vector<AccessToken::Group> AccessToken::Capabilities() const {
    426  return GetGroupsFromToken(token_.get(), TokenCapabilities);
    427 }
    428 
    429 absl::optional<AccessToken> AccessToken::LinkedToken() const {
    430  absl::optional<TOKEN_LINKED_TOKEN> value =
    431      GetTokenInfoFixed<TOKEN_LINKED_TOKEN>(token_.get(), TokenLinkedToken);
    432  if (!value)
    433    return absl::nullopt;
    434  return AccessToken(value->LinkedToken);
    435 }
    436 
    437 absl::optional<AccessControlList> AccessToken::DefaultDacl() const {
    438  absl::optional<std::vector<char>> dacl_buffer =
    439      GetTokenInfo(token_.get(), TokenDefaultDacl);
    440  if (!dacl_buffer)
    441    return absl::nullopt;
    442  TOKEN_DEFAULT_DACL* dacl_ptr = GetType<TOKEN_DEFAULT_DACL>(dacl_buffer);
    443  return AccessControlList::FromPACL(dacl_ptr->DefaultDacl);
    444 }
    445 
    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 
    452 CHROME_LUID AccessToken::Id() const {
    453  return ConvertLuid(GetTokenStatistics(token_.get()).TokenId);
    454 }
    455 
    456 CHROME_LUID AccessToken::AuthenticationId() const {
    457  return ConvertLuid(GetTokenStatistics(token_.get()).AuthenticationId);
    458 }
    459 
    460 std::vector<AccessToken::Privilege> AccessToken::Privileges() const {
    461  absl::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 
    475 bool AccessToken::IsElevated() const {
    476  absl::optional<TOKEN_ELEVATION> value =
    477      GetTokenInfoFixed<TOKEN_ELEVATION>(token_.get(), TokenElevation);
    478  if (!value)
    479    return false;
    480  return !!value->TokenIsElevated;
    481 }
    482 
    483 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 
    489 bool AccessToken::IsMember(WellKnownSid known_sid) const {
    490  return IsMember(Sid(known_sid));
    491 }
    492 
    493 bool AccessToken::IsImpersonation() const {
    494  return GetTokenStatistics(token_.get()).TokenType == TokenImpersonation;
    495 }
    496 
    497 bool AccessToken::IsIdentification() const {
    498  return ImpersonationLevel() < SecurityImpersonationLevel::kImpersonation;
    499 }
    500 
    501 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 
    511 absl::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 absl::nullopt;
    517  }
    518  return AccessToken{token};
    519 }
    520 
    521 absl::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 absl::nullopt;
    530  }
    531  return AccessToken(token);
    532 }
    533 
    534 absl::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 absl::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 absl::nullopt;
    559  }
    560 
    561  ScopedHandle token_handle(token);
    562  return FromToken(token_handle.get(), desired_access);
    563 }
    564 
    565 absl::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 absl::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 absl::nullopt;
    588  }
    589 
    590  ScopedHandle token_handle(token);
    591  return FromToken(token_handle.get(), desired_access);
    592 }
    593 
    594 absl::optional<bool> AccessToken::SetPrivilege(const std::wstring& name,
    595                                               bool enable) {
    596  absl::optional<DWORD> attrs =
    597      AdjustPrivilege(token_, name.c_str(), enable ? SE_PRIVILEGE_ENABLED : 0);
    598  if (!attrs) {
    599    return absl::nullopt;
    600  }
    601  return !!(*attrs & SE_PRIVILEGE_ENABLED);
    602 }
    603 
    604 bool AccessToken::RemovePrivilege(const std::wstring& name) {
    605  return AdjustPrivilege(token_, name.c_str(), SE_PRIVILEGE_REMOVED)
    606      .has_value();
    607 }
    608 
    609 bool AccessToken::is_valid() const {
    610  return token_.is_valid();
    611 }
    612 
    613 HANDLE AccessToken::get() const {
    614  return token_.get();
    615 }
    616 
    617 ScopedHandle AccessToken::release() {
    618  return ScopedHandle(token_.release());
    619 }
    620 
    621 AccessToken::AccessToken(HANDLE token) : token_(token) {}
    622 
    623 }  // namespace base::win