extern crate libc;
fn example(guid: u32) {
unsafe {
let ruid = libc::getuid();
libc::seteuid(guid);
let mut v = vec![0; 0];
let num_groups = libc::getgroups(0, v.as_mut_ptr());
let mut groups = Vec::with_capacity(num_groups as usize);
libc::getgroups(num_groups, groups.as_mut_ptr());
println!(
"real user id {} as user id {}, as user groups {:?}, numgroups {}",
&ruid, &guid, &groups, &num_groups
);
}
}
打印
real user id 1000 as user id 1000, as user groups [], numgroups 9
我的假设是它会显示9组的载体。
答案 0 :(得分:2)
您需要通过添加虚拟元素来更改groups
的大小,而不仅仅是其容量。像这样:
unsafe {
let ruid = libc::getuid();
let guid = libc::getgid();
let num_groups = libc::getgroups(0, ::std::ptr::null_mut());
let mut groups = vec![0; num_groups as usize];
libc::getgroups(num_groups, groups.as_mut_ptr());
println!(
"real user id {} as user id {}, as user groups {:?}, numgroups {}",
&ruid, &guid, &groups, &num_groups
);
}
答案 1 :(得分:2)
您的所有代码都没有检查错误! seteuid
和getgroups
可以失败,但您的代码会忽略这种可能性。您正在尝试调试失败,但甚至没有花时间检查您正在调用的函数是否成功。
在传递v.as_mut_ptr()
时要非常小心。空Vec
不有空指针。在这种情况下它很好,因为手册页说它只关心计数。
您不会处理第一次和第二次通话之间小组数量发生变化的情况。
You don't need to pass in references to the println
arguments
有了这个,因为你只在u32
中存储Vec
,你可以通过相应地调整大小和容量来避免用虚拟值填充它:
extern crate libc;
#[derive(Debug)]
struct Info {
guid: u32,
ruid: u32,
groups: Vec<u32>,
num_groups: usize,
}
fn example(guid: u32) -> Info {
unsafe {
let ruid = libc::getuid();
if -1 == libc::seteuid(guid) {
panic!("seteuid")
}
let mut groups = Vec::new();
let mut attempts = 0;
loop {
let num_groups = libc::getgroups(groups.capacity() as i32, groups.as_mut_ptr());
if -1 == num_groups {
panic!("getgroups")
}
let num_groups = num_groups as usize;
if num_groups <= groups.capacity() {
groups.set_len(num_groups);
return Info {
guid,
ruid,
groups,
num_groups,
};
}
groups.reserve_exact(num_groups);
attempts += 1;
if attempts >= 3 {
panic!("Unstable amount of groups")
}
}
}
}
fn main() {
println!("{:?}", example(unsafe { libc::getuid() }));
}
但是,我不会重写所有这些,我会依赖现有的工作。 nix crate提供了很好的包装器:
extern crate nix;
use nix::unistd::{self, Uid};
use std::u32;
fn example(guid: Uid) -> nix::Result<()> {
let ruid = unistd::getuid();
let no_change = Uid::from_raw(u32::MAX);
unistd::setresuid(no_change, guid, no_change)?;
let groups = nix::unistd::getgroups()?;
println!(
"real user id {} as user id {}, as user groups {:?}",
ruid, guid, groups
);
Ok(())
}
fn main() {
println!("{:?}", example(Uid::current()));
}