设计一个 LDAP 用户管理解决方案应满足以下要求:
- 服务一个集群环境:该环境严重依赖于一个一致的注册表视图;所有集群成员必须在任何时候都能访问相同的注册表信息。
- 包括所有用户和组特权:典型的 LDAP 解决方案把登录凭证和实际组成员分离开来。该解决方案必须能够管理上述两项。
- 管理一个注册表:典型的 LDAP 解决方案把系统用户和普通用户分开。这就确保当 LDAP 不可访问时,root 用户和其他功能用户仍然能进行系统维护。该设计的初始目标是使所有用户都在一个注册表中。
- 高可用性和 LDAP 故障可恢复性:因为设计的目标是要在一个 LDAP 注册表中配置所有用户,所以该设计应包括能够保证 root 用户和其他系统用户始终可用。
- 最终目标是在中央 LDAP 服务器群中建立 AIX 注册表。
在这之前,我们的集群用户环境是用普通文件和 rsync 机制进行管理。对于定期发生的批量更改,基于普通文件的解决方案也能运行得很好。由于会进行毫无规则的更改(如密码更改),所以问题也随之产生。在主机上设置密码和将密码分发给所有集群成员之间总是存在时间差。在此期间,当进行(集群的)身份验证时,集群应用程序会失败。
我们的安全性基础架构严重依赖于使用组分配所提供的特权。由于历史遗产和易用性,这些普通用户组也被用于向系统用户提供相似的组特权。将普通用户和系统用户分开是可行的。但是,用于保持两个注册表同步的管理基础架构就变得复杂了,而且可能不如预期可靠。
这也适用于将系统用户和普通用户分开。总是有一定程度的重叠情况出现,而导致难于管理。
当将 LDAP 视为一个可行的网络化用户管理注册表时,便可以清晰地看到 LDAP 有一些可用性选项,但缺乏基本的选项。LDAP 提供的最重要的特性是对等域设置的概念。这就允许配置两个或多个 LDAP 服务器,每个服务器都可以更新其相邻服务器的 LDAP 更改。但是,如果 LDAP 出现问题(处于维护模式或无法访问),备用可用性特性将不可用。
考虑 AIX 时,这个 SYSTEM(身份验证方法)参数能提供支持多种验证方法的选项,但是 registry 参数只支持一个注册表。因此,并没提供相应的参数告诉 AIX 要使用的那个注册表(也就是确实可用的那个)。
AIX 提供了内置的可用性框架,该框架能填补系统和子系统特性中的空缺:RSCT。
下图描述了 LDAP 的配置原理。
图 1. LDAP 配置
- 至少两个 LDAP 服务器,进行对等配置
- 为 AIX 用户管理配置的 LDAP
- 包括所有 root 用户在内的所有系统帐户
- 使用
memberfulldn=yes选项 - 用于密码 lastupdate 标记的用户秒数
- RSCT 监控和程序,以设置用户管理环境
- 从 LDAP 中定期提取,在普通文件注册表 (/etc/passwd) 中应用最新
- 添加一个 inittab 入口,设置注册表选项为文件
- 在启用 RSCT 之后,RSCT 监控就开始检测 LDAP 的可用性并配置返回到 LDAP 的注册表参数。
本小节将介绍可用性需求和产品需求,以及系统所处的用户管理状态。
可用性需求
保证注册表始终可用:
- 启动进程中
- LDAP 服务器发生故障的情况下
- LDAP 可用性问题或模式错误的情况下
产品需求
- AIX V6.1
- IBM Tivoli® Directory Server V6.3
- IBM AIX RSCT V1.7
- IBM DB2® V9.5
用户管理状态
下图描述了系统所处的两种状态。
图 2. 用户管理状态
如果 LDAP 正常工作(在这个配置中,如果 root 用户密码可从 LDAP 中检索的话),那么注册表就定义为 LDAP。
注意:您可以定义自己的规则来决定 LDAP 是否可用。root 用户是可供使用的最重要的用户,该概念中的监控可用性就是专注于在 LDAP 中查找 root 用户信息。
系统刚刚启动时,如果网络停止运行,或者如果无法获取 LDAP,那么注册表参数会切换到文件(files)。
LDAP 服务器配置(包含对等设置)以 IBM 技术网站和 IBM Redbooks® 中的各种文档为基础。
AIX LDAP 配置是 90% 标准,并可在一些领域进行调整来满足我们的需求。
RSCT 实现是完全在内部构建的。监控脚本基于我们对如何确定 LDAP 服务器是否可访问的经验。
LDAP 服务器将在两个主机或 LPAR 上进行配置。在如下示例和脚本中,使用如下变量:
- inst1 LDAP Server1 实例名
- inst2 LDAP Server2 实例名
- host1 LDAP Server1 主机名
- host2 LDAP Server2 主机名
- port1 LDAP Server1 端口号,默认为 20389
- port2 LDAP Server2 端口号,默认为 20389
- ldp1 用于 LDAP1 的 DB2 Server1 端口号
- ldp2 用于 LDAP2 的 DB2 Server2 端口号
- dbp1 DB2 Server1 服务器端口号
- dbp2 DB2 Server2 服务器端口号
- $ITDS /opt/IBM/ldap/V6.3
- $SUFFIX o=ORG,c=US
在 host1 上创建 inst1 实例
确保实例所有者主目录是本地的,即 /home,并注意密码:对于 inst2 实例所有者用户而言,密码配置应相同。
- 为两个实例所有者用户准备相同的基组(primary group)(例如,inst1、inst2 和
pgrp=dba)。 - 为 root 用户做准备,使其成为实例所有者的基组的一部分。
- 为 root 用户做准备,使其成为 idsldap 组的一部分。
- 确保
$DB2INSTPATH/default.env文件不包含实例 inst1 或 inst2。 - 创建目录
/db2/inst1/NODE0000和/db2event/inst1并确保/db2/inst1/NODE0000和/db2event/inst1可由实例所有者的基组编写。实例创建后,可以将其设置回 normal。
清单 1. 创建 inst1 实例:
$ITDS/sbin/idsicrt -q -n -I inst1-e idsldapinst1002007 -g inst100slapd -l /home/inst1 -p 20389 -s 21389 -a 22389 -c 23389 -t inst1 |
注意加密字符串。它应与 inst2 的加密字符串相同。
清单 2. 设置 rootdn 密码:
$ITDS/sbin/idsdnpw -q -I inst1 -n -u cn=rootdn -p rootdnpwd |
清单 3. 定义 LDAP 数据库:
$ITDS/sbin/idscfgdb -q -n -I inst1 -a inst1 -t dbinst1 -w rootdnpwd -l /db2 |
清单 4. 在 LDAP 中配置基础后缀:
$ITDS/sbin/idscfgsuf -q -I inst1 -s $SUFFIX |
清单 5. 加载 NIS 模式
file="etc/security/ldap/nisSchema.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
清单 6. 加载 AIX 安全模式
file="etc/security/ldap/sec.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
在 host2 上创建 inst2 实例
执行以下步骤,在 host2 上创建 inst2 实例。
- 准备两个实例所有者用户,两个都属于同一个基组(例如,inst1、inst2 和
pgrp=dba)。 - 为 root 用户做准备,使其成为实例所有者的基组的一部分。
- 为 root 用户做准备,使其成为 idsldap 组的一部分。
- 确保
$DB2INSTPATH/default.env文件不包含 inst1 或 inst2 实例。 - 创建目录
/db2/inst1/NODE0000和/db2event/inst1并确保/db2/inst1/NODE0000和/db2event/inst1可由实例所有者的基组编写。创建实例后,将其设置回 normal。 - 确保两个对等的 LDAP 服务器上的种子算法(seed algorithm)是相同的。这是在
idsicrt命令的-e标志中定义的。
清单 7. 创建 inst2 实例:
$ITDS/sbin/idsicrt -q -n -I inst2 -e idsldapinst1002007 -g inst100slapd -l /home/inst2 -p 20389 -s 21389 -a 22389 -c 23389 -t inst2 |
清单 8. 设置 rootdn 密码:
$ITDS/sbin/idsdnpw -q -I inst2 -n -u cn=rootdn -p rootdnpwd |
清单 9. 定义 LDAP 数据库:
$ITDS/sbin/idscfgdb -q -n -I inst1 -a inst1 -t dbinst1 -w rootdnpwd -l /db2 |
清单 10. 在 LDAP 中配置基础后缀:
$ITDS/sbin/idscfgsuf -q -I inst2 -s $SUFFIX |
清单 11. 加载 NIS 模式
file="etc/security/ldap/nisSchema.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
清单 12. 加载 AIX 安全模式
file="etc/security/ldap/sec.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
在 inst1 和 inst2 实例上加载 /etc/passwd 用户群
使用以下程序序列准备一个 Perl 脚本:
#!/usr/bin/perl
open(SEC,"< /etc/security/passwd");
@usr = <SEC>;
close(SEC);
chomp(@usr);
foreach $line (@usr) {
if ( $line =~ /(\w):/ ) {
$line =~ s/://;
$uid = $line;
}
if ( $line =~ /lastupdate/ ) {
@row = split("=",$line);
$row[1] += 0;
$lastupdate{$uid} = $row[1];
}
}
$file = "/opt/usrmgt/lib/secinit.ldif";
print("Creating $file containing initial user base ...\n")
$cmd = "/usr/sbin/sectoldif -d \"$SUFFIX\" -S rfc2307aix";
print("Command: $cmd\n");
open(SEC,"$cmd |");
@sec = <SEC>;
close(SEC);
chomp(@sec);
open(SEC,"> $file");
foreach $line (@sec) {
@row = split(":",$line);
if ( $line =~ /^uid:/ ) {
$uid = $row[1];
$uid =~ s/\s+//;
}
if ( $line =~ /^memberuid/ ) {
$row[1] =~ s/ //g;
print(SEC "$row[0]: uid=$row[1],ou=People,$SUFFIX\n");
} elsif ( $line =~ /^shadowlastchange/ ) {
print(SEC "shadowlastchange: $lastupdate{$uid}\n");
} else {
print(SEC "$line\n");
}
}
close(SEC);
print("Loading $file in LDAP Directory Server inst1 ...\n");
$baseauth = "-h host1 -p 20389 -D cn=rootdn -w rootdnpwd";
$cmd = "$ITDS/bin/ldapadd -c -v -a $baseauth -f $file";
print("Command: $cmd\n");
system("$cmd");
print("Loading $file in LDAP Directory Server inst2 ...\n");
$baseauth = "-h host2 -p 20389 -D cn=rootdn -w rootdnpwd";
$cmd = "$ITDS/bin/ldapadd -c -v -a $baseauth -f $file";
print("Command: $cmd\n");
system("$cmd");
|
设置 inst1 和 inst2 之间的对等复制
定义基础复制上下文
#!/usr/bin/perl
$ldif = "/opt/usrmgt/logs/suffix_replication.ldif";
open(LDIF,"> $ldif");
print(LDIF "dn: $SUFFIX\n");
print(LDIF "changetype: modify\n");
print(LDIF "add: objectclass\n");
print(LDIF "objectclass: ibm-replicationContext\n");
close(LDIF);
$baseauth = "-h host1 -p 20389 -D cn=rootdn -w rootdnpwd";
$cmd = "$ITDS/bin/ldapmodify -v $baseauth -k -l -i $ldif";
print("Executing $cmd ...\n");
system($cmd);
$baseauth = "-h host2 -p 20389 -D cn=rootdn -w rootdnpwd";
$cmd = "$ITDS/bin/ldapmodify -v $baseauth -k -l -i $ldif";
print("Executing $cmd ...\n");
system($cmd);
|
配置主复制 DN
#!/usr/bin/perl
$ldif = "$SOURCE/logs/master_replication_dn.ldif";
open(LDIF,"> $ldif");
print(LDIF "dn: cn=MasterServer,cn=configuration\n");
print(LDIF "cn: MasterServer\n");
print(LDIF "ibm-slapdMasterDN: cn=masterdn\n");
print(LDIF "ibm-slapdMasterPW: masterdnpwd \n");
print(LDIF "objectclass: ibm-slapdReplication\n");
print(LDIF "objectclass: ibm-slapdConfigEntry\n");
print(LDIF "objectclass: top\n");
close(LDIF);
$baseauth = "-h host1 -p 20389 -D cn=rootdn -w rootdnpwd";
$cmd = "$ITDS/bin/idsldapadd $baseauth -i $ldif";
print("Executing $cmd ...\n");
system($cmd);
$baseauth = "-h host2 -p 20389 -D cn=rootdn -w rootdnpwd";
$cmd = "$ITDS/bin/idsldapadd $baseauth -i $ldif";
print("Executing $cmd ...\n");
system($cmd);
|
配置复制规则
以下程序配置 inst1 和 inst2 之间的复制规则。该脚本应同时在两个实例主机上运行。参数(如 <serverId-inst2>)必须在基础实例配置中查询。确保正确映射实例和服务器 ID (serverID)。您可以使用以下命令获取服务器 ID:
$ITDS/bin/ldapsearch -h host1 -p 20389 -s base objectclass=* ibm-serverId |
从 host1 上的 inst1 实例获取服务器 ID。
$ITDS/bin/ldapsearch -h host2 -p 20389 -s base objectclass=* ibm-serverId |
从 host2 上的 inst2 实例获取服务器 ID。
#!/usr/bin/perl
$ldif = "$SOURCE/logs/Replication_Agreement.ldif";
open(LDIF,"> $ldif");
print(LDIF "dn: ibm-replicaGroup=default,$SUFFIX\n");
print(LDIF "objectclass: top\n");
print(LDIF "objectclass: ibm-replicaGroup\n");
print(LDIF "ibm-replicaGroup: default\n");
print(LDIF "\n");
print(LDIF "dn: cn=ReplicaBindCredentials,cn=replication,cn=IBMpolicies\n");
print(LDIF "objectclass: ibm-replicationCredentialsSimple\n");
print(LDIF "cn: ReplicaBindCredentials\n");
print(LDIF "replicaBindDN: cn=masterdn\n");
print(LDIF "replicaCredentials: masterdnpwd\n");
print(LDIF "description: Bind Credentials on peer to bind to each other.\n");
print(LDIF "\n");
print(LDIF "dn: ibm-replicaServerId=<serverId-inst2>,ibm-replicaGroup=default,$SUFFIX\n");
print(LDIF "objectclass: top\n");
print(LDIF "objectclass: ibm-replicaSubentry\n");
print(LDIF "ibm-replicaServerId: <serverId-inst2>\n");
print(LDIF "ibm-replicationServerIsMaster: true\n");
print(LDIF "cn: inst2\n");
print(LDIF "description: inst2 ibm-replicaSubentry\n");
print(LDIF "\n");
print(LDIF "dn: ibm-replicaServerId=<serverId-inst1>,ibm-replicaGroup=default,$SUFFIX\n");
print(LDIF "objectclass: top\n");
print(LDIF "objectclass: ibm-replicaSubentry\n");
print(LDIF "ibm-replicaServerId: <serverId-inst1>\n");
print(LDIF "ibm-replicationServerIsMaster: true\n");
print(LDIF "cn: inst1\n");
print(LDIF "description: inst1 ibm-replicaSubentry\n");
print(LDIF "\n");
print(LDIF "dn: cn=inst2,ibm-replicaServerId=<serverId-inst1>,
ibm-replicaGroup=default,$SUFFIX\n");
print(LDIF "objectclass: top\n");
print(LDIF "objectclass: ibm-replicationAgreement\n");
print(LDIF "cn: inst2\n");
print(LDIF "ibm-replicaConsumerId: <serverId-inst2>\n");
print(LDIF "ibm-replicaUrl: ldap://host2:20389\n");
print(LDIF "ibm-replicaCredentialsDN: cn=ReplicaBindCredentials,
cn=replication,cn=IBMpolicies\n");
print(LDIF "description: inst1 to inst2 agreement\n");
print(LDIF "\n");
print(LDIF "dn: cn=inst1,ibm-replicaServerId=<serverId-inst2>,
ibm-replicaGroup=default,$SUFFIX\n");
print(LDIF "objectclass: top\n");
print(LDIF "objectclass: ibm-replicationAgreement\n");
print(LDIF "cn: inst1\n");
print(LDIF "ibm-replicaConsumerId: <serverId-inst1>\n");
print(LDIF "ibm-replicaUrl: ldap://host1:20389\n");
print(LDIF "ibm-replicaCredentialsDN: cn=ReplicaBindCredentials,
cn=replication,cn=IBMpolicies\n");
print(LDIF "description: inst2 to inst1 agreement\n");
print(LDIF "\n");
close(LDIF);
$cmd = "$ITDS/sbin/idsslapd -I inst1 -k"; # stop LDAP
print("Executing $cmd ...\n");
system("$cmd"); # stop LDAP
print("Loading Replication agreement $ldif …\n")
$cmd = "$ITDS/sbin/idsldif2db -r no -i $ldif -I inst1";
print("Executing $cmd ...\n");
system($cmd);
print("Starting LDAP server ...\n");
$cmd = "$ITDS/sbin/idsslapd -I inst1"; # start LDAP
print("Executing $cmd ...\n");
system("$cmd"); # start LDAP
|
在 host2 上执行同一序列,
$cmd = "$ITDS/sbin/idsslapd -I inst2 -k"; # stop LDAP
print("Executing $cmd ...\n");
system("$cmd"); # stop LDAP
print("Loading Replication agreement $ldif …\n")
$cmd = "$ITDS/sbin/idsldif2db -r no -i $ldif -I inst2";
print("Executing $cmd ...\n");
system($cmd);
print("Starting LDAP server ...\n");
$cmd = "$ITDS/sbin/idsslapd -I inst2"; # start LDAP
print("Executing $cmd ...\n");
system("$cmd"); # start LDAP
|
准备 LDAP 客户端配置
设置服务器配置,支持下列对默认 aix2307rfc 模式的两个小幅更改:
- 密码过期不再以从 1970 年开始的天数为单位,而是以秒为单位。
- 对于组来说,使用
fulldn memberuid,而不是userid membernames
当将 LDAP 用于其他应用程序(如 IBM WebSphere®)时,这种设置对于定义 IBM WebSphere Console 用户管理授权是非常有用的。在 LDAP 中组的配置是默认配置。
cn=group1,ou=Groups,ou=SYS1,o=ORG,c=US cn=group1 objectClass=aixauxgroup objectClass=posixgroup objectClass=top gidnumber=1142 memberuid=user1 |
使用 memberfulldn=yes 选项,如下列代码所示。
cn=group1,ou=Groups,ou=SYS1,o=ORG,c=US cn=group1 objectClass=aixauxgroup objectClass=posixgroup objectClass=top gidnumber=1142 memberuid=uid=user1,ou=People,ou=SYS1,o=UBS,c=COM |
要准备客户端,使用下列程序配置所有参与的 LDAP 客户端。
#!/usr/bin/perl
$cfg = "/etc/security/ldap/2307aixuser.map";
open(ETC,"< $cfg");
@etc = <ETC>;
close(ETC);
chomp(@etc);
$updatecfg = 0;
$refreshldap = 0;
foreach $line (@etc) {
if ( $line =~ /^lastupdate/ ) {
@row = split(" ",$line) ;
if ( $row[-1] !~ /seconds/ ) {
$updatecfg = 1;
}
}
}
if ( $updatecfg ) {
open(ETC,"> $cfg");
foreach $line (@etc) {
if ( $line =~ /^lastupdate/ ) {
print("Setting LDAP user mapping to accept seconds ...\n");
print(ETC "lastupdate SEC_INT shadowlastchange s seconds\n");
} else {
print(ETC "$line\n");
}
}
close(ETC);
}
$cfg = "/etc/security/ldap/ldap.cfg";
open(ETC,"< $cfg");
@etc = <ETC>;
close(ETC);
chomp(@etc);
$updatecfg = 0;
foreach $line (@etc) {
if ( $line =~ /^memberfulldn:/ ) {
@row = split(":",$line) ;
if ( $row[1] !~ /yes/ ) {
$updatecfg = 1;
}
}
}
if ( $updatecfg ) {
open(ETC,"> $cfg");
foreach $line (@etc) {
if ( $line =~ /^memberfulldn:/ ) {
print("Setting LDAP configuration to accept fulldn ...\n");
print(ETC "memberfulldn: yes\n");
} else {
print(ETC "$line\n");
}
}
close(ETC);
}
$masters = "host1,host2";
$cmd = "/usr/sbin/mksecldap -c -a cn=rootdn -p rootdnpwd -d $SUFFIX -h $masters -n 20389";
print("INFO: configuring all nodes to listen to $masters peer-2-peer ...\n");
print("Executing $cmd ...\n");
system("$cmd");
|
清单 13. 将 root 用户添加到 LDAP
#!/usr/bin/perl
$rootuser = `/usr/sbin/lsuser –R files root`;
chomp($rootuser);
print("ROOTUSER = $rootuser\n");
$rootuser =~ s/^root //;
$rootuser =~ s/SYSTEM=LDAP or compat //;
$rootuser =~ s/SYSTEM=LDAP //;
$rootuser =~ s/SYSTEM=compat //;
$rootuser =~ s/SYSTEM=LDAP or compat//;
$rootuser =~ s/SYSTEM=LDAP//;
$rootuser =~ s/SYSTEM=compat//;
$rootuser =~ s/auth1=(\w+)/auth1=NONE/;
$rootuser =~ s/auth2=(\w+)/auth2=NONE/;
$rootuser =~ s/registry=(\w+)//;
$rootuser =~ s/(\w+)=(\s|$)//g; # remove all empty attributes
$rootuser =~ s/(\w+)_login=([\w-]+)\s//g; # remove all session status attributes
print("ROOTUSER = $rootuser\n");
$cmd = "/usr/bin/mkuser –R LDAP $rootuser root";
logger("Creating root: $cmd");
system("$cmd");
|
从 LDAP 中定期提取用户
为了保存一组最新的、基于文件的本地注册表,要预先安排从 LDAP 中提取以确保保存了一天中对 LDAP 进行的所有更改。使以下脚本成为 crontab 或另一个调度程序的一部分。选择最适合您的组织需求的频率。
强制启动文件注册表
为了确保启动进程永远运行,不管 LDAP 是否运行,都要告诉 AIX 总是在 registry=files 模式下启动。
为此,/etc/inittab 文件必须使用下列内容更新:
/usr/sbin/mkitab –I rctcpip "usrmgt:23456789:wait:/opt/usrmgt/bin/setregfiles >/dev/console 2>&1" |
其中,/opt/usrmgt/bin/setregfiles 如下所示:
#!/usr/bin/ksh /usr/bin/chsec -f /etc/security/user -s default -a registry=files /usr/bin/chsec -f /etc/security/group -s default -a registry=files |
激活 RSCT 监控
设置中的最后一步是 RSCT 配置。该配置监控 LDAP 的可用性。如果 LDAP 无法访问,registry 参数将设置为 files。
第 3.1 章中指定了在 IBM.Sensor 中定义的基础监控程序 $MON/checkldap。该示例中的监控间隔时间设定为 10 秒。谓词 String==\"NOK\" 基本上是一个虚拟谓词。将该谓词包含在内,以便 IBM.Sensor 资源监控程序子系统能用实际的 LDAP 状态信息来填充字符串,这样可供响应脚本参考。该谓词不用于实际监控,这里使用的是 Int32 参数。
第 3.2 章列出了响应脚本 $MON/restartldapclient。
#!/usr/bin/perl
$RSCT = "/usr/sbin/rsct/bin";
$MON = "/opt/usrmgt/mon";
$IV = "Name==\"CheckLDAP\"";
$PRED = "String==\"NOK\" || Int32>0";
system("$RSCT/mksensor -i 10 -e 0 CheckLDAP $MON/checkldap");
system("$RSCT/mkresponse -n 'SetLDAPEnvironment' -s '$MON/restartldapclient' -e b
RestartLDAPClient");
system("$RSCT/mkcondition -r IBM.Sensor -m l -S c -s '$IV' -e '$PRED' LDAP_PREP");
system("$RSCT/mkcondresp LDAP_PREP RestartLDAPClient");
system("$RSCT/startcondresp LDAP_PREP RestartLDAPClient");
|
RSCT LDAP 监控脚本 /opt/usrmgt/mon/checkldap
#!/usr/bin/perl
$ITDS = "/opt/IBM/ldap/V6.3"; # LDAP Source Code Directory
$SUFFIX = "o=ORG,c=US"; # Your LDAP Suffix
$SOURCE = "/opt/usrmgt"; # User Management Code directory
$LOG = "$SOURCE/mon/CheckLDAP.log"; # Monitor Log file
$running = 0; # initialization of runtime vars
$userregerror = 0;
$usersyserror = 0;
$groupregerror = 0;
$LDAPH1 = "host1";
$LDAPH2 = "host2";
$LDAPI1 = "inst1";
$LDAPI2 = "inst2";
$LDAPP1 = 20389;
$LDAPP2 = 20389;
# Note that coding passwords in scripts is not recommended
# but you could replace this with your own password retrieval method
$pwd = "rootdnpwd"; # LDAP rootdn password
$arg = $ARGV[0]; # Testflag for command line execution
if ( $arg eq "offline" ) {
$termoutput = 1;
}
#Check status of the LDAP servers and fill the errormessage with the status information
for ( $i=1 ; $i<=2 ; $i++) {
$host = "LDAPH${i}";
$inst = "LDAPI${i}";
$port = "LDAPP${i}";
# Check for a valid root user entry in LDAP
$cmd = "$ITDS/bin/ldapsearch -h $$host -p $$port -D cn=rootdn -w '\?' -b $SUFFIX
uid=root userpassword";
# Use this method to parse the rootdn password, without risking that the
# password appears in the process list
#print("CMD = $cmd writing to $LOG.$$inst using $pwd\n");
open(IDS,"| $cmd > $LOG.$$inst 2>&1");
print(IDS "$pwd\n");
close(IDS);
open(IDS,"< $LOG.$$inst");
@ids = <IDS>;
close(IDS);
chomp(@ids);
shift(@ids);
#unlink("$LOG");
if ( $#ids == 1 ) {
foreach $line (@ids) {
#print("LINE = $line\n");
if ( $line =~ /userpassword/ ) {
@row = split("=",$line);
if ( $row[1] =~ /crypt/ ) {
$running = 1;
$errormessage .= "# $$inst,$$port,$$host=1 ";
} else {
$errormessage .= "# $$inst,$$port,$$host=2 '";
}
}
}
} else {
$errormessage .= "# $$inst,$$port,$$host=0 ";
}
}
# Check status of the registry and SYSTEM parameters in /etc/security/user and group
open(SEC,"/usr/bin/lssec -c -f /etc/security/user -s default -a registry -a SYSTEM |");
@sec = <SEC>;
close(SEC);
chomp(@sec);
foreach $line (@sec) {
if ( $line =~ /^default/ ) {
@row = split(":",$line);
# The second field holds the registry value
if ( $row[1] eq "LDAP" ) {
$userregldapset = 1;
} elsif ( $row[1] eq "files" ) {
$userregldapset = 0;
} else {
$userregerror = 1;
}
$errormessage .= "# userreg=$row[1];";
# The third field holds the SYSTEM value
if ( $row[2] eq "\"LDAP or compat\"" ) {
$usersysldapset = $running;
} else {
$usersyserror = 1;
}
$row[2] =~ s/"//g;
$errormessage .= "SYSTEM='$row[2]';";
}
}
open(SEC,"/usr/bin/lssec -c -f /etc/security/group -s default -a registry |");
@sec = <SEC>;
close(SEC);
chomp(@sec);
foreach $line (@sec) {
if ( $line =~ /^default/ ) {
$line =~ s/"//g;
@row = split(":",$line);
if ( $row[1] eq "LDAP" ) {
$groupregldapset = 1;
} elsif ( $row[1] eq "files" ) {
$groupregldapset = 0;
} else {
$groupregerror = 1;
}
$errormessage .= "groupreg='$row[1]'";
}
}
$action = 0;
if ( $running ) {
if ( not ${userregldapset} || not ${usersysldapset} || not ${groupregldapset} ) {
$action = 1;
}
} else {
if ( ${userregldapset} || ${usersysldapset} || ${groupregldapset} ) {
$action = 1;
}
}
if ( $groupregerror || $userregerror ) {
$action = 1;
}
if ( $userregerror || $usersyserror || $groupregerror ) {
$actionstring = "-${running}${userregerror}${usersyserror}${groupregerror}"
} else {
$actionstring = "${running}${userregldapset}${usersysldapset}${groupregldapset}"
}
$errormessage = "$actionstring $errormessage";
if ( $termoutput ) {
print("$running\n");
print("Int32=$action String=\"$errormessage\"\n");
} else {
print("Int32=$action String=\"$errormessage\"");
}
|
在 RSCT 通知后恢复脚本:/opt/usrmgt/mon/restartldapclient
#!/usr/bin/perl
$reg{0} = "files"; # if $ldap is down
$reg{1} = "LDAP"; # if $ldap is up
$sys{0} = "LDAP or compat"; # if $ldap is down
$sys{1} = "LDAP or compat"; # if $ldap is up
$hostname = `/usr/bin/hostname -s`;
chomp($hostname);
if ( $ENV{ERRM_VALUE} ) { # Take ERRM_VALUE from notifier
$string = "$ENV{ERRM_VALUE}";
} else { # else simulate one for test
# Set a string fixed
# String = 0000 # host1-e0 NOT running # host2-e0 NOT running # User: registry is
'files' SYSTEM is 'LDAP or compat' , Group: registry is 'files'
# or get a string from IBM.Sensor
open(LSS,"/usr/sbin/rsct/bin/lssensor CheckLDAP |");
@lss = <LSS>;
close(LSS);
chomp(@lss);
foreach $line (@lss) {
$line =~ s/ *//;
if ( $line =~ /^String/ ) {
$string = $line;
$string =~ s/String = //;
print("STRINGLINE = $string\n");
}
}
}
@row = split("#",$string);
$ldapstatus = "$row[0]";
$ldapstatus =~ s/ //;
$group = "/etc/security/group";
$users = "/etc/security/user";
$debug = 1;
# 1=LDAP,2=UserReg,3=UserSys,4=GroupReg
if ( $ldapstatus =~ /^-/ ) {
$ldapstatus =~ s/^-//;
$ldap = substr($ldapstatus,0,1);
$userreg = substr($ldapstatus,1,1);
$usersys = substr($ldapstatus,2,1);
$groupreg = substr($ldapstatus,3,1);
setuserreg($reg{$ldap}) if ( $userreg );
setusersys($sys{$ldap}) if ( $usersys );
setgroupreg($reg{$ldap}) if ( $groupreg );
} else {
$ldap = substr($ldapstatus,0,1);
$ldap += 0;
$userreg = substr($ldapstatus,1,1);
$userreg += 0;
$usersys = substr($ldapstatus,2,1);
$usersys += 0;
$groupreg = substr($ldapstatus,3,1);
$groupreg += 0;
if ( $ldapstatus eq "0000" || $ldapstatus eq "1111" ) {
#print("NO CHANGE NEEDED\n");
$debug = 0;
} else {
$doit = ${ldap}^${userreg} ;
setuserreg($reg{$ldap}) if ( $doit );
$doit = ${ldap}^${usersys} ;
setusersys($sys{$ldap}) if ( $doit );
$doit = ${ldap}^${groupreg} ;
setgroupreg($reg{$ldap}) if ( $doit );
}
}
if ( $userchange || $groupchange ) {
system("/usr/sbin/restart-secldapclntd");
}
sub setuserreg {
my $registry = $_[0];
$cmd = "/usr/bin/chsec -f $users -s default -a registry=$registry";
system("$cmd");
$userchange = 1;
}
sub setusersys {
my $SYSTEM = $_[0];
$cmd = "/usr/bin/chsec -f $users -s default -a SYSTEM=\"$SYSTEM\"";
system("$cmd");
$userchange = 1;
}
sub setgroupreg {
my $registry = $_[0];
$cmd = "/usr/bin/chsec -f $group -s default -a registry=$registry";
system("$cmd");
$groupchange= 1;
}
|
学习
- AIX and UNIX 专区:developerWorks 的“AIX and UNIX 专区”提供了大量与 AIX 系统管理的所有方面相关的信息,您可以利用它们来扩展自己的 UNIX 技能。
- AIX and UNIX 新手入门:访问“AIX and UNIX 新手入门”页面可了解更多关于 AIX 和 UNIX 的内容。
- AIX and UNIX 专题汇总:AIX and UNIX 专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。
-
AIX and UNIX 下载中心:在这里你可以下载到可以运行在 AIX 或者是 UNIX 系统上的 IBM 服务器软件以及工具,让您可以提前免费试用他们的强大功能。
- IBM Systems Magazine for AIX 中文版:本杂志的内容更加关注于趋势和企业级架构应用方面的内容,同时对于新兴的技术、产品、应用方式等也有很深入的探讨。IBM Systems Magazine 的内容都是由十分资深的业内人士撰写的,包括 IBM 的合作伙伴、IBM 的主机工程师以及高级管理人员。所以,从这些内容中,您可以了解到更高层次的应用理念,让您在选择和应用 IBM 系统时有一个更好的认识。
讨论
- 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。