dolang_winterop/security/
win32_security.rs1use std::io;
11
12#[cfg(windows)]
13use std::{
14 os::windows::io::{AsRawHandle, FromRawHandle, OwnedHandle},
15 ptr,
16};
17
18#[cfg(windows)]
19use windows_sys::Win32::{
20 Foundation::{ERROR_NOT_ALL_ASSIGNED, GetLastError, SetLastError},
21 Security::{
22 AdjustTokenPrivileges, DuplicateTokenEx, LUID_AND_ATTRIBUTES, LookupPrivilegeValueW,
23 RevertToSelf, SE_PRIVILEGE_ENABLED, SE_SECURITY_NAME, SecurityImpersonation,
24 TOKEN_ADJUST_PRIVILEGES, TOKEN_DUPLICATE, TOKEN_IMPERSONATE, TOKEN_PRIVILEGES, TOKEN_QUERY,
25 TokenImpersonation,
26 },
27 System::Threading::{GetCurrentProcess, OpenProcessToken, SetThreadToken},
28};
29
30#[cfg_attr(docsrs, doc(cfg(windows)))]
38pub fn with_security_privilege<T, E: From<io::Error>>(
39 f: impl FnOnce() -> Result<T, E>,
40) -> Result<T, E> {
41 #[cfg(windows)]
42 {
43 struct RevertGuard;
44 impl Drop for RevertGuard {
45 fn drop(&mut self) {
46 unsafe {
47 RevertToSelf();
48 }
49 }
50 }
51
52 let mut process_token = ptr::null_mut();
53 if unsafe {
54 OpenProcessToken(
55 GetCurrentProcess(),
56 TOKEN_DUPLICATE | TOKEN_QUERY,
57 &mut process_token,
58 )
59 } == 0
60 {
61 return Err(io::Error::last_os_error().into());
62 }
63 let process_token = unsafe { OwnedHandle::from_raw_handle(process_token) };
64
65 let mut token = ptr::null_mut();
66 if unsafe {
67 DuplicateTokenEx(
68 process_token.as_raw_handle(),
69 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE,
70 ptr::null(),
71 SecurityImpersonation,
72 TokenImpersonation,
73 &mut token,
74 )
75 } == 0
76 {
77 return Err(io::Error::last_os_error().into());
78 }
79 let token = unsafe { OwnedHandle::from_raw_handle(token) };
80
81 let mut luid = Default::default();
82 if unsafe { LookupPrivilegeValueW(ptr::null(), SE_SECURITY_NAME, &mut luid) } == 0 {
83 return Err(io::Error::last_os_error().into());
84 }
85 let privileges = TOKEN_PRIVILEGES {
86 PrivilegeCount: 1,
87 Privileges: [LUID_AND_ATTRIBUTES {
88 Luid: luid,
89 Attributes: SE_PRIVILEGE_ENABLED,
90 }],
91 };
92 unsafe { SetLastError(0) };
93 if unsafe {
94 AdjustTokenPrivileges(
95 token.as_raw_handle(),
96 0,
97 &privileges,
98 0,
99 ptr::null_mut(),
100 ptr::null_mut(),
101 )
102 } == 0
103 {
104 return Err(io::Error::last_os_error().into());
105 }
106 if unsafe { GetLastError() } == ERROR_NOT_ALL_ASSIGNED {
107 return Err(io::Error::new(
108 io::ErrorKind::PermissionDenied,
109 "SeSecurityPrivilege is not available",
110 )
111 .into());
112 }
113 if unsafe { SetThreadToken(ptr::null(), token.as_raw_handle()) } == 0 {
114 return Err(io::Error::last_os_error().into());
115 }
116 let _guard = RevertGuard;
117 f()
118 }
119 #[cfg(all(docsrs, not(windows)))]
120 {
121 let _ = f;
122 unreachable!()
123 }
124}