diff --git a/src/uucore/src/lib/features/entries.rs b/src/uucore/src/lib/features/entries.rs index bc4166346..6b986e616 100644 --- a/src/uucore/src/lib/features/entries.rs +++ b/src/uucore/src/lib/features/entries.rs @@ -47,6 +47,9 @@ use std::io::Result as IOResult; use std::ptr; extern "C" { + /// From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html + /// > The getgrouplist() function scans the group database to obtain + /// > the list of groups that user belongs to. fn getgrouplist( name: *const c_char, gid: gid_t, @@ -55,6 +58,13 @@ extern "C" { ) -> c_int; } +/// From: https://man7.org/linux/man-pages/man2/getgroups.2.html +/// > getgroups() returns the supplementary group IDs of the calling +/// > process in list. +/// > If size is zero, list is not modified, but the total number of +/// > supplementary group IDs for the process is returned. This allows +/// > the caller to determine the size of a dynamically allocated list +/// > to be used in a further call to getgroups(). pub fn get_groups() -> IOResult> { let ngroups = unsafe { getgroups(0, ptr::null_mut()) }; if ngroups == -1 { @@ -83,17 +93,17 @@ pub fn get_groups() -> IOResult> { /// for `id --groups --real` if `gid` and `egid` are not equal. /// /// From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html -/// As implied by the definition of supplementary groups, the -/// effective group ID may appear in the array returned by -/// getgroups() or it may be returned only by getegid(). Duplication -/// may exist, but the application needs to call getegid() to be sure -/// of getting all of the information. Various implementation -/// variations and administrative sequences cause the set of groups -/// appearing in the result of getgroups() to vary in order and as to -/// whether the effective group ID is included, even when the set of -/// groups is the same (in the mathematical sense of ``set''). (The -/// history of a process and its parents could affect the details of -/// the result.) +/// > As implied by the definition of supplementary groups, the +/// > effective group ID may appear in the array returned by +/// > getgroups() or it may be returned only by getegid(). Duplication +/// > may exist, but the application needs to call getegid() to be sure +/// > of getting all of the information. Various implementation +/// > variations and administrative sequences cause the set of groups +/// > appearing in the result of getgroups() to vary in order and as to +/// > whether the effective group ID is included, even when the set of +/// > groups is the same (in the mathematical sense of ``set''). (The +/// > history of a process and its parents could affect the details of +/// > the result.) #[cfg(all(unix, feature = "process"))] pub fn get_groups_gnu(arg_id: Option) -> IOResult> { let groups = get_groups()?; @@ -184,16 +194,38 @@ impl Passwd { self.inner } + /// This is a wrapper function for `libc::getgrouplist`. + /// + /// From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html + /// > If the number of groups of which user is a member is less than or + /// > equal to *ngroups, then the value *ngroups is returned. + /// > If the user is a member of more than *ngroups groups, then + /// > getgrouplist() returns -1. In this case, the value returned in + /// > *ngroups can be used to resize the buffer passed to a further + /// > call getgrouplist(). + /// + /// However, on macOS/darwin (and maybe others?) `getgrouplist` does + /// not update `ngroups` if `ngroups` is too small. Therefore, if not + /// updated by `getgrouplist`, `ngroups` needs to be increased in a + /// loop until `getgrouplist` stops returning -1. pub fn belongs_to(&self) -> Vec { let mut ngroups: c_int = 8; + let mut ngroups_old: c_int; let mut groups = Vec::with_capacity(ngroups as usize); let gid = self.inner.pw_gid; let name = self.inner.pw_name; - unsafe { - if getgrouplist(name, gid, groups.as_mut_ptr(), &mut ngroups) == -1 { + loop { + ngroups_old = ngroups; + if unsafe { getgrouplist(name, gid, groups.as_mut_ptr(), &mut ngroups) } == -1 { + if ngroups == ngroups_old { + ngroups *= 2; + } groups.resize(ngroups as usize, 0); - getgrouplist(name, gid, groups.as_mut_ptr(), &mut ngroups); + } else { + break; } + } + unsafe { groups.set_len(ngroups as usize); } groups.truncate(ngroups as usize); diff --git a/src/uucore/src/lib/features/process.rs b/src/uucore/src/lib/features/process.rs index cda41bb4f..21bfa992c 100644 --- a/src/uucore/src/lib/features/process.rs +++ b/src/uucore/src/lib/features/process.rs @@ -17,18 +17,22 @@ use std::process::ExitStatus as StdExitStatus; use std::thread; use std::time::{Duration, Instant}; +/// `geteuid()` returns the effective user ID of the calling process. pub fn geteuid() -> uid_t { unsafe { libc::geteuid() } } +/// `getegid()` returns the effective group ID of the calling process. pub fn getegid() -> gid_t { unsafe { libc::getegid() } } +/// `getgid()` returns the real group ID of the calling process. pub fn getgid() -> gid_t { unsafe { libc::getgid() } } +/// `getuid()` returns the real user ID of the calling process. pub fn getuid() -> uid_t { unsafe { libc::getuid() } }