The following C program can check the password of a user on Linux.
But it does not work on macOS because some functions are Linux specific.
Could anybody show me how to revise the program so that it works on macOS?
#include <unistd.h> #include <pwd.h> #include <shadow.h> #include <string.h> #include <errno.h> #include <stdio.h> int main(int argc, char *argv[]) { char *username = argv[1]; struct passwd *pwd = getpwnam(username); if (pwd == NULL) { fputs("couldn't get password record", stderr); return 1; } struct spwd *spwd = getspnam(username); if (spwd == NULL) { if(errno == EACCES) { fputs("no permission to read shadow password file", stderr); return 1; } fputs("No such username", stderr); return 1; } char *password = getpass("Password: "); printf("spwd->sp_pwdp: %sn", spwd->sp_pwdp); char *encrypted = crypt(password, spwd->sp_pwdp); for (char *p = password; *p != ''; ++p) *p = ''; if (encrypted == NULL) { perror("crypt"); return 1; } if (strcmp(encrypted, spwd->sp_pwdp) != 0) { fputs("Incorrect passwordn", stderr); return 1; } printf("Successfully authenticated: UID=%dn", pwd->pw_uid); return 0; }
$ sudo ./checkpass "$USER" Password: spwd->sp_pwdp: $y$j9T$F5Jx5fExrKuPp53xLKQ..1$X3DX6M94c7o.9agCG9G317fhZg9SqC.5i5rd.RhAtQ7 Successfully authenticated: UID=504
Advertisement
Answer
Both Linux and macOS use PAM for authentication; Linux uses Linux-PAM, and MacOS and BSDs OpenPAM.
To authenticate via PAM:
/* This is a variant of the Linux-PAM example at http://www.linux-pam.org/Linux-PAM-html/adg-example.html modified to use the 'login' PAM service. That program was contributed by Shane Watts [modifications by AGM and kukuk] Save as ex_login.c, compile using (for Linux-PAM): gcc -Wall -Wextra -O2 ex_login.c -lpam -lpam_misc -o ex_login or (for OpenPAM): gcc -DOPENPAM -Wall -Wextra -O2 ex_login.c -lpam -o ex_login and run ./ex_login username to authenticate the specified user. */ #include <stdlib.h> #include <security/pam_appl.h> #ifdef OPENPAM #include <security/openpam.h> #define USE_CONV_FUNC openpam_ttyconv #else #include <security/pam_misc.h> #define USE_CONV_FUNC misc_conv #endif #include <stdio.h> static struct pam_conv conv = { USE_CONV_FUNC, NULL }; int main(int argc, char *argv[]) { const char *arg0 = (argc > 0 && argv && argv[0] && argv[0][0] != '') ? argv[0] : "(this)"; pam_handle_t *pamh = NULL; int retval; const char *user; if (argc != 2) { fprintf(stderr, "nUsage: %s USERNAMEnn", arg0); exit(EXIT_FAILURE); } user = argv[1]; retval = pam_start("login", user, &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); /* is user really user? */ if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ /* This is where we have been authorized or not. */ if (retval == PAM_SUCCESS) { fprintf(stdout, "Authenticatedn"); } else { fprintf(stdout, "Not Authenticatedn"); } if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "%s: failed to release authenticatorn", arg0); exit(EXIT_FAILURE); } return ( retval == PAM_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE ); }