This repository has been archived on 2025-06-27. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
chkgrp/chkgrp-ng.c
2025-06-19 01:15:24 +02:00

153 lines
3.8 KiB
C

/**
* chkgrp-ng is a program that checks if a user is a member of a group.
*
* Author: Johannes Findeisen <you@hanez.org> - 2025
* Homepage: https://git.xw3.org/hanez/chkgrp
* License: Apache-2.0 (see LICENSE)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 1024
#define MAX_NAME 256
void print_help(const char *prog)
{
printf("Usage: %s [OPTIONS] <username> <groupname>\n", prog);
printf("Options:\n");
printf(" --passwd PATH Use custom /etc/passwd file\n");
printf(" --group PATH Use custom /etc/group file\n");
printf(" -q Quiet mode (no output)\n");
printf(" -h Show this help message\n");
}
const char *get_arg(int *i, int argc, char *argv[], const char *opt)
{
if (*i + 1 >= argc) {
fprintf(stderr, "Missing argument after %s\n", opt);
exit(2);
}
return argv[++(*i)];
}
int get_user_gid(const char *user, const char *passwd_path)
{
FILE *fp = fopen(passwd_path, "r");
if (!fp) {
fprintf(stderr, "Error: Cannot open passwd file: %s\n", passwd_path);
return -1;
}
char line[MAX_LINE];
while (fgets(line, sizeof(line), fp)) {
char *name = strtok(line, ":");
if (!name || strcmp(name, user) != 0) continue;
strtok(NULL, ":"); // password
strtok(NULL, ":"); // UID
char *gid_str = strtok(NULL, ":");
fclose(fp);
return gid_str ? atoi(gid_str) : -1;
}
fclose(fp);
return -1;
}
int check_group(const char *user, const char *group, int user_gid,
const char *group_path)
{
FILE *fp = fopen(group_path, "r");
if (!fp) {
fprintf(stderr, "Error: Cannot open group file: %s\n", group_path);
return -1;
}
char line[MAX_LINE];
while (fgets(line, sizeof(line), fp)) {
char *grp = strtok(line, ":");
if (!grp || strcmp(grp, group) != 0) continue;
strtok(NULL, ":"); // password
char *gid_str = strtok(NULL, ":");
if (!gid_str) break;
int group_gid = atoi(gid_str);
if (group_gid == user_gid) {
fclose(fp);
return 1;
}
char *members = strtok(NULL, ":\n");
if (!members) break;
char *m = strtok(members, ",");
while (m) {
if (strcmp(m, user) == 0) {
fclose(fp);
return 1;
}
m = strtok(NULL, ",");
}
fclose(fp);
return 0;
}
fclose(fp);
return -1;
}
int main(int argc, char *argv[])
{
const char *passwd_file = "/etc/passwd";
const char *group_file = "/etc/group";
int quiet = 0;
int i = 1;
const char *username = NULL, *groupname = NULL;
while (i < argc) {
if (!strcmp(argv[i], "--passwd")) {
passwd_file = get_arg(&i, argc, argv, "--passwd");
} else if (!strcmp(argv[i], "--group")) {
group_file = get_arg(&i, argc, argv, "--group");
} else if (!strcmp(argv[i], "-q")) {
quiet = 1;
} else if (!strcmp(argv[i], "-h")) {
print_help(argv[0]);
return 0;
} else if (!username) {
username = argv[i];
} else if (!groupname) {
groupname = argv[i];
} else {
fprintf(stderr, "Unexpected argument: %s\n", argv[i]);
return 2;
}
i++;
}
if (!username || !groupname ||
strlen(username) > MAX_NAME || strlen(groupname) > MAX_NAME) {
return 2;
}
int user_gid = get_user_gid(username, passwd_file);
if (user_gid < 0)
return 2;
int result = check_group(username, groupname, user_gid, group_file);
if (result == 1) {
if (!quiet) puts("Yes");
return 0;
} else if (result == 0) {
if (!quiet) puts("No");
return 1;
}
return 2;
}