【问题标题】:Different access levels with PAMPAM 的不同访问级别
【发布时间】:2010-11-13 04:53:43
【问题描述】:

目前我有一个图形应用程序,它有两个访问级别,操作员和管理员。登录和身份验证都是自制的,我想将应用程序切换为使用 PAM。我不确定这样做的正确方法是什么。

如果我错了,请纠正我,但 PAM 似乎归结为“是”或“否”检查 - 是的,您可以访问此服务,或者不,您不能。没有规定根据哪个用户登录具有不同级别的访问权限。不过,我需要能够分辨谁是操作员,谁是管理员,如果可能的话,我希望能够严格通过 PAM 来做到这一点。

所以我的想法是设置两种不同配置的服务/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;
}

正如所写的那样,这个演示程序重复了“密码:”提示。我不想让它问两次!

【问题讨论】:

    标签: c linux security authentication pam


    【解决方案1】:

    我认为一种正确的方法可能是:

    • 设置“pamdemo”服务来执行帐户、身份验证和会话功能。
    • 将“pamdemo-admin”服务设置为执行帐户(可能还有会话)功能。没有身份验证。
    • 登录时,首先让他们通过“pamdemo”(以确保他们是他们所说的人) - 如果失败,将他们踢出。
    • 然后,一旦通过身份验证,将它们交给“pamdemo-admin”。这只是检查他们是否被允许成为管理员 - 如果是,则此检查成功,如果不是,则不会。由于此检查不执行身份验证模块,因此不会再次提示它们输入密码。

    【讨论】:

      【解决方案2】:

      根据 caf 的建议,这是我的解决方案:

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

      【讨论】:

        【解决方案3】:

        您可以使用命令“groups”或“id”获取用户的组,然后 grep 组,如果您先点击 admin,则它是 admin 用户,否则它是演示用户。

        groups / id 命令(在 Linux 上测试)也将获取非本地用户的组(例如 PAM / LDAP)

        因此,与其检查服务,不如检查用户所属的组。

        【讨论】:

          猜你喜欢
          • 2017-07-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-17
          • 1970-01-01
          • 1970-01-01
          • 2015-02-16
          • 2019-09-26
          相关资源
          最近更新 更多