#!/bin/ksh93 ############################################################################# # # Licensed Materials - Property of IBM # # 5608-E01 # 5608-E02 # # (C) Copyright International Business Machines Corp. 2010. # All rights reserved. # # US Government Users Restricted Rights - Use, duplication or disclosure # restricted by GSA ADP Schedule Contract with IBM Corp. # ############################################################################# # # NAME: dsmcvt2tcp # # FUNCTION: This script converts a TSM V6 database (TSMDB1) from using IPC # db2 connections to TCP/IP db2 connections. # # USAGE: See the "usage" function further down in the script # # This script requires the ksh93 version of korn shell. # # This script must be run as root. # # This script will: # 1. Verify that IP Security is configured for both IPv4 and IPv6, # configuring it if requested (-c, and, optionally, -4). # 2. Verify that the current TSMDB1 database in the instance is # configured for local connections. # 3. Reconfigure the database to use TCP/IP connections # 4. Create IP Security filter rules to limit access to the # DB2 service port to the localhost only. This is not performed # if -n is specified. # # Change History: # V1.0 - Initial Version - April 14, 2010 # ############################################################################# #------------------------------------------------------------------------------- # DB2 limitations are 8 characters or less for NODENAME, LOCALDB, and REMOTEDB #------------------------------------------------------------------------------- NODENAME=LOOPBK LOCALDB=TSMDB1 REMOTEDB=TSMDB1_L integer verbose=0 # set to 1 to see progress messages, set to 2 to see even more #------------------------------------------------------------------------------- # Do a quick check to make sure we're on AIX #------------------------------------------------------------------------------- if [[ "`uname -s`" != "AIX" ]]; then echo This script is for AIX only exit 9 fi #------------------------------------------------------------------------------- # Make sure we're root #------------------------------------------------------------------------------- if [[ `id -u` != 0 ]]; then echo "This script must be run as root" exit 13 fi #------------------------------------------------------------------------------- # Usage #------------------------------------------------------------------------------- usage() { echo "\n$(basename $1) [-c4nh] instance_name" echo " where" echo " -c\t\t\tspecifies that the IP Security devices (ipsec_v4 and " echo " \t\t\t ipsec_v6) should be configured" echo " -4\t\t\tspecifies that only IPv4 is to be configured, and that" echo " \t\t\t only IPv4 filter rules are to be defined" echo " -n\t\t\tspecifies that no IP Security is to be configured and" echo " \t\t\t that no filter rules are to be defined" echo " -h\t\t\tdisplays this help message" echo " instance_name\tis the name of the instance to modify" echo "" echo " Configuring IP Security is a two-step process. The first step is to turn" echo " on IP Security filtering by creating the ipsec_v4 and ipsec_v6 devices. The" echo " \"lsdev | grep ipsec\" command will show if they exist, are \"Defined\", or are" echo " \"Available\". They must be \"Available\" for this script to execute, unless -n" echo " is specified to bypass all IP Security, or -4 is specified to limit setup to" echo " IPv4 only. If the devices are not \"Available\", the -c option will configure" echo " them. If you want to set up only IPv4 filtering, you can use -c4 to" echo " configure just the ipsec_v4 device." echo "" echo " The second step is to create filter rules to actually block access to the" echo " port from other systems. This is done after the conversion, and uses the" echo " genfilt and mkfilt commands to create the rules to allow access to the port" echo " from localhost, but deny access to the port from all other systems. Both" echo " IPv4 and IPv6 filter rules are created, unless -4 is specified to create" echo " only IPv4 rules, or -n is specified to create no rules." } #------------------------------------------------------------------------------- # Parse the command-line flags #------------------------------------------------------------------------------- integer v4Only=0 integer noSec=0 integer configSec=0 while getopts h4nc arg do case $arg in 4) v4Only=1 ;; n) noSec=1 ;; c) configSec=1 ;; *) usage $0 exit 1 ;; esac done if [[ $noSec == 1 && $configSec == 1 ]]; then echo "Do not specify both -c and -n" usage $0 exit 10 fi if [[ $noSec == 1 && $v4Only == 1 ]]; then echo "Do not specify both -4 and -n" usage $0 exit 10 fi shift $(($OPTIND - 1)) #------------------------------------------------------------------------------- # Get the instance name from the command #------------------------------------------------------------------------------- INSTANCE=$1 if [[ "$INSTANCE" == "" ]]; then echo "Instance name not specified" usage $0 exit 14 fi #------------------------------------------------------------------------------- # Validate that the instance exists #------------------------------------------------------------------------------- id $INSTANCE >/dev/null 2>&1 if [[ $? != 0 ]]; then echo "Instance user $INSTANCE does not exist" exit 14 fi /opt/tivoi/tsm/db2/instance/db2ilist $INSTANCE >/dev/null 2>&1 if [[ $? != 0 ]]; then echo "$INSTANCE is not a valid TSM instance" exit 15 fi db2cmd="su - $INSTANCE -c LANG=C db2" #------------------------------------------------------------------------------- # Before proceeding, let's make sure the IPSEC stuff is configured. #------------------------------------------------------------------------------- if [[ $noSec == 0 ]]; then v4Status=`/usr/sbin/ipsecstat -d | grep ipsec_v4 | awk '{print $2}'` v6Status=`/usr/sbin/ipsecstat -d | grep ipsec_v6 | awk '{print $2}'` if [[ "$verbose" != 0 ]]; then echo "IPSec for IPv4 status: $v4Status" echo "IPSec for IPv6 status: $v6Status" fi if [[ "$v4Status" != "Available" ]]; then if [[ $configSec == 1 ]]; then echo "Configuring IP Security for IPv4" /usr/sbin/mkdev -c ipsec -t 4 /usr/sbin/mkfilt -v 4 -u -z p else echo "IP Security for IPv4 is not configured" echo "Configure it manually, or specify -c to autoconfigure it" exit 10 fi fi if [[ "$v6Status" != "Available" ]]; then if [[ $v4Only != 1 ]]; then if [[ $configSec == 1 ]]; then echo "Configuring IP Security for IPv6" /usr/sbin/mkdev -c ipsec -t 6 /usr/sbin/mkfilt -v 6 -u -z p else echo "IP Security for IPv6 is not configured" echo "Configure it manually, specify -c to autoconfigure it, or specify -4 to bypass" exit 11 fi fi fi fi SERVICE=DB2_${INSTANCE} #------------------------------------------------------------------------------- # The following arrays are for the database directory #------------------------------------------------------------------------------- integer dbCount dbIndex dbExists dbIsLocal set -A dbAlias set -A dbNode set -A dbName set -A dbType set -A dbDir #------------------------------------------------------------------------------- # The following arrays are for the node directory #------------------------------------------------------------------------------- integer nodeCount nodeIndex nodeExists set -A nodeName set -A nodeType set -A nodeHostname set -A nodeService #------------------------------------------------------------------------------- # DB2 must be running for this to work, but all connections must be stopped #------------------------------------------------------------------------------- $db2cmd stop dbm force $db2cmd start dbm #------------------------------------------------------------------------------- # This function parses the information from DB2 LIST DATABASE DIRECTORY # into a series of arrays for use by other functions. #------------------------------------------------------------------------------- parseDbDirectory() { integer i=0 dbCount=-1 while read a b c d e f g h i j; do case $a in Database) case $b in alias) dbAlias[$dbCount]=$d ;; name) dbName[$dbCount]=$d ;; *) if [[ "$c" == "entry:" ]]; then dbCount=dbCount+1 fi ;; esac ;; Directory) if [[ "$b" == "entry" && "$c" == "type" ]]; then dbType[$dbCount]=$e # Either Indirect or Remote fi ;; Local) if [[ "$b" == "database" && "$c" == "directory" ]]; then dbDir[$dbCount]=$e fi ;; Node) dbNode[$dbCount]=$d ;; *) ;; esac done if [[ $verbose == 2 ]]; then while [[ $i -le $dbCount ]]; do echo "For entry " $i echo " dbName is " ${dbName[$i]} echo " dbAlias is " ${dbAlias[$i]} echo " dbType is " ${dbType[$i]} echo " dbDir is " ${dbDir[$i]} echo " dbNode is " ${dbNode[$i]} ((i+=1)) done fi } #------------------------------------------------------------------------------- # This function checks to see if the indicated database exists #------------------------------------------------------------------------------- checkDBExists() { integer i=0 typeset -u dbToCheck=$1 dbExists=0 if [[ $verbose != 0 ]]; then echo "Checking to see if database $dbToCheck exists" fi while [[ $i -le $dbCount ]]; do if [[ "${dbName[$i]}" == "$dbToCheck" ]]; then echo "$dbToCheck exists as a database name" dbExists=1 fi if [[ "${dbAlias[$i]}" == "$dbToCheck" ]]; then echo "$dbToCheck exists as a database alias" dbExists=1 fi ((i+=1)) done if [[ $verbose != 0 ]]; then if [[ $dbExists == 1 ]]; then echo "Database $dbToCheck exists" else echo "Database $dbToCheck does not exist" fi fi } #------------------------------------------------------------------------------- # This function checks to see if the indicated database is local. A # database is local if the name and alias are the same and the type # is indirect. Anything else means a non-standard configuration #------------------------------------------------------------------------------- checkDBLocal() { integer i=0 typeset -u dbToCheck=$1 dbExists=0 dbIsLocal=1 if [[ $verbose != 0 ]]; then echo "Checking to see if database $dbToCheck exists and is local" fi while [[ $i -le $dbCount ]]; do if [ "${dbName[$i]}" == "$dbToCheck" ]; then if [[ $verbose != 0 ]]; then echo "Database $dbToCheck exits - validating" fi dbExists=1 dbIndex=$i if [[ "${dbType[$i]}" != "Indirect" ]]; then echo "Database type of $dbToCheck is not Indirect" dbIsLocal=0 fi if [[ "${dbName[$i]}" != "${dbAlias[$i]}" ]]; then echo "Database name (${dbName[$i]}) does not match alias (${dbAlias[$i]})" dbIsLocal=0 fi if [[ $verbose != 0 ]]; then if [[ $dbIsLocal == 1 ]]; then echo "Checking complete - database is local" else echo "Checking complete - database is not local" fi fi break; fi ((i+=1)) done if [[ $verbose != 0 && $dbExists = 0 ]]; then echo "Database $dbToCheck does not exist" fi } #------------------------------------------------------------------------------- # This function parses the information from DB2 LIST NODE DIRECTORY # into a series of arrays for use by other functions. #------------------------------------------------------------------------------- parseNodeDirectory() { integer i nodeCount=-1 while read a b c d e f g h i j; do case $a in Node) case $b in name) nodeName[$nodeCount]=$d ;; *) if [[ "$c" == "entry:" ]]; then nodeCount=nodeCount+1 fi ;; esac ;; Directory) if [[ "$b" == "entry" && "$c" == "type" ]]; then nodeType[$nodeCount]=$e # Should be LOCAL fi ;; Hostname) nodeHostname[$nodeCount]=$c ;; Service) if [[ "$b" == "name" ]]; then nodeService[$nodeCount]=$d fi ;; *) ;; esac done if [[ $verbose == 2 ]]; then while [[ $i -le $nodeCount ]]; do echo "For entry " $i echo " nodeName is " ${nodeName[$i]} echo " nodeType is " ${nodeType[$i]} echo " nodeHost is " ${nodeHostname[$i]} echo " nodeService is " ${nodeService[$i]} ((i+=1)) done fi } #------------------------------------------------------------------------------- # This function checks to see if the node exists. We cannot catalog a node # that already exists, so we need to make sure it doesn't exist. However, # if it does exist, and is properly configured, we can use it. #------------------------------------------------------------------------------- checkNode() { integer i typeset -u nodeToCheck=$1 if [ $verbose != 0 ]; then echo "Checking to see if node $nodeToCheck exists" fi nodeExists=0 nodeOk=1 while [[ $i -le $nodeCount ]]; do if [[ "${nodeName[$i]}" == "$nodeToCheck" ]]; then if [[ $verbose != 0 ]]; then echo "Node $nodeToCheck exits - validating" fi nodeExists=1 nodeIndex=$i if [[ "${nodeType[$i]}" != "LOCAL" ]]; then echo "Node type of node $nodeToCheck is not LOCAL" nodeOk=0 fi if [[ "${nodeHostname[$i]}" != "127.0.0.1" && "${nodeHostname[$i]}" != "localhost" ]]; then echo "Hostname for node $nodeToCheck is not 127.0.0.1 or localhost" nodeOk=0 fi # # Make sure the service is configured properly # checkService ${nodeService[$i]} if [[ $serviceExists == 0 ]]; then echo "Service ${nodeService[$i]} does not exist in /etc/services" nodeOk=0 fi if [ $verbose != 0 ]; then if [ $nodeOk == 1 ]; then echo "Checking complete - node is valid" else echo "Checking complete - node is invalid" fi fi break; fi ((i+=1)) done if [[ $verbose != 0 && $nodeExists == 0 ]]; then echo "Node $nodeToCheck does not exist" fi } #------------------------------------------------------------------------------- # This function checks to see if the named service exists in /etc/services. # If it doesn't exist, this would indicate a setup failure for the instance. #------------------------------------------------------------------------------- checkService() { service=$1 if [[ $verbose != 0 ]]; then echo "Validating service $service in /etc/services" fi grep -q $service /etc/services if [[ $? != 0 ]]; then echo "Entry ${service} is missing from /etc/services" serviceExists=0 fi grep -q ${service}_1 /etc/services if [[ $? != 0 ]]; then echo "Entry ${service}_1 is missing from /etc/services" serviceExists=0 fi grep -q ${service}_2 /etc/services if [[ $? != 0 ]]; then echo "Entry ${service}_2 is missing from /etc/services" serviceExists=0 fi grep -q ${service}_END /etc/services if [[ $? != 0 ]]; then echo "Entry ${service}_END is missing from /etc/services" serviceExists=0 fi } #------------------------------------------------------------------------------- # As part of error recovery, this recatalogs the local database #------------------------------------------------------------------------------- recatalogDB() { echo "Cleaning up from failed conversion" $db2cmd uncatalog database $LOCALDB $db2cmd uncatalog database $REMOTEDB $db2cmd catalog database $LOCALDB on ${dbDir[$dbIndex]} if [[ $? == 0 ]]; then echo "Recataloged local database $LOCALDB" else echo "An error occurred recataloging database" echo "The command to use is: db2 catalog database $LOCALDB on ${dbDir[$dbIndex]}" fi $db2cmd stop dbm } #------------------------------------------------------------------------------- # Set up the NODE arrays #------------------------------------------------------------------------------- if [[ $verbose != 0 ]]; then echo "Parsing output of DB2 LIST NODE DIRECTORY command" fi $db2cmd list node directory | parseNodeDirectory # # Make sure the loopbk node isn't defined, or if it is defined, # it is set up properly # checkNode $NODENAME if [[ $nodeExists == 1 && $nodeOk == 0 ]]; then echo "Node LOOPBK already exists but is not configured correctly" exit 1 fi #------------------------------------------------------------------------------- # Set up the DB arrays #------------------------------------------------------------------------------- if [[ $verbose != 0 ]]; then echo "Parsing output of DB2 LIST DATABASE DIRECTORY command" fi $db2cmd list database directory | parseDbDirectory checkDBExists $REMOTEDB if [[ $dbExists == 1 ]]; then echo "Database $REMOTEDB exists - Terminating" exit 2 fi checkDBLocal ${LOCALDB} if [[ $dbExists == 1 ]]; then if [[ $dbIsLocal == 0 ]]; then echo "Database $LOCALDB cannot be converted - database is not local" exit 3 fi else echo "Database $LOCALDB cannot be convert - database not found" exit 4 fi #------------------------------------------------------------------------------- # Make sure the service for the instance is set up properly #------------------------------------------------------------------------------- checkService ${INSTANCE} if [[ $serviceExists == 0 ]]; then echo "Entries in /etc/services for instance $INSTANCE are missing" exit 4 fi #------------------------------------------------------------------------------- # At this point, we know that the database exists and is local. We also know that # the "remote" variation of the name does not exist, and we know that the node # either doesn't exist, or is configured properly. Furthermore, the service we # are going to use is set up in /etc/services. We're all set to proceed. #------------------------------------------------------------------------------- #------------------------------------------------------------------------------- # First, uncatalog the local database #------------------------------------------------------------------------------- if [[ $verbose != 0 ]]; then echo "Uncataloging local database $LOCALDB" fi $db2cmd uncatalog database $LOCALDB if [[ $? != 0 ]]; then echo "Error uncataloging local database $LOCALDB" exit 5 fi #------------------------------------------------------------------------------- # Next, catalog the node if we need to #------------------------------------------------------------------------------- if [[ $nodeExists == 0 ]]; then if [[ $verbose != 0 ]]; then echo "Cataloging TCPIP node $NODENAME" fi $db2cmd catalog tcpip node $NODENAME remote 127.0.0.1 server ${SERVICE} if [[ $? != 0 ]]; then echo "Error cataloging node $NODENAME for 127.0.0.1 using service $SERVICE" recatalogDB exit 5 fi echo "Created node $NODENAME for localhost using service $SERVICE" fi #------------------------------------------------------------------------------- # Next, recatalog the database using the remote alias. #------------------------------------------------------------------------------- if [[ $verbose != 0 ]]; then echo "Cataloging database $LOCALDB as alias $REMOTEDB" fi $db2cmd catalog database $LOCALDB as $REMOTEDB on ${dbDir[$dbIndex]} if [[ $? != 0 ]]; then echo "Error cataloging $LOCALDB under name $REMOTEDB" recatalogDB exit 6 fi #------------------------------------------------------------------------------- # Next, catalog the local name as an alias to the remote name using # the node we just set up #------------------------------------------------------------------------------- if [[ $verbose != 0 ]]; then echo "Cataloging database $REMOTEDB as alias to $LOCALDB using node $NODENAME" fi $db2cmd catalog database $REMOTEDB as $LOCALDB at node $NODENAME if [[ $? != 0 ]]; then echo "Error cataloging $REMOTEDB under name $LOCALDB on remote node $NODENAME" recatalogDB exit 6 fi #------------------------------------------------------------------------------- # Next, configure the DB2 instance to use TCPIP with the correct service #------------------------------------------------------------------------------- if [[ $verbose != 0 ]]; then echo "Updating the DBM CONFIG for instance $INSTANCE" fi $db2cmd update dbm cfg using AUTHENTICATION CLIENT if [[ $? != 0 ]]; then echo "Error updating DBM CONFIG to use CLIENT authentication" recatalogDB exit 7 fi $db2cmd update dbm cfg using TRUST_CLNTAUTH CLIENT if [[ $? != 0 ]]; then echo "Error updating DBM CONFIG to use CLIENT for TRUST_CLNTAUTH" recatalogDB exit 7 fi $db2cmd update dbm cfg using SVCENAME ${SERVICE} if [[ $? != 0 ]]; then echo "Error updating DBM CONFIG to use service $SERVICE" recatalogDB exit 7 fi $db2cmd update dbm cfg using NUM_POOLAGENTS 0 if [[ $? != 0 ]]; then echo "Error updating DBM CONFIG to turn off connection pooling" fi if [[ $verbose != 0 ]]; then echo "Setting instance $INSTANCE to use TCPIP" fi ${db2cmd}set -i $INSTANCE DB2COMM=TCPIP if [[ $? != 0 ]]; then echo "Error setting instance $INSTANCE to use TCP/IP communications" echo "Issue the \"db2set -i $INSTANCE DB2COMM=TCPIP\" command" ${db2cmd} stop dbm exit 7 fi if [[ $verbose != 0 ]]; then echo "Stopping DB2" fi ${db2cmd} stop dbm #------------------------------------------------------------------------------- # Define the filters to protect the main port #------------------------------------------------------------------------------- if [[ $noSec == 0 ]]; then mainPort=`grep DB2_${INSTANCE} /etc/services | grep -v DB2_${INSTANCE}_ | awk '{print $2}'` mainPort=${mainPort%%/tcp} #----------------------------------------------------------------------------- # The following rule permits access to the main IP port by localhost #----------------------------------------------------------------------------- /usr/sbin/genfilt -v 4 -a P -s 127.0.0.1 -m 255.255.255.255 -d 0.0.0.0 -i all \ -M 0.0.0.0 -c tcp -o any -p 0 -O eq -P $mainPort -w I if [[ $? != 0 ]]; then echo "Error creating IP Security filter rule - please do this manually:" echo "/usr/sbin/genfilt -v 4 -a P -s 127.0.0.1 -m 255.255.255.255 -d 0.0.0.0"\ " -M 0.0.0.0 -c tcp -o any -p 0 -O eq -P $mainPort -w I" fi #----------------------------------------------------------------------------- # The following rule denies access to the main IP port by all other systems #----------------------------------------------------------------------------- /usr/sbin/genfilt -v 4 -a D -s 0.0.0.0 -m 0.0.0.0 -d 0.0.0.0 -M 0.0.0.0 -c tcp \ -o any -p 0 -O eq -P $mainPort -w I -i all if [[ $? != 0 ]]; then echo "Error creating IP Security filter rule - please do this manually:" echo "/usr/sbin/genfilt -v 4 -a D -s 0.0.0.0 -m 0.0.0.0 -d 0.0.0.0 -M 0.0.0.0"\ " -c tcp -o any -p 0 -O eq -P $mainPort -w I" fi #----------------------------------------------------------------------------- # The following command activates the 2 rules we just created #----------------------------------------------------------------------------- /usr/sbin/mkfilt -v4 -u if [[ $? != 0 ]]; then echo "Error activating the IP Security filter rules - please do this manually:" echo "/usr/sbin/mkfilt -v4 -u" fi if [[ $v4Only == 0 ]]; then #--------------------------------------------------------------------------- # The following rule permits access to the main IP port by localhost #--------------------------------------------------------------------------- /usr/sbin/genfilt -v 6 -a P -s "::1" -m "128" -d 0 -M 0 -i all \ -c tcp -o any -p 0 -O eq -P $mainPort -w I if [[ $? != 0 ]]; then echo "Error creating IP Security filter rule - please do this manually:" echo "/usr/sbin/genfilt -v 6 -a P -s "::1" -m "128" -d 0 -i all " \ " -M 0 -c tcp -o any -p 0 -O eq -P $mainPort -w I" fi #--------------------------------------------------------------------------- # The following rule denies access to the main IP port by all other systems #--------------------------------------------------------------------------- /usr/sbin/genfilt -v 6 -a D -s 0 -m 0 -d 0 -M 0 -i all \ -c tcp -o any -p 0 -O eq -P $mainPort -w I if [[ $? != 0 ]]; then echo "Error creating IP Security filter rule - please do this manually:" echo "/usr/sbin/genfilt -v 6 -a D -s 0 -m 0 -d 0 -M 0 -i all " \ " -c tcp -o any -p 0 -O eq -P $mainPort -w I" fi #--------------------------------------------------------------------------- # The following command activates the 2 rules we just created #--------------------------------------------------------------------------- /usr/sbin/mkfilt -v6 -u if [[ $? != 0 ]]; then echo "Error activating the IP Security filter rules - please do this manually:" echo "/usr/sbin/mkfilt -v6 -u" fi fi fi echo "Conversion completed successfully"