Skip to content

Commit

Permalink
users: drop the users crate
Browse files Browse the repository at this point in the history
Fixes #1
  • Loading branch information
fabianfreyer committed Dec 23, 2018
1 parent 37cfcb8 commit 24a017c
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 13 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased] - ReleaseDate
### Changed
- Dropped the `users` crate and fixed erroneous user lookups
([Issue](https://github.com/fubarnetes/rctl/pull/5),
[PR](https://github.com/fubarnetes/rctl/pull/5))

## [0.0.5] - 2018-12-20
### Added
- This Changelog
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,3 @@ libc = "0.2"
nix = "0.11"
number_prefix = "0.2"
sysctl = "0.2"
users = "0.7"
95 changes: 83 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ extern crate libc;
extern crate nix;
extern crate number_prefix;
extern crate sysctl;
extern crate users;

pub use nix::sys::signal::Signal;
use number_prefix::{binary_prefix, Prefix, Prefixed, Standalone};
Expand Down Expand Up @@ -89,6 +88,12 @@ pub enum ParseError {

#[fail(display = "Invalid Rule syntax: '{}'", _0)]
InvalidRuleSyntax(String),

#[fail(
display = "An interior Nul byte was found while attempting to construct a CString: {}",
_0
)]
CStringError(#[cause] NulError),
}

#[derive(Debug, Fail)]
Expand Down Expand Up @@ -117,33 +122,80 @@ mod subject {
use super::ParseError;
use libc;
use std::fmt;
use users;
use users::{get_user_by_name, get_user_by_uid};

/// Represents a user subject
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct User(pub users::uid_t);
pub struct User(pub libc::uid_t);

impl User {
pub fn from_uid(uid: libc::uid_t) -> User {
User(uid as users::uid_t)
User(uid)
}

pub fn from_name(name: &str) -> Result<User, ParseError> {
let uid = get_user_by_name(name)
.ok_or_else(|| ParseError::UnknownUser(name.into()))?
.uid();
// From getpwent(3):
//
// The functions getpwent_r(), getpwnam_r(), and getpwuid_r()
// are thread-safe versions of getpwent(), getpwnam(), and
// getpwuid(), respectively.
//
// The caller must provide storage for the results of the search in
// the pwd, buffer, bufsize, and result arguments.
let c_name = std::ffi::CString::new(name).map_err(ParseError::CStringError)?;
let mut passwd: libc::passwd = unsafe { std::mem::zeroed() };
const PWBUFLEN: usize = 2048;
let mut buf: Vec<libc::c_char> = vec![0; PWBUFLEN];
let mut result: *mut libc::passwd = std::ptr::null_mut();

unsafe {
libc::getpwnam_r(
c_name.as_ptr(),
&mut passwd,
buf.as_mut_ptr(),
buf.len(),
&mut result,
);
}

// If an entry is not found or an error occurs, result will be set
// to NULL.
if result.is_null() {
return Err(ParseError::UnknownUser(name.into()));
}

Ok(User::from_uid(uid))
// When these functions are successful, the pwd argument will be
// filled-in, and a pointer to that argument will be stored in
// result.
assert_eq!(result, &mut passwd as *mut libc::passwd);
Ok(User::from_uid(passwd.pw_uid))
}
}

impl fmt::Display for User {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match get_user_by_uid(self.0) {
Some(user) => write!(f, "user:{}", user.name()),
None => write!(f, "user:{}", self.0),
let mut passwd: libc::passwd = unsafe { std::mem::zeroed() };
const PWBUFLEN: usize = 2048;
let mut buf: Vec<libc::c_char> = vec![0; PWBUFLEN];
let mut result: *mut libc::passwd = std::ptr::null_mut();

unsafe {
libc::getpwuid_r(
self.0,
&mut passwd,
buf.as_mut_ptr(),
buf.len(),
&mut result,
);
}

// If an entry is not found or an error occurs, result will be set
// to NULL.
if result.is_null() {
return write!(f, "user:{}", self.0);
}

let name = unsafe { std::ffi::CStr::from_ptr(passwd.pw_name) };
write!(f, "user:{}", name.to_string_lossy())
}
}

Expand Down Expand Up @@ -204,6 +256,7 @@ mod subject {
#[cfg(test)]
mod tests {
use super::*;
use std::process::Command;

#[test]
fn display_jail_name() {
Expand All @@ -230,6 +283,24 @@ mod subject {
"loginclass:test".to_string()
);
}

#[test]
fn from_name() {
let nobody = User::from_name("nobody").expect("no nobody user");

// Get the UID using the `getent` command.
let uid_nobody = Command::new("id")
.args(&["-u", "nobody"])
.output()
.expect("failed to run `id -u nobody`");

let uid_nobody: libc::uid_t = String::from_utf8_lossy(&uid_nobody.stdout)
.trim()
.parse()
.expect("Could not parse UID");

assert_eq!(User::from_uid(uid_nobody), nobody);
}
}
}

Expand Down

0 comments on commit 24a017c

Please sign in to comment.