Skip to main content

running_process/
daemon_registration_common.rs

1//! Shared internals for the independently selectable registration writers.
2//!
3//! This is deliberately crate-private. The v1 and v2 public modules each
4//! expose their established public paths, while both retain one canonical
5//! validation, error, default-directory, and owner-private-directory
6//! implementation.
7
8#[path = "daemon_registration/validation.rs"]
9pub(crate) mod validation;
10
11#[path = "broker/secure_dir.rs"]
12pub(crate) mod secure_dir;
13
14pub(crate) mod service_definition {
15    use std::io;
16    use std::path::{Path, PathBuf};
17
18    use super::{secure_dir, validation::PipePathError};
19
20    /// Environment override for tests and development.
21    #[cfg(feature = "daemon-registration")]
22    pub const SERVICE_DEF_DIR_ENV: &str = "RUNNING_PROCESS_SERVICE_DEF_DIR";
23
24    /// Return the platform service-definition directory.
25    #[must_use]
26    pub fn service_definition_dir() -> PathBuf {
27        // An empty value is not a directory. It used to yield `PathBuf::from("")`,
28        // which resolves relative to the working directory -- so `…SERVICE_DEF_DIR=`
29        // silently moved service-definition lookup to wherever the broker happened
30        // to be started from, while `config --effective` still reported an override.
31        if let Some(path) = crate::env_vars::SERVICE_DEF_DIR.path() {
32            return path;
33        }
34
35        // Where a host keeps a product's configuration is a role `platform::fs`
36        // names; this used to spell out all three answers. Config is deliberately
37        // not the data root: Windows separates roaming settings from local data,
38        // and XDG gives configuration its own base directory.
39        crate::platform::fs::user_config_dir("running-process").join("services")
40    }
41
42    /// Ensure a service-definition directory exists with private permissions.
43    pub fn ensure_service_definition_dir(path: &Path) -> Result<(), ServiceDefinitionError> {
44        secure_dir::ensure_private_dir(path)?;
45        ensure_loadable_service_definition_dir(path)
46    }
47
48    /// Errors returned while loading or writing service-definition files.
49    #[derive(Debug, thiserror::Error)]
50    pub enum ServiceDefinitionError {
51        /// Filesystem operation failed.
52        #[error("service-definition I/O failed: {0}")]
53        Io(#[from] io::Error),
54        /// Protobuf decode failed.
55        #[error("service-definition protobuf decode failed: {0}")]
56        Decode(#[from] prost::DecodeError),
57        /// Name or version validation failed.
58        #[error(transparent)]
59        InvalidName(#[from] PipePathError),
60        /// Directory permissions are too broad.
61        #[error("service-definition directory has insecure permissions: {0}")]
62        InsecureDirectory(PathBuf),
63        /// File content did not match the requested service.
64        #[error("service-definition requested {requested:?} but file declares {actual:?}")]
65        ServiceNameMismatch {
66            /// Service name requested by the Hello path.
67            requested: String,
68            /// Service name decoded from disk.
69            actual: String,
70        },
71        /// A path field was empty or relative.
72        #[error("service-definition {field} is invalid: {path:?} ({reason})")]
73        InvalidPath {
74            /// Field name.
75            field: &'static str,
76            /// Field value.
77            path: String,
78            /// Why it failed validation.
79            reason: &'static str,
80        },
81        /// Isolation fields were inconsistent.
82        #[error("service-definition isolation is invalid: {reason}")]
83        InvalidIsolation {
84            /// Why it failed validation.
85            reason: &'static str,
86        },
87    }
88
89    fn ensure_loadable_service_definition_dir(path: &Path) -> Result<(), ServiceDefinitionError> {
90        if !secure_dir::private_dir_permissions_are_private(path)? {
91            return Err(ServiceDefinitionError::InsecureDirectory(
92                path.to_path_buf(),
93            ));
94        }
95        Ok(())
96    }
97}