Compare commits
21 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 |
18 changed files with 999 additions and 70 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
30
Makefile
30
Makefile
|
|
@ -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
121
README.md
|
|
@ -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
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;
|
||||||
|
}
|
||||||
|
|
||||||
6
chkpwd.1
6
chkpwd.1
|
|
@ -1,10 +1,10 @@
|
||||||
.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
|
||||||
chkpwd [OPTION]...
|
chkpwd [OPTION]...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
chkpwd 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.
|
UNIX/PAM-based system.
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
The options which apply to the chkpwd command are:
|
The options which apply to the chkpwd command are:
|
||||||
|
|
@ -16,7 +16,7 @@ The options which apply to the chkpwd command are:
|
||||||
-h Show this help.
|
-h Show this help.
|
||||||
|
|
||||||
chkpwd runs in an interactive mode when no username and/or password are set.
|
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
|
A missing username and/or password will then be asked for while program
|
||||||
execution.
|
execution.
|
||||||
|
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
|
|
|
||||||
33
chkpwd.c
33
chkpwd.c
|
|
@ -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]);
|
||||||
|
|
|
||||||
10
chkpwd.h
10
chkpwd.h
|
|
@ -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
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