Skip to content

Commit

Permalink
Add some basic setgroups(), getgroups() and initgroups().
Browse files Browse the repository at this point in the history
Also teach /bin/id to print the user's supplemental groups.
  • Loading branch information
awesomekling committed Nov 7, 2018
1 parent d3bd379 commit a7f1d89
Show file tree
Hide file tree
Showing 12 changed files with 167 additions and 19 deletions.
33 changes: 22 additions & 11 deletions AK/DoublyLinkedList.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -38,17 +39,13 @@ class DoublyLinkedList {

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
Expand Down Expand Up @@ -136,6 +133,20 @@ class DoublyLinkedList {
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; }

Expand Down
29 changes: 29 additions & 0 deletions AK/HashTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class HashTable {
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();
Expand Down Expand Up @@ -224,6 +225,7 @@ class HashTable {
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 };
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
{
Expand Down
35 changes: 34 additions & 1 deletion Kernel/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//#define FORK_DEBUG
//#define SCHEDULER_DEBUG
#define COOL_GLOBALS
#define MAX_PROCESS_GIDS 32

#ifdef COOL_GLOBALS
struct CoolGlobals {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions Kernel/Process.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ class Process : public InlineLinkedListNode<Process> {
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();

Expand Down Expand Up @@ -177,6 +179,8 @@ class Process : public InlineLinkedListNode<Process> {
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();
Expand Down Expand Up @@ -242,6 +246,7 @@ class Process : public InlineLinkedListNode<Process> {

Vector<String> m_arguments;
Vector<String> m_initialEnvironment;
HashTable<gid_t> m_gids;
};

class ProcessInspectionScope {
Expand Down
4 changes: 4 additions & 0 deletions Kernel/Syscall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions Kernel/Syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
22 changes: 22 additions & 0 deletions LibC/grp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,26 @@ struct group* getgrent()
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);
}

}
2 changes: 2 additions & 0 deletions LibC/grp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
15 changes: 15 additions & 0 deletions LibC/unistd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down Expand Up @@ -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);
}

}
2 changes: 2 additions & 0 deletions LibC/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...);
Expand Down
32 changes: 27 additions & 5 deletions Userland/id.cpp
Original file line number Diff line number Diff line change
@@ -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)
{
Expand All @@ -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;
}

5 changes: 3 additions & 2 deletions VirtualFileSystem/InodeMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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;
}
Expand Down

0 comments on commit a7f1d89

Please sign in to comment.