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