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 <string> 10 #include <vector> 11 12 #include "base/base_export.h" 13 #include "base/win/access_control_list.h" 14 #include "base/win/scoped_handle.h" 15 #include "base/win/sid.h" 16 #include "base/win/windows_types.h" 17 #include "third_party/abseil-cpp/absl/types/optional.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 absl::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 absl::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 absl::optional<AccessToken> FromProcess( 103 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 absl::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 absl::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 absl::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 absl::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 absl::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 absl::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 absl::optional<AccessToken> LinkedToken() const; 212 213 // Get the default DACL for the token. Returns an empty value on error. 214 absl::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 absl::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 absl::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 absl::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 absl::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 absl::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 // Indicates if the AccessToken object is valid. 316 bool is_valid() const; 317 318 // Get the underlying token handle. 319 HANDLE get() const; 320 321 // Take ownership of the underlying token handle. Once released no other 322 // methods on this object should be called. 323 ScopedHandle release(); 324 325 private: 326 explicit AccessToken(HANDLE token); 327 ScopedHandle token_; 328 }; 329 330 } // namespace base::win 331 332 #endif // BASE_WIN_ACCESS_TOKEN_H_ 333