endpoint_sec/event/event_gatekeeper_user_override.rs
1//! [`EventGatekeeperUserOverride`]
2
3use std::ffi::OsStr;
4
5use endpoint_sec_sys::{es_event_gatekeeper_user_override_t, es_gatekeeper_user_override_file_type_t, es_signed_file_info_t};
6
7use crate::File;
8
9/// Notification for a gatekeeper_user_override event.
10///
11/// This event type does not support caching (notify-only).
12///
13/// Hashes are calculated in usermode by Gatekeeper. There is no guarantee that
14/// any other program including the kernel will observe the same file at the
15/// reported path. Furthermore, there is no guarantee that the CDHash is valid
16/// or that it matches the containing binary.
17#[doc(alias = "es_event_gatekeeper_user_override_t")]
18pub struct EventGatekeeperUserOverride<'a> {
19 /// Raw event
20 pub(super) raw: &'a es_event_gatekeeper_user_override_t,
21}
22
23impl<'a> EventGatekeeperUserOverride<'a> {
24 /// Describes the target file that is being overridden by the user.
25 ///
26 /// If Endpoint security can't lookup the file at event submission it will
27 /// emit a path instead of a [`File`].
28 pub fn file(&self) -> Option<GatekeeperFile<'a>> {
29 match self.raw.file_type {
30 es_gatekeeper_user_override_file_type_t::ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_PATH => {
31 // Safety: Union access (file_path) is allowed as file_type
32 // indicates this field was used to construct this event.
33 //
34 // 'a tied to self, object obtained through ES
35 let file_path = unsafe { self.raw.file.file_path.as_os_str() };
36 Some(GatekeeperFile::Path(file_path))
37 },
38 es_gatekeeper_user_override_file_type_t::ES_GATEKEEPER_USER_OVERRIDE_FILE_TYPE_FILE => {
39 // Safety: Union access (file) is allowed as file_type indicates
40 // this field was used to construct this event.
41 //
42 // 'a tied to self, object obtained through ES
43 let file = unsafe { self.raw.file.file.as_ref() };
44 Some(GatekeeperFile::File(File::new(file)))
45 },
46 _ => None,
47 }
48 }
49
50 /// SHA256 of the file.
51 ///
52 /// Provided if the filesize is less than 100MB.
53 #[inline(always)]
54 pub fn sha256(&self) -> &[u8; 32] {
55 // Safety: 'a tied to self, object obtained through ES
56 unsafe {
57 &*self.raw.sha256
58 }
59 }
60
61 /// Signing Information, available if the file has been signed.
62 #[inline(always)]
63 pub fn signing_info(&self) -> Option<SignedFileInfo<'_>> {
64 // Safety: 'a tied to self, object obtained through ES
65 let signing_info = unsafe { self.raw.signing_info()? };
66 Some(SignedFileInfo::new(signing_info))
67 }
68}
69
70// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
71unsafe impl Send for EventGatekeeperUserOverride<'_> {}
72// Safety: safe to share across threads: does not contain any interior mutability nor depend on current thread state
73unsafe impl Sync for EventGatekeeperUserOverride<'_> {}
74
75impl_debug_eq_hash_with_functions!(EventGatekeeperUserOverride<'a>; file, sha256, signing_info);
76
77/// The file being overridden by a user.
78#[derive(Debug, PartialEq, Hash)]
79pub enum GatekeeperFile<'a> {
80 /// Endpoint Security couldn't lookup the file, and emitted a path.
81 Path(&'a OsStr),
82 /// The full information of the file being overridden.
83 File(File<'a>),
84}
85
86
87/// Information from a signed file.
88///
89/// If the file is a multiarchitecture binary, only the signing information for
90/// the native host architecture is reported. I.e. the CDHash from the AArch64
91/// slice if the host is AArch64.
92pub struct SignedFileInfo<'a> {
93 /// Raw event
94 raw: &'a es_signed_file_info_t,
95}
96
97impl<'a> SignedFileInfo<'a> {
98 /// Create a new [`SignedFileInfo`] instance.
99 fn new(raw: &es_signed_file_info_t) -> SignedFileInfo<'_> {
100 SignedFileInfo { raw }
101 }
102
103 /// Code Directory Hash
104 #[inline(always)]
105 pub fn cdhash(&self) -> &'a [u8; 20] {
106 &self.raw.cdhash
107 }
108
109 /// Signing Identifier, if available in the signing information.
110 #[inline(always)]
111 pub fn signing_id(&self) -> &'a OsStr {
112 // Safety: 'a tied to self, object obtained through ES
113 unsafe {
114 self.raw.signing_id.as_os_str()
115 }
116 }
117
118 /// Team Identifier, if available in the signing information.
119 #[inline(always)]
120 pub fn team_id(&self) -> &'a OsStr {
121 // Safety: 'a tied to self, object obtained through ES
122 unsafe {
123 self.raw.team_id.as_os_str()
124 }
125 }
126}
127
128impl_debug_eq_hash_with_functions!(SignedFileInfo<'a>; cdhash, signing_id, team_id);