1package Bastille::API::HPSpecific; 2 3use strict; 4use Bastille::API; 5use Bastille::API::FileContent; 6 7require Exporter; 8our @ISA = qw(Exporter); 9our @EXPORT_OK = qw( 10getIPFLocation 11getGlobalSwlist 12B_check_system 13B_swmodify 14B_load_ipf_rules 15B_Schedule 16B_ch_rc 17B_set_value 18B_chperm 19B_install_jail 20B_list_processes 21B_list_full_processes 22B_deactivate_inetd_service 23B_get_rc 24B_set_rc 25B_chrootHPapache 26isSystemTrusted 27isTrustedMigrationAvailable 28checkServiceOnHPUX 29B_get_path 30convertToTrusted 31isOKtoConvert 32convertToShadow 33getSupportedSettings 34B_get_sec_value 35secureIfNoNameService 36isUsingRemoteNameService 37remoteServiceCheck 38remoteNISPlusServiceCheck 39B_create_nsswitch_file 40B_combine_service_results 41 42%priorBastilleNDD 43%newNDD 44); 45our @EXPORT = @EXPORT_OK; 46 47 48 49# "Constants" for use both in testing and in lock-down 50our %priorBastilleNDD = ( 51 "ip_forward_directed_broadcasts" =>["ip", "0"], 52 "ip_forward_src_routed" =>["ip", "0"], 53 "ip_forwarding" =>["ip", "0"], 54 "ip_ire_gw_probe" =>["ip", "0"], 55 "ip_pmtu_strategy" =>["ip", "1"], 56 "ip_respond_to_echo_broadcast" =>["ip", "0"], 57 "ip_send_redirects" =>["ip", "0"], 58 "ip_send_source_quench" =>["ip", "0"], 59 "tcp_syn_rcvd_max" =>["tcp","1000"], 60 "tcp_conn_request_max" =>["tcp","4096"] ); 61 62our %newNDD = ( 63 "ip_forward_directed_broadcasts" =>["ip", "0"], 64 "ip_forward_src_routed" =>["ip", "0"], 65 "ip_forwarding" =>["ip", "0"], 66 "ip_ire_gw_probe" =>["ip", "0"], 67 "ip_pmtu_strategy" =>["ip", "1"], 68 "ip_respond_to_echo_broadcast" =>["ip", "0"], 69 "ip_send_redirects" =>["ip", "0"], 70 "ip_send_source_quench" =>["ip", "0"], 71 "tcp_syn_rcvd_max" =>["tcp","4096"], 72 "tcp_conn_request_max" =>["tcp","4096"], 73 "arp_cleanup_interval" =>["arp","60000"], 74 "ip_respond_to_timestamp" =>["ip", "0"], 75 "ip_respond_to_timestamp_broadcast" => ["ip","0"] ); 76 77 78#################################################################### 79# 80# This module makes up the HP-UX specific API routines. 81# 82#################################################################### 83# 84# Subroutine Listing: 85# &HP_ConfigureForDistro: adds all used file names to global 86# hashes and generates a global IPD 87# hash for SD modification lookup. 88# 89# &getGlobalSwlist($): Takes a fully qualified file name 90# and returns product:filset info 91# for that file. returns undef if 92# the file is not present in the IPD 93# 94# &B_check_system: Runs a series of system queries to 95# determine if Bastille can be safely 96# ran on the current system. 97# 98# &B_swmodify($): Takes a file name and runs the 99# swmodify command on it so that the 100# IPD is updated after changes 101# 102# &B_System($$): Takes a system command and the system 103# command that should be used to revert 104# whatever was done. Returns 1 on 105# success and 0 on failure 106# 107# &B_Backtick($) Takes a command to run and returns its stdout 108# to be used in place of the prior prevelent use 109# of un-error-handled backticks 110# 111# &B_load_ipf_rules($): Loads a set of ipfrules into ipf, storing 112# current rules for later reversion. 113# 114# &B_Schedule($$): Takes a pattern and a crontab line. 115# Adds or replaces the crontab line to 116# the crontab file, depending on if a 117# line matches the pattern 118# 119# &B_ch_rc($$): Takes a the rc.config.d flag name and 120# new value as well as the init script 121# location. This will stop a services 122# and set the service so that it will 123# not be restarted. 124# 125# &B_set_value($$$): Takes a param, value, and a filename 126# and sets the given value in the file. 127# Uses ch_rc, but could be rewritten using 128# Bastille API calls to make it work on Linux 129# 130# &B_TODO($): Appends the give string to the TODO.txt 131# file. 132# 133# &B_chperm($$$$): Takes new perm owner and group of given 134# file. TO BE DEPRECATED!!! 135# 136# &B_install_jail($$): Takes the jail name and the jail config 137# script location for a give jail... 138# These scripts can be found in the main 139# directory e.g. jail.bind.hpux 140# 141##################################################################### 142 143############################################################################## 144# 145# HP-UX Bastille directory structure 146# 147############################################################################## 148# 149# /opt/sec_mgmt/bastille/bin/ -- location of Bastille binaries 150# /opt/sec_mgmt/bastille/lib/ -- location of Bastille modules 151# /opt/sec_mgmt/bastille/doc/ -- location of Bastille doc files 152# 153# /etc/opt/sec_mgmt/bastille/ -- location of Bastille config files 154# 155# /var/opt/sec_mgmt/bastille/log -- location of Bastille log files 156# /var/opt/sec_mgmt/bastille/revert -- directory holding all Bastille- 157# created revert scripts 158# /var/opt/sec_mgmt/bastille/revert/backup -- directory holding the original 159# files that Bastille modifies, 160# with permissions intact 161# 162############################################################################## 163 164sub getIPFLocation () { # Temporary until we get defined search space support 165 my $ipf=&getGlobal('BIN','ipf_new'); 166 my $ipfstat=&getGlobal('BIN','ipfstat_new'); 167 if (not(-e $ipf)) { # Detect if the binaries moved 168 $ipf = &getGlobal('BIN','ipf'); 169 $ipfstat=&getGlobal('BIN','ipfstat'); 170 } 171 return ($ipf, $ipfstat); 172} 173 174############################################## 175# Given a combination of service results, provided 176# in an array, this function combines the result into 177# a reasonable aggregate result 178############################################## 179 180sub B_combine_service_results(@){ 181 my @results = @_; 182 183 #TODO: Consider greater sophistication wrt inconsistent, or not installed. 184 185 foreach my $result (@results) { 186 if (not(($result == SECURE_CAN_CHANGE) or 187 ($result == SECURE_CANT_CHANGE) or 188 ($result == NOT_INSTALLED()))) { 189 return NOTSECURE_CAN_CHANGE(); 190 } 191 } 192 return SECURE_CANT_CHANGE(); 193} 194 195#################################################################### 196# &getGlobalSwlist ($file); 197# This function returns the product and fileset information for 198# a given file or directory if it exists in the IPD otherwise 199# it returns undefined "undef" 200# 201# uses $GLOBAL_SWLIST{"$FILE"} 202#################################################################### 203sub getGlobalSwlist($){ 204 no strict; 205 my $file = $_[0]; 206 207 208 if(! %GLOBAL_SWLIST) { 209 # Generating swlist database for swmodify changes that will be required 210 # The database will be a hash of fully qualified file names that reference 211 # the files product name and fileset. These values are required to use 212 # swmodify... 213 214 # Files tagged 'is_volatile' in the IPD are not entered in the swlist database 215 # in order to avoid invoking swmodify if the file is changed later. Attempting to 216 # swmodify 'volatile' files is both unneccessary and complicated since swverify will 217 # not evaluate volatile files anyway, and adding another value to the swlist database 218 # would require complex code changes. 219 220 # temp variable to keep swlist command /usr/sbin/swlist 221 my $swlist = &getGlobal('BIN',"swlist"); 222 223 # listing of each directory and file that was installed by SD on the target machine 224 my @fileList = `$swlist -a is_volatile -l file`; 225 226 # listing of each patch and the patches that supersede each. 227 # hash which is indexed by patch.fileset on the system 228 my %patchSuperseded; 229 230 my @patchList = `${swlist} -l fileset -a superseded_by *.*,c=patch 2>&1`; 231 # check to see if any patches are present on the system 232 if(($? >> 8) == 0) { 233 234 # determining patch suppression for swmodify. 235 foreach my $patchState (@patchList) { 236 # removing empty lines and commented lines. 237 if($patchState !~ /^\s*\#/ && $patchState !~ /^\s*$/) { 238 239 # removing leading white space 240 $patchState =~ s/^\s+//; 241 my @patches = split /\s+/, $patchState; 242 if($#patches == 0){ 243 # patch is not superseded 244 $patchSuperseded{$patches[0]} = 0; 245 } 246 else { 247 # patch is superseded 248 $patchSuperseded{$patches[0]} = 1; 249 } 250 } 251 } 252 } 253 else { 254 &B_log("DEBUG","No patches found on the system.\n"); 255 } 256 257 if($#fileList >= 0){ 258 # foreach line of swlist output 259 foreach my $fileEntry ( @fileList ){ 260 #filter out commented portions 261 if( $fileEntry !~ /^\s*\#/ ){ 262 chomp $fileEntry; 263 # split the output into three fields: product.fileset, filename, flag_isvolatile 264 my( $productInfo, $file, $is_volatile ) = $fileEntry =~ /^\s*(\S+): (\S+)\t(\S+)/ ; 265 # do not register volatile files 266 next if ($is_volatile =~ /true/); # skip to next file entry 267 $productInfo =~ s/\s+//; 268 $file =~ s/\s+//; 269 # if the product is a patch 270 if($productInfo =~ /PH(CO|KL|NE|SS)/){ 271 # if the patch is not superseded by another patch 272 if($patchSuperseded{$productInfo} == 0){ 273 # add the patch to the list of owner for this file 274 push @{$GLOBAL_SWLIST{"$file"}}, $productInfo; 275 } 276 } 277 # not a patch. 278 else { 279 # add the product to the list of owners for this file 280 push @{$GLOBAL_SWLIST{"$file"}}, $productInfo; 281 } 282 283 } 284 } 285 } 286 else{ 287 # defining GLOBAL_SWLIST in error state. 288 $GLOBAL_SWLIST{"ERROR"} = "ERROR"; 289 &B_log("ERROR","Could not execute swlist. Swmodifys will not be attempted"); 290 } 291 } 292 293 if(exists $GLOBAL_SWLIST{"$file"}){ 294 return $GLOBAL_SWLIST{"$file"}; 295 } 296 else { 297 return undef; 298 } 299} 300 301################################################################### 302# &B_check_system; 303# This subroutine is called to validate that bastille may be 304# safely run on the current system. It will check to insure 305# that there is enough file system space, mounts are rw, nfs 306# mounts are not mounted noroot, and swinstall, swremove and 307# swmodify are not running 308# 309# uses ErrorLog 310# 311################################################################## 312sub B_check_system { 313 # exitFlag is one if a conflict with the successful execution 314 # of bastille is found. 315 my $exitFlag = 0; 316 317 my $ignoreCheck = &getGlobal("BDIR","config") . "/.no_system_check"; 318 if( -e $ignoreCheck ) { 319 return $exitFlag; 320 } 321 322 # first check for swinstall, swmodify, or swremove processes 323 my $ps = &getGlobal('BIN',"ps") . " -el"; 324 my @processTable = `$ps`; 325 foreach my $process (@processTable) { 326 if($process =~ /swinstall/ ) { 327 &B_log("ERROR","Bastille cannot run while a swinstall is in progress.\n" . 328 "Complete the swinstall operation and then run Bastille.\n\n"); 329 $exitFlag = 1; 330 } 331 332 if($process =~ /swremove/ ) { 333 &B_log("ERROR","Bastille cannot run while a swremove is in progress.\n" . 334 "Complete the swremove operation and then run Bastille.\n\n"); 335 $exitFlag = 1; 336 } 337 338 if($process =~ /swmodify/ ) { 339 &B_log("ERROR","Bastille cannot run while a swmodify is in progress.\n" . 340 "Complete the swmodify operation and then run Bastille.\n\n"); 341 $exitFlag = 1; 342 } 343 344 } 345 346 # check for root read only mounts for /var /etc /stand / 347 # Bastille is required to make changes to these file systems. 348 my $mount = &getGlobal('BIN',"mount"); 349 my $rm = &getGlobal('BIN',"rm"); 350 my $touch = &getGlobal('BIN',"touch"); 351 352 my @mnttab = `$mount`; 353 354 if(($? >> 8) != 0) { 355 &B_log("WARNING","Unable to use $mount to determine if needed partitions\n" . 356 "are root writable, based on disk mount options.\n" . 357 "Bastille will continue but note that disk\n" . 358 "mount checks were skipped.\n\n"); 359 } 360 else { 361 foreach my $record (@mnttab) { 362 my @fields = split /\s+/, $record; 363 if ((defined $fields[0]) && (defined $fields[2]) && (defined $fields[3])) { 364 my $mountPoint = $fields[0]; 365 my $mountType = $fields[2]; 366 my $mountOptions = $fields[3]; 367 368 # checks for /stand and /var/* removed 369 if($mountPoint =~ /^\/$|^\/etc|^\/var$/) { 370 371 if($mountOptions =~ /^ro,|,ro,|,ro$/) { 372 &B_log("ERROR","$mountPoint is mounted read-only. Bastille needs to make\n" . 373 "modifications to this file system. Please remount\n" . 374 "$mountPoint read-write and then run Bastille again.\n\n"); 375 $exitFlag = 1; 376 } 377 # looking for an nfs mounted file system 378 if($mountType =~/.+:\//){ 379 my $fileExisted=0; 380 if(-e "$mountPoint/.bastille") { 381 $fileExisted=1; 382 } 383 384 `$touch $mountPoint/.bastille 1>/dev/null 2>&1`; 385 386 if( (! -e "$mountPoint/.bastille") || (($? >> 8) != 0) ) { 387 &B_log("ERROR","$mountPoint is an nfs mounted file system that does\n" . 388 "not allow root to write to. Bastille needs to make\n" . 389 "modifications to this file system. Please remount\n" . 390 "$mountPoint giving root access and then run Bastille\n" . 391 "again.\n\n"); 392 393 $exitFlag = 1; 394 } 395 # if the file did not exist befor the touch then remove the generated file 396 if(! $fileExisted) { 397 `$rm -f $mountPoint/.bastille 1>/dev/null 2>&1`; 398 } 399 } 400 } 401 } 402 else { 403 &B_log("WARNING","Unable to use $mount to determine if needed partitions\n" . 404 "are root writable, based on disk mount options.\n" . 405 "Bastille will continue but note that disk\n" . 406 "mount checks were skipped.\n\n"); 407 } 408 } 409 410 } 411 412 # checks for enough disk space in directories that Bastille writes to. 413 my $bdf = &getGlobal('BIN',"bdf"); 414 #directories that Bastille writes to => required space in kilobytes. 415 my %bastilleDirs = ( "/etc/opt/sec_mgmt/bastille" => "4", "/var/opt/sec_mgmt/bastille"=> "1000"); 416 for my $directory (sort keys %bastilleDirs) { 417 my @diskUsage = `$bdf $directory`; 418 419 if(($? >> 8) != 0) { 420 &B_log("WARNING","Unable to use $bdf to determine disk usage for\n" . 421 "$directory\n" . 422 "Bastille will continue but note that disk\n" . 423 "usage checks were skipped.\n\n"); 424 425 } 426 else { 427 # removing bdf header line from usage information. 428 shift @diskUsage; 429 my $usageString= ""; 430 431 foreach my $usageRecord (@diskUsage) { 432 chomp $usageRecord; 433 $usageString .= $usageRecord; 434 } 435 436 $usageString =~ s/^\s+//; 437 438 my @fields = split /\s+/, $usageString; 439 if($#fields != 5) { 440 &B_log("WARNING","Unable to use $bdf to determine disk usage for\n" . 441 "$directory\n" . 442 "Bastille will continue but note that disk\n" . 443 "usage checks were skipped.\n\n"); 444 } 445 else { 446 447 my $mountPoint = $fields[5]; 448 my $diskAvail = $fields[3]; 449 450 if($diskAvail <= $bastilleDirs{"$directory"}) { 451 &B_log("ERROR","$mountPoint does not contain enough available space\n" . 452 "for Bastille to run properly. $directory needs\n" . 453 "at least $bastilleDirs{$directory} kilobytes of space.\n" . 454 "Please clear at least that amount of space from\n" . 455 "$mountPoint and run Bastille again.\n" . 456 "Current Free Space available = ${diskAvail} k\n\n"); 457 $exitFlag = 1; 458 } 459 } 460 } 461 } 462 463 # check to make sure that we are in at least run level 2 before we attempt to run 464 my $who = &getGlobal('BIN', "who") . " -r"; 465 my $levelInfo = `$who`; 466 if(($? >> 8) != 0 ) { 467 &B_log("WARNING","Unable to use \"$who\" to determine system run.\n" . 468 "level Bastille will continue but note that the run\n" . 469 "level check was skipped.\n\n"); 470 } 471 else { 472 chomp $levelInfo; 473 my @runlevel = split /\s+/, $levelInfo; 474 if ((! defined $runlevel[3]) or ($runlevel[3] < 2)) { 475 &B_log("WARNING","Bastille requires a run-level of 2 or more to run properly.\n" . 476 "Please move your system to a higher run level and then\n" . 477 "run 'bastille -b'.\n\n"); 478 if(defined $runlevel[3]) { 479 &B_log("ERROR","Current run-level is '$runlevel[3]'.\n\n"); 480 $exitFlag=1; 481 } 482 else { 483 &B_log("WARNING","Unable to use \"$who\" to determine system run.\n" . 484 "level Bastille will continue but note that the run\n" . 485 "level check was skipped.\n\n"); 486 } 487 } 488 else { 489 &B_log("DEBUG","System run-level is $runlevel[3]\n"); 490 } 491 } 492 493 if($exitFlag) { 494 exit(1); 495 } 496 497} 498 499################################################################### 500# &B_swmodify($file); 501# This subroutine is called after a file is modified. It will 502# redefine the file in the IPD with it's new properties. If 503# the file is not in the IPD it does nothing. 504# 505# uses B_System to make the swmodifications. 506################################################################## 507sub B_swmodify($){ 508 my $file = $_[0]; 509 if(defined &getGlobalSwlist($file)){ 510 my $swmodify = &getGlobal('BIN',"swmodify"); 511 my @productsInfo = @{&getGlobalSwlist($file)}; 512 # running swmodify on files that were altered by this function but 513 # were created and maintained by SD 514 foreach my $productInfo (@productsInfo) { 515 &B_System("$swmodify -x files='$file' $productInfo", 516 "$swmodify -x files='$file' $productInfo"); 517 } 518 } 519} 520 521#################################################################### 522# &B_load_ipf_rules($ipfruleset); 523# This function enables an ipfruleset. It's a little more 524# specific than most API functions, but necessary because 525# ipf doesn't return correct exit codes (syntax error results 526# in a 0 exit code) 527# 528# uses ActionLog and ErrorLog to log 529# calls crontab directly (to list and to read in new jobs) 530################################################################### 531sub B_load_ipf_rules ($) { 532 my $ipfruleset=$_[0]; 533 534 &B_log("DEBUG","# sub B_load_ipf_rules"); 535 536 # TODO: grab ipf.conf dynamically from the rc.config.d files 537 my $ipfconf = &getGlobal('FILE','ipf.conf'); 538 539 # file system changes - these are straightforward, and the API 540 # will take care of the revert 541 &B_create_file($ipfconf); 542 &B_blank_file($ipfconf, 'a$b'); 543 &B_append_line($ipfconf, 'a$b', $ipfruleset); 544 545 # runtime changes 546 547 # define binaries 548 my $grep = &getGlobal('BIN', 'grep'); 549 my ($ipf, $ipfstat) = &getIPFLocation; 550 # create backup rules 551 # This will exit with a non-zero exit code because of the grep 552 my @oldrules = `$ipfstat -io 2>&1 | $grep -v empty`; 553 554 my @errors=`$ipf -I -Fa -f $ipfconf 2>&1`; 555 556 if(($? >> 8) == 0) { 557 558 &B_set_rc("IPF_START","1"); 559 &B_set_rc("IPF_CONF","$ipfconf"); 560 561 # swap the rules in 562 &B_System("$ipf -s","$ipf -s"); 563 564 # now create a "here" document with the previous version of 565 # the rules and put it into the revert-actions script 566 &B_revert_log("$ipf -I -Fa -f - <<EOF\n@{oldrules}EOF"); 567 568 if (@errors) { 569 &B_log("ERROR","ipfilter produced the following errors when\n" . 570 " loading $ipfconf. You probably had an invalid\n" . 571 " rule in ". &getGlobal('FILE','customipfrules') ."\n". 572 "@errors\n"); 573 } 574 575 } else { 576 &B_log("ERROR","Unable to run $ipf\n"); 577 } 578 579} 580 581 582 583#################################################################### 584# &B_Schedule($pattern,$cronjob); 585# This function schedules a cronjob. If $pattern exists in the 586# crontab file, that job will be replaced. Otherwise, the job 587# will be appended. 588# 589# uses ActionLog and ErrorLog to log 590# calls crontab directly (to list and to read in new jobs) 591################################################################### 592sub B_Schedule ($$) { 593 my ($pattern,$cronjob)=@_; 594 $cronjob .= "\n"; 595 596 &B_log("DEBUG","# sub B_Schedule"); 597 my $crontab = &getGlobal('BIN','crontab'); 598 599 my @oldjobs = `$crontab -l 2>/dev/null`; 600 my @newjobs; 601 my $patternfound=0; 602 603 foreach my $oldjob (@oldjobs) { 604 if (($oldjob =~ m/$pattern/ ) and (not($patternfound))) { 605 push @newjobs, $cronjob; 606 $patternfound=1; 607 &B_log("ACTION","changing existing cron job which matches $pattern with\n" . 608 "$cronjob"); 609 } elsif ($oldjob !~ m/$pattern/ ) { 610 &B_log("ACTION","keeping existing cron job $oldjob"); 611 push @newjobs, $oldjob; 612 } #implied: else if pattern matches, but we've 613 #already replaced one, then toss the others. 614 } 615 616 unless ($patternfound) { 617 &B_log("ACTION","adding cron job\n$cronjob\n"); 618 push @newjobs, $cronjob; 619 } 620 621 if(open(CRONTAB, "|$crontab - 2> /dev/null")) { 622 print CRONTAB @newjobs; 623 624 # now create a "here" document with the previous version of 625 # the crontab file and put it into the revert-actions script 626 &B_revert_log("$crontab <<EOF\n" . "@oldjobs" . "EOF"); 627 close CRONTAB; 628 } 629 630 # Now check to make sure it happened, since cron will exit happily 631 # (retval 0) with no changes if there are any syntax errors 632 my @editedjobs = `$crontab -l 2>/dev/null`; 633 634 if (@editedjobs ne @newjobs) { 635 &B_log("ERROR","failed to add cron job:\n$cronjob\n" . 636 " You probably had an invalid crontab file to start with."); 637 } 638 639} 640 641 642#This function turns off a service, given a service name defined in HP-UX.service 643 644sub B_ch_rc($) { 645 646 my ($service_name)=@_; 647 648 if (&GetDistro != "^HP-UX") { 649 &B_log("ERROR","Tried to call ch_rc $service_name on a non-HP-UX\n". 650 " system! Internal Bastille error."); 651 return undef; 652 } 653 my $configfile=""; 654 my $command = &getGlobal('BIN', 'ch_rc'); 655 656 my $startup_script=&getGlobal('DIR','initd') . "/". $service_name; 657 my @rc_parameters= @{ &getGlobal('SERVICE',$service_name) }; 658 my @rcFiles=@{ &getGlobal('RCCONFIG',$service_name) }; 659 my $rcFile=''; 660 if (@rcFiles == 1){ 661 $rcFile=$rcFiles[0]; 662 } else { 663 &B_log("FATAL","Multiple RC Files not yet supported... internal error."); 664 } 665 666 # if the service-related process is not run, and the control variable is stilll 1 667 # there is a inconsistency. in this case we only need to change the control variable 668 my @psnames=@{ &getGlobal('PROCESS',$service_name)}; 669 my @processes; 670 foreach my $psname (@psnames) { 671 $psname .= '\b'; # avoid embedded match; anchor search pattern to trailing word boundry 672 my @procList = &isProcessRunning($psname); 673 if(@procList >= 0){ 674 splice @processes,$#processes+1,0,@procList; 675 } 676 } 677#Actually set the rc variable 678 foreach my $rcVariable (@rc_parameters){ 679 my $orig_value = &B_get_rc($rcVariable); 680 if ($orig_value eq "" ) { #If variable not set, used the defined file 681 $configfile=&getGlobal("DIR","rc.config.d") . "/" . $rcFile; 682 if (not( -f $configfile )) { 683 &B_create_file($configfile); 684 } 685 } 686 &B_log("DEBUG","In B_ch_rc (no procs), setting $rcVariable to 0 in $configfile" . 687 ", with an original value of $orig_value with rcfile: $rcFile"); 688 if ( ! @processes) { # IF there are no processes we don't neet to perform a "stop" 689 &B_set_rc($rcVariable, "0", $configfile); 690 } else { 691 if ( $orig_value !~ "1" ) { #If param is not already 1, the "stop" script won't work 692 &B_set_rc($rcVariable, "1",$configfile); 693 } 694 &B_System ($startup_script . " stop", #stop service, then restart if the user runs bastille -r 695 $startup_script . " start"); 696 # set parameter, so that service will stay off after reboots 697 &B_set_rc($rcVariable, "0", $configfile); 698 } 699 } 700} 701 702 703# This routine sets a value in a given file 704sub B_set_value($$$) { 705 my ($param, $value, $file)=@_; 706 707 &B_log("DEBUG","B_set_value: $param, $value, $file"); 708 if (! -e $file ) { 709 &B_create_file("$file"); 710 } 711 712 # If a value is already set to something other than $value then reset it. 713 #Note that though this tests for "$value ="the whole line gets replaced, so 714 #any pre-existing values are also replaced. 715 &B_replace_line($file,"^$param\\s*=\\s*","$param=$value\n"); 716 # If the value is not already set to something then set it. 717 &B_append_line($file,"^$param\\s*=\\s*$value","$param=$value\n"); 718 719} 720 721 722################################################################################## 723# &B_chperm($owner,$group,$mode,$filename(s)) 724# This function changes ownership and mode of a list of files. Takes four 725# arguments first the owner next the group and third the new mode in oct and 726# last a list of files that the permissions changes should take affect on. 727# 728# uses: &swmodify and &B_revert_log 729################################################################################## 730sub B_chperm($$$$) { 731 my ($newown, $newgrp, $newmode, $file_expr) = @_; 732 my @files = glob($file_expr); 733 734 my $return = 1; 735 736 foreach my $file (@files){ 737 my @filestat = stat $file; 738 my $oldmode = (($filestat[2]/512) % 8) . 739 (($filestat[2]/64) % 8) . 740 (($filestat[2]/8) % 8) . 741 (($filestat[2]) % 8); 742 743 if((chown $newown, $newgrp, $file) != 1 ){ 744 &B_log("ERROR","Could not change ownership of $file to $newown:$newgrp\n"); 745 $return = 0; 746 } 747 else{ 748 &B_log("ACTION","Changed ownership of $file to $newown:$newgrp\n"); 749 # swmodifying file if possible... 750 &B_swmodify($file); 751 &B_revert_log(&getGlobal('BIN',"chown") . " $filestat[4]:$filestat[5] $file\n"); 752 } 753 754 my $newmode_formatted=sprintf "%5lo",$newmode; 755 756 if((chmod $newmode, $file) != 1){ 757 &B_log("ERROR","Could not change mode of $file to $newmode_formatted\n"); 758 $return = 0; 759 } 760 else{ 761 &B_log("ACTION","Changed mode of $file to $newmode_formatted\n"); 762 &B_revert_log(&getGlobal('BIN',"chmod") . " $oldmode $file\n"); 763 } 764 765 766 } 767 return $return; 768} 769 770############################################################################ 771# &B_install_jail($jailname, $jailconfigfile); 772# This function takes two arguments ( jail_name, jail_config ) 773# It's purpose is to take read in config files that define a 774# chroot jail and then generate it bases on that specification 775############################################################################ 776sub B_install_jail($$) { 777 778 my $jailName = $_[0]; # Name of the jail e.g bind 779 my $jailConfig = $_[1]; # Name of the jails configuration file 780 # create the root directory of the jail if it does not exist 781 &B_create_dir( &getGlobal('BDIR','jail')); 782 &B_chperm(0,0,0555,&getGlobal('BDIR','jail')); 783 784 # create the Jail dir if it does not exist 785 &B_create_dir( &getGlobal('BDIR','jail') . "/" . $jailName); 786 &B_chperm(0,0,0555,&getGlobal('BDIR','jail') . "/". $jailName); 787 788 789 my $jailPath = &getGlobal('BDIR','jail') . "/" . $jailName; 790 my @lines; # used to store no commented no empty config file lines 791 # open configuration file for desired jail and parse in commands 792 if(open(JAILCONFIG,"< $jailConfig")) { 793 while(my $line=<JAILCONFIG>){ 794 if($line !~ /^\s*\#|^\s*$/){ 795 chomp $line; 796 push(@lines,$line); 797 } 798 } 799 close JAILCONFIG; 800 } 801 else{ 802 &B_log("ERROR","Open Failed on filename: $jailConfig\n"); 803 return 0; 804 } 805 # read through commands and execute 806 foreach my $line (@lines){ 807 &B_log("ACTION","Install jail: $line\n"); 808 my @confCmd = split /\s+/,$line; 809 if($confCmd[0] =~ /dir/){ # if the command say to add a directory 810 if($#confCmd == 4) { # checking dir Cmd form 811 if(! (-d $jailPath . "/" . $confCmd[1])){ 812 #add a directory and change its permissions according 813 #to the conf file 814 &B_create_dir( $jailPath . "/" . $confCmd[1]); 815 &B_chperm((getpwnam($confCmd[3]))[2], 816 (getgrnam($confCmd[4]))[2], 817 oct($confCmd[2]), 818 $jailPath . "/" . $confCmd[1]); 819 } 820 } 821 else { 822 &B_log("ERROR","Badly Formed Configuration Line:\n$line\n\n"); 823 } 824 } 825 elsif($confCmd[0] =~ /file/) { 826 if($#confCmd == 5) { # checking file cmd form 827 if(&B_cp($confCmd[1],$jailPath . "/" . $confCmd[2])){ 828 # for copy command cp file and change perms 829 &B_chperm($confCmd[4],$confCmd[5],oct($confCmd[3]),$jailPath . "/" . $confCmd[2]); 830 } 831 else { 832 &B_log("ERROR","Could not complete copy on specified files:\n" . 833 "$line\n"); 834 } 835 } 836 else { 837 &B_log("ERROR","Badly Formed Configuration Line:\n" . 838 "$line\n\n"); 839 } 840 } 841 elsif($confCmd[0] =~ /slink/) { 842 if($#confCmd == 2) { # checking file cmd form 843 if(!(-e $jailPath . "/" . $confCmd[2])){ 844 #for symlink command create the symlink 845 &B_symlink($jailPath . "/" . $confCmd[1], $confCmd[2]); 846 } 847 } 848 else { 849 &B_log("ERROR","Badly Formed Configuration Line:\n" . 850 "$line\n\n"); 851 } 852 } 853 else { 854 &B_log("ERROR","Unrecognized Configuration Line:\n" . 855 "$line\n\n"); 856 } 857 } 858 return 1; 859} 860 861 862 863########################################################################### 864# &B_list_processes($service) # 865# # 866# This subroutine uses the GLOBAL_PROCESS hash to determine if a # 867# service's corresponding processes are running on the system. # 868# If any of the processes are found to be running then the process # 869# name(s) is/are returned by this subroutine in the form of an list # 870# If none of the processes that correspond to the service are running # 871# then an empty list is returned. # 872########################################################################### 873sub B_list_processes($) { 874 875 # service name 876 my $service = $_[0]; 877 # list of processes related to the service 878 my @processes=@{ &getGlobal('PROCESS',$service)}; 879 880 # current systems process information 881 my $ps = &getGlobal('BIN',"ps"); 882 my $psTable = `$ps -elf`; 883 884 # the list to be returned from the function 885 my @running_processes; 886 887 # for every process associated with the service 888 foreach my $process (@processes) { 889 # if the process is in the process table then 890 if($psTable =~ m/$process/) { 891 # add the process to the list, which will be returned 892 push @running_processes, $process; 893 } 894 895 } 896 897 # return the list of running processes 898 return @running_processes; 899 900} 901 902############################################################################# 903# &B_list_full_processes($service) # 904# # 905# This subroutine simply grep through the process table for those matching # 906# the input argument TODO: Allow B_list process to levereage this code # 907# ... Not done this cycle to avoid release risk (late in cycle) # 908############################################################################# 909sub B_list_full_processes($) { 910 911 # service name 912 my $procName = $_[0]; 913 my $ps = &getGlobal('BIN',"ps"); 914 my @psTable = split(/\n/,`$ps -elf`); 915 916 # for every process associated with the service 917 my @runningProcessLines = grep(/$procName/ , @psTable); 918 # return the list of running processes 919 return @runningProcessLines; 920} 921 922################################################################################ 923# &B_deactivate_inetd_service($service); # 924# # 925# This subroutine will disable all inetd services associated with the input # 926# service name. Service name must be a reference to the following hashes # 927# GLOBAL_SERVICE GLOBAL_SERVTYPE and GLOBAL_PROCESSES. If processes are left # 928# running it will note these services in the TODO list as well as instruct the# 929# user in how they remaining processes can be disabled. # 930################################################################################ 931sub B_deactivate_inetd_service($) { 932 my $service = $_[0]; 933 my $servtype = &getGlobal('SERVTYPE',"$service"); 934 my $inetd_conf = &getGlobal('FILE',"inetd.conf"); 935 936 # check the service type to ensure that it can be configured by this subroutine. 937 if($servtype ne 'inet') { 938 &B_log("ACTION","The service \"$service\" is not an inet service so it cannot be\n" . 939 "configured by this subroutine\n"); 940 return 0; 941 } 942 943 # check for the inetd configuration files existence so it may be configured by 944 # this subroutine. 945 if(! -e $inetd_conf ) { 946 &B_log("ACTION","The file \"$inetd_conf\" cannot be located.\n" . 947 "Unable to configure inetd\n"); 948 return 0; 949 } 950 951 # list of service identifiers present in inetd.conf file. 952 my @inetd_entries = @{ &getGlobal('SERVICE',"$service") }; 953 954 foreach my $inetd_entry (@inetd_entries) { 955 &B_hash_comment_line($inetd_conf, "^\\s*$inetd_entry"); 956 } 957 958 # list of processes associated with this service which are still running 959 # on the system 960 my @running_processes = &B_list_processes($service); 961 962 if($#running_processes >= 0) { 963 my $todoString = "\n" . 964 "---------------------------------------\n" . 965 "Deactivating Inetd Service: $service\n" . 966 "---------------------------------------\n" . 967 "The following process(es) are associated with the inetd service \"$service\".\n" . 968 "They are most likely associated with a session which was initiated prior to\n" . 969 "running Bastille. To disable a process see \"kill(1)\" man pages or reboot\n" . 970 "the system\n" . 971 "Active Processes:\n" . 972 "###################################\n"; 973 foreach my $running_process (@running_processes) { 974 $todoString .= "\t$running_process\n"; 975 } 976 $todoString .= "###################################\n"; 977 978 &B_TODO($todoString); 979 } 980 981} 982 983 984################################################################################ 985# B_get_rc($key); # 986# # 987# This subroutine will use the ch_rc binary to get rc.config.d variables # 988# values properly escaped and quoted. # 989################################################################################ 990sub B_get_rc($) { 991 992 my $key=$_[0]; 993 my $ch_rc = &getGlobal('BIN',"ch_rc"); 994 995 # get the current value of the given parameter. 996 my $currentValue=`$ch_rc -l -p $key`; 997 chomp $currentValue; 998 999 if(($? >> 8) == 0 ) { 1000 # escape all meta characters. 1001 # $currentValue =~ s/([\"\`\$\\])/\\$1/g; 1002 # $currentValue = '"' . $currentValue . '"'; 1003 } 1004 else { 1005 return undef; 1006 } 1007 1008 return $currentValue; 1009} 1010 1011 1012 1013################################################################################ 1014# B_set_rc($key,$value); # 1015# # 1016# This subroutine will use the ch_rc binary to set rc.config.d variables. As # 1017# well as setting the variable this subroutine will set revert strings. # 1018# # 1019################################################################################ 1020sub B_set_rc($$;$) { 1021 1022 my ($key,$value,$configfile)=@_; 1023 my $ch_rc = &getGlobal('BIN',"ch_rc"); 1024 1025 # get the current value of the given parameter. 1026 my $currentValue=&B_get_rc($key); 1027 if(defined $currentValue ) { 1028 if ($currentValue =~ /^\"(.*)\"$/ ) { 1029 $currentValue = '"\"' . $1 . '\""'; 1030 } 1031 if ($value =~ /^\"(.*)\"$/ ) { 1032 $value = '"\"' . $1 . '\""'; 1033 } 1034 if ( &B_System("$ch_rc -a -p $key=$value $configfile", 1035 "$ch_rc -a -p $key=$currentValue $configfile") ) { 1036 #ch_rc success 1037 return 1; 1038 } 1039 else { 1040 #ch_rc failure. 1041 return 0; 1042 } 1043 } 1044 else { 1045 &B_log("ERROR","ch_rc was unable to lookup $key\n"); 1046 return 0; 1047 } 1048 1049} 1050 1051 1052################################################################################ 1053# &ChrootHPApache($chrootScript,$httpd_conf,$httpd_bin, 1054# $apachectl,$apacheJailDir,$serverString); 1055# 1056# This subroutine given an chroot script, supplied by the vendor, a 1057# httpd.conf file, the binary location of httpd, the control script, 1058# the jail directory, and the servers identification string, descriptive 1059# string for TODO etc. It makes modifications to httpd.conf so that when 1060# Apache starts it will chroot itself into the jail that the above 1061# mentions script creates. 1062# 1063# uses B_replace_line B_create_dir B_System B_TODO 1064# 1065############################################################################### 1066sub B_chrootHPapache($$$$$$) { 1067 1068 my ($chrootScript,$httpd_conf,$httpd_bin,$apachectl,$apacheJailDir,$serverString)= @_; 1069 1070 my $exportpath = "export PATH=/usr/bin;"; 1071 my $ps = &getGlobal('BIN',"ps"); 1072 my $isRunning = 0; 1073 my $todo_header = 0; 1074 1075 # checking for a 2.0 version of the apache chroot script. 1076 if(-e $chrootScript ) { 1077 1078 if(open HTTPD, $httpd_conf) { 1079 while (my $line = <HTTPD>){ 1080 if($line =~ /^\s*Chroot/) { 1081 &B_log("DEBUG","Apache is already running in a chroot as specified by the following line:\n$line\n" . 1082 "which appears in the httpd.conf file. No Apache Chroot action was taken.\n"); 1083 return; 1084 } 1085 } 1086 close(HTTPD); 1087 } 1088 1089 if(`$ps -ef` =~ $httpd_bin ) { 1090 $isRunning=1; 1091 &B_System("$exportpath " . $apachectl . " stop","$exportpath " . $apachectl . " start"); 1092 } 1093 &B_replace_line($httpd_conf, '^\s*#\s*Chroot' , 1094 "Chroot " . $apacheJailDir); 1095 if(-d &getGlobal('BDIR',"jail")){ 1096 &B_log("DEBUG","Jail directory already exists. No action taken.\n"); 1097 } 1098 else{ 1099 &B_log("ACTION","Jail directory was created.\n"); 1100 &B_create_dir( &getGlobal('BDIR','jail')); 1101 } 1102 1103 if(-d $apacheJailDir){ 1104 &B_log("DEBUG","$serverString jail already exists. No action taken.\n"); 1105 } 1106 else{ 1107 &B_System(&getGlobal('BIN',"umask") . " 022; $exportpath " . $chrootScript, 1108 &getGlobal('BIN',"echo") . " \"Your $serverString is now running outside of it's\\n" . 1109 "chroot jail. You must manually migrate your web applications\\n" . 1110 "back to your Apache server's httpd.conf defined location(s).\\n". 1111 "After you have completed this, feel free to remove the jail directories\\n" . 1112 "from your machine. Your apache jail directory is located in\\n" . 1113 &getGlobal('BDIR',"jail") . "\\n\" >> " . &getGlobal('BFILE',"TOREVERT")); 1114 1115 } 1116 if($isRunning){ 1117 &B_System("$exportpath " . $apachectl . " start","$exportpath " . $apachectl . " stop"); 1118 &B_log("ACTION","$serverString is now running in an chroot jail.\n"); 1119 } 1120 1121 &B_log("ACTION","The jail is located in " . $apacheJailDir . "\n"); 1122 1123 if ($todo_header !=1){ 1124 &B_TODO("\n---------------------------------\nApache Chroot:\n" . 1125 "---------------------------------\n"); 1126 } 1127 &B_TODO("$serverString Chroot Jail:\n" . 1128 "httpd.conf contains the Apache dependencies. You should\n" . 1129 "review this file to ensure that the dependencies made it\n" . 1130 "into the jail. Otherwise, you run a risk of your Apache server\n" . 1131 "not having access to all its modules and functionality.\n"); 1132 1133 1134 } 1135 1136} 1137 1138 1139sub isSystemTrusted { 1140 my $getprdef = &getGlobal('BIN',"getprdef"); 1141 my $definition = &B_Backtick("$getprdef -t 2>&1"); 1142 if($definition =~ "System is not trusted.") { 1143 return 0; 1144 } else { 1145 return 1; 1146 } 1147} 1148 1149 1150sub isTrustedMigrationAvailable { 1151 my $distroVersion=''; 1152 1153 if (&GetDistro =~ '^HP-UX11.(\d*)') { 1154 $distroVersion=$1; 1155 if ($distroVersion < 23) { # Not available before 11.23 1156 return 0; #FALSE 1157 } elsif ($distroVersion >= 31) { #Bundled with 11.31 and after 1158 &B_log('DEBUG','isTrustedMigrationAvailable: HP-UX 11.31 always has trusted mode extensions'); 1159 return 1; 1160 } elsif ($distroVersion == 23) { # Optional on 11.23 if filesets installed 1161 if ( -x &getGlobal('BIN',"userdbget") ) { 1162 &B_log('DEBUG','isTrustedMigrationAvailable: Trusted Extensions Installed'); 1163 return 1; 1164 } else { 1165 &B_log('DEBUG','isTrustedMigrationAvailable: Trusted Extensions Not Installed'); 1166 return 0; #FALSE 1167 } 1168 } else { 1169 &B_log('DEBUG','isTrustedMigrationAvailable: ' . &GetDistro . 1170 ' not currently supported for trusted extentions.'); 1171 return 0; #FALSE 1172 } 1173 } else { 1174 &B_log('WARNING','isTrustedMigrationAvailable: HP-UX routine called on Linux system'); 1175 return 0; #FALSE 1176 } 1177} 1178 1179 1180 1181########################################################################### 1182# &checkServiceOnHPUX($service); 1183# 1184# Checks if the given service is running on an HP/UX system. This is 1185# called by B_is_Service_Off(), which is the function that Bastille 1186# modules should call. 1187# 1188# Return values: 1189# NOTSECURE_CAN_CHANGE() if the service is on 1190# SECURE_CANT_CHANGE() if the service is off 1191# INCONSISTENT() if the state of the service cannot be determined 1192# NOT_INSTALLED() if the s/w isn't insalled 1193# 1194########################################################################### 1195sub checkServiceOnHPUX($) { 1196 my $service=$_[0]; 1197 1198 # get the list of parameters which could be used to initiate the service 1199 # (could be in /etc/rc.config.d, /etc/inetd.conf, or /etc/inittab, so we 1200 # check all of them) 1201 my @params= @{ &getGlobal('SERVICE',$service) }; 1202 my $grep =&getGlobal('BIN', 'grep'); 1203 my $inetd=&getGlobal('FILE', 'inetd.conf'); 1204 my $inittab=&getGlobal('FILE', 'inittab'); 1205 my $retVals; 1206 my $startup=&getGlobal('DIR','initd') ; 1207 my @inet_bins= @{ &getGlobal('PROCESS',$service) }; 1208 1209 my $entry_found = 0; 1210 1211 &B_log("DEBUG","CheckHPUXservice: $service"); 1212 my $full_initd_path = $startup . "/" . $service; 1213 if ($GLOBAL_SERVTYPE{$service} eq "rc") { # look for the init script in /sbin/init.d 1214 if (not(-e $full_initd_path )) { 1215 return NOT_INSTALLED(); 1216 } 1217 } else { #inet-based service, so look for inetd.conf entries. 1218 &B_log("DEBUG","Checking inet service $service"); 1219 my @inet_entries= @{ &getGlobal('SERVICE',$service) }; 1220 foreach my $service (@inet_entries) { 1221 &B_log('DEBUG',"Checking for inetd.conf entry of $service in checkService on HPUX"); 1222 my $service_regex = '^[#\s]*' . $service . '\s+'; 1223 if ( &B_match_line($inetd, $service_regex) ) { # inet entry search 1224 &B_log('DEBUG',"$service present, entry exists"); 1225 $entry_found = 1 ; 1226 } 1227 } 1228 if ($entry_found == 0 ) { 1229 return NOT_INSTALLED(); 1230 } 1231 } 1232 1233 foreach my $param (@params) { 1234 &B_log("DEBUG","Checking to see if service $service is off.\n"); 1235 if (&getGlobal('SERVTYPE', $service) =~ /rc/) { 1236 my $ch_rc=&getGlobal('BIN', 'ch_rc'); 1237 my $on=&B_Backtick("$ch_rc -l -p $param"); 1238 1239 $on =~ s/\s*\#.*$//; # remove end-of-line comments 1240 $on =~ s/^\s*\"(.+)\"\s*$/$1/; # remove surrounding double quotes 1241 $on =~ s/^\s*\'(.+)\'\s*$/$1/; # remove surrounding single quotes 1242 $on =~ s/^\s*\"(.+)\"\s*$/$1/; # just in case someone did '"blah blah"' 1243 1244 chomp $on; 1245 &B_log("DEBUG","ch_rc returned: $param=$on in checkServiceOnHPUX"); 1246 1247 if ($on =~ /^\d+$/ && $on != 0) { 1248 # service is on 1249 &B_log("DEBUG","CheckService found $param service is set to \'on\' in scripts."); 1250 return NOTSECURE_CAN_CHANGE(); 1251 } 1252 elsif($on =~ /^\s*$/) { 1253 # if the value returned is an empty string return 1254 # INCONSISTENT(), since we don't know what the hard-coded default is. 1255 return INCONSISTENT(); 1256 } 1257 } else { 1258 # those files which rely on comments to determine what gets 1259 # turned on, such as inetd.conf and inittab 1260 my $inettabs=&B_Backtick("$grep -e '^[[:space:]]*$param' $inetd $inittab"); 1261 if ($inettabs =~ /.+/) { # . matches anything except newlines 1262 # service is not off 1263 &B_log("DEBUG","Checking inetd.conf and inittab; found $inettabs"); 1264 ########################### BREAK out, don't skip question 1265 return NOTSECURE_CAN_CHANGE(); 1266 } 1267 } 1268 } # foreach $param 1269 1270 # boot-time parameters are not set; check processes 1271 # checkprocs for services returns INCONSISTENT() if a service is found 1272 # since a found-service is inconsistent with the above checks. 1273 B_log("DEBUG","Boot-Parameters not set, checking processes."); 1274 if (&runlevel < 2) { # Below runlevel 2, it is unlikely that 1275 #services will be running, so just check "on-disk" state 1276 &B_log("NOTE","Running during boot sequence, so skipping process checks"); 1277 return SECURE_CANT_CHANGE(); 1278 } else { 1279 return &checkProcsForService($service); 1280 } 1281} 1282 1283sub runlevel { 1284 my $who = &getGlobal("BIN", "who"); 1285 my $runlevel = &B_Backtick("$who -r"); 1286 if ($runlevel =~ s/.* run-level (\S).*/$1/) { 1287 &B_log("DEBUG","Runlevel is: $runlevel"); 1288 return $runlevel; 1289 } else { 1290 &B_log("WARNING","Can not determine runlevel, assuming runlevel 3"); 1291 &B_log("DEBUG","Runlevel command output: $runlevel"); 1292 return "3"; #safer since the who command didn't work, we'll assume 1293 # runlevel 3 since that provides more checks. 1294 } 1295} 1296 1297# 1298# given a profile file, it will return a PATH array set by the file. 1299# 1300sub B_get_path($) { 1301 my $file = $_[0]; 1302 my $sh = &getGlobal("BIN", "sh"); 1303 # use (``)[0] is becuase, signal 0 maybe trapped which will produce some stdout 1304 my $path = (`$sh -c '. $file 1>/dev/null 2>&1 < /dev/null ; echo \$PATH'`)[0]; 1305 my @path_arr = split(":", $path); 1306 my %tmp_path; 1307 my %path; 1308 for my $tmpdir (@path_arr) { 1309 chomp $tmpdir; 1310 if ($tmpdir ne "" && ! $tmp_path{$tmpdir}) { 1311 $tmp_path{$tmpdir}++; 1312 } 1313 } 1314 return keys %tmp_path; 1315} 1316 1317# Convert to trusted mode if it's not already 1318sub convertToTrusted { 1319 &B_log("DEBUG","# sub convertToTrusted \n"); 1320 if( ! &isSystemTrusted) { 1321 1322 my ($ok, $message) = &isOKtoConvert; 1323 1324 my $ts_header="\n---------------------------------\nTrusted Systems:\n" . 1325 "---------------------------------\n"; 1326 1327 if ($ok) { 1328 # actually do the conversion 1329 if(&B_System(&getGlobal('BIN','tsconvert'), &getGlobal('BIN','tsconvert') . " -r")){ 1330 # adjust change times for user passwords to keep them valid 1331 # default is to expire them when converting to a trusted system, 1332 # which can be problematic, especially since some older versions of 1333 # SecureShell do not allow the user to change the password 1334 &B_System(&getGlobal('BIN','modprpw') . " -V", ""); 1335 1336 my $getprdef = &getGlobal('BIN','getprdef'); 1337 my $oldsettings = &B_Backtick("$getprdef -m lftm,exptm,mintm,expwarn,umaxlntr"); 1338 $oldsettings =~ s/ //g; 1339 1340 # remove password lifetime and increasing login tries so they 1341 # don't lock themselves out of the system entirely. 1342 # set default expiration time and the like. 1343 my $newsettings="lftm=0,exptm=0,mintm=0,expwarn=0,umaxlntr=10"; 1344 1345 &B_System(&getGlobal('BIN','modprdef') . " -m $newsettings", 1346 &getGlobal('BIN','modprdef') . " -m $oldsettings"); 1347 1348 &B_TODO($ts_header . 1349 "Your system has been converted to a trusted system.\n" . 1350 "You should review the security settings available on a trusted system.\n". 1351 "$message"); 1352 1353 # to get rid of "Cron: Your job did not contain a valid audit ID." 1354 # error, we re-read the crontab file after converting to trusted mode 1355 # Nothing is necessary in "revert" since we won't be in trusted mode 1356 # at that time. 1357 # crontab's errors can be spurious, and this will report an 'error' 1358 # of the crontab file is missing, so we send stderr to the bit bucket 1359 my $crontab = &getGlobal('BIN',"crontab"); 1360 &B_System("$crontab -l 2>/dev/null | $crontab",""); 1361 } 1362 1363 } else { 1364 &B_TODO($ts_header . $message); 1365 return 0; # not ok to convert, so we didn't 1366 } 1367 } 1368 else { 1369 &B_log("DEBUG","System is already in trusted mode, no action taken.\n"); 1370 return 1; 1371 } 1372 1373 # just to make sure 1374 if( &isSystemTrusted ) { 1375 return 1; 1376 } else { 1377 &B_log("ERROR","Trusted system conversion was unsuccessful for an unknown reason.\n" . 1378 " You may try using SAM/SMH to do the conversion instead of Bastille.\n"); 1379 return 0; 1380 } 1381} 1382 1383# isOKtoConvert - check for conflicts between current system state and trusted 1384# mode 1385# 1386# Return values 1387# 0 - conflict found, see message for details 1388# 1 - no conflicts, see message for further instructions 1389# 1390sub isOKtoConvert { 1391 &B_log("DEBUG","# sub isOKtoConvert \n"); 1392 # initialize text for TODO instructions 1393 my $specialinstructions=" - convert to trusted mode\n"; 1394 1395 # These are somewhat out-of-place, but only affect the text of the message. 1396 # Each of these messages is repeated in a separate TODO item in the 1397 # appropriate subroutine. 1398 if (&getGlobalConfig("AccountSecurity","single_user_password") eq "Y") { 1399 if (&GetDistro =~ "^HP-UX11.(.*)" and $1<23 ) { 1400 $specialinstructions .= " - set a single user password\n"; 1401 } 1402 } 1403 1404 if (&getGlobalConfig("AccountSecurity","passwordpolicies") eq "Y") { 1405 $specialinstructions .= " - set trusted mode password policies\n"; 1406 } 1407 1408 if (&getGlobalConfig("AccountSecurity", "PASSWORD_HISTORY_DEPTHyn") eq "Y") { 1409 $specialinstructions .= " - set a password history depth\n"; 1410 } 1411 1412 if (&getGlobalConfig("AccountSecurity","system_auditing") eq "Y") { 1413 $specialinstructions .= " - enable auditing\n"; 1414 } 1415 1416 my $saminstructions= 1417 "The security settings can be modified by running SAM as follows:\n" . 1418 "# sam\n" . 1419 "Next, go to the \"Auditing and Security Area\" and review\n" . 1420 "each sub-section. Make sure that you review all of your\n" . 1421 "settings, as some policies may seem restrictive.\n\n" . 1422 "On systems using the System Management Homepage, you can\n". 1423 "change your settings via the Tools:Security Attributes Configuration\n". 1424 "section. On some systems, you may also have the option of using SMH.\n\n"; 1425 1426 # First, check for possible conflicts and corner cases 1427 1428 # check nsswitch for possible conflicts 1429 my $nsswitch = &getGlobal('FILE', 'nsswitch.conf'); 1430 if ( -e $nsswitch) { 1431 open(FILE, $nsswitch); 1432 while (<FILE>) { 1433 if (/nis/ or /compat/ or /ldap/) { 1434 my $message = "Bastille found a possible conflict between trusted mode and\n" . 1435 "$nsswitch. Please remove all references to\n" . 1436 "\"compat\", \"nis\" and \"ldap\" in $nsswitch\n" . 1437 "and rerun Bastille, or use SAM/SMH to\n" . 1438 "$specialinstructions\n". 1439 "$saminstructions"; 1440 close(FILE); 1441 return (0,$message); 1442 } 1443 } 1444 close(FILE); 1445 } 1446 1447 # check the namesvrs config file for possible NIS conflicts 1448 #Changed to unless "Y AND Y" since question can be skipped when nis is off 1449 # but corner cases can still exist, so check then too. 1450 unless ( &getGlobalConfig('MiscellaneousDaemons','nis_client') eq "Y" and 1451 &getGlobalConfig('MiscellaneousDaemons','nis_server') eq "Y" ) { 1452 my $namesvrs = &getGlobal('FILE', 'namesvrs'); 1453 if (open(FILE, $namesvrs)) { 1454 while (<FILE>) { 1455 if (/^NIS.*=["]?1["]?$/) { 1456 my $message= "Possible conflict between trusted mode and NIS found.\n". 1457 "Please use SAM/SMH to\n" . 1458 " - turn off NIS\n" . 1459 "$specialinstructions\n". 1460 "$saminstructions"; 1461 close(FILE); 1462 return (0,$message); 1463 } 1464 } 1465 close(FILE); 1466 } else { 1467 &B_log("ERROR","Unable to open $namesvrs for reading."); 1468 my $message= "Possible conflict between trusted mode and NIS found.\n". 1469 "Please use SAM/SMH to\n" . 1470 " - turn off NIS\n" . 1471 "$specialinstructions\n". 1472 "$saminstructions"; 1473 return (0,$message); 1474 } 1475 if ( &B_match_line (&getGlobal("FILE","passwd"),"^\+:.*")) { 1476 my $message= '"+" entry found in passwd file. These are not\n' . 1477 "compatible with Trusted Mode. Either remove the entries\n" . 1478 "and re-run Bastille, or re-run Bastille, and direct it to\n" . 1479 "disable NIS client and server.\n"; 1480 return (0,$message); 1481 } 1482 1483 } 1484 1485 1486 # check for conflicts with DCE integrated login 1487 my $authcmd = &getGlobal('BIN','auth.adm'); 1488 if ( -e $authcmd ) { 1489 my $retval = system("PATH=/usr/bin $authcmd -q 1>/dev/null 2>&1"); 1490 if ($retval != 0 and $retval != 1) { 1491 my $message="It appears that DCE integrated login is configured on this system.\n" . 1492 "DCE integrated login is incompatible with trusted systems and\n" . 1493 "auditing. Bastille is unable to\n" . 1494 "$specialinstructions" . 1495 "You will need to configure auditing and password policies using DCE.\n\n"; 1496 return (0,$message); 1497 } 1498 } 1499 1500 if ( -e &getGlobal('FILE','shadow') ) { 1501 my $message="This system has already been converted to shadow passwords.\n" . 1502 "Shadow passwords are incompatible with trusted mode.\n" . 1503 "Bastille is unable to\n" . 1504 "$specialinstructions" . 1505 "If you desire these features, you should use\n". 1506 "\'pwunconv\' to change back to standard passwords,\n". 1507 "and then rerun Bastille.\n\n"; 1508 return (0,$message); 1509 } 1510 1511 return (1,$saminstructions); 1512} 1513 1514# This routine allows Bastille to determine trusted-mode extension availability 1515 1516sub convertToShadow { 1517 1518 if (&isSystemTrusted) { 1519 # This is an internal error...Bastille should not call this routine 1520 # in this case. Error is here for robustness against future changes. 1521 &B_log("ERROR","This system is already converted to trusted mode.\n" . 1522 " Converting to shadow passwords will not be attempted.\n"); 1523 return 0; 1524 } 1525 1526 # configuration files on which shadowed passwords depend 1527 my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf"); 1528 1529 # binaries used to convert to a shadowed password 1530 my $pwconv = &getGlobal('BIN',"pwconv"); 1531 my $echo = &getGlobal('BIN','echo'); # the echo is used to pipe a yes into the pwconv program as 1532 # pwconv requires user interaction. 1533 1534 # the binary used in a system revert. 1535 my $pwunconv = &getGlobal('BIN',"pwunconv"); 1536 #check the password file for nis usage and if the nis client 1537 #or server is running. 1538 if(-e $nsswitch_conf) { 1539 # check the file for nis, nis+, compat, or dce usage. 1540 if(&B_match_line($nsswitch_conf, '^\s*passwd:.+(nis|nisplus|dce|compat)')) { 1541 my $shadowTODO = "\n---------------------------------\nHide encrypted passwords:\n" . 1542 "---------------------------------\n" . 1543 "This version of password shadowing does not support any repository other\n" . 1544 "than files. In order to convert your password database to shadowed passwords\n" . 1545 "there can be no mention of nis, nisplus, compat, or dce in the passwd\n" . 1546 "field of the \"$nsswitch_conf\" file. Please make the necessary edits to\n" . 1547 "the $nsswitch_conf file and run Bastille again using the command:\n" . 1548 "\"bastille -b\"\n"; 1549 # Adding the shadowTODO comment to the TODO list. 1550 &B_TODO("$shadowTODO"); 1551 # Notifing the user that the shadowed password coversion has failed. 1552 &B_log("ERROR","Password Shadowing Conversion Failed\n" . 1553 "$shadowTODO"); 1554 # exiting the subroutine. 1555 return 0; 1556 } 1557 1558 } 1559 1560 # convert the password file to a shadowed repository. 1561 if (( -e $pwconv ) and ( -e $pwunconv ) and 1562 ( &B_System("$echo \"yes\" | $pwconv","$pwunconv") ) ){ 1563 &B_TODO( "\n---------------------------------\nShadowing Password File:\n" . 1564 "---------------------------------\n" . 1565 "Your password file has been converted to use password shadowing.\n" . 1566 "This version of password shadowing does not support any repository other\n" . 1567 "than files. There can be no mention of nis, nisplus, compat, or dce\n" . 1568 "in the passwd field of the \"$nsswitch_conf\" file.\n\n" ); 1569 } else { 1570 &B_log("ERROR","Conversion to shadow mode failed. The system may require ". 1571 "a patch to be capable of switching to shadow mode, or the ". 1572 "system my be in a state where conversion is not possible."); 1573 } 1574} 1575 1576 1577 1578########################################################################## 1579# &getSupportedSettings(); 1580# Manipulates %trustedParameter and %isSupportedSetting, file-scoped variables 1581# 1582# Reads the password policy support matrix, which in-turn gives Bastille the 1583# places it should look for a given password policy setting. 1584 1585# Note the file was created like this so if could be maintained in an Excel(tm) 1586# spreadsheet, to optimize reviewability. TODO: consider other formats 1587 1588# File Format: 1589# HEADERS:<comment>,[<OS Version> <Mode> <Extensions>,]... 1590# [ 1591# :<label>:<trusted equivalent>,,,,,,,,,,,,<comment> 1592# <action> (comment), [<test value>,]... 1593# ] ... 1594# Example; 1595# HEADERS:Information Source (trusted equiv),11.11 Standard no-SMSE,11.11 Trusted no-SMSE,11.11 Shadow no-SMSE,11.23 Standard no-SMSE,11.23 Trusted no-SMSE,11.23 Shadow no-SMSE,11.23 Standard SMSE,11.23 Shadow SMSE,11.23 Trusted SMSE,11.31 Trusted SMSE,11.31 Shadow SMSE,11.31 Standard SMSE,Other Exceptions 1596#:ABORT_LOGIN_ON_MISSING_HOMEDIR,,,,,,,,,,,,,root 1597#/etc/security.dsc (search),x,,xx,x,x,x,!,!,!,!,!,!, 1598#/etc/default/security(search),y,y,y,y,y,y,y,y,y,y,y,y, 1599#getprdef (execute with <Trusted Equiv> argument),x,x,x,x,x,x,x,x,x,x,x,x, 1600 1601########################################################################### 1602our %trustedParameter = (); 1603our %isSupportedSetting = (); 1604 1605sub getSupportedSettings() { 1606 1607 my $line; # For a config file line 1608 my $linecount = 0; 1609 my $currentsetting = ""; 1610 my @fields; # Fields in a given line 1611 my @columns; #Column Definitions 1612 1613 1614 &B_open(*SETTINGSFILE,&getGlobal('BFILE','AccountSecSupport')); 1615 my @settingLines=<SETTINGSFILE>; 1616 &B_close(*SETTINGSFILE); 1617 1618 #Remove blank-lines and comments 1619 @settingLines = grep(!/^#/,@settingLines); 1620 @settingLines = grep(!/^(\s*,+)*$/,@settingLines); 1621 1622 foreach $line (@settingLines) { 1623 ++$linecount; 1624 @fields = split(/,/,$line); 1625 if ($line =~ /^Information Source:/) { #Sets up colums 1626 my $fieldcount = 1; #Skipping first field 1627 while ((defined($fields[$fieldcount])) and 1628 ($fields[$fieldcount] =~ /\d+\.\d+/)){ 1629 my @subfields = split(/ /,$fields[$fieldcount]); 1630 my $fieldsCount = @subfields; 1631 if ($fieldsCount != 3){ 1632 &B_log("ERROR","Invalid subfield count: $fieldsCount in:". 1633 &getGlobal('BFILE','AccountSecSupport') . 1634 " line: $linecount and field: $fieldcount"); 1635 } 1636 $columns[$fieldcount] = {OSVersion => $subfields[0], 1637 Mode => $subfields[1], 1638 Extension => $subfields[2] }; 1639 &B_log("DEBUG","Found Header Column, $columns[$fieldcount]{'OSVersion'}, ". 1640 $columns[$fieldcount]{'Mode'} ." , " . 1641 $columns[$fieldcount]{'Extension'}); 1642 ++$fieldcount; 1643 } # New Account Seting ex: 1644 } elsif ($line =~ /^:([^,:]+)(?::([^,]+))?/) { # :PASSWORD_WARNDAYS:expwarn,,,,,,,,,,,, 1645 $currentsetting = $1; 1646 if (defined($2)) { 1647 $trustedParameter{"$currentsetting"}=$2; 1648 } 1649 &B_log("DEBUG","Found Current Setting: ". $currentsetting . 1650 "/" . $trustedParameter{"$currentsetting"}); 1651 } elsif (($line =~ /(^[^, :\)\(]+)[^,]*,((?:(?:[!y?nx]|!!),)+)/) and #normal line w/ in setting ex: 1652 ($currentsetting ne "")){ # security.dsc (search),x,x,x,x,x,!,!!,!,!,!,!, 1653 my $placeToLook = $1; 1654 my $fieldcount = 1; #Skip the first one, which we used in last line 1655 while (defined($fields[$fieldcount])) { 1656 &B_log("DEBUG","Setting $currentsetting : $columns[$fieldcount]{OSVersion} , ". 1657 "$columns[$fieldcount]{Mode} , ". 1658 "$columns[$fieldcount]{Extension} , ". 1659 "$placeToLook, to $fields[$fieldcount]"); 1660 $isSupportedSetting{"$currentsetting"} 1661 {"$columns[$fieldcount]{OSVersion}"} 1662 {"$columns[$fieldcount]{Mode}"} 1663 {"$columns[$fieldcount]{Extension}"} 1664 {"$placeToLook"} = 1665 $fields[$fieldcount]; 1666 ++$fieldcount; 1667 } 1668 } else { 1669 if ($line !~ /^,*/) { 1670 &B_log("ERROR","Incorrectly Formatted Line at ". 1671 &getGlobal('BFILE','AccountSecSupport') . ": $linecount"); 1672 } 1673 } 1674 } 1675} 1676 1677########################################################################## 1678# &B_get_sec_value($param); 1679# This subroutine finds the value for a given user policy parameter. 1680# Specifically, it supports the parameters listed in the internal data structure 1681 1682# Return values: 1683# 'Not Defined' if the value is not present or not uniquely defined. 1684# $value if the value is present and unique 1685# 1686########################################################################### 1687sub B_get_sec_value($) { 1688 my $param=$_[0]; 1689 1690 my $os_version; 1691 if (&GetDistro =~ /^HP-UX\D*(\d+\.\d+)/ ){ 1692 $os_version=$1; 1693 } else { 1694 &B_log("ERROR","B_get_sec_value only supported on HP-UX"); 1695 return undef; 1696 } 1697# my $sec_dsc = &getGlobal('FILE', 'security.dsc'); 1698 my $sec_file = &getGlobal('FILE', 'security'); 1699 my $getprdef = &getGlobal('BIN','getprdef'); 1700 my $getprpw = &getGlobal('BIN','getprpw'); 1701 my $userdbget = &getGlobal('BIN','userdbget'); 1702 my $passwd = &getGlobal('BIN','passwd'); 1703 1704 my $sec_flags = ""; 1705 my @sec_settings=(); 1706 my $user_sec_setting=""; 1707 1708 my $security_mode="Standard"; 1709 my $security_extension="no-SMSE"; 1710 1711 &B_log("DEBUG","Entering get_sec_value for: $param"); 1712 1713 sub isok ($) { # Locally-scoped subroutine, takes supported-matrix entry as argument 1714 my $supportedMatrixEntry = $_[0]; 1715 1716 if ($supportedMatrixEntry =~ /!/) { #Matrix Entry for "Documented and/or tested" 1717 &B_log("DEBUG","isOk TRUE: $supportedMatrixEntry"); 1718 return 1; 1719 } else { 1720 &B_log("DEBUG","isOk FALSE: $supportedMatrixEntry"); 1721 return 0; #FALSE 1722 } 1723 } #end local subroutine 1724 1725 #Get Top Array item non-destructively 1726 sub getTop (@) { 1727 my @incomingArray = @_; 1728 my $topval = pop(@incomingArray); 1729 push(@incomingArray,$topval); #Probably redundant, but left in just in case. 1730 return $topval; 1731 } 1732 1733 sub ifExistsPushOnSecSettings($$) { 1734 my $sec_settings = $_[0]; 1735 my $pushval = $_[1]; 1736 1737 if ($pushval ne ""){ 1738 push (@$sec_settings, $pushval); 1739 } 1740 } 1741 1742 #prpw and prdef both use "YES" instead of "1" like the other settings. 1743 sub normalizePolicy($){ 1744 my $setting = $_[0]; 1745 1746 $setting =~ s/YES/1/; 1747 $setting =~ s/NO/1/; 1748 1749 return $setting; 1750 } 1751 1752 1753 1754 if ((%trustedParameter == ()) or (%isSupportedSetting == ())) { 1755 # Manipulates %trustedParameter and %isSupportedSetting 1756 &getSupportedSettings; 1757 } 1758 1759 #First determine the security mode 1760 my $shadowFile = &getGlobal("FILE","shadow"); 1761 my $passwdFile = &getGlobal("FILE","passwd"); 1762 1763 if (&isSystemTrusted) { 1764 $security_mode = 'Trusted'; 1765 } elsif ((-e $shadowFile) and #check file exist, and that passwd has no non-"locked" accounts 1766 (not(&B_match_line($passwdFile,'^[^\:]+:[^:]*[^:*x]')))) { 1767 $security_mode = 'Shadow'; 1768 } else { 1769 $security_mode = 'Standard'; 1770 } 1771 if (&isTrustedMigrationAvailable) { 1772 $security_extension = 'SMSE'; 1773 } else { 1774 $security_extension = 'no-SMSE'; 1775 } 1776 &B_log("DEBUG","Security mode: $security_mode extension: $security_extension"); 1777 # Now look up the value from each applicable database, from highest precedence 1778 # to lowest: 1779 &B_log("DEBUG","Checking $param in userdbget"); 1780 if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} 1781 {$security_extension}{"userdbget_-a"})) { 1782 &ifExistsPushOnSecSettings(\@sec_settings, 1783 &B_getValueFromString('\w+\s+\w+=(\S+)', 1784 &B_Backtick("$userdbget -a $param"))); 1785 &B_log("DEBUG", $param . ":userdbget setting: ". &getTop(@sec_settings)); 1786 } 1787 &B_log("DEBUG","Checking $param in passwd"); 1788 if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} 1789 {$security_extension}{"passwd_-sa"})) { 1790 if ($param eq "PASSWORD_MINDAYS") { 1791 &ifExistsPushOnSecSettings(\@sec_settings, 1792 &B_getValueFromString('(?:\w+\s+){2}[\d\/]+\s+(\d+)\s+\d+', 1793 &B_Backtick("$passwd -s -a"))); 1794 } elsif ($param eq "PASSWORD_MAXDAYS") { 1795 &ifExistsPushOnSecSettings(\@sec_settings, 1796 &B_getValueFromString('(?:\w+\s+){2}[\d\/]+\s+\d+\s+(\d+)', 1797 &B_Backtick("$passwd -s -a"))); 1798 } elsif ($param eq "PASSWORD_WARNDAYS") { 1799 &ifExistsPushOnSecSettings(\@sec_settings, 1800 &B_getValueFromString('(?:\w+\s+){2}[\d\/]+(?:\s+\d+){2}\s+(\d+)', 1801 &B_Backtick("$passwd -s -a"))); 1802 } 1803 &B_log("DEBUG", $param . ":passwd -sa setting: ". &getTop(@sec_settings)); 1804 } 1805 &B_log("DEBUG","Checking $param in get prpw"); 1806 if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} 1807 {$security_extension}{"getprpw"})) { 1808 my $logins = &getGlobal("BIN","logins"); 1809 my @userArray = split(/\n/,`$logins`); 1810 my $userParamVals = ''; 1811 foreach my $rawuser (@userArray) { 1812 $rawuser =~ /^(\S+)/; 1813 my $user = $1; 1814 my $nextParamVal=&B_Backtick("$getprpw -l -m $trustedParameter{$param} $user"); 1815 $nextParamVal =~ s/\w*=(-*[\w\d]*)/$1/; 1816 if ($nextParamVal != -1) { #Don't count users for which the local DB is undefined 1817 $userParamVals .= $user . "::::" . $nextParamVal ."\n"; 1818 } 1819 } #Note getValueFromStrings deals with duplicates, returning "Not Unigue" 1820 my $policySetting = &B_getValueFromString('::::(\S+)',"$userParamVals"); 1821 &ifExistsPushOnSecSettings (\@sec_settings, &normalizePolicy($policySetting)); 1822 &B_log("DEBUG", $param . ":prpw setting: ". &getTop(@sec_settings)); 1823 } 1824 &B_log("DEBUG","Checking $param in get prdef"); 1825 if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} 1826 {$security_extension}{"getprdef"})) { 1827 $_ = &B_Backtick ("$getprdef -m " . $trustedParameter{$param}); 1828 /\S+=(\S+)/; 1829 my $policySetting = $1; 1830 &ifExistsPushOnSecSettings(\@sec_settings, &normalizePolicy($policySetting)); 1831 &B_log("DEBUG", $param . ":prdef setting: ". &getTop(@sec_settings)); 1832 1833 } 1834 &B_log("DEBUG","Checking $param in default security"); 1835 if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} 1836 {$security_extension}{"/etc/default/security"})) { 1837 &ifExistsPushOnSecSettings(\@sec_settings,&B_getValueFromFile('^\s*'. $param . 1838 '\s*=\s*([^\s#]+)\s*$', $sec_file)); 1839 &B_log("DEBUG", $param . ":default setting: ". &getTop(@sec_settings)); 1840 } 1841 #Commented below code in 3.0 release to avoid implication that bastille 1842 #had ever set these values explicitly, and the implications to runnable 1843 #config files where Bastille would then apply the defaults as actual policy 1844 #with possible conversion to shadow or similar side-effect. 1845 1846# &B_log("DEBUG","Checking $param in security.dsc"); 1847 #security.dsc, only added in if valid for OS/mode/Extension, and nothing else 1848 #is defined (ie: @sec_settings=0) 1849# if ((&isok($isSupportedSetting{$param}{$os_version}{$security_mode} 1850# {$security_extension}{"/etc/security.dsc"})) and (@sec_settings == 0)) { 1851# &ifExistsPushOnSecSettings(\@sec_settings, &B_getValueFromFile('^' . $param . 1852# ';(?:[-\w/]*;){2}([-\w/]+);', $sec_dsc)); 1853# &B_log("DEBUG", $param . ":security.dsc: ". &getTop(@sec_settings)); 1854# } 1855 1856 # Return what we found 1857 my $last_setting=undef; 1858 my $current_setting=undef; 1859 while (@sec_settings > 0) { 1860 $current_setting = pop(@sec_settings); 1861 &B_log("DEBUG","Comparing $param configuration for identity: " . 1862 $current_setting); 1863 if ((defined($current_setting)) and ($current_setting ne '')) { 1864 if (not(defined($last_setting))){ 1865 $last_setting=$current_setting; 1866 } elsif (($last_setting ne $current_setting) or 1867 ($current_setting eq 'Not Unique')){ 1868 &B_log("DEBUG","$param setting not unique."); 1869 return 'Not Unique'; # Inconsistent state found, return 'Not Unique' 1870 } 1871 } 1872 } 1873 if ((not(defined($last_setting))) or ($last_setting eq '')) { 1874 return undef; 1875 } else { 1876 return $last_setting; 1877 } 1878 1879} #End B_get_sec_value 1880 1881sub secureIfNoNameService($){ 1882 my $retval = $_[0]; 1883 1884 if (&isUsingRemoteNameService) { 1885 return MANUAL(); 1886 } else { 1887 return $retval; 1888 } 1889} 1890 1891#Specifically for cleartext protocols like NIS, which are not "secure" 1892sub isUsingRemoteNameService(){ 1893 1894 if (&remoteServiceCheck('nis|nisplus|dce') == SECURE_CAN_CHANGE()){ 1895 return 0; #false 1896 } else { 1897 return 1; 1898 } 1899} 1900 1901 1902 1903########################################### 1904## This is a wrapper for two functions that 1905## test the existence of nis-like configurations 1906## It is used by both the front end test and the back-end run 1907############################################## 1908sub remoteServiceCheck($){ 1909 my $regex = $_[0]; 1910 1911 my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf"); 1912 my $passwd = &getGlobal('FILE',"passwd"); 1913 1914 # check the file for nis usage. 1915 if (-e $nsswitch_conf) { 1916 if (&B_match_line($nsswitch_conf, '^\s*passwd:.*('. $regex . ')')) { 1917 return NOTSECURE_CAN_CHANGE(); 1918 } elsif ((&B_match_line($nsswitch_conf, '^\s*passwd:.*(compat)')) and 1919 (&B_match_line($passwd, '^\s*\+'))) { 1920 return NOTSECURE_CAN_CHANGE(); # true 1921 } 1922 } elsif ((&B_match_line($passwd, '^\s*\+'))) { 1923 return NOTSECURE_CAN_CHANGE(); 1924 } 1925 1926 my $oldnisdomain=&B_get_rc("NIS_DOMAIN"); 1927 if ((($oldnisdomain eq "") or ($oldnisdomain eq '""')) and (&checkServiceOnHPUX('nis.client'))){ 1928 return SECURE_CAN_CHANGE(); 1929 } 1930 return NOTSECURE_CAN_CHANGE(); 1931} 1932 1933############################################# 1934# remoteNISPlusServiceCheck 1935# test the existence of nis+ configuration 1936############################################# 1937sub remoteNISPlusServiceCheck () { 1938 1939 my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf"); 1940 1941 # check the file for nis+ usage. 1942 if (-e $nsswitch_conf) { 1943 if (&B_match_line($nsswitch_conf, 'nisplus')) { 1944 return NOTSECURE_CAN_CHANGE(); 1945 } 1946 } 1947 1948 return &checkServiceOnHPUX('nisp.client'); 1949} 1950 1951 1952########################################################################## 1953# This subroutine creates nsswitch.conf file if the file not exists, 1954# and then append serveral services into the file if the service not 1955# exists in the file. 1956########################################################################## 1957sub B_create_nsswitch_file ($) { 1958 my $regex = $_[0]; 1959 1960 my $nsswitch = &getGlobal('FILE',"nsswitch.conf"); 1961 1962 if( ! -f $nsswitch ) { 1963 &B_create_file($nsswitch); 1964 # we don't need to revert the permissions change because we just 1965 # created the file 1966 chmod(0444, $nsswitch); 1967 1968 &B_append_line($nsswitch,'\s*passwd:', "passwd: $regex\n"); 1969 &B_append_line($nsswitch,'\s*group:', "group: $regex\n"); 1970 &B_append_line($nsswitch,'\s*hosts:', "hosts: $regex\n"); 1971 &B_append_line($nsswitch,'\s*networks:', "networks: $regex\n"); 1972 &B_append_line($nsswitch,'\s*protocols:', "protocols: $regex\n"); 1973 &B_append_line($nsswitch,'\s*rpc:', "rpc: $regex\n"); 1974 &B_append_line($nsswitch,'\s*publickey:', "publickey: $regex\n"); 1975 &B_append_line($nsswitch,'\s*netgroup:', "netgroup: $regex\n"); 1976 &B_append_line($nsswitch,'\s*automount:', "automount: $regex\n"); 1977 &B_append_line($nsswitch,'\s*aliases:', "aliases: $regex\n"); 1978 &B_append_line($nsswitch,'\s*services:', "services: $regex\n"); 1979 } 1980} 1981 19821; 1983 1984