diff --git a/src/unistd.rs b/src/unistd.rs index 8995fbe02e..6af218f0be 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3228,16 +3228,23 @@ mod setres { /// * returns: Ok or libc error code. /// /// Err is returned if the user doesn't have permission to set this UID. + /// + /// If one of the arguments equals None, the corresponding value is not changed. #[inline] - pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> { + pub fn setresuid(ruid: Option, euid: Option, suid: Option) -> Result<()> { + let ruid = ruid.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1)); + let euid = euid.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1)); + let suid = suid.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1)); let res = - unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) }; + unsafe { libc::setresuid(ruid, euid, suid) }; Errno::result(res).map(drop) } /// Sets the real, effective, and saved gid. - /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html)) + /// + /// If one of the arguments equals None, the corresponding value is not changed. + /// ([see setresgid(2)](https://man7.org/linux/man-pages/man2/setresgid.2.html)) /// /// * `rgid`: real group id /// * `egid`: effective group id @@ -3246,9 +3253,12 @@ mod setres { /// /// Err is returned if the user doesn't have permission to set this GID. #[inline] - pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> { + pub fn setresgid(rgid: Option, egid: Option, sgid: Option) -> Result<()> { + let rgid = rgid.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1)); + let egid = egid.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1)); + let sgid = sgid.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1)); let res = - unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) }; + unsafe { libc::setresgid(rgid, egid, sgid) }; Errno::result(res).map(drop) } diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 6037bb7a02..bcb36da664 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1430,3 +1430,40 @@ fn test_group_from() { assert_eq!(group.gid, group_id); assert_eq!(group.name, "wheel"); } + +// Tests for PR #1305: setresuid/setresgid with Option support +#[test] +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] +fn test_setresuid_with_option() { + let uid = getuid(); + + // Test 1: Set all to current values + assert!(setresuid(Some(uid), Some(uid), Some(uid)).is_ok()); + assert_eq!(geteuid(), uid); + + // Test 2: No-change (None for all) + let euid_before = geteuid(); + assert!(setresuid(None, None, None).is_ok()); + assert_eq!(geteuid(), euid_before, "UID should not change with None"); + + // Test 3: Selective change (only effective) + assert!(setresuid(None, Some(uid), None).is_ok()); +} + +#[test] +#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))] +fn test_setresgid_with_option() { + let gid = getgid(); + + // Test 1: Set all to current values + assert!(setresgid(Some(gid), Some(gid), Some(gid)).is_ok()); + assert_eq!(getegid(), gid); + + // Test 2: No-change (None for all) + let egid_before = getegid(); + assert!(setresgid(None, None, None).is_ok()); + assert_eq!(getegid(), egid_before, "GID should not change with None"); + + // Test 3: Selective change (only effective) + assert!(setresgid(None, Some(gid), None).is_ok()); +}