• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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