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