diff --git a/Cargo.toml b/Cargo.toml index 77620dd..c3e65c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/references/daemon.conf b/references/daemon.conf index 6431490..6bd3bf1 100644 --- a/references/daemon.conf +++ b/references/daemon.conf @@ -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" \ No newline at end of file diff --git a/src/auth.rs b/src/auth.rs index 4619d81..3d72411 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -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`) - 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>; + fn run( + &self, + command: &str, + envars: &HashMap, + ) -> Result<(), Box>; /// 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`) - 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> { + fn drop_and_run( + &self, + command: &str, + envars: &HashMap, + ) -> Result<(), Box> { 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> { - self.drop_and_run(command) + fn run( + &self, + command: &str, + envars: &HashMap, + ) -> Result<(), Box> { + self.drop_and_run(command, envars) } fn end(&self) -> Result<(), Box> { @@ -535,10 +554,14 @@ impl Session for PamSession { Ok(()) } - fn run(&self, command: &str) -> Result<(), Box> { + fn run( + &self, + command: &str, + envars: &HashMap, + ) -> Result<(), Box> { self.pam_set_credentials(PAM_ESTABLISH_CRED)? .pam_open_session()? - .drop_and_run(command) + .drop_and_run(command, envars) } fn end(&self) -> Result<(), Box> { diff --git a/src/configuration.rs b/src/configuration.rs index e7974f4..2a72ec3 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -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, } 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 + pub fn session_envars(&self) -> &HashMap { + &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(()) } } diff --git a/src/session.rs b/src/session.rs index cded421..76fcbac 100644 --- a/src/session.rs +++ b/src/session.rs @@ -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!(); } } diff --git a/src/tests.rs b/src/tests.rs index 6b6dbbb..3d8ac47 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -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" + ); }