X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/bc2fc8e149fd79346048b2b1764f95699e68665e..HEAD:/setup/setup-openssh.pl diff --git a/setup/setup-openssh.pl b/setup/setup-openssh.pl index 21f3d5d..6a4cdd5 100644 --- a/setup/setup-openssh.pl +++ b/setup/setup-openssh.pl @@ -1,32 +1,61 @@ +#!/usr/bin/perl # -# setup-openssh.pl: -# Adapts the installed gsi-ssh environment to the current machine, -# performing actions that originally occurred during the package's -# 'make install' phase. +# setup-openssh.pl # -# Large parts adapted from 'fixpath', a tool found in openssh-3.0.2p1. +# Adapts the installed gsi-openssh environment to the current machine, +# performing actions that originally occurred during the package's +# 'make install' phase. # # Send comments/fixes/suggestions to: # Chase Phillips # +# +# Get user's GPT_LOCATION since we may be installing this using a new(er) +# version of GPT. +# + +$gptpath = $ENV{GPT_LOCATION}; + +# +# And the old standby.. +# + $gpath = $ENV{GLOBUS_LOCATION}; if (!defined($gpath)) { - die "GLOBUS_LOCATION needs to be set before running this script" + exitDie("ERROR: GLOBUS_LOCATION needs to be set before running this script!\n"); } +# +# Include standard modules +# + +use Getopt::Long; +use Cwd; +use Cwd 'abs_path'; + # # i'm including this because other perl scripts in the gpt setup directories # do so # -@INC = (@INC, "$gpath/lib/perl"); +if (defined($gptpath)) +{ + @INC = (@INC, "$gptpath/lib/perl", "$gpath/lib/perl"); +} +else +{ + @INC = (@INC, "$gpath/lib/perl"); +} require Grid::GPT::Setup; +# +# script-centred variable initialization +# + my $globusdir = $gpath; -my $setupdir = "$globusdir/setup/globus"; my $myname = "setup-openssh.pl"; # @@ -35,335 +64,1051 @@ my $myname = "setup-openssh.pl"; $prefix = ${globusdir}; $exec_prefix = "${prefix}"; -$bindir = "${exec_prefix}/bin"; +$bindir = "${exec_prefix}/bin/ssh.d"; $sbindir = "${exec_prefix}/sbin"; -$mandir = "${prefix}/man"; -$mansubdir = "man"; -$libexecdir = "${exec_prefix}/libexec"; -$sysconfdir = "/etc/ssh"; -$piddir = "/var/run"; -$xauth_path = "/usr/bin/X11/xauth"; +$sysconfdir = "$prefix/etc/ssh"; +$localsshdir = "/etc/ssh"; +$setupdir = "$prefix/setup/gsi_openssh_setup"; + +# +# standard key types and their root file name mappings +# + +my $keyfiles = { + "dsa" => "ssh_host_dsa_key", + "rsa" => "ssh_host_rsa_key", + "rsa1" => "ssh_host_key", + }; + +# +# argument specification. we offload some processing work from later functions +# to verify correct args by using anon subs in various places. +# + +my($prompt, $force, $verbose); + +$prompt = 1; +$verbose = 0; + +GetOptions( + 'prompt!' => \$prompt, + 'force' => \$force, + 'verbose' => \$verbose, + ) or pod2usage(2); # -# Backup-related variables +# miscellaneous initialization functions # -$curr_time = time(); -$backupdir = "/etc/ssh/globus_backup_${curr_time}"; +setPrivilegeSeparation(0); # -# Check that we are running as root +# main execution. This should find its way into a subroutine at some future +# point. # -$uid = $>; +debug0("Configuring gsi_openssh\n"); +debug0("------------------------------------------------------------\n"); +debug0("Executing...\n"); + +makeConfDir(); +copyPRNGFile(); +$keyhash = determineKeys(); +runKeyGen($keyhash->{gen}); +linkKeyFiles($keyhash->{link}); +copyConfigFiles(); + +my $metadata = new Grid::GPT::Setup(package_name => "gsi_openssh_setup"); + +$metadata->finish(); + +debug0("\n"); +debug0("Notes:\n\n"); -if ($uid != 0) +if ( getPrivilegeSeparation() ) +{ + debug0(" o Privilege separation is on.\n"); +} +elsif ( !getPrivilegeSeparation() ) { - print "--> NOTE: You must be root to run this script! <--\n"; - exit 0; + debug0(" o Privilege separation is off.\n"); } +debug0(" o GSI-OpenSSH website is .\n"); +debug0("------------------------------------------------------------\n"); +debug0("Finished configuring gsi_openssh.\n"); + +exit; + +# +# subroutines +# + +### initPRNGHash( ) # -# We need to make sure it's okay to copy our setup files (if some files are already -# present). If we do copy any files, we backup the old files so the user can (possibly) -# reverse any damage. +# initialize the PRNG pathname hash # -sub test_dirs +sub initPRNGHash( ) { - print "\nPreparatory: Checking for existence of critical directories..\n"; + # + # standard prng to executable conversion names + # + + addPRNGCommand("\@PROG_LS\@", "ls"); + addPRNGCommand("\@PROG_NETSTAT\@", "netstat"); + addPRNGCommand("\@PROG_ARP\@", "arp"); + addPRNGCommand("\@PROG_IFCONFIG\@", "ifconfig"); + addPRNGCommand("\@PROG_PS\@", "ps"); + addPRNGCommand("\@PROG_JSTAT\@", "jstat"); + addPRNGCommand("\@PROG_W\@", "w"); + addPRNGCommand("\@PROG_WHO\@", "who"); + addPRNGCommand("\@PROG_LAST\@", "last"); + addPRNGCommand("\@PROG_LASTLOG\@", "lastlog"); + addPRNGCommand("\@PROG_DF\@", "df"); + addPRNGCommand("\@PROG_SAR\@", "sar"); + addPRNGCommand("\@PROG_VMSTAT\@", "vmstat"); + addPRNGCommand("\@PROG_UPTIME\@", "uptime"); + addPRNGCommand("\@PROG_IPCS\@", "ipcs"); + addPRNGCommand("\@PROG_TAIL\@", "tail"); + + debug1("Determining paths for PRNG commands...\n"); + + $paths = determinePRNGPaths(); + + return; +} + +### getDirectoryPaths( ) +# +# return an array ref containing all of the directories in which we should search +# for our listing of executable names. +# +sub getDirectoryPaths( ) +{ # - # Remember to put in check for /etc + # read in the PATH environmental variable and prepend a set of 'safe' + # directories from which to test PRNG commands. # + $path = $ENV{PATH}; + $path = "/bin:/usr/bin:/sbin:/usr/sbin:/etc:" . $path; + @dirs = split(/:/, $path); + # - # Test for /etc/ssh + # sanitize each directory listed in the array. # - if ( ! -d "$sysconfdir" ) + @dirs = map { + $tmp = $_; + $tmp =~ s:/+:/:g; + $tmp =~ s:^\s+|\s+$::g; + $tmp; + } @dirs; + + return \@dirs; +} + +### addPRNGCommand( $prng_name, $exec_name ) +# +# given a PRNG name and a corresponding executable name, add it to our list of +# PRNG commands for which to find on the system. +# + +sub addPRNGCommand +{ + my($prng_name, $exec_name) = @_; + + prngAddNode($prng_name, $exec_name); +} + +### copyPRNGFile( ) +# +# read in ssh_prng_cmds.in, translate the program listings to the paths we have +# found on the local system, and then write the output to ssh_prng_cmds. +# + +sub copyPRNGFile +{ + my($fileInput, $fileOutput); + my($mode, $uid, $gid); + my($data); + + if ( isPresent("$sysconfdir/ssh_prng_cmds") && !isForced() ) + { + debug1("ssh_prng_cmds found and not forced. Not installing ssh_prng_cmds...\n"); + return; + } + + initPRNGHash(); + + debug1("Fixing paths in ssh_prng_cmds...\n"); + + $fileInput = "$setupdir/ssh_prng_cmds.in"; + $fileOutput = "$sysconfdir/ssh_prng_cmds"; + + # + # verify that we are prepared to work with $fileInput + # + + if ( !isReadable($fileInput) ) + { + debug1("Cannot read $fileInput... skipping.\n"); + return; + } + + # + # verify that we are prepared to work with $fileOuput + # + + if ( !prepareFileWrite($fileOutput) ) { - print "Could not find directory: '${sysconfdir}'.. creating.\n"; - mkdir($sysconfdir, 16877); - # 16877 should be 755, or drwxr-xr-x + return; } # - # Test for /etc/ssh/globus_backup_ + # Grab the current mode/uid/gid for use later # - if ( ! -d "${backupdir}" ) + $mode = (stat($fileInput))[2]; + $uid = (stat($fileInput))[4]; + $gid = (stat($fileInput))[5]; + + # + # Open the files for reading and writing, and loop over the input's contents + # + + $data = readFile($fileInput); + for my $k (keys %$prngcmds) { - print "Could not find directory: '${backupdir}'.. creating.\n"; - mkdir($backupdir, 16877); + $sub = prngGetExecPath($k); + $data =~ s:$k:$sub:g; } + writeFile($fileOutput, $data); + + # + # An attempt to revert the new file back to the original file's + # mode/uid/gid + # + + chmod($mode, $fileOutput); + chown($uid, $gid, $fileOutput); return 0; } -sub backup_files +### determinePRNGPaths( ) +# +# for every entry in the PRNG hash, seek out and find the path for the +# corresponding executable name. +# + +sub determinePRNGPaths { - print "\nStage 1: Backing up configuration files to '${backupdir}/'..\n"; + my(@paths, @dirs); + my($exec_name, $exec_path); + + $dirs = getDirectoryPaths(); - if ( -e "${sysconfdir}/ssh_config" ) + for my $k (keys %$prngcmds) { - action("cp ${sysconfdir}/ssh_config ${backupdir}/ssh_config"); + $exec_name = prngGetExecName($k); + $exec_path = findExecutable($exec_name, $dirs); + prngSetExecPath($k, $exec_path); } - else + + return; +} + +### prngAddNode( $prng_name, $exec_name ) +# +# add a new node to the PRNG hash +# + +sub prngAddNode +{ + my($prng_name, $exec_name) = @_; + my($node); + + if (!defined($prngcmds)) { - print "${sysconfdir}/ssh_config does not exist.\n"; + $prngcmds = {}; } - if ( -e "${sysconfdir}/sshd_config" ) + $node = {}; + $node->{prng} = $prng_name; + $node->{exec} = $exec_name; + + $prngcmds->{$prng_name} = $node; +} + +### prngGetExecName( $key ) +# +# get the executable name from the prng commands hash named by $key +# + +sub prngGetExecName +{ + my($key) = @_; + + return $prngcmds->{$key}->{exec}; +} + +### prngGetExecPath( $key ) +# +# get the executable path from the prng commands hash named by $key +# + +sub prngGetExecPath +{ + my($key) = @_; + + return $prngcmds->{$key}->{exec_path}; +} + +### prngGetNode( $key ) +# +# return a reference to the node named by $key +# + +sub prngGetNode +{ + my($key) = @_; + + return ${$prngcmds}{$key}; +} + +### prngSetExecPath( $key, $path ) +# +# given a key, set the executable path in that node to $path +# + +sub prngSetExecPath +{ + my($key, $path) = @_; + + $prngcmds->{$key}->{exec_path} = $path; +} + +### findExecutable( $exec_name, $dirs ) +# +# given an executable name, test each possible path in $dirs to see if such +# an executable exists. +# + +sub findExecutable +{ + my($exec_name, $dirs) = @_; + + for my $d (@$dirs) { - action("cp ${sysconfdir}/sshd_config ${backupdir}/sshd_config"); + $test = "$d/$exec_name"; + + if ( isExecutable($test) ) + { + return $test; + } } - else + + return "undef"; +} + +### linkKeyFiles( $linklist ) +# +# given an array of keys to link, link both the key and its public variant into +# the gsi-openssh configuration directory. +# + +sub linkKeyFiles +{ + my($linklist) = @_; + my($regex, $basename); + + if (@$linklist) { - print "${sysconfdir}/sshd_config does not exist.\n"; + debug1("Linking ssh host keys...\n"); + + for my $f (@$linklist) + { + $f =~ s:/+:/:g; + + if (length($f) > 0) + { + $keyfile = "$f"; + $pubkeyfile = "$f.pub"; + + linkFile("$localsshdir/$keyfile", "$sysconfdir/$keyfile"); + linkFile("$localsshdir/$pubkeyfile", "$sysconfdir/$pubkeyfile"); + } + } } +} + +### isForced( ) +# +# return true if the user passed in the force flag. return false otherwise. +# - if ( -e "${sysconfdir}/moduli" ) +sub isForced +{ + if ( defined($force) && $force ) { - action("cp ${sysconfdir}/moduli ${backupdir}/moduli"); + return 1; } else { - print "${sysconfdir}/moduli does not exist.\n"; + return 0; } } -sub copy_setup_files -{ - my $response; - - print "\nStage 2: Copying configuration files into '${sysconfdir}'..\n"; - - action("cp ${globusdir}/setup/globus/ssh_config ${sysconfdir}/ssh_config"); - action("cp ${globusdir}/setup/globus/sshd_config ${sysconfdir}/sshd_config"); - action("cp ${globusdir}/setup/globus/moduli ${sysconfdir}/moduli"); -} +### isReadable( $file ) +# +# given a file, return true if that file both exists and is readable by the +# effective user id. return false otherwise. +# -sub runkeygen +sub isReadable { - print "\nStage 3: Generating ssh host keys..\n"; + my($file) = @_; - if ( ! -d "${sysconfdir}" ) + if ( ( -e $file ) && ( -r $file ) ) + { + return 1; + } + else { - print "Could not find ${sysconfdir} directory... creating\n"; - mkdir($sysconfdir, 16877); - # 16877 should be 755, or drwxr-xr-x + return 0; } +} + +### isExecutable( $file ) +# +# return true if $file is executable. return false otherwise. +# + +sub isExecutable +{ + my($file) = @_; - if ( -e "${sysconfdir}/ssh_host_key" ) + if ( -x $file ) { - print "${sysconfdir}/ssh_host_key already exists, skipping.\n"; + return 1; } else { - # if $sysconfdir/ssh_host_key doesn't exist.. - action("$bindir/ssh-keygen -t rsa1 -f $sysconfdir/ssh_host_key -N \"\""); + return 0; } +} + +### isWritable( $file ) +# +# given a file, return true if that file does not exist or is writable by the +# effective user id. return false otherwise. +# - if ( -e "${sysconfdir}/ssh_host_dsa_key" ) +sub isWritable +{ + my($file) = @_; + + if ( ( ! -e $file ) || ( -w $file ) ) { - print "${sysconfdir}/ssh_host_dsa_key already exists, skipping.\n"; + return 1; } else { - # if $sysconfdir/ssh_host_dsa_key doesn't exist.. - action("$bindir/ssh-keygen -t dsa -f $sysconfdir/ssh_host_dsa_key -N \"\""); + return 0; } +} - if ( -e "${sysconfdir}/ssh_host_rsa_key" ) +### isPresent( $file ) +# +# given a file, return true if that file exists. return false otherwise. +# + +sub isPresent +{ + my($file) = @_; + + if ( -e $file ) { - print "${sysconfdir}/ssh_host_rsa_key already exists, skipping.\n"; + return 1; } else { - # if $sysconfdir/ssh_host_rsa_key doesn't exist.. - action("$bindir/ssh-keygen -t rsa -f $sysconfdir/ssh_host_rsa_key -N \"\""); + return 0; } - - return 0; } -sub fixpaths +### makeConfDir( ) +# +# make the gsi-openssh configuration directory if it doesn't already exist. +# + +sub makeConfDir { - my $g; + if ( isPresent($sysconfdir) ) + { + if ( -d $sysconfdir ) + { + return; + } + + debug1("${sysconfdir} already exists and is not a directory!\n"); + exit; + } + + debug1("Could not find ${sysconfdir} directory... creating.\n"); + action("mkdir -p $sysconfdir"); - print "\nStage 4: Translating strings in config and man files..\n"; + return; +} + +### determineKeys( ) +# +# based on a set of key types, triage them to determine if for each key type, that +# key type should be copied from the main ssh configuration directory, or if it +# should be generated using ssh-keygen. +# + +sub determineKeys +{ + my($keyhash, $keylist); + my($count); # - # Set up path translations for the installation files + # initialize our variables # - %def = ( - "/etc/ssh_config" => "${sysconfdir}/ssh_config", - "/etc/ssh_known_hosts" => "${sysconfdir}/ssh_known_hosts", - "/etc/sshd_config" => "${sysconfdir}/sshd_config", - "/usr/libexec" => "${libexecdir}", - "/etc/shosts.equiv" => "${sysconfdir}/shosts.equiv", - "/etc/ssh_host_key" => "${sysconfdir}/ssh_host_key", - "/etc/ssh_host_dsa_key" => "${sysconfdir}/ssh_host_dsa_key", - "/etc/ssh_host_rsa_key" => "${sysconfdir}/ssh_host_rsa_key", - "/var/run/sshd.pid" => "${piddir}/sshd.pid", - "/etc/moduli" => "${sysconfdir}/moduli", - "/etc/sshrc" => "${sysconfdir}/sshrc", - "/usr/X11R6/bin/xauth" => "${xauth_path}", - "/usr/bin:/bin:/usr/sbin:/sbin" => "/usr/bin:/bin:/usr/sbin:/sbin:${bindir}", - ); + $count = 0; + + $keyhash = {}; + $keyhash->{gen} = []; # a list of keytypes to generate + $keyhash->{link} = []; # a list of files to link + + $genlist = $keyhash->{gen}; + $linklist = $keyhash->{link}; # - # Files on which to perform path translations + # loop over our keytypes and determine what we need to do for each of them # - @files = ( - "${sysconfdir}/ssh_config" => 0, - "${sysconfdir}/sshd_config" => 0, - "${sysconfdir}/moduli" => 0, - "${mandir}/${mansubdir}1/scp.1" => 0, - "${mandir}/${mansubdir}1/ssh-add.1" => 0, - "${mandir}/${mansubdir}1/ssh-agent.1" => 0, - "${mandir}/${mansubdir}1/ssh-keygen.1" => 0, - "${mandir}/${mansubdir}1/ssh-keyscan.1" => 0, - "${mandir}/${mansubdir}1/ssh.1" => 0, - "${mandir}/${mansubdir}8/sshd.8" => 0, - "${mandir}/${mansubdir}8/sftp-server.8" => 0, - "${mandir}/${mansubdir}1/sftp.1" => 0, - ); - - for my $f (@files) + for my $keytype (keys %$keyfiles) { - $f =~ /(.*\/)*(.*)$/; + $basekeyfile = $keyfiles->{$keytype}; # - # we really should create a random filename and make sure that it - # doesn't already exist (based off current time_t or something) + # if the key's are already present, we don't need to bother with this rigamarole # - $g = "$f.tmp"; + $gkeyfile = "$sysconfdir/$basekeyfile"; + $gpubkeyfile = "$sysconfdir/$basekeyfile.pub"; + + if ( isPresent($gkeyfile) && isPresent($gpubkeyfile) ) + { + if ( isForced() ) + { + if ( isWritable("$sysconfdir/$basekeyfile") && isWritable("$sysconfdir/$basekeyfile.pub") ) + { + action("rm $sysconfdir/$basekeyfile"); + action("rm $sysconfdir/$basekeyfile.pub"); + } + else + { + next; + } + } + } # - # Grab the current mode/uid/gid for use later + # if we can find a copy of the keys in /etc/ssh, we'll link them to the user's + # globus location # - $mode = (stat($f))[2]; - $uid = (stat($f))[4]; - $gid = (stat($f))[5]; + $mainkeyfile = "$localsshdir/$basekeyfile"; + $mainpubkeyfile = "$localsshdir/$basekeyfile.pub"; + + if ( isPresent($mainkeyfile) && isPresent($mainpubkeyfile) ) + { + push(@$linklist, $basekeyfile); + $count++; + next; + } # - # Move $f into a .tmp file for the translation step + # otherwise, we need to generate the key # - $result = system("mv $f $g 2>&1"); - if ($result or $?) - { - die "ERROR: Unable to execute command: $!\n"; - } + push(@$genlist, $keytype); + $count++; + } + + return $keyhash; +} - open(IN, "<$g") || die ("$0: input file $g missing!\n"); - open(OUT, ">$f") || die ("$0: unable to open output file $f!\n"); +### runKeyGen( $gen_keys ) +# +# given a set of key types, generate private and public keys for that key type and +# place them in the gsi-openssh configuration directory. +# - while () +sub runKeyGen +{ + my($gen_keys) = @_; + my $keygen = "$bindir/ssh-keygen"; + + if (@$gen_keys && -x $keygen) + { + debug1("Generating ssh host keys...\n"); + + for my $k (@$gen_keys) { - for $s (keys(%def)) + $keyfile = $keyfiles->{$k}; + + if ( !isPresent("$sysconfdir/$keyfile") ) { - s#$s#$def{$s}#; - } # for $s - print OUT "$_"; - } # while + action("$bindir/ssh-keygen -t $k -f $sysconfdir/$keyfile -N \"\""); + } + } + } + + return 0; +} - close(OUT); - close(IN); +### copySSHDConfigFile( ) +# +# this subroutine 'edits' the paths in sshd_config to suit them to the current environment +# in which the setup script is being run. +# - # - # Remove the old .tmp file - # +sub copySSHDConfigFile +{ + my($fileInput, $fileOutput); + my($mode, $uid, $gid); + my($line, $newline); + my($privsep_enabled); - $result = system("rm $g 2>&1"); + debug1("Fixing paths in sshd_config...\n"); - if ($result or $?) + $fileInput = "$setupdir/sshd_config.in"; + $fileOutput = "$sysconfdir/sshd_config"; + + # + # verify that we are prepared to work with $fileInput + # + + if ( !isReadable($fileInput) ) + { + debug1("Cannot read $fileInput... skipping.\n"); + return; + } + + # + # verify that we are prepared to work with $fileOuput + # + + if ( !prepareFileWrite($fileOutput) ) + { + return; + } + + # + # check to see whether we should enable privilege separation + # + + if ( userExists("sshd") && ( -d "/var/empty" ) && ( getOwnerID("/var/empty") eq 0 ) ) + { + setPrivilegeSeparation(1); + } + else + { + setPrivilegeSeparation(0); + } + + if ( getPrivilegeSeparation() ) + { + $privsep_enabled = "yes"; + } + else + { + $privsep_enabled = "no"; + } + + # + # Grab the current mode/uid/gid for use later + # + + $mode = (stat($fileInput))[2]; + $uid = (stat($fileInput))[4]; + $gid = (stat($fileInput))[5]; + + # + # Open the files for reading and writing, and loop over the input's contents + # + + $data = readFile($fileInput); + + # # + # # alter the PidFile config + # # + # + # $text = "PidFile\t$gpath/var/sshd.pid"; + # $data =~ s:^[\s|#]*PidFile.*$:$text:gm; + + # + # set the sftp directive + # + + $text = "Subsystem\tsftp\t$gpath/libexec/sftp-server"; + $data =~ s:^[\s|#]*Subsystem\s+sftp\s+.*$:$text:gm; + + # + # set the privilege separation directive + # + + $text = "UsePrivilegeSeparation\t${privsep_enabled}"; + $data =~ s:^[\s|#]*UsePrivilegeSeparation.*$:$text:gm; + + # + # dump the modified output to the config file + # + + writeFile($fileOutput, $data); + + # + # An attempt to revert the new file back to the original file's + # mode/uid/gid + # + + chmod($mode, $fileOutput); + chown($uid, $gid, $fileOutput); + + return 0; +} + +### setPrivilegeSeparation( $value ) +# +# set the privilege separation variable to $value +# + +sub setPrivilegeSeparation +{ + my($value) = @_; + + $privsep = $value; +} + +### getPrivilegeSeparation( ) +# +# return the value of the privilege separation variable +# + +sub getPrivilegeSeparation +{ + return $privsep; +} + +### prepareFileWrite( $file ) +# +# test $file to prepare for writing to it. +# + +sub prepareFileWrite +{ + my($file) = @_; + + if ( isPresent($file) ) + { + debug1("$file already exists... "); + + if ( isForced() ) + { + if ( isWritable($file) ) + { + debug1("removing.\n"); + action("rm $file"); + return 1; + } + else + { + debug1("not writable -- skipping.\n"); + return 0; + } + } + else { - die "ERROR: Unable to execute command: $!\n"; + debug1("skipping.\n"); + return 0; } + } - # - # An attempt to revert the new file back to the original file's - # mode/uid/gid - # + return 1; +} - chmod($mode, $f); - chown($uid, $gid, $f); - } # for $f +### copyConfigFiles( ) +# +# subroutine that copies some extra config files to their proper location in +# $GLOBUS_LOCATION/etc/ssh. +# - return 0; +sub copyConfigFiles +{ + # + # copy the sshd_config file into the ssh configuration directory and alter + # the paths in the file. + # + + copySSHDConfigFile(); + + # + # do straight copies of the ssh_config and moduli files. + # + + debug1("Copying ssh_config and moduli to their proper location...\n"); + + copyFile("$setupdir/ssh_config", "$sysconfdir/ssh_config"); + copyFile("$setupdir/moduli", "$sysconfdir/moduli"); + + # + # copy and alter the SXXsshd script. + # + + copySXXScript("$setupdir/SXXsshd.in", "$sbindir/SXXsshd"); } -print "---------------------------------------------------------------\n"; -print "$myname: Configuring package gsi_openssh..\n"; -print "\n"; -print "Hi, I'm the setup script for the gsi_openssh package! There\n"; -print "are some last minute details that I've got to set straight\n"; -print "in the config and man files, along with generating the ssh keys\n"; -print "for this machine (if it doesn't already have them).\n"; -print "\n"; -print "I like to install my config-related files in: -print " ${sysconfdir}\n"; -print "and, if you choose to continue, you will find a backup of the\n"; -print "original files in:\n"; -print " ${backupdir}/\n"; -print "\n"; -print "Your host keys will remain untouched if they are already present.\n"; -print "If they aren't present, this script will generate them for you.\n"; -print "\n"; +### linkFile( $src, $dest ) +# +# create a symbolic link from $src to $dest. +# + +sub linkFile +{ + my($src, $dest) = @_; + + if ( !isPresent($src) ) + { + debug1("$src is not readable... not creating $dest.\n"); + return; + } + + if ( !prepareFileWrite($dest) ) + { + return; + } -$response = query_boolean("Do you wish to continue with the setup package?","y"); + action("ln -s $src $dest"); +} -if ($response eq "n") +### copyFile( $src, $dest ) +# +# copy the file pointed to by $src to the location specified by $dest. in the +# process observe the rules regarding when the '-force' flag was passed to us. +# + +sub copyFile { - print "\n"; - print "Okay.. exiting gsi_openssh setup.\n"; + my($src, $dest) = @_; + + if ( !isReadable($src) ) + { + debug1("$src is not readable... not creating $dest.\n"); + return; + } + + if ( !prepareFileWrite($dest) ) + { + return; + } - exit 0; + action("cp $src $dest"); } -test_dirs(); -backup_files(); -copy_setup_files(); -runkeygen(); -fixpaths(); +### copySXXScript( $in, $out ) +# +# parse the input file, substituting in place the value of GLOBUS_LOCATION, and +# write the result to the output file. +# -my $metadata = new Grid::GPT::Setup(package_name => "gsi_openssh_setup"); +sub copySXXScript +{ + my($in, $out) = @_; + my($tmpgpath); -$metadata->finish(); + if ( !isReadable($in) ) + { + debug1("$in is not readable... not creating $out.\n"); + return; + } + + if ( !prepareFileWrite($out) ) + { + return; + } + + # + # clean up any junk in the globus path variable + # + + $tmpgpath = $gpath; + $tmpgpath =~ s:/+:/:g; + $tmpgpath =~ s:([^/]+)/$:\1:g; + + # + # read in the script, substitute globus location, then write it back out + # + + $data = readFile($in); + $data =~ s|\@GLOBUS_LOCATION\@|$tmpgpath|g; + writeFile($out, $data); + action("chmod 755 $out"); +} + +### readFile( $filename ) +# +# reads and returns $filename's contents +# + +sub readFile +{ + my($filename) = @_; + my($data); + + open(IN, "$filename") || exitDie("ERROR: Can't open '$filename': $!\n"); + $/ = undef; + $data = ; + $/ = "\n"; + close(IN); + + return $data; +} + +### writeFile( $filename, $fileinput ) +# +# create the inputs to the ssl program at $filename, appending the common name to the +# stream in the process +# + +sub writeFile +{ + my($filename, $fileinput) = @_; + + # + # test for a valid $filename + # + + if ( !defined($filename) || (length($filename) lt 1) ) + { + exitDie("ERROR: Filename is undefined!\n"); + } + + # + # verify that we are prepared to work with $filename + # + + if ( !prepareFileWrite($filename) ) + { + return; + } + + # + # write the output to $filename + # -print "\n"; -print "$myname: Finished configuring package 'gsi_openssh'.\n"; -print "---------------------------------------------------------------\n"; + open(OUT, ">$filename"); + print OUT "$fileinput"; + close(OUT); +} + +### debug1( $arg1, $arg2 ) +# +# Print out a debugging message at level 1. +# +sub debug1 +{ + debug(string => \@_, level => 1); +} + +### debug0( $arg1, $arg2 ) # -# Just need a minimal action() subroutine for now.. +# Print out a debugging message at level 0. +# + +sub debug0 +{ + debug(string => \@_, level => 0); +} + +### debug( string => $string, level => $level ) +# +# Print out debugging messages at various levels. Feel free to use debugN() directly +# which in turn calls this subroutine. +# + +sub debug +{ + my %args = @_; + + if (!defined($args{'level'})) + { + $args{'level'} = 0; + } + + if ($verbose >= $args{'level'}) + { + printf(@{$args{'string'}}); + } +} + +### action( $command ) +# +# run $command within a proper system() command. # sub action { - my ($command) = @_; + my($command) = @_; - printf "$command\n"; + debug1("$command\n"); - my $result = system("$command 2>&1"); + my $result = system("$command >/dev/null 2>&1"); if (($result or $?) and $command !~ m!patch!) { - die "ERROR: Unable to execute command: $!\n"; + exitDie("ERROR: Unable to execute $command: $!\n"); } } +### exitDie( $error ) +# +# a horribly named method meant to look like die but only exit, thereby not causing +# gpt-postinstall to croak. +# + +sub exitDie +{ + my($error) = @_; + + print $error; + exit; +} + +### query_boolean( $query_text, $default ) +# +# query the user with a string, and expect a response. If the user hits +# 'enter' instead of entering an input, then accept the default response. +# + sub query_boolean { - my ($query_text, $default) = @_; - my $nondefault, $foo, $bar; + my($query_text, $default) = @_; + my($nondefault, $foo, $bar); + + if ( !$prompt ) + { + print "Prompt suppressed. Continuing...\n"; + return "y"; + } # # Set $nondefault to the boolean opposite of $default. @@ -384,11 +1129,124 @@ sub query_boolean $foo = ; ($bar) = split //, $foo; - if ($bar ne $nondefault) + if ( grep(/\s/, $bar) ) + { + # this is debatable. all whitespace means 'default' + + $bar = $default; + } + elsif ($bar eq '') + { + $bar = $default; + } + elsif ($bar ne $default) + { + # everything else means 'nondefault'. + + $bar = $nondefault; + } + else { + # extraneous step. to get here, $bar should be eq to $default anyway. + $bar = $default; } return $bar; } +### absolutePath( $file ) +# +# converts a given pathname into a canonical path using the abs_path function. +# + +sub absolutePath +{ + my($file) = @_; + my $home = $ENV{'HOME'}; + $file =~ s!~!$home!; + my $startd = cwd(); + $file =~ s!^\./!$startd/!; + $file = "$startd/$file" if $file !~ m!^\s*/!; + $file = abs_path($file); + return $file; +} + +### getOwnerID( $file ) +# +# return the uid containing the owner ID of the given file. +# + +sub getOwnerID +{ + my($file) = @_; + my($uid); + + # + # call stat() to get the mode of the file + # + + $uid = (stat($file))[4]; + + return $uid; +} + +### getMode( $file ) +# +# return a string containing the mode of the given file. +# + +sub getMode +{ + my($file) = @_; + my($tempmode, $mode); + + # + # call stat() to get the mode of the file + # + + $tempmode = (stat($file))[2]; + if (length($tempmode) < 1) + { + return ""; + } + + # + # call sprintf to format the mode into a UNIX-like string + # + + $mode = sprintf("%04o", $tempmode & 07777); + + return $mode; +} + +### userExists( $username ) +# +# given a username, return true if the user exists on the system. return false +# otherwise. +# + +sub userExists +{ + my($username) = @_; + my($uid); + + # + # retrieve the userid of the user with the given username + # + + $uid = getpwnam($username); + + # + # return true if $uid is defined and has a length greater than 0 + # + + if ( defined($uid) and (length($uid) > 0) ) + { + return 1; + } + else + { + return 0; + } +}