Skip to main content

vmi_os_windows/comps/object/
token.rs

1use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead};
2
3use super::{
4    super::{WindowsLuid, WindowsSid, WindowsSidAndAttributes},
5    FromWindowsObject, WindowsObject, WindowsObjectTypeKind,
6};
7use crate::{ArchAdapter, WindowsOs, offset};
8
9/// A Windows access token.
10///
11/// An access token records a security principal's identity and the
12/// privileges the kernel grants to it. Every process holds a primary
13/// token. Threads may carry an [impersonation token] that overrides the
14/// process token for the duration of an impersonation.
15///
16/// # Implementation Details
17///
18/// Corresponds to `_TOKEN`.
19///
20/// [impersonation token]: crate::WindowsThread::impersonation_token
21pub struct WindowsToken<'a, Driver>
22where
23    Driver: VmiRead,
24    Driver::Architecture: ArchAdapter<Driver>,
25{
26    /// The VMI state.
27    vmi: VmiState<'a, WindowsOs<Driver>>,
28
29    /// Address of the `_TOKEN` structure.
30    va: Va,
31}
32
33impl<'a, Driver> From<WindowsToken<'a, Driver>> for WindowsObject<'a, Driver>
34where
35    Driver: VmiRead,
36    Driver::Architecture: ArchAdapter<Driver>,
37{
38    fn from(value: WindowsToken<'a, Driver>) -> Self {
39        Self::new(value.vmi, value.va)
40    }
41}
42
43impl<'a, Driver> FromWindowsObject<'a, Driver> for WindowsToken<'a, Driver>
44where
45    Driver: VmiRead,
46    Driver::Architecture: ArchAdapter<Driver>,
47{
48    fn from_object(object: WindowsObject<'a, Driver>) -> Result<Option<Self>, VmiError> {
49        match object.type_kind()? {
50            Some(WindowsObjectTypeKind::Token) => Ok(Some(Self::new(object.vmi, object.va))),
51            _ => Ok(None),
52        }
53    }
54}
55
56impl<Driver> VmiVa for WindowsToken<'_, Driver>
57where
58    Driver: VmiRead,
59    Driver::Architecture: ArchAdapter<Driver>,
60{
61    fn va(&self) -> Va {
62        self.va
63    }
64}
65
66bitflags::bitflags! {
67    /// Flags stored in `_TOKEN.TokenFlags`.
68    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
69    pub struct WindowsTokenFlags: u32 {
70        /// Corresponds to `TOKEN_HAS_TRAVERSE_PRIVILEGE`.
71        const HAS_TRAVERSE_PRIVILEGE         = 0x0000_0001;
72
73        /// Corresponds to `TOKEN_HAS_BACKUP_PRIVILEGE`.
74        const HAS_BACKUP_PRIVILEGE           = 0x0000_0002;
75
76        /// Corresponds to `TOKEN_HAS_RESTORE_PRIVILEGE`.
77        const HAS_RESTORE_PRIVILEGE          = 0x0000_0004;
78
79        /// Corresponds to `TOKEN_WRITE_RESTRICTED`.
80        const WRITE_RESTRICTED               = 0x0000_0008;
81
82        /// Corresponds to `TOKEN_IS_RESTRICTED`.
83        const IS_RESTRICTED                  = 0x0000_0010;
84
85        /// Corresponds to `TOKEN_SESSION_NOT_REFERENCED`.
86        const SESSION_NOT_REFERENCED         = 0x0000_0020;
87
88        /// Corresponds to `TOKEN_SANDBOX_INERT`.
89        const SANDBOX_INERT                  = 0x0000_0040;
90
91        /// Corresponds to `TOKEN_HAS_IMPERSONATE_PRIVILEGE`.
92        const HAS_IMPERSONATE_PRIVILEGE      = 0x0000_0080;
93
94        /// Corresponds to `SE_BACKUP_PRIVILEGES_CHECKED`.
95        const SE_BACKUP_PRIVILEGES_CHECKED   = 0x0000_0100;
96
97        /// Corresponds to `TOKEN_VIRTUALIZE_ALLOWED`.
98        const VIRTUALIZE_ALLOWED             = 0x0000_0200;
99
100        /// Corresponds to `TOKEN_VIRTUALIZE_ENABLED`.
101        const VIRTUALIZE_ENABLED             = 0x0000_0400;
102
103        /// Corresponds to `TOKEN_IS_FILTERED`.
104        const IS_FILTERED                    = 0x0000_0800;
105
106        /// Corresponds to `TOKEN_UIACCESS`.
107        const UIACCESS                       = 0x0000_1000;
108
109        /// Corresponds to `TOKEN_NOT_LOW`.
110        const NOT_LOW                        = 0x0000_2000;
111
112        /// Corresponds to `TOKEN_LOWBOX`.
113        const LOWBOX                         = 0x0000_4000;
114
115        /// Corresponds to `TOKEN_HAS_OWN_CLAIM_ATTRIBUTES`.
116        const HAS_OWN_CLAIM_ATTRIBUTES       = 0x0000_8000;
117
118        /// Corresponds to `TOKEN_PRIVATE_NAMESPACE`.
119        const PRIVATE_NAMESPACE              = 0x0001_0000;
120
121        /// Corresponds to `TOKEN_DO_NOT_USE_GLOBAL_ATTRIBS_FOR_QUERY`.
122        const DO_NOT_USE_GLOBAL_ATTRIBS_FOR_QUERY = 0x0002_0000;
123
124        /// Corresponds to `SPECIAL_ENCRYPTED_OPEN`.
125        const SPECIAL_ENCRYPTED_OPEN         = 0x0004_0000;
126
127        /// Corresponds to `TOKEN_NO_CHILD_PROCESS`.
128        const NO_CHILD_PROCESS               = 0x0008_0000;
129
130        /// Corresponds to `TOKEN_NO_CHILD_PROCESS_UNLESS_SECURE`.
131        const NO_CHILD_PROCESS_UNLESS_SECURE = 0x0010_0000;
132
133        /// Corresponds to `TOKEN_AUDIT_NO_CHILD_PROCESS`.
134        const AUDIT_NO_CHILD_PROCESS         = 0x0020_0000;
135
136        /// Corresponds to `TOKEN_ENFORCE_REDIRECTION_TRUST`.
137        const ENFORCE_REDIRECTION_TRUST      = 0x0040_0000;
138
139        /// Corresponds to `TOKEN_AUDIT_REDIRECTION_TRUST`.
140        const AUDIT_REDIRECTION_TRUST        = 0x0080_0000;
141
142        /// Corresponds to `TOKEN_LEARNING_MODE_LOGGING`.
143        const LEARNING_MODE_LOGGING          = 0x0100_0000;
144
145        /// Corresponds to `TOKEN_PERMISSIVE_LEARNING_MODE`.
146        ///
147        /// Implies `LEARNING_MODE_LOGGING`.
148        const PERMISSIVE_LEARNING_MODE       = 0x0300_0000;
149
150        /// Corresponds to `TOKEN_SYSTEM_MANAGED_ADMIN_FULL_TOKEN`.
151        const SYSTEM_MANAGED_ADMIN_FULL_TOKEN = 0x0800_0000;
152    }
153}
154
155/// Distinguishes a primary token from an impersonation token.
156///
157/// # Implementation Details
158///
159/// Corresponds to `_TOKEN_TYPE`.
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub enum WindowsTokenType {
162    /// `TokenPrimary`.
163    Primary,
164
165    /// `TokenImpersonation`.
166    Impersonation,
167
168    /// Token type not recognized.
169    Unknown(u32),
170}
171
172impl From<u32> for WindowsTokenType {
173    /// Decodes a raw `_TOKEN_TYPE` value.
174    fn from(value: u32) -> Self {
175        match value {
176            1 => Self::Primary,
177            2 => Self::Impersonation,
178            _ => Self::Unknown(value),
179        }
180    }
181}
182
183/// Impersonation level of a token.
184///
185/// # Implementation Details
186///
187/// Corresponds to `_SECURITY_IMPERSONATION_LEVEL`.
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub enum WindowsImpersonationLevel {
190    /// `SecurityAnonymous`.
191    Anonymous,
192
193    /// `SecurityIdentification`.
194    Identification,
195
196    /// `SecurityImpersonation`.
197    Impersonation,
198
199    /// `SecurityDelegation`.
200    Delegation,
201
202    /// Impersonation level not recognized.
203    Unknown(u32),
204}
205
206impl From<u32> for WindowsImpersonationLevel {
207    fn from(value: u32) -> Self {
208        match value {
209            0 => Self::Anonymous,
210            1 => Self::Identification,
211            2 => Self::Impersonation,
212            3 => Self::Delegation,
213            _ => Self::Unknown(value),
214        }
215    }
216}
217
218/// Identifies the subsystem that minted a token.
219///
220/// # Implementation Details
221///
222/// Corresponds to `_TOKEN_SOURCE`.
223pub struct WindowsTokenSource<'a, Driver>
224where
225    Driver: VmiRead,
226    Driver::Architecture: ArchAdapter<Driver>,
227{
228    /// The VMI state.
229    vmi: VmiState<'a, WindowsOs<Driver>>,
230
231    /// Address of the `_TOKEN_SOURCE` structure.
232    va: Va,
233}
234
235impl<Driver> VmiVa for WindowsTokenSource<'_, Driver>
236where
237    Driver: VmiRead,
238    Driver::Architecture: ArchAdapter<Driver>,
239{
240    fn va(&self) -> Va {
241        self.va
242    }
243}
244
245impl<'a, Driver> WindowsTokenSource<'a, Driver>
246where
247    Driver: VmiRead,
248    Driver::Architecture: ArchAdapter<Driver>,
249{
250    /// Creates a new Windows token source accessor.
251    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
252        Self { vmi, va }
253    }
254
255    /// Returns the raw 8-byte source name as stored in the kernel.
256    ///
257    /// # Implementation Details
258    ///
259    /// Corresponds to `_TOKEN_SOURCE.SourceName`.
260    pub fn name_bytes(&self) -> Result<[u8; 8], VmiError> {
261        let TOKEN_SOURCE = offset!(self.vmi, _TOKEN_SOURCE);
262        debug_assert_eq!(TOKEN_SOURCE.SourceName.size(), 8);
263
264        let mut bytes = [0; 8];
265        self.vmi
266            .read(self.va + TOKEN_SOURCE.SourceName.offset(), &mut bytes)?;
267
268        Ok(bytes)
269    }
270
271    /// Returns the source name.
272    ///
273    /// # Implementation Details
274    ///
275    /// Corresponds to `_TOKEN_SOURCE.SourceName`.
276    pub fn name(&self) -> Result<String, VmiError> {
277        let bytes = self.name_bytes()?;
278
279        let end = bytes
280            .iter()
281            .position(|byte| *byte == 0)
282            .unwrap_or(bytes.len());
283
284        Ok(String::from_utf8_lossy(&bytes[..end])
285            .trim_end()
286            .to_string())
287    }
288
289    /// Returns the source identifier LUID.
290    ///
291    /// # Implementation Details
292    ///
293    /// Corresponds to `_TOKEN_SOURCE.SourceIdentifier`.
294    pub fn identifier(&self) -> Result<WindowsLuid, VmiError> {
295        let TOKEN_SOURCE = offset!(self.vmi, _TOKEN_SOURCE);
296
297        let raw = self
298            .vmi
299            .read_u64(self.va + TOKEN_SOURCE.SourceIdentifier.offset())?;
300
301        Ok(WindowsLuid::from(raw))
302    }
303}
304
305/// A Windows access token privilege.
306///
307/// Wraps a privilege LUID's `LowPart`. `HighPart` is always zero for
308/// privilege LUIDs.
309#[derive(Copy, Clone, Eq, PartialEq, Hash)]
310pub struct WindowsPrivilege(u32);
311
312impl WindowsPrivilege {
313    /// Corresponds to `SE_CREATE_TOKEN_PRIVILEGE`.
314    pub const CREATE_TOKEN: Self = Self(2);
315
316    /// Corresponds to `SE_ASSIGNPRIMARYTOKEN_PRIVILEGE`.
317    pub const ASSIGNPRIMARYTOKEN: Self = Self(3);
318
319    /// Corresponds to `SE_LOCK_MEMORY_PRIVILEGE`.
320    pub const LOCK_MEMORY: Self = Self(4);
321
322    /// Corresponds to `SE_INCREASE_QUOTA_PRIVILEGE`.
323    pub const INCREASE_QUOTA: Self = Self(5);
324
325    /// Corresponds to `SE_MACHINE_ACCOUNT_PRIVILEGE`.
326    pub const MACHINE_ACCOUNT: Self = Self(6);
327
328    /// Corresponds to `SE_TCB_PRIVILEGE`.
329    pub const TCB: Self = Self(7);
330
331    /// Corresponds to `SE_SECURITY_PRIVILEGE`.
332    pub const SECURITY: Self = Self(8);
333
334    /// Corresponds to `SE_TAKE_OWNERSHIP_PRIVILEGE`.
335    pub const TAKE_OWNERSHIP: Self = Self(9);
336
337    /// Corresponds to `SE_LOAD_DRIVER_PRIVILEGE`.
338    pub const LOAD_DRIVER: Self = Self(10);
339
340    /// Corresponds to `SE_SYSTEM_PROFILE_PRIVILEGE`.
341    pub const SYSTEM_PROFILE: Self = Self(11);
342
343    /// Corresponds to `SE_SYSTEMTIME_PRIVILEGE`.
344    pub const SYSTEMTIME: Self = Self(12);
345
346    /// Corresponds to `SE_PROF_SINGLE_PROCESS_PRIVILEGE`.
347    pub const PROF_SINGLE_PROCESS: Self = Self(13);
348
349    /// Corresponds to `SE_INC_BASE_PRIORITY_PRIVILEGE`.
350    pub const INC_BASE_PRIORITY: Self = Self(14);
351
352    /// Corresponds to `SE_CREATE_PAGEFILE_PRIVILEGE`.
353    pub const CREATE_PAGEFILE: Self = Self(15);
354
355    /// Corresponds to `SE_CREATE_PERMANENT_PRIVILEGE`.
356    pub const CREATE_PERMANENT: Self = Self(16);
357
358    /// Corresponds to `SE_BACKUP_PRIVILEGE`.
359    pub const BACKUP: Self = Self(17);
360
361    /// Corresponds to `SE_RESTORE_PRIVILEGE`.
362    pub const RESTORE: Self = Self(18);
363
364    /// Corresponds to `SE_SHUTDOWN_PRIVILEGE`.
365    pub const SHUTDOWN: Self = Self(19);
366
367    /// Corresponds to `SE_DEBUG_PRIVILEGE`.
368    pub const DEBUG: Self = Self(20);
369
370    /// Corresponds to `SE_AUDIT_PRIVILEGE`.
371    pub const AUDIT: Self = Self(21);
372
373    /// Corresponds to `SE_SYSTEM_ENVIRONMENT_PRIVILEGE`.
374    pub const SYSTEM_ENVIRONMENT: Self = Self(22);
375
376    /// Corresponds to `SE_CHANGE_NOTIFY_PRIVILEGE`.
377    pub const CHANGE_NOTIFY: Self = Self(23);
378
379    /// Corresponds to `SE_REMOTE_SHUTDOWN_PRIVILEGE`.
380    pub const REMOTE_SHUTDOWN: Self = Self(24);
381
382    /// Corresponds to `SE_UNDOCK_PRIVILEGE`.
383    pub const UNDOCK: Self = Self(25);
384
385    /// Corresponds to `SE_SYNC_AGENT_PRIVILEGE`.
386    pub const SYNC_AGENT: Self = Self(26);
387
388    /// Corresponds to `SE_ENABLE_DELEGATION_PRIVILEGE`.
389    pub const ENABLE_DELEGATION: Self = Self(27);
390
391    /// Corresponds to `SE_MANAGE_VOLUME_PRIVILEGE`.
392    pub const MANAGE_VOLUME: Self = Self(28);
393
394    /// Corresponds to `SE_IMPERSONATE_PRIVILEGE`.
395    pub const IMPERSONATE: Self = Self(29);
396
397    /// Corresponds to `SE_CREATE_GLOBAL_PRIVILEGE`.
398    pub const CREATE_GLOBAL: Self = Self(30);
399
400    /// Corresponds to `SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE`.
401    pub const TRUSTED_CREDMAN_ACCESS: Self = Self(31);
402
403    /// Corresponds to `SE_RELABEL_PRIVILEGE`.
404    pub const RELABEL: Self = Self(32);
405
406    /// Corresponds to `SE_INC_WORKING_SET_PRIVILEGE`.
407    pub const INC_WORKING_SET: Self = Self(33);
408
409    /// Corresponds to `SE_TIME_ZONE_PRIVILEGE`.
410    pub const TIME_ZONE: Self = Self(34);
411
412    /// Corresponds to `SE_CREATE_SYMBOLIC_LINK_PRIVILEGE`.
413    pub const CREATE_SYMBOLIC_LINK: Self = Self(35);
414
415    /// Corresponds to `SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE`.
416    pub const DELEGATE_SESSION_USER_IMPERSONATE: Self = Self(36);
417
418    /// Creates a new token privilege from a LUID LowPart.
419    pub const fn new(low_part: u32) -> Self {
420        Self(low_part)
421    }
422
423    /// Returns the LUID `LowPart` that identifies this privilege.
424    pub const fn low_part(self) -> u32 {
425        self.0
426    }
427
428    /// Returns the `_SEP_TOKEN_PRIVILEGES` bit mask for this privilege.
429    pub const fn mask(self) -> u64 {
430        1 << self.0
431    }
432
433    /// Returns the canonical name.
434    pub const fn name(self) -> Option<&'static str> {
435        match self.0 {
436            2 => Some("SeCreateTokenPrivilege"),
437            3 => Some("SeAssignPrimaryTokenPrivilege"),
438            4 => Some("SeLockMemoryPrivilege"),
439            5 => Some("SeIncreaseQuotaPrivilege"),
440            6 => Some("SeMachineAccountPrivilege"),
441            7 => Some("SeTcbPrivilege"),
442            8 => Some("SeSecurityPrivilege"),
443            9 => Some("SeTakeOwnershipPrivilege"),
444            10 => Some("SeLoadDriverPrivilege"),
445            11 => Some("SeSystemProfilePrivilege"),
446            12 => Some("SeSystemtimePrivilege"),
447            13 => Some("SeProfileSingleProcessPrivilege"),
448            14 => Some("SeIncreaseBasePriorityPrivilege"),
449            15 => Some("SeCreatePagefilePrivilege"),
450            16 => Some("SeCreatePermanentPrivilege"),
451            17 => Some("SeBackupPrivilege"),
452            18 => Some("SeRestorePrivilege"),
453            19 => Some("SeShutdownPrivilege"),
454            20 => Some("SeDebugPrivilege"),
455            21 => Some("SeAuditPrivilege"),
456            22 => Some("SeSystemEnvironmentPrivilege"),
457            23 => Some("SeChangeNotifyPrivilege"),
458            24 => Some("SeRemoteShutdownPrivilege"),
459            25 => Some("SeUndockPrivilege"),
460            26 => Some("SeSyncAgentPrivilege"),
461            27 => Some("SeEnableDelegationPrivilege"),
462            28 => Some("SeManageVolumePrivilege"),
463            29 => Some("SeImpersonatePrivilege"),
464            30 => Some("SeCreateGlobalPrivilege"),
465            31 => Some("SeTrustedCredManAccessPrivilege"),
466            32 => Some("SeRelabelPrivilege"),
467            33 => Some("SeIncreaseWorkingSetPrivilege"),
468            34 => Some("SeTimeZonePrivilege"),
469            35 => Some("SeCreateSymbolicLinkPrivilege"),
470            36 => Some("SeDelegateSessionUserImpersonatePrivilege"),
471            _ => None,
472        }
473    }
474}
475
476impl std::fmt::Debug for WindowsPrivilege {
477    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
478        match self.name() {
479            Some(name) => write!(f, "{name}"),
480            None => write!(f, "UnknownPrivilege({})", self.low_part()),
481        }
482    }
483}
484
485/// A privilege entry in a Windows token.
486#[derive(Debug, Copy, Clone)]
487pub struct WindowsTokenPrivilege {
488    /// The privilege identity.
489    pub privilege: WindowsPrivilege,
490
491    /// Whether the privilege is currently enabled.
492    pub enabled: bool,
493
494    /// Whether the privilege is enabled by default for new sessions.
495    pub enabled_by_default: bool,
496}
497
498impl<'a, Driver> WindowsToken<'a, Driver>
499where
500    Driver: VmiRead,
501    Driver::Architecture: ArchAdapter<Driver>,
502{
503    /// Creates a new Windows token object.
504    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, va: Va) -> Self {
505        Self { vmi, va }
506    }
507
508    /// Returns the Terminal Services session ID.
509    ///
510    /// # Implementation Details
511    ///
512    /// Corresponds to `_TOKEN.SessionId`.
513    pub fn session_id(&self) -> Result<u32, VmiError> {
514        let TOKEN = offset!(self.vmi, _TOKEN);
515
516        self.vmi.read_u32(self.va + TOKEN.SessionId.offset())
517    }
518
519    /// Returns an accessor for the token source.
520    ///
521    /// # Implementation Details
522    ///
523    /// Corresponds to `_TOKEN.TokenSource`.
524    pub fn token_source(&self) -> WindowsTokenSource<'a, Driver> {
525        let TOKEN = offset!(self.vmi, _TOKEN);
526
527        WindowsTokenSource::new(self.vmi, self.va + TOKEN.TokenSource.offset())
528    }
529
530    /// Returns the authentication LUID identifying the logon session.
531    ///
532    /// # Implementation Details
533    ///
534    /// Corresponds to `_TOKEN.AuthenticationId`.
535    pub fn authentication_id(&self) -> Result<WindowsLuid, VmiError> {
536        let TOKEN = offset!(self.vmi, _TOKEN);
537
538        let raw = self
539            .vmi
540            .read_u64(self.va + TOKEN.AuthenticationId.offset())?;
541
542        Ok(WindowsLuid::from(raw))
543    }
544
545    /// Returns the token's own identifier.
546    ///
547    /// # Implementation Details
548    ///
549    /// Corresponds to `_TOKEN.TokenId`.
550    pub fn token_id(&self) -> Result<WindowsLuid, VmiError> {
551        let TOKEN = offset!(self.vmi, _TOKEN);
552
553        let raw = self.vmi.read_u64(self.va + TOKEN.TokenId.offset())?;
554
555        Ok(WindowsLuid::from(raw))
556    }
557
558    /// Returns the parent token identifier, or zero for tokens minted
559    /// from scratch.
560    ///
561    /// # Implementation Details
562    ///
563    /// Corresponds to `_TOKEN.ParentTokenId`.
564    pub fn parent_token_id(&self) -> Result<WindowsLuid, VmiError> {
565        let TOKEN = offset!(self.vmi, _TOKEN);
566
567        let raw = self.vmi.read_u64(self.va + TOKEN.ParentTokenId.offset())?;
568
569        Ok(WindowsLuid::from(raw))
570    }
571
572    /// Returns the modified-token identifier.
573    ///
574    /// # Implementation Details
575    ///
576    /// Corresponds to `_TOKEN.ModifiedId`.
577    pub fn modified_id(&self) -> Result<WindowsLuid, VmiError> {
578        let TOKEN = offset!(self.vmi, _TOKEN);
579
580        let raw = self.vmi.read_u64(self.va + TOKEN.ModifiedId.offset())?;
581
582        Ok(WindowsLuid::from(raw))
583    }
584
585    /// Returns the originating logon-session LUID.
586    ///
587    /// # Implementation Details
588    ///
589    /// Corresponds to `_TOKEN.OriginatingLogonSession`.
590    pub fn originating_logon_session(&self) -> Result<WindowsLuid, VmiError> {
591        let TOKEN = offset!(self.vmi, _TOKEN);
592
593        let raw = self
594            .vmi
595            .read_u64(self.va + TOKEN.OriginatingLogonSession.offset())?;
596
597        Ok(WindowsLuid::from(raw))
598    }
599
600    /// Returns the token type discriminator.
601    ///
602    /// # Implementation Details
603    ///
604    /// Corresponds to `_TOKEN.TokenType`.
605    pub fn token_type(&self) -> Result<WindowsTokenType, VmiError> {
606        let TOKEN = offset!(self.vmi, _TOKEN);
607
608        let raw = self.vmi.read_u32(self.va + TOKEN.TokenType.offset())?;
609
610        Ok(WindowsTokenType::from(raw))
611    }
612
613    /// Returns the impersonation level.
614    ///
615    /// # Implementation Details
616    ///
617    /// Corresponds to `_TOKEN.ImpersonationLevel`.
618    pub fn impersonation_level(&self) -> Result<WindowsImpersonationLevel, VmiError> {
619        let TOKEN = offset!(self.vmi, _TOKEN);
620
621        let raw = self
622            .vmi
623            .read_u32(self.va + TOKEN.ImpersonationLevel.offset())?;
624
625        Ok(WindowsImpersonationLevel::from(raw))
626    }
627
628    /// Returns the token flags.
629    ///
630    /// # Implementation Details
631    ///
632    /// Corresponds to `_TOKEN.TokenFlags`.
633    pub fn token_flags(&self) -> Result<WindowsTokenFlags, VmiError> {
634        let TOKEN = offset!(self.vmi, _TOKEN);
635
636        let raw = self.vmi.read_u32(self.va + TOKEN.TokenFlags.offset())?;
637
638        Ok(WindowsTokenFlags::from_bits_retain(raw))
639    }
640
641    /// Returns whether the token is currently in use.
642    ///
643    /// Only meaningful for primary tokens. Impersonation tokens leave
644    /// the field clear.
645    ///
646    /// # Implementation Details
647    ///
648    /// Corresponds to `_TOKEN.TokenInUse`.
649    pub fn token_in_use(&self) -> Result<bool, VmiError> {
650        let TOKEN = offset!(self.vmi, _TOKEN);
651
652        Ok(self.vmi.read_u8(self.va + TOKEN.TokenInUse.offset())? != 0)
653    }
654
655    /// Returns the number of entries in `UserAndGroups`. The first
656    /// entry is the user SID, the rest are group SIDs.
657    ///
658    /// # Implementation Details
659    ///
660    /// Corresponds to `_TOKEN.UserAndGroupCount`.
661    pub fn user_and_group_count(&self) -> Result<u32, VmiError> {
662        let TOKEN = offset!(self.vmi, _TOKEN);
663
664        self.vmi
665            .read_u32(self.va + TOKEN.UserAndGroupCount.offset())
666    }
667
668    /// Returns the number of entries in `RestrictedSids`.
669    ///
670    /// # Implementation Details
671    ///
672    /// Corresponds to `_TOKEN.RestrictedSidCount`.
673    pub fn restricted_sid_count(&self) -> Result<u32, VmiError> {
674        let TOKEN = offset!(self.vmi, _TOKEN);
675
676        self.vmi
677            .read_u32(self.va + TOKEN.RestrictedSidCount.offset())
678    }
679
680    /// Returns the primary group SID.
681    ///
682    /// # Implementation Details
683    ///
684    /// Corresponds to `_TOKEN.PrimaryGroup`.
685    pub fn primary_group(&self) -> Result<WindowsSid<'a, Driver>, VmiError> {
686        let TOKEN = offset!(self.vmi, _TOKEN);
687
688        let sid = self
689            .vmi
690            .read_va_native(self.va + TOKEN.PrimaryGroup.offset())?;
691
692        Ok(WindowsSid::new(self.vmi, sid))
693    }
694
695    /// Returns an iterator over the token's user SID followed by every
696    /// group SID. The first entry is always the user, the rest are
697    /// groups.
698    ///
699    /// # Implementation Details
700    ///
701    /// Walks `_TOKEN.UserAndGroups`.
702    pub fn user_and_groups(
703        &self,
704    ) -> Result<
705        impl Iterator<Item = Result<WindowsSidAndAttributes<'a, Driver>, VmiError>> + use<'a, Driver>,
706        VmiError,
707    > {
708        let TOKEN = offset!(self.vmi, _TOKEN);
709
710        let count = self.user_and_group_count()?;
711        let base = self
712            .vmi
713            .read_va_native(self.va + TOKEN.UserAndGroups.offset())?;
714
715        Ok(self.sid_and_attributes(base, count))
716    }
717
718    /// Returns an iterator over the token's restricted SIDs. Empty
719    /// when the token is not a restricted token.
720    ///
721    /// # Implementation Details
722    ///
723    /// Walks `_TOKEN.RestrictedSids`.
724    pub fn restricted_sids(
725        &self,
726    ) -> Result<
727        impl Iterator<Item = Result<WindowsSidAndAttributes<'a, Driver>, VmiError>> + use<'a, Driver>,
728        VmiError,
729    > {
730        let TOKEN = offset!(self.vmi, _TOKEN);
731
732        let count = self.restricted_sid_count()?;
733        let base = self
734            .vmi
735            .read_va_native(self.va + TOKEN.RestrictedSids.offset())?;
736
737        Ok(self.sid_and_attributes(base, count))
738    }
739
740    /// Returns the `_SEP_TOKEN_PRIVILEGES.Present` bitmap. Each set bit
741    /// is a privilege whose LUID `LowPart` equals the bit position.
742    ///
743    /// # Implementation Details
744    ///
745    /// Corresponds to `_TOKEN.Privileges.Present`.
746    pub fn privileges_present(&self) -> Result<u64, VmiError> {
747        let TOKEN = offset!(self.vmi, _TOKEN);
748        let SEP_TOKEN_PRIVILEGES = offset!(self.vmi, _SEP_TOKEN_PRIVILEGES);
749
750        self.vmi
751            .read_u64(self.va + TOKEN.Privileges.offset() + SEP_TOKEN_PRIVILEGES.Present.offset())
752    }
753
754    /// Returns the `_SEP_TOKEN_PRIVILEGES.Enabled` bitmap.
755    ///
756    /// # Implementation Details
757    ///
758    /// Corresponds to `_TOKEN.Privileges.Enabled`.
759    pub fn privileges_enabled(&self) -> Result<u64, VmiError> {
760        let TOKEN = offset!(self.vmi, _TOKEN);
761        let SEP_TOKEN_PRIVILEGES = offset!(self.vmi, _SEP_TOKEN_PRIVILEGES);
762
763        self.vmi
764            .read_u64(self.va + TOKEN.Privileges.offset() + SEP_TOKEN_PRIVILEGES.Enabled.offset())
765    }
766
767    /// Returns the `_SEP_TOKEN_PRIVILEGES.EnabledByDefault` bitmap.
768    ///
769    /// # Implementation Details
770    ///
771    /// Corresponds to `_TOKEN.Privileges.EnabledByDefault`.
772    pub fn privileges_enabled_by_default(&self) -> Result<u64, VmiError> {
773        let TOKEN = offset!(self.vmi, _TOKEN);
774        let SEP_TOKEN_PRIVILEGES = offset!(self.vmi, _SEP_TOKEN_PRIVILEGES);
775
776        self.vmi.read_u64(
777            self.va + TOKEN.Privileges.offset() + SEP_TOKEN_PRIVILEGES.EnabledByDefault.offset(),
778        )
779    }
780
781    /// Returns an iterator over privileges present in this token.
782    pub fn privileges(&self) -> Result<impl Iterator<Item = WindowsTokenPrivilege>, VmiError> {
783        let present = self.privileges_present()?;
784        let enabled = self.privileges_enabled()?;
785        let enabled_by_default = self.privileges_enabled_by_default()?;
786
787        Ok((0..64).filter_map(move |bit| {
788            let mask = 1u64 << bit;
789            match present & mask {
790                0 => None,
791                _ => Some(WindowsTokenPrivilege {
792                    privilege: WindowsPrivilege::new(bit),
793                    enabled: enabled & mask != 0,
794                    enabled_by_default: enabled_by_default & mask != 0,
795                }),
796            }
797        }))
798    }
799
800    /// Builds an iterator that walks an inline `_SID_AND_ATTRIBUTES` array.
801    fn sid_and_attributes(
802        &self,
803        base: Va,
804        count: u32,
805    ) -> impl Iterator<Item = Result<WindowsSidAndAttributes<'a, Driver>, VmiError>> + use<'a, Driver>
806    {
807        let vmi = self.vmi;
808        let sizeof_sid_and_attributes = offset!(vmi, _SID_AND_ATTRIBUTES).len() as u64;
809
810        (0..u64::from(count)).map(move |index| {
811            Ok(WindowsSidAndAttributes::new(
812                vmi,
813                base + index * sizeof_sid_and_attributes,
814            ))
815        })
816    }
817}