1use std::num::NonZeroU16;
6
7use selinux_policy_derive::{HasName, HasPolicyId, Parse, Serialize, Validate};
8
9use super::bitmap::IdSet;
10use super::error::{ParseError, SerializeError, ValidateError};
11use super::id_type::IdType;
12use super::parser::{PolicyCursor, PolicyWriter};
13use super::traits::{Parse, PolicyId, Serialize, Validate};
14use super::{ClassId, NewPolicy, TypeId, TypeSet};
15
16#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
18pub struct RoleTag;
19
20pub type RoleId = IdType<NonZeroU16, RoleTag>;
22
23pub type RoleSet = IdSet<RoleId>;
25
26#[derive(Parse, Serialize)]
27struct BinaryRoleMetadata {
28 key_length: u32,
29 id: RoleId,
30 bounds: Option<RoleId>,
31}
32
33#[derive(Debug, Validate, HasName, HasPolicyId)]
35pub struct Role {
36 id: RoleId,
37 name: Box<[u8]>,
38 bounds: Option<RoleId>,
39 dominates: RoleSet,
40 types: TypeSet,
41}
42
43impl Role {
44 pub fn bounds(&self) -> Option<RoleId> {
45 self.bounds
46 }
47
48 pub fn types(&self) -> &TypeSet {
49 &self.types
50 }
51}
52
53impl Parse for Role {
54 fn parse(cursor: &mut PolicyCursor<'_>) -> Result<Self, ParseError> {
55 let metadata = BinaryRoleMetadata::parse(cursor)?;
56 let name = Box::from(cursor.read_bytes(metadata.key_length as usize)?);
57 let dominates = RoleSet::parse(cursor)?;
58 let types = TypeSet::parse(cursor)?;
59
60 Ok(Self { id: metadata.id, name, bounds: metadata.bounds, dominates, types })
61 }
62}
63
64impl Serialize for Role {
65 fn serialize(&self, writer: &mut PolicyWriter<'_>) -> Result<(), SerializeError> {
66 let metadata = BinaryRoleMetadata {
67 key_length: self.name.len() as u32,
68 id: self.id,
69 bounds: self.bounds,
70 };
71 metadata.serialize(writer)?;
72 writer.write_bytes(&self.name);
73 self.dominates.serialize(writer)?;
74 self.types.serialize(writer)?;
75 Ok(())
76 }
77}
78impl Validate for RoleId {
79 fn validate(&self, policy: &NewPolicy) -> Result<(), ValidateError> {
80 policy
81 .roles()
82 .get_by_id(*self)
83 .map(|_| ())
84 .ok_or_else(|| ValidateError::UnknownId { kind: "role", id: self.as_u32() })
85 }
86}
87
88#[derive(Debug, Parse, Serialize, Validate)]
90pub struct RoleTransition {
91 current_role: RoleId,
92 type_: TypeId,
93 new_role: RoleId,
94 class: ClassId,
95}
96
97impl RoleTransition {
98 pub fn current_role(&self) -> RoleId {
99 self.current_role
100 }
101
102 pub fn type_(&self) -> TypeId {
103 self.type_
104 }
105
106 pub fn new_role(&self) -> RoleId {
107 self.new_role
108 }
109
110 pub fn class(&self) -> ClassId {
111 self.class
112 }
113}
114
115#[derive(Debug, Parse, Serialize, Validate)]
117pub struct RoleAllow {
118 source_role: RoleId,
119 new_role: RoleId,
120}
121
122impl RoleAllow {
123 pub fn source_role(&self) -> RoleId {
124 self.source_role
125 }
126
127 pub fn new_role(&self) -> RoleId {
128 self.new_role
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use crate::new_policy::metadata::PolicyVersion;
136 use crate::new_policy::parser::PolicyWriter;
137 use crate::new_policy::traits::{HasName, HasPolicyId, PolicyId};
138
139 #[test]
140 fn test_role_parse_and_serialize() {
141 let data = [
142 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, b't', b'e', b's', b't', 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
156 let mut cursor = PolicyCursor::new(&data);
157 let role = Role::parse(&mut cursor).unwrap();
158 assert_eq!(role.id(), RoleId::from_u32(1).unwrap());
159 assert_eq!(role.name(), b"test");
160 assert!(role.bounds().is_none());
161 let mut writer = Vec::new();
164 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
165 role.serialize(&mut policy_writer).unwrap();
166 assert_eq!(writer, data);
167 }
168
169 #[test]
170 fn test_role_transition_parse_and_serialize() {
171 let data = [
172 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, ];
177 let mut cursor = PolicyCursor::new(&data);
178 let trans = RoleTransition::parse(&mut cursor).unwrap();
179 assert_eq!(trans.current_role(), RoleId::from_u32(1).unwrap());
180 assert_eq!(trans.type_(), TypeId::from_u32(2).unwrap());
181 assert_eq!(trans.new_role(), RoleId::from_u32(3).unwrap());
182 assert_eq!(trans.class(), ClassId::from_u32(4).unwrap());
183
184 let mut writer = Vec::new();
185 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
186 trans.serialize(&mut policy_writer).unwrap();
187 assert_eq!(writer, data);
188 }
189
190 #[test]
191 fn test_role_allow_parse_and_serialize() {
192 let data = [
193 1, 0, 0, 0, 2, 0, 0, 0, ];
196 let mut cursor = PolicyCursor::new(&data);
197 let allow = RoleAllow::parse(&mut cursor).unwrap();
198 assert_eq!(allow.source_role(), RoleId::from_u32(1).unwrap());
199 assert_eq!(allow.new_role(), RoleId::from_u32(2).unwrap());
200
201 let mut writer = Vec::new();
202 let mut policy_writer = PolicyWriter::new(PolicyVersion::V33, &mut writer);
203 allow.serialize(&mut policy_writer).unwrap();
204 assert_eq!(writer, data);
205 }
206
207 #[test]
208 fn test_role_policy_elements() {
209 let policy_bytes =
210 include_bytes!("../../testdata/composite_policies/compiled/role_transition_policy");
211 let new_policy = NewPolicy::parse(policy_bytes).expect("parse role_transition policy");
212 new_policy.validate().expect("validate role_transition policy");
213
214 assert_eq!(new_policy.role_transitions().len(), 2);
215 assert_eq!(new_policy.role_allowlist().len(), 1);
216 }
217}