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
//! [`EventOdGroupAdd`]

use std::ffi::OsStr;

use endpoint_sec_sys::{es_event_od_group_add_t, es_od_member_id_t, es_od_member_id_t_anon0, es_od_member_type_t};

use crate::Process;

/// Notification that a member was added to a group.
///
/// This event does not indicate that a member was actually added. For example when adding a user
/// to a group they are already a member of.
#[doc(alias = "es_event_od_group_add_t")]
pub struct EventOdGroupAdd<'a> {
    /// The raw reference.
    pub(crate) raw: &'a es_event_od_group_add_t,
    /// The version of the message.
    pub(crate) version: u32,
}

impl<'a> EventOdGroupAdd<'a> {
    /// Process that instigated operation (XPC caller).
    #[inline(always)]
    pub fn instigator(&self) -> Process<'a> {
        // Safety: 'a tied to self, object obtained through ES
        Process::new(unsafe { self.raw.instigator.as_ref() }, self.version)
    }

    /// Result code for the operation.
    #[inline(always)]
    pub fn error_code(&self) -> i32 {
        self.raw.error_code
    }

    /// The group to which the member was added.
    #[inline(always)]
    pub fn group_name(&self) -> &'a OsStr {
        // Safety: 'a tied to self, object obtained through ES
        unsafe { self.raw.group_name.as_os_str() }
    }

    /// The identity of the member added.
    #[inline(always)]
    pub fn member(&self) -> OdMemberId<'a> {
        OdMemberId {
            // Safety: 'a tied to self, object obtained through ES
            raw: unsafe { self.raw.member.as_ref() },
        }
    }

    /// OD node being mutated.
    ///
    /// Typically one of "/Local/Default", "/LDAPv3/<server>" or "/Active Directory/<domain>".
    #[inline(always)]
    pub fn node_name(&self) -> &'a OsStr {
        // Safety: 'a tied to self, object obtained through ES
        unsafe { self.raw.node_name.as_os_str() }
    }

    /// Optional. If node_name is "/Local/Default", this is, the path of the database against which
    /// OD is authenticating.
    #[inline(always)]
    pub fn db_path(&self) -> Option<&'a OsStr> {
        if self.node_name() == OsStr::new("/Local/Default") {
            // Safety: 'a tied to self, object obtained through ES
            Some(unsafe { self.raw.db_path.as_os_str() })
        } else {
            None
        }
    }
}

// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Send for EventOdGroupAdd<'_> {}

impl_debug_eq_hash_with_functions!(EventOdGroupAdd<'a> with version; instigator, error_code, group_name, member, node_name, db_path);

/// The identity of a group member
#[doc(alias = "es_od_member_id_t")]
pub struct OdMemberId<'a> {
    /// The raw reference.
    pub(crate) raw: &'a es_od_member_id_t,
}

impl<'a> OdMemberId<'a> {
    /// Indicates the type of the member, and how it is identified.
    #[inline(always)]
    pub fn member_type(&self) -> es_od_member_type_t {
        self.raw.member_type
    }

    /// The member identity, as its raw value.
    #[inline(always)]
    pub fn raw_member_value(&self) -> &'a es_od_member_id_t_anon0 {
        &self.raw.member_value
    }

    /// The member identity.
    #[inline(always)]
    pub fn member_value(&self) -> Option<OdMemberIdValue<'a>> {
        // Safety in general: we check against the 'member_type' before accessing the union
        let res = match self.member_type() {
            es_od_member_type_t::ES_OD_MEMBER_TYPE_USER_UUID => {
                // Safety: 'a tied to self, object obtained through ES
                OdMemberIdValue::UserUuid(unsafe { self.raw.member_value.uuid })
            },
            es_od_member_type_t::ES_OD_MEMBER_TYPE_GROUP_UUID => {
                // Safety: 'a tied to self, object obtained through ES
                OdMemberIdValue::GroupUuid(unsafe { self.raw.member_value.uuid })
            },
            es_od_member_type_t::ES_OD_MEMBER_TYPE_USER_NAME => {
                // Safety: 'a tied to self, object obtained through ES
                OdMemberIdValue::UserName(unsafe { self.raw.member_value.name.as_os_str() })
            },
            _ => return None,
        };

        Some(res)
    }
}

// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Send for OdMemberId<'_> {}

impl_debug_eq_hash_with_functions!(OdMemberId<'a>; member_type, member_value);

/// A member identity.
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum OdMemberIdValue<'a> {
    /// Group member is a user, designated by name
    UserName(&'a OsStr),
    /// Group member is a user, designated by UUID
    UserUuid(libc::uuid_t),
    /// Group member is another group, designated by UUID
    GroupUuid(libc::uuid_t),
}

// Safety: safe to send across threads: does not contain any interior mutability nor depend on current thread state
unsafe impl Send for OdMemberIdValue<'_> {}