// Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_WIN_ACCESS_TOKEN_H_ #define BASE_WIN_ACCESS_TOKEN_H_ #include #include #include #include #include "base/base_export.h" #include "base/win/access_control_list.h" #include "base/win/scoped_handle.h" #include "base/win/sid.h" #include "base/win/windows_types.h" namespace base::win { // Impersonation level for the token. enum class SecurityImpersonationLevel { kAnonymous, kIdentification, kImpersonation, kDelegation }; // This class is used to access the information for a Windows access token. class BASE_EXPORT AccessToken { public: // This class represents an access token group. class BASE_EXPORT Group { public: // Get the group SID. const Sid& GetSid() const { return sid_; } // Get the group attribute flags. DWORD GetAttributes() const { return attributes_; } // Returns true if the group is an integrity level. bool IsIntegrity() const; // Returns true if the group is enabled. bool IsEnabled() const; // Returns true if the group is deny only. bool IsDenyOnly() const; // Returns true if the group is the logon ID. bool IsLogonId() const; Group(Sid&& sid, DWORD attributes); Group(Group&&); ~Group(); private: Sid sid_; DWORD attributes_; }; // This class represents an access token privilege. class BASE_EXPORT Privilege { public: // Get the privilege LUID. CHROME_LUID GetLuid() const { return luid_; } // Get the privilege attribute flags. DWORD GetAttributes() const { return attributes_; } // Get the name of the privilege. std::wstring GetName() const; // Returns true if the privilege is enabled. bool IsEnabled() const; Privilege(CHROME_LUID luid, DWORD attributes); private: CHROME_LUID luid_; DWORD attributes_; }; // Creates an AccessToken object from a token handle. // |token| the token handle. This handle will be duplicated for TOKEN_QUERY // access, therefore the caller must be granted that access to the token // object. The AccessToken object owns its own copy of the token handle so // the original can be closed. // |desired_access| specifies additional access for the token handle, // TOKEN_QUERY will always be requested. static std::optional FromToken(HANDLE token, ACCESS_MASK desired_access = 0); // Creates an AccessToken object from an existing token handle. // |token| the token handle. The AccessToken object will take ownership of // this handle without duplicating it. It must have been opened with at least // TOKEN_QUERY access to succeed. static std::optional FromToken(ScopedHandle&& token); // Creates an AccessToken object from a process handle. // |process| the process handle. The handle needs to have // PROCESS_QUERY_LIMITED_INFORMATION access to the handle and TOKEN_QUERY // access to the token object. // |impersonation| if true then the process token will be duplicated to an // impersonation token. This allows you to call the IsMember API which // requires an impersonation token. To duplicate TOKEN_DUPLICATE access is // required. // |desired_access| specifies additional access for the token handle, // TOKEN_QUERY will always be requested. static std::optional FromProcess(HANDLE process, bool impersonation = false, ACCESS_MASK desired_access = 0); // Creates an AccessToken object for the current process. // |impersonation| if true then the process token will be duplicated to an // impersonation token. This allows you to call the IsMember API which // requires an impersonation token. To duplicate TOKEN_DUPLICATE access is // required. // |desired_access| specifies additional access for the token handle, // TOKEN_QUERY will always be requested. static std::optional FromCurrentProcess( bool impersonation = false, ACCESS_MASK desired_access = 0); // Creates an AccessToken object from a thread handle. The thread must be // impersonating a token for this to succeed. // |thread| the thread handle. The handle needs to have // THREAD_QUERY_LIMITED_INFORMATION access and TOKEN_QUERY access to the // token object. // |open_as_self| open the token using the process token rather than the // current thread's impersonated token. // If the thread isn't impersonating it will return an empty value and the // Win32 last error code will be ERROR_NO_TOKEN. // |desired_access| specifies additional access for the token handle, // TOKEN_QUERY will always be requested. static std::optional FromThread(HANDLE thread, bool open_as_self = true, ACCESS_MASK desired_access = 0); // Creates an AccessToken object from the current thread. The thread must be // impersonating a token for this to succeed. // |open_as_self| open the thread handle using the process token rather // than the current thread's impersonated token. // If the thread isn't impersonating it will return an empty value and the // Win32 last error code will be ERROR_NO_TOKEN. // |desired_access| specifies additional access for the token handle, // TOKEN_QUERY will always be requested. static std::optional FromCurrentThread( bool open_as_self = true, ACCESS_MASK desired_access = 0); // Creates an AccessToken object for the current thread's effective token. // If the thread is impersonating then it'll try and open the thread token, // otherwise it'll open the process token. // |desired_access| specifies additional access for the token handle, // TOKEN_QUERY will always be requested. static std::optional FromEffective( ACCESS_MASK desired_access = 0); AccessToken(const AccessToken&) = delete; AccessToken& operator=(const AccessToken&) = delete; AccessToken(AccessToken&&); AccessToken& operator=(AccessToken&&); ~AccessToken(); // Get the token's user SID. Sid User() const; // Get the token's user group. Group UserGroup() const; // Get the token's owner SID. This can be different to the user SID, it's // used as the default owner for new secured objects. Sid Owner() const; // Get the token's primary group SID. Sid PrimaryGroup() const; // Get the token logon SID. Returns an empty value if the token doesn't have // a logon SID. If the logon SID doesn't exist then the Win32 last error code // will be ERROR_NOT_FOUND. std::optional LogonId() const; // Get the token's integrity level. Returns MAXDWORD if the token doesn't // have an integrity level. DWORD IntegrityLevel() const; // Set the token's integrity level. Token needs to have been opened with // TOKEN_ADJUST_DEFAULT access. bool SetIntegrityLevel(DWORD integrity_level); // Get the token's session ID. Returns MAXDWORD if the token if the session // ID can't be queried. DWORD SessionId() const; // The token's group list. std::vector Groups() const; // Get whether the token is a restricted. bool IsRestricted() const; // The token's restricted SIDs list. If not a restricted token this will // return an empty vector. std::vector RestrictedSids() const; // Get whether the token is an appcontainer. bool IsAppContainer() const; // Get the token's appcontainer SID. If not an appcontainer token this will // return an empty value. std::optional AppContainerSid() const; // The token's capabilities. If not an appcontainer token this will return an // empty vector. std::vector Capabilities() const; // Get the UAC linked token. std::optional LinkedToken() const; // Get the default DACL for the token. Returns an empty value on error. std::optional DefaultDacl() const; // Set the default DACL of the token. Token needs to have been opened with // TOKEN_ADJUST_DEFAULT access. bool SetDefaultDacl(const AccessControlList& default_dacl); // Get the token's ID. CHROME_LUID Id() const; // Get the token's authentication ID. CHROME_LUID AuthenticationId() const; // Get the token's privileges. std::vector Privileges() const; // Get whether the token is elevated. bool IsElevated() const; // Checks if the sid is a member of the token's groups. The token must be // an impersonation token rather than a primary token. If the token is not an // impersonation token then it returns false and the Win32 last error will be // set to ERROR_NO_IMPERSONATION_TOKEN. bool IsMember(const Sid& sid) const; // Checks if the well known sid is a member of the token's groups. The token // must be an impersonation token rather than a primary token. If the token // is not an impersonation token then it returns false and the Win32 last // error will be set to ERROR_NO_IMPERSONATION_TOKEN. bool IsMember(WellKnownSid known_sid) const; // Checks if the token is an impersonation token. If false then it's a primary // token. bool IsImpersonation() const; // Checks if the token can only be used for identification. This is based on // the security impersonation level of the token. If the level is less than // or equal to SecurityIdentification this function returns true. Always // returns false for a primary token. bool IsIdentification() const; // Get the current impersonation level. If the token is a primary token // the function returns kImpersonation. SecurityImpersonationLevel ImpersonationLevel() const; // Duplicate the token to a new primary token. // |desired_access| specifies additional access for the token handle. // TOKEN_QUERY will always be requested. // The original token must have TOKEN_DUPLICATE access to successfully // duplicate the token. std::optional DuplicatePrimary( ACCESS_MASK desired_access = 0) const; // Duplicate the token to a new impersonation token. // |impersonation_level| specifies the impersonation level for the token. // |desired_access| specifies additional access for the token handle. // TOKEN_QUERY will always be requested. // The original token must have TOKEN_DUPLICATE access to successfully // duplicate the token. std::optional DuplicateImpersonation( SecurityImpersonationLevel impersonation_level = SecurityImpersonationLevel::kImpersonation, ACCESS_MASK desired_access = 0) const; // Create a new restricted token from this token. // |flags| can be set to a combination of DISABLE_MAX_PRIVILEGE, // SANDBOX_INERT, LUA_TOKEN and WRITE_RESTRICTED. // |sids_to_disable| is the list of SIDs to disable in the token. // |privileges_to_delete| is the names of the privileges to delete. // |sids_to_restrict| is the list of SIDs to add as restricted SIDs. // |desired_access| specifies additional access for the token handle. // The token needs to be opened with TOKEN_DUPLICATE access. std::optional CreateRestricted( DWORD flags, const std::vector& sids_to_disable, const std::vector& privileges_to_delete, const std::vector& sids_to_restrict, ACCESS_MASK desired_access = 0) const; // Create a new AppContainer primary token from this token. // |app_container_sid| the AppContainer package SID. // |capabilities| the list of AppContainer capabilities. // |desired_access| specifies additional access for the token handle. // The token needs to be opened with TOKEN_DUPLICATE access. std::optional CreateAppContainer( const Sid& appcontainer_sid, const std::vector& capabilities, ACCESS_MASK desired_access = 0) const; // Enable or disable a privilege. // |name| the name of the privilege to change. // |enable| specify whether to enable or disable the privilege. // Returns the previous enable state of the privilege, or nullopt if failed. // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. std::optional SetPrivilege(const std::wstring& name, bool enable); // Remove a privilege permanently from the token. // |name| the name of the privilege to remove. // Returns true if successfully removed the privilege. // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. bool RemovePrivilege(const std::wstring& name); // Permanently remove all privileges from the token. // Returns true if the operation was successful. // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. bool RemoveAllPrivileges(); // Indicates if the AccessToken object is valid. bool is_valid() const; // Get the underlying token handle. HANDLE get() const; // Take ownership of the underlying token handle. Once released no other // methods on this object should be called. ScopedHandle release(); private: explicit AccessToken(HANDLE token); ScopedHandle token_; }; } // namespace base::win #endif // BASE_WIN_ACCESS_TOKEN_H_