Merged with chkgrp and renamed to chkusr.
This commit is contained in:
parent
b2461ba7a0
commit
8644ccbdc5
12 changed files with 779 additions and 22 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -1,5 +1,12 @@
|
|||
*.o
|
||||
*.so
|
||||
chkgrp
|
||||
chkgrp-min
|
||||
chkgrp-native
|
||||
chkgrp-native-min
|
||||
chkgrp-native-min-extended
|
||||
chkgrp-ng
|
||||
chkpwd
|
||||
chkpwd.o
|
||||
chkpwd.1.gz
|
||||
test
|
||||
test.c
|
||||
|
|
|
|||
26
Makefile
26
Makefile
|
|
@ -1,18 +1,44 @@
|
|||
all:
|
||||
$(CC) -Wall -o ./chkgrp ./chkgrp.c
|
||||
$(CC) -Wall -o ./chkgrp-min ./chkgrp-min.c
|
||||
$(CC) -Wall -o ./chkgrp-native ./chkgrp-native.c
|
||||
$(CC) -Wall -o ./chkgrp-native-min ./chkgrp-native-min.c
|
||||
$(CC) -Wall -o ./chkgrp-native-min-extended ./chkgrp-native-min-extended.c
|
||||
$(CC) -Wall -o ./chkgrp-ng ./chkgrp-ng.c
|
||||
$(CC) -Wall -o ./chkpwd ./chkpwd.c -lpam
|
||||
gzip -fk ./chkpwd.1
|
||||
|
||||
clean:
|
||||
rm -f ./chkgrp
|
||||
rm -f ./chkgrp-min
|
||||
rm -f ./chkgrp-native
|
||||
rm -f ./chkgrp-native-min
|
||||
rm -f ./chkgrp-native-min-extended
|
||||
rm -f ./chkgrp-ng
|
||||
rm -f ./chkpwd
|
||||
rm -f ./chkpwd.1.gz
|
||||
rm -f ./test
|
||||
|
||||
install:
|
||||
install -g 0 -o 0 -m 0655 ./chkgrp /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./chkgrp-min /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./chkgrp-native /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./chkgrp-native-min /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./chkgrp-native-min-extended /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./chkgrp-ng /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./chkpwd /usr/bin/
|
||||
install -g 0 -o 0 -m 0644 ./chkpwd.h /usr/include/
|
||||
install -g 0 -o 0 -m 0644 ./chkpwd.1.gz /usr/share/man/man1/
|
||||
install -g 0 -o 0 -m 0655 ./lua/chkgrp-native-min-extended.lua /usr/bin/
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/bin/chkgrp
|
||||
rm -f /usr/bin/chkgrp-min
|
||||
rm -f /usr/bin/chkgrp-native
|
||||
rm -f /usr/bin/chkgrp-native-min
|
||||
rm -f /usr/bin/chkgrp-native-min-extended
|
||||
rm -f /usr/bin/chkgrp-native-min-extended.lua
|
||||
rm -f /usr/bin/chkgrp-ng
|
||||
rm -f /usr/bin/chkpwd
|
||||
rm -f /usr/include/chkpwd.h
|
||||
rm -f /usr/share/man/man1/chkpwd.1.gz
|
||||
|
|
|
|||
54
README.md
54
README.md
|
|
@ -1,18 +1,30 @@
|
|||
# chkpwd
|
||||
# MERGED PROJECT!!! I WILL UPDATE THIS README IN THE NEXT DAYS!!! THE FOLLOWING DOCUMENTATION WILL NOT WORK ACTUALLY!
|
||||
|
||||
# chkusr
|
||||
|
||||
chkusr is a set of programs to verify information about a user on a UNIX based systems.
|
||||
|
||||
## chkgrp
|
||||
|
||||
chkgrp is a set of programs to verify if a user is a member of a group on a UNIX based system. This code is so simple that it describes itself very good.
|
||||
|
||||
More information will follow... Actually there are multiple programs with some different behavior. I will write more about this, but for now I will not.
|
||||
|
||||
## chkpwd
|
||||
|
||||
chkpwd is a program that checks the validity of a users password on a UNIX/[PAM](https://en.wikipedia.org/wiki/Pluggable_Authentication_Module)-based system.
|
||||
|
||||
Currently chkpwd is only tested on Linux, but it should work on a [AIX](https://en.wikipedia.org/wiki/IBM_AIX), [DragonFly BSD](https://www.dragonflybsd.org/), [FreeBSD](https://www.freebsd.org/), [HP-UX](https://en.wikipedia.org/wiki/HP-UX), [Linux](https://kernel.org/), [macOS](https://en.wikipedia.org/wiki/MacOS), [NetBSD](https://netbsd.org/) and [Solaris](https://en.wikipedia.org/wiki/Oracle_Solaris) operating system too.
|
||||
|
||||
## The idea
|
||||
### The idea
|
||||
|
||||
I needed a program to verify passwords of users on Linux/UNIX systems using PAM that just returns 0 on success and 1 on error.
|
||||
|
||||
## Requirements
|
||||
### Requirements
|
||||
|
||||
You need the PAM development package installed. On Alpine it is named linux-pam-dev, on Debian based systems it is libpam0g-dev.
|
||||
|
||||
## Building chkpwd
|
||||
### Building chkpwd
|
||||
|
||||
```
|
||||
git clone https://git.xw3.org/hanez/chkpwd.git
|
||||
|
|
@ -22,7 +34,7 @@ make
|
|||
|
||||
The code only supports verifying passwords for user id 1000 by default. Look at the file chkpwd.h for some compile time options!
|
||||
|
||||
### Custom build example
|
||||
#### Custom build example
|
||||
|
||||
Set MAX_UID and MIN_UID at compile time:
|
||||
|
||||
|
|
@ -30,7 +42,7 @@ Set MAX_UID and MIN_UID at compile time:
|
|||
gcc -Wall -DMAX_UID=1000 -DMIN_UID=1000 -o chkpwd chkpwd.c -lpam -lpam_misc
|
||||
```
|
||||
|
||||
## Installation
|
||||
### Installation
|
||||
|
||||
**WARNING:** Install this software with care. chkpwd could easily be used for bruteforcing passwords from local users!
|
||||
|
||||
|
|
@ -42,13 +54,13 @@ chkpwd is installed to /usr/bin/.
|
|||
|
||||
chkpwd.h is installed to /usr/include/ for use in other applications.
|
||||
|
||||
## Uninstall
|
||||
### Uninstall
|
||||
|
||||
```
|
||||
sudo make uninstall
|
||||
```
|
||||
|
||||
## Usage
|
||||
### Usage
|
||||
|
||||
```
|
||||
chkpwd -h
|
||||
|
|
@ -68,44 +80,38 @@ You can also use chkpwd even without installing by just running the following co
|
|||
./chkpwd
|
||||
```
|
||||
|
||||
### Return codes
|
||||
#### Return codes
|
||||
|
||||
chkpwd returns 0 on success, 1 otherwise.
|
||||
|
||||
### Examples
|
||||
#### Examples
|
||||
|
||||
|
||||
#### Interactive mode asking for a username and a password
|
||||
##### Interactive mode asking for a username and a password
|
||||
|
||||
```
|
||||
chkpwd
|
||||
```
|
||||
|
||||
#### Interactive mode only asking for a password
|
||||
##### Interactive mode only asking for a password
|
||||
|
||||
```
|
||||
chkpwd -u hanez
|
||||
```
|
||||
|
||||
#### None interactive mode with username and password provided as arguments to chkpwd
|
||||
##### None interactive mode with username and password provided as arguments to chkpwd
|
||||
|
||||
```
|
||||
chkpwd -u hanez -p password
|
||||
```
|
||||
|
||||
#### Request the result from the above commands
|
||||
##### Request the result from the above commands
|
||||
|
||||
```
|
||||
echo $?
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
chkpwd is licensed under the Apache License, Version 2.0.
|
||||
|
||||
See LICENSE for details.
|
||||
|
||||
## Links
|
||||
#### Links
|
||||
|
||||
- [https://git.xw3.org/hanez/chkpwd](https://git.xw3.org/hanez/chkpwd)
|
||||
- [https://www.man7.org/linux/man-pages/man8/unix_chkpwd.8.html](https://www.man7.org/linux/man-pages/man8/unix_chkpwd.8.html)
|
||||
|
|
@ -115,3 +121,9 @@ See LICENSE for details.
|
|||
- [https://github.com/ViKingIX/pam_test](https://github.com/ViKingIX/pam_test)
|
||||
- [https://github.com/Dareka826/chk_pw](https://github.com/Dareka826/chk_pw)
|
||||
|
||||
## License
|
||||
|
||||
chkpwd is licensed under the Apache License, Version 2.0.
|
||||
|
||||
See LICENSE for details.
|
||||
|
||||
|
|
|
|||
48
chkgrp-min.c
Normal file
48
chkgrp-min.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* chkgrp-min 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>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#define MAX_NAME 256
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
return 2;
|
||||
|
||||
if (strlen(argv[1]) > MAX_NAME || strlen(argv[2]) > MAX_NAME)
|
||||
return 2;
|
||||
|
||||
struct passwd *pw = getpwnam(argv[1]);
|
||||
if (!pw)
|
||||
return 2;
|
||||
|
||||
struct group *gr = getgrnam(argv[2]);
|
||||
if (!gr)
|
||||
return 2;
|
||||
|
||||
if (pw->pw_gid == gr->gr_gid) {
|
||||
puts("Yes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (char **m = gr->gr_mem; *m; ++m) {
|
||||
if (!strcmp(*m, argv[1])) {
|
||||
puts("Yes");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
puts("No");
|
||||
return 1;
|
||||
}
|
||||
|
||||
102
chkgrp-native-min-extended.c
Normal file
102
chkgrp-native-min-extended.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* chkgrp-min-native-extended 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>
|
||||
#include <ctype.h>
|
||||
|
||||
#define MAX_LINE 1024
|
||||
#define MAX_NAME 256
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
return 2;
|
||||
|
||||
const char *username = argv[1];
|
||||
const char *groupname = argv[2];
|
||||
|
||||
if (strlen(username) > MAX_NAME || strlen(groupname) > MAX_NAME)
|
||||
return 2;
|
||||
|
||||
// Step 1: Find user in /etc/passwd to get their primary GID
|
||||
FILE *passwd = fopen("/etc/passwd", "r");
|
||||
if (!passwd)
|
||||
return 2;
|
||||
|
||||
char line[MAX_LINE];
|
||||
int user_gid = -1;
|
||||
while (fgets(line, sizeof(line), passwd)) {
|
||||
char *u = strtok(line, ":");
|
||||
if (!u || strcmp(u, username) != 0)
|
||||
continue;
|
||||
|
||||
strtok(NULL, ":"); // skip password
|
||||
strtok(NULL, ":"); // skip UID
|
||||
char *gid_str = strtok(NULL, ":");
|
||||
if (!gid_str)
|
||||
break;
|
||||
|
||||
user_gid = atoi(gid_str);
|
||||
break;
|
||||
}
|
||||
fclose(passwd);
|
||||
if (user_gid < 0)
|
||||
return 2;
|
||||
|
||||
// Step 2: Find group in /etc/group and check membership or GID match
|
||||
FILE *group = fopen("/etc/group", "r");
|
||||
if (!group)
|
||||
return 2;
|
||||
|
||||
int found = 0;
|
||||
while (fgets(line, sizeof(line), group)) {
|
||||
char *grp = strtok(line, ":");
|
||||
if (!grp || strcmp(grp, groupname) != 0)
|
||||
continue;
|
||||
|
||||
strtok(NULL, ":"); // skip password
|
||||
char *gid_str = strtok(NULL, ":");
|
||||
if (!gid_str)
|
||||
break;
|
||||
|
||||
int group_gid = atoi(gid_str);
|
||||
if (group_gid == user_gid) {
|
||||
puts("Yes");
|
||||
fclose(group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *members = strtok(NULL, ":\n");
|
||||
if (!members)
|
||||
break;
|
||||
|
||||
char *m = strtok(members, ",");
|
||||
while (m) {
|
||||
if (!strcmp(m, username)) {
|
||||
puts("Yes");
|
||||
fclose(group);
|
||||
return 0;
|
||||
}
|
||||
m = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(group);
|
||||
if (!found)
|
||||
return 2;
|
||||
|
||||
puts("No");
|
||||
return 1;
|
||||
}
|
||||
|
||||
60
chkgrp-native-min.c
Normal file
60
chkgrp-native-min.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/**
|
||||
* chkgrp-min-native 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
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3)
|
||||
return 2;
|
||||
|
||||
const char *username = argv[1];
|
||||
const char *groupname = argv[2];
|
||||
|
||||
if (strlen(username) > MAX_NAME || strlen(groupname) > MAX_NAME)
|
||||
return 2;
|
||||
|
||||
FILE *fp = fopen("/etc/group", "r");
|
||||
if (!fp)
|
||||
return 2;
|
||||
|
||||
char line[MAX_LINE];
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
char *grp = strtok(line, ":");
|
||||
if (!grp || strcmp(grp, groupname) != 0)
|
||||
continue;
|
||||
|
||||
strtok(NULL, ":"); // skip password
|
||||
strtok(NULL, ":"); // skip GID
|
||||
|
||||
char *members = strtok(NULL, ":\n");
|
||||
if (!members) break;
|
||||
|
||||
char *m = strtok(members, ",");
|
||||
while (m) {
|
||||
if (!strcmp(m, username)) {
|
||||
puts("Yes");
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
m = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
break; // group matched, no user found
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
puts("No");
|
||||
return 1;
|
||||
}
|
||||
|
||||
78
chkgrp-native.c
Normal file
78
chkgrp-native.c
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* chkgrp-native 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
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <username> <groupname>\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const char *username = argv[1];
|
||||
const char *groupname = argv[2];
|
||||
|
||||
if (strlen(username) > MAX_NAME || strlen(groupname) > MAX_NAME) {
|
||||
fprintf(stderr, "Error: Name too long (max %d characters).\n", MAX_NAME);
|
||||
return 2;
|
||||
}
|
||||
|
||||
FILE *fp = fopen("/etc/group", "r");
|
||||
if (!fp) {
|
||||
perror("Error opening /etc/group");
|
||||
return 2;
|
||||
}
|
||||
|
||||
char line[MAX_LINE];
|
||||
int found = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
char *grp_name = strtok(line, ":");
|
||||
if (!grp_name) continue;
|
||||
|
||||
strtok(NULL, ":"); // skip password
|
||||
strtok(NULL, ":"); // skip GID
|
||||
|
||||
char *members = strtok(NULL, ":\n");
|
||||
if (!members) continue;
|
||||
|
||||
if (strcmp(grp_name, groupname) != 0)
|
||||
continue;
|
||||
|
||||
// Group found, now check for user in member list
|
||||
found = 1;
|
||||
char *member = strtok(members, ",");
|
||||
while (member) {
|
||||
if (strcmp(member, username) == 0) {
|
||||
fclose(fp);
|
||||
puts("Yes");
|
||||
return 0;
|
||||
}
|
||||
member = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
break; // no need to continue scanning
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (!found) {
|
||||
fprintf(stderr, "Group '%s' not found.\n", groupname);
|
||||
return 2;
|
||||
}
|
||||
|
||||
puts("No");
|
||||
return 1;
|
||||
}
|
||||
|
||||
153
chkgrp-ng.c
Normal file
153
chkgrp-ng.c
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
77
chkgrp.c
Normal file
77
chkgrp.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* chkgrp 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>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef LOGIN_NAME_MAX
|
||||
#define LOGIN_NAME_MAX 256
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <username> <groupname>\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const char *username = argv[1];
|
||||
const char *groupname = argv[2];
|
||||
|
||||
// Runtime check for max name length
|
||||
long max_name_len = sysconf(_SC_LOGIN_NAME_MAX);
|
||||
if (max_name_len <= 0 || max_name_len > 1024) {
|
||||
max_name_len = LOGIN_NAME_MAX;
|
||||
}
|
||||
|
||||
if (strlen(username) > (size_t)max_name_len) {
|
||||
fprintf(stderr, "Error: Username too long (max %ld characters).\n",
|
||||
max_name_len);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (strlen(groupname) > (size_t)max_name_len) {
|
||||
fprintf(stderr, "Error: Group name too long (max %ld characters).\n",
|
||||
max_name_len);
|
||||
return 2;
|
||||
}
|
||||
|
||||
struct passwd *pw = getpwnam(username);
|
||||
if (!pw) {
|
||||
fprintf(stderr, "Error: User '%s' not found.\n", username);
|
||||
return 2;
|
||||
}
|
||||
|
||||
struct group *gr = getgrnam(groupname);
|
||||
if (!gr) {
|
||||
fprintf(stderr, "Error: Group '%s' not found.\n", groupname);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (pw->pw_gid == gr->gr_gid) {
|
||||
puts("Yes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (char **members = gr->gr_mem; *members != NULL; members++) {
|
||||
if (strcmp(*members, username) == 0) {
|
||||
puts("Yes");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
puts("No");
|
||||
return 1;
|
||||
}
|
||||
|
||||
79
lua/checkgroup.lua
Normal file
79
lua/checkgroup.lua
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
-- This file is part of chkgrp that 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)
|
||||
|
||||
local checkgroup = {}
|
||||
|
||||
local MAX_NAME = 256
|
||||
|
||||
local function read_passwd_gid(username)
|
||||
local f = io.open("/etc/passwd", "r")
|
||||
if not f then return nil end
|
||||
|
||||
for line in f:lines() do
|
||||
local fields = {}
|
||||
for field in string.gmatch(line, "([^:]+)") do
|
||||
table.insert(fields, field)
|
||||
end
|
||||
if fields[1] == username then
|
||||
f:close()
|
||||
return tonumber(fields[4])
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
return nil
|
||||
end
|
||||
|
||||
local function check_group_membership(username, groupname, user_gid)
|
||||
local f = io.open("/etc/group", "r")
|
||||
if not f then return nil end
|
||||
|
||||
for line in f:lines() do
|
||||
local fields = {}
|
||||
for field in string.gmatch(line, "([^:]+)") do
|
||||
table.insert(fields, field)
|
||||
end
|
||||
if fields[1] == groupname then
|
||||
local group_gid = tonumber(fields[3])
|
||||
if group_gid == user_gid then
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
|
||||
for member in string.gmatch(fields[4] or "", "[^,]+") do
|
||||
if member == username then
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
return nil
|
||||
end
|
||||
|
||||
function checkgroup.is_user_in_group(username, groupname)
|
||||
if not username or not groupname then
|
||||
return nil
|
||||
end
|
||||
|
||||
if #username > MAX_NAME or #groupname > MAX_NAME then
|
||||
return nil
|
||||
end
|
||||
|
||||
local gid = read_passwd_gid(username)
|
||||
if not gid then return nil end
|
||||
|
||||
return check_group_membership(username, groupname, gid)
|
||||
end
|
||||
|
||||
return checkgroup
|
||||
|
||||
89
lua/chkgrp-native-min-extended.lua
Executable file
89
lua/chkgrp-native-min-extended.lua
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#!/usr/bin/env lua
|
||||
|
||||
-- This file is part of chkgrp that 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)
|
||||
|
||||
local MAX_NAME = 256
|
||||
|
||||
local function read_passwd_gid(username)
|
||||
local f = io.open("/etc/passwd", "r")
|
||||
if not f then return nil end
|
||||
|
||||
for line in f:lines() do
|
||||
local fields = {}
|
||||
for field in string.gmatch(line, "([^:]+)") do
|
||||
table.insert(fields, field)
|
||||
end
|
||||
if fields[1] == username then
|
||||
f:close()
|
||||
return tonumber(fields[4]) -- GID is 4th field
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
return nil
|
||||
end
|
||||
|
||||
local function check_group_membership(username, groupname, user_gid)
|
||||
local f = io.open("/etc/group", "r")
|
||||
if not f then return nil end
|
||||
|
||||
for line in f:lines() do
|
||||
local fields = {}
|
||||
for field in string.gmatch(line, "([^:]+)") do
|
||||
table.insert(fields, field)
|
||||
end
|
||||
if fields[1] == groupname then
|
||||
local group_gid = tonumber(fields[3])
|
||||
if group_gid == user_gid then
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
|
||||
for member in string.gmatch(fields[4] or "", "[^,]+") do
|
||||
if member == username then
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
f:close()
|
||||
return nil
|
||||
end
|
||||
|
||||
local username = arg[1]
|
||||
local groupname = arg[2]
|
||||
|
||||
if not username or not groupname then
|
||||
os.exit(2)
|
||||
end
|
||||
|
||||
if #username > MAX_NAME or #groupname > MAX_NAME then
|
||||
os.exit(2)
|
||||
end
|
||||
|
||||
local user_gid = read_passwd_gid(username)
|
||||
if not user_gid then
|
||||
os.exit(2)
|
||||
end
|
||||
|
||||
local result = check_group_membership(username, groupname, user_gid)
|
||||
if result == nil then
|
||||
os.exit(2)
|
||||
elseif result == true then
|
||||
print("Yes")
|
||||
os.exit(0)
|
||||
else
|
||||
print("No")
|
||||
os.exit(1)
|
||||
end
|
||||
|
||||
26
lua/test.lua
Executable file
26
lua/test.lua
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env lua
|
||||
|
||||
-- This file is part of chkgrp that 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)
|
||||
|
||||
local checkgroup = require("checkgroup")
|
||||
|
||||
local user = arg[1]
|
||||
local group = arg[2]
|
||||
|
||||
local result = checkgroup.is_user_in_group(user, group)
|
||||
|
||||
if result == true then
|
||||
print("Yes")
|
||||
os.exit(0)
|
||||
elseif result == false then
|
||||
print("No")
|
||||
os.exit(1)
|
||||
else
|
||||
os.exit(2)
|
||||
end
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue