diff options
Diffstat (limited to 'src/util/unix.rs')
-rw-r--r-- | src/util/unix.rs | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/src/util/unix.rs b/src/util/unix.rs new file mode 100644 index 0000000..ee0507c --- /dev/null +++ b/src/util/unix.rs @@ -0,0 +1,65 @@ +use std::{fs::File, io::Result, os::unix::prelude::AsRawFd, path::Path}; + +use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode, unistd}; + +use super::ToIOResult; + +pub struct SetEUID(unistd::Uid); + +impl Drop for SetEUID { + fn drop(&mut self) { + unistd::seteuid(self.0).expect("failed to reset effective UID"); + } +} + +pub fn seteuid(uid: unistd::Uid) -> Result<SetEUID> { + let old_uid = unistd::geteuid(); + unistd::seteuid(uid).to_io_result()?; + Ok(SetEUID(old_uid)) +} + +pub struct SetEGID(unistd::Gid); + +impl Drop for SetEGID { + fn drop(&mut self) { + unistd::setegid(self.0).expect("failed to reset effective GID"); + } +} + +pub fn setegid(gid: unistd::Gid) -> Result<SetEGID> { + let old_gid = unistd::getegid(); + unistd::setegid(gid).to_io_result()?; + Ok(SetEGID(old_gid)) +} + +pub fn create_as<P: AsRef<Path>>( + path: P, + uid: Option<unistd::Uid>, + gid: Option<unistd::Gid>, +) -> Result<File> { + let _setegid = gid.map(setegid).transpose()?; + let _seteuid = uid.map(seteuid).transpose()?; + + File::create(path) +} + +pub struct Chdir(Dir); + +impl Drop for Chdir { + fn drop(&mut self) { + unistd::fchdir(self.0.as_raw_fd()).expect("failed to revert directory change"); + } +} + +pub fn chdir<P: AsRef<Path>>(path: P) -> Result<Chdir> { + let dir = Dir::open( + ".", + OFlag::O_PATH | OFlag::O_CLOEXEC | OFlag::O_NOFOLLOW, + Mode::empty(), + ) + .to_io_result()?; + + unistd::chdir(path.as_ref()).to_io_result()?; + + Ok(Chdir(dir)) +} |