旧版应用程序的PAM认证

| 我有一个旧版应用程序,该应用程序通过网络异步接收用户名/密码请求。由于我已经将用户名和密码存储为变量,因此在Linux(Debian 6)上通过PAM进行身份验证的最佳方法是什么? 我曾尝试编写自己的对话功能,但不确定将密码输入其中的最佳方法。我已经考虑过将其存储在appdata中,并从pam_conv结构中引用它,但是几乎没有关于该操作的文档。 有没有一种简单的方法来对用户进行身份验证而又不会过度使用对话功能?我也无法成功使用pam_set_data,我不确定这是否合适。 这是我正在做的事情:
user = guiMessage->username;
pass = guiMessage->password;

pam_handle_t* pamh = NULL;
int           pam_ret;
struct pam_conv conv = {
  my_conv,
  NULL
};

pam_start(\"nxs_login\", user, &conv, &pamh);
pam_ret = pam_authenticate(pamh, 0);

if (pam_ret == PAM_SUCCESS)
  permissions = 0xff;

pam_end(pamh, pam_ret);
最初尝试使用对话功能导致(密码经过硬编码以进行测试):
int 
my_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data)
{
  struct pam_response *aresp;

  if (num_msg <= 0 || num_msg > PAM_MAX_NUM_MSG)
    return (PAM_CONV_ERR);
  if ((aresp = (pam_response*)calloc(num_msg, sizeof *aresp)) == NULL)
    return (PAM_BUF_ERR);
  aresp[0].resp_retcode = 0;
  aresp[0].resp = strdup(\"mypassword\");

  *resp = aresp;
  return (PAM_SUCCESS);
}
任何帮助,将不胜感激。谢谢!     
已邀请:
这就是我最终要做的。请参阅标有三个星号的注释。
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <security/pam_appl.h>
#include <unistd.h>

// To build this:
// g++ test.cpp -lpam -o test

// if pam header files missing try:
// sudo apt install libpam0g-dev

struct pam_response *reply;

//function used to get user input
int function_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
  *resp = reply;
  return PAM_SUCCESS;
}

int main(int argc, char** argv)
{
  if(argc != 2) {
      fprintf(stderr, \"Usage: check_user <username>\\n\");
      exit(1);
  }
  const char *username;
  username = argv[1];

  const struct pam_conv local_conversation = { function_conversation, NULL };
  pam_handle_t *local_auth_handle = NULL; // this gets set by pam_start

  int retval;

  // local_auth_handle gets set based on the service
  retval = pam_start(\"common-auth\", username, &local_conversation, &local_auth_handle);

  if (retval != PAM_SUCCESS)
  {
    std::cout << \"pam_start returned \" << retval << std::endl;
    exit(retval);
  }

  reply = (struct pam_response *)malloc(sizeof(struct pam_response));

  // *** Get the password by any method, or maybe it was passed into this function.
  reply[0].resp = getpass(\"Password: \");
  reply[0].resp_retcode = 0;

  retval = pam_authenticate(local_auth_handle, 0);

  if (retval != PAM_SUCCESS)
  {
    if (retval == PAM_AUTH_ERR)
    {
      std::cout << \"Authentication failure.\" << std::endl;
    }
    else
    {
      std::cout << \"pam_authenticate returned \" << retval << std::endl;
    }
    exit(retval);
  }

  std::cout << \"Authenticated.\" << std::endl;

  retval = pam_end(local_auth_handle, retval);

  if (retval != PAM_SUCCESS)
  {
    std::cout << \"pam_end returned \" << retval << std::endl;
    exit(retval);
  }

  return retval;
}
    
为PAM传递标准信息(例如密码)的方式是使用在pam句柄中使用pam_set_item设置的变量(有关pam_set_item,请参见手册页)。 您可以将应用程序以后需要使用的任何内容设置到pam_stack中。如果要将密码放入pam_stack中,则应该在调用pam_start()之后立即进行操作,方法是将PAM_AUTHTOK变量设置到堆栈中,类似于下面的伪代码:
pam_handle_t* handle = NULL;
pam_start(\"common-auth\", username, NULL, &handle);
pam_set_item( handle, PAM_AUTHTOK, password);
这将使密码可以在堆栈上提供给任何希望使用它的模块,但是通常您必须通过在服务的pam_configuration中设置标准use_first_pass或try_first_pass选项来告诉该模块使用该密码(在本例中为/ etc /pam.d/common-auth)。 标准的pam_unix模块确实支持try_first_pass,因此将其添加到系统的pam配置中(在pam_unix行的末尾)不会有任何问题。 执行完此操作后,从common-auth服务调用的对pam_authenticate()的任何调用都应该只提取密码并随身携带。 关于use_first_pass和try_first_pass之间的区别的一个小说明:它们都告诉模块(在本例中为pam_unix)尝试在pam_stack上输入密码,但是在没有密码/ AUTHTOK可用时,它们的行为有所不同。在缺少的情况下,use_first_pass失败,而try_first_pass允许模块提示输入密码。     
Fantius的解决方案对我来说是有效的,甚至是root。 我最初选择John的解决方案,因为它更干净,并且使用了不带会话功能的PAM变量(实际上,这里不需要它),但是它没有,而且也不会起作用。正如亚当·巴杜拉(Adam Badura)在这两篇文章中提到的那样,PAM进行了一些内部检查,以防止直接设置PAM_AUTHTOK。 John的解决方案将导致与此处提到的行为类似的行为,在该行为中,任何密码值都将被允许登录(即使您声明但未定义pam_conv变量)。 我还建议用户注意malloc的位置,因为它在您的应用程序中可能会有所不同(请记住,上面的代码更多的是测试/模板,而不是其他任何东西)。     

要回复问题请先登录注册