passwd_rs/
user.rs

1use std::ffi::{CStr, CString};
2use std::io;
3use std::os::raw::*;
4
5/// User information struct
6pub struct User {
7	/// Username
8	pub name: String,
9	/// Full name of the user
10	pub fullname: String,
11	/// Home directory
12	pub homedir: String,
13	/// Path to the shell in use
14	pub shell: String,
15	/// User password. Can be equal to 'x' what means that, the password is stored in shadow. Check `Shadow` struct.
16	pub passwd: Option<String>,
17
18	/// User ID
19	pub uid: c_uint,
20	/// Group ID, which is created for that user
21	pub gid: c_uint,
22}
23
24// Raw
25#[repr(C)]
26struct Raw {
27	pw_name: *const c_char,
28	pw_passwd: *const c_char,
29	pw_uid: c_uint,
30	pw_gid: c_uint,
31	pw_gecos: *const c_char,
32	pw_dir: *const c_char,
33	pw_shell: *const c_char,
34}
35extern "C" {
36	fn getpwnam(name: *const c_char) -> *const Raw;
37	fn getpwuid(uid: c_uint) -> *const Raw;
38}
39unsafe fn unref(ptr: *const c_char) -> String {
40	CStr::from_ptr(ptr).to_str().unwrap_or("").to_string()
41}
42
43impl User {
44	unsafe fn convert(raw: *const Raw) -> io::Result<Self> {
45		if raw == std::ptr::null() {
46			return Err(io::Error::last_os_error());
47		}
48
49		let name = unref((*raw).pw_name);
50		let passwd = {
51			let p = unref((*raw).pw_passwd);
52			let ret;
53			if p.eq("") {
54				ret = None
55			} else {
56				ret = Some(p);
57			}
58			ret
59		};
60		let uid = (*raw).pw_uid;
61		let gid = (*raw).pw_gid;
62		let fullname = unref((*raw).pw_gecos);
63		let homedir = unref((*raw).pw_dir);
64		let shell = unref((*raw).pw_shell);
65
66		Ok(Self {
67			name,
68			fullname,
69			homedir,
70			shell,
71			passwd,
72			uid,
73			gid,
74		})
75	}
76
77	/// Get user information by user ID
78	pub fn new_from_uid(uid: c_uint) -> io::Result<Self> {
79		unsafe { Self::convert(getpwuid(uid)) }
80	}
81
82	/// Get user information by it's username
83	pub fn new_from_name(name: &str) -> io::Result<Self> {
84		unsafe {
85			let cstr = match CString::new(name) {
86				Ok(o) => o,
87				Err(_) => return Err(io::Error::from(io::ErrorKind::InvalidData)),
88			};
89
90			Self::convert(getpwnam(cstr.as_ptr()))
91		}
92	}
93
94	/// Fetch information about current user
95	pub fn current_user() -> io::Result<Self> {
96		unsafe {
97			let uid = crate::getuid();
98
99			Self::convert(getpwuid(uid))
100		}
101	}
102}