aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp217
1 files changed, 134 insertions, 83 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 36226c7..7cc8d13 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -134,13 +134,16 @@ void print_help(const char *prog) {
}
void die_usage_generate(const char *prog) {
- err("Usage: %s generate [ -h ] [ -k KEYPATH ] [ -t { network, netdev, keyfile, nft } ] CONFIG_FILE", prog);
+ err("Usage: %s generate [ -h ] [ -k KEYPATH ] [ -t { network, netdev, keyfile, nft } ] [ -a ACTIVATION_POLICY ] CONFIG_FILE\n", prog);
die("Use -h for help");
}
void print_help_generate(const char *prog) {
- err("Usage: %s generate [ -h ] [ -k KEYPATH ] [ -t { network, netdev, keyfile, nft } ] CONFIG_FILE\n", prog);
+ err("Usage: %s generate [ -h ] [ -a ACTIVATION_POLICY ] [ -k KEYPATH ] [ -t { network, netdev, keyfile, nft } ] CONFIG_FILE\n", prog);
err("Options:");
+ err(" -a ACTIVATION_POLICY");
+ err(" manual Require manual activation (default)");
+ err(" up Automatically set the link \"up\"\n");
err(" -t FILE_TYPE");
err(" network Generate a Network Configuration File (see systemd.network(8))");
err(" netdev Generate a Virtual Device File (see systemd.netdev(8))");
@@ -153,12 +156,12 @@ void print_help_generate(const char *prog) {
}
void die_usage_install(const char *prog) {
- err("Usage: %s install [ -h ] [ -f FILE_NAME ] [ -k KEYFILE ] [ -o OUTPUT_PATH ] CONFIG_FILE", prog);
+ err("Usage: %s install [ -h ] [ -a ACTIVATION_POLICY ] [ -f FILE_NAME ] [ -o OUTPUT_PATH ] CONFIG_FILE\n", prog);
die("Use -h for help");
}
void print_help_install(const char *prog) {
- err("Usage: %s install [ -h ] [ -f FILE_NAME ] [ -o OUTPUT_PATH ] CONFIG_FILE\n", prog);
+ err("Usage: %s install [ -h ] [ -a ACTIVATION_POLICY ] [ -f FILE_NAME ] [ -o OUTPUT_PATH ] CONFIG_FILE\n", prog);
err(" `wg2nd install` translates `wg-quick(8)` configuration into corresponding");
err(" `networkd` configuration and installs the resulting files in `OUTPUT_PATH`.\n");
err(" `wg2nd install` generates a `netdev`, `network`, and `keyfile` for each");
@@ -170,6 +173,9 @@ void print_help_install(const char *prog) {
err(" with `wg2nd install`. The equivalent firewall can be generated with");
err(" `wg2nd generate -t nft CONFIG_FILE`.\n");
err("Options:");
+ err(" -a ACTIVATION_POLICY");
+ err(" manual Require manual activation (default)");
+ err(" up Automatically set the link \"up\"\n");
err(" -o OUTPUT_PATH The installation path (default is /etc/systemd/network)\n");
err(" -f FILE_NAME The base name for the installed configuration files. The");
err(" networkd-specific configuration suffix will be added");
@@ -211,7 +217,7 @@ enum class FileType {
using namespace wg2nd;
-void write_systemd_file(SystemdFilespec const & filespec, std::string output_path, bool secure) {
+static void write_systemd_file(SystemdFilespec const & filespec, std::string output_path, bool secure) {
std::string full_path = output_path + "/" + filespec.name;
std::ofstream ofs;
@@ -254,10 +260,11 @@ void write_systemd_file(SystemdFilespec const & filespec, std::string output_pat
}
}
-SystemdConfig generate_cfg_or_die(
+static SystemdConfig generate_cfg_or_die(
std::filesystem::path && config_path,
std::filesystem::path const & keyfile_or_output_path,
- std::optional<std::string> const & filename
+ std::optional<std::string> const & filename,
+ ActivationPolicy activation_policy
) {
std::fstream cfg_stream { config_path, std::ios_base::in };
@@ -270,7 +277,13 @@ SystemdConfig generate_cfg_or_die(
std::string interface_name = interface_name_from_filename(config_path);
try {
- cfg = wg2nd::wg2nd(interface_name, cfg_stream, keyfile_or_output_path, filename);
+ cfg = wg2nd::wg2nd(
+ interface_name,
+ cfg_stream,
+ keyfile_or_output_path,
+ filename,
+ activation_policy
+ );
} catch(ConfigurationException const & cex) {
const ParsingException * pex = dynamic_cast<const ParsingException *>(&cex);
@@ -286,8 +299,9 @@ SystemdConfig generate_cfg_or_die(
}
-void wg2nd_install_internal(std::optional<std::string> && filename, std::string && keyfile_name,
- std::filesystem::path && output_path, std::filesystem::path && config_path) {
+static void wg2nd_install_internal(std::optional<std::string> && filename, std::string && keyfile_name,
+ std::filesystem::path && output_path, std::filesystem::path && config_path,
+ ActivationPolicy activation_policy) {
if(!std::filesystem::path(output_path).is_absolute()) {
output_path = std::filesystem::absolute(output_path);
@@ -299,7 +313,12 @@ void wg2nd_install_internal(std::optional<std::string> && filename, std::string
keyfile_or_output_path /= keyfile_name;
}
- SystemdConfig cfg = generate_cfg_or_die(std::move(config_path), keyfile_or_output_path, std::move(filename));
+ SystemdConfig cfg = generate_cfg_or_die(
+ std::move(config_path),
+ keyfile_or_output_path,
+ std::move(filename),
+ activation_policy
+ );
for(std::string const & warning : cfg.warnings) {
err("warning: %s", warning.c_str());
@@ -314,11 +333,15 @@ void wg2nd_install_internal(std::optional<std::string> && filename, std::string
}
}
-void wg2nd_generate_internal(FileType type, std::string && config_file,
- std::optional<std::filesystem::path> && keyfile_path) {
+static void wg2nd_generate_internal(FileType type, std::string && config_file,
+ std::optional<std::filesystem::path> && keyfile_path,
+ ActivationPolicy activation_policy) {
SystemdConfig cfg = generate_cfg_or_die(
- std::move(config_file), std::move(keyfile_path.value_or(DEFAULT_OUTPUT_PATH)), {}
+ std::move(config_file),
+ std::move(keyfile_path.value_or(DEFAULT_OUTPUT_PATH)),
+ {},
+ activation_policy
);
switch(type) {
@@ -339,15 +362,79 @@ void wg2nd_generate_internal(FileType type, std::string && config_file,
}
}
+#ifdef HAVE_LIBCAP
+
+// Drop excess capabilities and ensure the process have proper capabilities upfront
+static void drop_excess_capabilities(std::vector<cap_value_t> cap_required) {
+
+ cap_t current_cap = cap_get_proc();
+ cap_t wanted_cap = cap_get_proc();
+
+ if(!current_cap || !wanted_cap) {
+ goto die_cap_failure;
+ }
+
+ if(cap_clear(wanted_cap)) {
+ goto die_cap_failure;
+ }
+
+ // Add required capabilities to the wanted set
+ for(cap_value_t cap : cap_required) {
+ cap_flag_value_t is_set;
+
+ // Print nice error message if the user does not have the required permissions
+ if(cap_get_flag(current_cap, cap, CAP_PERMITTED, &is_set)) {
+ goto die_cap_failure;
+ }
+
+ if(is_set != CAP_SET) {
+ char * name = cap_to_name(cap);
+ die("Failed to obtain capability \"%s\": do you need to elevate permissions?", name);
+ }
+
+ if(cap_set_flag(wanted_cap, CAP_PERMITTED, 1, &cap, CAP_SET)) {
+ goto die_cap_failure;
+ }
+
+ if(cap_set_flag(wanted_cap, CAP_EFFECTIVE, 1, &cap, CAP_SET)) {
+ goto die_cap_failure;
+ }
+ }
+
+ if(cap_set_proc(wanted_cap)) {
+ goto die_cap_failure;
+ }
+
+ if(cap_free(wanted_cap) || cap_free(current_cap)) {
+ goto die_cap_failure;
+ }
+
+ return;
+
+die_cap_failure:
+ die_errno("Failed to drop capabilities");
+}
+#endif /* HAVE_LIBCAP */
+
+static ActivationPolicy activation_policy_from_argument(std::string const & arg) {
+ if(arg == "manual") {
+ return ActivationPolicy::MANUAL;
+ } else if (arg == "up") {
+ return ActivationPolicy::UP;
+ } else {
+ die("Unknown activation policy: \"%s\"", arg.c_str());
+ }
+}
static int wg2nd_generate(char const * prog, int argc, char **argv) {
std::filesystem::path config_path = "";
FileType type = FileType::NONE;
std::optional<std::filesystem::path> keyfile_path = {};
+ ActivationPolicy activation_policy = ActivationPolicy::MANUAL;
int opt;
- while ((opt = getopt(argc, argv, "ht:k:")) != -1) {
+ while ((opt = getopt(argc, argv, "ht:k:a:")) != -1) {
switch (opt) {
case 't':
if (strcmp(optarg, "network") == 0) {
@@ -365,6 +452,9 @@ static int wg2nd_generate(char const * prog, int argc, char **argv) {
case 'k':
keyfile_path = optarg;
break;
+ case 'a':
+ activation_policy = activation_policy_from_argument(optarg);
+ break;
case 'h':
print_help_generate(prog);
break;
@@ -377,9 +467,18 @@ static int wg2nd_generate(char const * prog, int argc, char **argv) {
die_usage_generate(prog);
}
+#ifdef HAVE_LIBCAP
+ drop_excess_capabilities({});
+#endif /* HAVE_LIBCAP */
+
config_path = argv[optind];
- wg2nd_generate_internal(type, std::move(config_path), std::move(keyfile_path));
+ wg2nd_generate_internal(
+ type,
+ std::move(config_path),
+ std::move(keyfile_path),
+ activation_policy
+ );
return 0;
}
@@ -390,9 +489,10 @@ static int wg2nd_install(char const * prog, int argc, char **argv) {
std::optional<std::string> filename = {};
std::filesystem::path output_path = DEFAULT_OUTPUT_PATH;
std::string keyfile_name = "";
+ ActivationPolicy activation_policy = ActivationPolicy::MANUAL;
int opt;
- while ((opt = getopt(argc, argv, "o:f:k:h")) != -1) {
+ while ((opt = getopt(argc, argv, "o:f:k:a:h")) != -1) {
switch (opt) {
case 'o': {
std::string path = optarg;
@@ -411,6 +511,9 @@ static int wg2nd_install(char const * prog, int argc, char **argv) {
case 'k':
keyfile_name = optarg;
break;
+ case 'a':
+ activation_policy = activation_policy_from_argument(optarg);
+ break;
default:
die_usage_install(prog);
}
@@ -420,66 +523,25 @@ static int wg2nd_install(char const * prog, int argc, char **argv) {
die_usage_install(prog);
}
- config_path = argv[optind];
-
- wg2nd_install_internal(std::move(filename), std::move(keyfile_name), std::move(output_path), std::move(config_path));
-
- return 0;
-}
-
#ifdef HAVE_LIBCAP
+ drop_excess_capabilities({{
+ CAP_CHOWN,
+ CAP_DAC_OVERRIDE
+ }});
+#endif /* HAVE_LIBCAP */
-// Drop excess capabilities and ensure the process have proper capabilities upfront
-void drop_excess_capabilities(std::vector<cap_value_t> cap_required) {
-
- cap_t current_cap = cap_get_proc();
- cap_t wanted_cap = cap_get_proc();
-
- if(!current_cap || !wanted_cap) {
- goto die_cap_failure;
- }
-
- if(cap_clear(wanted_cap)) {
- goto die_cap_failure;
- }
-
- // Add required capabilities to the wanted set
- for(cap_value_t cap : cap_required) {
- cap_flag_value_t is_set;
-
- // Print nice error message if the user does not have the required permissions
- if(cap_get_flag(current_cap, cap, CAP_PERMITTED, &is_set)) {
- goto die_cap_failure;
- }
-
- if(is_set != CAP_SET) {
- char * name = cap_to_name(cap);
- die("Failed to obtain capability \"%s\": do you need to elevate permissions?", name);
- }
-
- if(cap_set_flag(wanted_cap, CAP_PERMITTED, 1, &cap, CAP_SET)) {
- goto die_cap_failure;
- }
-
- if(cap_set_flag(wanted_cap, CAP_EFFECTIVE, 1, &cap, CAP_SET)) {
- goto die_cap_failure;
- }
- }
-
- if(cap_set_proc(wanted_cap)) {
- goto die_cap_failure;
- }
-
- if(cap_free(wanted_cap) || cap_free(current_cap)) {
- goto die_cap_failure;
- }
+ config_path = argv[optind];
- return;
+ wg2nd_install_internal(
+ std::move(filename),
+ std::move(keyfile_name),
+ std::move(output_path),
+ std::move(config_path),
+ activation_policy
+ );
-die_cap_failure:
- die_errno("Failed to drop capabilities");
+ return 0;
}
-#endif /* HAVE_LIBCAP */
int main(int argc, char **argv) {
char const * prog = "wg2nd";
@@ -494,17 +556,6 @@ int main(int argc, char **argv) {
std::string action = argv[1];
-#ifdef HAVE_LIBCAP
- std::vector<cap_value_t> required_caps;
-
- if(action == "install") {
- required_caps.push_back(CAP_CHOWN);
- required_caps.push_back(CAP_DAC_OVERRIDE);
- }
-
- drop_excess_capabilities(required_caps);
-#endif /* HAVE_LIBCAP */
-
if (action == "generate") {
return wg2nd_generate(prog, argc - 1, argv + 1);
} else if (action == "install") {