From 5bb011bafb4d84598c69928e62407a95cf7b9547 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 30 Aug 2024 17:03:50 +0200 Subject: [PATCH] Make the config prefix build time configurable --- README.md | 4 +++ build.sh | 1 + letmein-conf/src/lib.rs | 53 +++++++++++++++++++++++++++++------- letmein/src/command/knock.rs | 7 +++-- letmein/src/main.rs | 4 +-- letmeind/src/main.rs | 4 +-- letmeinfwd/src/main.rs | 4 +-- 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e2f137e..0850f5e 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,10 @@ Installing the server will also install the service and socket into systemd and The server is used to receive knock packets from the client. Upon successful knock authentication, the server will open the knocked port in its `nftables` firewall. +## Crates.io: Installing with `cargo install` from crates.io + +TODO + ## Arch Linux: Installing from AUR If you use [Arch Linux](https://archlinux.org/), then you can install the client and the server from [AUR](https://aur.archlinux.org/packages/letmein). diff --git a/build.sh b/build.sh index 45f1f26..4178979 100755 --- a/build.sh +++ b/build.sh @@ -47,6 +47,7 @@ check_dynlibs() [ -f "$basedir/Cargo.toml" ] || die "basedir sanity check failed" cd "$basedir" || die "cd basedir failed." +export LETMEIN_CONF_PREFIX="/opt/letmein" cargo build || die "Cargo build (debug) failed." cargo test || die "Cargo test failed." cargo auditable build --release || die "Cargo build (release) failed." diff --git a/letmein-conf/src/lib.rs b/letmein-conf/src/lib.rs index ab24e28..e17eab7 100644 --- a/letmein-conf/src/lib.rs +++ b/letmein-conf/src/lib.rs @@ -19,23 +19,21 @@ mod ini; use crate::ini::Ini; use anyhow::{self as ah, format_err as err, Context as _}; use letmein_proto::{Key, ResourceId, UserId, PORT}; -use std::{collections::HashMap, path::Path, time::Duration}; - -/// The default install prefix. -#[cfg(not(target_os = "windows"))] -pub const INSTALL_PREFIX: &str = "/opt/letmein"; -#[cfg(target_os = "windows")] -pub const INSTALL_PREFIX: &str = ""; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + time::Duration, +}; /// The default server configuration path, relative to the install prefix. #[cfg(not(target_os = "windows"))] -pub const SERVER_CONF_PATH: &str = "/etc/letmeind.conf"; +const SERVER_CONF_PATH: &str = "etc/letmeind.conf"; /// The default client configuration path, relative to the install prefix. #[cfg(not(target_os = "windows"))] -pub const CLIENT_CONF_PATH: &str = "/etc/letmein.conf"; +const CLIENT_CONF_PATH: &str = "etc/letmein.conf"; #[cfg(target_os = "windows")] -pub const CLIENT_CONF_PATH: &str = "letmein.conf"; +const CLIENT_CONF_PATH: &str = "letmein.conf"; const DEFAULT_NFT_TIMEOUT: u32 = 600; @@ -329,6 +327,7 @@ pub enum ConfigVariant { #[derive(Clone, Default, Debug)] pub struct Config { variant: ConfigVariant, + path: Option, debug: bool, port: u16, seccomp: Seccomp, @@ -352,6 +351,39 @@ impl Config { } } + /// Get the default configuration file path. + pub fn get_default_path(variant: ConfigVariant) -> PathBuf { + // The build-time environment variable LETMEIN_CONF_PREFIX can be + // used to give an additional prefix. + let prefix = match option_env!("LETMEIN_CONF_PREFIX") { + Some(env_prefix) => env_prefix, + None => { + #[cfg(not(target_os = "windows"))] + let prefix = "/"; + #[cfg(target_os = "windows")] + let prefix = ""; + prefix + } + }; + + let mut path = PathBuf::new(); + path.push(prefix); + match variant { + ConfigVariant::Client => { + path.push(CLIENT_CONF_PATH); + } + ConfigVariant::Server => { + path.push(SERVER_CONF_PATH); + } + } + path + } + + /// Get the actual path the configuration was read from. + pub fn get_path(&self) -> Option<&Path> { + self.path.as_deref() + } + /// (Re-)load a configuration from a file. pub fn load(&mut self, path: &Path) -> ah::Result<()> { if let Ok(ini) = Ini::new_from_file(path) { @@ -359,6 +391,7 @@ impl Config { } else if self.variant == ConfigVariant::Server { return Err(err!("Failed to load configuration {path:?}")); } + self.path = Some(path.to_path_buf()); Ok(()) } diff --git a/letmein/src/command/knock.rs b/letmein/src/command/knock.rs index cf481ba..242d3c9 100644 --- a/letmein/src/command/knock.rs +++ b/letmein/src/command/knock.rs @@ -13,7 +13,7 @@ use crate::{ use anyhow::{self as ah, format_err as err, Context as _}; use letmein_conf::Config; use letmein_proto::{Key, Message, Operation, ResourceId, UserId}; -use std::sync::Arc; +use std::{path::Path, sync::Arc}; #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] pub enum AddrMode { @@ -118,13 +118,14 @@ pub async fn run_knock( knock_port: u16, user: Option, ) -> ah::Result<()> { + let confpath = conf.get_path().unwrap_or(Path::new("")); let user = user.unwrap_or_else(|| conf.default_user()); let Some(key) = conf.key(user) else { - return Err(err!("No key found in letmein.conf for user {user}")); + return Err(err!("No key found in {confpath:?} for user {user}")); }; let Some(resource) = conf.resource_id_by_port(knock_port, Some(user)) else { return Err(err!( - "Port {knock_port} is not mapped to a resource in letmein.conf" + "Port {knock_port} is not mapped to a resource in {confpath:?}" )); }; let server_port = server_port.unwrap_or_else(|| conf.port()); diff --git a/letmein/src/main.rs b/letmein/src/main.rs index ee189e7..463fff1 100644 --- a/letmein/src/main.rs +++ b/letmein/src/main.rs @@ -15,7 +15,7 @@ mod resolver; use crate::command::{genkey::run_genkey, knock::run_knock}; use anyhow::{self as ah, Context as _}; use clap::{Parser, Subcommand}; -use letmein_conf::{Config, ConfigVariant, CLIENT_CONF_PATH, INSTALL_PREFIX}; +use letmein_conf::{Config, ConfigVariant}; use letmein_proto::UserId; use std::{path::PathBuf, sync::Arc}; @@ -38,7 +38,7 @@ impl Opts { if let Some(config) = &self.config { config.clone() } else { - format!("{INSTALL_PREFIX}{CLIENT_CONF_PATH}").into() + Config::get_default_path(ConfigVariant::Client) } } } diff --git a/letmeind/src/main.rs b/letmeind/src/main.rs index a459484..b681454 100644 --- a/letmeind/src/main.rs +++ b/letmeind/src/main.rs @@ -18,7 +18,7 @@ mod server; use crate::{protocol::Protocol, server::Server}; use anyhow::{self as ah, format_err as err, Context as _}; use clap::Parser; -use letmein_conf::{Config, ConfigVariant, Seccomp, INSTALL_PREFIX, SERVER_CONF_PATH}; +use letmein_conf::{Config, ConfigVariant, Seccomp}; use letmein_seccomp::{seccomp_supported, Filter as SeccompFilter}; use std::{ fs::{create_dir_all, metadata, OpenOptions}, @@ -130,7 +130,7 @@ impl Opts { if let Some(config) = &self.config { config.clone() } else { - format!("{INSTALL_PREFIX}{SERVER_CONF_PATH}").into() + Config::get_default_path(ConfigVariant::Server) } } } diff --git a/letmeinfwd/src/main.rs b/letmeinfwd/src/main.rs index eb36db4..ed31b47 100644 --- a/letmeinfwd/src/main.rs +++ b/letmeinfwd/src/main.rs @@ -20,7 +20,7 @@ use crate::{ }; use anyhow::{self as ah, format_err as err, Context as _}; use clap::Parser; -use letmein_conf::{Config, ConfigVariant, INSTALL_PREFIX, SERVER_CONF_PATH}; +use letmein_conf::{Config, ConfigVariant}; use std::{ fs::{create_dir_all, metadata, set_permissions, OpenOptions}, io::Write as _, @@ -155,7 +155,7 @@ impl Opts { if let Some(config) = &self.config { config.clone() } else { - format!("{INSTALL_PREFIX}{SERVER_CONF_PATH}").into() + Config::get_default_path(ConfigVariant::Server) } } }