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