# Copyright 2001,2002 Hewlett-Packard Corporation
# Licensed under the GNU General Public License
# $Id: HP_UX.pm,v 1.57 2003/05/09 22:56:13 hpbuck Exp $

package Bastille::HP_UX;

use Bastille::API;

@ENV="";
$ENV{PATH}="";
$ENV{CDPATH}=".";
$ENV{BASH_ENV}="";

#######################################################################
##                   HP-UX specific hardening steps                  ##
#######################################################################

&StackNoExecute;
&RestrictSwacls;
&Ndd;
&Netstat;
&OtherTools;
&MailConfig;


######################################################################
#  StackNoExecute:  This subroutine uses kmtune and mk_kernel
#                   in order to un-set the executable stack kernel
#                   parameter and then recompile the kernel with
#                   the parameter value.
######################################################################

sub StackNoExecute {

  if (&getGlobalConfig("HP_UX","stack_execute") eq "Y") {
       &B_log("ACTION","# sub Stack Execute \n");
       # get binaries to be used...
       my $chmod = &getGlobal('BIN',"chmod"); 
       my $exportpath = &getGlobal('BIN',"umask")." 077; export PATH=/usr/bin;";
       my $kmtune = &getGlobal('BIN', "kmtune");       #kmtune's path
       my $kctune = &getGlobal('BIN', "kctune");       #kctune's path
       my $mk_kernel = &getGlobal('BIN', "mk_kernel"); #mk_kernel's path

       if (-x $kctune) {
          my @current=`$kctune -q executable_stack -P current`;

          # get the second column (1) on the first line (0)
          my $curval=(split /\s+/, $current[0])[1];

          &B_System("$kctune -K -s executable_stack=0",
                    "$kctune -K -s executable_stack=$curval");
       } else {
         # get the current kernel parameter information...

         # get current pending kernel parameters
         my @kmdiff = `$exportpath $kmtune -d`;
         # get executable stack query information
         my @kmq = `$exportpath $kmtune -q executable_stack`;
         my @kmexecq = split /\s+/, $kmq[2];

         if(($kmexecq[1] ne 0) || ($kmexecq[3] ne 0)){     #executable stack protection is not set
	   if($#kmdiff == 1){ #system tunable parameters are current
	       # going ahead and seting executable_stack param to 0
	       if(&B_System("$exportpath $kmtune -s executable_stack=0","$exportpath $kmtune -s executable_stack=$kmexecq[3]\n")){
		   #changed param successfully
		   &B_log("ACTION","Planned value of executable_stack tunable parameter is set to secure.\n");

		   if(&B_System("$exportpath $mk_kernel -o /stand/vmunix",
			     "$exportpath $kmtune -s executable_stack=$kmexecq[3]; $mk_kernel -o /stand/vmunix\n")){
		       # Kernel Build Successful
		       my $kernelbuilddir=&getGlobal('DIR',"dlkm_kernel_build");
		       if ( -e $kernelbuilddir ) {
                          # Just to make sure; this change should never be reverted
		          &B_System("$chmod og-w " .$kernelbuilddir,"");
                       }
		       &B_log("ACTION","Kernel Build Successful: Reboot for changes to take affect\n");
		       &B_TODO("\n\n---------------------------------\nStack Execute Permissions:\n" .
			       "---------------------------------\n" .
			       "Please reboot your system to enable stack execution protection.\n\n");
		   }
		   else{
		       &B_log("ERROR","The kernel build failed. Could not compile kernel.\n");
		   }
	       }
	       else{
		   &B_log("ERROR","The kernel build failed. Could not set tunable parameter.\n");
	       }
	   }
	   else{
	       &B_log("ERROR","The kernel build failed.  Tunable parameters are in an unstable\n".
                         "         state.  (Perhaps you forgot to reboot?)  Resolve the issue shown\n".
                         "         by the command $kmtune -d\n");
	   }
         }else{
	   &B_log("ACTION","System already has kernel level stack execution protection. No changes made.\n");
         }
       }
   }
}

sub RestrictSwacls {
    if (&getGlobalConfig("HP_UX","restrict_swacls") eq "Y") {
	&B_log("ACTION","# sub Restrict SWACLS\n");
	

	my $swagentd = &getGlobal('BIN',"swagentd");
	my $ps = &getGlobal('BIN',"ps");
	
	# is swagentd running
	my $isRunning=0;
	# process table.
	my @psTable = `$ps -elf`;
	foreach my $process (@psTable) {
	    if($process =~ $swagentd) {
		$isRunning = 1;
	    } 
	}
	
	if($isRunning) {
	    
	    # get the current permissions to store for revert later
	    my $swacl = &getGlobal('BIN','swacl');
	    
	    # Get the current swacl's for revert.
	    
	    # if no value is set for current permissions add any_other:-
	    # which is effectively the same as removing it all together.
	    my $hostperms="-";
	    my @host_swacl = `$swacl -l host`;
	    foreach my $definition (@host_swacl){
		# look for at least one non-'-'
		chomp $definition; #otherwise, \n matches as "non-dash"
		if($definition =~ /^any_other:(.*[^-]+.*)$/) {
		    $hostperms=$1;
		}
	    }
	    
	    my $rootperms = "-";
	    my @root_swacl = `$swacl -l root`;
	    foreach my $definition (@root_swacl){
		chomp $definition; #otherwise, \n matches as "non-dash"
		# look for at least one non-'-'
		if($definition =~ /^any_other:(.*[^-]+.*)$/) {
		    $rootperms=$1;
		}
	    }
	    
	    # Make the change.
	    
	    # edit host permissions  NO one off of host
	    &B_System(&getGlobal('BIN','swacl') . " -l host -D any_other", 
		      &getGlobal('BIN','swacl') . " -l host -M any_other:$hostperms");
	    # edit user permissions NO one except root
	    &B_System(&getGlobal('BIN','swacl') . " -l root -D any_other", 
		      &getGlobal('BIN','swacl') . " -l root -M any_other:$rootperms");
	}
	else {
	    &B_TODO("---------------------------------\n" . 
		    "SD Access Control Lists:\n" .
		    "---------------------------------\n" .
		    "Bastille was unable to make changes to the SD access control lists.\n" .
		    "In order to make changes swagentd must be running.  Ensure swagentd is\n" . 
		    "running and then run \"bastille -b\" to allow Bastille to the make SD access\n" . 
		    "control list changes.\n");
	}
    }
}

sub Ndd {

   # key is           NDD_NAME 
   # array element[0] TRANSPORT_NAME 
   # array element[1] NDD_VALUE (new)
   my %newNDD = (
      "ip_forward_directed_broadcasts" =>["ip",   "0"],
      "ip_forward_src_routed"          =>["ip",   "0"],
      "ip_forwarding"                  =>["ip",   "0"],
      "ip_ire_gw_probe"                =>["ip",   "0"],
      "ip_pmtu_strategy"               =>["ip",   "1"],
      "ip_respond_to_echo_broadcast"   =>["ip",   "0"],
      "ip_send_redirects"              =>["ip",   "0"],
      "ip_send_source_quench"          =>["ip",   "0"],
      "tcp_syn_rcvd_max"               =>["tcp","1000"],
      "tcp_conn_request_max"           =>["tcp","4096"] );


   if (&getGlobalConfig("HP_UX","ndd") eq "Y") {
       &B_log("ACTION","# sub Ndd\n");
       # get all current values (-A) starting with any of the given names
       my $ch_rc = &getGlobal('BIN','ch_rc');
       my @origParams = 
	   `$ch_rc -l -A -v -p TRANSPORT_NAME -p NDD_NAME -p NDD_VALUE`;
       my $ndd_call = &getGlobal('BIN','ndd');
       
       my $nddComplete = 1;
       for my $newNDDKey (keys %newNDD){
	   my $nddGetValue = `$ndd_call -get /dev/$newNDD{$newNDDKey}[0] $newNDDKey`;
	   chomp $nddGetValue;
	   if($nddGetValue ne $newNDD{$newNDDKey}[1]) {
	       $nddComplete = 0;  # if the machine already has the proper ndd values
	   }                      # then mark nddComplete.
       }

      # $#origParams returns the last index (0 if there is one element)
      # if there are any parameters already set in nddconf, then we need to
      # have some manual intervention, because any merge will probably mess
      # things up
      if($#origParams > -1 && (! $nddComplete) ) {
        my $ndd_text = 
           "This version of Bastille cannot resolve the ndd configuration\n" .
           "changes that were selected.  The following are the parameters\n" .
           "and the suggested values.\n" .
           "\n" . 
           "                                  Default    Suggested\n" .
           "                                             for security\n" .
           "---------------------------------------------------------\n" .
           "ip_forward_directed_broadcasts       1   =>    0\n" .
           "ip_forward_src_routed                1   =>    0\n" .
           "ip_forwarding                        2   =>    0\n" .
           "ip_ire_gw_probe                      1   =>    0\n" .
           "ip_pmtu_strategy                     2   =>    1\n" .
           "ip_respond_to_echo_broadcast         1   =>    0\n" .
           "ip_send_redirects                    1   =>    0\n" .
           "ip_send_source_quench                1   =>    0\n" .
           "tcp_syn_rcvd_max                   500   => 1000\n" .
           "tcp_conn_request_max                20   => 4096\n" .
           "\n" .
           "You will need to merge your current ndd settings in \n" .
           "&getGlobal('FILE', 'nddconf') with these manually.\n\n" .
           "For more information on each of these parameters, run\n" .
           "\n" .
           "ndd -h\n\n";
	&B_TODO("\n---------------------------------\nNdd Parameters:\n" .
		"---------------------------------\n" .
		$ndd_text);
      } 
       elsif (! $nddComplete) {
	   # setting bastille backend values of nddconf
	   my $index = 0;
	   # this string will allow bastille to revert the changes made to 
	   # the ndd settings.
	   my $revertString =""; 
	   
	   # This for generates the configuration file for ndd and it generates
	   # the revertString which will put the system back to its initial state
	   # when bastille -r is run.
	   for my $newNDDKey (keys %newNDD){
	       # string to be added to the configuration file
	       my $paramstring = 
		   " -p TRANSPORT_NAME[${index}]=" . $newNDD{$newNDDKey}[0] .
		   " -p NDD_NAME[${index}]=" . $newNDDKey .
		   " -p NDD_VALUE[${index}]=" . $newNDD{$newNDDKey}[1];

	       # string that receives the current value of the newNDDKey 
	       my $ndd_call = &getGlobal('BIN','ndd');
	       my $nddGetValue = `$ndd_call -get /dev/$newNDD{$newNDDKey}[0] $newNDDKey`;
	       chomp $nddGetValue;
	       # string that is generated to put ndd back to its pre-Bastilled state
	       $revertString .= "ndd -set /dev/" . $newNDD{$newNDDKey}[0] .
		   " " . $newNDDKey . " " . $nddGetValue . "\n";
	       

	       &B_System (&getGlobal('BIN','ch_rc') . " -a $paramstring " .
                          &getGlobal('FILE', 'nddconf'),
			  &getGlobal('BIN','ch_rc') . " -r $paramstring");
	       
	       $index++;
	   }    
	   # re-read config file after setting new parameters (at run time)
	   &B_System (&getGlobal('BIN',"ndd") . " -c","$revertString");
       }
   }
}

# The purpose of this subroutine is to add to the TODO.txt list some information
# about how the user should determine which ports are world listening
sub Netstat {
    if (&getGlobalConfig("HP_UX","scan_ports") eq "Y") {
	&B_log("ACTION","# sub Netstat\n");
	my $netstat_text = 
	    "Run a port scan to see what processes are still listening:\n" .
            "We recommend that you download the \"lsof\" tool from\n" .
            "  ftp://vic.cc.purdue.edu/pub/tools/unix/lsof/\n" .
            "and then run\n" .
            "  /path/to/lsof -i\n" .
	    "However you may also use the built-in tool \"netstat\" like:\n" .
	    "  /usr/bin/netstat -an\n" .
            "for a comprehensive listing of processes which are listening on\n" .
            "external ports.  More information is in the netstat man page and\n" .
            "the lsof documentation.\n\n";
	&B_TODO("\n---------------------------------\nPort Scan:\n" .
		"---------------------------------\n" .
		$netstat_text);
    }
}

# give pointers to other tools
sub OtherTools {

  if(&getGlobalConfig("HP_UX","other_tools") eq "Y"){

    my $toolinfo = "HP-UX Bastille can help you configure a lot of the security\n" .
                   "relevant parts of the HP-UX Operating System.  However, it\n" .
                   "is not a complete security solution.  HP provides many other\n" .
                   "tools which should be used in concert with your local security\n" .
                   "policies to ensure that you are adequately protected from attack.\n" .
                   "The following is a brief overview of some of the products and\n".
                   "services which are available, but not yet referenced elsewhere\n".
                   "within Bastille:\n\n";

                   # This can eventually be replaced by a more granular selection of types of
                   # tools the user might be interested in by putting if's around sections of
                   # text.
                   #------------ proper spacing point of reference-----------------------------

    $toolinfo .= "  - Authentication and other directory services:\n";
    $toolinfo .= "    * The hp-ux AAA server provides authentication, authorization\n" .
                 "      and accounting services using the RADIUS protocol\n";
    $toolinfo .= "    * The hp-ux Kerberos server provides key distribution and strong \n" .
                 "      authentication for client/server applications by using secret-key\n".
                 "      cryptography\n";
    $toolinfo .= "    * ldap-ux allows hp-ux to use LDAP based directory servers,\n" .
                 "      allowing a single repository for user, group and other\n" .
                 "      organizational data, integrating user authentication\n" .
                 "      among many different organizational tools and HP-UX.\n\n";
  
    $toolinfo .= "  - VPN\n";
    $toolinfo .= "    * hp-ux IPSec/9000 provides secure and private communication\n".
                 "      over the Internet and within the enterprise-without modifying\n".
                 "      existing applications\n";
  
    $toolinfo .= "  - Intrusion Detection Software\n";
    $toolinfo .= "    * IDS/9000 enhances host-level security with near real-time\n".
                 "      automatic monitoring of each configured host for signs of\n".
                 "      potentially damaging intrusions\n".
                 "    * Tripwire is a tool for ensuring the integrity of your data\n".
                 "      and detecting and analyzing intrusions after they have \n".
                 "      happened.  See\n".
                 "        http://www.tripwire.org\n" .
                 "      (Tripwire is not an HP supported product)\n\n";
  
    $toolinfo .= "  - Replacement for telnet, remsh, and ftp\n";
    $toolinfo .= "    * hp-ux secure shell provides a secure alternative for all\n".
                 "      your file transfer and remote shell needs.\n\n";
  
    $toolinfo .= "  - Special purpose security Operating System\n";
    $toolinfo .= "    * Virtual Vault is an HP-UX based operating system with root\n" .
                 "      containment features.  It is the only trusted and proven\n" .
                 "      Web-server platform on the market with no reported break-ins.\n\n";
    $toolinfo .= "  - Consulting\n";
    $toolinfo .= "    * HP consultants can help you with a variety of security needs,\n".
                 "      including penetration tests, custom security architectures,\n".
                 "      and creating custom Bastille configs to suit your\n".
                 "      unique needs.\n\n";
  
    $toolinfo .= "New tools and resources are being released all the time.  Check\n".
                 "  http://www.hp.com/security\n".
                 "for more resources and information.\n\n";

     &B_TODO("\n---------------------------------\nOther Tool Information:\n" . 
	     "---------------------------------\n" . 
	     $toolinfo);
    
  }
}

sub MailConfig {
    if(&getGlobalConfig("HP_UX","mail_config") eq "Y"){
	&B_log("ACTION","# sub MailConfig");
        my $config_email='bastille-configs@fc.hp.com';
        my $todo_email='bastille-todo@fc.hp.com';
        my $feedback_email='bastille-feedback@fc.hp.com';

        my $mailprogram = &getGlobal('BIN','mail');
        my $config = &getGlobal('BFILE','config');
	my $todo = &getGlobal('BFILE','TODO');
        my $echo = &getGlobal('BIN','echo');
        my $uname = &getGlobal('BIN','uname');

        &B_System("$mailprogram -s \"\$($uname -a)\" $config_email < $config",
                  "$echo \"REVERT\" | $mailprogram -s \"\$($uname -a)\" $config_email "); 
 
	&B_TODO("\n---------------------------------\nConfiguration File Mailing:\n" . 
		"---------------------------------\n" .
		"Your config file and TODO list have been mailed to\n".
		"$config_email and $todo_email respectively.\n" .
                "If you have other feedback or feature requests, please\n".
		"send it to $feedback_email.  We are especially interested in your\n" .
                "priorities in terms of TODO items you feel need automation and what\n".
		"features and lockdown steps you feel are missing entirely.\n".
		"Thank you.\n\n");

	&B_System("$mailprogram -s \"\$($uname -a)\" $todo_email < $todo","");

    }
}

1;









