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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
//! Low level function mapping for fanotify
//!
use crate::types::*;
use libc::c_void;
use std::ffi::{CString, OsStr};
use std::io::Error;
use std::mem;
use std::os::unix::ffi::OsStrExt;
use std::slice;
#[allow(unused_imports)]
use crate::flags::*;
/// Get current platform sizeof of fanotify_event_metadata.
const FAN_EVENT_METADATA_LEN: usize = mem::size_of::<fanotify_event_metadata>();
/// Length of memory to be allocated for read buffer
pub static mut FAN_EVENT_BUFFER_LEN: usize = 250;
/// Initializes a new fanotify group and returns a
/// file descriptor for the event queue associated with the group.
///
/// The file descriptor is used in calls to [`fanotify_mark()`] to
/// specify the files, directories, mounts, or filesystems for which
/// fanotify events shall be created. These events are received by
/// reading from the file descriptor. Some events are only
/// informative, indicating that a file has been accessed. Other
/// events can be used to determine whether another application is
/// permitted to access a file or directory. Permission to access
/// filesystem objects is granted by writing to the file descriptor.
///
/// Multiple programs may be using the fanotify interface at the same
/// time to monitor the same files.
///
/// In the current implementation, the number of fanotify groups per
/// user is limited to 128. This limit cannot be overridden.
///
/// Calling [`fanotify_init()`] requires the `CAP_SYS_ADMIN` capability.
/// This constraint might be relaxed in future versions of the API.
/// Therefore, certain additional capability checks have been
/// implemented as indicated below.
///
/// The flags argument contains a multi-bit field defining the
/// notification class of the listening application and further
/// single bit fields specifying the behavior of the file descriptor.
///
/// If multiple listeners for permission events exist, the
/// notification class is used to establish the sequence in which the
/// listeners receive the events.
///
/// # Arguments
/// * `flags` - Sets the notification group, can be mask of <br>
/// * [`FAN_CLASS_PRE_CONTENT`]
/// * [`FAN_CLASS_CONTENT`]
/// * [`FAN_CLASS_NOTIF`]
///
/// The following bits can additionally be set in `flags`: <br>
/// * [`FAN_CLOEXEC`]
/// * [`FAN_NONBLOCK`]
/// * [`FAN_UNLIMITED_QUEUE`]
/// * [`FAN_UNLIMITED_MARKS`]
/// * [`FAN_ENABLE_AUDIT`]
/// * [`FAN_REPORT_FID`]
/// * [`FAN_REPORT_DIR_FID`]
/// * [`FAN_REPORT_NAME`]
/// * [`FAN_REPORT_DFID_NAME`]
/// * `event_f_flags` - Defines the file status flags that
/// will be set on the open file descriptions that are created for
/// fanotify events. For details of these flags, see the description
/// of the flags values in open(2). `event_f_flags` includes a multi-
/// bit field for the access mode. This field can take the following
/// values:
/// * [`O_RDONLY`]
/// * [`O_WRONLY`]
/// * [`O_RDWR`]
///
/// Additional bits can be set in `event_f_flags`.
/// * [`O_LARGEFILE`]
/// * [`O_CLOEXEC`]
/// * [`O_APPEND`]
/// * [`O_DSYNC`]
/// * [`O_NOATIME`]
/// * [`O_NONBLOCK`]
///
/// # Example
/// This example will panic due to absence of `CAP_SYS_ADMIN` [capabilitity](https://man7.org/linux/man-pages/man7/capabilities.7.html)
/// ```rust
/// # #[should_panic]
/// # use naughtyfy::flags::*;
/// # use naughtyfy::api::*;
/// let fd = fanotify_init(FAN_CLASS_NOTIF | FAN_NONBLOCK, O_RDONLY);
/// ```
///
pub fn fanotify_init(flags: u32, event_f_flags: u32) -> Result<i32, Error> {
unsafe {
match libc::fanotify_init(flags, event_f_flags) {
-1 => Err(Error::last_os_error()),
fd => Ok(fd),
}
}
}
/// Converts the implemented types to [`OsStr`] using `as_os_str()` method. <br>
/// This is *NOT* [`std::path::Path`]
///
/// # Example
/// ```
/// # use std::ffi::OsStr;
/// # pub trait Path {
/// # fn as_os_str(&self) -> &OsStr;
/// # }
/// #
/// # impl Path for str {
/// # fn as_os_str(&self) -> &OsStr {
/// # OsStr::new(self)
/// # }
/// # }
/// let path = std::path::Path::new("/usr/bin");
/// let ostr = path.as_os_str();
/// assert_eq!(ostr,"/usr/bin");
/// ```
pub trait Path {
fn as_os_str(&self) -> &OsStr;
}
impl Path for std::path::Path {
fn as_os_str(&self) -> &OsStr {
self.as_os_str()
}
}
impl Path for str {
fn as_os_str(&self) -> &OsStr {
OsStr::new(self)
}
}
impl Path for String {
fn as_os_str(&self) -> &OsStr {
OsStr::new(self.as_str())
}
}
/// Adds, removes, or modifies an fanotify mark on a
/// filesystem object. The caller must have read permission on the
/// filesystem object that is to be marked.
///
/// # Arguments
/// * `fanotify_fd` - File descriptor returned by [`fanotify_init()`].
/// * `flags` - Bit mask describing the modification to perform. <br>
/// It must include **exactly one** of the following values:
/// * [`FAN_MARK_ADD`]
/// * [`FAN_MARK_REMOVE`]
/// * [`FAN_MARK_FLUSH`]
///
/// In addition, zero or more of the following values may be ORed
/// into flags:
/// * [`FAN_MARK_DONT_FOLLOW`]
/// * [`FAN_MARK_ONLYDIR`]
/// * [`FAN_MARK_MOUNT`]
/// * [`FAN_MARK_FILESYSTEM`]
/// * [`FAN_MARK_IGNORED_MASK`]
/// * [`FAN_MARK_IGNORED_SURV_MODIFY`]
/// * `mask` - Which events shall be listened for (or which shall be ignored). <br>
/// It is a bit mask composed of the following values:
/// * [`FAN_ACCESS`]
/// * [`FAN_MODIFY`]
/// * [`FAN_CLOSE_WRITE`]
/// * [`FAN_CLOSE_NOWRITE`]
/// * [`FAN_OPEN`]
/// * [`FAN_OPEN_EXEC`]
/// * [`FAN_ATTRIB`]
/// * [`FAN_CREATE`]
/// * [`FAN_DELETE`]
/// * [`FAN_DELETE_SELF`]
/// * [`FAN_MOVED_FROM`]
/// * [`FAN_MOVED_TO`]
/// * [`FAN_MOVE_SELF`]
/// * [`FAN_OPEN_PERM`]
/// * [`FAN_OPEN_EXEC_PERM`]
/// * [`FAN_ACCESS_PERM`]
/// * [`FAN_ONDIR`]
/// * [`FAN_EVENT_ON_CHILD`]
/// * [`FAN_CLOSE`]
/// * [`FAN_MOVE`]
/// * `dirfd` - Defines the filesystem object to be marked.
/// * `path` - Filesystem path of file or diretory.
///
/// The filesystem object to be marked is determined by the file
/// descriptor dirfd and the pathname specified in path:
///
/// * If pathname is `NULL`, dirfd defines the filesystem object to be
/// marked.
/// * If pathname is `NULL`, and dirfd takes the special value
/// `AT_FDCWD`, the current working directory is to be marked.
/// * If pathname is absolute, it defines the filesystem object to
/// be marked, and dirfd is ignored.
/// * If pathname is relative, and dirfd does not have the value
/// `AT_FDCWD`, then the filesystem object to be marked is
/// determined by interpreting pathname relative the directory
/// referred to by dirfd.
/// * If pathname is relative, and dirfd has the value `AT_FDCWD`,
/// then the filesystem object to be marked is determined by
/// interpreting pathname relative to the current working
/// directory.
///
/// # Example
/// This example will panic due to absence of `CAP_SYS_ADMIN` [capabilitity](https://man7.org/linux/man-pages/man7/capabilities.7.html)
/// ```rust
/// # #[should_panic]
/// # fn ex() {
/// # use naughtyfy::flags::*;
/// # use naughtyfy::types::*;
/// # use naughtyfy::api::*;
/// let fd = fanotify_init(FAN_CLASS_NOTIF, 0).unwrap();
/// fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS, libc::AT_FDCWD, "./");
/// # }
/// ```
pub fn fanotify_mark<P: ?Sized + Path>(
fanotify_fd: i32,
flags: u32,
mask: u64,
dirfd: i32,
path: &P,
) -> Result<(), Error> {
unsafe {
let path = CString::new(path.as_os_str().as_bytes())?;
match libc::fanotify_mark(fanotify_fd, flags, mask, dirfd, path.as_ptr()) {
0 => Ok(()),
_ => Err(Error::last_os_error()),
}
}
}
/// This function ateempts to read from a file descriptor `fanotify_fd`
/// into a `Vec<fanotify_event_metadata>` and return a Result.
///
/// # Argument
/// * `fd` - file descriptor returned by [`fanotify_init()`]
///
/// # Example
/// ```rust
/// # #[should_panic]
/// # fn ex() {
/// # use naughtyfy::flags::*;
/// # use naughtyfy::types::*;
/// # use naughtyfy::api::*;
/// let fd = fanotify_init(FAN_CLASS_NOTIF, 0).unwrap();
/// fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS, libc::AT_FDCWD, "./");
/// let fan_events = fanotify_read(fd);
/// println!("{fan_events:#?}");
/// # }
/// ```
pub fn fanotify_read(fanotify_fd: i32) -> Result<Vec<fanotify_event_metadata>, Error> {
let mut vec = Vec::new();
unsafe {
let buffer = libc::malloc(FAN_EVENT_METADATA_LEN * FAN_EVENT_BUFFER_LEN);
// allocation may fail due to limited memory.
if buffer == libc::PT_NULL as *mut c_void {
return Err(Error::last_os_error());
}
let sizeof = libc::read(
fanotify_fd,
buffer,
FAN_EVENT_METADATA_LEN * FAN_EVENT_BUFFER_LEN,
);
if sizeof != libc::EAGAIN as isize && sizeof > 0 {
let src = slice::from_raw_parts(
buffer as *mut fanotify_event_metadata,
sizeof as usize / FAN_EVENT_METADATA_LEN,
);
vec = src.to_vec();
}
libc::free(buffer);
}
Ok(vec)
}
/// Closes the file descriptor returned by [`fanotify_init()`]
///
/// # Argument
/// * `fd` - `fd` - file descriptor returned by [`fanotify_init()`]
///
/// # Example
/// ```rust
/// # #[should_panic]
/// # fn ex() {
/// # use naughtyfy::flags::*;
/// # use naughtyfy::types::*;
/// # use naughtyfy::api::*;
/// let fd = fanotify_init(FAN_CLASS_NOTIF, 0).unwrap();
/// fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS, libc::AT_FDCWD, "./");
/// let fan_events = fanotify_read(fd);
/// println!("{fan_events:#?}");
///
/// # }
/// ```
pub fn fanotify_close(fd: i32) -> Result<(), Error> {
unsafe {
match libc::close(fd) {
0 => Ok(()),
_ => Err(Error::last_os_error()),
}
}
}