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