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 #ifndef BASE_WIN_ACCESS_TOKEN_H_ 6 #define BASE_WIN_ACCESS_TOKEN_H_ 7 8 #include <memory> 9 #include <optional> 10 #include <string> 11 #include <vector> 12 13 #include "base/base_export.h" 14 #include "base/win/access_control_list.h" 15 #include "base/win/scoped_handle.h" 16 #include "base/win/sid.h" 17 #include "base/win/windows_types.h" 18 19 namespace base::win { 20 21 // Impersonation level for the token. 22 enum class SecurityImpersonationLevel { 23 kAnonymous, 24 kIdentification, 25 kImpersonation, 26 kDelegation 27 }; 28 29 // This class is used to access the information for a Windows access token. 30 class BASE_EXPORT AccessToken { 31 public: 32 // This class represents an access token group. 33 class BASE_EXPORT Group { 34 public: 35 // Get the group SID. GetSid()36 const Sid& GetSid() const { return sid_; } 37 // Get the group attribute flags. GetAttributes()38 DWORD GetAttributes() const { return attributes_; } 39 // Returns true if the group is an integrity level. 40 bool IsIntegrity() const; 41 // Returns true if the group is enabled. 42 bool IsEnabled() const; 43 // Returns true if the group is deny only. 44 bool IsDenyOnly() const; 45 // Returns true if the group is the logon ID. 46 bool IsLogonId() const; 47 48 Group(Sid&& sid, DWORD attributes); 49 Group(Group&&); 50 ~Group(); 51 52 private: 53 Sid sid_; 54 DWORD attributes_; 55 }; 56 57 // This class represents an access token privilege. 58 class BASE_EXPORT Privilege { 59 public: 60 // Get the privilege LUID. GetLuid()61 CHROME_LUID GetLuid() const { return luid_; } 62 // Get the privilege attribute flags. GetAttributes()63 DWORD GetAttributes() const { return attributes_; } 64 // Get the name of the privilege. 65 std::wstring GetName() const; 66 // Returns true if the privilege is enabled. 67 bool IsEnabled() const; 68 69 Privilege(CHROME_LUID luid, DWORD attributes); 70 71 private: 72 CHROME_LUID luid_; 73 DWORD attributes_; 74 }; 75 76 // Creates an AccessToken object from a token handle. 77 // |token| the token handle. This handle will be duplicated for TOKEN_QUERY 78 // access, therefore the caller must be granted that access to the token 79 // object. The AccessToken object owns its own copy of the token handle so 80 // the original can be closed. 81 // |desired_access| specifies additional access for the token handle, 82 // TOKEN_QUERY will always be requested. 83 static std::optional<AccessToken> FromToken(HANDLE token, 84 ACCESS_MASK desired_access = 0); 85 86 // Creates an AccessToken object from an existing token handle. 87 // |token| the token handle. The AccessToken object will take ownership of 88 // this handle without duplicating it. It must have been opened with at least 89 // TOKEN_QUERY access to succeed. 90 static std::optional<AccessToken> FromToken(ScopedHandle&& token); 91 92 // Creates an AccessToken object from a process handle. 93 // |process| the process handle. The handle needs to have 94 // PROCESS_QUERY_LIMITED_INFORMATION access to the handle and TOKEN_QUERY 95 // access to the token object. 96 // |impersonation| if true then the process token will be duplicated to an 97 // impersonation token. This allows you to call the IsMember API which 98 // requires an impersonation token. To duplicate TOKEN_DUPLICATE access is 99 // required. 100 // |desired_access| specifies additional access for the token handle, 101 // TOKEN_QUERY will always be requested. 102 static std::optional<AccessToken> FromProcess(HANDLE process, 103 bool impersonation = false, 104 ACCESS_MASK desired_access = 0); 105 106 // Creates an AccessToken object for the current process. 107 // |impersonation| if true then the process token will be duplicated to an 108 // impersonation token. This allows you to call the IsMember API which 109 // requires an impersonation token. To duplicate TOKEN_DUPLICATE access is 110 // required. 111 // |desired_access| specifies additional access for the token handle, 112 // TOKEN_QUERY will always be requested. 113 static std::optional<AccessToken> FromCurrentProcess( 114 bool impersonation = false, 115 ACCESS_MASK desired_access = 0); 116 117 // Creates an AccessToken object from a thread handle. The thread must be 118 // impersonating a token for this to succeed. 119 // |thread| the thread handle. The handle needs to have 120 // THREAD_QUERY_LIMITED_INFORMATION access and TOKEN_QUERY access to the 121 // token object. 122 // |open_as_self| open the token using the process token rather than the 123 // current thread's impersonated token. 124 // If the thread isn't impersonating it will return an empty value and the 125 // Win32 last error code will be ERROR_NO_TOKEN. 126 // |desired_access| specifies additional access for the token handle, 127 // TOKEN_QUERY will always be requested. 128 static std::optional<AccessToken> FromThread(HANDLE thread, 129 bool open_as_self = true, 130 ACCESS_MASK desired_access = 0); 131 132 // Creates an AccessToken object from the current thread. The thread must be 133 // impersonating a token for this to succeed. 134 // |open_as_self| open the thread handle using the process token rather 135 // than the current thread's impersonated token. 136 // If the thread isn't impersonating it will return an empty value and the 137 // Win32 last error code will be ERROR_NO_TOKEN. 138 // |desired_access| specifies additional access for the token handle, 139 // TOKEN_QUERY will always be requested. 140 static std::optional<AccessToken> FromCurrentThread( 141 bool open_as_self = true, 142 ACCESS_MASK desired_access = 0); 143 144 // Creates an AccessToken object for the current thread's effective token. 145 // If the thread is impersonating then it'll try and open the thread token, 146 // otherwise it'll open the process token. 147 // |desired_access| specifies additional access for the token handle, 148 // TOKEN_QUERY will always be requested. 149 static std::optional<AccessToken> FromEffective( 150 ACCESS_MASK desired_access = 0); 151 152 AccessToken(const AccessToken&) = delete; 153 AccessToken& operator=(const AccessToken&) = delete; 154 AccessToken(AccessToken&&); 155 AccessToken& operator=(AccessToken&&); 156 ~AccessToken(); 157 158 // Get the token's user SID. 159 Sid User() const; 160 161 // Get the token's user group. 162 Group UserGroup() const; 163 164 // Get the token's owner SID. This can be different to the user SID, it's 165 // used as the default owner for new secured objects. 166 Sid Owner() const; 167 168 // Get the token's primary group SID. 169 Sid PrimaryGroup() const; 170 171 // Get the token logon SID. Returns an empty value if the token doesn't have 172 // a logon SID. If the logon SID doesn't exist then the Win32 last error code 173 // will be ERROR_NOT_FOUND. 174 std::optional<Sid> LogonId() const; 175 176 // Get the token's integrity level. Returns MAXDWORD if the token doesn't 177 // have an integrity level. 178 DWORD IntegrityLevel() const; 179 180 // Set the token's integrity level. Token needs to have been opened with 181 // TOKEN_ADJUST_DEFAULT access. 182 bool SetIntegrityLevel(DWORD integrity_level); 183 184 // Get the token's session ID. Returns MAXDWORD if the token if the session 185 // ID can't be queried. 186 DWORD SessionId() const; 187 188 // The token's group list. 189 std::vector<Group> Groups() const; 190 191 // Get whether the token is a restricted. 192 bool IsRestricted() const; 193 194 // The token's restricted SIDs list. If not a restricted token this will 195 // return an empty vector. 196 std::vector<Group> RestrictedSids() const; 197 198 // Get whether the token is an appcontainer. 199 bool IsAppContainer() const; 200 201 // Get the token's appcontainer SID. If not an appcontainer token this will 202 // return an empty value. 203 std::optional<Sid> AppContainerSid() const; 204 205 // The token's capabilities. If not an appcontainer token this will return an 206 // empty vector. 207 std::vector<Group> Capabilities() const; 208 209 // Get the UAC linked token. 210 std::optional<AccessToken> LinkedToken() const; 211 212 // Get the default DACL for the token. Returns an empty value on error. 213 std::optional<AccessControlList> DefaultDacl() const; 214 215 // Set the default DACL of the token. Token needs to have been opened with 216 // TOKEN_ADJUST_DEFAULT access. 217 bool SetDefaultDacl(const AccessControlList& default_dacl); 218 219 // Get the token's ID. 220 CHROME_LUID Id() const; 221 222 // Get the token's authentication ID. 223 CHROME_LUID AuthenticationId() const; 224 225 // Get the token's privileges. 226 std::vector<Privilege> Privileges() const; 227 228 // Get whether the token is elevated. 229 bool IsElevated() const; 230 231 // Checks if the sid is a member of the token's groups. The token must be 232 // an impersonation token rather than a primary token. If the token is not an 233 // impersonation token then it returns false and the Win32 last error will be 234 // set to ERROR_NO_IMPERSONATION_TOKEN. 235 bool IsMember(const Sid& sid) const; 236 237 // Checks if the well known sid is a member of the token's groups. The token 238 // must be an impersonation token rather than a primary token. If the token 239 // is not an impersonation token then it returns false and the Win32 last 240 // error will be set to ERROR_NO_IMPERSONATION_TOKEN. 241 bool IsMember(WellKnownSid known_sid) const; 242 243 // Checks if the token is an impersonation token. If false then it's a primary 244 // token. 245 bool IsImpersonation() const; 246 247 // Checks if the token can only be used for identification. This is based on 248 // the security impersonation level of the token. If the level is less than 249 // or equal to SecurityIdentification this function returns true. Always 250 // returns false for a primary token. 251 bool IsIdentification() const; 252 253 // Get the current impersonation level. If the token is a primary token 254 // the function returns kImpersonation. 255 SecurityImpersonationLevel ImpersonationLevel() const; 256 257 // Duplicate the token to a new primary token. 258 // |desired_access| specifies additional access for the token handle. 259 // TOKEN_QUERY will always be requested. 260 // The original token must have TOKEN_DUPLICATE access to successfully 261 // duplicate the token. 262 std::optional<AccessToken> DuplicatePrimary( 263 ACCESS_MASK desired_access = 0) const; 264 265 // Duplicate the token to a new impersonation token. 266 // |impersonation_level| specifies the impersonation level for the token. 267 // |desired_access| specifies additional access for the token handle. 268 // TOKEN_QUERY will always be requested. 269 // The original token must have TOKEN_DUPLICATE access to successfully 270 // duplicate the token. 271 std::optional<AccessToken> DuplicateImpersonation( 272 SecurityImpersonationLevel impersonation_level = 273 SecurityImpersonationLevel::kImpersonation, 274 ACCESS_MASK desired_access = 0) const; 275 276 // Create a new restricted token from this token. 277 // |flags| can be set to a combination of DISABLE_MAX_PRIVILEGE, 278 // SANDBOX_INERT, LUA_TOKEN and WRITE_RESTRICTED. 279 // |sids_to_disable| is the list of SIDs to disable in the token. 280 // |privileges_to_delete| is the names of the privileges to delete. 281 // |sids_to_restrict| is the list of SIDs to add as restricted SIDs. 282 // |desired_access| specifies additional access for the token handle. 283 // The token needs to be opened with TOKEN_DUPLICATE access. 284 std::optional<AccessToken> CreateRestricted( 285 DWORD flags, 286 const std::vector<Sid>& sids_to_disable, 287 const std::vector<std::wstring>& privileges_to_delete, 288 const std::vector<Sid>& sids_to_restrict, 289 ACCESS_MASK desired_access = 0) const; 290 291 // Create a new AppContainer primary token from this token. 292 // |app_container_sid| the AppContainer package SID. 293 // |capabilities| the list of AppContainer capabilities. 294 // |desired_access| specifies additional access for the token handle. 295 // The token needs to be opened with TOKEN_DUPLICATE access. 296 std::optional<AccessToken> CreateAppContainer( 297 const Sid& appcontainer_sid, 298 const std::vector<Sid>& capabilities, 299 ACCESS_MASK desired_access = 0) const; 300 301 // Enable or disable a privilege. 302 // |name| the name of the privilege to change. 303 // |enable| specify whether to enable or disable the privilege. 304 // Returns the previous enable state of the privilege, or nullopt if failed. 305 // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. 306 std::optional<bool> SetPrivilege(const std::wstring& name, bool enable); 307 308 // Remove a privilege permanently from the token. 309 // |name| the name of the privilege to remove. 310 // Returns true if successfully removed the privilege. 311 // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. 312 bool RemovePrivilege(const std::wstring& name); 313 314 // Permanently remove all privileges from the token. 315 // Returns true if the operation was successful. 316 // The token must be opened with TOKEN_ADJUST_PRIVILEGES access. 317 bool RemoveAllPrivileges(); 318 319 // Indicates if the AccessToken object is valid. 320 bool is_valid() const; 321 322 // Get the underlying token handle. 323 HANDLE get() const; 324 325 // Take ownership of the underlying token handle. Once released no other 326 // methods on this object should be called. 327 ScopedHandle release(); 328 329 private: 330 explicit AccessToken(HANDLE token); 331 ScopedHandle token_; 332 }; 333 334 } // namespace base::win 335 336 #endif // BASE_WIN_ACCESS_TOKEN_H_ 337