endpoint_sec/event/
event_authentication.rs

1//! [`EventAuthentication`]
2
3use std::ffi::OsStr;
4
5use endpoint_sec_sys::{
6    es_authentication_type_t, es_auto_unlock_type_t, es_event_authentication_auto_unlock_t,
7    es_event_authentication_od_t, es_event_authentication_t, es_event_authentication_t_anon0,
8    es_event_authentication_token_t, es_event_authentication_touchid_t, es_touchid_mode_t, uid_t,
9};
10
11use crate::Process;
12
13/// An authentication was performed.
14#[doc(alias = "es_event_authentication_t")]
15pub struct EventAuthentication<'a> {
16    /// Raw event
17    pub(crate) raw: &'a es_event_authentication_t,
18    /// Message version
19    pub(crate) version: u32,
20}
21
22impl<'a> EventAuthentication<'a> {
23    /// True iff authentication was successful.
24    #[inline(always)]
25    pub fn success(&self) -> bool {
26        self.raw.success
27    }
28
29    /// The type of authentication.
30    #[inline(always)]
31    pub fn type_(&self) -> es_authentication_type_t {
32        self.raw.type_
33    }
34
35    /// Type-specific data describing the authentication.
36    #[inline(always)]
37    pub fn raw_data(&self) -> &'a es_event_authentication_t_anon0 {
38        &self.raw.data
39    }
40
41    /// Details about event
42    #[inline(always)]
43    pub fn data(&self) -> Option<AuthenticationData<'a>> {
44        let res = match self.type_() {
45            es_authentication_type_t::ES_AUTHENTICATION_TYPE_OD => AuthenticationData::Od(EventAuthenticationOd {
46                // Safety: access to union is gated on relevant enum
47                raw: unsafe { self.raw_data().od.as_opt()? },
48                version: self.version,
49            }),
50            es_authentication_type_t::ES_AUTHENTICATION_TYPE_TOUCHID => {
51                AuthenticationData::TouchId(EventAuthenticationTouchId {
52                    // Safety: access to union is gated on relevant enum
53                    raw: unsafe { self.raw_data().touchid.as_opt()? },
54                    version: self.version,
55                    success: self.success(),
56                })
57            },
58            es_authentication_type_t::ES_AUTHENTICATION_TYPE_TOKEN => {
59                AuthenticationData::Token(EventAuthenticationToken {
60                    // Safety: access to union is gated on relevant enum
61                    raw: unsafe { self.raw_data().token.as_opt()? },
62                    version: self.version,
63                })
64            },
65            es_authentication_type_t::ES_AUTHENTICATION_TYPE_AUTO_UNLOCK => {
66                AuthenticationData::AutoUnlock(EventAuthenticationAutoUnlock {
67                    // Safety: access to union is gated on relevant enum
68                    raw: unsafe { self.raw_data().auto_unlock.as_opt()? },
69                })
70            },
71            _ => return None,
72        };
73        Some(res)
74    }
75}
76
77// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
78unsafe impl Send for EventAuthentication<'_> {}
79// Safety: safe to share across threads: does not contain any interior mutability nor depend on current thread state
80unsafe impl Sync for EventAuthentication<'_> {}
81
82impl_debug_eq_hash_with_functions!(EventAuthentication<'a>; success, type_, data);
83
84/// See [`es_event_authentication_t_anon0`]
85#[doc(alias = "es_event_authentication_t_anon0")]
86#[doc(alias = "es_authentication_type_t")]
87#[derive(Debug, PartialEq, Eq, Hash)]
88pub enum AuthenticationData<'a> {
89    /// Wrapped [`es_event_authentication_t_anon_0.od`]
90    Od(EventAuthenticationOd<'a>),
91    /// Wrapped [`es_event_authentication_t_anon_0.touchid`]
92    TouchId(EventAuthenticationTouchId<'a>),
93    /// Wrapped [`es_event_authentication_t_anon_0.token`]
94    Token(EventAuthenticationToken<'a>),
95    /// Wrapped [`es_event_authentication_t_anon_0.auto_unlock`]
96    AutoUnlock(EventAuthenticationAutoUnlock<'a>),
97}
98
99/// OpenDirectory authentication data
100#[doc(alias = "es_event_authentication_od_t")]
101pub struct EventAuthenticationOd<'a> {
102    /// Raw event
103    raw: &'a es_event_authentication_od_t,
104    /// Message version
105    version: u32,
106}
107
108impl<'a> EventAuthenticationOd<'a> {
109    /// Process that instigated the authentication (XPC caller that asked for authentication).
110    #[inline(always)]
111    pub fn instigator(&self) -> Process<'a> {
112        Process::new(
113            // Safety: 'a tied to self, object obtained through ES
114            unsafe { self.raw.instigator.as_ref() },
115            self.version,
116        )
117    }
118
119    /// OD record type against which OD is authenticating. Typically `Users`, but other record types
120    /// can auth too.
121    #[inline(always)]
122    pub fn record_type(&self) -> &'a OsStr {
123        // Safety: 'a tied to self, object obtained through ES
124        unsafe { self.raw.record_type.as_os_str() }
125    }
126
127    /// OD record name against which OD is authenticating. For record type `Users`, this is the
128    /// username.
129    #[inline(always)]
130    pub fn record_name(&self) -> &'a OsStr {
131        // Safety: 'a tied to self, object obtained through ES
132        unsafe { self.raw.record_name.as_os_str() }
133    }
134
135    /// OD node against which OD is authenticating. Typically one of `/Local/Default`, `/LDAPv3/
136    /// <server>` or `/Active Directory/<domain>`.
137    #[inline(always)]
138    pub fn node_name(&self) -> &'a OsStr {
139        // Safety: 'a tied to self, object obtained through ES
140        unsafe { self.raw.node_name.as_os_str() }
141    }
142
143    /// Optional. If node_name is "/Local/Default", this is the path of the database against which
144    /// OD is authenticating.
145    #[inline(always)]
146    pub fn db_path(&self) -> &'a OsStr {
147        // Safety: 'a tied to self, object obtained through ES
148        unsafe { self.raw.db_path.as_os_str() }
149    }
150}
151
152// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
153unsafe impl Send for EventAuthenticationOd<'_> {}
154
155impl_debug_eq_hash_with_functions!(EventAuthenticationOd<'a>; instigator, record_name, node_name, db_path);
156
157/// TouchID authentication data
158#[doc(alias = "es_event_authentication_touchid_t")]
159pub struct EventAuthenticationTouchId<'a> {
160    /// Raw event
161    raw: &'a es_event_authentication_touchid_t,
162    /// Message version
163    version: u32,
164    /// Overall identification success
165    success: bool,
166}
167
168impl<'a> EventAuthenticationTouchId<'a> {
169    /// Process that instigated the authentication (XPC caller that asked for authentication).
170    #[inline(always)]
171    pub fn instigator(&self) -> Process<'a> {
172        Process::new(
173            // Safety: 'a tied to self, object obtained through ES
174            unsafe { self.raw.instigator.as_ref() },
175            self.version,
176        )
177    }
178
179    /// TouchID authentication type
180    #[inline(always)]
181    pub fn touchid_mode(&self) -> es_touchid_mode_t {
182        self.raw.touchid_mode
183    }
184
185    /// Describes whether or not the uid of the user authenticated is available
186    #[inline(always)]
187    pub fn has_uid(&self) -> bool {
188        self.raw.has_uid
189    }
190
191    /// UID of user that was authenticated.
192    #[inline(always)]
193    pub fn uid(&self) -> Option<uid_t> {
194        match (self.has_uid(), self.success, self.touchid_mode()) {
195            // Safety: access is gated on documented conditions
196            (true, true, es_touchid_mode_t::ES_TOUCHID_MODE_VERIFICATION) => unsafe { Some(self.raw.anon0.uid) },
197            _ => None,
198        }
199    }
200}
201
202// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
203unsafe impl Send for EventAuthenticationTouchId<'_> {}
204
205impl_debug_eq_hash_with_functions!(EventAuthenticationTouchId<'a>; instigator, touchid_mode, has_uid, uid);
206
207/// Token authentication data
208#[doc(alias = "es_event_authentication_token_t")]
209pub struct EventAuthenticationToken<'a> {
210    /// Raw event
211    raw: &'a es_event_authentication_token_t,
212    /// Message version
213    version: u32,
214}
215
216impl<'a> EventAuthenticationToken<'a> {
217    /// Process that instigated the authentication (XPC caller that asked for authentication).
218    #[inline(always)]
219    pub fn instigator(&self) -> Process<'a> {
220        Process::new(
221            // Safety: 'a tied to self, object obtained through ES
222            unsafe { self.raw.instigator.as_ref() },
223            self.version,
224        )
225    }
226
227    /// Hash of the public key which CryptoTokenKit is authenticating.
228    #[inline(always)]
229    pub fn pubkey_hash(&self) -> &'a OsStr {
230        // Safety: 'a tied to self, object obtained through ES
231        unsafe { self.raw.pubkey_hash.as_os_str() }
232    }
233
234    /// Token identifier of the event which CryptoTokenKit is authenticating.
235    #[inline(always)]
236    pub fn token_id(&self) -> &'a OsStr {
237        // Safety: 'a tied to self, object obtained through ES
238        unsafe { self.raw.token_id.as_os_str() }
239    }
240
241    /// Optional. This will be available if token is used for GSS PKINIT authentication for
242    /// obtaining a kerberos TGT. `NULL` in all other cases.
243    #[inline(always)]
244    pub fn kerberos_principal(&self) -> &'a OsStr {
245        // Safety: 'a tied to self, object obtained through ES
246        unsafe { self.raw.kerberos_principal.as_os_str() }
247    }
248}
249
250// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
251unsafe impl Send for EventAuthenticationToken<'_> {}
252
253impl_debug_eq_hash_with_functions!(EventAuthenticationToken<'a>; instigator, pubkey_hash, token_id, kerberos_principal);
254
255/// Auto unlock authentication data
256#[doc(alias = "es_event_authentication_auto_unlock_t")]
257pub struct EventAuthenticationAutoUnlock<'a> {
258    /// Raw event
259    raw: &'a es_event_authentication_auto_unlock_t,
260}
261
262impl<'a> EventAuthenticationAutoUnlock<'a> {
263    /// Username for which the authentication was attempted.
264    #[inline(always)]
265    pub fn username(&self) -> &'a OsStr {
266        // Safety: 'a tied to self, object obtained through ES
267        unsafe { self.raw.username.as_os_str() }
268    }
269
270    /// Purpose of the authentication.
271    #[inline(always)]
272    pub fn type_(&self) -> es_auto_unlock_type_t {
273        self.raw.type_
274    }
275}
276
277// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
278unsafe impl Send for EventAuthenticationAutoUnlock<'_> {}
279
280impl_debug_eq_hash_with_functions!(EventAuthenticationAutoUnlock<'a>; username, type_);