/* * This source code is released into the public domain. */ #include "exec.hh" #include "jail.hh" #include "generic_error.hh" #include "fileutils.hh" #include "jail_zfs.hh" #include "spawn.hh" namespace { using namespace lfjail; // Get the jails storage directory. auto get_jails_dir(context const &ctx) -> std::filesystem::path { return ctx.dbdir / "jails"; } // Get the config file for a jail. auto jail_config_file(context const &ctx, std::string_view jailname) -> std::filesystem::path { return get_jails_dir(ctx) / jailname; } // Make sure our jails config path exists. void ensure_jails_dir(context const &ctx) { ensure_dir(ctx, get_jails_dir(ctx)); } } // anonymous namespace namespace lfjail { auto get_jail_config(context const &ctx, std::string_view jailname) -> std::optional { ensure_jails_dir(ctx); auto file = jail_config_file(ctx, jailname); // Load the configuration text. std::string config_text; try { read_file(file, std::back_inserter(config_text)); } catch (io_error const &exc) { if (exc.error == std::errc::no_such_file_or_directory) return {}; throw; } // Parse the UCL. std::string err; auto uclconfig = ucl::Ucl::parse(config_text, err); jail ret; ret.name = jailname; if (!uclconfig) throw generic_error("{0}: {1}", file, err); for (auto const &uclvalue : uclconfig) { throw generic_error("{}: unknown option '{}'", file, uclvalue.key()); } return {ret}; } void set_jail_config(context const &ctx, jail const &jailconf) { // The UCL C++ API doesn't seem to support creating new objects // from scratch, so we use the C API here. auto ucl = ::ucl_object_typed_new(UCL_OBJECT); auto ucl_guard = guard([ucl] { ::ucl_object_unref(ucl); }); // We could add some jail options here... // Dump the UCL object to a string. auto *ucl_c_text = reinterpret_cast( ::ucl_object_emit(ucl, UCL_EMIT_CONFIG)); //NOLINTNEXTLINE(cppcoreguidelines-no-malloc) auto ucl_text_guard = guard([ucl_c_text] { ::free(ucl_c_text); }); std::string ucl_text(ucl_c_text); // Write the object to a file. auto file = jail_config_file(ctx, jailconf.name); safe_write_file(file, ucl_text); } auto jail_exists(context const &ctx, std::string_view name) -> bool { return static_cast(get_jail_config(ctx, name)); } void jail_destroy(context const &ctx, jail const &jailconf) { auto file = jail_config_file(ctx, jailconf.name); ::unlink(file.c_str()); zfs::destroy_for_jail(ctx, jailconf); } void jail_install(context const &, jail const &jailconf) { auto executor = exec::execl("/usr/sbin/pkg", "pkg", "-r", jailconf.root_path, "install", "-y", "FreeBSD-runtime", "FreeBSD-utilities", "FreeBSD-periodic", "FreeBSD-rc", "FreeBSD-syslogd", "FreeBSD-newsyslog", "FreeBSD-pkg-bootstrap", "pkg"); auto output = std::string(); auto ret = spawn(std::move(executor), capture(STDOUT_FILENO, output)).wait(); if (!ret) throw generic_error("pkg install failed"); } } // namespace lfjail