Skip to content

Commit e62b885

Browse files
committed
unistd: Add setgroups()
1 parent 1478e71 commit e62b885

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

src/unistd.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,51 @@ pub fn setgid(gid: Gid) -> Result<()> {
982982
Errno::result(res).map(drop)
983983
}
984984

985+
/// Set the list of supplementary group IDs for the calling process.
986+
///
987+
/// *Note:* On macOS, `getgroups()` may not return the same group list set by
988+
/// calling `setgroups()`. The use of `setgroups()` on macOS is 'highly
989+
/// discouraged' by Apple. Developers are referred to the `opendirectoryd`
990+
/// daemon and its set of APIs.
991+
///
992+
/// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html)
993+
///
994+
/// # Examples
995+
///
996+
/// `setgroups` can be used when dropping privileges from the root user to a
997+
/// specific user and group. For example, given the user `www-data` with UID
998+
/// `33` and the group `backup` with the GID `34`, one could switch user as
999+
/// follows:
1000+
/// ```
1001+
/// let uid = Uid::from_raw(33);
1002+
/// let gid = Gid::from_raw(34);
1003+
/// setgroups(&[gid])?;
1004+
/// setgid(gid)?;
1005+
/// setuid(uid)?;
1006+
/// ```
1007+
pub fn setgroups(groups: &[Gid]) -> Result<()> {
1008+
cfg_if! {
1009+
if #[cfg(any(target_os = "dragonfly",
1010+
target_os = "freebsd",
1011+
target_os = "ios",
1012+
target_os = "macos",
1013+
target_os = "netbsd",
1014+
target_os = "openbsd"))] {
1015+
type setgroups_ngroups_t = c_int;
1016+
} else {
1017+
type setgroups_ngroups_t = size_t;
1018+
}
1019+
}
1020+
// FIXME: On the platforms we currently support, the `Gid` struct has the
1021+
// same representation in memory as a bare `gid_t`. This is not necessarily
1022+
// the case on all Rust platforms, though. See RFC 1785.
1023+
let res = unsafe {
1024+
libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
1025+
};
1026+
1027+
Errno::result(res).map(|_| ())
1028+
}
1029+
9851030
#[inline]
9861031
pub fn pause() -> Result<()> {
9871032
let res = unsafe { libc::pause() };

0 commit comments

Comments
 (0)