summaryrefslogtreecommitdiffstats
path: root/src/util/unix.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/unix.rs')
-rw-r--r--src/util/unix.rs65
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))
+}