Skip to content
Advertisement

How to check password on macOS?

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 );
}
9 People found this is helpful
Advertisement