session: Initial environment.d support
Read the configuration files in the various environment.d folders to set up the user environment. Only very basic substition is currently supported. Environment variable precedence should be correct as per the documentation, but it has not been verified against the existing systemd implementations.
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::{BufRead, BufReader, Write};
|
||||||
use std::os::unix::io::{FromRawFd, RawFd};
|
use std::os::unix::io::{FromRawFd, RawFd};
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
@@ -105,6 +108,16 @@ pub struct Session<'a> {
|
|||||||
cmd: Vec<String>,
|
cmd: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn split_env<'a>(s: &'a str) -> Option<(&'a str, &str)> {
|
||||||
|
let components: Vec<&str> = s.splitn(2, "=").collect();
|
||||||
|
match components.len() {
|
||||||
|
0 => None,
|
||||||
|
1 => Some((components[0], "")),
|
||||||
|
2 => Some((components[0], components[1])),
|
||||||
|
_ => panic!("splitn returned more values than requested"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Session<'a> {
|
impl<'a> Session<'a> {
|
||||||
///
|
///
|
||||||
/// Create a Session object with details required to start the specified
|
/// Create a Session object with details required to start the specified
|
||||||
@@ -144,6 +157,80 @@ impl<'a> Session<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Process environment.d folders to generate the configured environment for
|
||||||
|
/// the session.
|
||||||
|
fn generate_user_environment(&mut self, home: String) -> Result<(), Box<dyn Error>> {
|
||||||
|
let dirs = [
|
||||||
|
"/usr/lib/environments.d/",
|
||||||
|
"/usr/local/lib/environments.d/",
|
||||||
|
"/run/environments.d/",
|
||||||
|
"/etc/environments.d/",
|
||||||
|
&format!("{}/.config/environment.d", home),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut env: HashMap<String, String> = HashMap::new();
|
||||||
|
for dir in dirs.iter() {
|
||||||
|
let entries = match fs::read_dir(dir) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut filepaths: Vec<PathBuf> =
|
||||||
|
entries.filter_map(Result::ok).map(|e| e.path()).collect();
|
||||||
|
|
||||||
|
filepaths.sort();
|
||||||
|
|
||||||
|
for filepath in filepaths.into_iter() {
|
||||||
|
let reader = BufReader::new(match File::open(&filepath) {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(_) => continue,
|
||||||
|
});
|
||||||
|
|
||||||
|
for line in reader.lines().filter_map(Result::ok) {
|
||||||
|
let (key, value) = match split_env(&line) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if key.starts_with("#") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !value.contains("$") {
|
||||||
|
env.insert(key.to_string(), value.to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let reference = &value[1..];
|
||||||
|
let value = match env.get(reference) {
|
||||||
|
Some(v) => v.to_string(),
|
||||||
|
None => match self.pam.getenv(reference) {
|
||||||
|
Some(pam_val) => match split_env(pam_val) {
|
||||||
|
Some((_, new_value)) => new_value.to_string(),
|
||||||
|
None => "".to_string(),
|
||||||
|
},
|
||||||
|
None => "".to_string(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
env.insert(key.to_string(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let env = env
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, value)| format!("{}={}", key, value));
|
||||||
|
|
||||||
|
for e in env {
|
||||||
|
self.pam
|
||||||
|
.putenv(&e)
|
||||||
|
.map_err(|e| format!("unable to set PAM environment: {}", e))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// The entry point for the session worker process. The session worker is
|
/// The entry point for the session worker process. The session worker is
|
||||||
/// responsible for the entirety of the session setup and execution. It is
|
/// responsible for the entirety of the session setup and execution. It is
|
||||||
/// started by Session::start.
|
/// started by Session::start.
|
||||||
@@ -263,6 +350,11 @@ impl<'a> Session<'a> {
|
|||||||
.map_err(|e| format!("unable to set PAM environment: {}", e))?;
|
.map_err(|e| format!("unable to set PAM environment: {}", e))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're almost done with our environment. Let's go through
|
||||||
|
// environment.d configuration to fix up the last bits.
|
||||||
|
let home = home.to_string();
|
||||||
|
self.generate_user_environment(home)?;
|
||||||
|
|
||||||
// Extract PAM environment for use with execve below.
|
// Extract PAM environment for use with execve below.
|
||||||
let mut pamenvlist = self
|
let mut pamenvlist = self
|
||||||
.pam
|
.pam
|
||||||
|
Reference in New Issue
Block a user