groups: First pass at support for supplementary group lists

This commit is contained in:
K. Lange 2021-08-31 20:46:48 +09:00
parent 8775a28209
commit 8984cc8f71
19 changed files with 226 additions and 13 deletions

View File

@ -119,9 +119,7 @@ int main (int argc, char ** argv) {
pid_t _session_pid = fork();
if (!_session_pid) {
setgid(uid);
setuid(uid);
toaru_auth_set_vars();
toaru_set_credentials(uid);
char * args[] = {"/bin/session", NULL};
execvp(args[0], args);
exit(1);

37
apps/groups.c Normal file
View File

@ -0,0 +1,37 @@
/**
* @brief List group memberships.
* @file apps/groups.c
*
* @copyright
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2021 K. Lange
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <pwd.h>
int main(int argc, char ** argv) {
/* First print our egid group */
struct passwd * p = getpwuid(getegid());
if (p) {
fprintf(stdout, "%s ", p->pw_name);
}
/* Then get the group list. */
int groupCount = getgroups(0, NULL);
if (groupCount) {
gid_t * myGroups = malloc(sizeof(gid_t) * groupCount);
groupCount = getgroups(groupCount, myGroups);
for (int i = 0; i < groupCount; ++i) {
p = getpwuid(myGroups[i]);
if (p) {
fprintf(stdout, "%s ", p->pw_name);
}
}
}
fprintf(stdout,"\n");
endpwent();
return 0;
}

View File

@ -27,10 +27,7 @@ int main(int argc, char * argv[]) {
int _session_pid = fork();
if (!_session_pid) {
setgid(1000);
setuid(1000);
toaru_auth_set_vars();
toaru_set_credentials(1000);
char * args[] = {"/bin/session", NULL};
execvp(args[0], args);

View File

@ -144,9 +144,8 @@ do_fork:
f = fork();
if (getpid() != pid) {
ioctl(STDIN_FILENO, IOCTLTTYLOGIN, &uid);
setuid(uid);
toaru_set_credentials(uid);
setsid();
toaru_auth_set_vars();
char * args[] = {
getenv("SHELL"),
NULL

View File

@ -26,6 +26,8 @@
#define SUDO_TIME 5 MINUTES
extern int setgroups(int size, const gid_t list[]);
static int sudo_loop(int (*prompt_callback)(char * username, char * password, int failures, char * argv[]), char * argv[]) {
int fails = 0;
@ -130,6 +132,7 @@ static int sudo_loop(int (*prompt_callback)(char * username, char * password, in
/* Actually become root, so real user id = 0 */
setgid(0);
setuid(0);
setgroups(0,NULL);
if (!strcmp(argv[1], "-s")) {
argv[1] = getenv("SHELL");

2
base/etc/group Normal file
View File

@ -0,0 +1,2 @@
root:x:0:
adm:x:1:local

View File

@ -1,2 +1,3 @@
root:x:0:0:Administrator:/home/root:/bin/sh:fancy
adm:x:1:1:Administrators:/tmp:/bin/false:nope
local:x:1000:1000:Local User:/home/local:/bin/sh:fancy

View File

@ -117,6 +117,9 @@ typedef struct process {
spin_lock_t sched_lock;
uintptr_t signals[NUMSIGNALS+1];
int supplementary_group_count;
gid_t * supplementary_group_list;
} process_t;
typedef struct {

View File

@ -127,6 +127,8 @@ DECL_SYSCALL4(fswait3, int, int*, int, int*);
DECL_SYSCALL0(getgid);
DECL_SYSCALL0(getegid);
DECL_SYSCALL1(setgid, unsigned int);
DECL_SYSCALL2(getgroups, int, int*);
DECL_SYSCALL2(setgroups, int, const int*);
_End_C_Header

View File

@ -68,3 +68,5 @@
#define SYS_GETGID 66
#define SYS_GETEGID 67
#define SYS_SETGID 68
#define SYS_GETGROUPS 69
#define SYS_SETGROUPS 70

View File

@ -13,6 +13,7 @@
#pragma once
#include <_cheader.h>
#include <unistd.h>
_Begin_C_Header
@ -31,4 +32,14 @@ extern int toaru_auth_check_pass(char * user, char * pass);
*/
extern void toaru_auth_set_vars(void);
/**
* Set supplementary groups from /etc/groups
*/
extern void toaru_auth_set_groups(uid_t uid);
/**
* Do the above two steps, and setuid, and setgid...
*/
extern void toaru_set_credentials(uid_t uid);
_End_C_Header

View File

@ -106,4 +106,6 @@ extern int truncate(const char *, off_t);
#define _PC_PATH_MAX 1
extern long pathconf(const char *path, int name);
extern int getgroups(int size, gid_t list[]);
_End_C_Header

View File

@ -435,6 +435,14 @@ process_t * spawn_process(volatile process_t * parent, int flags) {
proc->job = parent->job;
proc->session = parent->session;
if (parent->supplementary_group_count) {
proc->supplementary_group_count = parent->supplementary_group_count;
proc->supplementary_group_list = malloc(sizeof(gid_t) * proc->supplementary_group_count);
for (int i = 0; i < proc->supplementary_group_count; ++i) {
proc->supplementary_group_list[i] = parent->supplementary_group_list[i];
}
}
proc->thread.context.sp = 0;
proc->thread.context.bp = 0;
proc->thread.context.ip = 0;
@ -579,6 +587,11 @@ void process_delete(process_t * proc) {
shm_release_all(proc);
free(proc->shm_mappings);
if (proc->supplementary_group_list) {
proc->supplementary_group_count = 0;
free(proc->supplementary_group_list);
}
/* Is someone using this process? */
for (int i = 0; i < processor_count; ++i) {
if (i == this_core->cpu_id) continue;

View File

@ -499,6 +499,45 @@ static long sys_setgid(gid_t new_gid) {
return -EPERM;
}
static long sys_getgroups(int size, gid_t list[]) {
if (size == 0) {
return this_core->current_process->supplementary_group_count;
} else if (size < this_core->current_process->supplementary_group_count) {
return -EINVAL;
} else {
for (int i = 0; i < this_core->current_process->supplementary_group_count; ++i) {
PTR_VALIDATE(list + i);
list[i] = this_core->current_process->supplementary_group_list[i];
}
return this_core->current_process->supplementary_group_count;
}
}
static long sys_setgroups(int size, const gid_t list[]) {
if (this_core->current_process->user != USER_ROOT_UID) return -EPERM;
if (size < 0) return -EINVAL;
if (size > 32) return -EINVAL; /* Arbitrary decision */
/* Free the current set. */
if (this_core->current_process->supplementary_group_count) {
free(this_core->current_process->supplementary_group_list);
this_core->current_process->supplementary_group_list = NULL;
}
this_core->current_process->supplementary_group_count = size;
if (size == 0) return 0;
this_core->current_process->supplementary_group_list = malloc(sizeof(gid_t) * size);
for (int i = 0; i < size; ++i) {
PTR_VALIDATE(list + i);
this_core->current_process->supplementary_group_list[i] = list[i];
}
return 0;
}
static long sys_getpid(void) {
/* The user actually wants the pid of the originating thread (which can be us). */
return this_core->current_process->group ? (long)this_core->current_process->group : (long)this_core->current_process->id;
@ -979,6 +1018,8 @@ static long (*syscalls[])() = {
[SYS_GETGID] = sys_getgid,
[SYS_GETEGID] = sys_getegid,
[SYS_SETGID] = sys_setgid,
[SYS_GETGROUPS] = sys_getgroups,
[SYS_SETGROUPS] = sys_setgroups,
[SYS_SOCKET] = net_socket,
[SYS_SETSOCKOPT] = net_setsockopt,

View File

@ -73,9 +73,14 @@ int has_permission(fs_node_t * node, int permission_bit) {
uint8_t group_perm = (permissions >> 3) & 07;
if (this_core->current_process->user == node->uid) my_permissions |= user_perm;
if (this_core->current_process->user_group == node->uid) my_permissions |= group_perm;
/* TODO: Supplementary group IDs */
if (this_core->current_process->user_group == node->gid) my_permissions |= group_perm;
else if (this_core->current_process->supplementary_group_count) {
for (int i = 0; i < this_core->current_process->supplementary_group_count; ++i) {
if (this_core->current_process->supplementary_group_list[i] == node->gid) {
my_permissions |= group_perm;
}
}
}
return (permission_bit & my_permissions);
}

View File

@ -17,6 +17,8 @@
extern struct passwd *fgetpwent(FILE *stream);
#endif
extern int setgroups(int size, const gid_t list[]);
#define MASTER_PASSWD "/etc/master.passwd"
int toaru_auth_check_pass(char * user, char * pass) {
@ -63,3 +65,74 @@ void toaru_auth_set_vars(void) {
chdir(getenv("HOME"));
}
void toaru_auth_set_groups(uid_t uid) {
/* Get the username for this uid */
struct passwd * pwd = getpwuid(uid);
/* No username? No group memberships! */
if (!pwd) goto no_groups;
/* Open the group file */
FILE * groupList = fopen("/etc/group","r");
/* No groups? No membership. */
if (!groupList) goto no_groups;
/* Scan through lines of groups. */
#define LINE_LEN 2048
char * pw_blob = malloc(LINE_LEN);
int groupCount = 0;
gid_t myGroups[32] = {0};
while (!feof(groupList)) {
memset(pw_blob, 0x00, LINE_LEN);
fgets(pw_blob, LINE_LEN, groupList);
if (pw_blob[strlen(pw_blob)-1] == '\n') {
pw_blob[strlen(pw_blob)-1] = '\0'; /* erase newline */
}
/* Tokenize */
char * memberlist = NULL;
char *p, *last;
gid_t groupNumber = -1;
int i = 0;
for ((p = strtok_r(pw_blob, ":", &last)); p;
(p = strtok_r(NULL, ":", &last)), i++) {
if (i == 2) {
groupNumber = atoi(p);
} else if (i == 3) {
memberlist = p;
break;
}
}
if (groupNumber == -1) continue;
if (!memberlist) continue;
for ((p = strtok_r(memberlist, ",", &last)); p;
(p = strtok_r(NULL, ",", &last))) {
if (!strcmp(p, pwd->pw_name)) {
if (groupCount < 32) {
myGroups[groupCount] = groupNumber;
groupCount++;
}
}
}
}
setgroups(groupCount, myGroups);
free(pw_blob);
fclose(groupList);
return;
no_groups:
setgroups(0, NULL);
}
void toaru_set_credentials(uid_t uid) {
toaru_auth_set_groups(uid);
setgid(uid);
setuid(uid);
toaru_auth_set_vars();
}

11
libc/unistd/getgroups.c Normal file
View File

@ -0,0 +1,11 @@
#include <unistd.h>
#include <syscall.h>
#include <syscall_nums.h>
#include <errno.h>
DEFN_SYSCALL2(getgroups, SYS_GETGROUPS, int, gid_t *);
int getgroups(int size, gid_t list[]) {
__sets_errno(syscall_getgroups(size, list));
}

12
libc/unistd/setgroups.c Normal file
View File

@ -0,0 +1,12 @@
#include <unistd.h>
#include <syscall.h>
#include <syscall_nums.h>
#include <errno.h>
DEFN_SYSCALL2(setgroups, SYS_SETGROUPS, int, const gid_t *);
int setgroups(int size, const gid_t list[]) {
__sets_errno(syscall_setgroups(size, list));
}

View File

@ -71,7 +71,8 @@ static fs_node_t * spkr_device_create(void) {
fs_node_t * fnode = malloc(sizeof(fs_node_t));
memset(fnode, 0x00, sizeof(fs_node_t));
snprintf(fnode->name, 5, "spkr");
fnode->mask = 0666; /* TODO need a speaker group */
fnode->mask = 0660; /* TODO need a speaker group */
fnode->gid = 1;
fnode->flags = FS_CHARDEVICE;
fnode->write = write_spkr;
return fnode;