signstar_common/
admin_credentials.rs

1//! Data and functions for using administrative credentials on a Signstar host.
2//!
3//! # Examples
4//!
5//! ```
6//! use signstar_common::admin_credentials::get_credentials_dir;
7//!
8//! // Get the directory path in which administrative credentials reside.
9//! println!("{:?}", get_credentials_dir());
10//! ```
11
12use std::{
13    fs::{Permissions, create_dir_all, set_permissions},
14    os::unix::fs::{PermissionsExt, chown},
15    path::PathBuf,
16};
17
18use crate::common::{CREDENTIALS_DIR_MODE, get_data_home};
19
20/// File name of plaintext administrative credentials.
21const PLAINTEXT_CREDENTIALS_FILE: &str = "admin-credentials.toml";
22
23/// File name of systemd-creds encrypted administrative credentials.
24const SYSTEMD_CREDS_CREDENTIALS_FILE: &str = "admin-credentials.creds";
25
26/// The directory for administrative credentials (encrypted and unencrypted).
27const CREDENTIALS_DIR: &str = "creds/";
28
29/// An error that may occur when handling credentials.
30#[derive(Debug, thiserror::Error)]
31pub enum Error {
32    /// Applying permissions to a file failed.
33    #[error("Unable to apply permissions {permissions} to {path}:\n{source}")]
34    ApplyPermissions {
35        permissions: u32,
36        path: PathBuf,
37        source: std::io::Error,
38    },
39
40    /// No plaintext administrative credentials file can be found
41    #[error("Unable to create directory {dir}:\n{source}")]
42    CreateDirectory {
43        dir: &'static str,
44        source: std::io::Error,
45    },
46
47    /// The ownership of a directory can not be set.
48    #[error("Ownership of directory {dir} can not be changed to user {system_user}: {source}")]
49    DirChangeOwner {
50        dir: PathBuf,
51        system_user: String,
52        source: std::io::Error,
53    },
54}
55
56/// Returns the path of the directory in which administrative credentials reside.
57pub fn get_credentials_dir() -> PathBuf {
58    get_data_home().join(PathBuf::from(CREDENTIALS_DIR))
59}
60
61/// Returns the file path for plaintext administrative credentials.
62pub fn get_plaintext_credentials_file() -> PathBuf {
63    get_credentials_dir().join(PathBuf::from(PLAINTEXT_CREDENTIALS_FILE))
64}
65
66/// Returns the file path for systemd-creds encrypted administrative credentials.
67pub fn get_systemd_creds_credentials_file() -> PathBuf {
68    get_credentials_dir().join(PathBuf::from(SYSTEMD_CREDS_CREDENTIALS_FILE))
69}
70
71/// Creates the directory for administrative credentials.
72///
73/// # Errors
74///
75/// Returns an error if the directory or one of its parents can not be created.
76/// Refer to [`create_dir_all`] for further information on failure scenarios.
77pub fn create_credentials_dir() -> Result<(), Error> {
78    let credentials_dir = get_credentials_dir();
79    create_dir_all(credentials_dir.as_path()).map_err(|source| Error::CreateDirectory {
80        dir: CREDENTIALS_DIR,
81        source,
82    })?;
83
84    // Set the permissions of the credentials directory to `CREDENTIALS_DIR_MODE`.
85    set_permissions(
86        credentials_dir.as_path(),
87        Permissions::from_mode(CREDENTIALS_DIR_MODE),
88    )
89    .map_err(|source| Error::ApplyPermissions {
90        permissions: CREDENTIALS_DIR_MODE,
91        path: credentials_dir.clone(),
92        source,
93    })?;
94
95    // Recursively chown all directories to root, until `DATA_HOME` is
96    // reached.
97    let data_home = get_data_home();
98    let mut chown_dir = credentials_dir.clone();
99    while chown_dir != data_home {
100        chown(&chown_dir, Some(0), Some(0)).map_err(|source| Error::DirChangeOwner {
101            dir: chown_dir.to_path_buf(),
102            system_user: "root".to_string(),
103            source,
104        })?;
105        if let Some(parent) = &chown_dir.parent() {
106            chown_dir = parent.to_path_buf()
107        } else {
108            break;
109        }
110    }
111
112    Ok(())
113}