I would like to use setuid(2)
to drop root permissions. I'd like to do this via a username which means I need to first call getpwnam(3)
. Anyway, is the below code safe and does it avoid a memory leak?
libc
links:
extern crate alloc;
use alloc::ffi::{CString, NulError};
use core::ffi::c_void;
pub fn get_uid_from_pwnam(name: String) -> Result<Option<u32>, NulError> {
CString::new(name.into_bytes()).map(|n| {
let ptr = n.as_ptr();
// SAFETY:
// `getpwnam` is an FFI binding; thus requires unsafe code.
let entry = unsafe { libc::getpwnam(ptr) };
if entry.is_null() {
None
} else {
// SAFETY:
// `entry` is not null, so it's safe to dereference.
let pwd_ent = unsafe { *entry };
let uid = pwd_ent.pw_uid;
let void_ptr = entry.cast::<c_void>();
// SAFETY:
// `entry` is not null, so `void_ptr` isn't either.
// This means it's safe to free it.
unsafe { libc::free(void_ptr) }
Some(uid)
}
})
}
Edit
Do I need to be sure to drop pwd_ent
before free
ing void_ptr
? For example:
let uid = {
// SAFETY:
// `entry` is not null, so it's safe to dereference.
let pwd_ent = unsafe { *entry };
pwd_ent.pw_uid
};
let void_ptr = entry.cast::<c_void>();
// SAFETY:
// `entry` is not null, so `void_ptr` isn't either.
// This means it's safe to free it.
unsafe { libc::free(void_ptr) }