説明
PAM(Pluggable Authentication Modules)のpam_authenticate()は認証情報を検証しますが、アカウント管理ポリシーの確認を置き換えません。認証後にpam_acct_mgmt()の結果を確認しないと、アカウントの有効期限やアクセス制限を見落とす可能性があります。
想定される影響
- アカウント管理ポリシーで禁止したユーザーがログインできる可能性があります。
- アカウントやパスワードの期限切れを適切に処理できないおそれがあります。
- 実際の影響は、サービスに構成されたPAMモジュールとアカウントポリシーによって異なります。
対処方法
- 認証成功後に
pam_acct_mgmt()でアカウントの状態とアクセス条件を確認してください。成功しなければ、そのままアクセスを許可しないでください。 PAM_NEW_AUTHTOK_REQDはパスワードの変更が必要な状態です。許可された変更手続きが完了するまではアクセスを拒否してください。- 必要な認証・アカウント管理モジュールと最小権限のポリシーを構成してください。パスワードを記録せずに、ログインの成功と失敗をログに残してください。
例
PAMバインディングの流れを示す抜粋です。pam_startとhandle_convのバインディング、パスワードの受け渡し、pam_endによる終了処理は省略しています。実装時は初期化の成功を確認し、開始に成功したトランザクションをすべての終了経路で後始末してください。
変更前
python
from pam import PamHandle, PamConv
from ctypes import CDLL, c_int, byref
from ctypes.util import find_library
libpam = CDLL(find_library("pam"))
pam_authenticate = libpam.pam_authenticate
pam_authenticate.argtypes = [PamHandle, c_int]
pam_authenticate.restype = c_int
def authenticate(username, password, service='login'):
handle = PamHandle()
conv = PamConv(handle_conv, 0)
retval = pam_start(service, username, byref(conv), byref(handle))
if retval != 0:
return False
# アカウントポリシーを確認せずに認証
return pam_authenticate(handle, 0) == 0
変更後
python
from pam import PamHandle, PamConv
from ctypes import CDLL, c_int, byref
from ctypes.util import find_library
libpam = CDLL(find_library("pam"))
pam_authenticate = libpam.pam_authenticate
pam_authenticate.argtypes = [PamHandle, c_int]
pam_authenticate.restype = c_int
pam_acct_mgmt = libpam.pam_acct_mgmt
pam_acct_mgmt.argtypes = [PamHandle, c_int]
pam_acct_mgmt.restype = c_int
def authenticate(username, password, service='login'):
handle = PamHandle()
conv = PamConv(handle_conv, 0)
retval = pam_start(service, username, byref(conv), byref(handle))
if retval != 0:
return False
# アカウントの状態も確認
return pam_authenticate(handle, 0) == 0 and pam_acct_mgmt(handle, 0) == 0
説明:
- 変更前: 認証結果だけを確認し、アカウント管理ポリシーの結果を確認していません。
- 変更後: 認証とアカウント状態の確認が両方とも成功した場合だけ、
Trueを返します。