diff --git a/.gitignore b/.gitignore index d980a9c..73aa35c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,2 @@ -*.o -*.so -chkgrp -chkgrp-min -chkgrp-native -chkgrp-native-min -chkgrp-native-min-extended -chkgrp-ng -chkpwd -chkpwd.1.gz -chkpwr -test -test.c +checkpw +checkpw.o diff --git a/Makefile b/Makefile index 1628df2..7e9ebc9 100644 --- a/Makefile +++ b/Makefile @@ -1,52 +1,17 @@ all: - $(CC) -Wall -o ./chkgrp ./chkgrp.c - $(CC) -Wall -o ./chkgrp-min ./chkgrp-min.c - $(CC) -Wall -o ./chkgrp-native ./chkgrp-native.c - $(CC) -Wall -o ./chkgrp-native-min ./chkgrp-native-min.c - $(CC) -Wall -o ./chkgrp-native-min-extended ./chkgrp-native-min-extended.c - $(CC) -Wall -o ./chkgrp-ng ./chkgrp-ng.c - $(CC) -Wall -o ./chkpwd ./chkpwd.c -lpam - gzip -fk ./chkpwd.1 - $(CC) -Wall -o ./chkpwr ./chkpwr.c + $(CC) -Wall -o checkpw checkpw.c -lpam -lpam_misc clean: - rm -f ./chkgrp - rm -f ./chkgrp-min - rm -f ./chkgrp-native - rm -f ./chkgrp-native-min - rm -f ./chkgrp-native-min-extended - rm -f ./chkgrp-ng - rm -f ./chkpwd - rm -f ./chkpwd.1.gz - rm -f ./chkpwr - rm -f ./test + rm -f ./checkpw install: - install -g 0 -o 0 -m 0655 ./chkgrp /usr/bin/ - install -g 0 -o 0 -m 0655 ./chkgrp-min /usr/bin/ - install -g 0 -o 0 -m 0655 ./chkgrp-native /usr/bin/ - install -g 0 -o 0 -m 0655 ./chkgrp-native-min /usr/bin/ - install -g 0 -o 0 -m 0655 ./chkgrp-native-min-extended /usr/bin/ - install -g 0 -o 0 -m 0655 ./chkgrp-ng /usr/bin/ - install -g 0 -o 0 -m 0655 ./chkpwd /usr/bin/ - install -g 0 -o 0 -m 0644 ./chkpwd.h /usr/include/ - install -g 0 -o 0 -m 0644 ./chkpwd.1.gz /usr/share/man/man1/ - install -g 0 -o 0 -m 0655 ./chkpwr /usr/bin/ - install -g 0 -o 0 -m 0655 ./lua/chkgrp-native-min-extended.lua /usr/bin/ + cp ./checkpw /usr/bin/ + cp ./checkpw.1 /usr/share/man/man1/ + gzip -f /usr/share/man/man1/checkpw.1 + cp ./checkpw.h /usr/include/ 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/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 + rm -f /usr/bin/checkpw + rm -f /usr/share/man/man1/checkpw.1.gz + rm -f /usr/include/checkpw.h diff --git a/README.md b/README.md index d7e1945..6ee6876 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,54 @@ -# chkusr +# checkpw -chkusr is a set of programs (chkgrp, chkpwd and chkpwr) to verify information about a user and/or group on UNIX based systems. +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. -## THE FOLLOWING DOCUMENTATION WILL NOT WORK ACTUALLY! YOU NEED TO READ THE CODE! SORRY... +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 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) +## The idea -### The idea +I needed a program to verify passwords of users on Linux/UNIX systems using PAM that just returns 0 on success and 1 on error. -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 +## Building checkpw ``` -git clone https://git.xw3.org/hanez/chkusr.git -cd chkusr +git clone https://git.xw3.org/xw3/checkpw.git +cd checkpw make ``` -#### Installation +The code only supports verifying passwords for user id 1000 by default. Look at the file checkpw.h for some compile time options! -**WARNING:** Install this software with care. chkpwd could easily be used for bruteforcing passwords from local users! +### 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! ``` sudo make install ``` -chkusr programs are installed to /usr/bin/. +checkpw is installed to /usr/bin/. -chkpwd.h is installed to /usr/include/ for use in other applications. +checkpw.h is installed to /usr/include/ for use in other applications. -#### Uninstall +## Uninstall ``` sudo make uninstall ``` -### 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 +## Usage ``` -chkpwd -h -Usage: chkpwd [-u ] [-p ] [-v] [-V] [-h] +checkpw -h +Usage: checkpw [-u ] [-p ] [-v] [-V] [-h] Options: -u Set username. @@ -93,70 +58,50 @@ Options: -h Show this help. ``` -You can also use chkpwd even without installing by just running the following command: +You can also use checkpw even without installing by just running the following command: ``` -./chkpwd +./checkpk ``` -##### Return codes +checkpw 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 +checkpw ``` -###### Interactive mode only asking for a password +#### Interactive mode only asking for a password ``` -chkpwd -u hanez +checkpw -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 checkpw ``` -chkpwd -u hanez -p password +checkpw -u hanez -p password ``` -###### Request the result from the above commands +#### Request the result from the above commands ``` echo $? ``` -##### Custom build +## License -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. +checkpw 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/) diff --git a/checkpw.1 b/checkpw.1 new file mode 100644 index 0000000..90206b8 --- /dev/null +++ b/checkpw.1 @@ -0,0 +1,24 @@ +.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 Set username. + -p 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) diff --git a/chkpwd.c b/checkpw.c similarity index 87% rename from chkpwd.c rename to checkpw.c index 4273372..847b287 100644 --- a/chkpwd.c +++ b/checkpw.c @@ -1,15 +1,11 @@ /** - * chkpwd is a program that checks the validity of a users password on a + * checkpw is a program that checks the validity of a users password on a * UNIX/PAM-based system. * * Author: Johannes Findeisen - 2024 - * Homepage: https://git.xw3.org/hanez/chkpwd * License: Apache-2.0 (see LICENSE) */ -#include "chkpwd.h" -#include "config.h" - #include #include #include @@ -17,6 +13,8 @@ #include #include +#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) @@ -82,28 +80,28 @@ int main(int argc, char *argv[]) { bool verbose = false; bool version = false; - char password[MAX_PASSWORD] = {0}; - char username[MAX_NAME] = {0}; + char password[MAX_PASSWORD_LEN] = {0}; + char username[MAX_USERNAME_LEN] = {0}; int opt; // Parse command-line arguments while ((opt = getopt(argc, argv, "u:p:hvV")) != -1) { switch (opt) { case 'u': - if (strlen(optarg) >= MAX_NAME) { + if (strlen(optarg) >= MAX_USERNAME_LEN) { fprintf(stderr, "Error: Username is too long (maximum %d characters).\n", - MAX_NAME); + MAX_USERNAME_LEN); exit(1); } - strncpy(username, optarg, MAX_NAME - 1); + strncpy(username, optarg, MAX_USERNAME_LEN - 1); break; case 'p': - if (strlen(optarg) >= MAX_PASSWORD) { + if (strlen(optarg) >= MAX_PASSWORD_LEN) { fprintf(stderr, "Error: Password is too long (maximum %d characters).\n", - MAX_PASSWORD); + MAX_PASSWORD_LEN); exit(1); } - strncpy(password, optarg, MAX_PASSWORD - 1); + strncpy(password, optarg, MAX_PASSWORD_LEN - 1); break; case 'h': print_usage(argv[0]); @@ -159,7 +157,7 @@ int main(int argc, char *argv[]) printf("User '%s' passed UID check (UID: %d).\n", username, pwd->pw_uid); - if (checkpw_authenticate(username, password, verbose) == true) { + if (authenticate(username, password, verbose) == true) { printf("Authenticated successfully.\n"); return 0; } else { diff --git a/chkpwd.h b/checkpw.h similarity index 84% rename from chkpwd.h rename to checkpw.h index d97c229..bdfc1bf 100644 --- a/chkpwd.h +++ b/checkpw.h @@ -1,19 +1,34 @@ /** - * chkpwd.h is part of chkusr, a set of programs to verify information about - * a user on UNIX based systems. + * checkpw.h is part of checkpw, a program that checks the validity of a users + * password on a UNIX/PAM-based system. * * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr * License: Apache-2.0 (see LICENSE) */ #include -#include #include #include -bool checkpw_authenticate(const char *username, const char *password, - bool verbose); +#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); int pam_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); @@ -23,8 +38,7 @@ struct pam_credentials const char *password; }; -bool checkpw_authenticate(const char *username, const char *password, - bool verbose) +bool authenticate(const char *username, const char *password, bool verbose) { int retval; pam_handle_t *pamh = NULL; diff --git a/chkgrp-min.c b/chkgrp-min.c deleted file mode 100644 index 4bc4dcb..0000000 --- a/chkgrp-min.c +++ /dev/null @@ -1,48 +0,0 @@ -/** - * chkgrp-min is a program that checks if a user is a member of a group. - * - * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr - * License: Apache-2.0 (see LICENSE) - */ - - #include "config.h" - -#include -#include -#include -#include -#include - -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; -} - diff --git a/chkgrp-native-min-extended.c b/chkgrp-native-min-extended.c deleted file mode 100644 index 320c57f..0000000 --- a/chkgrp-native-min-extended.c +++ /dev/null @@ -1,101 +0,0 @@ -/** - * chkgrp-min-native-extended is a program that checks if a user is a member - * of a group. - * - * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr - * License: Apache-2.0 (see LICENSE) - */ - -#include "config.h" - -#include -#include -#include -#include - -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; -} - diff --git a/chkgrp-native-min.c b/chkgrp-native-min.c deleted file mode 100644 index 8786a20..0000000 --- a/chkgrp-native-min.c +++ /dev/null @@ -1,59 +0,0 @@ -/** - * chkgrp-min-native is a program that checks if a user is a member of a group. - * - * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr - * License: Apache-2.0 (see LICENSE) - */ - -#include "config.h" - -#include -#include -#include - -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; -} - diff --git a/chkgrp-native.c b/chkgrp-native.c deleted file mode 100644 index d19de61..0000000 --- a/chkgrp-native.c +++ /dev/null @@ -1,77 +0,0 @@ -/** - * chkgrp-native is a program that checks if a user is a member of a group. - * - * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr - * License: Apache-2.0 (see LICENSE) - */ - -#include "config.h" - -#include -#include -#include - -int main(int argc, char *argv[]) -{ - if (argc != 3) { - fprintf(stderr, "Usage: %s \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; -} - diff --git a/chkgrp-ng.c b/chkgrp-ng.c deleted file mode 100644 index e22c053..0000000 --- a/chkgrp-ng.c +++ /dev/null @@ -1,152 +0,0 @@ -/** - * chkgrp-ng is a program that checks if a user is a member of a group. - * - * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr - * License: Apache-2.0 (see LICENSE) - */ - -#include "config.h" - -#include -#include -#include - -void print_help(const char *prog) -{ - printf("Usage: %s [OPTIONS] \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; -} - diff --git a/chkgrp.c b/chkgrp.c deleted file mode 100644 index 35fcd75..0000000 --- a/chkgrp.c +++ /dev/null @@ -1,75 +0,0 @@ -/** - * chkgrp is a program that checks if a user is a member of a group. - * - * Author: Johannes Findeisen - 2025 - * Homepage: https://git.xw3.org/hanez/chkusr - * License: Apache-2.0 (see LICENSE) - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char *argv[]) -{ - if (argc != 3) { - fprintf(stderr, "Usage: %s \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; -} - diff --git a/chkpwd.1 b/chkpwd.1 deleted file mode 100644 index da6b5cb..0000000 --- a/chkpwd.1 +++ /dev/null @@ -1,27 +0,0 @@ -.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 Set username. - -p 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 . diff --git a/chkpwr.c b/chkpwr.c deleted file mode 100644 index e6be5eb..0000000 --- a/chkpwr.c +++ /dev/null @@ -1,100 +0,0 @@ -/** - * checkpwrule is a program that checks if an input string validates a - * password rule. - * - * Author: Johannes Findeisen - 2024 - * License: MIT (see LICENSE) - */ - -#include "config.h" - -#include -#include -#include - -// 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 \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 - } -} - diff --git a/config.h b/config.h deleted file mode 100644 index be0bc9a..0000000 --- a/config.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Author: Johannes Findeisen - 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 - diff --git a/lua/README.md b/lua/README.md deleted file mode 100644 index f891075..0000000 --- a/lua/README.md +++ /dev/null @@ -1 +0,0 @@ -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... diff --git a/lua/checkgroup.lua b/lua/checkgroup.lua deleted file mode 100755 index a8ee0db..0000000 --- a/lua/checkgroup.lua +++ /dev/null @@ -1,79 +0,0 @@ --- This file is part of chkgrp that is a program that checks if a user is a --- member of a group. --- --- Author: Johannes Findeisen - 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 - diff --git a/lua/chkgrp-native-min-extended.lua b/lua/chkgrp-native-min-extended.lua deleted file mode 100755 index 6b5f22f..0000000 --- a/lua/chkgrp-native-min-extended.lua +++ /dev/null @@ -1,89 +0,0 @@ -#!/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 - 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 - diff --git a/lua/test.lua b/lua/test.lua deleted file mode 100755 index 0bfb5e8..0000000 --- a/lua/test.lua +++ /dev/null @@ -1,26 +0,0 @@ -#!/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 - 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 -