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