blob: 7e7d709fbca3f520515ef40e009f5e54df6b0231 [file] [log] [blame]
Richard Marian Thomaiyar14fddef2018-07-13 23:55:56 +05301package 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