234 lines
5.4 KiB
C
234 lines
5.4 KiB
C
/// @file grp.c
|
|
/// @brief
|
|
/// @copyright (c) 2014-2022 This file is distributed under the MIT License.
|
|
/// See LICENSE.md for details.
|
|
|
|
#include "grp.h"
|
|
#include "sys/unistd.h"
|
|
#include "sys/errno.h"
|
|
#include "assert.h"
|
|
#include "string.h"
|
|
#include "stdio.h"
|
|
#include "debug.h"
|
|
#include "fcntl.h"
|
|
|
|
static int __fd = -1;
|
|
|
|
static inline void __parse_line(group_t *grp, char *buf)
|
|
{
|
|
assert(grp && "Received null grp!");
|
|
char *token;
|
|
// Parse the group name.
|
|
if ((token = strtok(buf, ":")) != NULL)
|
|
grp->gr_name = token;
|
|
// Parse the group passwd.
|
|
if ((token = strtok(NULL, ":")) != NULL)
|
|
grp->gr_passwd = token;
|
|
// Parse the group id.
|
|
if ((token = strtok(NULL, ":")) != NULL)
|
|
grp->gr_gid = atoi(token);
|
|
|
|
size_t found_users = 0;
|
|
while ((token = strtok(NULL, ",\n\0")) != NULL && found_users < MAX_MEMBERS_PER_GROUP) {
|
|
grp->gr_mem[found_users] = token;
|
|
found_users += 1;
|
|
}
|
|
|
|
// Null terminate array
|
|
grp->gr_mem[found_users] = "\0";
|
|
}
|
|
|
|
static inline char *__search_entry(int fd, char *buf, int buflen, const char *name, gid_t gid)
|
|
{
|
|
int ret;
|
|
char c;
|
|
int pos = 0;
|
|
while ((ret = read(fd, &c, 1U))) {
|
|
// Skip carriage return.
|
|
if (c == '\r')
|
|
continue;
|
|
if (pos >= buflen) {
|
|
errno = ERANGE;
|
|
return NULL;
|
|
}
|
|
// If we have found a newline or the EOF, parse the entry.
|
|
if ((c == '\n') || (ret == EOF)) {
|
|
// Close the buffer.
|
|
buf[pos] = 0;
|
|
// Check the entry.
|
|
if (name) {
|
|
if (strncmp(buf, name, strlen(name)) == 0)
|
|
return buf;
|
|
} else {
|
|
int gid_start = -1, col_count = 0;
|
|
for (int i = 0; i < pos; ++i) {
|
|
if (buf[i] == ':') {
|
|
if (++col_count == 2) {
|
|
gid_start = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((gid_start != -1) && (gid_start < pos)) {
|
|
// Parse the gid.
|
|
int found_gid = atoi(&buf[gid_start]);
|
|
// Check the gid.
|
|
if (found_gid == gid)
|
|
return buf;
|
|
}
|
|
}
|
|
// Reset the index.
|
|
pos = 0;
|
|
// If we have reached the EOF stop.
|
|
if (ret == EOF)
|
|
break;
|
|
} else {
|
|
buf[pos++] = c;
|
|
}
|
|
}
|
|
errno = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
group_t *getgrgid(gid_t gid)
|
|
{
|
|
static group_t grp;
|
|
static char buffer[BUFSIZ];
|
|
|
|
group_t *result;
|
|
if (!getgrgid_r(gid, &grp, buffer, BUFSIZ, &result))
|
|
return NULL;
|
|
|
|
return &grp;
|
|
}
|
|
|
|
group_t *getgrnam(const char *name)
|
|
{
|
|
if (name == NULL)
|
|
return NULL;
|
|
|
|
static group_t grp;
|
|
static char buffer[BUFSIZ];
|
|
|
|
group_t *result;
|
|
if (!getgrnam_r(name, &grp, buffer, BUFSIZ, &result))
|
|
return NULL;
|
|
|
|
return &grp;
|
|
}
|
|
|
|
int getgrgid_r(gid_t gid, group_t *group, char *buf, size_t buflen, group_t **result)
|
|
{
|
|
int fd = open("/etc/group", O_RDONLY, 0);
|
|
if (fd == -1) {
|
|
errno = ENOENT;
|
|
*result = NULL;
|
|
return 0;
|
|
}
|
|
|
|
char *entry = __search_entry(fd, buf, buflen, NULL, gid);
|
|
if (entry != NULL) {
|
|
// Close the file.
|
|
close(fd);
|
|
// Parse the line.
|
|
__parse_line(group, entry);
|
|
// Return success.
|
|
return 1;
|
|
}
|
|
|
|
// Close the file.
|
|
close(fd);
|
|
// Return fail.
|
|
return 0;
|
|
}
|
|
|
|
int getgrnam_r(const char *name, group_t *group, char *buf, size_t buflen, group_t **result)
|
|
{
|
|
int fd = open("/etc/group", O_RDONLY, 0);
|
|
if (fd == -1) {
|
|
errno = ENOENT;
|
|
*result = NULL;
|
|
return 0;
|
|
}
|
|
|
|
char *entry = __search_entry(fd, buf, buflen, name, 0);
|
|
if (entry != NULL) {
|
|
// Close the file.
|
|
close(fd);
|
|
// Parse the line.
|
|
__parse_line(group, entry);
|
|
// Return success.
|
|
return 1;
|
|
}
|
|
|
|
// Close the file.
|
|
close(fd);
|
|
// Return fail.
|
|
return 0;
|
|
}
|
|
|
|
group_t *getgrent(void)
|
|
{
|
|
static group_t result;
|
|
|
|
if (__fd == -1) {
|
|
//pr_debug("Opening group file\n");
|
|
__fd = open("/etc/group", O_RDONLY, 0);
|
|
if (__fd == -1) {
|
|
errno = ENOENT;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int ret;
|
|
char c;
|
|
int pos = 0;
|
|
|
|
static char buffer[BUFSIZ];
|
|
while ((ret = read(__fd, &c, 1U))) {
|
|
// Skip carriage return.
|
|
if (c == '\r')
|
|
continue;
|
|
|
|
if (pos >= BUFSIZ) {
|
|
errno = ERANGE;
|
|
return NULL;
|
|
}
|
|
|
|
// If we have found a newline or the EOF, parse the entry.
|
|
if ((c == '\n') || (ret == EOF)) {
|
|
// Close the buffer.
|
|
buffer[pos] = 0;
|
|
|
|
// Check the entry.
|
|
if (strlen(buffer) != 0) {
|
|
//pr_debug("Found entry in group file: %s\n", buffer);
|
|
__parse_line(&result, buffer);
|
|
return &result;
|
|
}
|
|
|
|
// If we have reached the EOF stop.
|
|
if (ret == EOF)
|
|
break;
|
|
|
|
} else {
|
|
buffer[pos++] = c;
|
|
}
|
|
}
|
|
|
|
errno = ENOENT;
|
|
return NULL;
|
|
}
|
|
|
|
void endgrent(void)
|
|
{
|
|
//pr_debug("Closing group file\n");
|
|
close(__fd);
|
|
__fd = -1;
|
|
}
|
|
|
|
void setgrent(void)
|
|
{
|
|
//pr_debug("Resetting pointer to beginning of group file\n");
|
|
lseek(__fd, 0, SEEK_SET);
|
|
} |