Compare commits

...

21 commits

Author SHA1 Message Date
cb8edf2913 README update. 2026-01-13 00:20:45 +01:00
fd829f1569 Some content update... 2025-09-08 03:59:43 +02:00
37a10d5c07 Some content update... 2025-09-08 03:49:31 +02:00
5a092b3b65 Some content update... 2025-09-08 03:37:36 +02:00
b082f1592b Some content update... 2025-09-08 03:35:08 +02:00
7adcaf989f Some fix. 2025-09-08 03:32:40 +02:00
025f792261 Some content update... 2025-09-08 03:17:18 +02:00
9709333e76 Some content update and fixes... 2025-09-08 03:13:19 +02:00
22303a3506 Some content update and fixes... 2025-09-08 03:08:28 +02:00
f9e1cf4c05 Some content update and fixes... 2025-09-08 03:05:56 +02:00
92fdb05161 Some content update and fixes... 2025-09-08 02:55:20 +02:00
71555fc275 Merged chkpwr to chkusr and moved defines to config.h. 2025-09-08 02:34:46 +02:00
0957057793 README update. 2025-06-27 03:10:35 +02:00
eb69c6989c README update. 2025-06-27 03:09:43 +02:00
d92c2d2a76 Merge nearly ready for 1.4.0. 2025-06-27 02:56:55 +02:00
f8870f6c80 Cleanups. 2025-06-27 02:30:01 +02:00
45973a3a90 README update. 2025-06-27 01:32:23 +02:00
12ea8e8273 README update. 2025-06-27 01:30:22 +02:00
bf732541c0 README update. 2025-06-27 01:09:31 +02:00
8644ccbdc5 Merged with chkgrp and renamed to chkusr. 2025-06-27 00:57:42 +02:00
b2461ba7a0 Link update as the site used Google adds. 2025-06-05 20:46:08 +02:00
18 changed files with 999 additions and 70 deletions

10
.gitignore vendored
View file

@ -1,5 +1,13 @@
*.o
*.so
chkgrp
chkgrp-min
chkgrp-native
chkgrp-native-min
chkgrp-native-min-extended
chkgrp-ng
chkpwd chkpwd
chkpwd.o
chkpwd.1.gz chkpwd.1.gz
chkpwr
test test
test.c test.c

View file

@ -1,19 +1,49 @@
all: 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 $(CC) -Wall -o ./chkpwd ./chkpwd.c -lpam
gzip -fk ./chkpwd.1 gzip -fk ./chkpwd.1
$(CC) -Wall -o ./chkpwr ./chkpwr.c
clean: 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
rm -f ./chkpwd.1.gz rm -f ./chkpwd.1.gz
rm -f ./chkpwr
rm -f ./test rm -f ./test
install: 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 0655 ./chkpwd /usr/bin/
install -g 0 -o 0 -m 0644 ./chkpwd.h /usr/include/ 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 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: 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/bin/chkpwd
rm -f /usr/bin/chkpwr
rm -f /usr/include/chkpwd.h rm -f /usr/include/chkpwd.h
rm -f /usr/share/man/man1/chkpwd.1.gz rm -f /usr/share/man/man1/chkpwd.1.gz

121
README.md
View file

@ -1,36 +1,51 @@
# chkpwd # chkusr
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. chkusr is a set of programs (chkgrp, chkpwd and chkpwr) to verify information about a user and/or group on UNIX based systems.
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 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
## Requirements 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.
You need the PAM development package installed. On Alpine it is named linux-pam-dev, on Debian based systems it is libpam0g-dev. #### Requirements
## Building chkpwd 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/hanez/chkpwd.git git clone https://git.xw3.org/hanez/chkusr.git
cd chkpwd cd chkusr
make make
``` ```
The code only supports verifying passwords for user id 1000 by default. Look at the file chkpwd.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 chkpwd chkpwd.c -lpam -lpam_misc
```
## Installation
**WARNING:** Install this software with care. chkpwd 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!
@ -38,17 +53,33 @@ gcc -Wall -DMAX_UID=1000 -DMIN_UID=1000 -o chkpwd chkpwd.c -lpam -lpam_misc
sudo make install sudo make install
``` ```
chkpwd is installed to /usr/bin/. chkusr programs are installed to /usr/bin/.
chkpwd.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 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
``` ```
chkpwd -h chkpwd -h
@ -68,50 +99,64 @@ You can also use chkpwd even without installing by just running the following co
./chkpwd ./chkpwd
``` ```
### Return codes ##### Return codes
chkpwd returns 0 on success, 1 otherwise. chk 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 chkpwd
``` ```
#### Interactive mode only asking for a password ###### Interactive mode only asking for a password
``` ```
chkpwd -u hanez 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 chkpwd -u hanez -p password
``` ```
#### Request the result from the above commands ###### Request the result from the above commands
``` ```
echo $? echo $?
``` ```
## License ##### Custom build
chkpwd is licensed under the Apache License, Version 2.0. Set MAX_UID and MIN_UID at compile time:
See LICENSE for details. ```
gcc -Wall -DMAX_UID=1000 -DMIN_UID=1000 -o chkpwd chkpwd.c -lpam -lpam_misc
```
## Links #### chkpwr
- [https://git.xw3.org/hanez/chkpwd](https://git.xw3.org/hanez/chkpwd) A program that checks if an input string validates a password rule. More to come... look at the code!
- [https://linux.die.net/man/8/unix_chkpwd](https://linux.die.net/man/8/unix_chkpwd)
### 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://cr.yp.to/checkpwd.html](https://cr.yp.to/checkpwd.html)
- [https://pamtester.sourceforge.net/](https://pamtester.sourceforge.net/) - [https://pamtester.sourceforge.net/](https://pamtester.sourceforge.net/)
- [https://github.com/AlexanderZhirov/chkpass](https://github.com/AlexanderZhirov/chkpass) - [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/ViKingIX/pam_test](https://github.com/ViKingIX/pam_test)
- [https://github.com/Dareka826/chk_pw](https://github.com/Dareka826/chk_pw) - [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.

48
chkgrp-min.c Normal file
View 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;
}

View 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
View 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
View 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
View 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
View 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;
}

View file

@ -1,4 +1,4 @@
.TH checkpw 1 "June 2025" "chkpwd 1.3.1" "chkpwd man page" .TH checkpw 1 "June 2025" "chkpwd 1.4.0" "chkpwd man page"
.SH NAME .SH NAME
chkpwd \- checks the validity of a users password on a UNIX/PAM-based system. chkpwd \- checks the validity of a users password on a UNIX/PAM-based system.
.SH SYNOPSIS .SH SYNOPSIS

View file

@ -8,6 +8,7 @@
*/ */
#include "chkpwd.h" #include "chkpwd.h"
#include "config.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
@ -16,22 +17,6 @@
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#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
// Function to prompt user for input, optionally hiding input // Function to prompt user for input, optionally hiding input
void prompt_for_input(char *buffer, size_t size, const char *prompt, void prompt_for_input(char *buffer, size_t size, const char *prompt,
bool hide_input) bool hide_input)
@ -97,28 +82,28 @@ int main(int argc, char *argv[])
{ {
bool verbose = false; bool verbose = false;
bool version = false; bool version = false;
char password[MAX_PASSWORD_LEN] = {0}; char password[MAX_PASSWORD] = {0};
char username[MAX_USERNAME_LEN] = {0}; char username[MAX_NAME] = {0};
int opt; int opt;
// Parse command-line arguments // Parse command-line arguments
while ((opt = getopt(argc, argv, "u:p:hvV")) != -1) { while ((opt = getopt(argc, argv, "u:p:hvV")) != -1) {
switch (opt) { switch (opt) {
case 'u': case 'u':
if (strlen(optarg) >= MAX_USERNAME_LEN) { if (strlen(optarg) >= MAX_NAME) {
fprintf(stderr, "Error: Username is too long (maximum %d characters).\n", fprintf(stderr, "Error: Username is too long (maximum %d characters).\n",
MAX_USERNAME_LEN); MAX_NAME);
exit(1); exit(1);
} }
strncpy(username, optarg, MAX_USERNAME_LEN - 1); strncpy(username, optarg, MAX_NAME - 1);
break; break;
case 'p': case 'p':
if (strlen(optarg) >= MAX_PASSWORD_LEN) { if (strlen(optarg) >= MAX_PASSWORD) {
fprintf(stderr, "Error: Password is too long (maximum %d characters).\n", fprintf(stderr, "Error: Password is too long (maximum %d characters).\n",
MAX_PASSWORD_LEN); MAX_PASSWORD);
exit(1); exit(1);
} }
strncpy(password, optarg, MAX_PASSWORD_LEN - 1); strncpy(password, optarg, MAX_PASSWORD - 1);
break; break;
case 'h': case 'h':
print_usage(argv[0]); print_usage(argv[0]);

View file

@ -1,18 +1,16 @@
/** /**
* chkpwd.h is part of chkpwd, a program that checks the validity of a users * chkpwd.h is part of chkusr, a set of programs to verify information about
* password on a UNIX/PAM-based system. * a user on UNIX based systems.
* *
* Author: Johannes Findeisen <you@hanez.org> - 2025 * Author: Johannes Findeisen <you@hanez.org> - 2025
* Homepage: https://git.xw3.org/hanez/chkpwd * Homepage: https://git.xw3.org/hanez/chkusr
* License: Apache-2.0 (see LICENSE) * License: Apache-2.0 (see LICENSE)
*/ */
#include <pwd.h> #include <pwd.h>
#include <stdbool.h>
#include <security/pam_appl.h> #include <security/pam_appl.h>
#include <security/pam_misc.h> #include <security/pam_misc.h>
#include <stdbool.h>
#define VERSION "1.3.1"
bool checkpw_authenticate(const char *username, const char *password, bool checkpw_authenticate(const char *username, const char *password,
bool verbose); bool verbose);

100
chkpwr.c Normal file
View 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
View 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
View 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
View 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

View 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
View 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