diff --git a/src/agent/rustjail/Cargo.toml b/src/agent/rustjail/Cargo.toml index 841ec3a49f..5ca8f9aa78 100644 --- a/src/agent/rustjail/Cargo.toml +++ b/src/agent/rustjail/Cargo.toml @@ -22,7 +22,6 @@ slog-scope = "4.1.2" scan_fmt = "0.2" regex = "1.1" path-absolutize = "1.2.0" -dirs = "3.0.1" anyhow = "1.0.32" cgroups = { package = "cgroups-rs", version = "0.2.1" } tempfile = "3.1.0" diff --git a/src/agent/rustjail/src/container.rs b/src/agent/rustjail/src/container.rs index edf99dfa03..bdaac295d2 100644 --- a/src/agent/rustjail/src/container.rs +++ b/src/agent/rustjail/src/container.rs @@ -58,6 +58,8 @@ use async_trait::async_trait; use rlimit::{setrlimit, Resource, Rlim}; use tokio::io::AsyncBufReadExt; +use crate::utils; + const STATE_FILENAME: &str = "state.json"; const EXEC_FIFO_FILENAME: &str = "exec.fifo"; const VER_MARKER: &str = "1.2.5"; @@ -634,8 +636,9 @@ fn do_init_child(cwfd: RawFd) -> Result<()> { // set the "HOME" env getting from "/etc/passwd" if env::var_os(HOME_ENV_KEY).is_none() { - if let Some(home_dir) = dirs::home_dir() { - env::set_var(HOME_ENV_KEY, home_dir); + match utils::home_dir(guser.uid) { + Ok(home_dir) => env::set_var(HOME_ENV_KEY, home_dir), + Err(e) => log_child!(cfd_log, "failed to get home dir: {:?}", e), } } diff --git a/src/agent/rustjail/src/lib.rs b/src/agent/rustjail/src/lib.rs index e29ce4b98a..6cdf3d0c54 100644 --- a/src/agent/rustjail/src/lib.rs +++ b/src/agent/rustjail/src/lib.rs @@ -45,8 +45,8 @@ pub mod process; pub mod specconv; pub mod sync; pub mod sync_with_async; +pub mod utils; pub mod validator; - // pub mod factory; //pub mod configs; // pub mod devices; diff --git a/src/agent/rustjail/src/utils.rs b/src/agent/rustjail/src/utils.rs new file mode 100644 index 0000000000..35ca4e45d8 --- /dev/null +++ b/src/agent/rustjail/src/utils.rs @@ -0,0 +1,119 @@ +// Copyright (c) 2021 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 +// +use anyhow::{anyhow, Context, Result}; +use libc::gid_t; +use libc::uid_t; +use std::fs::File; +use std::io::{BufRead, BufReader}; + +const PASSWD_FILE: &str = "/etc/passwd"; + +// An entry from /etc/passwd +#[derive(Debug, PartialEq, PartialOrd)] +pub struct PasswdEntry { + // username + pub name: String, + // user password + pub passwd: String, + // user id + pub uid: uid_t, + // group id + pub gid: gid_t, + // user Information + pub gecos: String, + // home directory + pub dir: String, + // User's Shell + pub shell: String, +} + +// get an entry for a given `uid` from `/etc/passwd` +fn get_entry_by_uid(uid: uid_t, path: &str) -> Result { + let file = File::open(path).with_context(|| format!("open file {}", path))?; + let mut reader = BufReader::new(file); + + let mut line = String::new(); + loop { + line.clear(); + match reader.read_line(&mut line) { + Ok(0) => return Err(anyhow!(format!("file {} is empty", path))), + Ok(_) => (), + Err(e) => { + return Err(anyhow!(format!( + "failed to read file {} with {:?}", + path, e + ))) + } + } + + if line.starts_with('#') { + continue; + } + + let parts: Vec<&str> = line.split(':').map(|part| part.trim()).collect(); + if parts.len() != 7 { + continue; + } + + match parts[2].parse() { + Err(_e) => continue, + Ok(new_uid) => { + if uid != new_uid { + continue; + } + + let entry = PasswdEntry { + name: parts[0].to_string(), + passwd: parts[1].to_string(), + uid: new_uid, + gid: parts[3].parse().unwrap_or(0), + gecos: parts[4].to_string(), + dir: parts[5].to_string(), + shell: parts[6].to_string(), + }; + + return Ok(entry); + } + } + } +} + +pub fn home_dir(uid: uid_t) -> Result { + get_entry_by_uid(uid, PASSWD_FILE).map(|entry| entry.dir) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::io::{self, Write}; + use tempfile::Builder; + + #[test] + fn test_get_entry_by_uid() { + let tmpdir = Builder::new().tempdir().unwrap(); + let tmpdir_path = tmpdir.path().to_str().unwrap(); + let temp_passwd = format!("{}/passwd", tmpdir_path); + + let mut tempf = File::create(temp_passwd.as_str()).unwrap(); + writeln!(tempf, "root:x:0:0:root:/root0:/bin/bash").unwrap(); + writeln!(tempf, "root:x:1:0:root:/root1:/bin/bash").unwrap(); + writeln!(tempf, "#root:x:1:0:root:/rootx:/bin/bash").unwrap(); + writeln!(tempf, "root:x:2:0:root:/root2:/bin/bash").unwrap(); + writeln!(tempf, "root:x:3:0:root:/root3").unwrap(); + writeln!(tempf, "root:x:3:0:root:/root3:/bin/bash").unwrap(); + + let entry = get_entry_by_uid(0, temp_passwd.as_str()).unwrap(); + assert_eq!(entry.dir.as_str(), "/root0"); + + let entry = get_entry_by_uid(1, temp_passwd.as_str()).unwrap(); + assert_eq!(entry.dir.as_str(), "/root1"); + + let entry = get_entry_by_uid(2, temp_passwd.as_str()).unwrap(); + assert_eq!(entry.dir.as_str(), "/root2"); + + let entry = get_entry_by_uid(3, temp_passwd.as_str()).unwrap(); + assert_eq!(entry.dir.as_str(), "/root3"); + } +}