Move user-switching functions to their own module

Remove `c_int` from the libc public exports list while I'm at it. This might break someone's code, but it shouldn't have been used from this library anyway (only for user switching functions!)
This commit is contained in:
Ben S
2016-01-26 19:10:48 +00:00
parent 80e0c7d6f2
commit 9dadca8993
3 changed files with 115 additions and 106 deletions
+1 -105
View File
@@ -1,11 +1,9 @@
use std::io::{Error as IOError, Result as IOResult};
use std::ffi::{CStr, CString};
use std::ptr::read;
use std::str::from_utf8_unchecked;
use std::sync::Arc;
use libc::{uid_t, gid_t, c_int};
use libc::{uid_t, gid_t};
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly"))]
use libc::{c_char, time_t};
@@ -59,17 +57,8 @@ extern {
fn getuid() -> uid_t;
fn geteuid() -> uid_t;
fn setuid(uid: uid_t) -> c_int;
fn seteuid(uid: uid_t) -> c_int;
fn getgid() -> gid_t;
fn getegid() -> gid_t;
fn setgid(gid: gid_t) -> c_int;
fn setegid(gid: gid_t) -> c_int;
fn setreuid(ruid: uid_t, euid: uid_t) -> c_int;
fn setregid(rgid: gid_t, egid: gid_t) -> c_int;
}
/// Information about a particular user.
@@ -243,99 +232,6 @@ pub fn get_effective_groupname() -> Option<String> {
get_group_by_gid(gid).map(|g| Arc::try_unwrap(g.name).unwrap())
}
/// Sets current user for the running process, requires root priviledges.
pub fn set_current_uid(uid: uid_t) -> IOResult<()> {
match unsafe { setuid(uid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Set current group for the running process, requires root priviledges.
pub fn set_current_gid(gid: gid_t) -> IOResult<()> {
match unsafe { setgid(gid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Set effective user for the running process, requires root priviledges.
pub fn set_effective_uid(uid: uid_t) -> IOResult<()> {
match unsafe { seteuid(uid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Set effective user for the running process, requires root priviledges.
pub fn set_effective_gid(gid: gid_t) -> IOResult<()> {
match unsafe { setegid(gid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Atomically set current and effective user for the running process, requires root priviledges.
pub fn set_both_uid(ruid: uid_t, euid: uid_t) -> IOResult<()> {
match unsafe { setreuid(ruid, euid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Atomically set current and effective group for the running process, requires root priviledges.
pub fn set_both_gid(rgid: gid_t, egid: gid_t) -> IOResult<()> {
match unsafe { setregid(rgid, egid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
pub struct SwitchUserGuard {
uid: uid_t,
gid: gid_t,
}
impl Drop for SwitchUserGuard {
fn drop(&mut self) {
// Panic on error here, as failing to set values back
// is a possible security breach.
set_effective_uid(self.uid).unwrap();
set_effective_gid(self.gid).unwrap();
}
}
/// Safely switch user and group for the current scope.
/// Requires root access.
///
/// ```ignore
/// {
/// let _guard = switch_user_group(1001, 1001);
/// // current and effective user and group ids are 1001
/// }
/// // back to the old values
/// ```
///
/// Use with care! Possible security issues can happen, as Rust doesn't
/// guarantee running the destructor! If in doubt run `drop()` method
/// on the guard value manually!
pub fn switch_user_group(uid: uid_t, gid: gid_t) -> Result<SwitchUserGuard, IOError> {
let current_state = SwitchUserGuard {
uid: get_effective_uid(),
gid: get_effective_gid(),
};
try!(set_effective_uid(uid));
try!(set_effective_gid(gid));
Ok(current_state)
}
#[cfg(test)]
mod test {
+4 -1
View File
@@ -109,7 +109,7 @@
//! edge cases.
extern crate libc;
pub use libc::{uid_t, gid_t, c_int};
pub use libc::{uid_t, gid_t};
mod base;
pub use base::*;
@@ -118,5 +118,8 @@ pub mod mock;
pub mod os;
pub use os::OSUsers;
pub mod switch;
use switch::*;
mod traits;
pub use traits::{Users, Groups};
+110
View File
@@ -0,0 +1,110 @@
use std::io::{Error as IOError, Result as IOResult};
use libc::{uid_t, gid_t, c_int};
use base::{get_effective_uid, get_effective_gid};
extern {
fn setuid(uid: uid_t) -> c_int;
fn seteuid(uid: uid_t) -> c_int;
fn setgid(gid: gid_t) -> c_int;
fn setegid(gid: gid_t) -> c_int;
fn setreuid(ruid: uid_t, euid: uid_t) -> c_int;
fn setregid(rgid: gid_t, egid: gid_t) -> c_int;
}
/// Sets current user for the running process, requires root priviledges.
pub fn set_current_uid(uid: uid_t) -> IOResult<()> {
match unsafe { setuid(uid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Set current group for the running process, requires root priviledges.
pub fn set_current_gid(gid: gid_t) -> IOResult<()> {
match unsafe { setgid(gid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Set effective user for the running process, requires root priviledges.
pub fn set_effective_uid(uid: uid_t) -> IOResult<()> {
match unsafe { seteuid(uid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Set effective user for the running process, requires root priviledges.
pub fn set_effective_gid(gid: gid_t) -> IOResult<()> {
match unsafe { setegid(gid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Atomically set current and effective user for the running process, requires root priviledges.
pub fn set_both_uid(ruid: uid_t, euid: uid_t) -> IOResult<()> {
match unsafe { setreuid(ruid, euid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
/// Atomically set current and effective group for the running process, requires root priviledges.
pub fn set_both_gid(rgid: gid_t, egid: gid_t) -> IOResult<()> {
match unsafe { setregid(rgid, egid) } {
0 => Ok(()),
-1 => Err(IOError::last_os_error()),
_ => unreachable!()
}
}
pub struct SwitchUserGuard {
uid: uid_t,
gid: gid_t,
}
impl Drop for SwitchUserGuard {
fn drop(&mut self) {
// Panic on error here, as failing to set values back
// is a possible security breach.
set_effective_uid(self.uid).unwrap();
set_effective_gid(self.gid).unwrap();
}
}
/// Safely switch user and group for the current scope.
/// Requires root access.
///
/// ```ignore
/// {
/// let _guard = switch_user_group(1001, 1001);
/// // current and effective user and group ids are 1001
/// }
/// // back to the old values
/// ```
///
/// Use with care! Possible security issues can happen, as Rust doesn't
/// guarantee running the destructor! If in doubt run `drop()` method
/// on the guard value manually!
pub fn switch_user_group(uid: uid_t, gid: gid_t) -> Result<SwitchUserGuard, IOError> {
let current_state = SwitchUserGuard {
uid: get_effective_uid(),
gid: get_effective_gid(),
};
try!(set_effective_uid(uid));
try!(set_effective_gid(gid));
Ok(current_state)
}