3

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: %s\n", spwd->sp_pwdp);
    char *encrypted = crypt(password, spwd->sp_pwdp);
    for (char *p = password; *p != '\0'; ++p)
        *p = '\0';

    if (encrypted == NULL) {
        perror("crypt");
        return 1;
    }

    if (strcmp(encrypted, spwd->sp_pwdp) != 0) {
        fputs("Incorrect password\n", stderr);
        return 1;
    }

    printf("Successfully authenticated: UID=%d\n", pwd->pw_uid);
    return 0;
}
$ sudo ./checkpass "$USER"
Password:
spwd->sp_pwdp: $y$j9T$F5Jx5fExrKuPp53xLKQ..1$X3DX6M94c7o.9agCG9G317fhZg9SqC.5i5rd.RhAtQ7
Successfully authenticated: UID=504

1 Answers1

3

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] != '\0') ? argv[0] : "(this)";
    pam_handle_t *pamh = NULL;
    int retval;
    const char *user;

    if (argc != 2) {
        fprintf(stderr, "\nUsage: %s USERNAME\n\n", 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, "Authenticated\n");
    } else {
        fprintf(stdout, "Not Authenticated\n");
    }

    if (pam_end(pamh,retval) != PAM_SUCCESS) {     /* close Linux-PAM */
        pamh = NULL;
        fprintf(stderr, "%s: failed to release authenticator\n", arg0);
        exit(EXIT_FAILURE);
    }

    return ( retval == PAM_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE );
}
Glärbo
  • 135
  • 2
  • This does not work on macOS. `#include ^~~~~~~~~~~~~~~~~~~~~ main.c:17:10: note: did not find header 'pam_misc.h' in framework 'security' (loaded from '/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks') 1 error generated.` –  Mar 29 '21 at 13:46
  • @user15502206: Could you try replacing `` with ``? (AFAIK the former was used at least for 10.3.9, perhaps it has changed in later versions.) – Glärbo Mar 29 '21 at 15:13
  • Thanks. I can compile now. But it shows `main.c:10:2: warning: 'misc_conv' is deprecated: first deprecated in macOS 10.6 [-Wdeprecated-declarations] misc_conv, ^ /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/security/openpam.h:229:5: note: 'misc_conv' has been explicitly marked deprecated here int misc_conv(int num_msg, ^ 1 warning generated.` How to fix it? –  Mar 29 '21 at 16:57
  • Where is the manpage of pam_start, etc? I don't find them. –  Mar 29 '21 at 16:59
  • 1
    @user15502206: Should work now. MacOS 10.6 and later apparently use [OpenPAM](https://www.openpam.org/) and not Linux-PAM; see [here for the sources used](https://opensource.apple.com/source/OpenPAM/OpenPAM-25/). The man pages can be found for example [here](https://www.unix.com/man-page/osx/3/openpam/), or `man -s 3 openpam`. – Glärbo Mar 29 '21 at 19:04