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
UnwrapSid(absl::optional<Sid> && sid)37 Sid UnwrapSid(absl::optional<Sid>&& sid) {
38 DCHECK(sid);
39 return std::move(*sid);
40 }
41
GetTokenInfo(HANDLE token,TOKEN_INFORMATION_CLASS info_class)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>
GetTokenInfoFixed(HANDLE token,TOKEN_INFORMATION_CLASS info_class)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>
GetType(absl::optional<std::vector<char>> & info)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
GetGroupsFromToken(HANDLE token,TOKEN_INFORMATION_CLASS info_class)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
GetTokenStatistics(HANDLE token)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
ConvertLuid(const LUID & luid)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
DuplicateToken(HANDLE token,ACCESS_MASK desired_access,SECURITY_IMPERSONATION_LEVEL imp_level,TOKEN_TYPE type)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
ConvertSids(const std::vector<Sid> & sids,DWORD attributes)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
LookupPrivilege(const std::wstring & name)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
ConvertPrivileges(const std::vector<std::wstring> & privs,DWORD attributes)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>
GetPointer(std::vector<T> & values)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>
Set(const ScopedHandle & token,TOKEN_INFORMATION_CLASS info_class,T & value)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
AdjustPrivilege(const ScopedHandle & token,const std::wstring & priv,DWORD attributes)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
IsIntegrity() const207 bool AccessToken::Group::IsIntegrity() const {
208 return !!(attributes_ & SE_GROUP_INTEGRITY);
209 }
210
IsEnabled() const211 bool AccessToken::Group::IsEnabled() const {
212 return !!(attributes_ & SE_GROUP_ENABLED);
213 }
214
IsDenyOnly() const215 bool AccessToken::Group::IsDenyOnly() const {
216 return !!(attributes_ & SE_GROUP_USE_FOR_DENY_ONLY);
217 }
218
IsLogonId() const219 bool AccessToken::Group::IsLogonId() const {
220 return (attributes_ & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID;
221 }
222
Group(Sid && sid,DWORD attributes)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
GetName() const228 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
IsEnabled() const240 bool AccessToken::Privilege::IsEnabled() const {
241 return !!(attributes_ & SE_PRIVILEGE_ENABLED);
242 }
243
Privilege(CHROME_LUID luid,DWORD attributes)244 AccessToken::Privilege::Privilege(CHROME_LUID luid, DWORD attributes)
245 : luid_(luid), attributes_(attributes) {}
246
FromToken(HANDLE token,ACCESS_MASK desired_access)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
FromToken(ScopedHandle && token)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
FromProcess(HANDLE process,bool impersonation,ACCESS_MASK desired_access)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
FromCurrentProcess(bool impersonation,ACCESS_MASK desired_access)289 absl::optional<AccessToken> AccessToken::FromCurrentProcess(
290 bool impersonation,
291 ACCESS_MASK desired_access) {
292 return FromProcess(::GetCurrentProcess(), impersonation, desired_access);
293 }
294
FromThread(HANDLE thread,bool open_as_self,ACCESS_MASK desired_access)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
FromCurrentThread(bool open_as_self,ACCESS_MASK desired_access)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
FromEffective(ACCESS_MASK desired_access)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
User() const326 Sid AccessToken::User() const {
327 return UserGroup().GetSid().Clone();
328 }
329
UserGroup() const330 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
Owner() const337 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
PrimaryGroup() const343 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
LogonId() const350 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
IntegrityLevel() const360 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
SetIntegrityLevel(DWORD integrity_level)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
SessionId() const384 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
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 absl::optional<DWORD> value =
406 GetTokenInfoFixed<DWORD>(token_.get(), TokenIsAppContainer);
407 if (!value)
408 return false;
409 return !!*value;
410 }
411
AppContainerSid() const412 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
Capabilities() const425 std::vector<AccessToken::Group> AccessToken::Capabilities() const {
426 return GetGroupsFromToken(token_.get(), TokenCapabilities);
427 }
428
LinkedToken() const429 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
DefaultDacl() const437 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
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 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
IsElevated() const475 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
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 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
DuplicateImpersonation(SecurityImpersonationLevel impersonation_level,ACCESS_MASK desired_access) const521 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
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 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
CreateAppContainer(const Sid & appcontainer_sid,const std::vector<Sid> & capabilities,ACCESS_MASK desired_access) const565 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
SetPrivilege(const std::wstring & name,bool enable)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
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
is_valid() const609 bool AccessToken::is_valid() const {
610 return token_.is_valid();
611 }
612
get() const613 HANDLE AccessToken::get() const {
614 return token_.get();
615 }
616
release()617 ScopedHandle AccessToken::release() {
618 return ScopedHandle(token_.release());
619 }
620
AccessToken(HANDLE token)621 AccessToken::AccessToken(HANDLE token) : token_(token) {}
622
623 } // namespace base::win
624