sn_node_manager/
config.rs

1// Copyright (C) 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use color_eyre::{eyre::eyre, Result};
10use sn_releases::ReleaseType;
11use std::path::PathBuf;
12
13#[cfg(unix)]
14pub fn get_daemon_install_path() -> PathBuf {
15    PathBuf::from("/usr/local/bin/safenodemand")
16}
17
18#[cfg(windows)]
19pub fn get_daemon_install_path() -> PathBuf {
20    PathBuf::from("C:\\ProgramData\\safenodemand\\safenodemand.exe")
21}
22
23#[cfg(unix)]
24pub fn get_node_manager_path() -> Result<PathBuf> {
25    // This needs to be a system-wide location rather than a user directory because the `install`
26    // command will run as the root user. However, it should be readable by non-root users, because
27    // other commands, e.g., requesting status, shouldn't require root.
28    use std::os::unix::fs::PermissionsExt;
29
30    let path = if is_running_as_root() {
31        let path = PathBuf::from("/var/safenode-manager/");
32        debug!("Running as root, creating node_manager_path and setting perms if path doesn't exists: {path:?}");
33        std::fs::create_dir_all(&path)?;
34        let mut perm = std::fs::metadata(&path)?.permissions();
35        perm.set_mode(0o755); // set permissions to rwxr-xr-x
36        std::fs::set_permissions(&path, perm)?;
37        path
38    } else {
39        let path = get_user_safenode_data_dir()?;
40        debug!("Running as non-root, node_manager_path is: {path:?}");
41        path
42    };
43
44    if is_running_as_root() && !path.exists() {
45        std::fs::create_dir_all(&path)?;
46        let mut perm = std::fs::metadata(&path)?.permissions();
47        perm.set_mode(0o755); // set permissions to rwxr-xr-x
48        std::fs::set_permissions(&path, perm)?;
49    }
50
51    Ok(path)
52}
53
54#[cfg(windows)]
55pub fn get_node_manager_path() -> Result<PathBuf> {
56    use std::path::Path;
57    let path = Path::new("C:\\ProgramData\\safenode-manager");
58    debug!("Running as root, creating node_manager_path at: {path:?}");
59
60    if !path.exists() {
61        std::fs::create_dir_all(path)?;
62    }
63    Ok(path.to_path_buf())
64}
65
66#[cfg(unix)]
67pub fn get_node_registry_path() -> Result<PathBuf> {
68    use std::os::unix::fs::PermissionsExt;
69
70    let path = get_node_manager_path()?;
71    let node_registry_path = path.join("node_registry.json");
72    if is_running_as_root() && !node_registry_path.exists() {
73        debug!("Running as root and node_registry_path doesn't exist, creating node_registry_path and setting perms at: {node_registry_path:?}");
74        std::fs::OpenOptions::new()
75            .write(true)
76            .create(true)
77            .truncate(true) // Do not append to the file if it already exists.
78            .open(node_registry_path.clone())?;
79        // Set the permissions of /var/safenode-manager/node_registry.json to rwxrwxrwx. The
80        // `status` command updates the registry with the latest information it has on the
81        // services at the time it runs. It's normally the case that service management status
82        // operations do not require elevated privileges. If we want that to be the case, we
83        // need to give all users the ability to write to the registry file. Everything else in
84        // the /var/safenode-manager directory and its subdirectories will still require
85        // elevated privileges.
86        let mut perm = std::fs::metadata(node_registry_path.clone())?.permissions();
87        perm.set_mode(0o777);
88        std::fs::set_permissions(node_registry_path.clone(), perm)?;
89    }
90    debug!("Node registry path is: {node_registry_path:?}");
91
92    Ok(node_registry_path)
93}
94
95#[cfg(windows)]
96pub fn get_node_registry_path() -> Result<PathBuf> {
97    use std::path::Path;
98    let path = Path::new("C:\\ProgramData\\safenode-manager");
99    if !path.exists() {
100        std::fs::create_dir_all(path)?;
101    }
102    debug!("Node registry path is: {path:?}");
103
104    Ok(path.join("node_registry.json"))
105}
106
107/// Get the data directory for the service.
108///
109/// It's a little counter-intuitive, but the owner will be `None` in the case of a user-mode
110/// service, because it will always run as the current user. The `owner` is really to specify the
111/// non-root user for running a system-wide service.
112#[cfg(unix)]
113pub fn get_service_data_dir_path(
114    custom_path: Option<PathBuf>,
115    owner: Option<String>,
116) -> Result<PathBuf> {
117    let path = match custom_path {
118        Some(p) => {
119            debug!("Using custom path for service data dir: {p:?}");
120            p
121        }
122        None => {
123            if owner.is_some() {
124                let path = PathBuf::from("/var/safenode-manager/services");
125                debug!("Using default path for service data dir: {path:?}");
126                path
127            } else {
128                let path = get_user_safenode_data_dir()?;
129                debug!("Using user mode service data dir: {path:?}");
130                path
131            }
132        }
133    };
134    if let Some(owner) = owner {
135        create_owned_dir(path.clone(), &owner)?;
136    }
137    Ok(path)
138}
139
140#[cfg(windows)]
141pub fn get_service_data_dir_path(
142    custom_path: Option<PathBuf>,
143    _owner: Option<String>,
144) -> Result<PathBuf> {
145    let path = match custom_path {
146        Some(p) => {
147            debug!("Using custom path for service data dir: {p:?}");
148            p
149        }
150        None => {
151            let path = PathBuf::from("C:\\ProgramData\\safenode\\data");
152            debug!("Using default path for service data dir: {path:?}");
153            path
154        }
155    };
156    std::fs::create_dir_all(&path)?;
157    Ok(path)
158}
159
160/// Get the logging directory for the service.
161///
162/// It's a little counter-intuitive, but the owner will be `None` in the case of a user-mode
163/// service, because it will always run as the current user. The `owner` is really to specify the
164/// non-root user for running a system-wide service.
165#[cfg(unix)]
166pub fn get_service_log_dir_path(
167    bin_type: ReleaseType,
168    custom_path: Option<PathBuf>,
169    owner: Option<String>,
170) -> Result<PathBuf> {
171    let path = match custom_path {
172        Some(p) => {
173            debug!("Using custom path for service log dir: {p:?}");
174            p
175        }
176        None => {
177            if owner.is_some() {
178                let path = PathBuf::from("/var/log").join(bin_type.to_string());
179                debug!("Using default path for service log dir: {path:?}");
180                path
181            } else {
182                let path = get_user_safenode_data_dir()?;
183                debug!("Using user mode service log dir: {path:?}");
184                path
185            }
186        }
187    };
188    if let Some(owner) = owner {
189        create_owned_dir(path.clone(), &owner)?;
190    }
191    Ok(path)
192}
193
194#[cfg(windows)]
195pub fn get_service_log_dir_path(
196    bin_type: ReleaseType,
197    custom_path: Option<PathBuf>,
198    _owner: Option<String>,
199) -> Result<PathBuf> {
200    let path = match custom_path {
201        Some(p) => {
202            debug!("Using custom path for service log dir: {p:?}");
203            p
204        }
205        None => {
206            let path = PathBuf::from("C:\\ProgramData")
207                .join(bin_type.to_string())
208                .join("logs");
209            debug!("Using default path for service log dir: {path:?}");
210            path
211        }
212    };
213    std::fs::create_dir_all(&path)?;
214    Ok(path)
215}
216
217#[cfg(unix)]
218pub fn create_owned_dir(path: PathBuf, owner: &str) -> Result<()> {
219    debug!("Creating owned dir and setting permissions: {path:?} with owner: {owner}");
220    use nix::unistd::{chown, Gid, Uid};
221    use std::os::unix::fs::PermissionsExt;
222    use users::get_user_by_name;
223
224    std::fs::create_dir_all(&path)?;
225    let permissions = std::fs::Permissions::from_mode(0o755);
226    std::fs::set_permissions(&path, permissions)?;
227
228    let user = get_user_by_name(owner).ok_or_else(|| {
229        error!("User '{owner}' does not exist");
230        eyre!("User '{owner}' does not exist")
231    })?;
232    let uid = Uid::from_raw(user.uid());
233    let gid = Gid::from_raw(user.primary_group_id());
234    chown(&path, Some(uid), Some(gid))?;
235    Ok(())
236}
237
238#[cfg(windows)]
239pub fn create_owned_dir(path: PathBuf, _owner: &str) -> Result<()> {
240    debug!("Creating owned dir: {path:?}");
241    std::fs::create_dir_all(path)?;
242    Ok(())
243}
244
245#[cfg(unix)]
246pub fn is_running_as_root() -> bool {
247    use nix::unistd::geteuid;
248    geteuid().is_root()
249}
250
251#[cfg(windows)]
252pub fn is_running_as_root() -> bool {
253    // Example: Attempt to read from a typically restricted system directory
254    std::fs::read_dir("C:\\Windows\\System32\\config").is_ok()
255}
256
257pub fn get_user_safenode_data_dir() -> Result<PathBuf> {
258    Ok(dirs_next::data_dir()
259        .ok_or_else(|| {
260            error!("Failed to get data_dir");
261            eyre!("Could not obtain user data directory")
262        })?
263        .join("safe")
264        .join("node"))
265}