Skip to content

Instantly share code, notes, and snippets.

@TruncatedDinoSour
Last active April 7, 2024 11:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TruncatedDinoSour/3f0b049ea1bb5c328f22d7365d18eb7a to your computer and use it in GitHub Desktop.
Save TruncatedDinoSour/3f0b049ea1bb5c328f22d7365d18eb7a to your computer and use it in GitHub Desktop.
(How to) check if a user is in a supplimentary group in Linux in ANSI C89. (/etc/group parser in C for Linux)
/*
* UNLICENSE
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *load_groups(size_t *size) {
int fd;
char *content;
fd = open("/etc/group", O_RDONLY);
if (fd < 0)
return 0;
*size = (size_t)lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
content = malloc((*size) + 1);
if (content == NULL)
return NULL;
content[read(fd, content, *size)] = '\0';
close(fd);
return content;
}
/* Checks if a user is in a supplimentary group */
unsigned char user_in_group(const char *groups,
const size_t size,
const char *user,
const char *group) {
size_t idx = 0;
size_t us, gs;
size_t gidx;
const char *users_start;
char *users_end;
char *found_user;
us = strlen(user);
gs = strlen(group);
if (size == 0 || us == 0 || gs == 0)
return 0;
for (gidx = 0; gidx < size; ++gidx) {
/* Find line */
while (groups[gidx] != '\n' && gidx < size)
++gidx;
/* Find group */
if (strncmp(&groups[idx], group, gs) == 0 && groups[idx + gs] == ':') {
idx = idx + gs + 3; /* Skip `group:x:`, the 3 is `:x:` */
/* Skip the group ID */
while (groups[idx] != ':' && idx < size)
++idx;
idx++; /* Skip ":" */
/* Find the EXACT user in users list (if exists) */
users_start = &groups[idx];
users_end = strchr(users_start, '\n');
found_user = strstr(users_start, user);
/* User string should not be NULL, user string should be before end
of line, user string should match exactly (hence checking next
character) */
if (found_user != NULL && found_user < users_end &&
(found_user[us] == ',' || found_user[us] == '\n'))
return 1;
}
/* Set the last line position */
idx = gidx + 1;
}
return 0;
}
int main(void) {
size_t idx;
size_t size = 0;
char *groups = load_groups(&size);
const char *comp[][2] = {
{"ari", "aria"}, {"aria", "ari"}, {"hello", "hello"},
{"ari", "ari"}, {"ari", "hello"}, {"hello", "ari"},
{"", ""}, {"aria", "aria"}, {"root", "root"}};
for (idx = 0; idx < sizeof(comp) / sizeof(comp[0]); ++idx)
printf("%s in %s = %u\n", comp[idx][0], comp[idx][1],
user_in_group(groups, size, comp[idx][0], comp[idx][1]));
free(groups);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment