#Author: Shivam Anand #Date Created : 03/31/2005 #Contains all perl Secure Utilities. #shianand - 27/7/2005 - fix bug 4149565 #shianand - 04/12/06 - fix bug 5158248 #shianand - 11/04/06 - fix bug 4766676 #shianand - 07/24/06 - fix bug 4571079 (remove mkwallet implmentation) #shianand - 08/29/06 - fix bug 5491469 (include oracle/jlib/ojpse.jar in classpath) #shianand - 08/29/06 - fix bug 5518632 (getConsole mode for 10.2 RAC DB) #shianand - 09/25/06 - fix bug 5556081 use English; use strict; use File::Copy; use File::Path; use IPC::Open2; package SecureUtil; my $ORACLE_HOME = $ENV{ORACLE_HOME}; my $EMDROOT = $ENV{EMDROOT}; my $JAVA_HOME = $ENV{JAVA_HOME}; my $JRE_HOME = $ENV{JRE_HOME}; my $DEFAULT_CLASSPATH = $ENV{DEFAULT_CLASSPATH}; my $emUploadHTTPPort = $ENV{EM_UPLOAD_PORT}; my $emUploadHTTPSPort = $ENV{EM_UPLOAD_HTTPS_PORT}; my $IS_WINDOWS = ""; my $cpSep = ":"; my $tempDir = "/tmp"; my $redirectStderr = "2>&1"; my $emWalletsDir = "$ORACLE_HOME/sysman/wallets"; my $emConfigDir = "$ORACLE_HOME/sysman/config"; my $initialKeystorePassword; my $OSNAME = $^O; if( ($OSNAME eq "MSWin32") or ($OSNAME eq "Windows_NT") ) { $IS_WINDOWS="TRUE"; $tempDir = $ENV{TEMP}; $redirectStderr = ""; $cpSep = ";"; } else { $IS_WINDOWS="FALSE"; } my $securelog = "$ORACLE_HOME/sysman/log/secure.log"; my $debug = "false"; sub setDebug { $debug = $_[0]; if($debug ne "") { $debug = "true"; } else { $debug = "false"; } } sub getDebug { return $debug; } sub setLogFile { if ($_[0] eq "") { $securelog = "$ORACLE_HOME/sysman/log/secure.log"; } elsif (defined($_[0])) { $securelog = $_[0]; } } sub getLogFile { return $securelog; } # # Get the type of OMS that is to be secured. It is one of the following: # # "CENTRAL" - a central OMS using a Repository. # "DBCONSOLE" - a standalone oc4j usiing a repository # "STANDALONE" - a standalone oc4j without a repository. # sub getConsoleMode { my (@args) = @_; my $propertiesFile = "$ORACLE_HOME/sysman/config/emoms.properties"; my $consoleModeProperty = "oracle.sysman.emSDK.svlt.ConsoleMode"; my %omsProps; # # if there is no emoms.properties then this is an iAS Standalone Console # using a Stand Alone OC4J # -> "STANDALONE" # # if there is an emoms.properties but no ConsoleMode then this is a # a Central OMS using an iAS Core # -> "CENTRAL" # # if there is an emoms.properties and it has a ConsoleMode set to # dbStandalone then this is a DBA Studio Standalone Console # using a Stand Alone OC4J # -> "STANDALONE" # # if there is an emoms.properties and it has a ConsoleMode set to # standalone then this is a Database Standalone Console using a # Stand Alone OC4J with a local Agent and Repository # -> "DBCONSOLE" # # if there is an emoms.properties and it has a ConsoleMode set to # some other value then we don't know what this is.. # my $emConsoleMode = ""; if (-e $propertiesFile) { %omsProps = &parseFile($propertiesFile); if (defined($omsProps{$consoleModeProperty})) { my $propValue = $omsProps{$consoleModeProperty}; if ($propValue eq "dbStandalone") { $emConsoleMode = "STANDALONE"; } if ($propValue eq "standalone") { $emConsoleMode = "DBCONSOLE"; } } else { $emConsoleMode = "CENTRAL"; } } else { $emConsoleMode = "STANDALONE"; } my $oracleUnqname = ""; my $topDir = ""; my $stateDir = ""; my $propState = ""; if ($emConsoleMode eq "STANDALONE") { my $HOST_SID_OFFSET_ENABLED = $ENV{HOST_SID_OFFSET_ENABLED}; if ($HOST_SID_OFFSET_ENABLED eq "host_sid") { $oracleUnqname = &EmctlCommon::getOracleUniqueName($ENV{ORACLE_HOME}, $ENV{ORACLE_SID}); if ($oracleUnqname ne "") { $topDir = &EmctlCommon::getLocalHostName(); #for 10.2 dbcontrol, use node name for RAC if(substr($ENV{EMPRODVER},0,4) ne "10.1") { if (defined($ENV{CRS_HOME}) and ($ENV{CRS_HOME} ne "#CRS_HOME#")) { # if we are in RAC, use the local node name $topDir = &EmctlCommon::getLocalRACNode(); if ($topDir eq "") { $topDir = &EmctlCommon::getLocalHostName(); } } } $stateDir = $topDir."_".$oracleUnqname; $propState = "$ORACLE_HOME/$stateDir/sysman/config/emoms.properties"; if (-e $propState) { $emConsoleMode = "DBCONSOLE"; } } else { print "Environment variable ORACLE_UNQNAME not defined. Please define it. \n"; } } } return $emConsoleMode; } sub getConsoleClassPath { my (@args) = @_; my $consoleMode = $args[0]; my $emLibDir = "$ORACLE_HOME/j2ee/OC4J_EM/applications/em/em/WEB-INF/lib"; my $emJarFile = "emCORE.jar"; if ($consoleMode eq "") { # If not specified, calculate it. $consoleMode = &getConsoleMode; } DEBUG ("consoleMode = $consoleMode"); DEBUG ("emLibDir = $emLibDir"); if ($consoleMode eq "CENTRAL") { $emLibDir = "$ORACLE_HOME/j2ee/OC4J_EM/applications/em/em/WEB-INF/lib"; $emJarFile = "emCORE.jar" } elsif ($consoleMode eq "DBCONSOLE") { $emLibDir = "$EMDROOT/sysman/jlib"; $emJarFile = "emCORE.jar" } elsif ($consoleMode eq "STANDALONE") { $emLibDir = "$EMDROOT/sysman/webapps/emd/WEB-INF/lib"; $emJarFile = "emd.jar" } DEBUG ("emLibDir = $emLibDir"); DEBUG ("emdroot = $EMDROOT"); # adding oracle_home/jlib/ojpse.jar from DB11 bug 5491469 # keeping oracle_home/encryption/jlib/ojpse.jar for backward compatibility my $consoleClassPath = "$DEFAULT_CLASSPATH". "$cpSep$ORACLE_HOME/oc4j/lib/dms.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/ojdbc5dms.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-mapping.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-translation.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-net-ee.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-utility.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-collation.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-net.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-internal.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-servlet.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-lcsd.jar". "$cpSep$ORACLE_HOME/oc4j/jdbc/lib/orai18n-tools.jar". "$cpSep$ORACLE_HOME/jlib/uix2.jar". "$cpSep$ORACLE_HOME/jlib/share.jar". "$cpSep$ORACLE_HOME/jlib/ojmisc.jar". "$cpSep$ORACLE_HOME/jlib/ojpse.jar". "$cpSep$ORACLE_HOME/lib/xmlparserv2.jar". "$cpSep$ORACLE_HOME/lib/emagentSDK.jar". "$cpSep$ORACLE_HOME/encryption/jlib/ojpse.jar". "$cpSep$ORACLE_HOME/jlib/http_client.jar". "$cpSep$ORACLE_HOME/j2ee/home/lib/http_client.jar". "$cpSep$emLibDir/log4j-core.jar". "$cpSep$EMDROOT/sysman/jlib/emagentSDK.jar". "$cpSep$emLibDir/$emJarFile"; return $consoleClassPath; } sub getOC4JHome { my (@args) = @_; my $consoleMode = $args[0]; my $oc4jHomeDir = ""; if ($consoleMode eq "") { # If not specified, calculate it. $consoleMode = &getConsoleMode; } if ($consoleMode eq "CENTRAL") { } elsif ($consoleMode eq "DBCONSOLE") { $oc4jHomeDir = &EmctlCommon::getOC4JHome("dbconsole"); } elsif ($consoleMode eq "STANDALONE") { $oc4jHomeDir = &EmctlCommon::getOC4JHome("iasconsole"); } return $oc4jHomeDir; } sub getEMHome { my (@args) = @_; my $consoleMode = $args[0]; my $emHome = ""; # For OMS and agent, use ORACLE_HOME # For DBConsole, use EmctlCommom.getHome as it gets the $OH/host_sid home # For IASConsole, use EmctlCommon.getHome. if (($consoleMode eq undef) || ($consoleMode eq "") ) { $emHome = $ORACLE_HOME; } elsif ($consoleMode eq "DBCONSOLE") { $emHome = &EmctlCommon::getEMHome("dbconsole"); } elsif ($consoleMode eq "STANDALONE") { $emHome = &EmctlCommon::getEMHome("iasconsole"); } elsif ($consoleMode eq "CENTRAL_AGENT") { $emHome = &EmctlCommon::getEMHome("agent"); } else { $emHome = $ORACLE_HOME; } return $emHome; } # # Get the type of Agent that is to be secured. It is one of the following: # # "CENTRAL_AGENT" - an Agent uploading metrics to an OMS / Repository. # "STANDALONE" - a local Agent belonging to a Standalone Console. # sub getAgentMode { my (@args) = @_; my $propertiesFile = "$EMDROOT/sysman/config/emd.properties"; my $agentModeProperty = "REPOSITORY_URL"; my $emAgentMode = ""; my %agentProps; if (-e $propertiesFile) { %agentProps = &parseFile($propertiesFile); if (defined($agentProps{$agentModeProperty})) { my $propValue = $agentProps{$agentModeProperty}; if (not $propValue eq "") { # a value for the REPOSITORY_URL means a Central Agent $emAgentMode = "CENTRAL_AGENT"; } else { # no value for the REPOSITORY_URL means a Standalone Agent $emAgentMode = "STANDALONE"; } } else { # no REPOSITORY_URL means a Standalone Agent $emAgentMode = "STANDALONE"; } } return $emAgentMode; } sub getAgentHostname { my (@args) = @_; my $emHome = $args[0]; my $propertiesFile = "$emHome/sysman/config/emd.properties"; my $emdUrlProperty = "EMD_URL"; my $emdUrl = ""; my $agentHostname = ""; my $agentPort = ""; if (-e $propertiesFile) { my (%agentProps) = &parseFile($propertiesFile); if (defined($agentProps{$emdUrlProperty})) { $emdUrl = $agentProps{$emdUrlProperty}; my ($protocol,$machine,$port,$ssl) = parseURL($emdUrl); $agentHostname = $machine; $agentPort = $port; } } return ($agentHostname, $agentPort); } sub getAgentClassPath { my (@args) = @_; my $propertiesFile = "$EMDROOT/sysman/config/emd.properties"; my $classPathProperty = "CLASSPATH"; my $agentClassPath = ""; if (-e $propertiesFile) { my (%agentProps) = &parseFile($propertiesFile); if (defined($agentProps{$classPathProperty})) { $agentClassPath = $agentProps{$classPathProperty}; } } return $agentClassPath; } # Utilities # [] ----------------------------------------------------------------- [] sub parseURL { ($_) = @_; my $ssl = " "; my ($protocol,$machine,$port) = /([^:]+):\/\/([^:]+):([0-9]+)\/.*/; if (! defined($protocol) ) { $protocol = "na"; $machine = "na"; $port = "na"; } else { $protocol = lc $protocol; if (! defined($port) ) { $port = 80; } if ($protocol eq "https") { $ssl = "Y"; } } return ($protocol,$machine,$port,$ssl); } # [] ----------------------------------------------------------------- [] sub parseFile { my($fname) = @_; my %lprop; if (! -T $fname ) { print "File $fname is not a text file\n"; next; } open(FILE,$fname) or die "Can not read file: $fname\n$!\n"; while () { ;# Remove leading and traling whitespaces s/^\s+|\s+$//; s/#.*$//g; ;# Validate each non-empty line if (! /^$/) { my($name,$value) = /([^=]+)\s*=\s*(.+)/; if (defined($name) && defined($value)) { $name =~ s/^\s+|\s+$//g; $value =~ s/^\s+|\s+$//g; $lprop{$name} = $value; } } } close(FILE); ;# Return success return %lprop; } # [] ----------------------------------------------------------------- [] sub write_to_file { my($fname,$msg) = @_; chomp($msg); if ( open(OUTPUT_FILE,">>" . $fname) ) { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); if ($year<=1000) { $year += 1900;} $mon += 1; my $prefix = sprintf("%02d-%02d-%4d %02d:%02d:%02d", $mday,$mon,$year,$hour,$min,$sec); printf(OUTPUT_FILE "[%s] %s\n",$prefix, $msg); close(OUTPUT_FILE); } } # [] ----------------------------------------------------------------- [] sub USERINFO { my $msg = $_[0]; my $verbose_mode = $debug; write_to_file($securelog, "USERINFO ::$msg"); print "$msg"; } # [] ----------------------------------------------------------------- [] sub INFO { my $msg = $_[0]; my $verbose_mode = $debug; write_to_file($securelog, "INFO ::$msg"); } # [] ----------------------------------------------------------------- [] sub DEBUG { my $msg = $_[0]; my $verbose_mode = $debug; if ($verbose_mode eq "true") { write_to_file($securelog, "DEBUG ::$msg"); } } # [] ----------------------------------------------------------------- [] sub REPLACE { my (@args) = @_; my $in_file = $args[0]; my $out_file = $args[1]; my @var_names = @{$args[2]}; my @var_values = @{$args[3]}; # my ($in_file, $out_file, *var_names, *var_values) = @_; DEBUG("Creating out file $out_file with in file = $in_file"); DEBUG("Count Var names = $#var_names Values = $#var_values"); for (my $i = 0; $i < @var_names; $i++) { DEBUG("Replacing [$var_names[$i]] with [$var_values[$i]]"); } # backup the existing out_file CP($out_file, "$out_file.bak.$$"); open(INFILE, "$in_file") || die "Could not open $in_file\n"; open(OUTFILE, ">$out_file") || die "Could not open $out_file\n"; #loop through in_file and do substitutions while() { for(my $i = 0; $i < @var_names; $i++) { $_ =~ s/$var_names[$i]/$var_values[$i]/g; } print OUTFILE; } close(INFILE); close(OUTFILE); return 0; } # [] ----------------------------------------------------------------- [] sub APPEND { # Append f1 to f2. my ($f1, $f2) = @_; CAT(">>", $f1, $f2); return 0; } # [] ----------------------------------------------------------------- [] sub CAT { # Concatenate f1 to f2. my ($direct, $f1, $f2) = @_; my @linesRead; open(FILE, $f1) or die "Can not read $f1"; @linesRead = ; close(FILE); if ( open(FILE, $direct . $f2) ) { foreach $_ (@linesRead) { print(FILE $_); } close(FILE); } else { die "Can not write $f2"; } DEBUG ("Concatenated $f1 to $f2"); return 0; } # [] ----------------------------------------------------------------- [] sub CATFILE { my ($my_filename) = @_; return 0; } # [] ----------------------------------------------------------------- [] sub CP { my ($f1, $f2) = @_; my $rc = File::Copy::copy($f1, $f2); if ($rc eq 1) { DEBUG ("Successfully Copied $f1 to $f2"); } else { DEBUG ("Failed to copy $f1 to $f2 retval = $rc"); } return 0; } # [] ----------------------------------------------------------------- [] sub ECHO { my($direct,$my_filename,$msg) = @_; if ( open(FILE,$direct . $my_filename) ) { printf(FILE "%s\n",$msg); close(FILE); } else { print "$msg\n"; } } # [] ----------------------------------------------------------------- [] sub MKDIRP { my ($dir) = @_; File::Path::mkpath($dir); DEBUG ("Creating directory $dir"); return 0; } # [] ----------------------------------------------------------------- [] sub RMRF { my ($rmDir) = @_; File::Path::rmtree($rmDir); DEBUG ("Removed directory $rmDir"); return 0; } # [] ----------------------------------------------------------------- [] sub RM { my ($rmFile) = @_; unlink $rmFile; DEBUG ("Removed file $rmFile"); return 0; } # [] ----------------------------------------------------------------- [] sub secureGenKeystore { my $securelog = $_[0]; my $emConsoleMode = $_[1]; my $thisDNSHost = $_[2]; my $rootKeyPassword = $_[3]; my $useOMSRootKey = $_[4]; my $execStr; my $javaStr; my $rc; my $rootKeyDir; my $endDate = "010110"; my $validityDays = "360"; my $keySize = "512"; my $rootKeyCertFile = ""; SecureUtil::setDebug($ENV{EM_SECURE_VERBOSE}); $debug = SecureUtil::getDebug; my $classPath = &SecureUtil::getConsoleClassPath($emConsoleMode); my $oc4jHome = &SecureUtil::getOC4JHome($emConsoleMode); my $emHome = &SecureUtil::getEMHome($emConsoleMode); my $emLibDir = "$ORACLE_HOME/sysman/webapps/emd/WEB-INF/lib"; my $keystorePasswd = "$JAVA_HOME/bin/java ". "-cp $classPath ". "oracle.sysman.util.crypt.Verifier -genPassword"; my $keystorePasswdKey = `$keystorePasswd`; $keystorePasswdKey =~ s/^\s+|\s+$//; DEBUG ("Key Store Password = $keystorePasswdKey "); $initialKeystorePassword = $keystorePasswdKey; my $keystoreDir = "$oc4jHome/config/server"; if ($debug ne "") { $debug = "true"; } else { $debug = "false"; } SecureUtil::RMRF ($keystoreDir); SecureUtil::MKDIRP ($keystoreDir); # # use the downloaded root cert and rely on the secure OMS for certificate # generation. # $rootKeyCertFile = "$emHome/sysman/config/b64LocalCertificate.txt"; INFO ("Not creating root wallet, using $rootKeyCertFile"); my $serverDN = "cn=$thisDNSHost, o=Oracle"; my $keystoreFile = "$keystoreDir/keystore.test"; my $serverCertReqFile = "$keystoreDir/server.csr"; my $serverCertFile = "$keystoreDir/server.cer"; my $serverKeyAlg = "RSA"; my $serverKeyPassword = "$initialKeystorePassword"; my $serverStorePassword = "$initialKeystorePassword"; # # Generate key.. # INFO ("Key Generation ....\n"); $execStr = "$JAVA_HOME/bin/keytool -genkey ". "-dname \"$serverDN\" ". "-keyalg $serverKeyAlg ". "-keystore $keystoreFile ". "-storepass $serverStorePassword ". "-keypass $serverKeyPassword ". "-validity $validityDays ". ">> $securelog $redirectStderr"; DEBUG ("Executing ... $execStr"); $rc = 0xffff & system($execStr); $rc >>= 8; if ( $rc eq 0 ) { INFO ("Done"); } else { INFO ("Failed rc = $rc"); return $rc; } # # Request for certificate.. # INFO ("Request for certificate..."); $execStr = "$JAVA_HOME/bin/keytool -certreq ". "-keyalg $serverKeyAlg ". "-file $serverCertReqFile ". "-keystore $keystoreFile ". "-storepass $serverStorePassword ". ">> $securelog $redirectStderr"; DEBUG ("Executing ... $execStr"); $rc = 0xffff & system($execStr); $rc >>= 8; if ( $rc eq 0 ) { INFO ("Done"); } else { INFO ("Failed rc = $rc"); return $rc; } INFO ("Certificate Generation ..."); INFO ("Using OMS root key $useOMSRootKey"); SecureUtil::CATFILE ($serverCertReqFile); $rootKeyDir = "$emWalletsDir/ca.$thisDNSHost"; $javaStr = "$JAVA_HOME/bin/java ". " -cp $classPath ". "-DemConsoleMode=$emConsoleMode ". " -Ddebug=$debug ". "-DrootKeyDir=$rootKeyDir ". "-DORACLE_HOME=$ORACLE_HOME ". "-DrepositoryPropertiesFile=$emHome/sysman/config/emoms.properties ". "-Ddebug=$debug ". "oracle.sysman.eml.sec.fsc.FSWalletUtil ". "-gencert $serverCertReqFile $serverCertFile $rootKeyPassword ". ">> $securelog $redirectStderr"; DEBUG ("Executing .. $javaStr"); $rc = 0xffff & system($javaStr); $rc >>= 8; if ($rc eq 0) { INFO ("Done"); } else { INFO ("Failed to Generate Certificate. rc = $rc"); return $rc } INFO ("Certificate obtained:\n"); SecureUtil::CATFILE ($serverCertFile); # Import Root certificate. INFO ("Importing Root certificate ...\n"); $execStr = "$JAVA_HOME/bin/keytool -import ". "-alias testrootca ". "-file $rootKeyCertFile ". "-keystore $keystoreFile ". "-storepass $serverStorePassword ". "-noprompt ". ">> $securelog $redirectStderr"; DEBUG ("Executing ... $execStr"); $rc = 0xffff & system($execStr); $rc >>= 8; if ( $rc eq 0 ) { INFO ("Done"); } else { INFO ("Failed rc = $rc"); return $rc; } # Import the certificate response to keystore INFO ("Importing Certificate Response ..."); $execStr = "$JAVA_HOME/bin/keytool -import ". "-trustcacerts ". "-keyalg $serverKeyAlg ". "-file $serverCertFile ". "-keystore $keystoreFile ". "-storepass $serverStorePassword ". ">> $securelog $redirectStderr"; DEBUG ("Executing ... $execStr"); $rc = 0xffff & system($execStr); $rc >>= 8; if ( $rc eq 0 ) { INFO ("Done"); } else { INFO ("Failed rc = $rc"); return $rc; } SecureUtil::RMRF ($serverCertReqFile); SecureUtil::RMRF ($serverCertFile); return 0; } # [] ----------------------------------------------------------------- [] sub configureEMKeyStore { my $securelog = $_[0]; my $emConsoleMode = $_[1]; my @linesRead; my $rc = 0; my $oc4jHome = &SecureUtil::getOC4JHome($emConsoleMode); my $emWebSiteFile = "$oc4jHome/config/http-web-site.xml"; INFO ("Configuring key store in $emWebSiteFile"); SecureUtil::CP("$emWebSiteFile", "$emWebSiteFile.$$"); open(FILE, $emWebSiteFile) or die "Can not read $emWebSiteFile"; @linesRead = ; close(FILE); my $endTagFound = 0; ;# Walk the lines, and write to new file if ( open(FILE,">" . $emWebSiteFile) ) { foreach $_ (@linesRead) { if (// secure="TRUE">/; } } if (// shared="true" \/>/; } } if (/\n"; $_=$change_key_line; $endTagFound = 1; } if (/<\/web-site>/) { if ($endTagFound == 0) { my $change_key_line = "\t\n<\/web-site>\n"; $_=$change_key_line; } } ;# Print the property line print(FILE $_); } close(FILE); } else { die "Can not write $emWebSiteFile"; } INFO (" Done.\n"); return 0; } # [] ----------------------------------------------------------------- [] sub configureEMDKeyStore { my $securelog = $_[0]; my $emHTTPSPort = $_[1]; my $emSecureEnabled = $_[2]; my $rc = 0; my $emShipHomeStart; my $emShipHomeEnd; DEBUG ("IN_VOB = $EmctlCommon::IN_VOB"); if ($EmctlCommon::IN_VOB eq "TRUE") { $emShipHomeStart = " "; $emShipHomeEnd = " "; } else { $emShipHomeStart = "-->"; $emShipHomeEnd = "', '