代码之家  ›  专栏  ›  技术社区  ›  user1685095

如何通过libc::get groups为用户获取组?

  •  0
  • user1685095  · 技术社区  · 6 年前
    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个组的向量。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Shepmaster Tim Diekmann    6 年前

    你需要改变 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
        );
    }
    
        2
  •  2
  •   Shepmaster Tim Diekmann    6 年前
    • 没有一个代码检查错误! 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()));
    }