Sis puella magica!

いろいろ書く予定

Linux-PAM

PAMについて調べたことのまとめ。内容については十分確認してないのでもしかしたら見当違いな事を書いてるかもしれない。

PAMとは

  • Pluggable Authentication Module
  • 認証処理を行うモジュール群とそれを利用するためのAPIからなるユーザー認証システム
  • http://www.linux-pam.org/ のドキュメントでは認証処理を行うモジュールをLinux-PAM Module、APIを利用するアプリケーションをLinux-PAM Applicationと呼んでいる

モジュールの例

Chapter 6. A reference guide for available modules

pam_unix

linuxでログインするとき/etc/passwdや/etc/shadowを見て認証を行う

pam_time

/etc/security/time.confの記述に従って、時間帯によるログインの制限ができる

pam_nologin

root以外のログインを禁止する

pam_permit

常に許可する

pam_mount

ログイン時に自動でマウントする
暗号化したホームディレクトリのマウントなどに使える

pam_ldap

ldapによる認証を行う

アプリケーションの例

  • sudo
  • login

PAMの動作

/etc/pam.d/*に各Applicationがどのようにモジュールを利用するかを記述したファイルが存在する
Linuxの各アプリケーションが共通して利用する「PAM認証」についてhttps://www.freebsd.org/doc/en/articles/pam/pam-essentials.htmlが分かりやすい

% ls /etc/pam.d/
accountsservice                cron                          newusers
chfn                           cups-daemon                   other
chpasswd                       gnome-screensaver             passwd
chsh                           lightdm                       polkit-1
common-account                 lightdm-autologin             ppp
common-auth                    lightdm-greeter               samba
common-password                lightdm-remote-freerdp        su
common-session                 lightdm-remote-uccsconfigure  sudo
common-session-noninteractive  login
% cat /etc/pam.d/login
#
# The PAM configuration file for the Shadow `login' service
#

# Enforce a minimal delay in case of failure (in microseconds).
# (Replaces the `FAIL_DELAY' setting from login.defs)
# Note that other modules may require another minimal delay. (for example,
# to disable any delay, you should add the nodelay option to pam_unix)
auth       optional   pam_faildelay.so  delay=3000000

# Outputs an issue file prior to each login prompt (Replaces the
# ISSUE_FILE option from login.defs). Uncomment for use
# auth       required   pam_issue.so issue=/etc/issue

# Disallows root logins except on tty's listed in /etc/securetty
# (Replaces the `CONSOLE' setting from login.defs)
#
# With the default control of this module:
#   [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die]
# root will not be prompted for a password on insecure lines.
# if an invalid username is entered, a password is prompted (but login
# will eventually be rejected)
#
# You can change it to a "requisite" module if you think root may mis-type
# her login and should not be prompted for a password in that case. But
# this will leave the system as vulnerable to user enumeration attacks.
#
# You can change it to a "required" module if you think it permits to
# guess valid user names of your system (invalid user names are considered
# as possibly being root on insecure lines), but root passwords may be
# communicated over insecure lines.
auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so

# Disallows other than root logins when /etc/nologin exists
# (Replaces the `NOLOGINS_FILE' option from login.defs)
auth       requisite  pam_nologin.so

# SELinux needs to be the first session rule. This ensures that any 
# lingering context has been cleared. Without out this it is possible 
# that a module could execute code in the wrong domain.
# When the module is present, "required" would be sufficient (When SELinux
# is disabled, this returns success.)
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close

# This module parses environment configuration file(s)
# and also allows you to use an extended config
# file /etc/security/pam_env.conf.
# 
# parsing /etc/environment needs "readenv=1"
session       required   pam_env.so readenv=1
# locale variables are also kept into /etc/default/locale in etch
# reading this file *in addition to /etc/environment* does not hurt
session       required   pam_env.so readenv=1 envfile=/etc/default/locale

# Standard Un*x authentication.
@include common-auth

# This allows certain extra groups to be granted to a user
# based on things like time of day, tty, service, and user.
# Please edit /etc/security/group.conf to fit your needs
# (Replaces the `CONSOLE_GROUPS' option in login.defs)
auth       optional   pam_group.so

# Uncomment and edit /etc/security/time.conf if you need to set
# time restrainst on logins.
# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
# as well as /etc/porttime)
# account    requisite  pam_time.so

# Uncomment and edit /etc/security/access.conf if you need to
# set access limits.
# (Replaces /etc/login.access file)
# account  required       pam_access.so

# Sets up user limits according to /etc/security/limits.conf
# (Replaces the use of /etc/limits in old login)
session    required   pam_limits.so

# Prints the last login info upon succesful login
# (Replaces the `LASTLOG_ENAB' option from login.defs)
session    optional   pam_lastlog.so

# Prints the message of the day upon succesful login.
# (Replaces the `MOTD_FILE' option in login.defs)
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session    optional   pam_motd.so  motd=/run/motd.dynamic noupdate
session    optional   pam_motd.so

# Prints the status of the user's mailbox upon succesful login
# (Replaces the `MAIL_CHECK_ENAB' option from login.defs). 
#
# This also defines the MAIL environment variable
# However, userdel also needs MAIL_DIR and MAIL_FILE variables
# in /etc/login.defs to make sure that removing a user 
# also removes the user's mail spool file.
# See comments in /etc/login.defs
session    optional   pam_mail.so standard

# Standard Un*x account and session
@include common-account
@include common-session
@include common-password

# SELinux needs to intervene at login time to ensure that the process
# starts in the proper default security context. Only sessions which are
# intended to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
# When the module is present, "required" would be sufficient (When SELinux
# is disabled, this returns success.)

Programming

  • 認証の情報はpam_handle_t型(へのポインタ)のpamhが持っている
  • Application側もModule側もpam_set_itemやpam_get_itemで必要な情報をsetしたりgetしたりする
  • struct pam_convにApplicationとModuleが直接やりとりするためのcallback関数を設定する
モジュールを書く

The Linux-PAM Module Writers' Guide
コードはlinux-pam.gitのmodules(特にpam_permitは単純)やSample PAM Moduleを参考にすればいいと思う

pam_get_user
PAM_USERか、PAM_USERがNULLならプロンプトを出してユーザー名を取得する
アプリケーションを書く

The Linux-PAM Application Developers' Guide
Sample PAM Applicationやsudoのソースコードのplugins/sudoers/auth/pam.c、loginのソースコードのlogin.cが参考になると思う
sudoやloginのソースコードの取得はUbuntuなら`apt-get source sudo(またはlogin)`とすればいいはず

  • pam_chauthtok
    authentication token(パスワードとか)の変更
  • pam_open_session
    認証に成功したユーザーのセッションの開始時に呼び出す。pam_close_sessionをあとで呼び出すべきである。
  • pam_close_session
    セッション終了時に呼び出す。
  • pam_acct_mgmt
    パスワードの期限切れ、アカウントの期限切れなどを調べてユーザーアカウントが有効かどうかを判定する
    It is typically called after the user has been authenticated.
  • pam_setcred
    It should be called to set the credentials after a user has been authenticated and before a session is opened for the user (with pam_open_session(3)).
  • pam_authenticate
    ユーザーの認証
  • pam_fail_delay
    pam_authenticateが認証に失敗した時にアプリケーションに制御を返すまでの時間を設定する
  • pam_start
    初期化
    第一引数service_nameが/etc/pam.d/に対応する
  • pam_end
  • pam_strerror
    エラーコードを説明する文字列

モジュールで実装する関数とAPIの対応
Application側API Module側
pam_authenticate pam_sm_authenticate
pam_setcred pam_sm_setcred
pam_acct_mgmt pam_sm_acct_mgmt
pam_open_session pam_sm_open_session
pam_close_session pam_sm_close_session
pam_chauthtok pam_sm_chauthtok

呼び出す順序は3.4. Transactionsが詳しい