diff options
Diffstat (limited to 'base/setup/pkiremove')
-rwxr-xr-x | base/setup/pkiremove | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/base/setup/pkiremove b/base/setup/pkiremove new file mode 100755 index 000000000..dd9fbc7f9 --- /dev/null +++ b/base/setup/pkiremove @@ -0,0 +1,680 @@ +#!/usr/bin/perl +# +# --- BEGIN COPYRIGHT BLOCK --- +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright (C) 2007-2010 Red Hat, Inc. +# All rights reserved. +# --- END COPYRIGHT BLOCK --- +# + +use strict; +use warnings; + +use Getopt::Long qw(GetOptions); + +############################################################## +# This script is used to remove an existing PKI instance. +# +# To execute: +# +# ./pkiremove -pki_instance_root=<pki_instance_root> # Instance root +# # directory destination +# +# -pki_instance_name=<pki_instance_id> # Unique PKI subsystem +# # instance name +# # (e. g. - pki-pki1) +# +# [-token_pwd=<token pw>] # Password of token containing +# # subsystem certificate +# +# [-force] # Don't ask any +# # questions +# +############################################################## + + +############################################################## +# Execution Check +############################################################## + +# Check to insure that this script's original +# invocation directory has not been deleted! +my $cwd = `/bin/pwd`; +chomp $cwd; +if (!$cwd) { + emit("Cannot invoke '$0' from non-existent directory!\n", "error"); + exit 255; +} + +############################################################## +# Environment Variables +############################################################## + +# untaint called subroutines +if (($^O ne 'Windows_NT') && ($^O ne 'MSWin32')) { + $> = $<; # set effective user ID to real UID + $) = $(; # set effective group ID to real GID + $ENV{'PATH'} = '/bin:/usr/bin'; + $ENV{'ENV'} = '' if !defined($ENV{'ENV'}); +} + + +############################################################## +# Command-Line Variables +############################################################## + +my $ARGS = ($#ARGV + 1); + + +############################################################## +# Shared Common Perl Data and Subroutines +############################################################## + +use lib "/usr/share/pki/scripts"; +use pkicommon; + +# make -w happy by suppressing warnings of Global variables used only once +my $suppress = ""; +$suppress = $default_file_permissions; + +############################################################## +# Local Constants +############################################################## + +my $semanage = "/usr/sbin/semanage"; + +############################################################## +# Local Data Structures +############################################################## + + +############################################################## +# Local Variables +############################################################## + +my $pki_instance_root = undef; +my $pki_instance_name = undef; +my $force = 0; +my $token_pwd = ""; + +my $conf_file = undef; +my $pki_instance_path = undef; +my $subsystem_type = undef; + +# PKI init script variables +my $pki_registry_initscript = undef; +my $pki_registry_initscript_command = undef; + +# PKI registry variables +my $pki_registry_subsystem_path = undef; + +#systemd specific variables +my $use_systemd = 0; +my $pki_instance_systemd_service_name = undef; + +############################################################## +# Platform-Dependent Data Initialization +############################################################## + +if ($^O eq "linux") { + if (is_Fedora() && (fedora_release() >= 16)) { + $use_systemd = 1; + } +} else { + emit("Unsupported platform '$^O'!\n", "error"); + exit 255; +} + +############################################################## +# Local Data Initialization +############################################################## + +############################################################## +# PKI Instance Removal Subroutines +############################################################## + +# no args +# no return value +sub usage +{ + print STDOUT <<'EOF'; +Usage: pkiremove -pki_instance_root=<pki_instance_root> # Instance root + # directory + # destination + -pki_instance_name=<pki_instance_id> # Unique PKI + # subsystem + # instance name + # (e. g. - pki-pki1) + # +[-token_pwd=<token password>] # Password for token containing subsystem cert. + +[-force] # Don't ask any questions + +[-verbose] # Display detailed information. May be specified multiple times, + # each time increasing the verbosity level. + +[-dry_run] # Do not perform any actions. + # Just report what would have been done. + +Example: pkiremove -pki_instance_root=/var/lib -pki_instance_name=pki-ca + +IMPORTANT: Must be run as root! +EOF + return; +} + +sub update_domain +{ + my $sport; + my $ncsport; + my $sechost; + my $httpport; + my $seceeport; + my $secagentport; + my $secadminport; + my $adminsport; + my $agentsport; + my $secselect; + my $subsystemnick; + my $machinename; + my $typeval; + my $url; + + get_cs_cfg($conf_file, {"service.machineName" => \$machinename, + "service.securityDomainPort" => \$sport, + "service.non_clientauth_securePort" => \$ncsport, + "securitydomain.host" => \$sechost, + "securitydomain.httpport" => \$httpport, + "securitydomain.httpseeport" => \$seceeport, + "securitydomain.httpsagentport" => \$secagentport, + "securitydomain.httpsadminport" => \$secadminport, + "securitydomain.select" => \$secselect, + "pkicreate.admin_secure_port" => \$adminsport, + "cs.type" => \$typeval, + "pkicreate.agent_secure_port" => \$agentsport}); + + my $subsystemnick_param = lc($typeval) . ".cert.subsystem.nickname"; + get_cs_cfg($conf_file, {$subsystemnick_param => \$subsystemnick}); + + # NOTE: Don't check for the existence of $httpport, as this will + # be undefined for a Security Domain that has been migrated! + if ((!defined($sechost)) || + (!defined($seceeport)) || + (!defined($secagentport)) || + (!defined($secadminport))) { + print(STDOUT "No security domain defined.\nIf this is an unconfigured instance, then that is OK.\n" . + "Otherwise, manually delete the entry from the security domain master.\n"); + return; + } + + die "Subsystem nickname not defined" if (!defined($subsystemnick)); + if (!defined($adminsport)) { + $adminsport = ""; + } + + if (!defined($agentsport)) { + $agentsport = ""; + } + + if (!defined($ncsport)) { + $ncsport = ""; + } + + (my $token_name, my $nick) = split(/:/, $subsystemnick, 2); + if ((!defined($nick)) || ($nick eq "")) { + $token_name = "internal"; + } + + if ($secselect ne "new") { + # This is not a domain master, so we need to update the master + print(STDOUT "Contacting the security domain master to update the security domain\n"); + my $listval = $subsystem_type . "List"; + my $urlheader = "https://" . $sechost . ":" . $seceeport; + my $urlagentheader = "https://" . $sechost . ":" . $secagentport; + my $urladminheader = "https://" . $sechost . ":" . $secadminport; + my $updateURL = "/ca/agent/ca/updateDomainXML"; + + if ($token_pwd eq "") { + my $pwfile = $pki_instance_path . "/conf/password.conf"; + if (-r $pwfile) { + open(DAT, $pwfile) or die "Could not open password.conf file to read token password."; + my @pw_data=<DAT>; + foreach my $line (@pw_data) { + chomp($line); + if (($typeval eq "CA") || + ($typeval eq "KRA") || + ($typeval eq "OCSP") || + ($typeval eq "TKS")) { + (my $varname, my $valname) = split(/=/, $line); + if ($varname eq "hardware-$token_name") { $token_pwd = $valname; } + if ($varname eq "$token_name") { $token_pwd = $valname; } + } else { # TPS, RA + (my $varname, my $valname) = split(/:/, $line); + if ($varname eq $token_name) { $token_pwd = $valname; } + if ($varname eq "hardware-$token_name") { $token_pwd = $valname; } + } + } + close($pwfile); + } + } + + while ($token_pwd eq "") { + $token_pwd = prompt( "No password found for $token_name. What is the password for this token?"); + } + + my $params = "name=$pki_instance_name" . + "&type=$typeval" . + "&list=$listval" . + "&host=$machinename" . + "&sport=$sport" . + "&ncsport=$ncsport" . + "&adminsport=$adminsport" . + "&agentsport=$agentsport" . + "&operation=remove"; + + #update domainXML + my $cmd = `/usr/bin/sslget -d \"$pki_instance_path/alias\" -p \"$token_pwd\" -v -n \"$subsystemnick\" -r \"$updateURL\" -e \"$params\" $sechost:$secagentport 2>&1`; + $cmd =~ /\<Status\>(.*?)\<\/Status\>/; + $cmd = $1; + + die ("Security Domain returns non-zero status for updateDomainXML.") if ($cmd ne "0"); + } +} + +sub remove_fcontext +{ + my ($fcontext, $fname, $ftype, $cmd_ref) = @_; + emit(sprintf("remove_fcontext(%s)\n", join(", ", @_)), "debug"); + + my $tmp = `$semanage fcontext -l -C |grep $fcontext |grep $fname |wc -l`; + chomp $tmp; + if ($tmp eq "0" ) { + emit("File context $fcontext for $fname defined in policy, not deleted", "debug"); + return 0; + } + + if ($ftype eq "f") { + $$cmd_ref .= "fcontext -d -t $fcontext -f -- $fname\n"; + } else { + $$cmd_ref .= "fcontext -d -t $fcontext $fname\n"; + } +} + +sub get_selinux_fcontexts +{ + my ($cmd_ref) = @_; + my $setype = "pki_" . $subsystem_type; + my $default_instance_name = "pki-" . $subsystem_type; + my $default_instance_root = "/var/lib"; + my $default_log_path = "/var/log/" . $default_instance_name; + my $default_conf_path = "/etc/" . $default_instance_name; + + my $log_path = "$pki_instance_path/logs"; + my $conf_path = "$pki_instance_path/conf"; + my $ftype; + my $java_component = 0; + + if (($subsystem_type eq $CA) || + ($subsystem_type eq $KRA) || + ($subsystem_type eq $OCSP) || + ($subsystem_type eq $TKS)) { + $java_component=1; + } + + if (-l $log_path) { + $log_path = readlink $log_path; + }; + + if (-l $conf_path) { + $conf_path = readlink $conf_path; + }; + + # For backwards compatibility, support removal of instances + # which use the legacy start/stop implementation + if (entity_exists("$default_initscripts_path/$pki_instance_name")) { + # remove context for "$default_initscripts_path/$pki_instance_name" + if ($pki_instance_name ne $default_instance_name) { + remove_fcontext($setype . "_script_exec_t", + "/etc/rc\\.d/init\\.d/$pki_instance_name", "f", $cmd_ref); + } + } + + # remove context for $pki_instance_root/$pki_instance_name + if (($pki_instance_name ne $default_instance_name) || ($pki_instance_root ne $default_instance_root)) { + remove_fcontext($setype . "_var_lib_t", + "\"$pki_instance_root/$pki_instance_name(/.*)?\"", "a", $cmd_ref); + } + + # remove context for /var/run/$pki_instance_name.pid + if (($java_component) && ($pki_instance_name ne $default_instance_name)) { + remove_fcontext($setype . "_var_run_t", + "/var/run/$pki_instance_name" . '.pid', "f", $cmd_ref); + } + + # remove context for $log_path + if ($log_path ne $default_log_path) { + remove_fcontext($setype . "_log_t", + "\"$log_path(/.*)?\"", "a", $cmd_ref); + } + + # remove context for $conf_path + if ($conf_path ne $default_conf_path) { + remove_fcontext($setype . "_etc_rw_t", + "\"$conf_path(/.*)?\"", "a", $cmd_ref); + } + +} + + +sub get_selinux_ports +{ + my ($cmd_ref) = @_; + my $status; + my $semanage = "/usr/sbin/semanage"; + my $secure_port; + my $non_clientauth_secure_port; + my $unsecure_port; + my @ports = (); + + get_cs_cfg($conf_file, {"service.securePort" => \$secure_port, + "service.non_clientauth_securePort" => \$non_clientauth_secure_port, + "service.unsecurePort" => \$unsecure_port}); + + if (($subsystem_type eq $CA) || + ($subsystem_type eq $KRA) || + ($subsystem_type eq $OCSP) || + ($subsystem_type eq $TKS)) { + use XML::LibXML; + my $parser = XML::LibXML->new(); + my $config = $parser->parse_file($pki_instance_path . "/conf/server.xml") + or die "Could not read XML from server.xml to determine ports."; + + my $root = $config->getDocumentElement; + + my $i = 0; + foreach my $port ($root->findnodes('//@port')) { + $ports[$i] = $port->getValue(); + $i++; + } + } else { # TPS, RA + my $i =0; + if (defined $secure_port) { + $ports[$i] = $secure_port; + $i++; + } + if (defined $non_clientauth_secure_port) { + $ports[$i] = $non_clientauth_secure_port; + $i++; + } + if (defined $unsecure_port) { + $ports[$i] = $unsecure_port; + $i++; + } + } + + print(STDOUT "\n"); + foreach my $port (@ports) { + my $setype = "pki_" . $subsystem_type . "_port_t"; + my $tmp = `$semanage port -l -C |grep $setype |grep $port | wc -l`; + chomp $tmp; + if ($tmp eq "0") { + emit("Port context $setype for $port defined in policy, not deleting", "debug"); + } else { + $$cmd_ref .= "port -d -t $setype -ptcp $port\n"; + } + } +} + + +# Return 1 if success, 0 if failure +sub remove_instance +{ + my ($result, $confirm, $install_info); + $confirm = "Y"; + $result = 1; + + print(STDOUT "PKI instance Deletion Utility cleaning up instance ...\n\n"); + +ASK_AGAIN: + if (!$force) { + $confirm = prompt("You have elected to remove the instance " + . "installed in $pki_instance_path.\n" + . "Are you sure (Y/N)? "); + } + + if ($confirm eq "N" || $confirm eq "n") { + return 1; + } elsif ($confirm ne "Y" && $confirm ne "y") { + goto ASK_AGAIN; + } + + $install_info = read_install_info_from_dir($pki_instance_path); + if (!defined($install_info)) { + emit("Can't remove instance, installation manifest does not exist!", "error"); + return $result; + } + + eval { update_domain(); } if !$dry_run; # FIXME so update_domain shows what it would do + warn "Error updating security domain: " . $@ if $@; + + if (($^O eq "linux") && (is_Fedora() || (is_RHEL() && (! is_RHEL4())))) { + my $semanage_cmds = ""; + + eval { get_selinux_ports(\$semanage_cmds); }; + warn "Error getting selinux ports: " . $@ if $@; + + eval { get_selinux_fcontexts(\$semanage_cmds); }; + warn "Error getting selinux file contexts: " . $@ if $@; + + print STDOUT "Removing selinux contexts\n"; + if ($semanage_cmds ne "") { + emit("Executing selinux commands in batch mode.\n", "debug"); + if (! $dry_run) { + if (! run_command("$semanage -S targeted -i - " . '<< _EOF' . "\n$semanage_cmds\n" . '_EOF' . "\n")) { + emit("Error executing selinux batch commands\n", "error"); + } + } + } else { + emit("No selinux contexts need to be removed. No need to run semanage. \n"); + } + } + + $pki_registry_initscript = get_registry_initscript_name($subsystem_type); + + # Shutdown this instance + if ($^O eq "linux") { + if ($use_systemd) { + $pki_instance_systemd_service_name = + "${pki_registry_initscript}\@${pki_instance_name}.service"; + $pki_registry_initscript_command = + "/bin/systemctl stop $pki_instance_systemd_service_name"; + } else { + if (entity_exists("$default_initscripts_path/$pki_instance_name")) { + $pki_registry_initscript_command = "/sbin/service $pki_instance_name stop"; + } else { + $pki_registry_initscript_command = + "/sbin/service $pki_registry_initscript stop $pki_instance_name"; + } + } + } else { + emit("Unsupported platform '$^O'!\n", "error"); + exit 255; + } + run_command($pki_registry_initscript_command); + + if (!$use_systemd) { + # De-register this instance with "chkconfig" + if ($^O eq "linux") { + if (entity_exists("$default_initscripts_path/$pki_instance_name")) { + # De-register this instance with '/sbin/chkconfig' + print(STDOUT "Removing '$pki_instance_name' from chkconfig.\n"); + deregister_pki_instance_with_chkconfig($pki_instance_name); + } + } + } + + print(STDOUT "\n"); + + # Remove all installed files and directories. + $result = 0 if !uninstall($install_info); + + if ($use_systemd) { + run_command("/bin/systemctl --system daemon-reload"); + } + + print(STDOUT "\n"); + + return $result; +} + + +############################################################## +# Main Program +############################################################## + +# no args +# return 1 - success, or +# return 0 - failure +sub main +{ + chdir("/tmp"); + + my $result = 0; + + print(STDOUT "PKI instance Deletion Utility ...\n\n"); + + # On Linux/UNIX, insure that this script is being run as "root". + $result = check_for_root_UID(); + if (!$result) { + usage(); + exit 255; + } + + # Check for a valid number of command-line arguments. + if ($ARGS < 2) { + emit("$0: Insufficient arguments!", "error"); + usage(); + exit 255; + } + + # Parse command-line arguments. + $result = GetOptions("pki_instance_root=s" => \$pki_instance_root, + "pki_instance_name=s" => \$pki_instance_name, + "token_pwd=s" => \$token_pwd, + "verbose+" => \$verbose, + "dry_run" => \$dry_run, + "force" => \$force); + + # Always disallow root to be the pki_instance_root. + if ($pki_instance_root eq "/") { + emit("$0: Don't even think about making root " + . "the pki_instance_root!", "error"); + usage(); + exit 255; + } + + $pki_instance_root = normalize_path($pki_instance_root); + + # Check for valid content of command-line arguments. + if (!$pki_instance_root) { + emit("$0: Must have value for -pki_instance_root!", "error"); + usage(); + exit 255; + } + + if (!$pki_instance_name) { + emit("$0: The instance ID of the PKI instance " + . "to be removed is required!", "error"); + usage(); + exit 255; + } + + $pki_instance_path = "${pki_instance_root}/${pki_instance_name}"; + + if (!directory_exists($pki_instance_path)) { + emit("$0: Target directory $pki_instance_path " + . "is not a legal directory.", "error"); + usage(); + exit 255; + } + + # Capture uninstall information in a log file, always overwrite this file. + # When removing an instance it's never a fatal error if the logfile + # cannot be created. + my $logfile = "/var/log/${pki_instance_name}-uninstall.log"; + open_logfile($logfile, $default_file_permissions); + + emit("Capturing installation information in $logfile.\n"); + + if ($verbose) { + emit(" verbose mode ENABLED (level=$verbose)\n"); + } + + if ($dry_run) { + emit(" dry run mode ENABLED, system will not be modified, log to $logfile\n"); + print STDOUT "dry run mode ENABLED, system will not be modified\n"; + } + + emit(" pki_instance_root $pki_instance_root\n"); + emit(" pki_instance_name $pki_instance_name\n"); + emit(" pki_instance_path $pki_instance_path\n"); + + $conf_file = $pki_instance_path . "/conf/CS.cfg"; + $subsystem_type = get_cs_cfg($conf_file, "cs.type"); + if (!defined($subsystem_type)) { + emit("Could not determine the subsystem type from the file \"$conf_file\"\n", "error"); + exit 1; + } + $subsystem_type = lc($subsystem_type); + + # Remove the specified instance + $result = remove_instance(); + if ($result != 1) { + exit 255; + } + + # Establish PKI subsystem-level registry + $pki_registry_subsystem_path = "$pki_registry_path/$subsystem_type"; + + # If empty, remove the PKI subsystem-level registry + if (directory_exists($pki_registry_subsystem_path)) { + if (is_directory_empty($pki_registry_subsystem_path)) { + remove_directory($pki_registry_subsystem_path); + } + } + + # If empty, remove the PKI-level registry + if (directory_exists($pki_registry_path)) { + if (is_directory_empty($pki_registry_path)) { + remove_directory($pki_registry_path); + } + } + + if ($dry_run) { + print STDOUT "dry run mode ENABLED, system was not modified\n"; + } + + return $result; +} + + +############################################################## +# PKI Instance Removal +############################################################## + +main(); + +exit 0; + |