Add some basic setgroups(), getgroups() and initgroups().

Also teach /bin/id to print the user's supplemental groups.
This commit is contained in:
Andreas Kling 2018-11-07 01:38:51 +01:00
parent d3bd3791cb
commit a7f1d892a9
Notes: sideshowbarker 2024-07-19 18:32:47 +09:00
12 changed files with 167 additions and 19 deletions

View file

@ -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; }

View file

@ -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
{

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;

View file

@ -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))

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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, ...);

View file

@ -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;
}

View file

@ -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;
}