apio
ac260d0397
All checks were successful
Build and test / build (push) Successful in 1m42s
This segments privileges more, making it so that any app connecting to wsys.sock can't just always access every single advanced feature in wind if they don't need to. Of course, apps have to restrict themselves, which is why only privileged apps have access to this feature in the first place. Normal apps' pledges are all empty and can't be changed. An example: taskbar uses the "ExtendedLayers" pledge to move its window to the background, but relinquishes it afterwards, and doesn't need any other advanced feature for now. If a pledge-capable app tries to use a pledge-protected function without having pledged anything, it can't. Pledges are mandatory if you want to access certain functionality, unlike the kernel's pledges which make every syscall available if you don't use pledge().
177 lines
5.9 KiB
C++
177 lines
5.9 KiB
C++
#include "Client.h"
|
|
#include "Keyboard.h"
|
|
#include "Layer.h"
|
|
#include "Mouse.h"
|
|
#include "Screen.h"
|
|
#include "Window.h"
|
|
#include <errno.h>
|
|
#include <moon/Keyboard.h>
|
|
#include <os/ArgumentParser.h>
|
|
#include <os/File.h>
|
|
#include <os/IPC.h>
|
|
#include <os/LocalServer.h>
|
|
#include <os/Process.h>
|
|
#include <os/Security.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
static constexpr uid_t WIND_USER_ID = 2;
|
|
static constexpr gid_t WIND_GROUP_ID = 2;
|
|
static constexpr gid_t WSYS_GROUP_ID = 3;
|
|
|
|
Result<int> luna_main(int argc, char** argv)
|
|
{
|
|
srand((unsigned)time(NULL));
|
|
|
|
TRY(os::Security::pledge("stdio rpath wpath cpath unix tty id", NULL));
|
|
|
|
StringView socket_path = "/tmp/wind.sock";
|
|
StringView system_socket_path = "/tmp/wsys.sock";
|
|
|
|
os::ArgumentParser parser;
|
|
parser.add_description("The display server for Luna's graphical user interface."_sv);
|
|
parser.add_system_program_info("wind"_sv);
|
|
parser.add_value_argument(socket_path, 's', "socket"_sv, "the path for the local IPC socket"_sv);
|
|
parser.add_value_argument(system_socket_path, ' ', "system-socket"_sv,
|
|
"the path for the system IPC socket, for privileged clients"_sv);
|
|
parser.parse(argc, argv);
|
|
|
|
if (geteuid() != 0)
|
|
{
|
|
os::eprintln("error: wind must be run as root to initialize resources, the server will drop "
|
|
"privileges automatically afterwards");
|
|
return 1;
|
|
}
|
|
|
|
auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly));
|
|
mouse->set_buffer(os::File::NotBuffered);
|
|
mouse->set_close_on_exec();
|
|
|
|
auto keyboard = TRY(os::File::open("/dev/kbd", os::File::ReadOnly));
|
|
keyboard->set_buffer(os::File::NotBuffered);
|
|
keyboard->set_close_on_exec();
|
|
|
|
TRY(Screen::open());
|
|
auto& screen = Screen::the();
|
|
|
|
Mouse mouse_pointer { screen.canvas() };
|
|
|
|
umask(0002);
|
|
|
|
// Set permissions to wind:wsys temporarily, to create /tmp/wsys.sock with those privileges.
|
|
setegid(WSYS_GROUP_ID);
|
|
seteuid(WIND_USER_ID);
|
|
|
|
auto system_server = TRY(os::LocalServer::create(system_socket_path, false));
|
|
TRY(system_server->listen(20));
|
|
|
|
seteuid(0);
|
|
|
|
// Opened all necessary files as root, drop privileges now.
|
|
setgid(WIND_GROUP_ID);
|
|
setuid(WIND_USER_ID);
|
|
|
|
auto server = TRY(os::LocalServer::create(socket_path, false));
|
|
TRY(server->listen(20));
|
|
|
|
int fd = open("/dev/null", O_RDONLY);
|
|
if (fd >= 0)
|
|
{
|
|
dup2(fd, STDIN_FILENO);
|
|
close(fd);
|
|
}
|
|
|
|
// We're ready now.
|
|
os::IPC::notify_parent();
|
|
|
|
ui::Color background = ui::Color::from_rgb(0x10, 0x10, 0x10);
|
|
|
|
Vector<OwnedPtr<Client>> clients;
|
|
Vector<struct pollfd> fds;
|
|
TRY(fds.try_append({ .fd = mouse->fd(), .events = POLLIN, .revents = 0 }));
|
|
TRY(fds.try_append({ .fd = keyboard->fd(), .events = POLLIN, .revents = 0 }));
|
|
TRY(fds.try_append({ .fd = server->fd(), .events = POLLIN, .revents = 0 }));
|
|
TRY(fds.try_append({ .fd = system_server->fd(), .events = POLLIN, .revents = 0 }));
|
|
|
|
TRY(os::Security::pledge("stdio rpath wpath cpath unix", NULL));
|
|
|
|
while (1)
|
|
{
|
|
screen.canvas().fill(background);
|
|
Layer::draw_all_windows(screen.canvas());
|
|
mouse_pointer.draw(screen.canvas());
|
|
screen.sync();
|
|
|
|
for (auto& pfd : fds) { pfd.revents = 0; }
|
|
|
|
int rc = poll(fds.data(), fds.size(), 1000);
|
|
if (!rc) continue;
|
|
if (rc < 0 && errno != EINTR) { os::println("poll: error: %s", strerror(errno)); }
|
|
|
|
if (fds[0].revents & POLLIN)
|
|
{
|
|
moon::MousePacket packet;
|
|
TRY(mouse->read_typed(packet));
|
|
mouse_pointer.update(packet);
|
|
}
|
|
if (fds[1].revents & POLLIN)
|
|
{
|
|
moon::KeyboardPacket packet;
|
|
TRY(keyboard->read_typed(packet));
|
|
auto request = wind::Keyboard::decode_keyboard_event((moon::KeyCode)packet.key, packet.released);
|
|
if (auto* window = Layer::focused_window())
|
|
{
|
|
request.window = window->id;
|
|
window->client->conn->send_async(request);
|
|
}
|
|
}
|
|
if (fds[2].revents & POLLIN)
|
|
{
|
|
auto client = TRY(server->accept());
|
|
os::println("wind: New client connected!");
|
|
TRY(fds.try_append({ .fd = client.fd(), .events = POLLIN, .revents = 0 }));
|
|
|
|
auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client)));
|
|
|
|
OwnedPtr<Client> c = TRY(adopt_owned_if_nonnull(new Client(move(connection), EMPTY_PLEDGE)));
|
|
TRY(clients.try_append(move(c)));
|
|
}
|
|
if (fds[3].revents & POLLIN)
|
|
{
|
|
auto client = TRY(system_server->accept());
|
|
os::println("wind: New privileged client connected!");
|
|
TRY(fds.try_append({ .fd = client.fd(), .events = POLLIN, .revents = 0 }));
|
|
|
|
auto connection = TRY(os::IPC::ClientConnection::adopt_connection(move(client)));
|
|
|
|
OwnedPtr<Client> c = TRY(adopt_owned_if_nonnull(new Client(move(connection), HAS_NOT_YET_PLEDGED)));
|
|
TRY(clients.try_append(move(c)));
|
|
}
|
|
for (usize i = 0; i < clients.size(); i++)
|
|
{
|
|
if (fds[i + 4].revents & POLLIN) clients[i]->conn->check_for_messages();
|
|
if (fds[i + 4].revents & POLLHUP) clients[i]->should_be_disconnected = true;
|
|
if (clients[i]->should_be_disconnected)
|
|
{
|
|
os::println("wind: Client %zu disconnected", i);
|
|
fds.remove_at(i + 4);
|
|
auto client = clients.remove_at(i);
|
|
client->conn->disconnect();
|
|
for (auto& window : client->windows)
|
|
{
|
|
if (window)
|
|
{
|
|
window->layer->windows.remove(window);
|
|
mouse_pointer.window_did_close(window);
|
|
delete window;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|