2011-05-06 53 views
8

我有一个传统应用程序,通过线路异步接收用户名/密码请求。由于我已经将用户名和密码存储为变量,因此在Linux(Debian 6)上使用PAM进行身份验证的最佳方式是什么?传统应用程序的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); 
} 

任何帮助,将不胜感激。谢谢!

回答

12

这就是我最终做的。查看标有三个星号的评论。

#include <stdlib.h> 
#include <iostream> 
#include <fstream> 
#include <security/pam_appl.h> 
#include <unistd.h> 

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

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; 
} 
+0

谢谢!在这里,我试图找到方法来沟通_对话函数,而不是绕过并处理其外部的响应。 – 2011-05-12 19:26:46

+0

这不适用于'root'(只是'root',所有其他用户都可以自动认证)。这是一个错误? – alexandernst 2013-04-28 16:44:04

+0

我不知道。我没有尝试root。如果您需要定期使用root密码,那么您可能会出错。 – Fantius 2013-04-28 19:17:09

1

标准信息(如密码)传递PAM的方法是使用与pam_set_item PAM句柄(参见pam_set_item手册页)设置的变量。

您可以设置您的应用程序稍后需要使用的任何内容到pam_stack中。

pam_handle_t* handle = NULL; 
pam_start("common-auth", username, NULL, &handle); 
pam_set_item(handle, PAM_AUTHTOK, password); 

这将使密码:如果你想把密码进入pam_stack的,你应该通过设置PAM_AUTHTOK可变进栈类似于下面的伪代码调用pam_start()后,马上就能做到这一点在堆栈中可用于任何使用它的模块,但通常必须通过在服务的pam_configuration中设置标准use_first_pass或try_first_pass选项(在本例中为/etc/pam.d/)来告诉模块使用它常见-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允许模块提示输入密码。

+0

http://pubs.opengroup.org/onlinepubs/8329799/chap4.htm#tagcjh_05_02_01_01提到''PAM_AUTHTOK'是“_只对PAM模块可用,对应用程序不可用”。所以你不应该做你描述的那些。你检查过它是否有效?也许它确实但不是便携式的? – 2015-09-29 10:28:18

+0

然后'pam_set_item'文档(http://pubs.opengroup.org/onlinepubs/8329799/pam_set_item.htm#tagmref_pam_set_item)似乎没有重复这种情况,而它确实提供了'PAM_AUTHOK'。 – 2015-09-29 12:13:48

0

Fantius的解决方案为我工作,甚至作为根。

我最初选择了John的解决方案,因为它更干净,并且使用PAM变量而没有对话功能(实际上,这里没有必要),但它不会,也不会工作。正如Adam Badura在两篇文章中提到的,PAM有一些内部检查来防止直接设置PAM_AUTHTOK。

John的解决方案将导致类似here的行为,其中任何密码值都将被允许登录(即使您声明,但不定义pam_conv变量)。

我还建议用户注意malloc的位置,因为它可能会在你的应用程序中有所不同(请记住,上面的代码更多的是测试/模板,而不是其他任何东西)。

+0

这不提供问题的答案。一旦你有足够的[声誉](https://stackoverflow.com/help/whats-reputation),你将可以[对任何帖子发表评论](https://stackoverflow.com/help/privileges/comment);相反,[提供不需要提问者澄清的答案](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-c​​an- I-DO-代替)。 - [来自评论](/ review/low-quality-posts/18803902) – Umair 2018-02-13 05:24:32

+0

请不要添加“谢谢”作为答案。相反,投票答案,你觉得有帮助。 - [来自评论](/ review/low-quality-posts/18803902) – Graham 2018-02-13 05:42:29

+0

感谢您提醒我为什么我在这些网站上随便;)我的道歉! – gagan 2018-02-13 06:11:12