2

現在、オペレータと管理者の 2 つのレベルのアクセスを持つグラフィカル アプリケーションがあります。ログインと認証はすべて自作であり、代わりに PAM を使用するようにアプリケーションを切り替えたいと考えています。それを行う正しい方法が何であるかはわかりません。

私が間違っている場合は訂正してください。ただし、PAM は「はい」または「いいえ」のチェックに要約されるようです。つまり、このサービスにアクセスできるか、できないかです。どのユーザーがログインしているかに基づいて、さまざまなレベルのアクセス権を持つための規定はありません。ただし、誰がオペレーターで誰が管理者であるかを判別できるようにする必要があり、可能であれば PAM を介して厳密に実行できるようにしたいと考えています。

したがって、オペレーター用と管理者用の 2 つの異なる構成を持つ 2 つのサービスをセットアップすると思います。次に、私のアプリケーションは最初に認証を試み、それが失敗した場合は. 両方が失敗した場合、アクセスは拒否されます。私は正しい軌道に乗っていますか、それとも完全に脱線していますか?/etc/pam.d/pamdemo/etc/pam.d/pamdemo-adminpamdemo-adminpamdemo

概念実証として作成した C コードのサンプルを次に示します。ログインを行うときに、ユーザーに資格情報を 2 回要求したくありません。2回の呼び出しでユーザー名を覚えているので、アプリケーションレベルから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;
}

書かれているように、このデモ プログラムは "password:" プロンプトを繰り返します。二度も聞かれたくない!

4

3 に答える 3

2

これを行う正しい方法の1つは次のとおりだと思います。

  • 「pamdemo」サービスをセットアップして、アカウント、認証、およびセッション機能を実行します。
  • 「pamdemo-admin」サービスをセットアップして、アカウント (および場合によってはセッション) 機能のみを実行します。認証なし。
  • ログインするときは、まず "pamdemo" を渡すようにします (本人であることを確認するため)。これが失敗した場合は、追い出します。
  • 次に、認証されたら、それらを「pamdemo-admin」に渡します。これは、管理者になることが許可されているかどうかを確認するだけです。許可されている場合、このチェックは成功し、許可されていない場合は失敗します。このチェックは認証モジュールを行わないため、再度パスワードを要求されることはありません。
于 2009-07-23T04:58:43.417 に答える
1

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;
}
于 2009-07-23T17:51:04.877 に答える
0

コマンド「groups」または「id」を使用してユーザーのグループを取得し、グループをgrepして、最初にadminを押すと、それはadminユーザーになり、それ以外の場合はデモユーザーになります。

groups / idコマンド(Linuxでテスト済み)は、非ローカルユーザー(PAM / LDAPなど)のグループも取得します

したがって、サービスに対してチェックする代わりに、ユーザーが属するグループをチェックします。

于 2011-03-17T17:34:15.620 に答える