PAM详解

 

最近接触PAM比较多,而中文版的文档过于老久,所以专门下载了英文版的指南,边学习边翻译。
由于水平有限,如有错误请及时指正。
1 简介
Linux-PAM(Pluggable Authentication Modules for Linux.基于Linux的插入式验证模块)是一组共享库,使用这些模块,系统管理者可以自由选择应用程序使用的验证机制。也就是说,勿需重新编译应用程序就可以切换应用程序使用的验证机制。甚至,不必触动应用程序就可以完全升级系统使用的验证机制。

  在历史上,需要对用户进行验证的应用程序,必须同某种验证机制编译到一起。例如,传统的UN*X系统是使用密码对用户进行校验的。用户输入的密码经过crypt加密后,然后和/etc /passwd文件中的密文进行比较。在这种系统中,如果优先级授予的形式不是基于这种单一方式,就需要通过用户识别符和用户组识别符对优先权进行验证。服务和应用程序可以使用基于用户和用户组识别的验证方式。通常,用户组的成员关系已经基于/etc/group指定了。

  Linux- PAM工程的目的就是分离应用软件和验证机制的开发。通过验证函数库可以实现上述目的,一个应用程序可以使用这些函数库去进行用户的认证。PAM库由本地的系统配置文件 /etc/pam.conf或者/etc/pam.d/目录下的一些配置文件来设置。而模块以动态可加载目标文件(使用dloptn(3)函数打开)的形式保存在 /lib/security和 /lib64/security

2 关于本文的一些说明

  在开始阅读本文时,你应该清楚本文假定特定的文件是在特定的目录中。我们遵照RFC-86的约定。如果你使用的linux发行版或其他支持PAM的系统以不同的方式发布这些文件的话,那么你应该谨慎使用本文提供的例子。

  例如,本文假设PAM可加载目标文件(模块)是在/lib/security/和/lib64/security/目录下,这是符合 HFS(Filesystem Hierarchy Standard)标准的。在 Solaris中,他们有属于 Solaris自己的PAM版本,在其他的UN*X中,你可能会在/usr/lib/security中看到这些文件。因此,使用本文的例子时应该注意进行必要的转换。

3 综述

    我们从一个例子开始讨论。首先找一个能够为用户提供服务的应用程序,login就是一个这样的程序。login要做两件事,首先确认发出请求的这个用户是不是该用户本身,然后为用户提供所需服务:在这里提供的是以一个以用户身份的运行的shell(bash, tcsh, zsh, etc.)
 
    通常,login所做的前面的步骤只是提示用户输入密码并与验证是否与系统本地中存储的密码一致,然后对用户身份的验证,就是Linux-PAM的工作了。

    从一个程序开发人员的角度看(在这个例子中,就是login程序的开发人员),Linux-PAM的工作就是校验--验证用户的身份。

   Linux-PAM具有很大的灵活性,系统管理者可以通过它自由选择使用的验证方式。你也可以自由的为部分或所有PAM-aware的应用程序选择所使用的验证方式。Linux-PAM能够提供的验证方式多种多样,从绝对信任(pam_permit)到视网膜扫描、音频分析以及一次性口令,不一而足。

    为了描述Linux-PAM的灵活性,我们可以假想一种情况:一个系统管理者(父母)希望提高用户(他们的子女)的数学能力。他/她就可以通过一个孩子们非常喜欢的游戏“Shoot 'em up game”达成上述目的,当然前提是这个游戏能够使用PAM提供的验证机制。验证可以设置:每次孩子们要玩游戏时,都需要回答出一组小于12的随机数的乘积。这样孩子们每次玩游戏之前都可以练习乘法运算。随着他们的成长,可以增加数字的大小。

   Linux-PAM处理四种类型的任务:验证管理(auth)、帐户管理(account)、会话管理(session)和口令管理 (password)。应用程序使用的管理方式通过相关的Linux-PAM配置文件设置。管理功能是有配置文件指定的模块完成的。配置文件的语法将会在下面讨论。

   下图描述了Linux-PAM组织架构:
+----------------+
| application: X |
+----------------+       / +----------+       +================+
| authentication-[---->--\--] Linux-    |--<--| PAM config file|
|       +        [----<--/--]    PAM    |     |================|
|[conversation()][--+    \ |            |     | X auth .. a.so |
+----------------+ |     / +-n--n-----+       | X auth .. b.so |
|                | |         __| |            |            _____/
| service user | A         |      |           |____,-----'
|                | |       V      A
+----------------+ +------|-----|---------+ -----+------+
                       +---u-----u----+     |      |       |
                       |   auth....   |--[ a ]--[ b ]--[ c ]
                       +--------------+
                       |   acct....   |--[ b ]--[ d ]
                       +--------------+
                       |   password   |--[ b ]--[ c ]
                       +--------------+
                       |   session    |--[ e ]--[ c ]
                       +--------------+


  上图中,左边的应用程序X,它通过一些接口调用Linux-PAM库,而自己并不知道使用的验证方法。中间的Linux-PAM库参照图右边配置文件中的内容,加载应用程序X所适用的模块。这些模块进入某个管理组,并按照配置文件里的配置层叠在一起。在这些模块被Linux-PAM调用时,会对应用程序执行不同的验证工作。应用程序和用户之间的信息交换可以通过 conversation函数实现。
 
     如果一个程序想使用PAM,在程序中必须有支持PAM功能的代码。如果你有程序的源代码,你可以将合适的PAM功能代码添加进去,如果只有二进制文件,而二进制文件又不支持PAM,那就无能为力了。

4 Linux-PAM配置文件

    当一个使用了PAM的应用程序启动时,它会启动于PAM-API的连接,然后去读取配置文件/etc/pam.conf,另外,配置文件也可能存在于/etc/pam.d中。如果存在/etc/pam.d,那么/etc/pam.conf将会被忽略。
  
    这些配置文件列出了某个或某些系统服务所要求PAM验证规则,以及PAM规则失败事件发生时PAM-API的行为。

4.1 配置文件语法

     下面将介绍配置文件的语法。配置文件是一个规则列表,每条规则都独占一行,但也可能由于某个规则长度过长导致溢出,可以使用使用转意服符 `\'转写到下一行。 在同一行中,写在“#”后面的都是注释。

     每一条规则的内容都是用空格分开的,前三个参数不区分大小写,如下:
    service type control module-path module-arguments
    (服务)  (类型)(控制)  (模块路径)      (模块参数)

     在/etc/pam.d目录下的配置文件,其规则内容都是不包含service部分的,即不包含服务名称,而/etc/pam.d目录下文件的名字就是服务名称。文件名必须是小写的。

    PAM的一个重要特点是,许多个PAM规则叠加在一块共同起作用的来完成一个指定的验证工作。

    service(服务) 通常都是类似于login或su这样的常见应用程序。为定义默认的规则,预留了service-name。
    The service is typically the familiar name of the corresponding application: login and su are good examples.
    The service-name, other, is reserved for giving default rules. On

ly lines that mention the current service
    (or in the absence of such, the other entries) will be associated with the given service-application.

    type(类型)是一个管理相近规则的管理组,他的作用就是指定后面的模块与哪一个管理组相关联。包括下面四总类型:
   
        acount   用于非验证的帐户管理,它主要用来限制/允许用户对某个服务的访问时间,当前可用的系统资源(用户的最大数量),或者限制用户的位置(例如:root用户只能从控制台登录)

        auth     为用户提供了两个方面的验证,第一, 让应用程序提示用户输入密码或者其它的标记,确认用户的合法性;第二,通过它的凭证许可权限,设定组成员关系(不同于上面讨论的/etc/groups文件)或者其它优先权。
   
        passwd   用来升级用户验证标记

        session  这类模块的主要用途是处理为用户提供服务之前/后需要做的一些事情,包括:记录打开/关闭交换数据的信息,挂载目录等。

     如果在类型之前加了"-",则当模块丢失导致不能正常加载时,相关的日志将不会记录到系统日志中,对于那些不一定每次都需要安装的模块来说,这一特性是有用的。
 
    control(控制标志) 控制标志用来设置验证成功或者失败后PAM-API需要作出的反应,控制标志有两种语法,一种是简单的,只需要一个单独的关键字即可,另一种复杂的方式是在方括号里面写“value=action”

     简单语法如下:

        required   表示即使某个模块对用户的验证失败,也要等所有的模块都执行完毕之后,PAM才返回错误信息。这样做是为了不让用户知道被哪个模块拒绝。如果对用户验证成功,所有的模块都会返回成功信息。

        requisite  如果特定的模块对用户的验证失败,PAM马上返回一个错误信息,把控制权交回应用程序,不再执行其它模块进行验证。返回值与第一个fail的模块有关。

        sufficient 表示如果一个用户通过这个模块的验证,PAM结构就立刻返回验证成功信息(即使前面有模块fail了,也会把fail结果忽略掉),把控制权交回应用程序。后面的层叠模块即使使用requisite或者required控制标志,也不再执行。如果验证失败,sufficient的作用和optional 相同。

         optional   表示即使本行指定的模块验证失败,也允许用户享受应用程序提供的服务。使用这个标志,PAM框架会忽略这这个模块产生的验证错误,继续顺序执行下一个层叠模块。

        include    include all lines of given type from the configuration file specified as an argument to
                       this control.

        substack   include all lines of given type from the configuration file specified as an argument to
                   this control. This differs from include in that evaluation of the done and die actions in
                   a substack does not cause skipping the rest of the complete module stack, but only of
                   the substack. Jumps in a substack also can not make evaluation jump out of it, and the
                   whole substack is counted as one module when the jump is done in a parent stack. The
                   reset action will reset the state of a module stack to the state it was in as of beginning
                   of the substack evaluation.
   
    还有一种比较复杂的语法来设置控制标志,它由一组value=action形式的标记组成,标记之间以空格分开:

  [value1=action1 value2=action2 ...]

  valueN可以是Linux-PAM函数库中任何一个函数的返回值,返回值包括:success, open_err, symbol_err, service_err, system_err,buf_err, perm_denied, auth_err, cred_insufficient, authinfo_unavail, user_unknown,maxtries,new_authtok_reqd,acct_expired, session_err, cred_unavail, cred_expired, cred_err, no_module_data,conv_err, authtok_err, authtok_recover_err, authtok_lock_busy, authtok_disable_aging, try_again,ignore, abort,authtok_expired,module_unknown, bad_item, conv_again, incomplete, and default.最后一个(default)能够用来设置上面的返回值无法表达的行为。

   actionN可以是一个无符号整数(非负整数),或者是下面的记号之一:ignore、ok、done、bad、die和reset。如果是非负整数 n,就表示需要忽略后面堆叠的n个同样类型的模块。通过这种方式,系统管理者可以更加灵活地设置层叠模块,模块的层叠路径由单个模块的反应决定。

       ignore  如果使用层叠模块,这个模块的返回状态将不会对应用程序获取的返回值产生影响。

        bad     它表示这个返回码应该被看作是模块验证失败。如果这个模块是层叠模块的第一个验证失败的模块,那么它的状态值就是整个层叠模块的状态值。
 
        die     对层叠模块最终结果的影响相当于bad,并且立刻反回到应用程序。

        ok      告诉PAM这个模块的返回值直接作为整个层叠模块的返回值。也就是说,如果这个模块前面的模块返回状态是PAM_SUCCESS,那这个返回值就会覆盖前面的返回状态。注意:如果前面的模块的返回状态表示模块验证失败,那么这个“ok”标记的返回值将不会覆盖前面的返回值。

        done    对层叠模块最终结果的影响相当于ok,并且立刻反回到应用程序。

        reset   清除所有层叠模块的返回状态,从下一个层叠模块重新开始。

    对于简单语法的四种控制标志: required; requisite; sufficient; and optional,都有相同效果的复杂语法与其对应。

   required   [success=ok new_authtok_reqd=ok ignore=ignore default=bad]
   requisite  [success=ok new_authtok_reqd=ok ignore=ignore default=die]
   sufficient [success=done new_authtok_reqd=done default=ignore]
   optional   [success=ok new_authtok_reqd=ok default=ignore]

   module-path(模块路径) 如果以"/"开头,则表示模块的全路径,否则就表示相对于 /lib/security/或/lib64/security/的相对路径。

   module-arguments(模块参数) 一组用空格分开的变量,用来改变当前PAM模块的行为。对于当前模块无效的参数将会被忽略,并把错误信息记录到syslog中。注意,如果想在一个参数中使用空格,就要在其外面加上中括号,例子如下:
  
   squid auth required pam_mysql.so user=passwd_query passwd=mada \
   db=eminence [query=select user_name from internet_service \
   where user_name='%u' and password=PASSWORD('%p') and \
   service='web_proxy']

    按照规则,你可以在字符串中使用字符“[”,但是如果要使用字符"]",就必须加上转移字符"\]"

    配置文件中,任何一行的语法错误都会引发认证过程失败,失败信息会记录到syslog中。

4.2 基于目录的配置

    比单一配置文件更灵活的配置方法是使用/etc/pam.d目录。这个目录中存放的都是以service-name(服务名称)命名的文件:每个服务都有私有配置文件。
 
   /etc/pam.d目录下的配置文件语法与/etc/pam.conf基本相同,由一下几部分组成:
 
   type control module-path module-arguments

    唯一不同的是没有了service-name,service-name直接作为了文件的名字。例如 /etc/pam.d/login就是login服务的配置文件。

4.3 配置文件内容举例
   
    本节我们将会举一些Linux-PAM配置文件的例子。作为第一次配置你的系统,你可以按照下面的例子来配置。

    一个合理的OTHER入口对于加强系统安全非常重要。下面是一个非常偏执的例子(但是以它作为开始并不坏)。

   #
   # default; deny access
   #
   other   auth     required  pam_deny.so
   other   account  required  pam_deny.so
   other   password required  pam_deny.so
   other   session  required  pam_deny.so

    虽然这是一个最安全的策略(默认拒绝访问),但是对于一个PAM没有配置好的系统来说,这中配置并不合理。例如:如果这个文件的其它部分编写不好,那么很容易把所有的用户挡在门外。

   pam_deny.so模块并不是非常完善,pam_deny模块在运行时不记录任何信息,除非用户在无法执行某个服务程序时能够与系统管理人员联系,否则系统管理者很长时间不会知道系统配置错误。

    在上面例子中,以模块层叠的方式加入以下几行,系统管理者就可以获得有关的警告信息了:

   #
   # default; wake up! This application is not configured
   #
   other auth     required pam_warn.so
   other password required pam_warn.so

    在使用/etc/pam.d目录的系统中,以other命名的配置文件内容应该是这样的:

   #
   # default configuration: /etc/pam.d/other
   #
   auth     required       pam_warn.so
   auth     required       pam_deny.so
   account  required       pam_deny.so
   password required       pam_warn.so
   password required       pam_deny.so
   session  required       pam_deny.so

    对于不熟悉Linux-PAM的系统管理者,下列几行可以作为最基本的系统配置:

   #
   # default; standard UN*X access
   #
   auth     required       pam_unix.so
   account required        pam_unix.so
   password required       pam_unix.so
   session required        pam_unix.so

5 安全问题

5.1 如果出现错误

    如果发生错误,Linux-PAM可能会改变系统的安全性。这取决于你自己的选择,你可以选择不安全(开放系统)和绝对安全(拒绝任何访问)。通常,Linux-PAM在发生错误时,倾向于后者。任何的配置错误都可能导致系统整个或者部分无法访问。

    配置Linux-PAM时,可能遇到最大的问题可能就是Linux-PAM的配置文件(/etc/pam.d/*或者/etc/pam.conf)被删除了。如果发生这种事情,你的系统就会被锁住。

    有办法可以进行恢复,最好的方法就是用一个备份的镜像来恢复系统,或者登录进单用户模式然后进行正确的配置。

5.2 不要使用脆弱的other文件 

   other文件的脆弱并不是一件好事,因为支持PAM的应用程序如果没有特定的配置文件在/etc/pam.d下的话,则将会用other的配置,这样的话系统很可能受到攻击的威胁。

    这是一个示例配置,pam_deny模块将拒绝所有的访问,而pam_warn模块将向auth.notice日志设备发送一条警告信息:
   #
   # The PAM configuration file for the `other' service
   #
   auth      required   pam_deny.so
   auth      required   pam_warn.so
   account   required   pam_deny.so
   account   required   pam_warn.so
   password  required   pam_deny.so
   password  required   pam_warn.so
   session   required   pam_deny.so
   session   required   pam_warn.so

参考:
The Linux-PAM System Administrators' Guide(1.1.0)
Linux-PAM系统管理指南 http://doc.linuxpk.com/5214.html

你可能感兴趣的:(系统)