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

This commit was merged in pull request #2.
This commit is contained in:
DL
2026-03-26 15:27:42 +01:00
committed by dany
parent 0cca54c151
commit a256c54ecf
6 changed files with 93 additions and 14 deletions

View File

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

View File

@@ -7,6 +7,7 @@
# PAM service # PAM service
# the pam service used for authentication # the pam service used for authentication
# if not specified, default to diya
pam_service = "diya" pam_service = "diya"
# Default session command # Default session command
@@ -14,6 +15,7 @@ pam_service = "diya"
# any session ruining. Often, this default session will be a login # any session ruining. Often, this default session will be a login
# session that handles the user input and send user # session that handles the user input and send user
# credentials to the daemon via Dbus message # 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_command = "/usr/bin/diyac -x /usr/bin/diya-login-shell"
# default session user # default session user
@@ -23,12 +25,21 @@ default_session_user = "xdg"
# if false keep only one session at a time # if false keep only one session at a time
# open a new session will close any previously opened session # open a new session will close any previously opened session
# default true, optional # default true (if not specified), optional
enable_multiple_session = false enable_multiple_session = false
# User session command # User session command
# The command to run to start a user session after the # The command to run to start a user session after the
# login session is successful # login session is successful
# the logged in user will own this session # 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::setgroups;
use nix::unistd::User; use nix::unistd::User;
use nix::unistd::{getgrouplist, initgroups, setgid, setuid}; use nix::unistd::{getgrouplist, initgroups, setgid, setuid};
use std::collections::HashMap;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr; use std::ptr;
@@ -196,6 +197,7 @@ pub trait Session {
/// ///
/// - `&self` - Object that implement this trait /// - `&self` - Object that implement this trait
/// - `command` (`&str`) - Command to executed in a new user session /// - `command` (`&str`) - Command to executed in a new user session
/// - `envars` (`&HashMap<String, String>`) - environment variable for the new session
/// ///
/// # Returns /// # Returns
/// ///
@@ -205,7 +207,11 @@ pub trait Session {
/// ///
/// Any error raised during session opening /// 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 /// End the currently running session
/// ///
@@ -234,6 +240,7 @@ trait DropPrivilege {
/// ///
/// - `&self` - Object that define this trait /// - `&self` - Object that define this trait
/// - `command` (`&str`) - Command that will be executed un the user session after privilege dropping /// - `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 /// # Returns
/// ///
@@ -242,7 +249,11 @@ trait DropPrivilege {
/// # Errors /// # Errors
/// Any error /// 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()); DEBUG!("Run command: {} as user: {}", command, self.username());
let user = let user =
User::from_name(self.username())?.ok_or(ERR!("Unknown user {}", self.username()))?; 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_c = CString::new("-c")?;
let arg_cmd = CString::new(command)?; let arg_cmd = CString::new(command)?;
let args = vec![arg0.as_c_str(), arg_c.as_c_str(), arg_cmd.as_c_str()]; 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)?; execvpe(shell.as_c_str(), &args, &envs)?;
Ok(()) Ok(())
} }
@@ -511,8 +526,12 @@ impl Session for AnonymousSession {
Ok(()) Ok(())
} }
fn run(&self, command: &str) -> Result<(), Box<dyn std::error::Error>> { fn run(
self.drop_and_run(command) &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>> { fn end(&self) -> Result<(), Box<dyn std::error::Error>> {
@@ -535,10 +554,14 @@ impl Session for PamSession {
Ok(()) 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)? self.pam_set_credentials(PAM_ESTABLISH_CRED)?
.pam_open_session()? .pam_open_session()?
.drop_and_run(command) .drop_and_run(command, envars)
} }
fn end(&self) -> Result<(), Box<dyn std::error::Error>> { fn end(&self) -> Result<(), Box<dyn std::error::Error>> {

View File

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

View File

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

View File

@@ -20,4 +20,16 @@ fn test_configuration_loading() {
"/usr/bin/diyac -x /usr/bin/diya-shell" "/usr/bin/diyac -x /usr/bin/diya-shell"
); );
assert_eq!(config.enable_multiple_session(), false); 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"
);
} }