Linux-PAM (Linux 系统的可插入式认证模块) 是一套共享函数库,它表示一种性能健硕而且灵活方便的用户级认证方式,允许系统管理员来决定应用程序如何识别用户,即不需要 (重写和) 重新编译一个 (支持 PAM 的) 应用,就可以切换它所用的认证机制。目前,Linux-PAM 已经成为 Linux、BSD 和其它一些 Unix 操作系统的首选认证方式,特别是在 Linux 上,几乎所有的 daemon 和一些与授权有关的命令都通过 PAM 来进行验证。
Linux-PAM 主要是由一组共享库文件(share libraries, 也就是.so 文件)和一些配置文件组成。当用户请求服务时,具有 PAM 认证功能的应用程序将与这些.so 文件进行交互,以此判断是否可以授权给发起请求的用户来使用服务,比如 su、vsftp、httpd 等。如果认证成功,那么用户便可以使用该服务或命令;如果认证失败,用户将不能使用该服务,同时,PAM 将向指定的 log 文件写入警告信息。PAM 不依赖于任何应用或服务,用户完全可以升级这些应用或服务而不必管 PAM 的共享库的更新或升级,反之亦然。所以它非常的灵活。
PAM 的认证过程是通过对一些服务或应用的配置文件来控制的。在 Linux 上,PAM 配置信息通常位于目录 /etc/pam.d,但是 UNIX 系统把所有的配置都放在/etc/pam.conf 文件里。对于使用 PAM 的各项服务,/etc/pam.d 目录中都有一个对应的配置文件,PAM 的配置文件是一系列的单行配置命令构成,每行配置都说明一种在操作系统上使用的特殊 PAM 模块。
其一般格式为:
[service] module-type control-flag module-path [arguments]
PAM 配置文件中的字段包括:
service: 指定服务/应用程序的名称,如 telnet、login、ftp 等(默认值为 OTHER)。
module-type: 为 service 字段中的服务/应用程序指定模块类型,模块类型有四种类型(auth/account/session/password)。
control-flag: 指定了"配置段"里的模块应该怎么相互作用,可以理解为对 PAM 认证的流程控制,它可以获取诸如 requisite、required、sufficient 和 optional 之类的值。
module-path: 指定实现模块的库对象的路径名称。最好使用绝对路径,缺省路径一般是/lib/security 或/lib64/security。
arguments:指定可以传递给服务模块的选项或参数(可选字段)。
PAM 框架将按照配置文件中列出的条目顺序调用相应的模块,这取决于每个条目允许的 control_flag 的值。control_flag 指定了"配置段"里的模块应该怎么相互作用,生成该配置段的最终结果。control_flag 值包括:
required:表示这一模块的认证是必须成功的,如果认证失败,认证过程不会即刻终止,PAM 将继续下一个同类型的模块认证。
requisite:与 required 类似,只是如果认证失败,认证过程将立即终止。
sufficient:表示如果认证成功,那么对这一类的模块认证是充足的,其它的模块将不会再检验。
optional:表示这一模块认证是可选的,也不会对认证成功或失败产生影响。
include:类似于 DNS 的 include。表示将包括其他的一些认证,这样可以建立一个分离式的配置文件管理机制。
/etc/pam.d/login #%PAM-1.0 auth requisite pam_nologin.so auth [user_unknown=ignore success=ok ignore=ignore auth_err=die default=bad]pam_securetty.so auth include common-auth account include common-account password include common-password session required pam_loginuid.so session include common-session session required pam_lastlog.so nowtmp session optional pam_mail.so standard
PAM 配置文件来源于 SUSE Linux Enterprise Server11 操作系统。对于 PAM 的结构有了基本的了解,我们来看看 PAM 是如果控制 login 的,从上至下对于 login 的 PAM 配置文件的流程控制为:
login 的第一行 pam_nologin 模块检查有没有/etc/nologin 文件,如果有这个文件,除非是 root 用户,否则该模块就立即中止登陆。
继续第二项 auth 认证,第二行以方括号括起来的 key/value 值的组合用来表示 control_flag 的值,pam_securetty.so 模块确保 root 用户只能从文件/etc/securetty 里列出的那些终端登陆到系统里,限制 root 用户在特殊设备上登陆。
继续第三项 auth 认证,具体的验证规则包含在 common-auth 中。
继续第四项 account 认证,具体的验证规则包含在 common-account 中
继续第五项 password 认证,具体的验证规则在 common-password 中。
继续第六项 session 的验证。注意:pam_loginuid.so 模块用来设置 loginuid 过程属性,其他的 session 验证过程,请参照 control-flag 的说明,不再一一赘述。
OpenLDAP 是轻型目录访问协议(Lightweight Directory Access Protocol,LDAP)的自由和开源的实现,是最常用的目录服务之一。在 Linux 的发型版本中提供的 OpenLDAP 软件按照客户机/服务器模式实现了轻量级目录访问协议(LDAP)。
LDAP 目录以树状的层次结构来存储数据(这很类同于 DNS),最顶层即根部称作"基准 DN",形如"dc=mydomain, dc=org"或者"o= mydomain.org",在根目录的下面有很多的文件和目录,为了把这些大量的数据从逻辑上分开,LDAP 像其它的目录服务协议一样使用 OU (Organization Unit),可以用来表示公司内部机构,如部门等,也可以用来表示设备、人员等。同时 OU 还可以有子 OU,用来表示更为细致的分类。
本文使用 OpenLDAP 2.4.30 来构建 LDAP 的服务器和客户机。操作系统使用 SUSE Linux Enterprise Server11。用户可以从 OpenLDAP 下载页http://www.openldap.org/software/download/或者ftp://ftp.openldap.org/pub/OpenLDAP/下载 OpenLDAP 软件到/usr/local,解压 OpenLDAP,并进入 OpenLDAP 的最外层目录,编译并安装 LDAP。
#tarzxvfopenldap-stable-20120311.tgz #cd /usr/local/openldap-2.4.30 #./configure withwrappers Please "make depend" to build dependencies #make depend #make #make test #make install
OpenLDAP 依赖于一些第三方软件包,因此安装配置 OpenLDAP 之前需要首先安装第三方软件包。执行"make install"命令要求用户有超级用户权限。安装成功后,可以配置 OpenLDAP 的服务器端和客户端。
OpenLDAP 安装成功后,用户会在/usr/local/etc/openldap 找到配置文件 slapd.conf。/usr/local/etc/openldap/slapd.conf 是 OpenLDAP 服务器最重要的配置文件,配置权限、口令、数据库类型和数据库位置等等。slapd.conf 文件中包括一系列全局配置选项,它们作为一个整体应用到 slapd 上面,后面是包含数据库特有信息的数据库后端定义。空行和以 "#" 字符开头的注释行都会被忽略。
# # See slapd.conf(5) for details on configuration options. # This file should NOT be world readable. # include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/rfc2307bis.schema include /etc/openldap/schema/yast.schema # Define global ACLs to disable default read access. # Do not enable referrals until AFTER you have a working directory # service AND an understanding of referrals. #referral ldap://root.openldap.org pidfile /var/run/slapd/slapd.pid argsfile /var/run/slapd/slapd.args # Load dynamic backend modules: # modulepath /usr/lib/openldap/modules # moduleload back_bdb.la # moduleload back_hdb.la # moduleload back_ldap.la # Sample security restrictions # Require integrity protection (prevent hijacking) # Require 112-bit (3DES or better) encryption for updates # Require 63-bit encryption for simple bind # security ssf=1 update_ssf=112 simple_bind=64 # Sample access control policy: # Root DSE: allow anyone to read it # Subschema (sub)entry DSE: allow anyone to read it # Other DSEs: # Allow self write access to user password # Allow anonymous users to authenticate # Allow read access to everything else # Directives needed to implement policy: access to dn.base="" by * read access to dn.base="cn=Subschema" by * read access to attrs=userPassword,userPKCS12 by self write by * auth access to attrs=shadowLastChange by self write by * read access to * by * read ####################################################################### # BDB database definitions ####################################################################### database bdb suffix "dc=my-domain,dc=com" rootdn "cn=Manager,dc=my-domain,dc=com" # Cleartext passwords, especially for the rootdn, should # be avoid. See slappasswd(8) and slapd.conf(5) for details. # Use of strong authentication encouraged. rootpw secret # The database directory MUST exist prior to running slapd AND # should only be accessible by the slapd and slap tools. # Mode 700 recommended. directory /var/lib/ldap # Indices to maintain index objectClass eq
下面解释一下配置文件中的设置:
database bdb
定义使用的后端数据存储方式,数据库格式默认采用 Berkeley DB。其后可以跟的值有 bdb、ldbm、passwd 和 shell。bdb 指使用 Berkley DB 4 数据库。
suffix "dc=my-domain,dc=com"
suffix 是"LDAP 基准名",它是 LDAP 名字空间在这里的根。设置想要创建的子树的根的 DN(distinguished name),将 my-domain 替换成用户实际使用的 domain。
rootdn "cn=Manager,dc=my-domain,dc=com"
设置管理 LDAP 目录的超级用户的 DN。这个用户名不要出现在"/etc/passwd"文件里。
rootpw secret
设置这个数据库的超级用户的口令验证方式。也就是上面"rootdn"设置的用户的口令。千万不要用明文进行口令验证,一定要用加密的口令,可以使用的加密方式有:CRYPT、MD5、SMD5、SHA 和 SSHA。
directory var/lib/ldap
设置 LDAP 数据库和索引文件所在的目录。在安装阶段指定 LDAP 的后台数据库。
access to dn.base=""
by * read
access to dn.base="cn=Subschema"
by * read
…...
用来定义访问控制列表。
attrs=userPassword #指定"密码"属性
by self write #用户自己可更改
by * auth #所有访问者需要通过认证
到现在为止,服务器基本就配置完成,在启动 slapd 之前可以使用 slaptest 测试一下,slaptest 在/usr/sbin 目录下。出现 config file testing succeeed 就表示配置没有问题了。
#/usr/sbin/slaptest bdb_monitor_db_open: monitoring disabled; configure monitor database to enable config file testing succeeded
#/usr/local/openldap/libexec/slapd [email protected] ldomain:/usr/local/src/openldap-2.4.30/servers/slapd
可以用 ps -aux 查看,或用以下命令查询服务器,测试服务启动是否成功:
ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
如果命令执行成功,返回一些信息,则说明服务器正常运行了。如果启动不成功,它会提示一些出错信息,多数是 slapd.conf 配置出错。仔细核查一下配置文件。如果 OpenLDAP 配置为非匿名访问,请在 ldapsearch 命令中加入-D 和-w 参数。
手工配置 OpenLDAP 客户机,编辑/etc/openldap/ldap.conf。
TLS_REQCERT never URI ldap://localhost:389 base dc=base,dc=com binddn cn=manager,dc=base,dc=com bindpw crypt{ae2ec15710d547a0} searchfilter (&(uid=%v)(objectclass=person)) pam_login_attribute uid ldap_version 3 timelimit 30 bind_timelimit 30 pam_lookup_policy yes
URI :访问
LDAP server的
URI,默认端口为
389;启用
SSL/TLS时,使用
ldaps://host,端口为
636。
base :指定默认的
base DN。
binddn: 指定默认的
bind DN。
bindpw: 认证用户的密码,建议使用密文。
回页首
基于 PAM 的 LDAP 身份验证要想正常的工作,还需要配置其他服务:系统命名服务和身份验证服务。
系统命名服务(NSS)需要配置为使用 LDAP 来解析诸如用户和组帐号之类的资源,即将用户的 uid 解析为用户名。由于未来用户都存储在 LDAP 目录中,因此系统需要配置成同时对 /etc/passwd 文件和 LDAP 目录中的帐号进行解析。这种功能是通过 /usr/lib/libnss_ldap.so 库提供的。
身份验证服务是实际执行 LDAP 验证用户身份的服务。Linux-PAM 提供了本地 Linux 身份验证服务。基于 PAM 的 LDAP 身份认证首先在本地的 /etc/passwd 文件检查用户帐号,如果用户在/etc/passwd 中存在,则 PAM LDAP 模块可以将身份验证重定向到 LDAP 目录上。并进行密码的校验,/lib/security/pam_ldap.so PAM 模块提供了 LDAP 身份验证功能。如果用户在/etc/passwd 中不存在,则对 LDAP 服务器进行检查,用户在 LDAP 上存在,且用户所在的组有权限登录 Linux 操作系统,则 PAM 身份认证程序自动在 Linux 操作系统上创建同名的用户,并将用户加入默认的组。以后用户只需要在 LDAP 上维护,不需要在 Linux 操作系统上维护。从而减轻了管理员的维护工作,也是用户免去了记录多个用户 ID 和密码的烦恼。
Linux 系统成功配置 OpenLDAP 后,为了与 PAM 集成统一管理用户,需要开发 PAM 相关的 so 文件实现用户的身份验证,在本文中 so 文件命名为 pam_ldap_union.so。当 LDAP 用户首次登陆 Linux terminal 时,首先判断用户在 Linux 操作系统中是否存在。如果用户在操作系统中存在,则直接返回 PAM_SUCCESS。如果用户不存在,则查询 OpenLDAP server。如果用户在 OpenLDAP server 存在,并且用户所在的组具有登陆 Linux 操作系统的权限,则在本地创建同名的用户,并给用户分配相应的权限。
//判断用户在 Linux 操作系统中是否存在。用户存在,直接返回 PAM_SUCCESS;否则,查询 OpenLDAP server。 int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc,const char **argv) { rc = pam_get_user(pamh, &user, NULL);// the user name is in the authentication handle �C pamh rc = pam_get_item(pamh, PAM_SERVICE, (const void**)&service);// get current user service. localuser = getpwnam(user); // get user from /etc/passwd if ( localuser != NULL ) { return PAM_SUCCESS; } …… } //从文件/etc/openldap/ldap.conf 获取 binddn 的 bindpw 值,作为 ldapsearch 命令的参数。 FILE *fp = fopen("/etc/openldap/ldap.conf", "r"); int rc=0; char ldapsearch[300]; //通过 ldapsearch 命令查询当前用户是否在 LDAP server 中。 sprintf(ldapsearch, "/usr/bin/ldapsearch -x -D \"%s\" -w \"%s\" cn=%s | grep \"=%s,\" 2>&1", binddn, bindpw, group, user); rc = system(ldapsearch); if(rc == 0){ printf ("pam_ldap_union: user %s found in LDAP directory", user); break; }else { printf("pam_ldap_union: user %s not found in LDAP directory ,local account will not be created", user, user); if(i == 5){ return(PAM_AUTH_ERR); } } char useradd[100]; char *homeDir = "-m"; char *primarygroup = "-g users"; char *supplgroup = "-G \'\'"; char *shell = "-s /bin/smrsh"; //如果用户在 LDAP server 中,通过 useradd 命令在 Linux 操作系统创建同名用户。 sprintf(useradd, "/usr/sbin/useradd %s %s %s %s %s >/dev/null 2>&1", homeDir, primarygroup, supplgroup, shell, user); rc = system(useradd); if ( rc != 0 ) { printf("pam_ldap_union: useradd command failed with return code %d", rc); } return PAM_SUCCESS;
要让 PAM 身份验证服务使用 OpenLDAP 服务器中的用户,将 pam_ldap 和 pam_ldap_union 加入到 PAM 配置文件/etc/pam.d/login 中,/etc/pam.d/login 中包含了 common-auth、common-account、
common-password。将 pam_ldap 和 pam_ldap_union 按照以下方式加入到相应配置文件中。
清单 8. login 文件清单
#%PAM-1.0 auth requisite pam_nologin.so auth [user_unknown=ignore success=ok ignore=ignore auth_err=die default=bad] pam_securetty.so auth include common-auth account include common-account password include common-password session required pam_loginuid.so session include common-session session required pam_lastlog.so nowtmp session optional pam_mail.so standard
清单 9. common-auth 文件清单
auth required pam_tally2.so onerr=fail deny=20 unlock_time=3600 silent auth required /lib/security/pam_ldap_union.so auth sufficient /lib/security/pam_ldap.so config=/etc/openldap/ldap.conf ignore_authinfo_unavail ignore_unknown_user auth required pam_unix_auth.so try_first_pass delay #nullok set_setrpc
清单 10. common-account 文件清单:
account required pam_tally2.so account required pam_unix_acct.so account sufficient /lib/security/pam_ldap.so config=/etc/openldap/ldap.conf
清单 11. common-password 文件清单
Password required pam_cracklib.so type=# password sufficient /lib/security/pam_ldap.so config=/etc/openldap/ldap.conf use_authtok password required pam_unix_passwd.so use_first_pass sha512
清单 12. common-session 文件清单
session required pam_limits.so session required pam_unix_session.so debug # none or trace session optional pam_umask.so
LDAP 用户的统一管理
经过以上 PAM 程序的开发和配置,LDAP 用户以后可以直接登陆 Linux 操作系统。企业中的用户只需要记录一套用户名和密码,就可以登录企业其他应用服务。当 LDAP server 上的用户出现新增、修改、删除等变化时,用户可以开发一套脚本,实现 Linux 操作系统和 LDAP server 上用户的同步。主要使用的命令如下:
新增用户使用的命令:
LDAP:ldapadd,例如 ldapadd -x -D <bindDN> -w <password>
Linux:useradd,例如 useradd �Cm �Cg <group> -s <shell> <name>
修改用户使用的命令:
LDAP:ldapmodify 或者 ldappasswd,ldappasswd 用于设置密码。
Linux:usermod,修改用户相关信息。
删除用户使用的命令:
LDAP:ldapdelete
,例如
ldapdelete -x -D <bindDN> -w secret <userinfo>
Linux:userdel <username>
用户也可以不开发此类脚本,这样在操作系统上会存在一些冗余的用户,但是不影响用户的登陆,凡是在 LDAP server 上作废的用户,是无法在操作系统上登陆的。
回页首
基于 PAM 的 LDAP 用户统一管理的应用
随着企业业务的不断发展,企业的信息系统随之增加,用户信息相对分散,为保障系统的安全正常使用和信息的一致性,需要将分散的用户信息整合集中进行统一管理,LDAP 是用户首选的用户管理工具,由 LDAP 统一管理企业的所有用户,能够快速构建出符合企业自身用户信息管理的需求,消除应用系统间用户信息孤岛,实现人员集中管理和企业各级分散的授权管理,形成人员和应用统一入口、统一管理。Linux-PAM 与 LDAP 的集成,可以用来管理企业的 Linux 服务器的用户。LDAP 服务器上有非常多的用户,属于不同组的用户具有不同的权限,只要将用户添加到相应的组,用户便有权限登陆操作系统或维护企业的 Linux 操作系统服务器,虽然用户可以在 LDAP 上维护,但是用户的权限信息还是维护在各自的应用系统上。在一些拥有几十万员工和以及拥有数以千计的服务器的企业中,这种应用能够简化管理员的维护工作,也能免去用户繁琐的记录多套用户名和密码的烦恼。
原文出自:https://www.ibm.com/developerworks/cn/linux/1406_liulz_pamopenldap/