Compare commits
40 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb8edf2913 | |||
| fd829f1569 | |||
| 37a10d5c07 | |||
| 5a092b3b65 | |||
| b082f1592b | |||
| 7adcaf989f | |||
| 025f792261 | |||
| 9709333e76 | |||
| 22303a3506 | |||
| f9e1cf4c05 | |||
| 92fdb05161 | |||
| 71555fc275 | |||
| 0957057793 | |||
| eb69c6989c | |||
| d92c2d2a76 | |||
| f8870f6c80 | |||
| 45973a3a90 | |||
| 12ea8e8273 | |||
| bf732541c0 | |||
| 8644ccbdc5 | |||
| b2461ba7a0 | |||
| dbd240f31f | |||
| ccfd170bae | |||
| ce7fc820a7 | |||
| 3d0022ced1 | |||
| d819e7c821 | |||
| a2bcc55b38 | |||
| 0fb2bc12e7 | |||
| bdc6fab467 | |||
| 22e4f0790a | |||
| 1665cdc1a3 | |||
| bec3be6746 | |||
| 4c50974efc | |||
| 6d3e3393b5 | |||
| 687777f90b | |||
| bc4713e82e | |||
| 0b7219c6d8 | |||
| 5e80936967 | |||
| bd2ac5b829 | |||
| f53aaced69 |
19 changed files with 1063 additions and 108 deletions
15
.gitignore
vendored
15
.gitignore
vendored
|
|
@ -1,2 +1,13 @@
|
|||
checkpw
|
||||
checkpw.o
|
||||
*.o
|
||||
*.so
|
||||
chkgrp
|
||||
chkgrp-min
|
||||
chkgrp-native
|
||||
chkgrp-native-min
|
||||
chkgrp-native-min-extended
|
||||
chkgrp-ng
|
||||
chkpwd
|
||||
chkpwd.1.gz
|
||||
chkpwr
|
||||
test
|
||||
test.c
|
||||
|
|
|
|||
53
Makefile
53
Makefile
|
|
@ -1,17 +1,52 @@
|
|||
all:
|
||||
$(CC) -Wall -o checkpw checkpw.c -lpam -lpam_misc
|
||||
$(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
|
||||
$(CC) -Wall -o ./chkpwr ./chkpwr.c
|
||||
|
||||
clean:
|
||||
rm -f ./checkpw
|
||||
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 ./chkpwr
|
||||
rm -f ./test
|
||||
|
||||
install:
|
||||
cp ./checkpw /usr/bin/
|
||||
cp ./checkpw.1 /usr/share/man/man1/
|
||||
gzip -f /usr/share/man/man1/checkpw.1
|
||||
cp ./checkpw.h /usr/include/
|
||||
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 ./chkpwr /usr/bin/
|
||||
install -g 0 -o 0 -m 0655 ./lua/chkgrp-native-min-extended.lua /usr/bin/
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/bin/checkpw
|
||||
rm -f /usr/share/man/man1/checkpw.1.gz
|
||||
rm -f /usr/include/checkpw.h
|
||||
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/bin/chkpwr
|
||||
rm -f /usr/include/chkpwd.h
|
||||
rm -f /usr/share/man/man1/chkpwd.1.gz
|
||||
|
||||
test:
|
||||
$(CC) -Wall -DPAM_DEBUG -o test test.c
|
||||
|
||||
|
|
|
|||
143
README.md
143
README.md
|
|
@ -1,54 +1,89 @@
|
|||
# checkpw
|
||||
# chkusr
|
||||
|
||||
checkpw 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.
|
||||
chkusr is a set of programs (chkgrp, chkpwd and chkpwr) to verify information about a user and/or group on UNIX based systems.
|
||||
|
||||
Currently checkpw 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 FOLLOWING DOCUMENTATION WILL NOT WORK ACTUALLY! YOU NEED TO READ THE CODE! SORRY...
|
||||
|
||||
## The idea
|
||||
* [The idea](#the-idea)
|
||||
* [Requirements](#requirements)
|
||||
* [Configuration](#configuration)
|
||||
* [Building chkusr](#building-chkusr)
|
||||
* [Installation](#installation)
|
||||
* [Uninstall](#uninstall)
|
||||
* [Programs](#programs)
|
||||
* [chkgrp](#chkgrp)
|
||||
* [chkpwd](#chkpwd)
|
||||
* [Usage](#usage)
|
||||
* [Return codes](#return-codes)
|
||||
* [Examples](#examples)
|
||||
* [Interactive mode asking for a username and a password](#interactive-mode-asking-for-a-username-and-a-password)
|
||||
* [Interactive mode only asking for a password](#interactive-mode-only-asking-for-a-password)
|
||||
* [None interactive mode with username and password provided as arguments to chkpwd](#none-interactive-mode-with-username-and-password-provided-as-arguments-to-chkpwd)
|
||||
* [Request the result from the above commands](#request-the-result-from-the-above-commands)
|
||||
* [Custom build](#custom-build)
|
||||
* [chkpwr](#chkpwr)
|
||||
* [Links](#links)
|
||||
* [License](#license)
|
||||
|
||||
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.
|
||||
### The idea
|
||||
|
||||
## Building checkpw
|
||||
I needed some programs to verify some information about users and groups on a Linux/UNIX system just returning 0 on success and 1 on error. Nonetheless, some programs also return a message.
|
||||
|
||||
#### Requirements
|
||||
|
||||
You need the PAM development package installed. On Alpine it is named linux-pam-dev, on Debian based systems it is named libpam0g-dev. Not all programs require PAM but you need to edit the Makefile to disable PAM based programs in the build process.
|
||||
|
||||
#### Configuration
|
||||
|
||||
chkusr needs to be configured before compilation. Always look at config.h for configuration options. I did it this way because I need the programs as small and simple as possible, and I don't want to parse a configuration file.
|
||||
|
||||
#### Building chkusr
|
||||
|
||||
```
|
||||
git clone https://git.xw3.org/xw3/checkpw.git
|
||||
cd checkpw
|
||||
git clone https://git.xw3.org/hanez/chkusr.git
|
||||
cd chkusr
|
||||
make
|
||||
```
|
||||
|
||||
The code only supports verifying passwords for user id 1000 by default. Look at the file checkpw.h for some compile time options!
|
||||
#### Installation
|
||||
|
||||
### Custom build example
|
||||
|
||||
Set MAX_UID and MIN_UID at compile time:
|
||||
|
||||
```
|
||||
gcc -Wall -DMAX_UID=1000 -DMIN_UID=1000 -o checkpw checkpw.c -lpam -lpam_misc
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
**WARNING:** Install this software with care. checkpw could easily be used for bruteforcing passwords from local users!
|
||||
**WARNING:** Install this software with care. chkpwd could easily be used for bruteforcing passwords from local users!
|
||||
|
||||
```
|
||||
sudo make install
|
||||
```
|
||||
|
||||
checkpw is installed to /usr/bin/.
|
||||
chkusr programs are installed to /usr/bin/.
|
||||
|
||||
checkpw.h is installed to /usr/include/ for use in other applications.
|
||||
chkpwd.h is installed to /usr/include/ for use in other applications.
|
||||
|
||||
## Uninstall
|
||||
#### Uninstall
|
||||
|
||||
```
|
||||
sudo make uninstall
|
||||
```
|
||||
|
||||
## Usage
|
||||
### Programs
|
||||
|
||||
#### chkgrp
|
||||
|
||||
chkgrp is a program to verify if a user is a member of a group.
|
||||
|
||||
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 code only supports verifying passwords for user id 1000 by default. Look at the file chkpwd.h for some compile time options!
|
||||
|
||||
##### Usage
|
||||
|
||||
```
|
||||
checkpw -h
|
||||
Usage: checkpw [-u <username>] [-p <password>] [-v] [-V] [-h]
|
||||
chkpwd -h
|
||||
Usage: chkpwd [-u <username>] [-p <password>] [-v] [-V] [-h]
|
||||
|
||||
Options:
|
||||
-u <username> Set username.
|
||||
|
|
@ -58,50 +93,70 @@ Options:
|
|||
-h Show this help.
|
||||
```
|
||||
|
||||
You can also use checkpw even without installing by just running the following command:
|
||||
You can also use chkpwd even without installing by just running the following command:
|
||||
|
||||
```
|
||||
./checkpk
|
||||
./chkpwd
|
||||
```
|
||||
|
||||
checkpw returns 0 on success, 1 otherwise.
|
||||
##### Return codes
|
||||
|
||||
### Examples
|
||||
chk returns 0 on success, 1 otherwise.
|
||||
|
||||
##### Examples
|
||||
|
||||
#### Interactive mode asking for a username and a password
|
||||
###### Interactive mode asking for a username and a password
|
||||
|
||||
```
|
||||
checkpw
|
||||
chkpwd
|
||||
```
|
||||
|
||||
#### Interactive mode only asking for a password
|
||||
###### Interactive mode only asking for a password
|
||||
|
||||
```
|
||||
checkpw -u hanez
|
||||
chkpwd -u hanez
|
||||
```
|
||||
|
||||
#### None interactive mode with username and password provided as arguments to checkpw
|
||||
###### None interactive mode with username and password provided as arguments to chkpwd
|
||||
|
||||
```
|
||||
checkpw -u hanez -p password
|
||||
chkpwd -u hanez -p password
|
||||
```
|
||||
|
||||
#### Request the result from the above commands
|
||||
###### Request the result from the above commands
|
||||
|
||||
```
|
||||
echo $?
|
||||
```
|
||||
|
||||
## License
|
||||
##### Custom build
|
||||
|
||||
checkpw is licensed under the Apache License, Version 2.0.
|
||||
Set MAX_UID and MIN_UID at compile time:
|
||||
|
||||
```
|
||||
gcc -Wall -DMAX_UID=1000 -DMIN_UID=1000 -o chkpwd chkpwd.c -lpam -lpam_misc
|
||||
```
|
||||
|
||||
#### chkpwr
|
||||
|
||||
A program that checks if an input string validates a password rule. More to come... look at the code!
|
||||
|
||||
### Links
|
||||
|
||||
- [https://git.xw3.org/hanez/chkusr](https://git.xw3.org/hanez/chkusr)
|
||||
- [https://github.com/shadow-maint/shadow](https://github.com/shadow-maint/shadow)
|
||||
- [https://github.com/linux-pam/linux-pam](https://github.com/linux-pam/linux-pam)
|
||||
- [https://www.man7.org/linux/man-pages/man8/unix_chkpwd.8.html](https://www.man7.org/linux/man-pages/man8/unix_chkpwd.8.html)
|
||||
- [https://cr.yp.to/checkpwd.html](https://cr.yp.to/checkpwd.html)
|
||||
- [https://pamtester.sourceforge.net/](https://pamtester.sourceforge.net/)
|
||||
- [https://github.com/AlexanderZhirov/chkpass](https://github.com/AlexanderZhirov/chkpass)
|
||||
- [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
|
||||
|
||||
chkusr is licensed under the Apache License, Version 2.0.
|
||||
|
||||
See LICENSE for details.
|
||||
|
||||
## Links
|
||||
|
||||
- [Homepage of checkpw](https://git.xw3.org/xw3/checkpw)
|
||||
- [https://cr.yp.to/checkpwd.html](https://cr.yp.to/checkpwd.html)
|
||||
- [https://pamtester.sourceforge.net/](https://pamtester.sourceforge.net/)
|
||||
|
||||
|
|
|
|||
24
checkpw.1
24
checkpw.1
|
|
@ -1,24 +0,0 @@
|
|||
.TH man 1 "01 Jan 2025" "checkpw 1.1.1" "checkpw man page"
|
||||
.SH NAME
|
||||
checkpw \- checks the validity of a users password on a UNIX/PAM-based system.
|
||||
.SH SYNOPSIS
|
||||
checkpw [OPTION]...
|
||||
.SH DESCRIPTION
|
||||
checkpw is a program that checks the validity of a users password on a UNIX/PAM-based system.
|
||||
.SH OPTIONS
|
||||
The options which apply to the checkpw command are:
|
||||
|
||||
-u <username> Set username.
|
||||
-p <password> Set password.
|
||||
-v Enable verbose mode.
|
||||
-V Print program version.
|
||||
-h Show this help.
|
||||
|
||||
checkpw runs in an interactive mode when no username and/or password are set. A missing username and/or password will then be asked for program execution.
|
||||
|
||||
.SH SEE ALSO
|
||||
pam(3), pam_authenticate(3), PAM(8)
|
||||
.SH BUGS
|
||||
No known bugs.
|
||||
.SH AUTHOR
|
||||
Johannes Findeisen (you@hanez.org)
|
||||
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/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
101
chkgrp-native-min-extended.c
Normal file
101
chkgrp-native-min-extended.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* 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/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
59
chkgrp-native-min.c
Normal file
59
chkgrp-native-min.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 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/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
77
chkgrp-native.c
Normal file
77
chkgrp-native.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* 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/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
152
chkgrp-ng.c
Normal file
152
chkgrp-ng.c
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/**
|
||||
* 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/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
75
chkgrp.c
Normal file
75
chkgrp.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* 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/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
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 = MAX_NAME;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
27
chkpwd.1
Normal file
27
chkpwd.1
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
.TH checkpw 1 "June 2025" "chkpwd 1.4.0" "chkpwd man page"
|
||||
.SH NAME
|
||||
chkpwd \- checks the validity of a users password on a UNIX/PAM-based system.
|
||||
.SH SYNOPSIS
|
||||
chkpwd [OPTION]...
|
||||
.SH DESCRIPTION
|
||||
chkpwd is a program that checks the validity of a users password on a
|
||||
UNIX/PAM-based system.
|
||||
.SH OPTIONS
|
||||
The options which apply to the chkpwd command are:
|
||||
|
||||
-u <username> Set username.
|
||||
-p <password> Set password.
|
||||
-v Enable verbose mode.
|
||||
-V Print program version.
|
||||
-h Show this help.
|
||||
|
||||
chkpwd runs in an interactive mode when no username and/or password are set.
|
||||
A missing username and/or password will then be asked for while program
|
||||
execution.
|
||||
|
||||
.SH SEE ALSO
|
||||
pam(3), pam_authenticate(3), PAM(8), pam_unix(8)
|
||||
.SH BUGS
|
||||
No known bugs.
|
||||
.SH AUTHOR
|
||||
Written by Johannes Findeisen <you@hanez.org>.
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
/**
|
||||
* checkpw is a program that checks the validity of a users password on a
|
||||
* chkpwd is a program that checks the validity of a users password on a
|
||||
* UNIX/PAM-based system.
|
||||
*
|
||||
* Author: Johannes Findeisen <you@hanez.org> - 2024
|
||||
* Homepage: https://git.xw3.org/hanez/chkpwd
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "chkpwd.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -13,8 +17,6 @@
|
|||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "checkpw.h"
|
||||
|
||||
// Function to prompt user for input, optionally hiding input
|
||||
void prompt_for_input(char *buffer, size_t size, const char *prompt,
|
||||
bool hide_input)
|
||||
|
|
@ -80,28 +82,28 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
bool verbose = false;
|
||||
bool version = false;
|
||||
char password[MAX_PASSWORD_LEN] = {0};
|
||||
char username[MAX_USERNAME_LEN] = {0};
|
||||
char password[MAX_PASSWORD] = {0};
|
||||
char username[MAX_NAME] = {0};
|
||||
int opt;
|
||||
|
||||
// Parse command-line arguments
|
||||
while ((opt = getopt(argc, argv, "u:p:hvV")) != -1) {
|
||||
switch (opt) {
|
||||
case 'u':
|
||||
if (strlen(optarg) >= MAX_USERNAME_LEN) {
|
||||
if (strlen(optarg) >= MAX_NAME) {
|
||||
fprintf(stderr, "Error: Username is too long (maximum %d characters).\n",
|
||||
MAX_USERNAME_LEN);
|
||||
MAX_NAME);
|
||||
exit(1);
|
||||
}
|
||||
strncpy(username, optarg, MAX_USERNAME_LEN - 1);
|
||||
strncpy(username, optarg, MAX_NAME - 1);
|
||||
break;
|
||||
case 'p':
|
||||
if (strlen(optarg) >= MAX_PASSWORD_LEN) {
|
||||
if (strlen(optarg) >= MAX_PASSWORD) {
|
||||
fprintf(stderr, "Error: Password is too long (maximum %d characters).\n",
|
||||
MAX_PASSWORD_LEN);
|
||||
MAX_PASSWORD);
|
||||
exit(1);
|
||||
}
|
||||
strncpy(password, optarg, MAX_PASSWORD_LEN - 1);
|
||||
strncpy(password, optarg, MAX_PASSWORD - 1);
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
|
|
@ -157,7 +159,7 @@ int main(int argc, char *argv[])
|
|||
printf("User '%s' passed UID check (UID: %d).\n", username,
|
||||
pwd->pw_uid);
|
||||
|
||||
if (authenticate(username, password, verbose) == true) {
|
||||
if (checkpw_authenticate(username, password, verbose) == true) {
|
||||
printf("Authenticated successfully.\n");
|
||||
return 0;
|
||||
} else {
|
||||
|
|
@ -1,34 +1,19 @@
|
|||
/**
|
||||
* checkpw.h is part of checkpw, a program that checks the validity of a users
|
||||
* password on a UNIX/PAM-based system.
|
||||
* chkpwd.h is part of chkusr, a set of programs to verify information about
|
||||
* a user on UNIX based systems.
|
||||
*
|
||||
* Author: Johannes Findeisen <you@hanez.org> - 2025
|
||||
* Homepage: https://git.xw3.org/hanez/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdbool.h>
|
||||
#include <security/pam_appl.h>
|
||||
#include <security/pam_misc.h>
|
||||
|
||||
#define VERSION "1.1.1"
|
||||
|
||||
#ifndef MAX_PASSWORD_LEN
|
||||
#define MAX_PASSWORD_LEN 256
|
||||
#endif
|
||||
|
||||
#ifndef MAX_USERNAME_LEN
|
||||
#define MAX_USERNAME_LEN 32
|
||||
#endif
|
||||
|
||||
#ifndef MAX_UID
|
||||
#define MAX_UID 1000
|
||||
#endif
|
||||
|
||||
#ifndef MIN_UID
|
||||
#define MIN_UID 1000
|
||||
#endif
|
||||
|
||||
bool authenticate(const char *username, const char *password, bool verbose);
|
||||
bool checkpw_authenticate(const char *username, const char *password,
|
||||
bool verbose);
|
||||
|
||||
int pam_conversation(int num_msg, const struct pam_message **msg,
|
||||
struct pam_response **resp, void *appdata_ptr);
|
||||
|
|
@ -38,7 +23,8 @@ struct pam_credentials
|
|||
const char *password;
|
||||
};
|
||||
|
||||
bool authenticate(const char *username, const char *password, bool verbose)
|
||||
bool checkpw_authenticate(const char *username, const char *password,
|
||||
bool verbose)
|
||||
{
|
||||
int retval;
|
||||
pam_handle_t *pamh = NULL;
|
||||
100
chkpwr.c
Normal file
100
chkpwr.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/**
|
||||
* checkpwrule is a program that checks if an input string validates a
|
||||
* password rule.
|
||||
*
|
||||
* Author: Johannes Findeisen <you@hanez.org> - 2024
|
||||
* License: MIT (see LICENSE)
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
// Return 1 if non-ASCII characters are found, 0 if all are ASCII
|
||||
int is_valid_ascii(char *str) {
|
||||
for (int i = 0; i < strlen(str); i++) {
|
||||
if ((unsigned char)str[i] > 127) {
|
||||
return 1; // Non-ASCII character detected, return 1 (indicating invalid)
|
||||
}
|
||||
}
|
||||
return 0; // All characters are ASCII
|
||||
}
|
||||
|
||||
int is_valid(char *str) {
|
||||
int lowercase_count = 0, uppercase_count = 0, digit_count = 0, special_count = 0;
|
||||
int i;
|
||||
int length = strlen(str);
|
||||
|
||||
// Check if the input contains any non-ASCII characters
|
||||
if (is_valid_ascii(str)) {
|
||||
printf("Password contains non-ASCII characters.\n");
|
||||
return 1; // Invalid input, return 1 to signal failure
|
||||
}
|
||||
|
||||
// Check if the length is within the allowed range
|
||||
if (length < MIN_PASSWORD_LENGTH) {
|
||||
printf("Password is too short! It must be at least %d characters long.\n", MIN_PASSWORD_LENGTH);
|
||||
return 1;
|
||||
}
|
||||
if (length > MAX_PASSWORD_LENGTH) {
|
||||
printf("Password exceeds the maximum length of %d characters.\n", MAX_PASSWORD_LENGTH);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check each character of the string and count occurrences
|
||||
for (i = 0; i < length; i++) {
|
||||
if (islower(str[i])) {
|
||||
lowercase_count++;
|
||||
} else if (isupper(str[i])) {
|
||||
uppercase_count++;
|
||||
} else if (isdigit(str[i])) {
|
||||
digit_count++;
|
||||
} else if (ispunct(str[i])) { // Checks for special characters like !, @, #, etc.
|
||||
special_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all counts meet the required minimums
|
||||
if (lowercase_count < MIN_LOWERCASE) {
|
||||
printf("Password needs at least %d lowercase letters.\n", MIN_LOWERCASE);
|
||||
return 1;
|
||||
}
|
||||
if (uppercase_count < MIN_UPPERCASE) {
|
||||
printf("Password needs at least %d uppercase letters.\n", MIN_UPPERCASE);
|
||||
return 1;
|
||||
}
|
||||
if (digit_count < MIN_DIGITS) {
|
||||
printf("Password needs at least %d digits.\n", MIN_DIGITS);
|
||||
return 1;
|
||||
}
|
||||
if (special_count < MIN_SPECIAL) {
|
||||
printf("Password needs at least %d special characters.\n", MIN_SPECIAL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If all conditions are met, return 0 (indicating success)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
printf("Usage: %s <string>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_valid(argv[1]) == 0) {
|
||||
printf("The string is valid.\n");
|
||||
return 0; // Success
|
||||
} else {
|
||||
printf("The string is invalid. It must contain at least:\n");
|
||||
printf("- %d lowercase letters\n", MIN_LOWERCASE);
|
||||
printf("- %d uppercase letters\n", MIN_UPPERCASE);
|
||||
printf("- %d digits\n", MIN_DIGITS);
|
||||
printf("- %d special characters\n", MIN_SPECIAL);
|
||||
printf("And be between %d and %d characters long.\n", MIN_PASSWORD_LENGTH, MAX_PASSWORD_LENGTH);
|
||||
return 1; // Invalid password, return 1
|
||||
}
|
||||
}
|
||||
|
||||
56
config.h
Normal file
56
config.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Author: Johannes Findeisen <you@hanez.org> - 2025
|
||||
* Homepage: https://git.xw3.org/hanez/chkusr
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#define VERSION "1.5.1"
|
||||
|
||||
/* For chkgrp */
|
||||
#ifndef MAX_LINE
|
||||
#define MAX_LINE 1024
|
||||
#endif
|
||||
|
||||
/* MAX_NAME is also used by chkpwd */
|
||||
#ifndef MAX_NAME
|
||||
#define MAX_NAME 256
|
||||
#endif
|
||||
|
||||
/* For chkpwd; Also uses MAX_NAME from chkgrp above */
|
||||
#ifndef MAX_PASSWORD
|
||||
#define MAX_PASSWORD 256
|
||||
#endif
|
||||
|
||||
#ifndef MAX_UID
|
||||
#define MAX_UID 1000
|
||||
#endif
|
||||
|
||||
#ifndef MIN_UID
|
||||
#define MIN_UID 1000
|
||||
#endif
|
||||
|
||||
/* For chkpwr */
|
||||
#ifndef MAX_PASSWORD_LENGTH
|
||||
#define MAX_PASSWORD_LENGTH 32
|
||||
#endif
|
||||
|
||||
#ifndef MIN_PASSWORD_LENGTH
|
||||
#define MIN_PASSWORD_LENGTH 12
|
||||
#endif
|
||||
|
||||
#ifndef MIN_LOWERCASE
|
||||
#define MIN_LOWERCASE 2
|
||||
#endif
|
||||
|
||||
#ifndef MIN_UPPERCASE
|
||||
#define MIN_UPPERCASE 2
|
||||
#endif
|
||||
|
||||
#ifndef MIN_DIGITS
|
||||
#define MIN_DIGITS 2
|
||||
#endif
|
||||
|
||||
#ifndef MIN_SPECIAL
|
||||
#define MIN_SPECIAL 2
|
||||
#endif
|
||||
|
||||
1
lua/README.md
Normal file
1
lua/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is experimental at the monent but I really will implement some programs from chkusr in Lua or write some wrappers for the C programs...
|
||||
79
lua/checkgroup.lua
Executable file
79
lua/checkgroup.lua
Executable 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