目前我有一个图形应用程序,它有两个级别的访问权限,操作员和管理员。登录和身份验证都是自制的,我想将应用程序切换为使用PAM。我不确定这样做的正确方法是什么。
如果我错了,请纠正我,但似乎PAM归结为“是”或“否”检查 - 是的,您可以访问此服务,或者不,您不能。根据用户登录的情况,没有提供各种级别的访问权限。我需要能够告诉谁是操作员以及谁是管理员,并且我希望能够在可能的情况下通过PAM严格执行。< / p>
所以我的想法是,我为运营商设置了两种不同配置的服务,/etc/pam.d/pamdemo
,为管理员设置了/etc/pam.d/pamdemo-admin
。然后,我的应用程序首先尝试对pamdemo-admin
进行身份验证,如果失败,则pamdemo
。如果两者都失败,则拒绝访问。 我是在正确的轨道还是我完全脱离轨道?
这是我编写的一些示例C代码作为概念证明。当我登录时,我不想两次提示用户提供他的凭据。我已经知道了,所以它记住了两个pam_start()
调用的用户名,但我无法从应用程序级别访问pam_get_item(PAM_AUTHTOK)
来对密码进行相同的缓存。正是在努力这样做,我意识到可能有一种完全不同的方式来做到这一点。 无论身份验证方法是什么,我希望此应用程序能够正常工作,无论是用户名/密码还是Kerberos票证或指纹,无论如何。
pam_handle_t *try_login(const char *service, int *retval)
{
static char * username = NULL;
struct pam_conv pam_conversation = { conv, NULL };
pam_handle_t * pamh;
*retval = pam_start(service, username, &pam_conversation, &pamh);
if (*retval == PAM_SUCCESS) *retval = pam_authenticate(pamh, 0);
if (*retval == PAM_SUCCESS) *retval = pam_acct_mgmt (pamh, 0);
if (*retval == PAM_SUCCESS) *retval = pam_open_session(pamh, 0);
if (username == NULL) {
if (pam_get_item(pamh, PAM_USER, (const void **) &username) == PAM_SUCCESS) {
username = strdup(username);
}
}
if (*retval != PAM_SUCCESS) {
fprintf(stderr, "%s: %s\n", service, pam_strerror(pamh, *retval));
pam_end(pamh, *retval);
pamh = NULL;
}
return pamh;
}
int main(void)
{
pam_handle_t *pamh = NULL;
int retval;
const char *service, *username;
if (!pamh) pamh = try_login("pamdemo-admin", &retval);
if (!pamh) pamh = try_login("pamdemo", &retval);
if (!pamh) {
fprintf(stderr, "Access denied.\n");
return 1;
}
pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
pam_get_item(pamh, PAM_USER, (const void **) &username);
printf("Logged into %s as %s.\n", service, username);
pam_close_session(pamh, 0);
pam_end (pamh, retval);
return 0;
}
正如编写的这个演示程序重复“密码:”提示。我不想让它问两次!
答案 0 :(得分:2)
我认为这样做的正确方法可能是:
答案 1 :(得分:1)
根据咖啡馆的建议,这是我的解决方案:
#define PAM_CALL(call) \
do { \
if ((retval = (call)) != PAM_SUCCESS) { \
goto pam_error; \
} \
} while (0)
int check_admin_login(const char *user)
{
pam_handle_t * pamh = NULL;
struct pam_conv pam_conversation = { conv, NULL };
int retval;
PAM_CALL(pam_start ("pamdemo-admin", user, &pam_conversation, &pamh));
PAM_CALL(pam_acct_mgmt(pamh, 0));
PAM_CALL(pam_end (pamh, retval));
return 1;
pam_error:
pam_end(pamh, retval);
return 0;
}
int main(void)
{
pam_handle_t * pamh = NULL;
struct pam_conv pam_conversation = { conv, NULL };
int retval;
const char * user;
int is_admin;
PAM_CALL(pam_start ("pamdemo", NULL, &pam_conversation, &pamh));
PAM_CALL(pam_authenticate (pamh, 0));
PAM_CALL(pam_acct_mgmt (pamh, 0));
PAM_CALL(pam_open_session (pamh, 0));
PAM_CALL(pam_get_item (pamh, PAM_USER, (const void **) &user));
is_admin = check_admin_login(user);
printf("Logged in as %s (%s).\n", user, is_admin ? "administrator" : "operator");
PAM_CALL(pam_close_session(pamh, 0));
pam_end (pamh, retval);
return 0;
pam_error:
fprintf(stderr, "%s\n", pam_strerror(pamh, retval));
pam_end(pamh, retval);
return 1;
}
答案 2 :(得分:0)
你可以使用命令“groups”或“id”来获取用户的组,然后grep这些组,如果你先点击管理员,那么它是管理员用户,否则它是一个演示用户。
groups / id命令(在Linux上测试)也将为非本地用户获取组(例如PAM / LDAP)
因此,请检查用户所属的组,而不是检查服务。