Kernel/LibC: Implement {get,set,init}groups
This allows dropping /etc/group parsing from the kernel :D
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
static FILE* s_grent_fp = nullptr;
|
||||
static group s_grent_struct;
|
||||
@@ -211,3 +212,106 @@ int getgrnam_r(const char* name, struct group* grp, char* buffer, size_t bufsize
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gid_t* get_user_groups(const char* user)
|
||||
{
|
||||
FILE* fp = fopen("/etc/group", "r");
|
||||
if (fp == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const long initial_len = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
|
||||
size_t buffer_len = (initial_len == -1) ? 512 : initial_len;
|
||||
char* buffer = static_cast<char*>(malloc(buffer_len));
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t group_count = 0;
|
||||
gid_t* groups = static_cast<gid_t*>(malloc(sizeof(gid_t)));
|
||||
if (groups == nullptr)
|
||||
{
|
||||
free(buffer);
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
struct group result;
|
||||
struct group* resultp;
|
||||
|
||||
int error = getgrent_impl(fp, &result, buffer, buffer_len, &resultp);
|
||||
if (error == ERANGE)
|
||||
{
|
||||
const size_t new_buffer_len = buffer_len * 2;
|
||||
char* new_buffer = static_cast<char*>(realloc(buffer, new_buffer_len));
|
||||
if (new_buffer == nullptr)
|
||||
{
|
||||
error = ENOMEM;
|
||||
break;
|
||||
}
|
||||
buffer = new_buffer;
|
||||
buffer_len = new_buffer_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (error != 0)
|
||||
{
|
||||
free(buffer);
|
||||
free(groups);
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (resultp == nullptr)
|
||||
break;
|
||||
|
||||
bool contains = false;
|
||||
for (size_t i = 0; result.gr_mem[i] && !contains; i++)
|
||||
contains = (strcmp(result.gr_mem[i], user) == 0);
|
||||
if (!contains)
|
||||
continue;
|
||||
|
||||
gid_t* new_groups = static_cast<gid_t*>(realloc(groups, group_count * sizeof(gid_t)));
|
||||
if (new_groups == nullptr)
|
||||
{
|
||||
free(buffer);
|
||||
free(groups);
|
||||
fclose(fp);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
groups = new_groups;
|
||||
groups[group_count++] = result.gr_gid;
|
||||
}
|
||||
|
||||
groups[group_count] = -1;
|
||||
|
||||
free(buffer);
|
||||
fclose(fp);
|
||||
return groups;
|
||||
}
|
||||
|
||||
int initgroups(const char* user, gid_t group)
|
||||
{
|
||||
gid_t* groups = get_user_groups(user);
|
||||
if (groups == nullptr)
|
||||
return -1;
|
||||
|
||||
size_t group_count = 0;
|
||||
while (groups[group_count] != -1)
|
||||
group_count++;
|
||||
groups[group_count] = group;
|
||||
|
||||
int result = setgroups(group_count + 1, groups);
|
||||
free(groups);
|
||||
return result;
|
||||
}
|
||||
|
||||
int setgroups(size_t size, const gid_t list[])
|
||||
{
|
||||
return syscall(SYS_SETGROUPS, list, size);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ __BEGIN_DECLS
|
||||
struct group
|
||||
{
|
||||
char* gr_name; /* The name of the group. */
|
||||
char* gr_passwd;/* The password of the group */
|
||||
char* gr_passwd; /* The password of the group */
|
||||
gid_t gr_gid; /* Numerical group ID. */
|
||||
char** gr_mem; /* Pointer to a null-terminated array of character pointers to member names. */
|
||||
};
|
||||
@@ -27,6 +27,9 @@ struct group* getgrnam(const char* name);
|
||||
int getgrnam_r(const char* name, struct group* grp, char* buffer, size_t bufsize, struct group** result);
|
||||
void setgrent(void);
|
||||
|
||||
int initgroups(const char* user, gid_t group);
|
||||
int setgroups(size_t size, const gid_t list[]);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
@@ -111,6 +111,8 @@ __BEGIN_DECLS
|
||||
O(SYS_FLOCK, flock) \
|
||||
O(SYS_GET_NPROCESSOR, get_nprocessor) \
|
||||
O(SYS_FUTEX, futex) \
|
||||
O(SYS_GETGROUPS, getgroups) \
|
||||
O(SYS_SETGROUPS, setgroups) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
||||
@@ -673,8 +673,7 @@ error:
|
||||
|
||||
int getgroups(int gidsetsize, gid_t grouplist[])
|
||||
{
|
||||
dwarnln("FIXME: getgroups({}, {})", gidsetsize, grouplist);
|
||||
return 0;
|
||||
return syscall(SYS_GETGROUPS, grouplist, gidsetsize);
|
||||
}
|
||||
|
||||
pid_t getppid(void)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -94,6 +95,8 @@ int main(int argc, char** argv)
|
||||
|
||||
printf("Welcome back %s!\n", pwd->pw_name);
|
||||
|
||||
if (initgroups(name_buffer, pwd->pw_gid) == -1)
|
||||
perror("initgroups");
|
||||
if (setgid(pwd->pw_gid) == -1)
|
||||
perror("setgid");
|
||||
if (setuid(pwd->pw_uid) == -1)
|
||||
|
||||
Reference in New Issue
Block a user