mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-30 04:19:20 +00:00
sys_util: add get_user_id and get_group_id functions
Add safe wrappers for getpwnam_r and getgrnam_r. BUG=none TEST=./build_test Change-Id: I737b4d264334ed788884a7320f5649cfc2266709 Reviewed-on: https://chromium-review.googlesource.com/733730 Commit-Ready: Stephen Barber <smbarber@chromium.org> Tested-by: Stephen Barber <smbarber@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
7a2fec4596
commit
5bf651c0e4
2 changed files with 121 additions and 0 deletions
|
@ -28,6 +28,7 @@ mod signal;
|
|||
mod fork;
|
||||
mod signalfd;
|
||||
mod sock_ctrl_msg;
|
||||
mod passwd;
|
||||
|
||||
pub use mmap::*;
|
||||
pub use shm::*;
|
||||
|
@ -45,6 +46,7 @@ pub use fork::*;
|
|||
pub use signalfd::*;
|
||||
pub use ioctl::*;
|
||||
pub use sock_ctrl_msg::*;
|
||||
pub use passwd::*;
|
||||
|
||||
pub use mmap::Error as MmapError;
|
||||
pub use guest_memory::Error as GuestMemoryError;
|
||||
|
|
119
sys_util/src/passwd.rs
Normal file
119
sys_util/src/passwd.rs
Normal file
|
@ -0,0 +1,119 @@
|
|||
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
//! Wrappers for passwd and group file access.
|
||||
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use libc;
|
||||
use libc::{c_char, gid_t, uid_t, getgrnam_r, getpwnam_r};
|
||||
|
||||
use {Result, errno_result};
|
||||
|
||||
/// Safe wrapper for getting a uid from a user name with `getpwnam_r(3)`.
|
||||
#[inline(always)]
|
||||
pub fn get_user_id(user_name: &CStr) -> Result<uid_t> {
|
||||
// libc::passwd is a C struct and can be safely initialized with zeroed memory.
|
||||
let mut passwd: libc::passwd = unsafe { mem::zeroed() };
|
||||
let mut passwd_result: *mut libc::passwd = ptr::null_mut();
|
||||
let mut buf = [0 as c_char; 256];
|
||||
|
||||
// For thread-safety, use the reentrant version of this function. This allows us to give it a
|
||||
// buffer on the stack (instead of a global buffer). Unlike most libc functions, the return
|
||||
// value of this doesn't really need to be checked, since the extra result pointer that is
|
||||
// passed in indicates whether or not the function succeeded.
|
||||
//
|
||||
// This call is safe as long as it behaves as described in the man page. We pass in valid
|
||||
// pointers to stack-allocated buffers, and the length check for the scratch buffer is correct.
|
||||
unsafe {
|
||||
handle_eintr!(getpwnam_r(user_name.as_ptr(),
|
||||
&mut passwd,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len(),
|
||||
&mut passwd_result))
|
||||
};
|
||||
|
||||
if passwd_result.is_null() {
|
||||
errno_result()
|
||||
} else {
|
||||
Ok(passwd.pw_uid)
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe wrapper for getting a gid from a group name with `getgrnam_r(3)`.
|
||||
#[inline(always)]
|
||||
pub fn get_group_id(group_name: &CStr) -> Result<gid_t> {
|
||||
// libc::group is a C struct and can be safely initialized with zeroed memory.
|
||||
let mut group: libc::group = unsafe { mem::zeroed() };
|
||||
let mut group_result: *mut libc::group = ptr::null_mut();
|
||||
let mut buf = [0 as c_char; 256];
|
||||
|
||||
// For thread-safety, use the reentrant version of this function. This allows us to give it a
|
||||
// buffer on the stack (instead of a global buffer). Unlike most libc functions, the return
|
||||
// value of this doesn't really need to be checked, since the extra result pointer that is
|
||||
// passed in indicates whether or not the function succeeded.
|
||||
//
|
||||
// This call is safe as long as it behaves as described in the man page. We pass in valid
|
||||
// pointers to stack-allocated buffers, and the length check for the scratch buffer is correct.
|
||||
unsafe {
|
||||
handle_eintr!(getgrnam_r(group_name.as_ptr(),
|
||||
&mut group,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len(),
|
||||
&mut group_result))
|
||||
};
|
||||
|
||||
if group_result.is_null() {
|
||||
errno_result()
|
||||
} else {
|
||||
Ok(group.gr_gid)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn get_good_uid() {
|
||||
let root_name = CStr::from_bytes_with_nul(b"root\0").unwrap();
|
||||
|
||||
// root's uid should always exist, and should be 0.
|
||||
let root_uid = get_user_id(root_name).unwrap();
|
||||
assert_eq!(root_uid, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_bad_uid() {
|
||||
let bad_name = CStr::from_bytes_with_nul(b"this better not be a user\0").unwrap();
|
||||
|
||||
// This user should give us an error. As a cruel joke, the getpwnam(3) man page allows
|
||||
// ENOENT, ESRCH, EBADF, EPERM, or even 0 to be set in errno if a user isn't found. So
|
||||
// instead of checking which error we got, just see that we did get one.
|
||||
let bad_uid_result = get_user_id(bad_name);
|
||||
assert!(bad_uid_result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_good_gid() {
|
||||
let root_name = CStr::from_bytes_with_nul(b"root\0").unwrap();
|
||||
|
||||
// root's gid should always exist, and should be 0.
|
||||
let root_gid = get_group_id(root_name).unwrap();
|
||||
assert_eq!(root_gid, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_bad_gid() {
|
||||
let bad_name = CStr::from_bytes_with_nul(b"this better not be a group\0").unwrap();
|
||||
|
||||
// This group should give us an error. As a cruel joke, the getgrnam(3) man page allows
|
||||
// ENOENT, ESRCH, EBADF, EPERM, or even 0 to be set in errno if a group isn't found. So
|
||||
// instead of checking which error we got, just see that we did get one.
|
||||
let bad_gid_result = get_group_id(bad_name);
|
||||
assert!(bad_gid_result.is_err());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue