1use std::{ffi::c_void, ops::Deref};
37use windows::{
38 Win32::{
39 Foundation::{
40 CloseHandle, E_INVALIDARG, ERROR_INSUFFICIENT_BUFFER, ERROR_NOT_ALL_ASSIGNED,
41 GetLastError, HANDLE, HLOCAL, LUID, LocalFree,
42 },
43 Security::{
44 AdjustTokenGroups, AdjustTokenPrivileges, AllocateAndInitializeSid,
45 Authorization::{ConvertSidToStringSidW, ConvertStringSidToSidW},
46 CREATE_RESTRICTED_TOKEN_FLAGS, CheckTokenMembership, CreateRestrictedToken,
47 CreateWellKnownSid, DuplicateTokenEx, FreeSid, GetLengthSid, GetSidSubAuthority,
48 GetSidSubAuthorityCount, GetTokenInformation, IsValidSid, IsWellKnownSid,
49 LUID_AND_ATTRIBUTES, LookupAccountSidW, LookupPrivilegeNameW, LookupPrivilegeValueW,
50 PSID, SE_PRIVILEGE_ENABLED, SE_PRIVILEGE_REMOVED, SECURITY_IMPERSONATION_LEVEL,
51 SECURITY_NT_AUTHORITY, SID_IDENTIFIER_AUTHORITY, SID_NAME_USE, TOKEN_ACCESS_MASK,
52 TOKEN_APPCONTAINER_INFORMATION, TOKEN_ELEVATION, TOKEN_ELEVATION_TYPE, TOKEN_GROUPS,
53 TOKEN_INFORMATION_CLASS, TOKEN_LINKED_TOKEN, TOKEN_MANDATORY_LABEL, TOKEN_PRIVILEGES,
54 TOKEN_PRIVILEGES_ATTRIBUTES, TOKEN_TYPE, TOKEN_USER, TokenAppContainerNumber,
55 TokenAppContainerSid, TokenCapabilities, TokenDeviceGroups, TokenElevation,
56 TokenElevationType, TokenGroups, TokenHasRestrictions, TokenImpersonationLevel,
57 TokenIntegrityLevel, TokenIsAppContainer, TokenLinkedToken, TokenLogonSid, TokenOwner,
58 TokenPrimary, TokenPrimaryGroup, TokenPrivileges, TokenRestrictedDeviceGroups,
59 TokenRestrictedSids, TokenType, TokenUIAccess, TokenUser, TokenVirtualizationAllowed,
60 TokenVirtualizationEnabled, WELL_KNOWN_SID_TYPE,
61 },
62 System::{
63 SystemServices::SE_GROUP_ENABLED,
64 Threading::{GetCurrentProcess, OpenProcessToken},
65 },
66 },
67 core::{BOOL, Error, HSTRING, PCWSTR, PWSTR, Result},
68};
69
70fn buffer_probe(res: Result<()>) -> Result<()> {
71 match res {
72 Ok(()) => Ok(()),
73 Err(e) if e.code() == ERROR_INSUFFICIENT_BUFFER.to_hresult() => Ok(()),
74 Err(e) => Err(e),
75 }
76}
77
78fn nonempty_slice<T>(slice: &[T]) -> Option<&[T]> {
79 if slice.is_empty() { None } else { Some(slice) }
80}
81
82#[derive(Debug)]
88pub struct OwnedToken {
89 handle: HANDLE,
90}
91
92impl OwnedToken {
93 pub fn from_current_process(access: TOKEN_ACCESS_MASK) -> Result<Self> {
95 unsafe {
96 let mut h = HANDLE::default();
97 OpenProcessToken(GetCurrentProcess(), access, &mut h)?;
98 Ok(Self { handle: h })
99 }
100 }
101
102 pub unsafe fn new(handle: HANDLE) -> Self {
109 Self { handle }
110 }
111
112 pub fn into_raw(self) -> HANDLE {
117 let h = self.handle;
118 std::mem::forget(self);
119 h
120 }
121}
122
123impl Drop for OwnedToken {
124 fn drop(&mut self) {
125 unsafe { CloseHandle(self.handle).ok() };
126 }
127}
128
129impl Deref for OwnedToken {
130 type Target = Token;
131 fn deref(&self) -> &Self::Target {
132 unsafe { Token::new(&self.handle) }
133 }
134}
135
136#[repr(transparent)]
142#[derive(Copy, Clone, Debug)]
143pub struct Token {
144 handle: HANDLE,
145}
146
147impl Token {
148 pub unsafe fn new(handle: &HANDLE) -> &Self {
149 unsafe { &*(handle as *const HANDLE as *const Token) }
150 }
151
152 pub fn handle(&self) -> HANDLE {
154 self.handle
155 }
156
157 pub fn duplicate(
159 &self,
160 access: TOKEN_ACCESS_MASK,
161 token_type: TOKEN_TYPE,
162 imp_level: SECURITY_IMPERSONATION_LEVEL,
163 ) -> Result<OwnedToken> {
164 unsafe {
165 let mut dup = HANDLE::default();
166 DuplicateTokenEx(self.handle, access, None, imp_level, token_type, &mut dup)?;
167 Ok(OwnedToken { handle: dup })
168 }
169 }
170
171 pub fn is_elevated(&self) -> Result<bool> {
173 unsafe {
174 let mut elev: TOKEN_ELEVATION = std::mem::zeroed();
175 let mut ret = 0u32;
176 GetTokenInformation(
177 self.handle,
178 TokenElevation,
179 Some(&mut elev as *mut _ as *mut c_void),
180 std::mem::size_of::<TOKEN_ELEVATION>() as u32,
181 &mut ret,
182 )?;
183 Ok(elev.TokenIsElevated != 0)
184 }
185 }
186
187 pub fn integrity_level(&self) -> Result<Sid> {
189 unsafe {
190 let mut len = 0u32;
191 buffer_probe(GetTokenInformation(
192 self.handle,
193 TokenIntegrityLevel,
194 None,
195 0,
196 &mut len,
197 ))?;
198 let mut buf = vec![0u8; len as usize];
199 GetTokenInformation(
200 self.handle,
201 TokenIntegrityLevel,
202 Some(buf.as_mut_ptr() as *mut c_void),
203 len,
204 &mut len,
205 )?;
206 let label = &*(buf.as_ptr() as *const TOKEN_MANDATORY_LABEL);
207 Sid::from_ptr(label.Label.Sid)
208 }
209 }
210
211 fn groups_of(&self, class: TOKEN_INFORMATION_CLASS) -> Result<Vec<Group>> {
212 unsafe {
213 let mut len = 0u32;
214 buffer_probe(GetTokenInformation(self.handle, class, None, 0, &mut len))?;
215 let mut buf = vec![0u8; len as usize];
216 GetTokenInformation(
217 self.handle,
218 class,
219 Some(buf.as_mut_ptr() as *mut c_void),
220 len,
221 &mut len,
222 )?;
223 let groups = &*(buf.as_ptr() as *const TOKEN_GROUPS);
224 let slice =
225 std::slice::from_raw_parts(groups.Groups.as_ptr(), groups.GroupCount as usize);
226 slice
227 .iter()
228 .map(|ga| {
229 Ok(Group {
230 sid: Sid::from_ptr(ga.Sid)?,
231 attributes: ga.Attributes,
232 })
233 })
234 .collect()
235 }
236 }
237
238 pub fn groups(&self) -> Result<Vec<Group>> {
240 self.groups_of(TokenGroups)
241 }
242
243 pub fn capabilities(&self) -> Result<Vec<Group>> {
245 self.groups_of(TokenCapabilities)
246 }
247
248 pub fn logon_sid(&self) -> Result<Vec<Group>> {
250 self.groups_of(TokenLogonSid)
251 }
252
253 pub fn restricted_sids(&self) -> Result<Vec<Group>> {
255 self.groups_of(TokenRestrictedSids)
256 }
257
258 pub fn device_groups(&self) -> Result<Vec<Group>> {
260 self.groups_of(TokenDeviceGroups)
261 }
262
263 pub fn restricted_device_groups(&self) -> Result<Vec<Group>> {
265 self.groups_of(TokenRestrictedDeviceGroups)
266 }
267
268 pub fn linked_token(&self) -> Result<OwnedToken> {
270 unsafe {
271 let mut linked: TOKEN_LINKED_TOKEN = std::mem::zeroed();
272 let mut ret = 0u32;
273 GetTokenInformation(
274 self.handle,
275 TokenLinkedToken,
276 Some(&mut linked as *mut _ as *mut c_void),
277 std::mem::size_of::<TOKEN_LINKED_TOKEN>() as u32,
278 &mut ret,
279 )?;
280 Ok(OwnedToken {
281 handle: linked.LinkedToken,
282 })
283 }
284 }
285
286 pub fn elevation_type(&self) -> Result<TOKEN_ELEVATION_TYPE> {
288 unsafe {
289 let mut et: TOKEN_ELEVATION_TYPE = std::mem::zeroed();
290 let mut ret = 0u32;
291 GetTokenInformation(
292 self.handle,
293 TokenElevationType,
294 Some(&mut et as *mut _ as *mut c_void),
295 std::mem::size_of::<TOKEN_ELEVATION_TYPE>() as u32,
296 &mut ret,
297 )?;
298 Ok(et)
299 }
300 }
301
302 pub fn impersonation_level(&self) -> Result<SECURITY_IMPERSONATION_LEVEL> {
304 unsafe {
305 let mut lvl: SECURITY_IMPERSONATION_LEVEL = std::mem::zeroed();
306 let mut ret = 0u32;
307 GetTokenInformation(
308 self.handle,
309 TokenImpersonationLevel,
310 Some(&mut lvl as *mut _ as *mut c_void),
311 std::mem::size_of::<SECURITY_IMPERSONATION_LEVEL>() as u32,
312 &mut ret,
313 )?;
314 Ok(lvl)
315 }
316 }
317
318 #[inline]
320 fn info_buffer(&self, class: TOKEN_INFORMATION_CLASS) -> Result<Vec<u8>> {
321 unsafe {
322 let mut len = 0u32;
323 buffer_probe(GetTokenInformation(self.handle, class, None, 0, &mut len))?;
324 let mut buf = vec![0u8; len as usize];
325 GetTokenInformation(
326 self.handle,
327 class,
328 Some(buf.as_mut_ptr() as *mut c_void),
329 len,
330 &mut len,
331 )?;
332 Ok(buf)
333 }
334 }
335
336 #[inline]
338 fn dword_info(&self, class: TOKEN_INFORMATION_CLASS) -> Result<u32> {
339 unsafe {
340 let mut val: u32 = 0;
341 let mut ret = 0u32;
342 GetTokenInformation(
343 self.handle,
344 class,
345 Some(&mut val as *mut _ as *mut c_void),
346 std::mem::size_of::<u32>() as u32,
347 &mut ret,
348 )?;
349 Ok(val)
350 }
351 }
352
353 fn bool_info(&self, class: TOKEN_INFORMATION_CLASS) -> Result<bool> {
355 Ok(self.dword_info(class)? != 0)
356 }
357
358 pub fn has_restrictions(&self) -> Result<bool> {
360 self.bool_info(TokenHasRestrictions)
361 }
362
363 pub fn virtualization_allowed(&self) -> Result<bool> {
365 self.bool_info(TokenVirtualizationAllowed)
366 }
367
368 pub fn virtualization_enabled(&self) -> Result<bool> {
370 self.bool_info(TokenVirtualizationEnabled)
371 }
372
373 pub fn is_app_container(&self) -> Result<bool> {
375 self.bool_info(TokenIsAppContainer)
376 }
377
378 pub fn is_primary(&self) -> Result<bool> {
380 unsafe {
381 let mut ty: TOKEN_TYPE = std::mem::zeroed();
382 let mut ret = 0u32;
383 GetTokenInformation(
384 self.handle,
385 TokenType,
386 Some(&mut ty as *mut _ as *mut c_void),
387 std::mem::size_of::<TOKEN_TYPE>() as u32,
388 &mut ret,
389 )?;
390 Ok(ty == TokenPrimary)
391 }
392 }
393
394 pub fn user(&self) -> Result<Sid> {
396 let buf = self.info_buffer(TokenUser)?;
397 let tu = unsafe { &*(buf.as_ptr() as *const TOKEN_USER) };
398 unsafe { Sid::from_ptr(tu.User.Sid) }
399 }
400
401 pub fn primary_group(&self) -> Result<Sid> {
403 let buf = self.info_buffer(TokenPrimaryGroup)?;
404 let tpg =
405 unsafe { &*(buf.as_ptr() as *const windows::Win32::Security::TOKEN_PRIMARY_GROUP) };
406 unsafe { Sid::from_ptr(tpg.PrimaryGroup) }
407 }
408
409 pub fn owner(&self) -> Result<Sid> {
411 let buf = self.info_buffer(TokenOwner)?;
412 let to = unsafe { &*(buf.as_ptr() as *const windows::Win32::Security::TOKEN_OWNER) };
413 unsafe { Sid::from_ptr(to.Owner) }
414 }
415
416 pub fn privileges(&self) -> Result<Vec<Privilege>> {
418 unsafe {
419 let mut len = 0u32;
420 buffer_probe(GetTokenInformation(
421 self.handle,
422 TokenPrivileges,
423 None,
424 0,
425 &mut len,
426 ))?;
427
428 let mut buf = vec![0u8; len as usize];
429 GetTokenInformation(
430 self.handle,
431 TokenPrivileges,
432 Some(buf.as_mut_ptr() as *mut c_void),
433 len,
434 &mut len,
435 )?;
436
437 let tprivs = &*(buf.as_ptr() as *const TOKEN_PRIVILEGES);
438 let slice = std::slice::from_raw_parts(
439 tprivs.Privileges.as_ptr(),
440 tprivs.PrivilegeCount as usize,
441 );
442
443 Ok(slice.iter().map(|la| Privilege::from_raw(la)).collect())
444 }
445 }
446
447 pub fn adjust_privileges(&self, privs: &[Privilege]) -> Result<()> {
452 if privs.is_empty() {
453 return Ok(());
454 }
455
456 unsafe {
457 let count = privs.len();
459 let buf_len = std::mem::size_of::<TOKEN_PRIVILEGES>()
460 + (count - 1) * std::mem::size_of::<LUID_AND_ATTRIBUTES>();
461 let mut buf = vec![0u8; buf_len];
462
463 *(buf.as_mut_ptr() as *mut u32) = count as u32;
465
466 let la_ptr =
468 buf.as_mut_ptr().add(std::mem::size_of::<u32>()) as *mut LUID_AND_ATTRIBUTES;
469
470 for (i, p) in privs.iter().enumerate() {
471 *la_ptr.add(i) = LUID_AND_ATTRIBUTES {
472 Luid: p.inner.Luid,
473 Attributes: if p.is_enabled() {
474 SE_PRIVILEGE_ENABLED
475 } else {
476 SE_PRIVILEGE_REMOVED
477 },
478 };
479 }
480
481 let tp_ptr = buf.as_ptr() as *const TOKEN_PRIVILEGES;
482
483 AdjustTokenPrivileges(self.handle, false, Some(&*tp_ptr), 0, None, None)?;
484 if GetLastError() == ERROR_NOT_ALL_ASSIGNED {
485 return Err(Error::from_win32());
486 }
487 }
488 Ok(())
489 }
490
491 pub fn check_membership(&self, sid: &Sid) -> Result<bool> {
493 unsafe {
494 let mut is_member = BOOL(0);
495 CheckTokenMembership(
497 Some(self.handle),
498 PSID(sid.buf.as_ptr() as *mut c_void),
499 &mut is_member,
500 )?;
501 Ok(is_member.as_bool())
502 }
503 }
504
505 pub fn ui_access(&self) -> Result<bool> {
507 self.bool_info(TokenUIAccess)
508 }
509
510 pub fn app_container_sid(&self) -> Result<Option<Sid>> {
512 let buf = self.info_buffer(TokenAppContainerSid)?;
513 let info = unsafe { &*(buf.as_ptr() as *const TOKEN_APPCONTAINER_INFORMATION) };
514 if info.TokenAppContainer.0.is_null() {
515 return Ok(None);
516 }
517 let sid = unsafe { Sid::from_ptr(info.TokenAppContainer)? };
518 Ok(Some(sid))
519 }
520
521 pub fn app_container_number(&self) -> Result<u32> {
523 self.dword_info(TokenAppContainerNumber)
524 }
525
526 pub fn adjust_groups(&self, groups: &[Group]) -> Result<()> {
532 if groups.is_empty() {
533 return Ok(());
534 }
535
536 unsafe {
537 let sid_attrs = Self::sid_attr_vec(groups);
538 let count = sid_attrs.len();
539
540 let buf_len = std::mem::size_of::<TOKEN_GROUPS>()
542 + (count - 1) * std::mem::size_of::<windows::Win32::Security::SID_AND_ATTRIBUTES>();
543
544 let usize_slots =
545 (buf_len + std::mem::size_of::<usize>() - 1) / std::mem::size_of::<usize>();
546 let mut buf: Vec<usize> = vec![0; usize_slots];
547
548 let tg_ptr = buf.as_mut_ptr() as *mut TOKEN_GROUPS;
549
550 (*tg_ptr).GroupCount = count as u32;
551
552 let sa_ptr = (*tg_ptr).Groups.as_mut_ptr();
553 std::ptr::copy_nonoverlapping(sid_attrs.as_ptr(), sa_ptr, count);
554
555 AdjustTokenGroups(self.handle, false, Some(&*tg_ptr), 0, None, None)?;
556
557 if GetLastError() == ERROR_NOT_ALL_ASSIGNED {
558 return Err(Error::from_win32());
559 }
560 }
561
562 Ok(())
563 }
564
565 fn sid_attr_vec(groups: &[Group]) -> Vec<windows::Win32::Security::SID_AND_ATTRIBUTES> {
569 groups
570 .iter()
571 .map(|g| windows::Win32::Security::SID_AND_ATTRIBUTES {
572 Sid: PSID(g.sid.buf.as_ptr() as *mut _),
573 Attributes: g.attributes(),
574 })
575 .collect()
576 }
577
578 pub fn create_restricted_token(
583 &self,
584 flags: CREATE_RESTRICTED_TOKEN_FLAGS,
585 sids_to_disable: &[Group],
586 privileges_to_delete: &[Privilege],
587 sids_to_restrict: &[Group],
588 ) -> Result<OwnedToken> {
589 unsafe {
590 let disable_vec = Self::sid_attr_vec(sids_to_disable);
592 let restrict_vec = Self::sid_attr_vec(sids_to_restrict);
593 let priv_vec: Vec<LUID_AND_ATTRIBUTES> =
595 privileges_to_delete.iter().map(|p| p.inner).collect();
596 let mut new_tok = HANDLE::default();
597
598 CreateRestrictedToken(
599 self.handle,
600 flags,
601 nonempty_slice(&disable_vec),
602 nonempty_slice(&priv_vec),
603 nonempty_slice(&restrict_vec),
604 &mut new_tok,
605 )?;
606
607 Ok(OwnedToken { handle: new_tok })
608 }
609 }
610}
611
612impl<'a> From<&'a OwnedToken> for Token {
613 fn from(tok: &'a OwnedToken) -> Self {
614 Token { handle: tok.handle }
615 }
616}
617
618#[derive(Clone, Debug, PartialEq, Eq, Hash)]
624pub struct Sid {
625 buf: Vec<u8>,
626}
627
628impl Sid {
629 pub fn parse(s: &str) -> Result<Self> {
631 unsafe {
632 let mut psid = PSID::default();
633 let hstring = HSTRING::from(s);
634 ConvertStringSidToSidW(PCWSTR(hstring.as_ptr()), &mut psid)?;
635 let len = GetLengthSid(psid);
636 let slice = std::slice::from_raw_parts(psid.0 as *const u8, len as usize);
637 let v = slice.to_vec();
638 LocalFree(Some(HLOCAL(psid.0 as *mut c_void)));
639 Ok(Self { buf: v })
640 }
641 }
642
643 pub fn to_string(&self) -> Result<String> {
645 unsafe {
646 let mut pwstr = PWSTR::null();
647 ConvertSidToStringSidW(PSID(self.buf.as_ptr() as *mut c_void), &mut pwstr)?;
648 let s = pwstr.to_string();
649 LocalFree(Some(HLOCAL(pwstr.0 as *mut c_void)));
650 Ok(s?)
651 }
652 }
653
654 pub fn account(&self) -> Result<(String, String)> {
656 unsafe {
657 let mut name_len = 0u32;
658 let mut dom_len = 0u32;
659 let mut use_ty = SID_NAME_USE(0);
660 buffer_probe(LookupAccountSidW(
661 PCWSTR::null(),
662 PSID(self.buf.as_ptr() as *mut _),
663 None,
664 &mut name_len,
665 None,
666 &mut dom_len,
667 &mut use_ty,
668 ))?;
669 let mut name = vec![0u16; name_len as usize];
670 let mut dom = vec![0u16; dom_len as usize];
671 LookupAccountSidW(
672 PCWSTR::null(),
673 PSID(self.buf.as_ptr() as *mut _),
674 Some(PWSTR(name.as_mut_ptr())),
675 &mut name_len,
676 Some(PWSTR(dom.as_mut_ptr())),
677 &mut dom_len,
678 &mut use_ty,
679 )?;
680 Ok((
681 String::from_utf16(&name[..name_len as usize])?,
682 String::from_utf16(&dom[..dom_len as usize])?,
683 ))
684 }
685 }
686
687 pub fn well_known(kind: WELL_KNOWN_SID_TYPE) -> Result<Self> {
689 unsafe {
690 let mut size = 0u32;
691 buffer_probe(CreateWellKnownSid(kind, None, None, &mut size))?;
692 let mut buf = vec![0u8; size as usize];
693 CreateWellKnownSid(
694 kind,
695 None,
696 Some(PSID(buf.as_mut_ptr() as *mut _)),
697 &mut size,
698 )?;
699 Ok(Self { buf })
700 }
701 }
702
703 pub(crate) unsafe fn from_ptr(psid: PSID) -> Result<Self> {
705 unsafe {
706 let len = GetLengthSid(psid);
707 if len == 0 {
708 return Err(Error::from_win32());
709 }
710 let slice = std::slice::from_raw_parts(psid.0 as *const u8, len as usize);
711 Ok(Self {
712 buf: slice.to_vec(),
713 })
714 }
715 }
716
717 pub fn rid(&self) -> Result<u32> {
719 unsafe {
720 let cnt_ptr = GetSidSubAuthorityCount(PSID(self.buf.as_ptr() as *mut c_void));
721 if cnt_ptr.is_null() {
722 return Err(Error::from_win32());
723 }
724 let rid_ptr = GetSidSubAuthority(
725 PSID(self.buf.as_ptr() as *mut c_void),
726 (*cnt_ptr as u32) - 1,
727 );
728 if rid_ptr.is_null() {
729 return Err(Error::from_win32());
730 }
731 Ok(*rid_ptr)
732 }
733 }
734
735 pub fn is_valid(&self) -> bool {
737 unsafe { IsValidSid(PSID(self.buf.as_ptr() as *mut _)).as_bool() }
738 }
739
740 pub fn is_well_known(&self, kind: WELL_KNOWN_SID_TYPE) -> bool {
742 unsafe { IsWellKnownSid(PSID(self.buf.as_ptr() as *mut _), kind).as_bool() }
743 }
744
745 pub fn from_parts(authority: &SID_IDENTIFIER_AUTHORITY, subids: &[u32]) -> Result<Self> {
749 if subids.len() > 8 {
750 return Err(Error::new(E_INVALIDARG, "too many RIDs"));
751 }
752
753 unsafe {
754 let mut psid = PSID::default();
755 let mut subs = [0u32; 8];
757 for (i, &rid) in subids.iter().enumerate() {
758 subs[i] = rid;
759 }
760
761 AllocateAndInitializeSid(
762 authority,
763 subids.len() as u8,
764 subs[0],
765 subs[1],
766 subs[2],
767 subs[3],
768 subs[4],
769 subs[5],
770 subs[6],
771 subs[7],
772 &mut psid,
773 )?;
774
775 let len = GetLengthSid(psid);
777 let slice = std::slice::from_raw_parts(psid.0 as *const u8, len as usize);
778 let buf = slice.to_vec();
779 FreeSid(psid);
780
781 Ok(Self { buf })
782 }
783 }
784
785 pub fn from_nt_authority(subids: &[u32]) -> Result<Self> {
788 Self::from_parts(&SECURITY_NT_AUTHORITY, subids)
789 }
790}
791
792impl std::fmt::Display for Sid {
793 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
794 match self.to_string() {
795 Ok(s) => write!(f, "{s}"),
796 Err(_) => write!(f, "<invalid sid>"),
797 }
798 }
799}
800
801#[derive(Clone, Debug, PartialEq, Eq)]
807pub struct Group {
808 sid: Sid,
809 attributes: u32,
810}
811
812impl Group {
813 pub fn sid(&self) -> &Sid {
815 &self.sid
816 }
817
818 pub fn attributes(&self) -> u32 {
820 self.attributes
821 }
822
823 pub fn account(&self) -> Result<(String, String)> {
825 self.sid.account()
826 }
827
828 pub fn new(sid: Sid, attributes: u32) -> Self {
833 Self { sid, attributes }
834 }
835
836 pub fn enabled(sid: Sid) -> Self {
839 Self::new(sid, SE_GROUP_ENABLED as u32)
840 }
841
842 pub fn disabled(sid: Sid) -> Self {
845 Self::new(sid, 0)
846 }
847}
848
849impl std::fmt::Display for Group {
850 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
851 write!(f, "{}", self.sid)
853 }
854}
855
856#[derive(Clone, Debug)]
862pub struct Privilege {
863 inner: LUID_AND_ATTRIBUTES,
864}
865
866impl Privilege {
867 pub(crate) fn from_raw(inner: &LUID_AND_ATTRIBUTES) -> Self {
869 Self { inner: *inner }
870 }
871
872 pub fn name(&self) -> Result<String> {
874 unsafe {
875 let mut len = 0u32;
876 buffer_probe(LookupPrivilegeNameW(
877 PCWSTR::null(),
878 &self.inner.Luid,
879 None,
880 &mut len,
881 ))?;
882 let mut buf = vec![0u16; len as usize];
883 LookupPrivilegeNameW(
884 PCWSTR::null(),
885 &self.inner.Luid,
886 Some(PWSTR(buf.as_mut_ptr())),
887 &mut len,
888 )?;
889 Ok(String::from_utf16(&buf[..len as usize])?)
890 }
891 }
892
893 pub fn attributes(&self) -> TOKEN_PRIVILEGES_ATTRIBUTES {
895 self.inner.Attributes
896 }
897
898 pub fn is_enabled(&self) -> bool {
900 self.inner.Attributes.contains(SE_PRIVILEGE_ENABLED)
901 }
902
903 pub fn new(name: &str, enable: bool) -> Result<Self> {
906 unsafe {
907 let mut luid = LUID::default();
909 let hstring = HSTRING::from(name);
910 LookupPrivilegeValueW(PCWSTR::null(), PCWSTR(hstring.as_ptr()), &mut luid)?;
911
912 Ok(Self {
913 inner: LUID_AND_ATTRIBUTES {
914 Luid: luid,
915 Attributes: if enable {
916 SE_PRIVILEGE_ENABLED
917 } else {
918 SE_PRIVILEGE_REMOVED
919 },
920 },
921 })
922 }
923 }
924
925 pub fn enabled(name: &str) -> Result<Self> {
928 Self::new(name, true)
929 }
930
931 pub fn disabled(name: &str) -> Result<Self> {
934 Self::new(name, false)
935 }
936}
937
938impl std::fmt::Display for Privilege {
939 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
940 let name = self.name().unwrap_or_else(|_| {
941 let luid = self.inner.Luid;
942 format!("LUID({:?},{:?})", luid.HighPart, luid.LowPart)
943 });
944 let state = if self.is_enabled() {
945 "enabled"
946 } else {
947 "disabled"
948 };
949 write!(f, "{name} ({state})")
950 }
951}