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