#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/bin/cdat/cdat-access.pl 1.6 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2010,2011 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)19 1.6 src/bos/usr/bin/cdat/cdat-access.pl, cdat, bos720 7/15/11 04:01:14 use warnings; use strict; use Getopt::Long; use cdat; use messages; # # Constants. # my $USER = 'cdat'; # # Globals. # my $delete; my $pubkey = ""; ###################################################################### # Function: usage # Purpose: Display usage. # Tasks: Print usage and exit. # Input: None # Output: None ###################################################################### sub usage { printf(STDERR catgets(MSG_CDAT_ACCESS_USAGE, "Usage: cdat access -h\n". " cdat access [-dF] [-u User] -n Type:[User@]Node ...\n". " cdat access [-dF] [-u User] -f File ...\n")); exit(1); } ###################################################################### # Function: lpar_install # Purpose: Initialize access to an AIX LPAR. # Tasks: Initialize access to an AIX LPAR. # Input: hostname, user to create, password # Output: 0 on success, remote command exit status on failure ###################################################################### sub lpar_install { my ($name, $user, $passwd) = @_; # List of RBAC authorizations that are needed for the default collect # types on AIX (perfpmr, snap, trace, psrasinit, psrasremove): my $AUTH = "aix.fs.stat,aix.lvm.perf.tune,". "aix.network.config.tcpip,aix.network.daemon,aix.proc,aix.ras.debug,". "aix.ras.dump,aix.ras.error,aix.ras.trace,aix.security.audit,". "aix.system.boot.info,aix.system.config.diag,aix.system.config.dlpar,". "aix.system.config.odm,aix.system.config.perf,aix.system.config.src,". "aix.system.config.wlm,aix.system.install,aix.system.stat,". "aix.wpar.system.resources,aix.system.debug,ibm.ps.client.bind"; my $cmd = < /dev/null 2>&1 [ \$? -ne 0 ] && { # check if the ibm.ps.client.bind authorization exists /usr/sbin/lsauth ibm.ps.client.bind > /dev/null 2>&1 [ \$? -ne 0 ] && { # create the authorization hierarchy if it does not exist # NB: that mail fail if it already exists but errors will # be caught below when creating ibm.ps.client.bind (/usr/bin/mkauth ibm /usr/bin/mkauth ibm.ps /usr/bin/mkauth ibm.ps.client) > /dev/null 2>&1 # create the bind authorization /usr/bin/mkauth ibm.ps.client.bind > /dev/null 2>&1 [ \$? -ne 0 ] && exit 2 } # create our CDAT role now that all authorizations exist /usr/bin/mkrole authorizations=${AUTH} CdatClient [ \$? -ne 0 ] && exit 3 # set entries in the kernel security tables /usr/sbin/setkst -q -t role,auth > /dev/null 2>&1 } # check if the user already exists /usr/sbin/lsuser "$user" > /dev/null 2>&1 [ \$? -ne 0 ] && { # create the user with the CdatClient RBAC role /usr/bin/mkuser roles=CdatClient default_roles=CdatClient "$user" > /dev/null 2>&1 [ \$? -ne 0 ] && exit 4 # set the initial password echo "$user:$passwd" | /usr/bin/chpasswd -f NOCHECK [ \$? -ne 0 ] && exit 5 # create the .cdat file indicating that we created this user ourselves /usr/bin/su $user "-c touch ~$user/.cdat" > /dev/null 2>&1 } # retrieve user home directory (~user does not always work!) homedir=`/usr/sbin/lsuser -a home $user | cut -d= -f2` [ -z "\$homedir" ] && exit 6 [ ! -d "\$homedir/.ssh" ] && { # create the .ssh directory /usr/bin/su $user "-c mkdir -p \\\"\$homedir/.ssh\\\"" > /dev/null 2>&1 [ \$? -ne 0 ] && exit 7 } # always set correct permissions for the .ssh directory /usr/bin/su $user "-c chmod 700 \\\"\$homedir/.ssh\\\"" > /dev/null 2>&1 [ ! -f "\$homedir/.ssh/authorized_keys2" ] && { # create an empty authorized_keys2 file /usr/bin/su $user "-c touch \\\"\$homedir/.ssh/authorized_keys2\\\"" > /dev/null 2>&1 [ \$? -ne 0 ] && exit 8 } # always set correct permissions for the authorized_keys2 file /usr/bin/su $user "-c chmod 600 \\\"\$homedir/.ssh/authorized_keys2\\\"" > /dev/null 2>&1 [ ! -z "$pubkey" ] && { # check if our SSH public key is already installed /usr/bin/grep -q "$pubkey" "\$homedir/.ssh/authorized_keys2" [ \$? -ne 0 ] && { # install our SSH public key echo "$pubkey" >> "\$homedir/.ssh/authorized_keys2" [ \$? -ne 0 ] && exit 9 } } exit 0 EOF ; my @lines = print cdat::remote_cmd('root', $name, $cmd, $cdat::REMOTE_ASKUSER | $cdat::REMOTE_PROBE); DEBUG(1, @lines); return $?; } ###################################################################### # Function: lpar_uninstall # Purpose: Remove access to an AIX LPAR. # Tasks: Remove access to an AIX LPAR. # Input: hostname, user to remove # Output: 0 on success, remote command exit status on failure ###################################################################### sub lpar_uninstall { my ($name, $user) = @_; my $cmd = < /dev/null 2>&1 elif [ ! -z "$pubkey" -a -f ~$user/.ssh/authorized_keys2 ]; then /usr/bin/su $user "-c touch ~$user/.ssh/authorized_keys2.bak" [ \$? -eq 0 ] && { chmod 600 ~$user/.ssh/authorized_keys2.bak [ \$? -eq 0 ] && { # remove our SSH public key /usr/bin/grep -v "$pubkey" ~$user/.ssh/authorized_keys2 > ~$user/.ssh/authorized_keys2.bak cat ~$user/.ssh/authorized_keys2.bak > ~$user/.ssh/authorized_keys2 rm -f ~$user/.ssh/authorized_keys2.bak } } fi # remove the CdatClient RBAC role if it is no longer used /usr/sbin/lsuser ALL | grep -wq CdatClient [ \$? -ne 0 ] && { /usr/bin/lslpp -lq pureScale.client.rte 2>/dev/null | grep -wq COMMITTED [ \$? -ne 0 ] && { # remove the ibm.ps.client.bind authorization (/usr/sbin/rmauth ibm.ps.client.bind /usr/sbin/rmauth ibm.ps.client /usr/sbin/rmauth ibm.ps /usr/sbin/rmauth ibm) > /dev/null 2>&1 } # NB: safe even if it does not exist /usr/sbin/rmrole CdatClient > /dev/null 2>&1 # set entries in the kernel security tables /usr/sbin/setkst -q -t role,auth > /dev/null 2>&1 } exit 0 # discard errors EOF ; my @lines = cdat::remote_cmd('root', $name, $cmd, $cdat::REMOTE_ASKUSER | $cdat::REMOTE_PROBE); DEBUG(1, @lines); return $?; } ###################################################################### # Function: vios_install # Purpose: Initialize access to a VIOS. # Tasks: Initialize access to a VIOS. # Input: hostname, user to create, password # Output: 0 on success, remote command exit status on failure ###################################################################### sub vios_install { my ($name, $user, $passwd) = @_; my $cmd = < /dev/null 2>&1 [ \\\$? -ne 0 ] && { # create our CDAT role /usr/bin/mkrole authorizations=aix.system.stat,aix.ras.trace CdatClient [ \\\$? -ne 0 ] && exit 2 # set entries in the kernel security tables /usr/sbin/setkst -q -t role,auth > /dev/null 2>&1 } # check if the user already exists /usr/sbin/lsuser "$user" > /dev/null 2>&1 [ \\\$? -ne 0 ] && { # create the user with the CdatClient RBAC role /usr/bin/mkuser roles=CdatClient default_roles=CdatClient "$user" > /dev/null 2>&1 [ \\\$? -ne 0 ] && exit 3 # set the initial password echo "$user:$passwd" | /usr/bin/chpasswd -f NOCHECK [ \\\$? -ne 0 ] && exit 4 # create the .cdat file indicating that we created this user ourselves /usr/bin/su $user "-c touch /home/$user/.cdat" > /dev/null 2>&1 } [ ! -d /home/$user/.ssh ] && { # create the .ssh directory /usr/bin/su $user "-c mkdir -p /home/$user/.ssh" > /dev/null 2>&1 [ \\\$? -ne 0 ] && exit 5 } # always set correct permissions for the .ssh directory /usr/bin/su $user "-c chmod 700 /home/$user/.ssh" > /dev/null 2>&1 [ ! -f /home/$user/.ssh/authorized_keys2 ] && { # create an empty authorized_keys2 file /usr/bin/su $user "-c touch /home/$user/.ssh/authorized_keys2" > /dev/null 2>&1 [ \\\$? -ne 0 ] && exit 6 } # always set correct permissions for the authorized_keys2 file /usr/bin/su $user "-c chmod 600 /home/$user/.ssh/authorized_keys2" > /dev/null 2>&1 [ ! -z "$pubkey" ] && { # check if our SSH public key is already installed /usr/bin/grep -q "$pubkey" /home/$user/.ssh/authorized_keys2 [ \\\$? -ne 0 ] && { # install our SSH public key echo "$pubkey" >> /home/$user/.ssh/authorized_keys2 [ \\\$? -ne 0 ] && exit 7 } } exit 0 EOT EOF ; my @lines = cdat::remote_cmd('padmin', $name, $cmd, $cdat::REMOTE_ASKUSER | $cdat::REMOTE_PROBE); DEBUG(1, @lines); return $?; } ###################################################################### # Function: vios_uninstall # Purpose: Remove access to a VIOS. # Tasks: Remove access to a VIOS. # Input: hostname, user to remove # Output: 0 on success, remote command exit status on failure ###################################################################### sub vios_uninstall { my ($name, $user) = @_; my $cmd = < /dev/null 2>&1 elif [ ! -z "$pubkey" -a -f /home/$user/.ssh/authorized_keys2 ]; then /usr/bin/su $user "-c touch /home/$user/.ssh/authorized_keys2.bak" [ \\\$? -eq 0 ] && { chmod 600 /home/$user/.ssh/authorized_keys2.bak [ \\\$? -eq 0 ] && { # remove our SSH public key /usr/bin/grep -v "$pubkey" /home/$user/.ssh/authorized_keys2 > /home/$user/.ssh/authorized_keys2.bak cat /home/$user/.ssh/authorized_keys2.bak > /home/$user/.ssh/authorized_keys2 rm -f /home/$user/.ssh/authorized_keys2.bak } } fi # remove the CdatClient RBAC role if it is no longer used /usr/sbin/lsuser ALL | grep -wq CdatClient [ \\\$? -ne 0 ] && { # NB: safe even if it does not exist /usr/sbin/rmrole CdatClient > /dev/null 2>&1 # set entries in the kernel security tables /usr/sbin/setkst -q -t role,auth > /dev/null 2>&1 } exit 0 # discard errors EOT EOF ; my @lines = cdat::remote_cmd('padmin', $name, $cmd, $cdat::REMOTE_ASKUSER | $cdat::REMOTE_PROBE); DEBUG(1, @lines); return $?; } ###################################################################### # Function: hmc_install # Purpose: Initialize access to an HMC. # Tasks: Initialize access to an HMC. # Input: hostname, user to create, password # Output: 0 on success, remote command exit status on failure ###################################################################### sub hmc_install { my ($name, $user, $passwd) = @_; my $cmd = < \&usage, 'd' => \$delete, 'F' => \$force, 'n=s' => \@rawnodes, 'u=s' => \$user, 'f=s' => \@filenames, ); if (!$rc || @ARGV != 0) { usage(); } # make sure we have -n or -f, but not both if (!((@filenames != 0) ^ (@rawnodes != 0))) { usage(); } cdat::switch_user(); if (@filenames != 0) { %nodes = cdat::read_nodes_from_files(@filenames); } else { %nodes = cdat::read_nodes_from_array(@rawnodes); } if (!%nodes) { printf(STDERR catgets(MSG_NO_NODES_TO_CONNECT, "No nodes to connect to.\n")); exit(3); } if (!defined($user)) { # no -u specified, use default collect user $user = $USER; } $has_ssh = -x '/usr/bin/ssh'; if ($has_ssh) { if (open(FILE, "$ENV{HOME}/.ssh/id_rsa.pub")) { $pubkey = ; chomp($pubkey); close(FILE); } } my %hosts; cdat::read_host_db(\%hosts); my $status = 0; while (my ($name, $node) = each(%nodes)) { # Skip node types that we don't manage (PSCALE) my $type = $node->{type}; if ($type ne 'HMC' && $type ne 'VIOS' && $type ne 'LPAR') { printf(catgets(MSG_ACCESS_IGNORE_TYPE, "Ignoring node type '%s'.\n"), $type); next; } my $login = $node->{user}; # if no user@ specified, use -u (or default) $login = $user if (!defined($login)); if (!defined($force)) { # -F not specified, skeep nodes already (de)initialized if (!defined($delete)) { if (defined($hosts{$name}) && defined($hosts{$name}{users}{$login})) { # User@Host is already in hosts db, use force to re-create printf(catgets(MSG_ACCESS_ALREADY_IN_DB, "%s@%s is already in hosts database, use -F to force.\n"), $login, $name); next; } } else { if (!defined($hosts{$name}) || !defined($hosts{$name}{users}{$login})) { # User@Host is not in hosts db, use force to delete anyway printf(catgets(MSG_ACCESS_NOT_IN_DB, "%s@%s is not in hosts database, use -F to force.\n"), $login, $name); next; } } } if (!defined($passwd) && !defined($delete)) { printf(catgets(MSG_USER_PASSWD, "The collect user will be created with the same password on all nodes.\n")); # Ask for a password and a confirmation of the password my $prompt1 = catgets(MSG_PLEASE_ENTER_PASSWORD, "Please enter a password for the collect user: "); my $prompt2 = catgets(MSG_REENTER_PASSWORD, "Re-enter the collect user password: "); $passwd = cdat::define_password($prompt1, $prompt2); if (!defined($passwd)) { printf(catgets(MSG_PASSWORD_MISMATCH, "Password mismatch.\n")); exit(1); } elsif (length($passwd) < 7) { # this is required for HMCs printf(catgets(MSG_PASSWORD_INVALID, "Password cannot be less than 7 characters.\n")); exit(1); } } if (defined($delete)) { printf(catgets(MSG_REMOVE_ACCESS, "Removing access to '%s' on host '%s'...\n"), $login, $name); } else { printf(catgets(MSG_INIT_ACCESS, "Initializing access to '%s' on host '%s'...\n"), $login, $name); } if ($has_ssh) { printf(catgets(MSG_ACCESS_TRYING, "Trying '%s'..."), "ssh"); if (cdat::check_remote_protocol($name, "ssh")) { printf(catgets(MSG_FOUND, "found\n")); $status = access($type, $name, $login, $passwd); next if ($status != 0); if (!defined($delete)) { $hosts{$name}{protocol} = "ssh"; # NB: we do not store passwords for SSH $hosts{$name}{users}{$login} = ""; } elsif (defined($hosts{$name})) { delete($hosts{$name}{users}{$login}); } next; } printf(catgets(MSG_NOT_FOUND, "not found\n")); } printf(catgets(MSG_ACCESS_TRYING, "Trying '%s'..."), "exec"); if (cdat::check_remote_protocol($name, "exec")) { printf(catgets(MSG_FOUND, "found\n")); $status = access($type, $name, $login, $passwd); next if ($status != 0); if (!defined($delete)) { $hosts{$name}{protocol} = "exec"; $hosts{$name}{users}{$login} = $passwd; } elsif (defined($hosts{$name})) { delete($hosts{$name}{users}{$login}); } next; } printf(catgets(MSG_NOT_FOUND, "not found\n")); printf(catgets(MSG_ACCESS_TRYING, "Trying '%s'..."), "telnet"); if (cdat::check_remote_protocol($name, "telnet")) { printf(catgets(MSG_FOUND, "found\n")); $status = access($type, $name, $login, $passwd); next if ($status != 0); if (!defined($delete)) { $hosts{$name}{protocol} = "telnet"; $hosts{$name}{users}{$login} = $passwd; $hosts{$name}{login_pattern} = $ENV{EXPECT_PATTERN1}; $hosts{$name}{password_pattern} = $ENV{EXPECT_PATTERN2}; } elsif (defined($hosts{$name})) { delete($hosts{$name}{users}{$login}); } next; } printf(catgets(MSG_NOT_FOUND, "not found\n")); printf(catgets(MSG_CANNOT_CONNECT_TO, "Cannot connect to %s.\n"), $name); } cdat::write_host_db(%hosts); exit($status); } main;