diff options
-rw-r--r-- | src/unistd.rs | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/src/unistd.rs b/src/unistd.rs index 42c6d583..28220e5d 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -464,7 +464,7 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { /// fn main() { /// let tmp_dir = TempDir::new("test_fifo").unwrap(); /// let fifo_path = tmp_dir.path().join("foo.pipe"); -/// +/// /// // create new fifo and give read, write and execute rights to the owner /// match unistd::mkfifo(&fifo_path, stat::S_IRWXU) { /// Ok(_) => println!("created {:?}", fifo_path), @@ -1047,6 +1047,51 @@ pub fn setgid(gid: Gid) -> Result<()> { Errno::result(res).map(drop) } +/// Set the list of supplementary group IDs for the calling process. +/// +/// *Note:* On macOS, `getgroups()` may not return the same group list set by +/// calling `setgroups()`. The use of `setgroups()` on macOS is 'highly +/// discouraged' by Apple. Developers are referred to the `opendirectoryd` +/// daemon and its set of APIs. +/// +/// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html) +/// +/// # Examples +/// +/// `setgroups` can be used when dropping privileges from the root user to a +/// specific user and group. For example, given the user `www-data` with UID +/// `33` and the group `backup` with the GID `34`, one could switch user as +/// follows: +/// ``` +/// let uid = Uid::from_raw(33); +/// let gid = Gid::from_raw(34); +/// setgroups(&[gid])?; +/// setgid(gid)?; +/// setuid(uid)?; +/// ``` +pub fn setgroups(groups: &[Gid]) -> Result<()> { + cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd"))] { + type setgroups_ngroups_t = c_int; + } else { + type setgroups_ngroups_t = size_t; + } + } + // FIXME: On the platforms we currently support, the `Gid` struct has the + // same representation in memory as a bare `gid_t`. This is not necessarily + // the case on all Rust platforms, though. See RFC 1785. + let res = unsafe { + libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t) + }; + + Errno::result(res).map(|_| ()) +} + /// Suspend the thread until a signal is received /// /// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html) |