feat: allow to set defaut environment variables when opening a new session

This commit is contained in:
DL
2026-03-26 15:27:42 +01:00
parent 2ab3f50ad0
commit dbcab4fdd4
6 changed files with 93 additions and 14 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "dysm-rs"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
authors = ["Dany LE"]
description = "Diya Session Manager"

View File

@@ -7,6 +7,7 @@
# PAM service
# the pam service used for authentication
# if not specified, default to diya
pam_service = "diya"
# Default session command
@@ -14,6 +15,7 @@ pam_service = "diya"
# any session ruining. Often, this default session will be a login
# session that handles the user input and send user
# credentials to the daemon via Dbus message
# this configuration is mandatory
default_session_command = "/usr/bin/diyac -x /usr/bin/diya-login-shell"
# default session user
@@ -23,12 +25,21 @@ default_session_user = "xdg"
# if false keep only one session at a time
# open a new session will close any previously opened session
# default true, optional
# default true (if not specified), optional
enable_multiple_session = false
# User session command
# The command to run to start a user session after the
# login session is successful
# the logged in user will own this session
# this configuration is mandatory
user_session_command = "/usr/bin/diyac -x /usr/bin/diya-shell"
# setting environment variables
# when opening a session, optional
[session.envars]
# format key = string value
# example
DBUS_SESSION_BUS_ADDRESS = "unix:path=/tmp/dbus-1"
DBUS_SESSION_BUS_PID = "3598"
user_session_command = "/usr/bin/diyac -x /usr/bin/diya-shell"

View File

@@ -35,6 +35,7 @@ use nix::unistd::execvpe;
use nix::unistd::setgroups;
use nix::unistd::User;
use nix::unistd::{getgrouplist, initgroups, setgid, setuid};
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::os::raw::c_void;
use std::ptr;
@@ -196,6 +197,7 @@ pub trait Session {
///
/// - `&self` - Object that implement this trait
/// - `command` (`&str`) - Command to executed in a new user session
/// - `envars` (`&HashMap<String, String>`) - environment variable for the new session
///
/// # Returns
///
@@ -205,7 +207,11 @@ pub trait Session {
///
/// Any error raised during session opening
///
fn run(&self, command: &str) -> Result<(), Box<dyn std::error::Error>>;
fn run(
&self,
command: &str,
envars: &HashMap<String, String>,
) -> Result<(), Box<dyn std::error::Error>>;
/// End the currently running session
///
@@ -234,6 +240,7 @@ trait DropPrivilege {
///
/// - `&self` - Object that define this trait
/// - `command` (`&str`) - Command that will be executed un the user session after privilege dropping
/// - `envars` (`&HashMap<String, String>`) - environment variable for the new session
///
/// # Returns
///
@@ -242,7 +249,11 @@ trait DropPrivilege {
/// # Errors
/// Any error
///
fn drop_and_run(&self, command: &str) -> Result<(), Box<dyn std::error::Error>> {
fn drop_and_run(
&self,
command: &str,
envars: &HashMap<String, String>,
) -> Result<(), Box<dyn std::error::Error>> {
DEBUG!("Run command: {} as user: {}", command, self.username());
let user =
User::from_name(self.username())?.ok_or(ERR!("Unknown user {}", self.username()))?;
@@ -258,8 +269,12 @@ trait DropPrivilege {
let arg_c = CString::new("-c")?;
let arg_cmd = CString::new(command)?;
let args = vec![arg0.as_c_str(), arg_c.as_c_str(), arg_cmd.as_c_str()];
let env_user = CString::new(format!("USER={}", self.username()))?;
let envs = vec![env_user.as_c_str()];
let mut envs_c_string = vec![CString::new(format!("USER={}", self.username()))?];
for (k, v) in envars {
envs_c_string.push(CString::new(format!("{}={}", k, v))?);
}
let envs: Vec<&CStr> = envs_c_string.iter().map(|e| e.as_c_str()).collect();
execvpe(shell.as_c_str(), &args, &envs)?;
Ok(())
}
@@ -511,8 +526,12 @@ impl Session for AnonymousSession {
Ok(())
}
fn run(&self, command: &str) -> Result<(), Box<dyn std::error::Error>> {
self.drop_and_run(command)
fn run(
&self,
command: &str,
envars: &HashMap<String, String>,
) -> Result<(), Box<dyn std::error::Error>> {
self.drop_and_run(command, envars)
}
fn end(&self) -> Result<(), Box<dyn std::error::Error>> {
@@ -535,10 +554,14 @@ impl Session for PamSession {
Ok(())
}
fn run(&self, command: &str) -> Result<(), Box<dyn std::error::Error>> {
fn run(
&self,
command: &str,
envars: &HashMap<String, String>,
) -> Result<(), Box<dyn std::error::Error>> {
self.pam_set_credentials(PAM_ESTABLISH_CRED)?
.pam_open_session()?
.drop_and_run(command)
.drop_and_run(command, envars)
}
fn end(&self) -> Result<(), Box<dyn std::error::Error>> {

View File

@@ -8,7 +8,7 @@
//! the `Display` trait for easy debugging and logging.
use crate::INFO;
use core::fmt;
use std::path::PathBuf;
use std::{collections::HashMap, path::PathBuf};
use toml::Value;
/// Configuration
@@ -25,6 +25,8 @@ pub struct Configuration {
user_session_command: String,
/// flag to enable multiple session
enable_multiple_session: bool,
/// Session environment variables
session_envars: HashMap<String, String>,
}
impl Configuration {
@@ -77,6 +79,23 @@ impl Configuration {
.get("enable_multiple_session")
.and_then(Value::as_bool)
.unwrap_or(true),
session_envars: table
.get("session")
.and_then(Value::as_table)
.and_then(|table| table.get("envars"))
.and_then(Value::as_table)
.and_then(|table| {
Some(
table
.into_iter()
.filter_map(|(k, v)| {
v.as_str()
.and_then(|value| Some((k.to_string(), value.to_string())))
})
.collect(),
)
})
.unwrap_or(HashMap::new()),
})
}
@@ -120,6 +139,14 @@ impl Configuration {
pub fn enable_multiple_session(&self) -> bool {
self.enable_multiple_session
}
/// Session default environment variables
///
/// # Returs
/// HashMap<String, String>
pub fn session_envars(&self) -> &HashMap<String, String> {
&self.session_envars
}
}
impl fmt::Display for Configuration {
@@ -141,6 +168,10 @@ impl fmt::Display for Configuration {
" - Enable multiple session: {}",
self.enable_multiple_session
)?;
writeln!(f, " - Session environment variables:")?;
for (k, v) in &self.session_envars {
writeln!(f, " + {} = '{}'", k, v)?;
}
Ok(())
}
}

View File

@@ -404,7 +404,7 @@ impl SessionManager {
Ok(()) => {
DEBUG!("Authenticate success");
invocation.return_value(Some(&Variant::tuple_from_iter([true.to_variant()])));
if ! self.config.enable_multiple_session() {
if !self.config.enable_multiple_session() {
self.drop_all_sessions();
}
match self.open_session(self.config.user_session_command(), &session) {
@@ -445,7 +445,9 @@ impl SessionManager {
Ok(child)
}
ForkResult::Child => {
session.run(command).expect("This should not happend");
session
.run(command, self.config.session_envars())
.expect("This should not happend");
panic!();
}
}

View File

@@ -20,4 +20,16 @@ fn test_configuration_loading() {
"/usr/bin/diyac -x /usr/bin/diya-shell"
);
assert_eq!(config.enable_multiple_session(), false);
assert_eq!(
config
.session_envars()
.get("DBUS_SESSION_BUS_ADDRESS")
.unwrap(),
"unix:path=/tmp/dbus-1"
);
assert_eq!(
config.session_envars().get("DBUS_SESSION_BUS_PID").unwrap(),
"3598"
);
}