mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 20:17:41 +00: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
12 changed files with 167 additions and 19 deletions
|
@ -8,6 +8,7 @@ template<typename T>
|
||||||
class DoublyLinkedList {
|
class DoublyLinkedList {
|
||||||
private:
|
private:
|
||||||
struct Node {
|
struct Node {
|
||||||
|
explicit Node(const T& v) : value(v) { }
|
||||||
explicit Node(T&& v) : value(move(v)) { }
|
explicit Node(T&& v) : value(move(v)) { }
|
||||||
T value;
|
T value;
|
||||||
Node* next { nullptr };
|
Node* next { nullptr };
|
||||||
|
@ -38,17 +39,13 @@ public:
|
||||||
|
|
||||||
void append(T&& value)
|
void append(T&& value)
|
||||||
{
|
{
|
||||||
auto* node = new Node(move(value));
|
append_node(new Node(move(value)));
|
||||||
if (!m_head) {
|
|
||||||
ASSERT(!m_tail);
|
}
|
||||||
m_head = node;
|
|
||||||
m_tail = node;
|
void append(const T& value)
|
||||||
return;
|
{
|
||||||
}
|
append_node(new Node(value));
|
||||||
ASSERT(m_tail);
|
|
||||||
m_tail->next = node;
|
|
||||||
node->prev = m_tail;
|
|
||||||
m_tail = node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool containsSlow(const T& value) const
|
bool containsSlow(const T& value) const
|
||||||
|
@ -136,6 +133,20 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class Iterator;
|
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; }
|
Node* head() { return m_head; }
|
||||||
const Node* head() const { return m_head; }
|
const Node* head() const { return m_head; }
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ public:
|
||||||
unsigned size() const { return m_size; }
|
unsigned size() const { return m_size; }
|
||||||
unsigned capacity() const { return m_capacity; }
|
unsigned capacity() const { return m_capacity; }
|
||||||
|
|
||||||
|
void set(const T&);
|
||||||
void set(T&&);
|
void set(T&&);
|
||||||
bool contains(const T&) const;
|
bool contains(const T&) const;
|
||||||
void clear();
|
void clear();
|
||||||
|
@ -224,6 +225,7 @@ private:
|
||||||
Bucket& lookup(const T&, unsigned* bucketIndex = nullptr);
|
Bucket& lookup(const T&, unsigned* bucketIndex = nullptr);
|
||||||
const Bucket& lookup(const T&, unsigned* bucketIndex = nullptr) const;
|
const Bucket& lookup(const T&, unsigned* bucketIndex = nullptr) const;
|
||||||
void rehash(unsigned capacity);
|
void rehash(unsigned capacity);
|
||||||
|
void insert(const T&);
|
||||||
void insert(T&&);
|
void insert(T&&);
|
||||||
|
|
||||||
Bucket* m_buckets { nullptr };
|
Bucket* m_buckets { nullptr };
|
||||||
|
@ -251,6 +253,26 @@ void HashTable<T, TraitsForT>::set(T&& value)
|
||||||
m_size++;
|
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>
|
template<typename T, typename TraitsForT>
|
||||||
void HashTable<T, TraitsForT>::rehash(unsigned newCapacity)
|
void HashTable<T, TraitsForT>::rehash(unsigned newCapacity)
|
||||||
{
|
{
|
||||||
|
@ -291,6 +313,13 @@ void HashTable<T, TraitsForT>::insert(T&& value)
|
||||||
bucket.chain.append(move(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>
|
template<typename T, typename TraitsForT>
|
||||||
bool HashTable<T, TraitsForT>::contains(const T& value) const
|
bool HashTable<T, TraitsForT>::contains(const T& value) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
//#define FORK_DEBUG
|
//#define FORK_DEBUG
|
||||||
//#define SCHEDULER_DEBUG
|
//#define SCHEDULER_DEBUG
|
||||||
#define COOL_GLOBALS
|
#define COOL_GLOBALS
|
||||||
|
#define MAX_PROCESS_GIDS 32
|
||||||
|
|
||||||
#ifdef COOL_GLOBALS
|
#ifdef COOL_GLOBALS
|
||||||
struct CoolGlobals {
|
struct CoolGlobals {
|
||||||
|
@ -304,7 +305,7 @@ int Process::exec(const String& path, Vector<String>&& arguments, Vector<String>
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handle->metadata().mayExecute(m_euid, m_egid))
|
if (!handle->metadata().mayExecute(m_euid, m_gids))
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
auto elfData = handle->readEntireFile();
|
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_tty(tty)
|
||||||
, m_ppid(ppid)
|
, m_ppid(ppid)
|
||||||
{
|
{
|
||||||
|
m_gids.set(m_gid);
|
||||||
|
|
||||||
if (fork_parent) {
|
if (fork_parent) {
|
||||||
m_sid = fork_parent->m_sid;
|
m_sid = fork_parent->m_sid;
|
||||||
m_pgid = fork_parent->m_pgid;
|
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);
|
action.handler_or_sigaction = LinearAddress((dword)act->sa_sigaction);
|
||||||
return 0;
|
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$dup(int oldfd);
|
||||||
int sys$dup2(int oldfd, int newfd);
|
int sys$dup2(int oldfd, int newfd);
|
||||||
int sys$sigaction(int signum, const Unix::sigaction* act, Unix::sigaction* old_act);
|
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();
|
static void initialize();
|
||||||
|
|
||||||
|
@ -177,6 +179,8 @@ public:
|
||||||
Process* fork(RegisterDump&);
|
Process* fork(RegisterDump&);
|
||||||
int exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment);
|
int exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment);
|
||||||
|
|
||||||
|
bool is_root() const { return m_euid == 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MemoryManager;
|
friend class MemoryManager;
|
||||||
friend bool scheduleNewProcess();
|
friend bool scheduleNewProcess();
|
||||||
|
@ -242,6 +246,7 @@ private:
|
||||||
|
|
||||||
Vector<String> m_arguments;
|
Vector<String> m_arguments;
|
||||||
Vector<String> m_initialEnvironment;
|
Vector<String> m_initialEnvironment;
|
||||||
|
HashTable<gid_t> m_gids;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcessInspectionScope {
|
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);
|
return current->sys$sigaction((int)arg1, (const Unix::sigaction*)arg2, (Unix::sigaction*)arg3);
|
||||||
case Syscall::SC_umask:
|
case Syscall::SC_umask:
|
||||||
return current->sys$umask((mode_t)arg1);
|
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:
|
default:
|
||||||
kprintf("<%u> int0x80: Unknown function %x requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x80: Unknown function %x requested {%x, %x, %x}\n", current->pid(), function, arg1, arg2, arg3);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -52,6 +52,8 @@
|
||||||
__ENUMERATE_SYSCALL(sigaction) \
|
__ENUMERATE_SYSCALL(sigaction) \
|
||||||
__ENUMERATE_SYSCALL(getppid) \
|
__ENUMERATE_SYSCALL(getppid) \
|
||||||
__ENUMERATE_SYSCALL(umask) \
|
__ENUMERATE_SYSCALL(umask) \
|
||||||
|
__ENUMERATE_SYSCALL(getgroups) \
|
||||||
|
__ENUMERATE_SYSCALL(setgroups) \
|
||||||
|
|
||||||
|
|
||||||
#define DO_SYSCALL_A0(function) Syscall::invoke((dword)(function))
|
#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;
|
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* getgrnam(const char* name);
|
||||||
struct group* getgrgid(gid_t);
|
struct group* getgrgid(gid_t);
|
||||||
|
|
||||||
|
int initgroups(const char* user, gid_t);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <Kernel/Syscall.h>
|
#include <Kernel/Syscall.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -218,4 +221,16 @@ int dup2(int old_fd, int new_fd)
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__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();
|
uid_t getuid();
|
||||||
gid_t getgid();
|
gid_t getgid();
|
||||||
pid_t getpid();
|
pid_t getpid();
|
||||||
|
int getgroups(int size, gid_t list[]);
|
||||||
|
int setgroups(size_t, const gid_t*);
|
||||||
pid_t tcgetpgrp(int fd);
|
pid_t tcgetpgrp(int fd);
|
||||||
int tcsetpgrp(int fd, pid_t pgid);
|
int tcsetpgrp(int fd, pid_t pgid);
|
||||||
int open(const char* path, int options, ...);
|
int open(const char* path, int options, ...);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#include <LibC/unistd.h>
|
#include <unistd.h>
|
||||||
#include <LibC/stdio.h>
|
#include <stdio.h>
|
||||||
#include <LibC/pwd.h>
|
#include <pwd.h>
|
||||||
#include <LibC/grp.h>
|
#include <grp.h>
|
||||||
|
#include <alloca.h>
|
||||||
|
|
||||||
int main(int c, char** v)
|
int main(int c, char** v)
|
||||||
{
|
{
|
||||||
|
@ -11,7 +12,28 @@ int main(int c, char** v)
|
||||||
struct passwd* pw = getpwuid(uid);
|
struct passwd* pw = getpwuid(uid);
|
||||||
struct group* gr = getgrgid(gid);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "InodeIdentifier.h"
|
#include "InodeIdentifier.h"
|
||||||
#include "UnixTypes.h"
|
#include "UnixTypes.h"
|
||||||
|
#include <AK/HashTable.h>
|
||||||
|
|
||||||
inline bool isDirectory(Unix::mode_t mode) { return (mode & 0170000) == 0040000; }
|
inline bool isDirectory(Unix::mode_t mode) { return (mode & 0170000) == 0040000; }
|
||||||
inline bool isCharacterDevice(Unix::mode_t mode) { return (mode & 0170000) == 0020000; }
|
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 {
|
struct InodeMetadata {
|
||||||
bool isValid() const { return inode.isValid(); }
|
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)
|
if (uid == u)
|
||||||
return mode & 0100;
|
return mode & 0100;
|
||||||
if (gid == g)
|
if (g.contains(gid))
|
||||||
return mode & 0010;
|
return mode & 0010;
|
||||||
return mode & 0001;
|
return mode & 0001;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue