call pam_end from within the child session, not the parent

this allows modules like pam_cap to configure the capability bits of the
session process, particularly the ambient capability set.

further details/precedent can be found here:
- <https://github.com/shadow-maint/shadow/pull/408>
- <https://bugzilla.kernel.org/show_bug.cgi?id=214377>
This commit is contained in:
Colin 2024-01-29 18:29:48 +00:00
parent 67eaa39b93
commit 208cd4a687
1 changed files with 27 additions and 2 deletions

View File

@ -1,4 +1,4 @@
use std::{env, ffi::CString, os::unix::net::UnixDatagram};
use std::{env, ffi::CString, io::Write as _, os::unix::net::UnixDatagram};
use nix::{
sys::wait::waitpid,
@ -123,6 +123,11 @@ fn worker(sock: &UnixDatagram) -> Result<(), Error> {
msg => return Err(format!("expected InitiateLogin or Cancel, got: {:?}", msg).into()),
};
println!("worker fn start (stdout)");
eprintln!("worker fn start (stderr)");
std::io::stdout().flush();
std::io::stderr().flush();
let conv = Box::pin(SessionConv::new(sock));
let mut pam = PamSession::start(service, user, conv)?;
@ -242,6 +247,11 @@ fn worker(sock: &UnixDatagram) -> Result<(), Error> {
let pamenvlist = pam.getenvlist()?;
let envvec = pamenvlist.to_vec();
println!("about to fork (stdout)");
eprintln!("about to fork (stderr)");
std::io::stdout().flush();
std::io::stderr().flush();
// PAM is weird and gets upset if you exec from the process that opened
// the session, registering it automatically as a log-out. Thus, we must
// exec in a new child.
@ -252,6 +262,11 @@ fn worker(sock: &UnixDatagram) -> Result<(), Error> {
// accidentally using '?'. The process *must* exit from within
// this match arm.
println!("entered fork (stdout)");
eprintln!("entered fork (stderr)");
std::io::stdout().flush();
std::io::stderr().flush();
// Drop privileges to target user
initgroups(&cusername, user.gid).expect("unable to init groups");
setgid(user.gid).expect("unable to set GID");
@ -264,8 +279,19 @@ fn worker(sock: &UnixDatagram) -> Result<(), Error> {
// Change working directory
if let Err(e) = env::set_current_dir(user.dir) {
eprintln!("unable to set working directory: {}", e);
std::io::stderr().flush();
}
if let Err(e) = pam.end() {
eprintln!("pam.end failed: {}", e);
std::io::stderr().flush();
}
println!("called pam.end (stdout)");
eprintln!("called pam.end (stderr)");
std::io::stdout().flush();
std::io::stderr().flush();
// Run
let cpath = CString::new("/bin/sh").unwrap();
execve(
@ -310,7 +336,6 @@ fn worker(sock: &UnixDatagram) -> Result<(), Error> {
// inner-most child.
pam.close_session(PamFlag::NONE)?;
pam.setcred(PamFlag::DELETE_CRED)?;
pam.end()?;
Ok(())
}