endpoint_sec/event/event_od_attribute_set.rs
1//! [`EventOdAttributeSet`]
2
3use std::ffi::OsStr;
4
5use endpoint_sec_sys::{es_event_od_attribute_set_t, es_od_record_type_t, es_string_token_t};
6
7use crate::{AuditToken, Process};
8
9/// Notification that an attribute is being set.
10///
11/// Attributes conceptually have the type `Map String (Set String)`.
12/// Each OD record has a Map of attribute name to Set of attribute value.
13/// When an attribute value is added, it is inserted into the set of values for that name.
14///
15/// The new set of attribute values may be empty.
16#[doc(alias = "es_event_od_attribute_set_t")]
17pub struct EventOdAttributeSet<'a> {
18 /// The raw reference.
19 pub(crate) raw: &'a es_event_od_attribute_set_t,
20 /// The version of the message.
21 pub(crate) version: u32,
22}
23
24impl<'a> EventOdAttributeSet<'a> {
25 /// Process that instigated operation (XPC caller).
26 #[inline(always)]
27 pub fn instigator(&self) -> Option<Process<'a>> {
28 // Safety: 'a tied to self, object obtained through ES
29 let process = unsafe { self.raw.instigator()? };
30 Some(Process::new(process, self.version))
31 }
32
33 /// Audit token of the process that instigated this event.
34 pub fn instigator_token(&self) -> AuditToken {
35 #[cfg(feature = "macos_15_0_0")]
36 if self.version >= 8 {
37 return AuditToken(self.raw.instigator_token);
38 }
39
40 // On old versions, the process was always non-null, and we can get
41 // its token easily.
42 self.instigator().unwrap().audit_token()
43 }
44
45 /// Result code for the operation.
46 #[inline(always)]
47 pub fn error_code(&self) -> i32 {
48 self.raw.error_code
49 }
50
51 /// The type of the record for which the attribute is being set.
52 #[inline(always)]
53 pub fn record_type(&self) -> es_od_record_type_t {
54 self.raw.record_type
55 }
56
57 /// The name of the record for which the attribute is being set.
58 #[inline(always)]
59 pub fn record_name(&self) -> &'a OsStr {
60 // Safety: 'a tied to self, object obtained through ES
61 unsafe { self.raw.record_name.as_os_str() }
62 }
63
64 /// The name of the attribute that was set.
65 #[inline(always)]
66 pub fn attribute_name(&self) -> &'a OsStr {
67 // Safety: 'a tied to self, object obtained through ES
68 unsafe { self.raw.attribute_name.as_os_str() }
69 }
70
71 /// The size of attribute_value_array.
72 #[inline(always)]
73 pub fn attribute_value_count(&self) -> usize {
74 self.raw.attribute_value_count
75 }
76
77 /// Iterator over the attribute values that were set.
78 #[inline(always)]
79 pub fn attribute_values<'s>(&'s self) -> AttributeValues<'s, 'a> {
80 AttributeValues::new(self)
81 }
82
83 /// OD node being mutated.
84 ///
85 /// Typically one of "/Local/Default", "/LDAPv3/<server>" or "/Active Directory/<domain>".
86 #[inline(always)]
87 pub fn node_name(&self) -> &'a OsStr {
88 // Safety: 'a tied to self, object obtained through ES
89 unsafe { self.raw.node_name.as_os_str() }
90 }
91
92 /// Optional. If node_name is "/Local/Default", this is, the path of the database against which
93 /// OD is authenticating.
94 #[inline(always)]
95 pub fn db_path(&self) -> Option<&'a OsStr> {
96 if self.node_name() == OsStr::new("/Local/Default") {
97 // Safety: 'a tied to self, object obtained through ES
98 Some(unsafe { self.raw.db_path.as_os_str() })
99 } else {
100 None
101 }
102 }
103}
104
105// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
106unsafe impl Send for EventOdAttributeSet<'_> {}
107// Safety: safe to share across threads: does not contain any interior mutability nor depend on current thread state
108unsafe impl Sync for EventOdAttributeSet<'_> {}
109
110impl_debug_eq_hash_with_functions!(EventOdAttributeSet<'a> with version; instigator, instigator_token, error_code, record_type, record_name, attribute_name, attribute_value_count, node_name, db_path);
111
112/// Read the `idx` attribute value of `raw`
113///
114/// # Safety
115///
116/// Must be called with a valid event for which `idx` is in range `0..raw.attribute_value_count`
117unsafe fn read_nth_attribute_value(raw: &es_event_od_attribute_set_t, idx: usize) -> es_string_token_t {
118 // SAFETY:
119 // * upheld by the caller for the index;
120 // * `raw.attribute_value_array` is given to us by ES, so adding to it preserves alignment;
121 unsafe { std::ptr::read(raw.attribute_value_array.add(idx)) }
122}
123
124make_event_data_iterator!(
125 EventOdAttributeSet;
126 /// Iterator over the attribute values of an [`EventOdAttributeSet`]
127 AttributeValues with attribute_value_count (usize);
128 &'raw OsStr;
129 read_nth_attribute_value,
130 super::as_os_str,
131);