Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is PAM an appropriate method to authenticate a user on MacOS

Tags:

macos

pam

I am trying to authenticate a user on MacOS using PAM with the following code:

#include <security/pam_appl.h>

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

static int PamCallbackFn( int num_msg,
            const struct pam_message **msg,
            struct pam_response **resp,
            void *appdata_ptr )
{
    printf("PamCallbackFn num_msg=%d:\n", num_msg );
    for ( int idx = 0; idx < num_msg; ++ idx )
    {
        printf(
            "\tPrompt type %d for '%s'\n", 
            msg[idx]->msg_style,
            msg[idx]->msg );
    }

    assert( num_msg == 1 );
    struct pam_response *response = 
        (struct pam_response *)malloc( sizeof( struct pam_response ) );
    response->resp = strdup( "fhtest" );
    response->resp_retcode = 0;

    *resp = response;
    return PAM_SUCCESS;
}

int main( int argc, char **argv )
{
    struct pam_conv Callback;
    Callback.conv = PamCallbackFn;
    Callback.appdata_ptr = 0;

    printf("Calling pam_start()...\n");

    pam_handle_t *AuthHandle = 0;
    int Result = 
        pam_start(
            "test",     // Client program name
            "fhtest",   // User name
            &Callback,
            &AuthHandle );
    if ( Result != PAM_SUCCESS )
    {
        printf(
            "pam_start() returned %d (%s)\n",
            Result,
            pam_strerror( AuthHandle, Result ) );
        return EXIT_FAILURE;
    }

    printf("Calling pam_authenticate()...\n");
    Result = pam_authenticate( AuthHandle, PAM_SILENT );
    if ( Result != PAM_SUCCESS )
    {
        printf(
            "pam_authenticate() returned %d (%s)\n",
            Result,
            pam_strerror( AuthHandle, Result ) );
        return EXIT_FAILURE;
    }

    printf("Calling pam_acct_mgmt()...\n");
    Result = pam_acct_mgmt( AuthHandle, 0 );
    if ( Result != PAM_SUCCESS )
    {
        printf(
            "pam_acct_mgmt() returned %d (%s)\n",
            Result,
            pam_strerror( AuthHandle, Result ) );
        return EXIT_FAILURE;
    }

    printf("Success !\n");
    pam_end( AuthHandle, Result );
    return EXIT_SUCCESS;
}

The compile and run commands on MacOS are:

clang pamtest.c -lpam
sudo ./a.out

However when the code is run on MacOS the output is:

Calling pam_start()…
Calling pam_authenticate()…
pam_authenticate() returned 9 (authentication error)

No attempt is made to by pam to call PamCallbackFn() to supply the password.

If the same code is compiled and run on Ubuntu, authentication is successful and I get the following output:

Calling pam_start()…
Calling pam_authenticate()…
PamCallbackFn num_msg=1
    Prompt type 1 for 'Password: '
Calling pam_acct_mgmt()…
Success !

The user account fhtest exists on both MacOS and Ubuntu. I can login manually using this account to both computers.

There is no specific pam service file for "test" in /etc/pam.d (first argument to the pam_start call). In this case pam should fall back to using /etc/pam.conf. The file /etc/pam.conf exists on the Ubuntu computer, but consists only of comments. The file /etc/pam.conf does not exist on the MacOS computer. Creating the file /etc/pam/conf on the MacOS computer similar to the one on the Ubuntu computer does not fix the problem.

What I am looking for is a working example of how to authenticate a user with a UserName and Password on MacOS. The solution should be usable from a background service or daemon.

like image 716
bradfordrg Avatar asked Sep 06 '25 18:09

bradfordrg


1 Answers

PAM is an interface for authentication tasks and it does not make the authentication by itself (for example it can delegate the authentication to a remote Kerberos or LDAP server, or to a local login system).

The configuration must be done at system level in /etc/pam.d or /etc/pam.conf. You should verify if your configuration is correct. For example, as your service name is "test", you probably need a file /etc/pam.d/test.

Or you can try to chose another service name in the pam_start() call. For example "login".

like image 76
user803422 Avatar answered Sep 09 '25 16:09

user803422