diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..23f5b79 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,56 @@ +use libc::mode_t; +use openat::{Dir, AsPath}; +use pam::constants::{PamFlag, PamResultCode}; +use pam::module::{PamHandle, PamHooks}; +use std::ffi::CStr; +use std::io::{ErrorKind, Write}; +use std::process; + +const CG_MOUNT: &str = "/sys/fs/cgroup"; + +struct PAMUserCG; +pam::pam_hooks!(PAMUserCG); + +fn create_and_open_dir<P: AsPath + Copy>( + d: &Dir, path: P, mode: mode_t, + ) -> std::io::Result<Dir> { + match d.create_dir(path, mode) { + Ok(()) => Ok(()), + Err(e) => match e.kind() { + ErrorKind::AlreadyExists => Ok(()), + _ => Err(e), + } + }?; + d.sub_dir(path) +} + +struct SessionError; + +fn open_session(h: &mut PamHandle) -> Result<(), SessionError> { + let user = h.get_user(None).or(Err(SessionError))?; + let user = users::get_user_by_name(&user).ok_or(SessionError)?; + let d = Dir::open(CG_MOUNT).or(Err(SessionError))?; + let d = create_and_open_dir(&d, "user", 0o777).or(Err(SessionError))?; + let d = create_and_open_dir(&d, &user.uid().to_string(), 0o777) + .or(Err(SessionError))?; + let d = create_and_open_dir(&d, "leaf", 0o777).or(Err(SessionError))?; + let pid = process::id().to_string(); + let mut procs = d.open_file_ex("cgroup.procs", libc::O_WRONLY, 0) + .or(Err(SessionError))?; + procs.write_all(pid.as_bytes()).or(Err(SessionError))?; + Ok(()) +} + +impl PamHooks for PAMUserCG { + fn sm_open_session( + h: &mut PamHandle, + _args: Vec<&CStr>, + _flags: PamFlag + ) -> PamResultCode { + if open_session(h).is_ok() { + PamResultCode::PAM_SUCCESS + } else { + PamResultCode::PAM_SESSION_ERR + } + } +} |