Search code examples
clinuxubuntupam

understanding why pam c api function pam_get_data() get uninitialized value error " No module specific data is present "?


my issue is with PAM -https://linux.die.net/man/3/pam my code enter twice to the API function PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) ; during one ssh session entrance. in this function i am sending request to a server so i added session is to the pamh, but after pam_set_date i can't get the data via pam_get _data and i cna/t get this variable. my code :

#define _GNU_SOURCE

#include "pam_hook.h" /*standart c includes file and defines */


/*PAM includes */
#include <security/pam_modules.h>
#include <security/pam_modutil.h>
#include <security/pam_ext.h>

/*PAM defintion */
#define PAM_SM_AUTH
#define PAM_SM_SESSION

/*
 * 0 - it's first time in SHM ,  else -1 error , 1- it's not fist time and  
 */
int pam_set_or_get_data(pam_handle_t *pamh){
    int retval;
    void *dataptr;
    const void * getData;
    retval = pam_get_data(pamh, "pam_session_id",(const void **) &getData);
    if (retval== PAM_SUCCESS) 
    {
        PAM_LOG_args( "pam_set_or_get_data not first time ", pam_strerror(pamh,retval));
            return 1;
    }
    else
    {
        PAM_LOG_args( "pam_set_or_get_data yes first time get failed du to ", pam_strerror(pamh,retval));

    }

    dataptr = strdup ("sesion_ID");
     if(dataptr==NULL)
     {
        PAM_LOG_args( "pam_set_or_get_data strdup error ", pam_strerror(pamh,retval));
         perror("strdup insufficient memory was available");
         return -1;

     }

  retval = pam_set_data (pamh,"pam_session_id", dataptr, sesion_id_cleanup);
  if (retval == PAM_SUCCESS)
    {
        PAM_LOG_args( "pam_set_or_get_data yes first time ", pam_strerror(pamh,retval));
        retval = pam_get_data(pamh,"pam_session_id",(const void **) &getData);
        if (retval== PAM_SUCCESS) 
        {
            PAM_LOG_args( "pam_set_or_get_data get after set ", pam_strerror(pamh,retval));

        }

      return 0;
    }
  else
  {
      PAM_LOG_args( "pam_set_data returned when expecting PAM_SYSTEM_ERR ", pam_strerror(pamh,retval)); 
      free (dataptr);  
      return -1;
  }

}

/* The actual pam functions are merely wrappers around succeed_if */
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    const char * password=NULL;
    struct passwd *pwd;
    const char *user;
    int pam_err=0;

    PAM_LOG_args( "pam_sm_authenticate", strerror(errno));
    debugPrint("pam_sm_authenticate ","",0,pamh);
    printTime();
        /* identify user */
    pam_err = pam_get_user(pamh, &user, NULL);
    if (pam_err != PAM_SUCCESS)
    {
    debugPrint("error in getting the user name :",(char *)pam_strerror(pamh, pam_err),0,pamh);

            return (pam_err);
    }

    if ((pwd = getpwnam(user)) == NULL)
    {
        debugPrint("user not defined in the system :",(char *)pam_strerror(pamh, pam_err),0,pamh);

            return (PAM_USER_UNKNOWN);
    }
    /*note : if user is not deefined pawsword return will be "^H$^M^?INCORRECT^@" */
    pam_err  = pam_get_authtok(pamh, PAM_AUTHTOK, &password , NULL);
    if (pam_err!=PAM_SUCCESS)
    {
        debugPrint("error in getting the pasword :",(char *)pam_strerror(pamh, pam_err),0,pamh);
            return (PAM_AUTH_ERR);
    }


    /*tacacs/radius auhtenticate */
    if( pam_set_or_get_data(pamh) ==0)
    {
        debugPrint("pam_sm_authenticate already_send_req!=1 goto isAuthenticate user: ",(char *)user,0,pamh);
        pam_err = isAuthenticate((char *)user,(char *)password);
        if (pam_err != PAM_OK)
        {
            debugPrint("user is not valid with tacacs/radius","",0,pamh);
                return (PAM_AUTH_ERR);
        }

    }


        return (PAM_SUCCESS);
}

the prints i made:

function :  pam_sm_authenticate  my  PID: 29452  parent PID 29445 Success stererr :Success
function :  pam_set_or_get_data yes first time get failed du to   my  PID: 29452  parent PID 29445 No module specific data is present stererr :Success
function :  pam_set_or_get_data yes first time   my  PID: 29452  parent PID 29445 Success stererr :Success
function :  pam_set_or_get_data get after set   my  PID: 29452  parent PID 29445 Success stererr :Success
function :  isAuthenticate  my  PID: 29452  parent PID 29445 Success stererr :Success
function :  pam_sm_open_session   my  PID: 29452  parent PID 29445 Unknown error -3 stererr :Unknown error -3
function :  pam_sm_authenticate  my  PID: 29459  parent PID 29445 Success stererr :Success
function :  pam_set_or_get_data yes first time get failed du to   my  PID: 29459  parent PID 29445 No module specific data is present stererr :Success
function :  pam_set_or_get_data yes first time   my  PID: 29459  parent PID 29445 Success stererr :Success
function :  pam_set_or_get_data get after set   my  PID: 29459  parent PID 29445 Success stererr :Success
function :  isAuthenticate  my  PID: 29459  parent PID 29445 Success stererr :Success
function :  sesion_id_cleanup   my  PID: 29459  parent PID 29445 Authentication failure stererr :Broken pipe
function :  pam_sm_close_session   my  PID: 29452  parent PID 29445 No such file or directory stererr :No such file or directory
function :  pam_sm_close_session succses get pam sesion id  my  PID: 29452  parent PID 29445 sesion_ID stererr :No such file or directory
function :  sesion_id_cleanup   my  PID: 29452  parent PID 29445 Success stererr :Unknown error -6

i can see that a diffrent procces is calling pam_sm_authenticate, why ? and why it does not get the data i set sesion_id ?

my pam configuration

root@compute:/# cat /etc/pam.d/sshd
 auth        requisite       /root/my_target/disk2/Sw-Pack/Active/iu_pam_hook.so
 session     optional       /root/my_target/disk2/Sw-Pack/Active/iu_pam_hook.so

compiled it with :

gcc -fPIC -Wall -shared -lpam -o pam_hook.so pam_hook.c

Solution

  • sshd uses privilege separation by default. This means that the authentication occurs in a separate process, with a defined channel of data being passed back and forth.

    So, in the case of sshd use of pam_set_data only works within the same PAM section. In other words data stored in the auth section will not be available to the session section - this is because the data is stored in the context of the auth process, which doesn't share data with the session process.

    Using pam_set_data might work if you turn off privilege separation for sshd, however this is not a long term solution as the option is removed from sshd 7.5 onwards so you would need to reimplement it using another mechanism

    A mechanism you can use would be environment variables - pam_putenv works just fine for passing data back from the auth process to the session management section from what I can tell.

    So in the auth section, store the data in environment variables - pam_putenv(handle, "VAR=value") and retrieve them using pam_getenv(handle, "VAR").

    The only issue is, of course, if the data is in a binary form, you won't be able to transfer it in this manner unencoded, and in addition, you probably want to pam_putenv(handle, "VAR") to prevent the PAM environment variable from leaking into the user session.