fapolicy_rules/object.rs
1/*
2 * Copyright Concurrent Technologies Corporation 2021
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 */
8
9use std::fmt::{Display, Formatter};
10
11use crate::{bool_to_c, ObjPart, Rvalue};
12
13/// # Object
14/// The object is the file that the subject is interacting with.
15/// The fields in the rule that describe the object are written in a `name=value` format.
16/// There can be one or more object fields. Each field is and'ed with others to decide if a rule triggers.
17#[derive(Clone, Debug, PartialEq)]
18pub struct Object {
19 pub parts: Vec<Part>,
20}
21
22impl Object {
23 pub fn new(parts: Vec<Part>) -> Self {
24 Object { parts }
25 }
26
27 pub fn is_all(&self) -> bool {
28 self.parts.contains(&Part::All)
29 }
30
31 pub fn all() -> Self {
32 Self::new(vec![ObjPart::All])
33 }
34
35 pub fn path(&self) -> Option<String> {
36 match self.parts.iter().find(|p| matches!(p, Part::Path(_))) {
37 Some(Part::Path(path)) => Some(path.clone()),
38 _ => None,
39 }
40 }
41
42 pub fn from_path(path: &str) -> Object {
43 Object::new(vec![ObjPart::Path(path.into())])
44 }
45}
46
47/// # Object Field
48/// Composed with logical AND to create the Object of the rule
49///
50/// ### Currently unsupported Object Fields
51/// - `sha256hash`: This option matches against the sha256 hash of the file being accessed.
52/// - The hash in the rules should be all lowercase letters and do NOT start with 0x.
53/// - Lowercase is the default output of sha256sum.
54///
55#[derive(Clone, Debug, PartialEq)]
56pub enum Part {
57 /// This matches against any subject. When used, this must be the only subject in the rule.
58 All,
59 /// This option will match against the device that the file being accessed resides on. To use it, start with `/dev/` and add the target device name.
60 Device(String),
61 /// If you wish to match on access to any file in a directory, then use this by giving the full path to the directory.
62 /// - Its recommended to end with the `/` to ensure it matches a directory.
63 /// - There are 3 keywords that `dir` supports:
64 /// - `execdirs`
65 /// - `systemdirs`
66 /// - `untrusted`
67 ///
68 /// ### See the `dir` option under Subject for an explanation of these keywords.
69 Dir(String),
70 /// This option matches against the mime type of the file being accessed. See `ftype` under Subject for more information on determining the mime type.
71 FileType(Rvalue),
72 /// This is the full path to the file that will be accessed. Globbing is not supported. You may also use the special keyword `untrusted` to match on the subject not being listed in the rpm database.
73 Path(String),
74 /// This is a boolean describing whether it is required for the object to be in the trust database or not. A value of 1 means its required while 0 means its not. Trust checking is extended by the integrity setting in fapolicyd.conf.
75 Trust(bool),
76}
77
78impl From<Part> for Object {
79 fn from(p: Part) -> Self {
80 Object { parts: vec![p] }
81 }
82}
83
84impl Display for Object {
85 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86 let s: String = self
87 .parts
88 .iter()
89 .map(|p| format!("{}", p))
90 .collect::<Vec<String>>()
91 .join(" ");
92 f.write_fmt(format_args!("{}", s))
93 }
94}
95
96impl Display for Part {
97 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
98 match self {
99 Part::All => f.write_str("all"),
100 Part::Device(p) => f.write_fmt(format_args!("device={}", p)),
101 Part::Dir(p) => f.write_fmt(format_args!("dir={}", p)),
102 Part::FileType(t) => f.write_fmt(format_args!("ftype={}", t)),
103 Part::Path(p) => f.write_fmt(format_args!("path={}", p)),
104 Part::Trust(b) => f.write_fmt(format_args!("trust={}", bool_to_c(*b))),
105 }
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use crate::file_type::Rvalue::Literal;
112
113 use super::*;
114
115 #[test]
116 fn display() {
117 assert_eq!(format!("{}", Part::All), "all");
118 assert_eq!(format!("{}", Part::Dir("/foo".into())), "dir=/foo");
119 assert_eq!(
120 format!("{}", Part::Device("/dev/cdrom".into())),
121 "device=/dev/cdrom"
122 );
123 assert_eq!(
124 format!(
125 "{}",
126 Part::FileType(Literal("application/x-sharedlib".into()))
127 ),
128 "ftype=application/x-sharedlib"
129 );
130 }
131
132 #[test]
133 fn display_trusted() {
134 assert_eq!(
135 format!("{}", Object::new(vec![Part::All, Part::Trust(true)])),
136 "all trust=1"
137 );
138 assert_eq!(
139 format!(
140 "{}",
141 Object::new(vec![Part::Dir("/foo".into()), Part::Trust(true)])
142 ),
143 "dir=/foo trust=1"
144 );
145 assert_eq!(
146 format!(
147 "{}",
148 Object::new(vec![Part::Device("/dev/cdrom".into()), Part::Trust(true)])
149 ),
150 "device=/dev/cdrom trust=1"
151 );
152 assert_eq!(
153 format!(
154 "{}",
155 Object::new(vec![
156 Part::FileType(Literal("application/x-sharedlib".into())),
157 Part::Trust(true)
158 ])
159 ),
160 "ftype=application/x-sharedlib trust=1"
161 );
162 }
163}