Linux の PAM: リモート/外部認証 DB が否定応答を返す場合にローカル認証をスキップする方法はありますか?

Linux の PAM: リモート/外部認証 DB が否定応答を返す場合にローカル認証をスキップする方法はありますか?

親愛なるシステムいじり仲間の皆さん、

管理者の友人が私に次の質問をしました:

彼は、多くのネットワーク要素とサーバーで、TACACS+ サーバーに対するリモート認証を使用しています。このような独自のアプライアンスでは、リモートメソッドが「認証サーバーが利用できません」(到達不能、タイムアウト) を返す場合にのみ、認証はローカル認証 DB に問い合わせます。リモート認証サーバーが利用できず、否定応答が返された場合、問題のボックスはそれを額面通りに受け取り、ローカル ユーザー データベースに対して認証を試行しません。

さて、Linux ベースのボックスで、同じ動作を実現したいと考えています。しかし、どうやらできないようです。Linux OS は最初にリモート認証を試行しますが、明らかに否定的な応答 (サーバーが「認証失敗、有効な資格情報ではありません」と応答) があると、先に進み、ローカル データベースも試行します。

リモート TACACS+ 認証は、pam_tacplus という優れた PAM モジュールによって調整されていることがわかりました。PAM 全般について読んでみると、pam_tacplus に問題があるわけではないことがわかってきました。むしろ、観察された動作は、PAM 全体の動作方法にすぎません。そうであれば、直接的な解決策としては、PAM コードベースに構成可能なグローバル オプションを追加し、場合によっては特定の PAM 構成ファイルのキーワード/構文を追加して、動作を望ましい方向に変更する必要があるでしょう。

このトピックに関するさらなるメモは歓迎します :-)

答え1

...さらに読んだ内容に基づいて、回答を提案させてください。もちろん、追加や修正があれば大歓迎です。

まず最初に、これはかなり昔のものだと気づいたPAM 入門おそらく、長年にわたってその鋭い機知を失っていないでしょう。

中身を覗いてみると、認証モジュールの戻り値は公式のlinux-pamドキュメントに記載されている

リストには、 PAM_AUTHINFO_UNAVAIL という有望な retval が表示されます。

実際に定義されているlibpam/include/security/_pam_types.h

#define PAM_SUCCESS 0
#define PAM_AUTHINFO_UNAVAIL 9
#define _PAM_RETURN_VALUES 32 

PAM_AUTHINFO_UNAVAILの定義が矛盾しているようです。libpam/include/security/_pam_compat.h

# define PAM_AUTHINFO_UNAVAIL     12

-- おそらく無視しても安全です。

ソースファイルlibpam/pam_dispatch.c には、_pam_dispatch_aux() と呼ばれる重要な関数が含まれています。は、登録された認証モジュールのスタックを実際に走査し、その戻り値に基づいて動作します。そして、それは「retval」に直接基づいて多くのことを行わず、おそらく を含んでいることが判明しましたPAM_AUTHINFO_UNAVAIL。 の特定の「内部の特別な使用」値に直接応答しますretvalが、 に対して特別な処理はありませんPAM_AUTHINFO_UNAVAIL。は、それ自体retvalの戻り値ではありません_pam_dispatch_aux()。むしろ、 は、retval登録された認証モジュールのスタックを走査する for(;;) ループ内で宣言されたローカル変数にすぎず、ブロックローカルはretval特定のモジュールの戻り値を収集します。スタックウォーク ループは、実際には他の変数に基づいて重要な決定を行います。そのうちの 1 つは と呼ばれる派生変数でありaction、もう 1 つはモジュールによって参照によって「返される」と呼ばれる構造体メンバーですimpression。したがって、結局のところ、モジュール自体のコードによって影響を受ける可能性があります。

実際には、これはaction「アクションの参照テーブル」から取得されます。 インデックスああretval

action = h->actions[cached_retval];

アクションのテーブルはモジュールによって定義されていますか?しかし、_PAM_ACTION_*マクロが#definedである場合、libpam/pam_private.h?

アクション[]テーブルは一般的な方法で初期化される_pam_parse_conf_file()で呼び出される関数によってlibpam/pam_handlers.c直接文字列比較required、、、requisiteなどoptionalのキーワードに(一致)します sufficient

そして、テーブル全体には現在32の位置(上記のマクロ定義を参照)があり、卸売初期化特定のモジュールの設定エントリを解析する前に、_PAM_ACTION_UNDEF に変更します。個々の「強度キーワード」は、個々のretvalを特定の望ましいアクションに再マップします。

したがって、例えば次のようなものからインスピレーションを得るのはかなり明白なようです:

} else if (!strcasecmp("required", tok)) {
    D(("*PAM_F_REQUIRED*"));
    actions[PAM_SUCCESS] = _PAM_ACTION_OK;
    actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
    actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
    _pam_set_default_control(actions, _PAM_ACTION_BAD);
} else if (!strcasecmp("sufficient", tok)) {
    D(("*PAM_F_SUFFICIENT*"));
    actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
    actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
    _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
}

そして、次のようなものを追加します

} else if (!strcasecmp("reqd_if_avail", tok)) {
    D(("*PAM_F_REQD_IF_AVAIL*"));
    actions[PAM_SUCCESS] = _PAM_ACTION_OK;
    actions[PAM_AUTHINFO_UNAVAIL] = _PAM_ACTION_IGNORE; // !!!!!!!!!!
    actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;     // ?
    actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
    _pam_set_default_control(actions, _PAM_ACTION_BAD); // !!!
}

そしてどうやらpam_tacplusその道を歩むのを助けてくれる

ソース コードをハッキングすることなく、既存の PAM 構成ファイル構文で同じ効果を実現できれば、確かに便利です。

関連情報