Compare commits
5 Commits
e97b61ef16
...
73a7d4f2a1
Author | SHA1 | Date | |
---|---|---|---|
73a7d4f2a1 | |||
efeab5699e | |||
1005305d5a | |||
8a90db837b | |||
3ad23eab21 |
34
apps/su.cpp
34
apps/su.cpp
@ -1,4 +1,6 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <os/ArgumentParser.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
@ -89,6 +91,30 @@ char* getpass()
|
||||
return buf;
|
||||
}
|
||||
|
||||
Result<void> set_supplementary_groups(const char* name)
|
||||
{
|
||||
Vector<gid_t> extra_groups;
|
||||
|
||||
setgrent();
|
||||
group* grp;
|
||||
while ((grp = getgrent()))
|
||||
{
|
||||
for (char** user = grp->gr_mem; *user; user++)
|
||||
{
|
||||
if (!strcmp(*user, name))
|
||||
{
|
||||
TRY(extra_groups.try_append(grp->gr_gid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
endgrent();
|
||||
|
||||
if (setgroups(static_cast<int>(extra_groups.size()), extra_groups.data()) < 0) return err(errno);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<int> luna_main(int argc, char** argv)
|
||||
{
|
||||
StringView name;
|
||||
@ -122,6 +148,12 @@ Result<int> luna_main(int argc, char** argv)
|
||||
{
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
|
||||
if (!strcmp(entry->pw_passwd, "!"))
|
||||
{
|
||||
fprintf(stderr, "%s: %s's password is disabled!\n", argv[0], entry->pw_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* pass = getpass();
|
||||
if (!pass) return 1;
|
||||
|
||||
@ -134,6 +166,8 @@ Result<int> luna_main(int argc, char** argv)
|
||||
memset(pass, 0, strlen(pass));
|
||||
}
|
||||
|
||||
TRY(set_supplementary_groups(name.chars()));
|
||||
|
||||
setgid(entry->pw_gid);
|
||||
setuid(entry->pw_uid);
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
root:!:0:
|
||||
users:!:1:
|
||||
users:!:1:selene
|
||||
wind:!:2:selene
|
||||
selene:!:1000:
|
||||
|
@ -1,2 +1,3 @@
|
||||
root:toor:0:0:Administrator:/:/usr/bin/sh
|
||||
wind:!:2:2:Window Manager:/:/usr/bin/init
|
||||
selene:moon:1000:1000:User:/home/selene:/usr/bin/sh
|
||||
|
@ -9,7 +9,7 @@
|
||||
_e(pivot_root) _e(sigreturn) _e(sigaction) _e(kill) _e(sigprocmask) _e(setpgid) _e(isatty) \
|
||||
_e(getpgid) _e(socket) _e(bind) _e(connect) _e(listen) _e(accept) _e(poll) _e(msync) \
|
||||
_e(truncate) _e(ftruncate) _e(utimensat) _e(setitimer) _e(pledge) _e(memstat) \
|
||||
_e(setsid) _e(getsid)
|
||||
_e(setsid) _e(getsid) _e(getgroups) _e(setgroups)
|
||||
|
||||
enum Syscalls
|
||||
{
|
||||
|
@ -35,9 +35,9 @@ Result<u64> ScriptLoader::load(AddressSpace* space)
|
||||
auto& interpreter_path = m_interpreter_cmdline[0];
|
||||
auto* current = Scheduler::current();
|
||||
|
||||
auto interpreter =
|
||||
TRY(VFS::resolve_path(interpreter_path.chars(), current->auth, current->current_directory, true));
|
||||
if (!VFS::can_execute(interpreter, current->auth)) return err(EACCES);
|
||||
auto interpreter = TRY(VFS::resolve_path(interpreter_path.chars(), current->auth, ¤t->extra_groups,
|
||||
current->current_directory, true));
|
||||
if (!VFS::can_execute(interpreter, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
auto loader = TRY(BinaryFormat::create_loader(interpreter, m_recursion_level + 1));
|
||||
u64 entry = TRY(loader->load(space));
|
||||
|
@ -20,7 +20,7 @@ void InitRD::initialize()
|
||||
|
||||
static Result<void> vfs_create_dir_if_not_exists(const char* path, mode_t mode)
|
||||
{
|
||||
auto rc = VFS::create_directory(path, mode & (mode_t)~S_IFMT, Credentials {});
|
||||
auto rc = VFS::create_directory(path, mode & (mode_t)~S_IFMT, Credentials {}, nullptr);
|
||||
if (rc.has_error())
|
||||
{
|
||||
if (rc.error() == EEXIST) return {};
|
||||
@ -37,7 +37,8 @@ Result<void> InitRD::populate_vfs()
|
||||
{
|
||||
if (entry.type == TarStream::EntryType::RegularFile)
|
||||
{
|
||||
auto file = TRY(VFS::create_file(entry.name.chars(), entry.mode & (mode_t)~S_IFMT, Credentials {}));
|
||||
auto file =
|
||||
TRY(VFS::create_file(entry.name.chars(), entry.mode & (mode_t)~S_IFMT, Credentials {}, nullptr));
|
||||
file->write(entry.data(), 0, entry.size);
|
||||
}
|
||||
else if (entry.type == TarStream::EntryType::Directory)
|
||||
|
@ -17,8 +17,9 @@ namespace VFS
|
||||
|
||||
static constexpr int MAX_SYMLINKS = 8;
|
||||
|
||||
Result<SharedPtr<Inode>> resolve_path_impl(const char* path, Credentials auth, SharedPtr<Inode> current_inode,
|
||||
bool follow_last_symlink, int& symlinks_followed)
|
||||
Result<SharedPtr<Inode>> resolve_path_impl(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<Inode> current_inode, bool follow_last_symlink,
|
||||
int& symlinks_followed)
|
||||
{
|
||||
if (symlinks_followed >= MAX_SYMLINKS) return err(ELOOP);
|
||||
|
||||
@ -31,7 +32,7 @@ namespace VFS
|
||||
const char* section;
|
||||
while (parser.next().try_set_value(section))
|
||||
{
|
||||
if (!can_execute(current_inode, auth)) return err(EACCES);
|
||||
if (!can_execute(current_inode, auth, extra_groups)) return err(EACCES);
|
||||
current_inode = TRY(current_inode->find(section));
|
||||
|
||||
if (current_inode->type() == VFS::InodeType::Symlink && (follow_last_symlink || parser.has_next()))
|
||||
@ -45,7 +46,8 @@ namespace VFS
|
||||
symlink_root = parent_inode;
|
||||
|
||||
symlinks_followed++;
|
||||
current_inode = TRY(resolve_path_impl(link.chars(), auth, symlink_root, true, symlinks_followed));
|
||||
current_inode =
|
||||
TRY(resolve_path_impl(link.chars(), auth, extra_groups, symlink_root, true, symlinks_followed));
|
||||
symlinks_followed--;
|
||||
}
|
||||
|
||||
@ -55,8 +57,8 @@ namespace VFS
|
||||
return current_inode;
|
||||
}
|
||||
|
||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory,
|
||||
bool follow_last_symlink)
|
||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<VFS::Inode> working_directory, bool follow_last_symlink)
|
||||
{
|
||||
SharedPtr<Inode> current_inode;
|
||||
|
||||
@ -66,17 +68,17 @@ namespace VFS
|
||||
|
||||
int symlinks_followed = 0;
|
||||
|
||||
return resolve_path_impl(path, auth, current_inode, follow_last_symlink, symlinks_followed);
|
||||
return resolve_path_impl(path, auth, extra_groups, current_inode, follow_last_symlink, symlinks_followed);
|
||||
}
|
||||
|
||||
Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth,
|
||||
SharedPtr<Inode> working_directory)
|
||||
const Vector<gid_t>* extra_groups, SharedPtr<Inode> working_directory)
|
||||
{
|
||||
auto parent_path = TRY(PathParser::dirname(path));
|
||||
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||
|
||||
if (!can_write(parent_inode, auth)) return err(EACCES);
|
||||
if (!can_write(parent_inode, auth, extra_groups)) return err(EACCES);
|
||||
|
||||
auto child_name = TRY(PathParser::basename(path));
|
||||
|
||||
@ -86,13 +88,13 @@ namespace VFS
|
||||
}
|
||||
|
||||
Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth,
|
||||
SharedPtr<Inode> working_directory)
|
||||
const Vector<gid_t>* extra_groups, SharedPtr<Inode> working_directory)
|
||||
{
|
||||
auto parent_path = TRY(PathParser::dirname(path));
|
||||
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||
|
||||
if (!can_write(parent_inode, auth)) return err(EACCES);
|
||||
if (!can_write(parent_inode, auth, extra_groups)) return err(EACCES);
|
||||
|
||||
auto child_name = TRY(PathParser::basename(path));
|
||||
|
||||
@ -133,7 +135,8 @@ namespace VFS
|
||||
return {};
|
||||
}
|
||||
|
||||
bool can_execute(SharedPtr<Inode> inode, Credentials auth)
|
||||
// FIXME: Check all three permissions even if the UID or GID match.
|
||||
bool can_execute(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups)
|
||||
{
|
||||
if (auth.euid == 0) return true;
|
||||
|
||||
@ -142,10 +145,19 @@ namespace VFS
|
||||
if (metadata.uid == auth.euid) { return metadata.mode & S_IXUSR; }
|
||||
if (metadata.gid == auth.egid) { return metadata.mode & S_IXGRP; }
|
||||
|
||||
if (extra_groups)
|
||||
{
|
||||
for (gid_t group : *extra_groups)
|
||||
{
|
||||
if (metadata.gid == group) return metadata.mode & S_IXGRP;
|
||||
}
|
||||
}
|
||||
|
||||
return metadata.mode & S_IXOTH;
|
||||
}
|
||||
|
||||
bool can_write(SharedPtr<Inode> inode, Credentials auth)
|
||||
// FIXME: Check all three permissions even if the UID or GID match.
|
||||
bool can_write(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups)
|
||||
{
|
||||
if (auth.euid == 0) return true;
|
||||
|
||||
@ -154,10 +166,19 @@ namespace VFS
|
||||
if (metadata.uid == auth.euid) { return metadata.mode & S_IWUSR; }
|
||||
if (metadata.gid == auth.egid) { return metadata.mode & S_IWGRP; }
|
||||
|
||||
if (extra_groups)
|
||||
{
|
||||
for (gid_t group : *extra_groups)
|
||||
{
|
||||
if (metadata.gid == group) return metadata.mode & S_IWGRP;
|
||||
}
|
||||
}
|
||||
|
||||
return metadata.mode & S_IWOTH;
|
||||
}
|
||||
|
||||
bool can_read(SharedPtr<Inode> inode, Credentials auth)
|
||||
// FIXME: Check all three permissions even if the UID or GID match.
|
||||
bool can_read(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups)
|
||||
{
|
||||
if (auth.euid == 0) return true;
|
||||
|
||||
@ -166,6 +187,14 @@ namespace VFS
|
||||
if (metadata.uid == auth.euid) { return metadata.mode & S_IRUSR; }
|
||||
if (metadata.gid == auth.egid) { return metadata.mode & S_IRGRP; }
|
||||
|
||||
if (extra_groups)
|
||||
{
|
||||
for (gid_t group : *extra_groups)
|
||||
{
|
||||
if (metadata.gid == group) return metadata.mode & S_IRGRP;
|
||||
}
|
||||
}
|
||||
|
||||
return metadata.mode & S_IROTH;
|
||||
}
|
||||
|
||||
@ -203,7 +232,8 @@ namespace VFS
|
||||
auto new_root_parent = TRY(PathParser::dirname(new_root));
|
||||
auto new_root_path = TRY(PathParser::basename(new_root));
|
||||
|
||||
auto new_root_parent_inode = TRY(VFS::resolve_path(new_root_parent.chars(), Credentials {}, working_directory));
|
||||
auto new_root_parent_inode =
|
||||
TRY(VFS::resolve_path(new_root_parent.chars(), Credentials {}, nullptr, working_directory));
|
||||
auto new_root_inode = TRY(new_root_parent_inode->find(new_root_path.chars()));
|
||||
|
||||
if (new_root_inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||
@ -215,7 +245,7 @@ namespace VFS
|
||||
|
||||
kdbgln("vfs: Pivoting root from / to %s, using %s as new root", put_old, new_root);
|
||||
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), Credentials {}, working_directory));
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), Credentials {}, nullptr, working_directory));
|
||||
|
||||
auto inode = TRY(parent_inode->find(child.chars()));
|
||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||
@ -236,7 +266,7 @@ namespace VFS
|
||||
}
|
||||
|
||||
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
|
||||
SharedPtr<VFS::Inode> working_directory)
|
||||
const Vector<gid_t>* extra_groups, SharedPtr<VFS::Inode> working_directory)
|
||||
{
|
||||
auto parent_path = TRY(PathParser::dirname(path));
|
||||
auto child = TRY(PathParser::basename(path));
|
||||
@ -245,7 +275,7 @@ namespace VFS
|
||||
kdbgln("vfs: Mounting filesystem on target %s", path);
|
||||
#endif
|
||||
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||
|
||||
auto inode = TRY(parent_inode->find(child.chars()));
|
||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||
@ -260,7 +290,8 @@ namespace VFS
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> umount(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory)
|
||||
Result<void> umount(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<VFS::Inode> working_directory)
|
||||
{
|
||||
auto parent_path = TRY(PathParser::dirname(path));
|
||||
auto child = TRY(PathParser::basename(path));
|
||||
@ -269,7 +300,7 @@ namespace VFS
|
||||
|
||||
kinfoln("vfs: Unmounting filesystem on target %s", path);
|
||||
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, working_directory));
|
||||
auto parent_inode = TRY(resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||
|
||||
auto inode = TRY(parent_inode->find(child.chars()));
|
||||
if (!inode->is_mountpoint()) return err(EINVAL);
|
||||
|
@ -306,21 +306,23 @@ namespace VFS
|
||||
virtual ~DeviceInode() = default;
|
||||
};
|
||||
|
||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth,
|
||||
Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<VFS::Inode> working_directory = {},
|
||||
bool follow_last_symlink = true);
|
||||
|
||||
Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth,
|
||||
const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<VFS::Inode> working_directory = {});
|
||||
|
||||
Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth,
|
||||
const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<VFS::Inode> working_directory = {});
|
||||
|
||||
Result<void> validate_filename(StringView name);
|
||||
|
||||
bool can_execute(SharedPtr<Inode> inode, Credentials auth);
|
||||
bool can_read(SharedPtr<Inode> inode, Credentials auth);
|
||||
bool can_write(SharedPtr<Inode> inode, Credentials auth);
|
||||
bool can_execute(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups);
|
||||
bool can_read(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups);
|
||||
bool can_write(SharedPtr<Inode> inode, Credentials auth, const Vector<gid_t>* extra_groups);
|
||||
bool is_setuid(SharedPtr<Inode> inode);
|
||||
bool is_setgid(SharedPtr<Inode> inode);
|
||||
bool is_sticky(SharedPtr<Inode> inode);
|
||||
@ -332,7 +334,8 @@ namespace VFS
|
||||
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs);
|
||||
Result<void> pivot_root(const char* new_root, const char* put_old, SharedPtr<VFS::Inode> working_directory);
|
||||
Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth,
|
||||
SharedPtr<Inode> working_directory = {});
|
||||
const Vector<gid_t>* extra_groups, SharedPtr<Inode> working_directory = {});
|
||||
|
||||
Result<void> umount(const char* path, Credentials auth, SharedPtr<Inode> working_directory = {});
|
||||
Result<void> umount(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<Inode> working_directory = {});
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ void oom_thread()
|
||||
mark_critical(BinaryFormat::init(), "Failed to register initial binary formats");
|
||||
mark_critical(FSRegistry::init(), "Failed to register initial file systems");
|
||||
|
||||
auto init =
|
||||
mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}), "Can't find init in the initial ramfs!");
|
||||
auto init = mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}, nullptr),
|
||||
"Can't find init in the initial ramfs!");
|
||||
auto init_thread = mark_critical(Scheduler::create_init_process(init, "/bin/preinit"),
|
||||
"Failed to create PID 1 process for init");
|
||||
|
||||
|
@ -52,14 +52,14 @@ Result<usize> UnixSocket::recv(u8* buf, usize length, int) const
|
||||
return m_data.dequeue_data(buf, length);
|
||||
}
|
||||
|
||||
static Result<void> bind_socket_to_fs(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory,
|
||||
SharedPtr<UnixSocket> socket)
|
||||
static Result<void> bind_socket_to_fs(const char* path, Credentials auth, const Vector<gid_t>* extra_groups,
|
||||
SharedPtr<VFS::Inode> working_directory, SharedPtr<UnixSocket> socket)
|
||||
{
|
||||
auto parent_path = TRY(PathParser::dirname(path));
|
||||
|
||||
auto parent_inode = TRY(VFS::resolve_path(parent_path.chars(), auth, working_directory));
|
||||
auto parent_inode = TRY(VFS::resolve_path(parent_path.chars(), auth, extra_groups, working_directory));
|
||||
|
||||
if (!VFS::can_write(parent_inode, auth)) return err(EACCES);
|
||||
if (!VFS::can_write(parent_inode, auth, extra_groups)) return err(EACCES);
|
||||
|
||||
auto child_name = TRY(PathParser::basename(path));
|
||||
|
||||
@ -91,7 +91,8 @@ Result<void> UnixSocket::bind(struct sockaddr* addr, socklen_t addrlen)
|
||||
m_metadata.uid = current->auth.euid;
|
||||
m_metadata.gid = current->auth.egid;
|
||||
|
||||
auto rc = bind_socket_to_fs(path.chars(), current->auth, current->current_directory, SharedPtr<Socket> { this });
|
||||
auto rc = bind_socket_to_fs(path.chars(), current->auth, ¤t->extra_groups, current->current_directory,
|
||||
SharedPtr<Socket> { this });
|
||||
if (rc.has_error())
|
||||
{
|
||||
if (rc.error() == EEXIST) return err(EADDRINUSE);
|
||||
@ -123,10 +124,11 @@ Result<void> UnixSocket::connect(Registers* regs, int flags, struct sockaddr* ad
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
|
||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||
auto inode =
|
||||
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||
if (inode->type() != VFS::InodeType::Socket)
|
||||
return err(ENOTSOCK); // FIXME: POSIX doesn't say what error to return here?
|
||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
auto socket = (SharedPtr<UnixSocket>)inode;
|
||||
if (socket->m_state != State::Listening) return err(ECONNREFUSED);
|
||||
|
@ -14,10 +14,10 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
|
||||
|
||||
if (PathParser::is_absolute(path.view()))
|
||||
{
|
||||
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth));
|
||||
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups));
|
||||
|
||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_execute(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
inode->add_handle();
|
||||
if (current->current_directory) current->current_directory->remove_handle();
|
||||
@ -29,10 +29,11 @@ Result<u64> sys_chdir(Registers*, SyscallArgs args)
|
||||
}
|
||||
else
|
||||
{
|
||||
SharedPtr<VFS::Inode> inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||
SharedPtr<VFS::Inode> inode =
|
||||
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||
|
||||
if (inode->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_execute(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
auto old_wdir = current->current_directory_path.view();
|
||||
|
||||
|
@ -68,9 +68,10 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
||||
|
||||
TRY(check_pledge(current, Promise::p_exec));
|
||||
|
||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||
auto inode =
|
||||
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||
|
||||
if (!VFS::can_execute(inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_execute(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
#ifdef EXEC_DEBUG
|
||||
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
||||
@ -159,6 +160,8 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
||||
|
||||
TRY(check_pledge(current, Promise::p_proc));
|
||||
|
||||
auto extra_groups = TRY(current->extra_groups.shallow_copy());
|
||||
|
||||
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
||||
|
||||
memcpy(¤t->regs, regs, sizeof(*regs));
|
||||
@ -183,6 +186,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
||||
thread->controlling_terminal = current->controlling_terminal;
|
||||
thread->pgid = current->pgid;
|
||||
thread->sid = current->sid;
|
||||
thread->extra_groups = move(extra_groups);
|
||||
|
||||
thread->virtual_clock.set_resolution(1'000'000);
|
||||
thread->profiling_clock.set_resolution(1'000'000);
|
||||
|
@ -259,9 +259,10 @@ Result<u64> sys_truncate(Registers*, SyscallArgs args)
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
TRY(check_pledge(current, Promise::p_wpath));
|
||||
auto inode = TRY(VFS::resolve_path(path.chars(), current->auth, current->current_directory));
|
||||
auto inode =
|
||||
TRY(VFS::resolve_path(path.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||
|
||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
TRY(inode->truncate(length));
|
||||
|
||||
@ -308,8 +309,8 @@ Result<u64> sys_utimensat(Registers*, SyscallArgs args)
|
||||
|
||||
if (allow_write_access)
|
||||
{
|
||||
if (!VFS::can_write(inode, current->auth) && current->auth.euid != inode->metadata().uid &&
|
||||
current->auth.euid != 0)
|
||||
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups) &&
|
||||
current->auth.euid != inode->metadata().uid && current->auth.euid != 0)
|
||||
return err(EACCES);
|
||||
}
|
||||
else if (current->auth.euid != inode->metadata().uid && current->auth.euid != 0)
|
||||
|
@ -237,3 +237,54 @@ Result<u64> sys_fchownat(Registers*, SyscallArgs args)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result<u64> sys_getgroups(Registers*, SyscallArgs args)
|
||||
{
|
||||
int ngroups = (int)args[0];
|
||||
gid_t* grouplist = (gid_t*)args[1];
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
|
||||
TRY(check_pledge(current, Promise::p_stdio));
|
||||
|
||||
if (!ngroups) return current->extra_groups.size();
|
||||
if (ngroups < 0) return err(EINVAL);
|
||||
|
||||
if (static_cast<usize>(ngroups) < current->extra_groups.size()) return err(EINVAL);
|
||||
|
||||
if (!MemoryManager::copy_to_user(grouplist, current->extra_groups.data(),
|
||||
current->extra_groups.size() * sizeof(gid_t)))
|
||||
return err(EFAULT);
|
||||
|
||||
return current->extra_groups.size();
|
||||
}
|
||||
|
||||
Result<u64> sys_setgroups(Registers*, SyscallArgs args)
|
||||
{
|
||||
int ngroups = (int)args[0];
|
||||
const gid_t* grouplist = (const gid_t*)args[1];
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
|
||||
TRY(check_pledge(current, Promise::p_id));
|
||||
|
||||
Credentials& auth = current->auth;
|
||||
if (auth.euid != 0) return err(EPERM);
|
||||
|
||||
if (!ngroups)
|
||||
{
|
||||
current->extra_groups.clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ngroups < 0 || ngroups > 32) return err(EINVAL);
|
||||
|
||||
TRY(current->extra_groups.try_reserve(ngroups));
|
||||
|
||||
current->extra_groups.mutate([&](gid_t* list, usize) -> usize {
|
||||
if (MemoryManager::copy_from_user(grouplist, list, ngroups * sizeof(gid_t))) return ngroups;
|
||||
return current->extra_groups.size();
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
|
||||
kinfoln("unlinkat: remove %s from directory %s, dirfd is %d", basename.chars(), dirname.chars(), dirfd);
|
||||
|
||||
auto inode = TRY(current->resolve_atfile(dirfd, dirname, false, false));
|
||||
if (!VFS::can_write(inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
auto child = TRY(inode->find(basename.chars()));
|
||||
if (flags == AT_REMOVEDIR && child->type() != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||
@ -52,7 +52,7 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
|
||||
|
||||
auto parent_inode = TRY(current->resolve_atfile(dirfd, parent, false, true));
|
||||
|
||||
if (!VFS::can_write(parent_inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_write(parent_inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
auto child_name = TRY(PathParser::basename(linkpath.view()));
|
||||
|
||||
@ -115,7 +115,7 @@ Result<u64> sys_linkat(Registers*, SyscallArgs args)
|
||||
|
||||
if (target->fs() != parent_inode->fs()) return err(EXDEV);
|
||||
|
||||
if (!VFS::can_write(parent_inode, current->auth)) return err(EACCES);
|
||||
if (!VFS::can_write(parent_inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
auto child_name = TRY(PathParser::basename(newpath.view()));
|
||||
|
||||
|
@ -13,8 +13,8 @@ Result<u64> sys_mkdir(Registers*, SyscallArgs args)
|
||||
Thread* current = Scheduler::current();
|
||||
TRY(check_pledge(current, Promise::p_cpath));
|
||||
|
||||
auto inode =
|
||||
TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, current->current_directory));
|
||||
auto inode = TRY(VFS::create_directory(path.chars(), mode & ~current->umask, current->auth, ¤t->extra_groups,
|
||||
current->current_directory));
|
||||
auto metadata = inode->metadata();
|
||||
metadata.uid = current->auth.euid;
|
||||
metadata.gid = current->auth.egid;
|
||||
|
@ -19,7 +19,8 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
||||
if (current->auth.euid != 0) return err(EPERM);
|
||||
|
||||
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
|
||||
auto inode = TRY(VFS::resolve_path(source.chars(), current->auth, current->current_directory));
|
||||
auto inode =
|
||||
TRY(VFS::resolve_path(source.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||
if (inode->type() != VFS::InodeType::BlockDevice) return err(ENOTBLK);
|
||||
dev_t device_id = inode->metadata().devid;
|
||||
return TRY(DeviceRegistry::fetch_special_device(luna_dev_major(device_id), luna_dev_minor(device_id)));
|
||||
@ -40,7 +41,7 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
||||
fs = TRY(factory(device));
|
||||
}
|
||||
|
||||
TRY(VFS::mount(target.chars(), fs, current->auth, current->current_directory));
|
||||
TRY(VFS::mount(target.chars(), fs, current->auth, ¤t->extra_groups, current->current_directory));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -53,7 +54,7 @@ Result<u64> sys_umount(Registers*, SyscallArgs args)
|
||||
TRY(check_pledge(current, Promise::p_mount));
|
||||
if (current->auth.euid != 0) return err(EPERM);
|
||||
|
||||
TRY(VFS::umount(target.chars(), current->auth, current->current_directory));
|
||||
TRY(VFS::umount(target.chars(), current->auth, ¤t->extra_groups, current->current_directory));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
|
||||
{
|
||||
if (error == ENOENT && (flags & O_CREAT) && !path.is_empty())
|
||||
{
|
||||
inode = TRY(VFS::create_file(path.chars(), mode & ~current->umask, current->auth, parent_inode));
|
||||
inode = TRY(VFS::create_file(path.chars(), mode & ~current->umask, current->auth, ¤t->extra_groups,
|
||||
parent_inode));
|
||||
// FIXME: Pass these in create_file().
|
||||
auto metadata = inode->metadata();
|
||||
metadata.uid = current->auth.euid;
|
||||
@ -58,8 +59,8 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
|
||||
return err(EEXIST);
|
||||
else
|
||||
{
|
||||
if ((flags & O_RDONLY) && !VFS::can_read(inode, current->auth)) return err(EACCES);
|
||||
if ((flags & O_WRONLY) && !VFS::can_write(inode, current->auth)) return err(EACCES);
|
||||
if ((flags & O_RDONLY) && !VFS::can_read(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
if ((flags & O_WRONLY) && !VFS::can_write(inode, current->auth, ¤t->extra_groups)) return err(EACCES);
|
||||
}
|
||||
|
||||
inode = TRY(inode->open());
|
||||
|
@ -81,9 +81,9 @@ Result<u64> sys_faccessat(Registers*, SyscallArgs args)
|
||||
|
||||
auto inode = TRY(current->resolve_atfile(dirfd, path, false, true));
|
||||
|
||||
if ((amode & R_OK) && !VFS::can_read(inode, creds)) return err(EACCES);
|
||||
if ((amode & W_OK) && !VFS::can_write(inode, creds)) return err(EACCES);
|
||||
if ((amode & X_OK) && !VFS::can_execute(inode, creds)) return err(EACCES);
|
||||
if ((amode & R_OK) && !VFS::can_read(inode, creds, ¤t->extra_groups)) return err(EACCES);
|
||||
if ((amode & W_OK) && !VFS::can_write(inode, creds, ¤t->extra_groups)) return err(EACCES);
|
||||
if ((amode & X_OK) && !VFS::can_execute(inode, creds, ¤t->extra_groups)) return err(EACCES);
|
||||
|
||||
// Either all checks succeeded, or amode == F_OK and the file exists, since resolve_atfile() would have failed
|
||||
// otherwise.
|
||||
|
@ -156,6 +156,7 @@ namespace Scheduler
|
||||
thread->pgid = 1;
|
||||
thread->cmdline = name;
|
||||
thread->auth = Credentials { .uid = 0, .euid = 0, .suid = 0, .gid = 0, .egid = 0, .sgid = 0 };
|
||||
thread->extra_groups = {};
|
||||
|
||||
Vector<String> args;
|
||||
auto name_string = TRY(String::from_cstring(name));
|
||||
|
@ -64,10 +64,11 @@ Result<SharedPtr<VFS::Inode>> Thread::resolve_atfile(int dirfd, const String& pa
|
||||
if (parent_inode) *parent_inode = this->current_directory;
|
||||
|
||||
if (PathParser::is_absolute(path.view()))
|
||||
return VFS::resolve_path(path.chars(), this->auth, {}, follow_last_symlink);
|
||||
return VFS::resolve_path(path.chars(), this->auth, &this->extra_groups, {}, follow_last_symlink);
|
||||
|
||||
if (dirfd == AT_FDCWD)
|
||||
return VFS::resolve_path(path.chars(), this->auth, this->current_directory, follow_last_symlink);
|
||||
return VFS::resolve_path(path.chars(), this->auth, &this->extra_groups, this->current_directory,
|
||||
follow_last_symlink);
|
||||
|
||||
auto descriptor = TRY(resolve_fd(dirfd));
|
||||
|
||||
@ -75,7 +76,7 @@ Result<SharedPtr<VFS::Inode>> Thread::resolve_atfile(int dirfd, const String& pa
|
||||
|
||||
if (path.is_empty() && allow_empty_path) return descriptor->inode();
|
||||
|
||||
return VFS::resolve_path(path.chars(), this->auth, descriptor->inode(), follow_last_symlink);
|
||||
return VFS::resolve_path(path.chars(), this->auth, &this->extra_groups, descriptor->inode(), follow_last_symlink);
|
||||
}
|
||||
|
||||
[[noreturn]] void Thread::exit_and_signal_parent(int _status)
|
||||
|
@ -54,6 +54,7 @@ struct Thread : public LinkedListNode<Thread>
|
||||
pid_t sid { 0 };
|
||||
|
||||
Credentials auth;
|
||||
Vector<gid_t> extra_groups;
|
||||
|
||||
u64 user_ticks_self = 0;
|
||||
u64 kernel_ticks_self = 0;
|
||||
|
@ -33,6 +33,9 @@ extern "C"
|
||||
/* End group file parsing. */
|
||||
void endgrent(void);
|
||||
|
||||
/* Set this process's list of supplementary groups. */
|
||||
int setgroups(int size, const gid_t* list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -205,6 +205,9 @@ extern "C"
|
||||
/* Restrict system operations. */
|
||||
int pledge(const char* promises, const char* execpromises);
|
||||
|
||||
/* Get this process's list of supplementary groups. */
|
||||
int getgroups(int size, gid_t* list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <luna/Vector.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static struct group grp;
|
||||
static FILE* f { nullptr };
|
||||
@ -112,4 +114,10 @@ extern "C"
|
||||
f = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int setgroups(int size, const gid_t* list)
|
||||
{
|
||||
long rc = syscall(SYS_setgroups, size, list);
|
||||
__errno_return(rc, int);
|
||||
}
|
||||
}
|
||||
|
@ -545,4 +545,10 @@ extern "C"
|
||||
long rc = syscall(SYS_setsid);
|
||||
__errno_return(rc, pid_t);
|
||||
}
|
||||
|
||||
int getgroups(int size, gid_t* list)
|
||||
{
|
||||
long rc = syscall(SYS_getgroups, size, list);
|
||||
__errno_return(rc, int);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/CString.h>
|
||||
#include <luna/Common.h>
|
||||
#include <luna/Result.h>
|
||||
#include <luna/Slice.h>
|
||||
#include <luna/Types.h>
|
||||
@ -245,6 +246,12 @@ template <typename T> class Vector
|
||||
return other;
|
||||
}
|
||||
|
||||
template <typename Callback> void mutate(Callback callback)
|
||||
{
|
||||
usize size = callback(m_data, m_capacity);
|
||||
m_size = min(m_capacity, size);
|
||||
}
|
||||
|
||||
private:
|
||||
T* m_data { nullptr };
|
||||
usize m_capacity { 0 };
|
||||
@ -252,7 +259,7 @@ template <typename T> class Vector
|
||||
|
||||
Result<void> resize(usize new_capacity)
|
||||
{
|
||||
if (new_capacity < m_capacity) return {};
|
||||
if (new_capacity <= m_capacity) return {};
|
||||
|
||||
const usize new_byte_capacity = new_capacity * sizeof(T);
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace os::SharedMemory
|
||||
{
|
||||
Result<u8*> create(StringView path, usize size)
|
||||
{
|
||||
int fd = shm_open(path.chars(), O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
int fd = shm_open(path.chars(), O_RDWR | O_CREAT | O_EXCL, 0660);
|
||||
if (fd < 0)
|
||||
{
|
||||
int olderr = errno;
|
||||
@ -57,7 +57,7 @@ namespace os::SharedMemory
|
||||
|
||||
Result<u8*> adopt(StringView path, usize size, bool delete_fs)
|
||||
{
|
||||
int fd = shm_open(path.chars(), O_RDWR, 0600);
|
||||
int fd = shm_open(path.chars(), O_RDWR, 0660);
|
||||
if (delete_fs) shm_unlink(path.chars());
|
||||
if (fd < 0) return err(errno);
|
||||
|
||||
|
@ -19,6 +19,7 @@ namespace ui
|
||||
{
|
||||
IPC_ENUM_SERVER(ui),
|
||||
CREATE_WINDOW_ID,
|
||||
REMOVE_SHM_ID,
|
||||
SET_WINDOW_TITLE_ID,
|
||||
INVALIDATE_ID,
|
||||
CLOSE_WINDOW_ID,
|
||||
@ -41,6 +42,13 @@ namespace ui
|
||||
WindowType type;
|
||||
};
|
||||
|
||||
struct RemoveSharedMemoryRequest
|
||||
{
|
||||
static constexpr u8 ID = REMOVE_SHM_ID;
|
||||
|
||||
int window;
|
||||
};
|
||||
|
||||
struct SetWindowTitleRequest
|
||||
{
|
||||
static constexpr u8 ID = SET_WINDOW_TITLE_ID;
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <luna/String.h>
|
||||
#include <os/File.h>
|
||||
#include <os/SharedMemory.h>
|
||||
#include <sys/mman.h>
|
||||
#include <ui/App.h>
|
||||
@ -27,13 +28,17 @@ namespace ui
|
||||
|
||||
auto path = COPY_IPC_STRING(response.shm_path);
|
||||
|
||||
u32* pixels = (u32*)TRY(os::SharedMemory::adopt(path.view(), rect.height * rect.width * 4));
|
||||
u32* pixels = (u32*)TRY(os::SharedMemory::adopt(path.view(), rect.height * rect.width * 4, false));
|
||||
|
||||
window->m_canvas = ui::Canvas { rect.width, rect.height, rect.width, (u8*)pixels };
|
||||
window->m_id = response.window;
|
||||
|
||||
Window* p = window.ptr();
|
||||
|
||||
ui::RemoveSharedMemoryRequest shm_request;
|
||||
shm_request.window = response.window;
|
||||
os::IPC::send_async(App::the().client(), shm_request);
|
||||
|
||||
App::the().register_window(move(window), {});
|
||||
|
||||
return p;
|
||||
|
15
wind/IPC.cpp
15
wind/IPC.cpp
@ -5,6 +5,7 @@
|
||||
#include <luna/String.h>
|
||||
#include <os/File.h>
|
||||
#include <os/SharedMemory.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
|
||||
#define TRY_OR_IPC_ERROR(expr) \
|
||||
@ -94,10 +95,23 @@ static Result<void> handle_create_window_message(Client& client)
|
||||
ui::CreateWindowResponse response;
|
||||
response.window = id;
|
||||
SET_IPC_STRING(response.shm_path, shm_path.chars());
|
||||
window->shm_path = move(shm_path);
|
||||
os::IPC::send_async(client.conn, response);
|
||||
return {};
|
||||
}
|
||||
|
||||
static Result<void> handle_remove_shm_message(Client& client)
|
||||
{
|
||||
ui::RemoveSharedMemoryRequest request;
|
||||
READ_MESSAGE(request);
|
||||
|
||||
CHECK_WINDOW_ID(request);
|
||||
|
||||
shm_unlink(client.windows[request.window]->shm_path.chars());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Result<void> handle_set_window_title_message(Client& client)
|
||||
{
|
||||
ui::SetWindowTitleRequest request;
|
||||
@ -162,6 +176,7 @@ namespace wind
|
||||
switch (id)
|
||||
{
|
||||
case ui::CREATE_WINDOW_ID: return handle_create_window_message(client);
|
||||
case ui::REMOVE_SHM_ID: return handle_remove_shm_message(client);
|
||||
case ui::SET_WINDOW_TITLE_ID: return handle_set_window_title_message(client);
|
||||
case ui::INVALIDATE_ID: return handle_invalidate_message(client);
|
||||
case ui::CLOSE_WINDOW_ID: return handle_close_window_message(client);
|
||||
|
@ -16,6 +16,7 @@ struct Window : public LinkedListNode<Window>
|
||||
ui::Rect contents;
|
||||
u32* pixels;
|
||||
String name;
|
||||
String shm_path;
|
||||
bool dirty { false };
|
||||
Client* client;
|
||||
int id;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Screen.h"
|
||||
#include "Window.h"
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <moon/Keyboard.h>
|
||||
#include <os/ArgumentParser.h>
|
||||
#include <os/File.h>
|
||||
@ -17,6 +18,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -52,6 +54,31 @@ static void debug(const Vector<OwnedPtr<Client>>& clients)
|
||||
os::println("--- wind: END DEBUG OUTPUT ---");
|
||||
}
|
||||
|
||||
Result<void> set_supplementary_groups(const char* name)
|
||||
{
|
||||
Vector<gid_t> extra_groups;
|
||||
|
||||
setgrent();
|
||||
group* grp;
|
||||
while ((grp = getgrent()))
|
||||
{
|
||||
for (char** user = grp->gr_mem; *user; user++)
|
||||
{
|
||||
if (!strcmp(*user, name))
|
||||
{
|
||||
os::println("Adding supplementary group: %d", grp->gr_gid);
|
||||
TRY(extra_groups.try_append(grp->gr_gid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
endgrent();
|
||||
|
||||
if (setgroups(static_cast<int>(extra_groups.size()), extra_groups.data()) < 0) return err(errno);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<int> luna_main(int argc, char** argv)
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
@ -95,25 +122,44 @@ Result<int> luna_main(int argc, char** argv)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
clearenv();
|
||||
|
||||
if (!user.is_empty())
|
||||
{
|
||||
auto* pwd = getpwnam(user.chars());
|
||||
if (pwd)
|
||||
{
|
||||
setgid(pwd->pw_gid);
|
||||
setuid(pwd->pw_uid);
|
||||
}
|
||||
}
|
||||
setegid(2);
|
||||
seteuid(2);
|
||||
|
||||
if (setsid() < 0) perror("setsid");
|
||||
|
||||
mode_t mask = umask(0002);
|
||||
|
||||
auto server = TRY(os::LocalServer::create(socket_path, false));
|
||||
TRY(server->listen(20));
|
||||
|
||||
StringView args[] = { "/usr/bin/init"_sv, "--user"_sv };
|
||||
TRY(os::Process::spawn("/usr/bin/init"_sv, Slice<StringView> { args, 2 }, false));
|
||||
umask(mask);
|
||||
|
||||
seteuid(0);
|
||||
|
||||
clearenv();
|
||||
|
||||
pid_t child = TRY(os::Process::fork());
|
||||
if (!child)
|
||||
{
|
||||
if (!user.is_empty())
|
||||
{
|
||||
auto* pwd = getpwnam(user.chars());
|
||||
if (pwd)
|
||||
{
|
||||
TRY(set_supplementary_groups(user.chars()));
|
||||
setgid(pwd->pw_gid);
|
||||
setuid(pwd->pw_uid);
|
||||
}
|
||||
}
|
||||
|
||||
StringView args[] = { "/usr/bin/init"_sv, "--user"_sv };
|
||||
TRY(os::Process::exec("/usr/bin/init"_sv, Slice<StringView> { args, 2 }, false));
|
||||
}
|
||||
|
||||
umask(0002);
|
||||
|
||||
setuid(2);
|
||||
setgid(2);
|
||||
|
||||
ui::Color background = ui::Color::from_rgb(0x10, 0x10, 0x10);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user