Skip to content

Commit

Permalink
Merge pull request #120 from lucab/ups/credentials
Browse files Browse the repository at this point in the history
credentials: add helpers for accessing credential data
  • Loading branch information
lucab committed Nov 4, 2022
2 parents d6e0db6 + aafe872 commit 8ada6e3
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ rust-version = "1.56"
hmac = "^0.12"
libc = "^0.2"
log = "^0.4"
nix = { version = "^0.25", default-features = false, features = ["fs", "socket", "process", "uio"] }
nix = { version = "^0.25", default-features = false, features = ["dir", "fs", "socket", "process", "uio"] }
nom = "7"
serde = { version = "^1.0.91", features = ["derive"] }
sha2 = "^0.10"
Expand Down
105 changes: 105 additions & 0 deletions src/credentials.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::errors::SdError;
use nix::dir;
use nix::fcntl::OFlag;
use nix::sys::stat::Mode;
use std::env;
use std::fs::File;
use std::path::PathBuf;

/// Credential loader for units.
///
/// Credentials are read by systemd on unit startup and exported by their ID.
///
/// **Note**: only the user associated with the unit and the superuser may access credentials.
///
/// More documentation: <https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Credentials>
#[derive(Debug)]
pub struct CredentialsLoader {
path: PathBuf,
_dirfd: dir::Dir,
}

impl CredentialsLoader {
/// Try to open credentials directory.
pub fn open() -> Result<Self, SdError> {
let path = Self::path_from_env().ok_or_else(|| {
SdError::from("No valid environment variable 'CREDENTIALS_DIRECTORY' found")
})?;

// NOTE(lucab): we try to open the directory and then store its dirfd, so
// that we know it exists. We don't further use it now, but in the
// future we may couple it to something like 'cap-std' helpers.
let _dirfd = dir::Dir::open(&path, OFlag::O_RDONLY | OFlag::O_DIRECTORY, Mode::empty())
.map_err(|e| {
let msg = format!(
"Opening credentials directory at '{}': {}",
path.display(),
e
);
SdError::from(msg)
})?;

let loader = Self { path, _dirfd };
Ok(loader)
}

/// Return the location of the credentials directory, if any.
pub fn path_from_env() -> Option<PathBuf> {
env::var("CREDENTIALS_DIRECTORY").map(|v| v.into()).ok()
}

/// Get credential by ID.
///
/// # Examples
///
/// ```no_run
/// use libsystemd::credentials::CredentialsLoader;
///
/// let loader = CredentialsLoader::open()?;
/// let token = loader.get("token")?;
/// let token_metadata = token.metadata()?;
/// println!("token size: {}", token_metadata.len());
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn get(&self, id: impl AsRef<str>) -> Result<File, SdError> {
let cred_path = self.cred_absolute_path(id.as_ref())?;
File::open(&cred_path).map_err(|e| {
let msg = format!("Opening credential at {}: {}", cred_path.display(), e);
SdError::from(msg)
})
}

/// Validate credential ID and return its absolute path.
fn cred_absolute_path(&self, id: &str) -> Result<PathBuf, SdError> {
if id.contains('/') {
return Err(SdError::from("Invalid credential ID"));
}

let abs_path = self.path.join(id);
Ok(abs_path)
}

/// Return an iterator over all existing credentials.
///
/// # Examples
///
/// ```no_run
/// use libsystemd::credentials::CredentialsLoader;
///
/// let loader = CredentialsLoader::open()?;
/// for entry in loader.iter()? {
/// let credential = entry?;
/// println!("Credential ID: {}", credential.file_name().to_string_lossy());
/// }
/// # Ok::<(), Box<dyn std::error::Error>>(())
pub fn iter(&self) -> Result<std::fs::ReadDir, SdError> {
std::fs::read_dir(&self.path).map_err(|e| {
let msg = format!(
"Opening credential directory at {}: {}",
self.path.display(),
e
);
SdError::from(msg)
})
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

/// Interfaces for socket-activated services.
pub mod activation;
/// Helpers for securely passing potentially sensitive data to services.
pub mod credentials;
/// Interfaces for systemd-aware daemons.
pub mod daemon;
/// Error handling.
Expand Down

0 comments on commit 8ada6e3

Please sign in to comment.