Design a LDAP user-management solution that can satisfy the following requirements:
- Serve a clustered environment: The environment is heavily dependent on a consistent registry view; all cluster members must be able to access the same registry information at any time.
- Include all users and group privileges: Typical LDAP solutions separate the login credentials from the actual group membership. This solution needs to be able to manage both.
- Manage one registry: Typical LDAP solutions separate system users from common users. This is to make sure that when LDAP is not accessible, the system can still be maintained by the root and other functional users. The starting position of this design is to have all the users in one registry.
- Highly available and able to recover from LDAP failures: As the design goal is to configure all the users in an LDAP registry, the design should include the guarantee that the root and other system users are available at all times.
- The ultimate goal is to offshore the AIX registry in a central LDAP server farm.
Environmental and product limitations
Up until this date, our clustered user environment was managed with flat files and an rsync mechanism. For batch changes that occur at regular intervals, a flat file-based solution can work well. The problems occur with irregular changes, such as password changes. There will always be a gap between setting the password on the master and distributing the passwords to all the cluster members. During this time, the cluster applications can fail, when (clustered) authentications take place.
Our security infrastructure heavily depends on providing privileges using group assignments. Due to historic heritage and ease of use, these common user groups are also used for providing similar group privileges to system users. Separating common users from system users is possible, however, the management infrastructure needed to keep both the registries in synchronization, becomes complex and is perhaps not as reliable as expected.
This also applies to separating system users from common users. There is always a certain degree of overlap that becomes hard to manage.
Looking at LDAP as a possible networked, user-management registry, it quickly becomes clear that LDAP has a few availability options, but also lacks essential options. The most important feature that LDAP provides is the concept of a peer-to-peer domain setup. This allows for the configuration of two or more LDAP servers, each one updating its neighbors about LDAP changes. However, if the LDAP is corrupt (in maintenance mode or otherwise not accessible), alternate availability features are not available.
Looking at AIX, the SYSTEM (authentication method) parameter does provide the option to support multiple authentication methods, but the registry parameter supports only one registry. So, in order to tell AIX which registry to use, that is the one that is reliably available, is not provided.
AIX is delivered with an availability framework that can fill in these gaps in system and subsystem features: RSCT.
The following figure depicts the principle of the LDAP configuration.
Figure 1. LDAP configuration
- At least two LDAP servers, in a peer-to-peer configuration
- LDAP configured for AIX user management
- Include all system accounts, including root
- Use the
memberfulldn=yesoption - user seconds for password lastupdate stamp
- RSCT monitoring and programs to set the user-management environment
- Regular extract from LDAP, applying the result in the flat file registry (/etc/passwd)
- Add an inittab entry to set the registry to files
- RSCT monitoring detects the availability of LDAP after RSCT is started and configures the registry parameter back to LDAP.
This section explains the availability requirements and the product requirements and also the user-management states that the system can be in.
Availability requirements
Guarantee registry availability, at all time:
- For the boot process
- In case of LDAP server failures
- In case of LDAP accessibility problems or schema errors
Product requirements
- AIX V6.1
- IBM Tivoli® Directory Server V6.3
- IBM AIX RSCT V1.7
- IBM DB2® V9.5
User management states
The following figure depicts the two states that the system can be in.
Figure 2. User-management states
If LDAP is working correctly (in this configuration, if the root password can be retrieved from LDAP), the registry is defined as LDAP.
Note: You can define your own rules to determine if LDAP is available. As the root user is the most important user to be available, monitoring availability in this concept is concentrated on finding the root user information in LDAP.
When a system has just booted, when the network is down or if LDAP is not reachable, the registry parameter is switched to files.
The LDAP server configuration, including the peer-to-peer setup is based on various documents from the IBM technical web pages and from IBM Redbooks®.
The AIX LDAP configuration is 90 percent standard and adapted in a few areas to meet our requirements.
The RSCT implementation is completely home built. The monitoring scripts are based on our experiences on how to determine if LDAP servers are accessible.
The LDAP servers are being configured on two hosts / LPARs. In the examples and scripts following, I use the following variables:
- inst1 LDAP Server1 instance name
- inst2 LDAP Server2 instance name
- host1 LDAP Server1 host name
- host2 LDAP Server2 host name
- port1 LDAP Server1 port number, default 20389
- port2 LDAP Server2 port number, default 20389
- ldp1 DB2 Server1 port number for LDAP1
- ldp2 DB2 Server2 port number for LDAP2
- dbp1 DB2 Server1 server port number
- dbp2 DB2 Server2 server port number
- $ITDS /opt/IBM/ldap/V6.3
- $SUFFIX o=ORG,c=US
Create the inst1 instance on host1
Make sure that the instance owner home directory is local, that is /home and note the password: it should be configured the same for the inst2 instance owner user.
- Prepare two instance owner users with both the same primary group (inst1, inst2 and for example
pgrp=dba), - Prepare the root user to be part of the primary group of the instance owners.
- Prepare the root user to be part of the idsldap group.
- Make sure that the
$DB2INSTPATH/default.envfile does not contain the instance inst1 or inst2. - Create the directories
/db2/inst1/NODE0000and/db2event/inst1and make sure that/db2/inst1/NODE0000and/db2event/inst1are writable by the instance owner's primary group. After creating the instances, you can set this back to normal.
Listing 1. Create the inst1 instance:
$ITDS/sbin/idsicrt -q -n -I inst1-e idsldapinst1002007 -g inst100slapd -l /home/inst1 -p 20389 -s 21389 -a 22389 -c 23389 -t inst1 |
Note the encryption string. It should be the same as the encryption string for the inst2 instance.
Listing 2. Set the rootdn password:
$ITDS/sbin/idsdnpw -q -I inst1 -n -u cn=rootdn -p rootdnpwd |
Listing 3. Define the LDAP database:
$ITDS/sbin/idscfgdb -q -n -I inst1 -a inst1 -t dbinst1 -w rootdnpwd -l /db2 |
Listing 4. Configure the base suffix in LDAP:
$ITDS/sbin/idscfgsuf -q -I inst1 -s $SUFFIX |
Prepare LDAP for AIX user management
Listing 5. Load the NIS schema
file="etc/security/ldap/nisSchema.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
Listing 6. Load the AIX security schema
file="etc/security/ldap/sec.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
Create the inst2 instance on host2
Perform the following steps to create the inst2 instance on host2.
- Prepare two instance owner users with both belonging to the same primary group (inst1, inst2, and for example,
pgrp=dba). - Prepare the root user to be part of the primary group of the instance owners.
- Prepare the root user to be part of the idsldap group.
- Make sure that the
$DB2INSTPATH/default.envfile does not contain the inst1 or inst2 instance. - Create the
/db2/inst2/NODE0000and/db2event/inst2directories and make sure that/db2/inst2/NODE0000and/db2event/inst1are writable by the instance owner's primary group. After creating the instances, you can set this back to normal. - Make sure that the seed algorithm on the two peer-to-peer LDAP servers is the same. This is defined in the
-eflag of theidsicrtcommand.
Listing 7. Create the inst2 instance:
$ITDS/sbin/idsicrt -q -n -I inst2 -e idsldapinst1002007 -g inst100slapd -l /home/inst2 -p 20389 -s 21389 -a 22389 -c 23389 -t inst2 |
Listing 8. Set the rootdn password:
$ITDS/sbin/idsdnpw -q -I inst2 -n -u cn=rootdn -p rootdnpwd |
Listing 9. Define the LDAP database:
$ITDS/sbin/idscfgdb -q -n -I inst1 -a inst1 -t dbinst1 -w rootdnpwd -l /db2 |
Listing 10. Configure the base suffix in LDAP:
$ITDS/sbin/idscfgsuf -q -I inst2 -s $SUFFIX |
Prepare LDAP for AIX user management
Listing 11. Load the NIS schema
file="etc/security/ldap/nisSchema.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
Listing 12. Load the AIX security schema
file="etc/security/ldap/sec.ldif" $ITDS/bin/ldapmodify -c -v -a -h host1 -p 20389 -D cn=rootdn -w rootdnpwd -f $file |
Load the /etc/passwd user base on the inst1 and inst2 instances
Prepare a Perl script with the following program sequence:
#!/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");
|
Setting up peer-to-peer replication between inst1 and inst2
Defining the base replication context
#!/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);
|
Configuring the master replication 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);
|
Configuring the replication agreement
The following program configures the replication agreement between inst1 and inst2. This script should be ran on both of the instance hosts. The parameters, such as <serverId-inst2> must be queried from the base instance configuration. Make sure to map the instance and server ID (serverID) correctly. You can get the server ID with the following command:
$ITDS/bin/ldapsearch -h host1 -p 20389 -s base objectclass=* ibm-serverId |
To get the server ID from the inst1 instance on host1.
$ITDS/bin/ldapsearch -h host2 -p 20389 -s base objectclass=* ibm-serverId |
To get the server ID from inst2 on host2.
#!/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
|
Perform the same sequence on 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
|
Prepare LDAP client configuration
The server configuration is set up to support the following two minor changes to the default aix2307rfc schema:
- Password expiration in seconds, not in days from 1970.
fulldn memberuid, instead ofuserid membernamesfor groups
This setting is particularly useful when using LDAP for other applications, such as IBM WebSphere®, to define user administration authorizations for the IBM WebSphere Console.Default configuration for a group in LDAP:
cn=group1,ou=Groups,ou=SYS1,o=ORG,c=US cn=group1 objectClass=aixauxgroup objectClass=posixgroup objectClass=top gidnumber=1142 memberuid=user1 |
Using the memberfulldn=yes option, this looks as shown in the following code.
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 |
In order to prepare the client for this, use the following program to configure the participating LDAP clients.
#!/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");
|
Listing 13. Adding the root user to 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");
|
Extracting users from LDAP on a regular basis
In order to keep an up-to-date set of local, files-based registry, an extract from LDAP can be scheduled to make sure that all the changes occurring in LDAP during a day are saved. Make the following script to be part of crontab or another scheduler. Choose a frequency that fits best to your organization's needs.
Forcing file registry at boot
In order to make sure that the boot process will always work, no matter if LDAP runs or not, is to tell AIX to always boot in the registry=files mode.
For this, the /etc/inittab file must be updated with:
/usr/sbin/mkitab –I rctcpip "usrmgt:23456789:wait:/opt/usrmgt/bin/setregfiles >/dev/console 2>&1" |
where /opt/usrmgt/bin/setregfiles looks as follows:
#!/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 |
Activating RSCT monitoring
The last step in the setup is the configuration of RSCT. This configuration monitors the availability of LDAP and if LDAP is not reachable, the registry parameter will be set to files.
The base monitor $MON/checkldap, defined in IBM.Sensor, is specified in Chapter 3.1. The monitoring interval in this example is set to 10 seconds. The predicate String==\"NOK\" is basically a dummy predicate. It is included so that the IBM.Sensor resource monitor subsystem can fill the string with the actual LDAP status information, so that it becomes available in the response script for reference. It is not used for the actual monitoring, for this, the Int32 parameter is used.
The response script $MON/restartldapclient is listed in Chapter 3.2.
#!/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 monitoring script, /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\"");
}
|
Recovery script after RSCT notification: /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;
}
|
Peter Kes started his IT career as a System Engineer at IBM. He developed many customer solutions in the field of IBM AIX and IBM RS/6000 SP, developed and conducted technical classes and wrote a few IBM Redbooks titles about AIX and service pack (SP) system management. After a brief but intensive period at IBM USA (Poughkeepsie), he started working for UBS in a large data warehouse project. He was and still is responsible for writing, designing, and developing advanced technical solutions for security, web deployment, and system management. You can reach him at peter.kes@ubs.com.



