mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-22 09:12:13 -05:00
Add some basic setgroups(), getgroups() and initgroups().
Also teach /bin/id to print the user's supplemental groups.
This commit is contained in:
parent
d3bd3791cb
commit
a7f1d892a9
Notes:
sideshowbarker
2024-07-19 18:32:47 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/a7f1d892a95
12 changed files with 167 additions and 19 deletions
|
@ -8,6 +8,7 @@ template<typename T>
|
|||
class DoublyLinkedList {
|
||||
private:
|
||||
struct Node {
|
||||
explicit Node(const T& v) : value(v) { }
|
||||
explicit Node(T&& v) : value(move(v)) { }
|
||||
T value;
|
||||
Node* next { nullptr };
|
||||
|
@ -38,17 +39,13 @@ public:
|
|||
|
||||
void append(T&& value)
|
||||
{
|
||||
auto* node = new Node(move(value));
|
||||
if (!m_head) {
|
||||
ASSERT(!m_tail);
|
||||
m_head = node;
|
||||
m_tail = node;
|
||||
return;
|
||||
}
|
||||
ASSERT(m_tail);
|
||||
m_tail->next = node;
|
||||
node->prev = m_tail;
|
||||
m_tail = node;
|
||||
append_node(new Node(move(value)));
|
||||
|
||||
}
|
||||
|
||||
void append(const T& value)
|
||||
{
|
||||
append_node(new Node(value));
|
||||
}
|
||||
|
||||
bool containsSlow(const T& value) const
|
||||
|
@ -136,6 +133,20 @@ public:
|
|||
private:
|
||||
friend class Iterator;
|
||||
|
||||
void append_node(Node* node)
|
||||
{
|
||||
if (!m_head) {
|
||||
ASSERT(!m_tail);
|
||||
m_head = node;
|
||||
m_tail = node;
|
||||
return;
|
||||
}
|
||||
ASSERT(m_tail);
|
||||
m_tail->next = node;
|
||||
node->prev = m_tail;
|
||||
m_tail = node;
|
||||
}
|
||||
|
||||
Node* head() { return m_head; }
|
||||
const Node* head() const { return m_head; }
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
unsigned size() const { return m_size; }
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
|
||||
void set(const T&);
|
||||
void set(T&&);
|
||||
bool contains(const T&) const;
|
||||
void clear();
|
||||
|
@ -224,6 +225,7 @@ private:
|
|||
Bucket& lookup(const T&, unsigned* bucketIndex = nullptr);
|
||||
const Bucket& lookup(const T&, unsigned* bucketIndex = nullptr) const;
|
||||
void rehash(unsigned capacity);
|
||||
void insert(const T&);
|
||||
void insert(T&&);
|
||||
|
||||
Bucket* m_buckets { nullptr };
|
||||
|
@ -251,6 +253,26 @@ void HashTable<T, TraitsForT>::set(T&& value)
|
|||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::set(const T& value)
|
||||
{
|
||||
if (!m_capacity)
|
||||
rehash(1);
|
||||
auto& bucket = lookup(value);
|
||||
for (auto& e : bucket.chain) {
|
||||
if (e == value)
|
||||
return;
|
||||
}
|
||||
if (size() >= capacity()) {
|
||||
rehash(size() + 1);
|
||||
insert(value);
|
||||
} else {
|
||||
bucket.chain.append(value);
|
||||
}
|
||||
m_size++;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::rehash(unsigned newCapacity)
|
||||
{
|
||||
|
@ -291,6 +313,13 @@ void HashTable<T, TraitsForT>::insert(T&& value)
|
|||
bucket.chain.append(move(value));
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::insert(const T& value)
|
||||
{
|
||||
auto& bucket = lookup(value);
|
||||
bucket.chain.append(value);
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
bool HashTable<T, TraitsForT>::contains(const T& value) const
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
//#define FORK_DEBUG
|
||||
//#define SCHEDULER_DEBUG
|
||||
#define COOL_GLOBALS
|
||||
#define MAX_PROCESS_GIDS 32
|
||||
|
||||
#ifdef COOL_GLOBALS
|
||||
struct CoolGlobals {
|
||||
|
@ -304,7 +305,7 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
|
|||
return error;
|
||||
}
|
||||
|
||||
if (!handle->metadata().mayExecute(m_euid, m_egid))
|
||||
if (!handle->metadata().mayExecute(m_euid, m_gids))
|
||||
return -EACCES;
|
||||
|
||||
auto elfData = handle->readEntireFile();
|
||||
|
@ -573,6 +574,8 @@ Process::Process(String&& name, uid_t uid, gid_t gid, pid_t ppid, RingLevel ring
|
|||
, m_tty(tty)
|
||||
, m_ppid(ppid)
|
||||
{
|
||||
m_gids.set(m_gid);
|
||||
|
||||
if (fork_parent) {
|
||||
m_sid = fork_parent->m_sid;
|
||||
m_pgid = fork_parent->m_pgid;
|
||||
|
@ -1566,3 +1569,33 @@ int Process::sys$sigaction(int signum, const Unix::sigaction* act, Unix::sigacti
|
|||
action.handler_or_sigaction = LinearAddress((dword)act->sa_sigaction);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$getgroups(int count, gid_t* gids)
|
||||
{
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
ASSERT(m_gids.size() < MAX_PROCESS_GIDS);
|
||||
if (!count)
|
||||
return m_gids.size();
|
||||
if (count != m_gids.size())
|
||||
return -EINVAL;
|
||||
VALIDATE_USER_WRITE(gids, sizeof(gid_t) * count);
|
||||
size_t i = 0;
|
||||
for (auto gid : m_gids)
|
||||
gids[i++] = gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$setgroups(size_t count, const gid_t* gids)
|
||||
{
|
||||
if (!is_root())
|
||||
return -EPERM;
|
||||
if (count >= MAX_PROCESS_GIDS)
|
||||
return -EINVAL;
|
||||
VALIDATE_USER_READ(gids, sizeof(gid_t) * count);
|
||||
m_gids.clear();
|
||||
m_gids.set(m_gid);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
m_gids.set(gids[i]);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -139,6 +139,8 @@ public:
|
|||
int sys$dup(int oldfd);
|
||||
int sys$dup2(int oldfd, int newfd);
|
||||
int sys$sigaction(int signum, const Unix::sigaction* act, Unix::sigaction* old_act);
|
||||
int sys$getgroups(int size, gid_t*);
|
||||
int sys$setgroups(size_t, const gid_t*);
|
||||
|
||||
static void initialize();
|
||||
|
||||
|
@ -177,6 +179,8 @@ public:
|
|||
Process* fork(RegisterDump&);
|
||||
int exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment);
|
||||
|
||||
bool is_root() const { return m_euid == 0; }
|
||||
|
||||
private:
|
||||
friend class MemoryManager;
|
||||
friend bool scheduleNewProcess();
|
||||
|
@ -242,6 +246,7 @@ private:
|
|||
|
||||
Vector<String> m_arguments;
|
||||
Vector<String> m_initialEnvironment;
|
||||
HashTable<gid_t> m_gids;
|
||||
};
|
||||
|
||||
class ProcessInspectionScope {
|
||||
|
|
|
@ -152,6 +152,10 @@ static DWORD handle(RegisterDump& regs, DWORD function, DWORD arg1, DWORD arg2,
|
|||
return current->sys$sigaction((int)arg1, (const Unix::sigaction*)arg2, (Unix::sigaction*)arg3);
|
||||
case Syscall::SC_umask:
|
||||
return current->sys$umask((mode_t)arg1);
|
||||
case Syscall::SC_getgroups:
|
||||
return current->sys$getgroups((int)arg1, (gid_t*)arg2);
|
||||
case Syscall::SC_setgroups:
|
||||
return current->sys$setgroups((size_t)arg1, (const gid_t*)arg2);
|
||||
default:
|
||||
kprintf("<%u> int0x80: Unknown function %x requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||
break;
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
__ENUMERATE_SYSCALL(sigaction) \
|
||||
__ENUMERATE_SYSCALL(getppid) \
|
||||
__ENUMERATE_SYSCALL(umask) \
|
||||
__ENUMERATE_SYSCALL(getgroups) \
|
||||
__ENUMERATE_SYSCALL(setgroups) \
|
||||
|
||||
|
||||
#define DO_SYSCALL_A0(function) Syscall::invoke((dword)(function))
|
||||
|
|
22
LibC/grp.cpp
22
LibC/grp.cpp
|
@ -118,4 +118,26 @@ next_entry:
|
|||
return __grdb_entry;
|
||||
}
|
||||
|
||||
int initgroups(const char* user, gid_t extra_gid)
|
||||
{
|
||||
size_t count = 0;
|
||||
gid_t gids[32];
|
||||
bool extra_gid_added = false;
|
||||
setgrent();
|
||||
while (auto* gr = getgrent()) {
|
||||
for (auto* mem = gr->gr_mem; *mem; ++mem) {
|
||||
if (!strcmp(*mem, user)) {
|
||||
gids[count++] = gr->gr_gid;
|
||||
if (gr->gr_gid == extra_gid)
|
||||
extra_gid_added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
endgrent();
|
||||
if (!extra_gid_added)
|
||||
gids[count++] = extra_gid;
|
||||
return setgroups(count, gids);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,4 +18,6 @@ void endgrent();
|
|||
struct group* getgrnam(const char* name);
|
||||
struct group* getgrgid(gid_t);
|
||||
|
||||
int initgroups(const char* user, gid_t);
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <Kernel/Syscall.h>
|
||||
|
||||
extern "C" {
|
||||
|
@ -218,4 +221,16 @@ int dup2(int old_fd, int new_fd)
|
|||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int setgroups(size_t size, const gid_t* list)
|
||||
{
|
||||
int rc = Syscall::invoke(Syscall::SC_getgroups, (dword)size, (dword)list);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int getgroups(int size, gid_t list[])
|
||||
{
|
||||
int rc = Syscall::invoke(Syscall::SC_getgroups, (dword)size, (dword)list);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ gid_t getegid();
|
|||
uid_t getuid();
|
||||
gid_t getgid();
|
||||
pid_t getpid();
|
||||
int getgroups(int size, gid_t list[]);
|
||||
int setgroups(size_t, const gid_t*);
|
||||
pid_t tcgetpgrp(int fd);
|
||||
int tcsetpgrp(int fd, pid_t pgid);
|
||||
int open(const char* path, int options, ...);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#include <LibC/unistd.h>
|
||||
#include <LibC/stdio.h>
|
||||
#include <LibC/pwd.h>
|
||||
#include <LibC/grp.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <alloca.h>
|
||||
|
||||
int main(int c, char** v)
|
||||
{
|
||||
|
@ -11,7 +12,28 @@ int main(int c, char** v)
|
|||
struct passwd* pw = getpwuid(uid);
|
||||
struct group* gr = getgrgid(gid);
|
||||
|
||||
printf("uid=%u(%s), gid=%u(%s)\n", uid, pw ? pw->pw_name : "n/a", gid, gr ? gr->gr_name : "n/a", getpid());
|
||||
printf("uid=%u(%s), gid=%u(%s)", uid, pw ? pw->pw_name : "n/a", gid, gr ? gr->gr_name : "n/a", getpid());
|
||||
|
||||
int extra_gid_count = getgroups(0, nullptr);
|
||||
if (extra_gid_count) {
|
||||
auto* extra_gids = (gid_t*)alloca(extra_gid_count * sizeof(gid_t));
|
||||
int rc = getgroups(extra_gid_count, extra_gids);
|
||||
if (rc < 0) {
|
||||
perror("\ngetgroups");
|
||||
return 1;
|
||||
}
|
||||
printf(",");
|
||||
for (int g = 0; g < extra_gid_count; ++g) {
|
||||
auto* gr = getgrgid(extra_gids[g]);
|
||||
if (gr)
|
||||
printf("%u(%s)", extra_gids[g], gr->gr_name);
|
||||
else
|
||||
printf("%u", extra_gids[g]);
|
||||
if (g != extra_gid_count - 1)
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "InodeIdentifier.h"
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/HashTable.h>
|
||||
|
||||
inline bool isDirectory(Unix::mode_t mode) { return (mode & 0170000) == 0040000; }
|
||||
inline bool isCharacterDevice(Unix::mode_t mode) { return (mode & 0170000) == 0020000; }
|
||||
|
@ -17,11 +18,11 @@ inline bool isSetGID(Unix::mode_t mode) { return mode & 02000; }
|
|||
struct InodeMetadata {
|
||||
bool isValid() const { return inode.isValid(); }
|
||||
|
||||
bool mayExecute(uid_t u, gid_t g) const
|
||||
bool mayExecute(uid_t u, const HashTable<gid_t>& g) const
|
||||
{
|
||||
if (uid == u)
|
||||
return mode & 0100;
|
||||
if (gid == g)
|
||||
if (g.contains(gid))
|
||||
return mode & 0010;
|
||||
return mode & 0001;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue