1use std::{mem, ptr};
4
5use windows::{
6 Win32::{
7 Foundation::{
8 CloseHandle, ERROR_SUCCESS, GetLastError, HANDLE, LUID, SetLastError, WIN32_ERROR,
9 },
10 Security::{
11 AdjustTokenPrivileges, DuplicateTokenEx, GetTokenInformation, ImpersonateLoggedOnUser,
12 LUID_AND_ATTRIBUTES, LookupPrivilegeValueW, RevertToSelf, SE_PRIVILEGE_ENABLED,
13 SecurityImpersonation, SetTokenInformation, TOKEN_ACCESS_MASK, TOKEN_ADJUST_PRIVILEGES,
14 TOKEN_ALL_ACCESS, TOKEN_GROUPS, TOKEN_INFORMATION_CLASS, TOKEN_PRIVILEGES, TOKEN_QUERY,
15 TOKEN_USER, TokenGroups, TokenImpersonation, TokenPrimary, TokenSessionId, TokenUser,
16 },
17 System::{
18 SystemServices::MAXIMUM_ALLOWED,
19 Threading::{
20 GetCurrentProcess, OpenProcess, OpenProcessToken, PROCESS_QUERY_INFORMATION,
21 },
22 },
23 },
24 core::PCWSTR,
25};
26
27use super::{HandleGuard, Sid, privilege::Privilege, win32};
28use crate::error::ElevateError;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum TokenType {
33 Primary,
35 Impersonation,
37}
38
39pub struct Token(HANDLE);
41
42impl Drop for Token {
43 fn drop(&mut self) {
44 if !self.0.is_invalid() {
45 unsafe {
46 let _ = CloseHandle(self.0);
47 }
48 }
49 }
50}
51
52impl Token {
53 pub fn current() -> Result<Self, ElevateError> {
55 let mut handle = HANDLE::default();
56 win32!(OpenProcessToken(
57 GetCurrentProcess(),
58 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
59 &raw mut handle
60 ))?;
61 Ok(Self(handle))
62 }
63
64 pub fn from_pid(pid: u32) -> Result<Self, ElevateError> {
66 let proc = HandleGuard(win32!(OpenProcess(PROCESS_QUERY_INFORMATION, false, pid))?);
67 let mut token = HANDLE::default();
68 win32!(OpenProcessToken(
69 proc.0,
70 TOKEN_ACCESS_MASK(MAXIMUM_ALLOWED),
71 &raw mut token
72 ))?;
73 Ok(Self(token))
74 }
75
76 pub const fn as_raw(&self) -> HANDLE {
78 self.0
79 }
80
81 pub fn duplicate(&self, token_type: TokenType) -> Result<Self, ElevateError> {
83 let access = match token_type {
84 TokenType::Primary => TOKEN_ALL_ACCESS,
85 TokenType::Impersonation => TOKEN_ACCESS_MASK(MAXIMUM_ALLOWED),
86 };
87 let raw_type = match token_type {
88 TokenType::Primary => TokenPrimary,
89 TokenType::Impersonation => TokenImpersonation,
90 };
91
92 let mut dup = HANDLE::default();
93 win32!(DuplicateTokenEx(
94 self.0,
95 access,
96 None,
97 SecurityImpersonation,
98 raw_type,
99 &raw mut dup
100 ))?;
101 Ok(Self(dup))
102 }
103
104 pub fn enable_privileges(&self, privileges: &[Privilege]) -> Result<(), ElevateError> {
106 for &privilege in privileges {
107 let mut luid = LUID::default();
108 win32!(LookupPrivilegeValueW(
109 PCWSTR::null(),
110 privilege.as_pcwstr(),
111 &raw mut luid
112 ))?;
113
114 let privs = TOKEN_PRIVILEGES {
115 PrivilegeCount: 1,
116 Privileges: [LUID_AND_ATTRIBUTES {
117 Luid: luid,
118 Attributes: SE_PRIVILEGE_ENABLED,
119 }],
120 };
121
122 unsafe { SetLastError(WIN32_ERROR(0)) };
123 win32!(AdjustTokenPrivileges(
124 self.0,
125 false,
126 Some(ptr::from_ref(&privs)),
127 mem::size_of::<TOKEN_PRIVILEGES>() as u32,
128 None,
129 None,
130 ))?;
131
132 if unsafe { GetLastError() } != ERROR_SUCCESS {
133 return Err(ElevateError::PrivilegeNotAssigned(privilege.as_str()));
134 }
135 }
136 Ok(())
137 }
138
139 pub fn session_id(&self) -> Result<u32, ElevateError> {
141 let mut session_id = 0u32;
142 let mut len = 0u32;
143 win32!(GetTokenInformation(
144 self.0,
145 TokenSessionId,
146 Some(ptr::from_mut(&mut session_id).cast()),
147 mem::size_of::<u32>() as u32,
148 &raw mut len
149 ))?;
150 Ok(session_id)
151 }
152
153 pub fn set_session_id(&self, session_id: u32) -> Result<(), ElevateError> {
155 win32!(SetTokenInformation(
156 self.0,
157 TokenSessionId,
158 ptr::from_ref(&session_id).cast(),
159 mem::size_of::<u32>() as u32
160 ))?;
161 Ok(())
162 }
163
164 pub fn impersonate(&self) -> Result<ImpersonationGuard, ElevateError> {
166 win32!(ImpersonateLoggedOnUser(self.0))?;
167 Ok(ImpersonationGuard)
168 }
169
170 pub fn user_sid(&self) -> Result<String, ElevateError> {
172 let buf = self.query_info_buffer(TokenUser)?;
173 let user = unsafe { &*buf.as_ptr().cast::<TOKEN_USER>() };
175 Sid::string_from_raw(user.User.Sid)
176 }
177
178 pub fn has_sid(&self, target_sid: PCWSTR) -> Result<bool, ElevateError> {
180 let target = Sid::parse(target_sid)?;
181 let buf = self.query_info_buffer(TokenGroups)?;
182 let groups = unsafe { &*buf.as_ptr().cast::<TOKEN_GROUPS>() };
184
185 let slice = unsafe {
186 std::slice::from_raw_parts(groups.Groups.as_ptr(), groups.GroupCount as usize)
187 };
188 Ok(slice.iter().any(|g| Sid::equal(g.Sid, target.as_raw())))
189 }
190
191 fn query_info_buffer(
193 &self,
194 class: TOKEN_INFORMATION_CLASS,
195 ) -> Result<Vec<usize>, ElevateError> {
196 let mut len = 0u32;
197 let _ = unsafe { GetTokenInformation(self.0, class, None, 0, &raw mut len) };
198 if len == 0 {
199 return Err(ElevateError::InvalidTokenBuffer);
200 }
201
202 let usize_size = mem::size_of::<usize>();
203 let count = ((len as usize).saturating_add(usize_size - 1)) / usize_size;
204 let mut buf: Vec<usize> = vec![0; count];
205
206 win32!(GetTokenInformation(
207 self.0,
208 class,
209 Some(buf.as_mut_ptr().cast()),
210 len,
211 &raw mut len
212 ))?;
213 Ok(buf)
214 }
215}
216
217pub struct ImpersonationGuard;
219
220impl Drop for ImpersonationGuard {
221 fn drop(&mut self) {
222 unsafe {
223 let _ = RevertToSelf();
224 }
225 }
226}