Linux PAM

PAM(Pluggable Authentication Modules) 由 Sun Microsystems 发明并最初在 Solarise OS 上实现,Linux 于 1997 年实现了 Linux-PAM.

PAM 简化了系统认证管理的过程,使用 PAM 提供了以下好处:

  • 使用中心化的方式简化了用户身份认证过程以及系统管理员的视角
  • 简化了应用在认证相关功能方面的开发,开发者无需重复写认证相关代码,只需要直接使用已有的认证模块即可
  • 认证灵活性
    • 可以根据用户身份或者是特定的时间,或者是对特定资源的使用进行允许/拒绝操作

包含 PAM 的应用中 PAM 使用流程大体如下

  • 一个主体(用户或者进程)请求访问(通过认证)一个应用
  • 此应用读取其 PAM 配置文件,其 PAM 配置文件中配置了认证策略,认证策略中一般包含要进行认证的 PAM 模块的列表,这个列表也称为 Stack
  • Stack 中配置的 PAM 模块被依次调用
  • 每个 PAM 模块会根据其配置返回 成功(Success) 或者 失败(Failure) 状态
  • 最后是否认证成功,由所有的 PAM 模块返回的结果组合得到 成功(Success) 或者 失败(Failure) ,具体组合方式取决于配置文件中的配置。

Linux 中,大多数包含 PAM 的应用的配置文件位于 /etc/pam.d/,通用的 PAM 配置文件格式使用:

context 'control flag' 'PAM module' [module options]

Linux 中,系统安全(如资源限制,用户登陆等)相关的 PAM 配置文件位于 /etc/security/*.conf

PAM Contexts

PAM 模块为不同的认证服务提供了标准的函数,这些 PAM 模块中的标准函数根据其函数类型称为 Contexts,也可以叫做 Module Interfaces 或者 Types,下列出了不同的 PAM Contexts 及其对应的 认证服务(Authentication Service)

Context Service Description
auth 提供认证管理服务(Authentication Management Services),如验证帐号密码
account 帐号验证服务(Account Validation Services),例如只允许特定时间登陆
password 管理帐号密码(Manages Account Passwords),如限制帐号密码长度

PAM Control Flags

PAM 中的 Control Flags 用于决定返回什么样的状态。下表列出了 PAM 配置中的相关的 Control Flags 及其响应

Control Flag Response Handle
required If failed, returns a failure status to the application, after the rest of the contexts have been run in the stack.
For example, a requisite control might cause a login to fail if someone types in an invalid user. But the user might not be told of the failure until after entering a password, hiding the fact that it was the bad username that caused the failure
requisite If failed, returns a failure status to the application immediately without running the rest of the stack(Be careful where you place this control in the stack.)
For example, a requisite control might require key-based authentication and fail immediately when a valid key is not provided . In that case, it could fail before even prompting for a username/password.
sufficient - If failed, the module status is ignored.
- If successful, then a success status is immediately returned to the application without running the rest of the stack.
(Be careful where you place this control in the stack.)
optional This control flag is important only for the final overall return status of success or failure . Think of it as a tiebreaker. When the other modules in the configuration file stack return statuses that are neither clear-cut failure nor success statuses, this optional module’s status is used to determine the final status or break the tie. In cases where the other modules in the stack are returning a clear-cut path of failure or success, this status is ignored.
include Get all the return statuses from this particular PAM configuration file’s stack to include in this stack’s overall return status. It’s as if the entire stack from the named configuration file is now in this configuration file
substack Similar to the include control flag, except for how certain errors and evaluations affect the main stack. This forces the included configuration file stack to act as a substack to the main stack. Thus, certain errors and evaluations affect only the substack and not the main stack.

PAM Modules

Linux 中,PAM Modules 其实是系统共享库(Shared Library Module)文件,RHEL 默认位于 /usr/lib64/security/pam*.so, Ubuntu 位于 /usr/lib/x86_64-linux-gnu/security/pam*.so

# ls /usr/lib/x86_64-linux-gnu/security/
pam_access.so pam_exec.so pam_gdm.so pam_listfile.so pam_nologin.so pam_securetty.so pam_stress.so pam_unix.so
pam_cap.so pam_extrausers.so pam_gnome_keyring.so pam_localuser.so pam_oddjob_mkhomedir.so pam_selinux.so pam_succeed_if.so pam_userdb.so
pam_dcvgraphicalsso.so pam_faildelay.so pam_group.so pam_loginuid.so pam_permit.so pam_sepermit.so pam_systemd.so pam_usertype.so
pam_debug.so pam_faillock.so pam_issue.so pam_mail.so pam_pwhistory.so pam_setquota.so pam_time.so pam_warn.so
pam_deny.so pam_filter.so pam_keyinit.so pam_mkhomedir.so pam_pwquality.so pam_shells.so pam_timestamp.so pam_wheel.so
pam_echo.so pam_fprintd.so pam_lastlog.so pam_motd.so pam_rhosts.so pam_sss_gss.so pam_tty_audit.so pam_xauth.so
pam_env.so pam_ftp.so pam_limits.so pam_namespace.so pam_rootok.so pam_sss.so pam_umask.so

要查看 PAM Module 的帮助文档,可以使用 man 手册,如 man pam_access

使用 PAM 的应用可以大概分为以下 2 类:

  • 普通程序(Application) 。默认使用 PAM 的应用的配置位于 /etc/pam.d,每个使用 PAM Module 的应用程序都应该有其自己的配置文件来定义它如何使用 PAM 模块。如果没有,这将是一个漏洞,为了防止这种情况出现,系统内置了一个 other 的配置(/etc/pam.d/other),所有使用了 PAM 但是没有指定其配置文件的应用都将使用此配置。 other 配置默认拒绝(Implicit Deny)所有的请求

    # ls /etc/pam.d/
    chfn common-auth cron gdm-autologin gdm-smartcard login polkit-1 samba sudo
    chpasswd common-password cups gdm-fingerprint gdm-smartcard-pkcs11-exclusive newusers ppp sshd sudo-i
    chsh common-session dcv gdm-launch-environment gdm-smartcard-sssd-exclusive other runuser sssd-shadowutils su-l
    common-account common-session-noninteractive dcv-graphical-sso gdm-password gdm-smartcard-sssd-or-password passwd runuser-l su vmtoolsd

  • 系统安全相关程序 。系统安全相关的 PAM 配置默认位于 /etc/security

    # ls /etc/security/
    access.conf faillock.conf limits.conf namespace.conf namespace.init pam_env.conf sepermit.conf
    capability.conf group.conf limits.d namespace.d opasswd pwquality.conf time.conf

Linux 中的常用的 PAM 模块

Linux 中的 PAM 模块提供了非常丰富的功能,以下列出经常使用的功能

pam_limits 限制系统资源的使用

Fork Bomb : Fork 炸弹属于一种攻击或者是对资源的错误使用,一个进程无限制的循环创建子进程,直到系统资源耗尽

pam_limits 模块主要用来 限制系统资源的使用 。其 PAM 配置文件为 /etc/security/limits.conf 。默认情况下,这个文件里面没有任何对资源的使用限制。

要自定义对资源的限制配置时,建议使用 /etc/security/limits.d/*.conf 下的文件,如此无需修改 /etc/security/limits.conf

/etc/security/limits.conf
# /etc/security/limits.conf
#
#Each line describes a limit for a user in the form:
#
#<domain> <type> <item> <value>
#
#Where:
#<domain> can be:
# - a user name
# - a group name, with @group syntax
# - the wildcard *, for default entry
# - the wildcard %, can be also used with %group syntax,
# for maxlogin limit
# - NOTE: group and wildcard limits are not applied to root.
# To apply a limit to the root user, <domain> must be
# the literal username root.
#
#<type> can have the two values:
# - "soft" for enforcing the soft limits
# - "hard" for enforcing hard limits
#
#<item> can be one of the following:
# - core - limits the core file size (KB)
# - data - max data size (KB)
# - fsize - maximum filesize (KB)
# - memlock - max locked-in-memory address space (KB)
# - nofile - max number of open file descriptors
# - rss - max resident set size (KB)
# - stack - max stack size (KB)
# - cpu - max CPU time (MIN)
# - nproc - max number of processes
# - as - address space limit (KB)
# - maxlogins - max number of logins for this user
# - maxsyslogins - max number of logins on the system
# - priority - the priority to run user process with
# - locks - max number of file locks the user can hold
# - sigpending - max number of pending signals
# - msgqueue - max memory used by POSIX message queues (bytes)
# - nice - max nice priority allowed to raise to values: [-20, 19]
# - rtprio - max realtime priority
# - chroot - change root to directory (Debian-specific)
#
#<domain> <type> <item> <value>
#

#* soft core 0
#root hard core 100000
#* hard rss 10000
#@student hard nproc 20
#@faculty soft nproc 20
#@faculty hard nproc 50
#ftp hard nproc 0
#ftp - chroot /ftp
#@student - maxlogins 4

# End of file

/etc/security/limits.conf 配置中相关参数说明,详细帮助信息可参考 man 5 limits.conf

  • domain : 资源限制针对的目标,可以是用户(如 root)或组(如 @student),* 表示对所有用户和组生效

  • typehard 表示限制不能被超出; soft 表示限制可以短暂的超出

  • item : 要限制的资源

    Item Description Examples
    nproc 限制用户或组能够启动/创建的最大进程数(Tasks)
    可以防止 Fork Bomb
    maxlogins 设置一个用户同时登录系统的最大数量(session),确保用户无法通过多次登录来绕过资源限制。
    用户的资源限制(例如进程数量、文件打开数量等)通常只在该登录会话期间有效。一旦用户注销并重新登录,这些限制可能会被重置。因此,恶意用户可以通过多次登录来绕过这些限制,或者在每次登录会话中制造大量进程,进而创建一种被称为 fork bomb 的攻击。
    * hard maxlogins 3
    当用户同时登陆的数量(Sessions)超过 3 时,会无法登陆,提示 Too many logins for
    nofile 最大可以打开的 file descriptors

通过以下方式检查使用了 pam_limits 模块的应用,pam_limits 模块使用了配置 /etc/security/limits.conf

# grep 'pam_limits' /etc/pam.d/*
/etc/pam.d/cron:session required pam_limits.so
/etc/pam.d/gdm-autologin:session required pam_limits.so
/etc/pam.d/gdm-fingerprint:session required pam_limits.so
/etc/pam.d/gdm-launch-environment:session required pam_limits.so
/etc/pam.d/gdm-password:session required pam_limits.so
/etc/pam.d/gdm-smartcard:session required pam_limits.so
/etc/pam.d/gdm-smartcard-pkcs11-exclusive:session required pam_limits.so
/etc/pam.d/gdm-smartcard-sssd-exclusive:session required pam_limits.so
/etc/pam.d/gdm-smartcard-sssd-or-password:session required pam_limits.so
/etc/pam.d/login:session required pam_limits.so
/etc/pam.d/runuser:session required pam_limits.so
/etc/pam.d/sshd:session required pam_limits.so
/etc/pam.d/su:session required pam_limits.so
/etc/pam.d/sudo:session required pam_limits.so
/etc/pam.d/sudo-i:session required pam_limits.so

pam_time 限制特定的时间使用特定的资源

通过 pam_time PAM 模块可以实现类似功能:

  • 在每天的固定时间才能访问指定的应用
  • 在每周的固定时间才能登陆系统

负责处理类似时间限制的 PAM 配置文件是 /etc/security/time.conf,使用此配置的 PAM 模块是 pam_time

/etc/security/time.conf
# this is an example configuration file for the pam_time module. Its syntax
# was initially based heavily on that of the shadow package (shadow-960129).
#
# the syntax of the lines is as follows:
#
# services;ttys;users;times
#
# white space is ignored and lines maybe extended with '\\n' (escaped
# newlines). As should be clear from reading these comments,
# text following a '#' is ignored to the end of the line.
#
# the combination of individual users/terminals etc is a logic list
# namely individual tokens that are optionally prefixed with '!' (logical
# not) and separated with '&' (logical and) and '|' (logical or).
#
# services
# is a logic list of PAM service names that the rule applies to.
#
# ttys
# is a logic list of terminal names that this rule applies to.
#
# users
# is a logic list of users or a netgroup of users to whom this
# rule applies.
#
# NB. For these items the simple wildcard '*' may be used only once.
#
# times
# the format here is a logic list of day/time-range
# entries the days are specified by a sequence of two character
# entries, MoTuSa for example is Monday Tuesday and Saturday. Note
# that repeated days are unset MoMo = no day, and MoWk = all weekdays
# bar Monday. The two character combinations accepted are
#
# Mo Tu We Th Fr Sa Su Wk Wd Al
#
# the last two being week-end days and all 7 days of the week
# respectively. As a final example, AlFr means all days except Friday.
#
# each day/time-range can be prefixed with a '!' to indicate "anything
# but"
#
# The time-range part is two 24-hour times HHMM separated by a hyphen
# indicating the start and finish time (if the finish time is smaller
# than the start time it is deemed to apply on the following day).
#
# for a rule to be active, ALL of service+ttys+users must be satisfied
# by the applying process.
#

#
# Here is a simple example: running blank on tty* (any ttyXXX device),
# the users 'you' and 'me' are denied service all of the time
#

#blank;tty* & !ttyp*;you|me;!Al0000-2400

# Another silly example, user 'root' is denied xsh access
# from pseudo terminals at the weekend and on mondays.

#xsh;ttyp*;root;!WdMo0000-2400

#
# End of example file.
#

/etc/security/time.conf 配置中相关参数说明,详细帮助信息请参考 man 5 time.conf

  • services : PAM 的服务名称逻辑列表,被限制的对象,如 Login
  • tty : 关联的终端名称逻辑列表,如 ttys-* 表示所有终端
  • users : 关联的用户名称逻辑列表,如 !root 表示除 root 外的所有用户
  • times : 时间。具体格式请参考 man 5 time.conf

A logic list namely means individual tokens that are optionally prefixed with ‘!’ (logical not) and separated with ‘&’ (logical and) and ‘|’ (logical or).

使用了 pam_time 模块的应用包括:

# grep pam_time /etc/pam.d/*
/etc/pam.d/login:# account requisite pam_time.so
/etc/pam.d/su:# account requisite pam_time.so

pam_wheel 限制 su 命令的使用

默认情况下,系统上的所有用户都可以使用 su 命令切换到其他用户环境。su 是一个 PAM-ware 的应用,其 PAM 配置文件为 /etc/pam.d/su

/etc/pam.d/su
#
# The PAM configuration file for the Shadow `su' service
#

# This allows root to su without passwords (normal operation)
auth sufficient pam_rootok.so

# Uncomment this to force users to be a member of group wheel
# before they can use `su'. You can also add "group=foo"
# to the end of this line if you want to use a group other
# than the default "wheel" (but this may have side effect of
# denying "root" user, unless she's a member of "foo" or explicitly
# permitted earlier by e.g. "sufficient pam_rootok.so").
# (Replaces the `SU_WHEEL_ONLY' option from login.defs)
# auth required pam_wheel.so

# Uncomment this if you want wheel members to be able to
# su without a password.
# auth sufficient pam_wheel.so trust

# Uncomment this if you want members of a specific group to not
# be allowed to use su at all.
# auth required pam_wheel.so deny group=nosu

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

# 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

# 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
#
# "nopen" stands to avoid reporting new mail when su'ing to another user
session optional pam_mail.so nopen

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

# The standard Unix authentication modules, used with
# NIS (man nsswitch) as well as normal /etc/passwd and
# /etc/shadow entries.
@include common-auth
@include common-account
@include common-session

要更改 su 命令的行为,可以参考以下配置:

  • 限制只有在 wheel 组中的用户才能使用 su,可以启用

    /etc/pam.d/su
    auth       required   pam_wheel.so

    启用此配置,并确保 wheel 组中无任何用户,可以限制任何普通用户使用 su 命令

  • 限制只有在 foo 组中的用户才能使用 su,可以配置为

    /etc/pam.d/su
    auth       required   pam_wheel.so group=foo
  • 限制在 wheel 组中的用户使用 su 时无需输入密码

    /etc/pam.d/su
    # Uncomment this if you want wheel members to be able to
    # su without a password.
    auth sufficient pam_wheel.so trust
  • 指定组中的用户限制其使用 su 命令

    /etc/pam.d/su
    # Uncomment this if you want members of a specific group to not
    # be allowed to use su at all.
    auth required pam_wheel.so deny group=nosu