Skip to content

Commit 798bf07

Browse files
committed
Fix #931: Support no-change in setresuid/setresgid
- Change signature to accept Option<Uid/Gid> - None maps to -1 via wrapping arithmetic - Add comprehensive tests for both Some and None cases - Fix setresgid documentation link (was pointing to setresuid)
1 parent 984420e commit 798bf07

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

src/unistd.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3228,16 +3228,23 @@ mod setres {
32283228
/// * returns: Ok or libc error code.
32293229
///
32303230
/// Err is returned if the user doesn't have permission to set this UID.
3231+
///
3232+
/// If one of the arguments equals None, the corresponding value is not changed.
32313233
#[inline]
3232-
pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
3234+
pub fn setresuid(ruid: Option<Uid>, euid: Option<Uid>, suid: Option<Uid>) -> Result<()> {
3235+
let ruid = ruid.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1));
3236+
let euid = euid.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1));
3237+
let suid = suid.map(Into::into).unwrap_or((0 as libc::uid_t).wrapping_sub(1));
32333238
let res =
3234-
unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
3239+
unsafe { libc::setresuid(ruid, euid, suid) };
32353240

32363241
Errno::result(res).map(drop)
32373242
}
32383243

32393244
/// Sets the real, effective, and saved gid.
3240-
/// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
3245+
///
3246+
/// If one of the arguments equals None, the corresponding value is not changed.
3247+
/// ([see setresgid(2)](https://man7.org/linux/man-pages/man2/setresgid.2.html))
32413248
///
32423249
/// * `rgid`: real group id
32433250
/// * `egid`: effective group id
@@ -3246,9 +3253,12 @@ mod setres {
32463253
///
32473254
/// Err is returned if the user doesn't have permission to set this GID.
32483255
#[inline]
3249-
pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
3256+
pub fn setresgid(rgid: Option<Gid>, egid: Option<Gid>, sgid: Option<Gid>) -> Result<()> {
3257+
let rgid = rgid.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1));
3258+
let egid = egid.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1));
3259+
let sgid = sgid.map(Into::into).unwrap_or((0 as libc::gid_t).wrapping_sub(1));
32503260
let res =
3251-
unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
3261+
unsafe { libc::setresgid(rgid, egid, sgid) };
32523262

32533263
Errno::result(res).map(drop)
32543264
}

test/test_unistd.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,3 +1430,40 @@ fn test_group_from() {
14301430
assert_eq!(group.gid, group_id);
14311431
assert_eq!(group.name, "wheel");
14321432
}
1433+
1434+
// Tests for PR #1305: setresuid/setresgid with Option support
1435+
#[test]
1436+
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
1437+
fn test_setresuid_with_option() {
1438+
let uid = getuid();
1439+
1440+
// Test 1: Set all to current values
1441+
assert!(setresuid(Some(uid), Some(uid), Some(uid)).is_ok());
1442+
assert_eq!(geteuid(), uid);
1443+
1444+
// Test 2: No-change (None for all)
1445+
let euid_before = geteuid();
1446+
assert!(setresuid(None, None, None).is_ok());
1447+
assert_eq!(geteuid(), euid_before, "UID should not change with None");
1448+
1449+
// Test 3: Selective change (only effective)
1450+
assert!(setresuid(None, Some(uid), None).is_ok());
1451+
}
1452+
1453+
#[test]
1454+
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"))]
1455+
fn test_setresgid_with_option() {
1456+
let gid = getgid();
1457+
1458+
// Test 1: Set all to current values
1459+
assert!(setresgid(Some(gid), Some(gid), Some(gid)).is_ok());
1460+
assert_eq!(getegid(), gid);
1461+
1462+
// Test 2: No-change (None for all)
1463+
let egid_before = getegid();
1464+
assert!(setresgid(None, None, None).is_ok());
1465+
assert_eq!(getegid(), egid_before, "GID should not change with None");
1466+
1467+
// Test 3: Selective change (only effective)
1468+
assert!(setresgid(None, Some(gid), None).is_ok());
1469+
}

0 commit comments

Comments
 (0)