// Copyright (C) 2023 Tomasz Kramkowski // SPDX-License-Identifier: MIT mod passwd; use cap_std::fs::{Dir, OpenOptions}; use pam::module::PamHandle; use std::ffi::{c_char, c_int, CString}; use std::io::{ErrorKind, Write}; use std::panic; use std::path::Path; use std::process; fn create_and_open_dir + Copy>( d: &Dir, path: P, ) -> std::io::Result { if let Err(e) = d.create_dir(path) { if e.kind() != ErrorKind::AlreadyExists { return Err(e); } } d.open_dir(path) } struct SessionError; impl From for SessionError { fn from(_: std::io::Error) -> Self { SessionError } } fn open_session(h: &PamHandle, mountpoint: &str) -> Result<(), SessionError> { let user = h.get_user(None).or(Err(SessionError))?; let user = CString::new(user).or(Err(SessionError))?; let uid = passwd::get_uid_by_name(&user).ok_or(SessionError)?; let uid = uid.to_string(); let d = Dir::open_ambient_dir(mountpoint, cap_std::ambient_authority())?; let d = create_and_open_dir(&d, "user")?; let d = create_and_open_dir(&d, &uid)?; let d = create_and_open_dir(&d, "leaf")?; let pid = process::id().to_string(); let mut options = OpenOptions::new(); options.write(true); let mut procs = d.open_with("cgroup.procs", &options)?; procs.write_all(pid.as_bytes())?; Ok(()) } const CG_MOUNT: &str = "/sys/fs/cgroup"; #[no_mangle] pub extern "C" fn pam_sm_open_session( h: &mut PamHandle, _flags: c_int, _argc: c_int, _argv: *const *const c_char, ) -> c_int { match panic::catch_unwind(|| open_session(h, CG_MOUNT)) { Ok(Ok(())) => 0, _ => 14, } } #[no_mangle] pub extern "C" fn pam_sm_close_session( _h: &mut PamHandle, _flags: c_int, _argc: c_int, _argv: *const *const c_char, ) -> c_int { 0 }