了解为什么 pam c api function pam_get_data() 得到未初始化的值错误“不存在模块特定数据”?

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

我的问题是 PAM -https://linux.die.net/man/3/pam 我的代码在 API 函数中输入两次 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) ;在一个 ssh 会话入口期间。 在此函数中,我向服务器发送请求,因此我将会话添加到 pamh,但在 pam_set_date 之后,我无法通过 pam_get _data 获取数据,而我 cna/t 获取此变量.我的代码:

#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);
}

我制作的版画:

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

我可以看到不同的进程正在调用 pam_sm_authenticate,为什么?为什么它没有得到我设置的数据 sesion_id ?

我的 pam 配置

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

用 :

编译它
gcc -fPIC -Wall -shared -lpam -o pam_hook.so pam_hook.c

sshd 默认使用权限分离。这意味着身份验证发生在一个单独的过程中,定义的数据通道来回传递。

因此,在使用 sshd 的情况下,pam_set_data 仅适用于同一 PAM 部分。换句话说,存储在 auth 部分的数据对 session 部分不可用 - 这是因为数据存储在 auth 进程的上下文中,不与会话共享数据过程。

如果您关闭 sshd 的特权分离,使用 pam_set_data 可能 工作,但这不是一个长期的解决方案,因为该选项从 sshd 7.5 开始被删除所以您需要使用另一种机制重新实现它

您可以使用的一种机制是环境变量 - pam_putenv 据我所知,可以很好地将数据从 auth 进程传回会话管理部分。

因此在 auth 部分,将数据存储在环境变量中 - pam_putenv(handle, "VAR=value") 并使用 pam_getenv(handle, "VAR") 检索它们。

当然,唯一的问题是,如果数据是二进制形式,您将无法以这种未编码的方式传输它,此外,您可能希望 pam_putenv(handle, "VAR")防止 PAM 环境变量泄漏到用户会话中。