pub(crate) use pwd::make_module;
#[pymodule]
mod pwd {
use crate::{
builtins::{PyIntRef, PyStrRef},
convert::{IntoPyException, ToPyObject},
exceptions,
types::PyStructSequence,
PyObjectRef, PyResult, VirtualMachine,
};
use nix::unistd::{self, User};
use std::ptr::NonNull;
#[pyattr]
#[pyclass(module = "pwd", name = "struct_passwd")]
#[derive(PyStructSequence)]
struct Passwd {
pw_name: String,
pw_passwd: String,
pw_uid: u32,
pw_gid: u32,
pw_gecos: String,
pw_dir: String,
pw_shell: String,
}
#[pyclass(with(PyStructSequence))]
impl Passwd {}
impl From<User> for Passwd {
fn from(user: User) -> Self {
let cstr_lossy = |s: std::ffi::CString| {
s.into_string()
.unwrap_or_else(|e| e.into_cstring().to_string_lossy().into_owned())
};
let pathbuf_lossy = |p: std::path::PathBuf| {
p.into_os_string()
.into_string()
.unwrap_or_else(|s| s.to_string_lossy().into_owned())
};
Passwd {
pw_name: user.name,
pw_passwd: cstr_lossy(user.passwd),
pw_uid: user.uid.as_raw(),
pw_gid: user.gid.as_raw(),
pw_gecos: cstr_lossy(user.gecos),
pw_dir: pathbuf_lossy(user.dir),
pw_shell: pathbuf_lossy(user.shell),
}
}
}
#[pyfunction]
fn getpwnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult<Passwd> {
let pw_name = name.as_str();
if pw_name.contains('\0') {
return Err(exceptions::cstring_error(vm));
}
let user = User::from_name(name.as_str()).map_err(|err| err.into_pyexception(vm))?;
let user = user.ok_or_else(|| {
vm.new_key_error(
vm.ctx
.new_str(format!("getpwnam(): name not found: {pw_name}"))
.into(),
)
})?;
Ok(Passwd::from(user))
}
#[pyfunction]
fn getpwuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult<Passwd> {
let uid_t = libc::uid_t::try_from(uid.as_bigint())
.map(unistd::Uid::from_raw)
.ok();
let user = uid_t
.map(User::from_uid)
.transpose()
.map_err(|err| err.into_pyexception(vm))?
.flatten();
let user = user.ok_or_else(|| {
vm.new_key_error(
vm.ctx
.new_str(format!("getpwuid(): uid not found: {}", uid.as_bigint()))
.into(),
)
})?;
Ok(Passwd::from(user))
}
#[pyfunction]
fn getpwall(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
static GETPWALL: parking_lot::Mutex<()> = parking_lot::const_mutex(());
let _guard = GETPWALL.lock();
let mut list = Vec::new();
unsafe { libc::setpwent() };
while let Some(ptr) = NonNull::new(unsafe { libc::getpwent() }) {
let user = User::from(unsafe { ptr.as_ref() });
let passwd = Passwd::from(user).to_pyobject(vm);
list.push(passwd);
}
unsafe { libc::endpwent() };
Ok(list)
}
}