Skip to content

Commit

Permalink
Implement a bunch of FreeBSD things (#900)
Browse files Browse the repository at this point in the history
  • Loading branch information
squell authored Nov 4, 2024
2 parents 1f63cac + c21d6ad commit 8c5b040
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 6 deletions.
3 changes: 3 additions & 0 deletions src/pam/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ mod securemem;
#[allow(nonstandard_style)]
pub mod sys;

#[cfg(target_os = "freebsd")]
const PAM_DATA_SILENT: std::ffi::c_int = 0;

pub use converse::{CLIConverser, Converser};

pub struct PamContext<C: Converser> {
Expand Down
24 changes: 24 additions & 0 deletions src/sudo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,28 @@ mod env;
mod pam;
mod pipeline;

/// show warning message when SUDO_RS_IS_UNSTABLE is not set to the appropriate value
fn unstable_warning() {
if cfg!(target_os = "linux") {
return;
}

let check_var = std::env::var("SUDO_RS_IS_UNSTABLE").unwrap_or_else(|_| "".to_string());

if check_var != "I accept that my system may break unexpectedly" {
eprintln_ignore_io_error!(
"WARNING!
Sudo-rs is in the early stages of supporting OSes other than Linux and could potentially
break your system. We recommend that you do not run this on any production environment.
To turn off this warning and start using sudo-rs set the environment variable
SUDO_RS_IS_UNSTABLE to the value `I accept that my system may break unexpectedly`. If
you are unsure how to do this then this software is not suited for you at this time."
);

std::process::exit(1);
}
}

const VERSION: &str = std::env!("CARGO_PKG_VERSION");

pub(crate) fn candidate_sudoers_file() -> &'static Path {
Expand Down Expand Up @@ -127,6 +149,8 @@ fn sudo_process() -> Result<(), Error> {
eprintln_ignore_io_error!("{}", help::USAGE_MSG);
std::process::exit(1);
} else {
unstable_warning();

pipeline.run(options)
}
}
Expand Down
121 changes: 119 additions & 2 deletions src/system/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::fmt;
// TODO: remove unused attribute when system is cleaned up
#[cfg(target_os = "linux")]
use std::str::FromStr;
use std::{
collections::BTreeSet,
ffi::{c_uint, CStr, CString},
Expand All @@ -11,7 +13,6 @@ use std::{
unix::{self, prelude::OsStrExt},
},
path::{Path, PathBuf},
str::FromStr,
};

use crate::{
Expand Down Expand Up @@ -279,7 +280,7 @@ pub fn set_target_user(
unsafe {
cmd.pre_exec(move || {
cerr(libc::setgroups(
target_user.groups.len(),
target_user.groups.len() as _,
// We can cast to gid_t because `GroupId` is marked as transparent
target_user.groups.as_ptr().cast::<libc::gid_t>(),
))?;
Expand Down Expand Up @@ -562,6 +563,7 @@ pub enum WithProcess {
}

impl WithProcess {
#[cfg(target_os = "linux")]
fn to_proc_string(&self) -> String {
match self {
WithProcess::Current => "self".into(),
Expand Down Expand Up @@ -620,6 +622,7 @@ impl Process {

/// Returns the device identifier of the TTY device that is currently
/// attached to the given process
#[cfg(target_os = "linux")]
pub fn tty_device_id(pid: WithProcess) -> std::io::Result<Option<DeviceId>> {
// device id of tty is displayed as a signed integer of 32 bits
let data: i32 = read_proc_stat(pid, 6 /* tty_nr */)?;
Expand All @@ -635,7 +638,66 @@ impl Process {
}
}

/// Returns the device identifier of the TTY device that is currently
/// attached to the given process
#[cfg(target_os = "freebsd")]
pub fn tty_device_id(pid: WithProcess) -> std::io::Result<Option<DeviceId>> {
use std::ffi::c_void;
use std::ptr;

let mut ki_proc: Vec<libc::kinfo_proc> = Vec::with_capacity(1);

let pid = match pid {
WithProcess::Current => std::process::id() as i32,
WithProcess::Other(pid) => pid.inner(),
};

loop {
let mut size = ki_proc.capacity() * size_of::<libc::kinfo_proc>();
match cerr(unsafe {
libc::sysctl(
[
libc::CTL_KERN,
libc::KERN_PROC,
libc::KERN_PROC_PID,
pid,
size_of::<libc::kinfo_proc>() as i32,
1,
]
.as_ptr(),
4,
ki_proc.as_mut_ptr().cast::<c_void>(),
&mut size,
ptr::null(),
0,
)
}) {
Ok(_) => {
assert!(size >= size_of::<libc::kinfo_proc>());
// SAFETY: The above sysctl has initialized at least `size` bytes. We have
// asserted that this is at least a single element.
unsafe {
ki_proc.set_len(1);
}
break;
}
Err(e) if e.raw_os_error() == Some(libc::ENOMEM) => {
// Vector not big enough. Grow it by 10% and try again.
ki_proc.reserve(ki_proc.capacity() + (ki_proc.capacity() + 9) / 10);
}
Err(e) => return Err(e),
}
}

if ki_proc[0].ki_tdev == !0 {
Ok(None)
} else {
Ok(Some(DeviceId::new(ki_proc[0].ki_tdev)))
}
}

/// Get the process starting time of a specific process
#[cfg(target_os = "linux")]
pub fn starting_time(pid: WithProcess) -> io::Result<SystemTime> {
let process_start: u64 = read_proc_stat(pid, 21 /* start_time */)?;

Expand All @@ -654,6 +716,60 @@ impl Process {
((process_start % ticks_per_second) * (1_000_000_000 / ticks_per_second)) as i64,
))
}

/// Get the process starting time of a specific process
#[cfg(target_os = "freebsd")]
pub fn starting_time(pid: WithProcess) -> io::Result<SystemTime> {
use std::ffi::c_void;
use std::ptr;

let mut ki_proc: Vec<libc::kinfo_proc> = Vec::with_capacity(1);

let pid = match pid {
WithProcess::Current => std::process::id() as i32,
WithProcess::Other(pid) => pid.inner(),
};

loop {
let mut size = ki_proc.capacity() * size_of::<libc::kinfo_proc>();
match cerr(unsafe {
libc::sysctl(
[
libc::CTL_KERN,
libc::KERN_PROC,
libc::KERN_PROC_PID,
pid,
size_of::<libc::kinfo_proc>() as i32,
1,
]
.as_ptr(),
4,
ki_proc.as_mut_ptr().cast::<c_void>(),
&mut size,
ptr::null(),
0,
)
}) {
Ok(_) => {
assert!(size >= size_of::<libc::kinfo_proc>());
// SAFETY: The above sysctl has initialized at least `size` bytes. We have
// asserted that this is at least a single element.
unsafe {
ki_proc.set_len(1);
}
break;
}
Err(e) if e.raw_os_error() == Some(libc::ENOMEM) => {
// Vector not big enough. Grow it by 10% and try again.
ki_proc.reserve(ki_proc.capacity() + (ki_proc.capacity() + 9) / 10);
}
Err(e) => return Err(e),
}
}

let ki_start = ki_proc[0].ki_start;
Ok(SystemTime::new(ki_start.tv_sec, ki_start.tv_usec * 1000))
}
}

/// Read the n-th field (with 0-based indexing) from `/proc/<pid>/self`.
Expand All @@ -664,6 +780,7 @@ impl Process {
/// IMPORTANT: the first two fields are not accessible with this routine.
///
/// [proc_stat_fields]: https://www.kernel.org/doc/html/latest/filesystems/proc.html#id10
#[cfg(target_os = "linux")]
fn read_proc_stat<T: FromStr>(pid: WithProcess, field_idx: isize) -> io::Result<T> {
// the first two fields are skipped by the code below, and we never need them,
// so no point in implementing code for it in this private function.
Expand Down
13 changes: 10 additions & 3 deletions src/system/term/user_term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ use libc::{
c_void, cfgetispeed, cfgetospeed, cfmakeraw, cfsetispeed, cfsetospeed, ioctl, sigaction,
sigemptyset, sighandler_t, siginfo_t, sigset_t, tcflag_t, tcgetattr, tcsetattr, termios,
winsize, CS7, CS8, ECHO, ECHOCTL, ECHOE, ECHOK, ECHOKE, ECHONL, ICANON, ICRNL, IEXTEN, IGNCR,
IGNPAR, IMAXBEL, INLCR, INPCK, ISIG, ISTRIP, IUTF8, IXANY, IXOFF, IXON, NOFLSH, OCRNL, OLCUC,
ONLCR, ONLRET, ONOCR, OPOST, PARENB, PARMRK, PARODD, PENDIN, SIGTTOU, TCSADRAIN, TCSAFLUSH,
TIOCGWINSZ, TIOCSWINSZ, TOSTOP,
IGNPAR, IMAXBEL, INLCR, INPCK, ISIG, ISTRIP, IXANY, IXOFF, IXON, NOFLSH, OCRNL, ONLCR, ONLRET,
ONOCR, OPOST, PARENB, PARMRK, PARODD, PENDIN, SIGTTOU, TCSADRAIN, TCSAFLUSH, TIOCGWINSZ,
TIOCSWINSZ, TOSTOP,
};
#[cfg(target_os = "linux")]
use libc::{IUTF8, OLCUC};

#[cfg(not(target_os = "linux"))]
const IUTF8: libc::tcflag_t = 0;
#[cfg(not(target_os = "linux"))]
const OLCUC: libc::tcflag_t = 0;

use super::{TermSize, Terminal};
use crate::{
Expand Down
13 changes: 12 additions & 1 deletion src/system/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ use std::{
ops::{Add, Sub},
};

/// A timestamp relative to `CLOCK_BOOTTIME` on most systems.
///
/// On FreeBSD it is relative to `CLOCK_REALTIME` as that is what the kernel uses for the start time
/// of processes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SystemTime {
secs: i64,
Expand All @@ -22,7 +26,14 @@ impl SystemTime {
let mut spec = MaybeUninit::<libc::timespec>::uninit();
// SAFETY: valid pointer is passed to clock_gettime
crate::cutils::cerr(unsafe {
libc::clock_gettime(libc::CLOCK_BOOTTIME, spec.as_mut_ptr())
libc::clock_gettime(
if cfg!(target_os = "freebsd") {
libc::CLOCK_REALTIME
} else {
libc::CLOCK_BOOTTIME
},
spec.as_mut_ptr(),
)
})?;
// SAFETY: The `libc::clock_gettime` will correctly initialize `spec`,
// otherwise it will return early with the `?` operator.
Expand Down

0 comments on commit 8c5b040

Please sign in to comment.