1use std::{
4 ffi::CString,
5 os::fd::{AsFd, FromRawFd, OwnedFd},
6};
7
8use nix::{
9 errno::Errno,
10 libc,
11 unistd::{Gid, Uid, User, dup2, getpid, initgroups, setpgid, setresgid, setresuid, setsid},
12};
13
14pub fn nullify_stdio() -> Result<(), std::io::Error> {
15 let dev_null = std::fs::File::options()
16 .read(true)
17 .write(true)
18 .open("/dev/null")?;
19 let mut stdin = unsafe { OwnedFd::from_raw_fd(0) };
20 let mut stdout = unsafe { OwnedFd::from_raw_fd(1) };
21 let mut stderr = unsafe { OwnedFd::from_raw_fd(2) };
22 dup2(dev_null.as_fd(), &mut stdin)?;
23 dup2(dev_null.as_fd(), &mut stdout)?;
24 dup2(dev_null.as_fd(), &mut stderr)?;
25 std::mem::forget(stdin);
26 std::mem::forget(stdout);
27 std::mem::forget(stderr);
28 Ok(())
29}
30
31pub fn runas(user: &User, effective: Option<(Uid, Gid)>) -> Result<(), Errno> {
32 let (euid, egid) = effective.unwrap_or((user.uid, user.gid));
33 initgroups(&CString::new(user.name.as_str()).unwrap()[..], user.gid)?;
34 setresgid(user.gid, egid, Gid::from_raw(u32::MAX))?;
35 setresuid(user.uid, euid, Uid::from_raw(u32::MAX))?;
36 Ok(())
37}
38
39pub fn lead_process_group() -> Result<(), Errno> {
40 let me = getpid();
41 setpgid(me, me)
42}
43
44pub fn lead_session_and_control_terminal() -> Result<(), Errno> {
45 setsid()?;
46 if unsafe { libc::ioctl(0, libc::TIOCSCTTY as _, 0) } == -1 {
47 Err(Errno::last())?;
48 }
49 Ok(())
50}