diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp index e69de29..2e5a20a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -0,0 +1,145 @@ +#include <algorithm> +#include <cerrno> +#include <charconv> +#include <cstdint> +#include <cstring> +#include <expected> +#include <filesystem> +#include <iostream> +#include <optional> +#include <ostream> +#include <security-context-v1-client-protocol.h> +#include <string_view> +#include <sys/socket.h> +#include <sys/un.h> +#include <system_error> +#include <wayland-client-core.h> +#include <wayland-client-protocol.h> +#include <wayland-client.h> + +struct App { + std::optional<wl_display *> display; + std::optional<wl_registry *> registry; + std::optional<wp_security_context_v1 *> security_context; + std::optional<wp_security_context_manager_v1 *> security_context_manager; +}; + +void register_global(void *data, wl_registry *registry, std::uint32_t name, + const char *interface, std::uint32_t version) { + std::println(std::cerr, "global advertised: {}", interface); + + App *app = static_cast<App *>(data); + + if (std::strcmp(interface, wp_security_context_manager_v1_interface.name) == + 0) { + app->security_context_manager = + static_cast<wp_security_context_manager_v1 *>(wl_registry_bind( + registry, name, &wp_security_context_manager_v1_interface, + version)); + } +} + +void unregister_global([[gnu::unused]] void *data, + [[gnu::unused]] wl_registry *registry, + [[gnu::unused]] std::uint32_t name) {} + +struct wl_registry_listener listener = {.global = register_global, + .global_remove = unregister_global}; + +std::optional<int> parse_int(std::string_view string) { + int number; + + auto [ptr, err] = + std::from_chars(string.data(), string.data() + string.size(), number); + + if (!(err == std::errc{})) { + return std::nullopt; + } + + return number; +} + +std::expected<int, int> open_socket(const std::filesystem::path &socket_path) { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + sockaddr_un address = {.sun_family = AF_UNIX, .sun_path = "\0"}; + auto len = + std::min(sizeof(address.sun_path), std::strlen(socket_path.c_str())); + + std::copy_n(socket_path.c_str(), len, address.sun_path); + + if (bind(fd, reinterpret_cast<sockaddr *>(&address), + sizeof(address.sun_path)) == -1) { + return std::unexpected{errno}; + } + + if (listen(fd, 20) == -1) { + return std::unexpected{errno}; + } + + return fd; +} + +int main(int argc, char **argv) { + if (argc < 2) { + std::println( + std::cerr, + "usage: wayland-sandbox <path to unix socket> <file descriptor>"); + return 1; + } + + std::filesystem::path socket_path(argv[1]); + if (std::filesystem::exists(socket_path)) { + std::println(std::cerr, "socket already exists: {}", argv[1]); + return 1; + } + + auto parse_fd_result = parse_int(argv[2]); + if (!parse_fd_result) { + std::println(std::cerr, "failed to parse fd: {}", argv[2]); + return 1; + } + + int close_fd = parse_fd_result.value(); + + App app; + + app.display = wl_display_connect(NULL); + + std::println(std::cerr, "connected to compositor"); + + if (!app.display.value()) { + std::println(std::cerr, "failed to connect to compositor"); + return 1; + } + + app.registry = wl_display_get_registry(app.display.value()); + wl_registry_add_listener(app.registry.value(), &listener, &app); + wl_display_roundtrip(app.display.value()); + + if (!app.security_context_manager.has_value()) { + std::println(std::cerr, "failed to bind security context manager"); + } + + auto open_socket_result = open_socket(socket_path); + + if (!open_socket_result) { + std::println(std::cerr, "failed to open socket: {}", + std::strerror(open_socket_result.error())); + return 1; + } + + auto sockfd = open_socket_result.value(); + + std::println(std::cerr, "opened socket: {}", socket_path.c_str()); + + app.security_context = wp_security_context_manager_v1_create_listener( + app.security_context_manager.value(), sockfd, close_fd); + + wp_security_context_v1_set_sandbox_engine(app.security_context.value(), + "wayland-sandbox"); + wp_security_context_v1_commit(app.security_context.value()); + + wl_display_roundtrip(app.display.value()); + + return 0; +} |