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/containers/span.h"
13 #include "base/numerics/checked_math.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16
17 namespace base::win {
18
19 namespace {
20
21 // The SECURITY_IMPERSONATION_LEVEL type is an enum and therefore can't be
22 // forward declared in windows_types.h. Ensure our separate definition matches
23 // the existing values for simplicity.
24 static_assert(static_cast<int>(SecurityImpersonationLevel::kAnonymous) ==
25 SecurityAnonymous);
26 static_assert(static_cast<int>(SecurityImpersonationLevel::kIdentification) ==
27 SecurityIdentification);
28 static_assert(static_cast<int>(SecurityImpersonationLevel::kImpersonation) ==
29 SecurityImpersonation);
30 static_assert(static_cast<int>(SecurityImpersonationLevel::kDelegation) ==
31 SecurityDelegation);
32
33 typedef BOOL(WINAPI* CreateAppContainerTokenFunction)(
34 HANDLE TokenHandle,
35 PSECURITY_CAPABILITIES SecurityCapabilities,
36 PHANDLE OutToken);
37
UnwrapSid(std::optional<Sid> && sid)38 Sid UnwrapSid(std::optional<Sid>&& sid) {
39 DCHECK(sid);
40 return std::move(*sid);
41 }
42
GetTokenInfo(HANDLE token,TOKEN_INFORMATION_CLASS info_class)43 std::optional<std::vector<char>> GetTokenInfo(
44 HANDLE token,
45 TOKEN_INFORMATION_CLASS info_class) {
46 // Get the buffer size. The call to GetTokenInformation should never succeed.
47 DWORD size = 0;
48 if (::GetTokenInformation(token, info_class, nullptr, 0, &size) || !size)
49 return std::nullopt;
50
51 std::vector<char> temp_buffer(size);
52 if (!::GetTokenInformation(token, info_class, temp_buffer.data(), size,
53 &size)) {
54 return std::nullopt;
55 }
56
57 return std::move(temp_buffer);
58 }
59
60 template <typename T>
GetTokenInfoFixed(HANDLE token,TOKEN_INFORMATION_CLASS info_class)61 std::optional<T> GetTokenInfoFixed(HANDLE token,
62 TOKEN_INFORMATION_CLASS info_class) {
63 T result;
64 DWORD size = sizeof(T);
65 if (!::GetTokenInformation(token, info_class, &result, size, &size))
66 return std::nullopt;
67
68 return result;
69 }
70
71 template <typename T>
GetType(std::optional<std::vector<char>> & info)72 T* GetType(std::optional<std::vector<char>>& info) {
73 DCHECK(info);
74 DCHECK(info->size() >= sizeof(T));
75 return reinterpret_cast<T*>(info->data());
76 }
77
GetGroupsFromToken(HANDLE token,TOKEN_INFORMATION_CLASS info_class)78 std::vector<AccessToken::Group> GetGroupsFromToken(
79 HANDLE token,
80 TOKEN_INFORMATION_CLASS info_class) {
81 std::optional<std::vector<char>> groups = GetTokenInfo(token, info_class);
82 // Sometimes only the GroupCount field is returned which indicates an empty
83 // group set. If the buffer is smaller than the TOKEN_GROUPS structure then
84 // just return an empty vector.
85 if (!groups || (groups->size() < sizeof(TOKEN_GROUPS)))
86 return {};
87
88 TOKEN_GROUPS* groups_ptr = GetType<TOKEN_GROUPS>(groups);
89 std::vector<AccessToken::Group> ret;
90 ret.reserve(groups_ptr->GroupCount);
91 for (DWORD index = 0; index < groups_ptr->GroupCount; ++index) {
92 ret.emplace_back(UnwrapSid(Sid::FromPSID(groups_ptr->Groups[index].Sid)),
93 groups_ptr->Groups[index].Attributes);
94 }
95 return ret;
96 }
97
GetTokenStatistics(HANDLE token)98 TOKEN_STATISTICS GetTokenStatistics(HANDLE token) {
99 std::optional<TOKEN_STATISTICS> value =
100 GetTokenInfoFixed<TOKEN_STATISTICS>(token, TokenStatistics);
101 if (!value)
102 return {};
103 return *value;
104 }
105
ConvertLuid(const LUID & luid)106 CHROME_LUID ConvertLuid(const LUID& luid) {
107 CHROME_LUID ret;
108 ret.LowPart = luid.LowPart;
109 ret.HighPart = luid.HighPart;
110 return ret;
111 }
112
DuplicateToken(HANDLE token,ACCESS_MASK desired_access,SECURITY_IMPERSONATION_LEVEL imp_level,TOKEN_TYPE type)113 HANDLE DuplicateToken(HANDLE token,
114 ACCESS_MASK desired_access,
115 SECURITY_IMPERSONATION_LEVEL imp_level,
116 TOKEN_TYPE type) {
117 HANDLE new_token;
118 if (!::DuplicateTokenEx(token, TOKEN_QUERY | desired_access, nullptr,
119 imp_level, type, &new_token)) {
120 return nullptr;
121 }
122 return new_token;
123 }
124
ConvertSids(const std::vector<Sid> & sids,DWORD attributes)125 std::vector<SID_AND_ATTRIBUTES> ConvertSids(const std::vector<Sid>& sids,
126 DWORD attributes) {
127 std::vector<SID_AND_ATTRIBUTES> ret;
128 ret.reserve(sids.size());
129 for (const Sid& sid : sids) {
130 SID_AND_ATTRIBUTES entry = {};
131 entry.Sid = sid.GetPSID();
132 entry.Attributes = attributes;
133 ret.push_back(entry);
134 }
135 return ret;
136 }
137
LookupPrivilege(const std::wstring & name)138 std::optional<LUID> LookupPrivilege(const std::wstring& name) {
139 LUID luid;
140 if (!::LookupPrivilegeValue(nullptr, name.c_str(), &luid)) {
141 return std::nullopt;
142 }
143 return luid;
144 }
145
ConvertPrivileges(const std::vector<std::wstring> & privs,DWORD attributes)146 std::vector<LUID_AND_ATTRIBUTES> ConvertPrivileges(
147 const std::vector<std::wstring>& privs,
148 DWORD attributes) {
149 std::vector<LUID_AND_ATTRIBUTES> ret;
150 ret.reserve(privs.size());
151 for (const std::wstring& priv : privs) {
152 std::optional<LUID> luid = LookupPrivilege(priv);
153 if (!luid) {
154 return {};
155 }
156 LUID_AND_ATTRIBUTES entry = {};
157 entry.Luid = *luid;
158 entry.Attributes = attributes;
159 ret.push_back(entry);
160 }
161 return ret;
162 }
163
164 template <typename T>
GetPointer(std::vector<T> & values)165 T* GetPointer(std::vector<T>& values) {
166 if (values.empty()) {
167 return nullptr;
168 }
169 return values.data();
170 }
171
172 template <typename T>
Set(const ScopedHandle & token,TOKEN_INFORMATION_CLASS info_class,T & value)173 bool Set(const ScopedHandle& token,
174 TOKEN_INFORMATION_CLASS info_class,
175 T& value) {
176 return !!::SetTokenInformation(token.get(), info_class, &value,
177 sizeof(value));
178 }
179
AdjustPrivilege(const ScopedHandle & token,const std::wstring & priv,DWORD attributes)180 std::optional<DWORD> AdjustPrivilege(const ScopedHandle& token,
181 const std::wstring& priv,
182 DWORD attributes) {
183 TOKEN_PRIVILEGES token_privs = {};
184 token_privs.PrivilegeCount = 1;
185 std::optional<LUID> luid = LookupPrivilege(priv);
186 if (!luid) {
187 return std::nullopt;
188 }
189 token_privs.Privileges[0].Luid = *luid;
190 token_privs.Privileges[0].Attributes = attributes;
191
192 TOKEN_PRIVILEGES out_privs = {};
193 DWORD out_length = 0;
194 if (!::AdjustTokenPrivileges(token.get(), FALSE, &token_privs,
195 sizeof(out_privs), &out_privs, &out_length)) {
196 return std::nullopt;
197 }
198 if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
199 return std::nullopt;
200 }
201 if (out_privs.PrivilegeCount == 1) {
202 return out_privs.Privileges[0].Attributes;
203 }
204 return attributes;
205 }
206 } // namespace
207
IsIntegrity() const208 bool AccessToken::Group::IsIntegrity() const {
209 return !!(attributes_ & SE_GROUP_INTEGRITY);
210 }
211
IsEnabled() const212 bool AccessToken::Group::IsEnabled() const {
213 return !!(attributes_ & SE_GROUP_ENABLED);
214 }
215
IsDenyOnly() const216 bool AccessToken::Group::IsDenyOnly() const {
217 return !!(attributes_ & SE_GROUP_USE_FOR_DENY_ONLY);
218 }
219
IsLogonId() const220 bool AccessToken::Group::IsLogonId() const {
221 return (attributes_ & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID;
222 }
223
Group(Sid && sid,DWORD attributes)224 AccessToken::Group::Group(Sid&& sid, DWORD attributes)
225 : sid_(std::move(sid)), attributes_(attributes) {}
226 AccessToken::Group::Group(Group&&) = default;
227 AccessToken::Group::Group::~Group() = default;
228
GetName() const229 std::wstring AccessToken::Privilege::GetName() const {
230 WCHAR name[128];
231 LUID luid;
232 luid.LowPart = luid_.LowPart;
233 luid.HighPart = luid_.HighPart;
234 DWORD size = std::size(name);
235 return ::LookupPrivilegeName(nullptr, &luid, name, &size)
236 ? name
237 : ASCIIToWide(
238 StringPrintf("%08lX-%08lX", luid.HighPart, luid.LowPart));
239 }
240
IsEnabled() const241 bool AccessToken::Privilege::IsEnabled() const {
242 return !!(attributes_ & SE_PRIVILEGE_ENABLED);
243 }
244
Privilege(CHROME_LUID luid,DWORD attributes)245 AccessToken::Privilege::Privilege(CHROME_LUID luid, DWORD attributes)
246 : luid_(luid), attributes_(attributes) {}
247
FromToken(HANDLE token,ACCESS_MASK desired_access)248 std::optional<AccessToken> AccessToken::FromToken(HANDLE token,
249 ACCESS_MASK desired_access) {
250 HANDLE new_token;
251 if (!::DuplicateHandle(::GetCurrentProcess(), token, ::GetCurrentProcess(),
252 &new_token, TOKEN_QUERY | desired_access, FALSE, 0)) {
253 return std::nullopt;
254 }
255 return AccessToken(new_token);
256 }
257
FromToken(ScopedHandle && token)258 std::optional<AccessToken> AccessToken::FromToken(ScopedHandle&& token) {
259 if (!token.is_valid()) {
260 ::SetLastError(ERROR_INVALID_HANDLE);
261 return std::nullopt;
262 }
263 if (!GetTokenInfoFixed<TOKEN_STATISTICS>(token.get(), TokenStatistics)) {
264 return std::nullopt;
265 }
266 return AccessToken(token.release());
267 }
268
FromProcess(HANDLE process,bool impersonation,ACCESS_MASK desired_access)269 std::optional<AccessToken> AccessToken::FromProcess(
270 HANDLE process,
271 bool impersonation,
272 ACCESS_MASK desired_access) {
273 HANDLE token = nullptr;
274 if (impersonation) {
275 if (!::OpenProcessToken(process, TOKEN_DUPLICATE, &token))
276 return std::nullopt;
277 ScopedHandle primary_token(token);
278 token = DuplicateToken(primary_token.get(), desired_access,
279 SecurityIdentification, TokenImpersonation);
280 if (!token) {
281 return std::nullopt;
282 }
283 } else {
284 if (!::OpenProcessToken(process, TOKEN_QUERY | desired_access, &token))
285 return std::nullopt;
286 }
287 return AccessToken(token);
288 }
289
FromCurrentProcess(bool impersonation,ACCESS_MASK desired_access)290 std::optional<AccessToken> AccessToken::FromCurrentProcess(
291 bool impersonation,
292 ACCESS_MASK desired_access) {
293 return FromProcess(::GetCurrentProcess(), impersonation, desired_access);
294 }
295
FromThread(HANDLE thread,bool open_as_self,ACCESS_MASK desired_access)296 std::optional<AccessToken> AccessToken::FromThread(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 std::nullopt;
303 return AccessToken(token);
304 }
305
FromCurrentThread(bool open_as_self,ACCESS_MASK desired_access)306 std::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 std::optional<AccessToken> AccessToken::FromEffective(
313 ACCESS_MASK desired_access) {
314 std::optional<AccessToken> token = FromCurrentThread(true, desired_access);
315 if (token)
316 return token;
317 if (::GetLastError() != ERROR_NO_TOKEN)
318 return std::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 std::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 std::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 std::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 std::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 std::nullopt;
358 }
359
IntegrityLevel() const360 DWORD AccessToken::IntegrityLevel() const {
361 std::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 std::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 std::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 std::optional<DWORD> value =
406 GetTokenInfoFixed<DWORD>(token_.get(), TokenIsAppContainer);
407 if (!value)
408 return false;
409 return !!*value;
410 }
411
AppContainerSid() const412 std::optional<Sid> AccessToken::AppContainerSid() const {
413 std::optional<std::vector<char>> buffer =
414 GetTokenInfo(token_.get(), TokenAppContainerSid);
415 if (!buffer)
416 return std::nullopt;
417
418 TOKEN_APPCONTAINER_INFORMATION* info =
419 GetType<TOKEN_APPCONTAINER_INFORMATION>(buffer);
420 if (!info->TokenAppContainer)
421 return std::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 std::optional<AccessToken> AccessToken::LinkedToken() const {
430 std::optional<TOKEN_LINKED_TOKEN> value =
431 GetTokenInfoFixed<TOKEN_LINKED_TOKEN>(token_.get(), TokenLinkedToken);
432 if (!value)
433 return std::nullopt;
434 return AccessToken(value->LinkedToken);
435 }
436
DefaultDacl() const437 std::optional<AccessControlList> AccessToken::DefaultDacl() const {
438 std::optional<std::vector<char>> dacl_buffer =
439 GetTokenInfo(token_.get(), TokenDefaultDacl);
440 if (!dacl_buffer)
441 return std::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 std::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 std::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 std::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 std::nullopt;
517 }
518 return AccessToken{token};
519 }
520
DuplicateImpersonation(SecurityImpersonationLevel impersonation_level,ACCESS_MASK desired_access) const521 std::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 std::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 std::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 std::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 std::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 std::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 std::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 std::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 std::optional<bool> AccessToken::SetPrivilege(const std::wstring& name,
595 bool enable) {
596 std::optional<DWORD> attrs =
597 AdjustPrivilege(token_, name.c_str(), enable ? SE_PRIVILEGE_ENABLED : 0);
598 if (!attrs) {
599 return std::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
RemoveAllPrivileges()609 bool AccessToken::RemoveAllPrivileges() {
610 std::optional<std::vector<char>> privileges_buffer =
611 GetTokenInfo(token_.get(), TokenPrivileges);
612 if (!privileges_buffer ||
613 (privileges_buffer->size() < sizeof(TOKEN_PRIVILEGES))) {
614 return false;
615 }
616 auto* const token_privileges = GetType<TOKEN_PRIVILEGES>(privileges_buffer);
617 if (privileges_buffer->size() <
618 (offsetof(TOKEN_PRIVILEGES, Privileges) +
619 sizeof(LUID_AND_ATTRIBUTES) * token_privileges->PrivilegeCount)) {
620 return false;
621 }
622
623 for (auto privileges = base::make_span(&token_privileges->Privileges[0],
624 token_privileges->PrivilegeCount);
625 auto& privilege : privileges) {
626 privilege.Attributes = SE_PRIVILEGE_REMOVED;
627 }
628 return ::AdjustTokenPrivileges(
629 token_.get(), /*DisableAllPrivileges=*/FALSE, token_privileges,
630 static_cast<DWORD>(privileges_buffer->size()),
631 /*PreviousState=*/nullptr, /*ReturnLength=*/nullptr);
632 }
633
is_valid() const634 bool AccessToken::is_valid() const {
635 return token_.is_valid();
636 }
637
get() const638 HANDLE AccessToken::get() const {
639 return token_.get();
640 }
641
release()642 ScopedHandle AccessToken::release() {
643 return ScopedHandle(token_.release());
644 }
645
AccessToken(HANDLE token)646 AccessToken::AccessToken(HANDLE token) : token_(token) {}
647
648 } // namespace base::win
649