1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! [`EventAuthorizationJudgement`]
use std::ffi::OsStr;
use endpoint_sec_sys::{es_authorization_result_t, es_authorization_rule_class_t, es_event_authorization_judgement_t};
use crate::{AuditToken, Process};
/// Notification that a process had it's right petition judged
#[doc(alias = "es_event_authorization_judgement_t")]
pub struct EventAuthorizationJudgement<'a> {
/// The raw reference.
pub(crate) raw: &'a es_event_authorization_judgement_t,
/// The version of the message.
pub(crate) version: u32,
}
impl<'a> EventAuthorizationJudgement<'a> {
/// Process that submitted the petition (XPC caller)
#[inline(always)]
pub fn instigator(&self) -> Option<Process<'a>> {
// Safety: 'a tied to self, object obtained through ES
let process = unsafe { self.raw.instigator()? };
Some(Process::new(process, self.version))
}
/// Audit token of the process that instigated this event.
pub fn instigator_token(&self) -> AuditToken {
#[cfg(feature = "macos_15_0_0")]
if self.version >= 8 {
return AuditToken(self.raw.instigator_token);
}
// On old versions, the process was always non-null, and we can get
// its token easily.
self.instigator().unwrap().audit_token()
}
/// Process that created the petition
#[inline(always)]
pub fn petitioner(&self) -> Option<Process<'a>> {
Some(Process::new(
// Safety: 'a tied to self, object obtained through ES
unsafe { self.raw.petitioner.as_ref()? },
self.version,
))
}
/// Audit token of the process that created the petition.
pub fn petitioner_token(&self) -> AuditToken {
#[cfg(feature = "macos_15_0_0")]
if self.version >= 8 {
return AuditToken(self.raw.petitioner_token);
}
// On old versions, the process was always non-null, and we can get
// its token easily.
self.petitioner().unwrap().audit_token()
}
/// The overall result of the petition. 0 indicates success.
///
/// Possible return codes are defined in Security framework "Authorization/Authorization.h"
#[inline(always)]
pub fn return_code(&self) -> i32 {
self.raw.return_code
}
/// Number of results.
#[inline(always)]
pub fn result_count(&self) -> usize {
self.raw.result_count
}
/// Iterator over the results
#[inline(always)]
pub fn rights<'event>(&'event self) -> AuthorizationJudgementResults<'event, 'a> {
AuthorizationJudgementResults::new(self)
}
}
// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Send for EventAuthorizationJudgement<'_> {}
// Safety: safe to share across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Sync for EventAuthorizationJudgement<'_> {}
impl_debug_eq_hash_with_functions!(EventAuthorizationJudgement<'a> with version; instigator, instigator_token, petitioner, petitioner_token, return_code, result_count);
/// Describes, for a single right, the class of that right and if it was granted
#[doc(alias = "es_authorization_result_t")]
pub struct AuthorizationResult<'a> {
/// The raw reference.
pub(crate) raw: &'a es_authorization_result_t,
}
impl<'a> AuthorizationResult<'a> {
/// The name of the right being considered
#[inline(always)]
pub fn right_name(&self) -> &'a OsStr {
// Safety: 'a tied to self, object obtained through ES
unsafe { self.raw.right_name.as_os_str() }
}
/// The class of the right being considered
///
/// The rule class determines how the operating system determines if it should be granted or not
#[inline(always)]
pub fn rule_class(&self) -> es_authorization_rule_class_t {
self.raw.rule_class
}
/// Indicates if the right was granted or not
#[inline(always)]
pub fn granted(&self) -> bool {
self.raw.granted
}
}
// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Send for AuthorizationResult<'_> {}
impl_debug_eq_hash_with_functions!(AuthorizationResult<'a>; right_name, rule_class, granted);
/// Read the `idx` result of `raw`
///
/// # Safety
///
/// Must be called with a valid event for which `idx` is in range `0..raw.result_count`
unsafe fn read_nth_result(raw: &es_event_authorization_judgement_t, idx: usize) -> *const es_authorization_result_t {
// SAFETY:
// * upheld by the caller for the index;
// * `raw.results` is given to us by ES, so adding to it preserves alignment;
unsafe { raw.results.add(idx).cast_const() }
}
/// See [`super::as_os_str()`] for lifetime and safety docs
unsafe fn make_result<'a>(result: *const es_authorization_result_t) -> AuthorizationResult<'a> {
assert!(!result.is_null());
AuthorizationResult {
raw: unsafe { &*result },
}
}
make_event_data_iterator!(
EventAuthorizationJudgement;
/// Iterator over the rights of an [`EventAuthorizationJudgement`]
AuthorizationJudgementResults with result_count (usize);
AuthorizationResult<'raw>;
read_nth_result,
make_result,
);