# Copyright (C) 1999, 2000 Jay Beale
# Copyright (C) 2001-2003 Hewlett Packard
# Licensed under the GNU General Public License

package Bastille::AccountSecurity;
use lib "/usr/lib";


use Bastille::API;

use Bastille::TestAPI;

#######################################################################
##                     Account Creation/Security                     ##
#######################################################################

&ProtectRhosts;
&PasswordAging;
&PasswordStrength_Linux;
&RestrictCron;
&SetUmask;
&RootTTYLogins;
&Securetty;

# HPDefaultSecurity sets values in /etc/default/security.  Similar 
# settings are set by setPWpolicies for existing users and/or trusted
&HPDefaultSecurity;
&HPSingleUserPassword;
&HPEnableAudit;

# Do this one last to decrease the chances of hitting a needed trusted
# mode conversion after converting to shadow passwords
# Passwords will be hidden if hidepasswords or you want password policies
&HPHidePasswords;

&setPWpolicies;

&RemoveUnnecessaryAccounts;
&RemoveUnnecessaryGroups;


sub ProtectRhosts {

    if ( &getGlobalConfig("AccountSecurity","protectrhost") eq "Y" ) {

	&B_log("ACTION","# sub ProtectRhosts\n");

	unless (&GetDistro =~ /^OSX/) {
	    # Disallow rlogin,rsh,rexec via Pluggable Authentication Modules
	    foreach $service ( "rexec","rlogin","rsh" ) {
		if ( -e &getGlobal('DIR', "pamd") . "/$service" ) {
		    &B_prepend_line(&getGlobal('DIR', "pamd") . "/$service","pam_deny","auth      required   pam_deny.so\n");
		}
	    }
	}

	# Deactivate the daemons by removing execute status
	&B_chmod_if_exists(0000,&getGlobal('BIN',"rlogind"));
	&B_chmod_if_exists(0000,&getGlobal('BIN',"rshd"));
	&B_chmod_if_exists(0000,&getGlobal('BIN',"rexecd"));

	# Deactivate the user binaries by removing execute status and confirming that files are owned by root:root
	&B_chmod_if_exists(0000,&getGlobal('BIN',"rlogin"));
	&B_chmod_if_exists(0000,&getGlobal('BIN',"rsh"));
	&B_chmod_if_exists(0000,&getGlobal('BIN',"rcp"));
	
	# Comment out rsh/rlogin/rexec lines from inetd.conf
        # Note: SecureInetd.pm does this too.
	if ( -e &getGlobal('FILE', "inetd.conf") ) {
	    &B_hash_comment_line( &getGlobal('FILE', "inetd.conf"),"rlogind");
	    &B_hash_comment_line( &getGlobal('FILE', "inetd.conf"),"rexecd");
	    &B_hash_comment_line( &getGlobal('FILE', "inetd.conf"),"rshd");
	}
	if ( -e &getGlobal('FILE','xinetd.conf') ) {
	    # Some systems, including Mac OS X, have an inetd.conf file even when they're xinetd-based.
	    # Actually, you can have both inetd and xinetd running, so longer as they don't overlap ports.
	    foreach $file ('exec','login','rlogin','shell','rsh') {
		if (( -e &getGlobal('DIR', "xinetd.d") . "/$file") && (&getGlobal('DIR', "xinetd.d") ne "")) {
		    &B_replace_line(&getGlobal('DIR', "xinetd.d") . "/$file",'disable\s*=',"\tdisable\t\t= yes\n");
		    &B_insert_line(&getGlobal('DIR', "xinetd.d") . "/$file",'disable\s*=',"\tdisable\t\t= yes\n",'server\s*=');
		}
	    }
	}
    }
}


sub PasswordAging {

# Set default password aging, such that accounts are disabled if the
# password is not changed every 60 days.  We use this hopefully to keep
# passwords fresh and automatically disable accounts that haven't been 
# used in a while.  We could create a cron job that parses lastlog looking
# for unused accounts, but that would fail if your lastlog got deleted by
# an attacker or cycled by your log cycler, as the cron job would disable
# many accounts...

    if (&getGlobalConfig("AccountSecurity","passwdage") eq "Y") {
	&B_log("ACTION","# sub Password Aging\n");
	&B_log("ACTION","adding PASS_MAX_DAYS setting to /etc/login.defs\n");
	
	# Make sure a PASS_MAX_DAYS line is modified or added.
        my $got_replaced=&B_replace_line("/etc/login.defs",'^\s*PASS_MAX_DAYS',"PASS_MAX_DAYS   60\n");
        unless ($got_replaced) {
            B_append_line("/etc/login.defs",'^\s*PASS_MAX_DAYS',"PASS_MAX_DAYS   60\n");
        }
	# Add a warning period - TODO: in the future, gain the ability to 
	# check the warning period in place already so that longer ones are
	# not replaced by shorter ones.
	unless (&B_replace_line("/etc/login.defs",'^\s*PASS_WARN_AGE',"PASS_WARN_AGE   5\n")) {
	    B_append_line("/etc/login.defs",'^\s*PASS_WARN_AGE',"PASS_WARN_AGE   5\n");
        }

    }				      
}

sub PasswordStrength_Linux {

# Set password strength requirements, including a minimum length requirement of 8 characters

    return;

    if (&getGlobalConfig("AccountSecurity","password_strength_linux") eq "Y") {
	&B_log("ACTION","# sub Password Strength Linux\n");

	if ( -e "/lib/security/pam_passwdqc.so") {
	    &B_log("ACTION","activating pam_passwdqc (password quality control) to /etc/pam.d/passwd\n");

	    # Make sure our pam_passwdqc.so line is there
	    my $got_replaced=&B_replace_line("/etc/pam.d/passwd",'^\s*password\s+required\s+pam_passwdqc\.so',"password required pam_passwdqc.so min=disabled,disabled,disabled,disabled,8 random=0\n");
	    unless ($got_replaced) {
		B_append_line("/etc/pam.d/passwd",'^\s*password\s+required\s+pam_passwdqc\.so',"password required pam_passwdqc.so min=disabled,disabled,disabled,disabled,8 random=0\n");
	    }
	}
    }
}

	

sub RestrictCron {

   if ( &getGlobalConfig("AccountSecurity","cronuser") eq "Y" ) {

       &B_log("ACTION","# sub RestrictCron\n");

	# We do this even if cron isn't installed/enabled, because
	# it doesn't hurt

       # Create an cron.allow file, thus restricting crontab's use to
       # root (and other users that might be added to this list)

       # Create the cron.allow file, unless it already exists.
       my $cron_allow = &getGlobal('FILE','cron.allow');
       if ($cron_allow) {
	   &B_create_file ($cron_allow);
	   
	   # Append a list of accounts that can use cron -- only adding lines
	   # if they're not yet in there...
       
	   &B_append_line($cron_allow,"^root\$","root\n");
       }
   }       

}

sub SetUmask {
    if ( &getGlobalConfig("AccountSecurity","umaskyn") eq "Y" ) {
	&B_log("ACTION","# sub SetUmask\n");

        # set the umask in all known shell startup scripts
	my $umask = &getGlobalConfig("AccountSecurity","umask");

	my @filelist = ("profile", "rootprofile", "zprofile", "csh.login");
	if (&GetDistro =~ '^OSX') {
	    @filelist = ("profile", "csh.login");
	}
        for my $startupfile (@filelist) {
           my $fullpath=&getGlobal('FILE', $startupfile);

	   if ( -e $fullpath ) {	       
	       &B_append_line( $fullpath ,'^(\s*)*umask',"umask $umask\n");
	       &B_replace_line( $fullpath,'^(\s*)*umask',"umask $umask\n");
	   }
        }

        # on HP-UX11.22 and later, set the system umask for all pam_unix(5) 
        # initiated sessions
	if (&GetDistro =~ "^HP-UX11.(.*)" and $1>20) {
	    if (defined $umask) {
		my $secfile = &getGlobal('FILE','security');
		&B_set_value('UMASK', $umask, $secfile);
	    }
	}
    }
}

sub RootTTYLogins {
    if ( &getGlobalConfig("AccountSecurity","rootttylogins") eq "Y" ) {
	&B_log("ACTION","# sub RootTTYLogins\n");
	my $securetty = &getGlobal('FILE','securetty');
	
        if ( -e $securetty) {
            my $tty;
            foreach $tty (1,2,3,4,5,6,7,8,9,0) {
                &B_delete_line($securetty, "tty$tty");
                &B_delete_line($securetty, "vc/$tty");
            }
	}
        else {
            # A missing /etc/securetty file would allow root login from 
            # anywhere.
            &B_create_file($securetty);
            &B_append_line($securetty, 
                           '#.*must\s+exist', 
                           '# This file must exist to block root logins, so don\'t delete it unless you want to imply "root may login on any tty device."');
        }
	
        # Prevent root from logging in via a graphical display manager.
        if (( -e '/etc/pam.d/xdm' ) || ( -e '/etc/pam.d/gdm' ) || ( -e '/etc/pam.d/kde' )) {
	    &B_create_file("/etc/bastille-no-login");
	    &B_append_line("/etc/bastille-no-login",'\broot\b',"root\n");
        }
	# stop root from logging in via xdm
#       &B_append_line("/etc/X11/xdm/Xresources","xlogin\.Login\.allowRootLogin","xlogin.Login.allowRootLogin: false");
# TODO: Determine why the above line was commented out.
	if ( -e '/etc/pam.d/xdm') {
	    &B_prepend_line("/etc/pam.d/xdm",'bastille-no-login',"auth\trequired\t/lib/security/pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login\n");
	}

	# stop root from logging in via gdm
#       &B_replace_line("/etc/X11/gdm/gdm.conf",'^\s*AllowRoot\b',"AllowRoot=0\n");
# TODO: Determine why the above line was commented out.
	if ( -e '/etc/pam.d/gdm') {
	    &B_prepend_line("/etc/pam.d/gdm",'bastille-no-login',"auth\trequired\t/lib/security/pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login\n");
	}

	# stop root from logging in via kdm
	if ( -e '/etc/pam.d/kde') {
	    &B_prepend_line("/etc/pam.d/kde",'bastille-no-login',"auth\trequired\t/lib/security/pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login\n");
	}

#    } #Shouldn't make changes when the user picks "no" on a question.  Also, this changes 
#      #systems even when the question wasn't asked (other distros) "else" commented out Jul 23 2001 - RwF
#    else {
#	my $tty;
#        foreach $tty (1,2,3,4,5,6) {
#            &B_append_line("/etc/securetty","tty$tty","tty$tty\n");
 #       }
    }
    #BUG  we need to allow the user to reverse this on gdm,xdm and kdm too
	 	
}

sub RestrictUserView {
    
    # This routine restricts the kdm/gdm userview in Linux-Mandrake
    # Motivation: Compabilitity with msec

    if (&getGlobalConfig("AccountSecurity","forbiduserview") eq "Y") {
	&B_log("DEBUG","# sub RestrictUserView\n");

	# Old KDM's use UserView, while new ones use ShowUsers.
	my $kdmrc = &getGlobal('FILE','kdmrc');
	&B_replace_line($kdmrc,'^UserView\s*=',"UserView=false\n");
	&B_replace_line($kdmrc,'^\s*ShowUsers\s*=',"ShowUsers=None\n");

	# Now do gdm.  Older ones use Browser= 0 or 1, while newer ones use true or false.
	my $gdmconf = &getGlobal('FILE','gdm.conf');
	&B_replace_line($gdmconf,"^Browser\s*=\s*1","Browser=0\n");
	&B_replace_line($gdmconf,"^Browser\s*=\s*(true|True|TRUE)","Browser=false\n");

    }
}

sub Securetty { 

    if (&getGlobalConfig("AccountSecurity","create_securetty") eq "Y") {
	
	&B_log("DEBUG","# sub Securetty\n");
	# echo console > /etc/securetty
        # chmod 400 /etc/securetty

	my $securetty = &getGlobal('FILE', "securetty");
	unless ( -e $securetty ) {
	    &B_create_file($securetty);
	}
	&B_blank_file($securetty,'a$b');

#	&B_chmod(0400,&getGlobal('FILE', "securetty"));

	&B_append_line($securetty,"console","console\n");

    }
    
}


sub HPDefaultSecurity {

    if (&GetDistro =~ "^HP-UX") {
	my $secfile = &getGlobal('FILE','security');

	# options to disallow logins by normal users
	# ABORT_LOGIN_ON_MISSING_HOMEDIR - don't login if homedir is missing
	# NOLOGIN - don't login if /etc/nologin exists
	foreach my $param ("ABORT_LOGIN_ON_MISSING_HOMEDIR", "NOLOGIN", ) {
	    if (&getGlobalConfig("AccountSecurity","$param") eq "Y") {
		&B_set_value("$param", '1', $secfile);
	    }
	}
	
	### Set password policies
        ### This sets values in /etc/default/security ONLY.  Corresponding trusted 
        ### mode parameters are set in convertToTrusted.
        ###
	if (&getGlobalConfig("AccountSecurity","passwordpolicies") eq "Y") {
	  if (&GetDistro =~ "^HP-UX11.(.*)" and $1>20) {
	    foreach my $param ("MIN_PASSWORD_LENGTH",
			       "PASSWORD_MAXDAYS",
			       "PASSWORD_MINDAYS",
			       "PASSWORD_WARNDAYS",) {
		&B_set_value("$param", 
			     &getGlobalConfig("AccountSecurity", $param), $secfile);
	    }

	    if (&getGlobalConfig("AccountSecurity", "PASSWORD_HISTORY_DEPTHyn") eq "Y") {

	        &B_set_value("PASSWORD_HISTORY_DEPTH", 
			     &getGlobalConfig("AccountSecurity", "PASSWORD_HISTORY_DEPTH"), $secfile);
                if (!&convertToTrusted) {
                  &B_TODO("\n" .
                      "------------------------------------\n" .
                      "Password History Depth:\n" .
		      "------------------------------------\n".
                      "Because Trusted System conversion was unsuccessful, you\n".
                      "will need to use SAM to convert to Trusted mode before\n".
                      "the password history depth will take effect.\n");
                }
	    }
          }
	}
	

	if (&getGlobalConfig("AccountSecurity", "NUMBER_OF_LOGINS_ALLOWEDyn") eq "Y") {
	    &B_set_value("NUMBER_OF_LOGINS_ALLOWED", 
			 &getGlobalConfig("AccountSecurity", "NUMBER_OF_LOGINS_ALLOWED"), $secfile);
	}
	
	if (&getGlobalConfig("AccountSecurity", "SU_DEFAULT_PATHyn") eq "Y") {
	    &B_set_value("SU_DEFAULT_PATH", 
			 &getGlobalConfig("AccountSecurity", "SU_DEFAULT_PATH"), $secfile);
	}
    }	
}

# HPHidePasswords - either convert to trusted mode or shadow depending on OS version
sub HPHidePasswords {

   if( &getGlobalConfig('AccountSecurity',"hidepasswords") eq "Y" ||
       &getGlobalConfig('AccountSecurity',"passwordpolicies") eq "Y") {
      &B_log("DEBUG","# sub HPHidePasswords\n");

      if (&isSystemTrusted) {
         &B_log("DEBUG","System is already trusted, passwords are hidden, no action taken.");
         return 1;
      }

      if ( -e &getGlobal('FILE','shadow') ) {
         &B_log("DEBUG","System already has shadow passwords, passwords are hidden, no action taken.");
         return 1;
      }

      if (&GetDistro =~ "^HP-UX11.(.*)" and $1<22) {
          # Conversion to trusted mode is required on 11.20 and prior
          &convertToTrusted;
      } else {
          &convertToShadow;
      }
   }
}

sub HPSingleUserPassword {
    # set password for single user mode
    if (&getGlobalConfig("AccountSecurity","single_user_password") eq "Y") {
	&B_log("DEBUG","# sub HPSingleUserPassword\n");
	
	if ( (&GetDistro =~ "^HP-UX11.(.*)" and $1<23) or &isSystemTrusted ) {
	    # Conversion to trusted mode is required on 11.22 and prior
	    # trusted mode conversion routine takes care of bootpw parameter
	    if ( &convertToTrusted ) {
		# set single user password, if requested and the system is in trusted mode.
		my $getprdef = &getGlobal('BIN','getprdef');
		my $oldbootpwstring=`$getprdef -m bootpw`;
		chomp $oldbootpwstring;
		
		if ($oldbootpwstring ne "bootpw=YES") {
		    my $newbootpwstring="bootpw=YES";
		    &B_System(&getGlobal('BIN','modprdef') . " -m $newbootpwstring", 
			      &getGlobal('BIN','modprdef') . " -m $oldbootpwstring");   
		}
	    }
	    else {
		&B_TODO("\n" .
			"------------------------------------\n" .
			"Set a password for single user mode:\n" .
			"------------------------------------\n".
			"Because Trusted System conversion was unsuccessful, you\n".
			"will need to use SAM to require a password for single user mode.\n");
	    }

	} 
	else {
	    # On versions of HP-UX 11.23 and later, we don't need to convert to trusted
	    # BOOT_AUTH - require root password to enter single user mode.
	    &B_set_value("BOOT_AUTH", '1', &getGlobal('FILE','security'));
	}
    }
}

sub HPEnableAudit {
   # enable auditing
   if (&getGlobalConfig("AccountSecurity","system_auditing") eq "Y") {
       &B_log("DEBUG","# sub HPEnableAudit\n");

       # Conversion to trusted mode is required on all current HP-UX versions
       if (&convertToTrusted) {

           &B_set_rc("PRI_SWITCH",10240);
           &B_set_rc("SEC_SWITCH",10240);
      
           if(&B_get_rc("AUDITING") =~ /1/){
               &B_System(&getGlobal('FILE', 'chkconfig_auditing') . " stop", &getGlobal('FILE', 'chkconfig_auditing') . " start");
           } else{
               &B_set_rc("AUDITING",1);
           }

           if(&B_get_rc("START_ACCT") =~ /1/){
               &B_System(&getGlobal('FILE', 'chkconfig_acct') . " stop", &getGlobal('FILE', 'chkconfig_acct') . " start");
           } else{
               &B_set_rc("START_ACCT",1);
           }
      
             &B_System(&getGlobal('FILE', 'chkconfig_auditing') . " start", &getGlobal('FILE', 'chkconfig_auditing') . " stop");
             &B_System(&getGlobal('FILE', 'chkconfig_acct') . " start", &getGlobal('FILE', 'chkconfig_acct') . " stop");
      } else {
              &B_TODO("\n" .
                      "------------------------------------\n" .
                      "Enable auditing:\n" .
		      "------------------------------------\n".
                      "Because Trusted System conversion was unsuccessful, you\n".
                      "will need to enable auditing manually, or fix the problem\n" .
                      "and rerun Bastille.\n");

      }
   }
}

sub setPWpolicies {

    if (&getGlobalConfig("AccountSecurity","passwordpolicies") eq "Y") {
        my $exptm=  &getGlobalConfig("AccountSecurity","PASSWORD_MAXDAYS");
        my $mintm=  &getGlobalConfig("AccountSecurity","PASSWORD_MINDAYS");
        my $expwarn=&getGlobalConfig("AccountSecurity","PASSWORD_WARNDAYS");

	if (&isSystemTrusted) {
	    
	    &B_log("DEBUG","#sub setPWpolicies\n");
	    my $getprdef = &getGlobal('BIN','getprdef');
	    
	    my $oldsettings = `$getprdef -m exptm,mintm,expwarn`;
	    $oldsettings =~ s/ //g;
	    
	    # remove password lifetime and increasing login tries so they
	    # don't lock themselves out of the system entirely.
	    my $newsettings="exptm=$exptm,mintm=$mintm,expwarn=$expwarn";
	    
	    &B_System(&getGlobal('BIN','modprdef') . " -m $newsettings", 
		      &getGlobal('BIN','modprdef') . " -m $oldsettings");   
	}
	elsif ( -e &getGlobal('FILE','shadow') ) {
	    
	    my $passwd=&getGlobal('BIN','passwd') . " -r files";
	    my $userlistcmd="$passwd -s -a";
	    open USERS,"$userlistcmd|";
	    while (my $line=<USERS>) {
		chomp $line;
		my ($name, $status, $date, $oldmin, $oldmax, $oldwarn)=split(/\s+/, $line);
		# if warn is set to 0, the field will be blank
		if (not defined $oldwarn || $oldwarn eq "") {
		    $oldwarn=0;
		}
		
		if ($name!~/root/) {
		    if (defined $oldmin && defined $oldmax) {
			&B_System("$passwd -n $mintm -x $exptm -w $expwarn $name",
				  "$passwd -n $oldmin -x $oldmax -w $oldwarn $name");
		    } else {
			&B_System("$passwd -n $mintm -x $exptm -w $expwarn $name",
				  "$passwd -x -1 $name");
		    }
		}
	    }
	    close USERS;
	}
	else {
	    &B_TODO("\n---------------------------------\n" .
		    "Password policies:\n" .
		    "---------------------------------\n" .
		    "Because trusted system conversion or shadow password\n" .
		    "conversion failed, you will need to manually set password\n" .
		    "policies using SAM or the passwd command.  Alternatively,\n" .
		    "fix the problem that caused the conversion to fail and\n".
		    "rerun Bastille.\n");
	}

    }
    
    
}

###########################
# Utility routines follow
#
# sub convertToTrusted 
# sub isOKtoConvert
# sub isSystemTrusted
# sub convertToShadow 
###########################

# Convert to trusted mode if it's not already
sub convertToTrusted {
   &B_log("DEBUG","# sub convertToTrusted \n");
   if( ! &isSystemTrusted) {

      my ($ok, $message) = &isOKtoConvert;

      my $ts_header="\n---------------------------------\nTrusted Systems:\n" .
                    "---------------------------------\n";

      if ($ok) {
	# actually do the conversion
        if(&B_System(&getGlobal('BIN','tsconvert'), &getGlobal('BIN','tsconvert') . " -r")){
	  # adjust change times for user passwords to keep them valid
	  # default is to expire them when converting to a trusted system,
	  # which can be problematic, especially since some older versions of
	  # SecureShell do not allow the user to change the password
	  &B_System(&getGlobal('BIN','modprpw') . " -V", "");

	  my $getprdef = &getGlobal('BIN','getprdef');
	  my $oldsettings = `$getprdef -m lftm,exptm,mintm,expwarn,umaxlntr`;
	  $oldsettings =~ s/ //g;
	    
	  # remove password lifetime and increasing login tries so they
	  # don't lock themselves out of the system entirely.
	  # set default expiration time and the like.
	  my $newsettings="lftm=0,exptm=0,mintm=0,expwarn=0,umaxlntr=10";
	  
	  &B_System(&getGlobal('BIN','modprdef') . " -m $newsettings", 
		    &getGlobal('BIN','modprdef') . " -m $oldsettings");   

          &B_TODO($ts_header .
                  "Your system has been converted to a trusted system.\n" . 
                  "You should review the security settings available on a trusted system.\n".
                  "$message");

          # to get rid of "Cron: Your job did not contain a valid audit ID."
          # error, we re-read the crontab file after converting to trusted mode
          # Nothing is necessary in "revert" since we won't be in trusted mode
          # at that time.
          # crontab's errors can be spurious, and this will report an 'error'
          # of the crontab file is missing, so we send stderr to the bit bucket
          my $crontab = &getGlobal('BIN',"crontab");
	  &B_System("$crontab -l 2>/dev/null | $crontab","");
        }  

      } else {
          &B_TODO($ts_header . $message);
          return 0; # not ok to convert, so we didn't
      }
   }
   else {
      &B_log("DEBUG","System is already in trusted mode, no action taken.\n");
      return 1;
   }

   # just to make sure
   if( &isSystemTrusted ) {
      return 1;
   } else {
      &B_log("ERROR","Trusted system conversion was unsuccessful for an unknown reason.\n" .
                "         You may try using SAM to do the conversion instead of Bastille.\n");
      return 0;
   }
}

# isOKtoConvert - check for conflicts between current system state and trusted 
# mode
#
# Return values
# 0 - conflict found, see message for details
# 1 - no conflicts, see message for further instructions
#
sub isOKtoConvert {
    &B_log("DEBUG","# sub isOKtoConvert \n");
    # initialize text for TODO instructions
    my $specialinstructions="  - convert to trusted mode\n";

    # These are somewhat out-of-place, but only affect the text of the message.
    # Each of these messages is repeated in a separate TODO item in the
    # appropriate subroutine.
    if (&getGlobalConfig("AccountSecurity","single_user_password") eq "Y") {
	if (&GetDistro =~ "^HP-UX11.(.*)" and $1<23 ) {	
	    $specialinstructions .= "  - set a single user password\n";
	}
    }

    if (&getGlobalConfig("AccountSecurity","passwordpolicies") eq "Y") {
	    $specialinstructions .= "  - set trusted mode password policies\n";
    }

    if (&getGlobalConfig("AccountSecurity", "PASSWORD_HISTORY_DEPTHyn") eq "Y") {
       $specialinstructions .= "  - set a password history depth\n";
    }

    if (&getGlobalConfig("AccountSecurity","system_auditing") eq "Y") {
       $specialinstructions .= "  - enable auditing\n";
    }

    my $saminstructions=
	   "The security settings can be modified by running SAM as follows:\n" .
	   "# sam\n" .
	   "Next, go to the \"Auditing and Security Area\" and review\n" .
	   "each sub-section.  Make sure that you review all of your\n" .
	   "settings, as some policies may seem restrictive.\n\n";

    # First, check for possible conflicts and corner cases
       
    # check nsswitch for possible conflicts
    my $nsswitch = &getGlobal('FILE', 'nsswitch.conf');
    if ( -e $nsswitch) {
        open(FILE, $nsswitch);
        while (<FILE>) {
            if (/nis/ or /compat/ or /ldap/) {
              my $message = "Bastille found a possible conflict between trusted mode and\n" .
		            "$nsswitch.  Please remove all references to\n" .
                            "\"compat\", \"nis\" and \"ldap\" in $nsswitch\n" .
                            "and rerun Bastille, or use SAM to\n" .
                            "$specialinstructions\n".
                            "$saminstructions";
              close(FILE);
	      return (0,$message);
            }
        }
        close(FILE);
    }

    # check the namesvrs config file for possible NIS conflicts
    if ( &getGlobalConfig('MiscellaneousDaemons','nis_client') eq "N" or
         &getGlobalConfig('MiscellaneousDaemons','nis_server') eq "N" ) {
	my $namesvrs = &getGlobal('FILE', 'namesvrs');
	if (open(FILE, $namesvrs)) {
	    while (<FILE>) {
		if (/^NIS.*=["]?1["]?$/) {
		    my $message= "Possible conflict between trusted mode and NIS found.\n".
			"Please use SAM to\n" .
			"  - turn off NIS\n" .
			"$specialinstructions\n".
			"$saminstructions";
		    close(FILE);
		    return (0,$message);
		}
	    }
	    close(FILE);
	} else {
            &B_log("ERROR","Unable to open $namesvrs for reading.");
            my $message= "Possible conflict between trusted mode and NIS found.\n".
		"Please use SAM to\n" .
		"  - turn off NIS\n" .
		"$specialinstructions\n".
		"$saminstructions";
	    return (0,$message);
	}
    }
    

    # check for conflicts with DCE integrated login
    my $authcmd = &getGlobal('BIN','auth.adm');
    if ( -e $authcmd ) {
         my $retval = system("PATH=/usr/bin $authcmd -q 1>/dev/null 2>&1");
         if ($retval != 0 and $retval != 1) {
             my $message="It appears that DCE integrated login is configured on this system.\n" .
		      "DCE integrated login is incompatible with trusted systems and\n" .
		      "auditing.  Bastille is unable to\n" .
		      "$specialinstructions" .
		      "You will need to configure auditing and password policies using DCE.\n\n";
	     return (0,$message);
         }
    }

    if ( -e &getGlobal('FILE','shadow') ) {
       my $message="This system has already been converted to shadow passwords.\n" .
                   "Shadow passwords are incompatible with trusted mode.\n" .
		   "Bastille is unable to\n" .
		   "$specialinstructions" .
                   "If you desire these features, you should use\n".
                   "\'pwunconv\' to change back to standard passwords,\n".
                   "and then rerun Bastille.\n\n";
       return (0,$message);
   }

    return (1,$saminstructions);
}

sub isSystemTrusted {
   &B_log("DEBUG","# sub isSystemTrusted \n");
   my $getprdef = &getGlobal('BIN',"getprdef");
   my $definition = `$getprdef -t 2>&1`;
   if($definition =~ "System is not trusted.") {
     return 0;
   } else {
     return 1;
   }
}
   
sub convertToShadow {

        if (&isSystemTrusted) {
            # This is an internal error...Bastille should not call this routine
            # in this case.  Error is here for robustness against future changes.
            &B_log("ERROR","This system is already converted to trusted mode.\n" .
                      "         Converting to shadow passwords will not be attempted.\n");
            return 0;
        }
    
	# configuration files on which shadowed passwords depend
        my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf");

	# binaries used to convert to a shadowed password
	my $pwconv = &getGlobal('BIN',"pwconv");
	my $echo = &getGlobal('BIN','echo'); # the echo is used to pipe a yes into the pwconv program as
	                                     # pwconv requires user interaction.

	# the binary used in a system revert.
	my $pwunconv = &getGlobal('BIN',"pwunconv");
	#check the password file for nis usage and if the nis client
	#or server is running.  
	if(-e $nsswitch_conf) {
	    # check the file for nis, nis+, compat, or dce usage.
	    if(&B_match_line($nsswitch_conf, '^\s*passwd:.+(nis|nisplus|dce|compat)')) {
		my $shadowTODO = "\n---------------------------------\nHide encrypted passwords:\n" . 
		                 "---------------------------------\n" .
		                 "This version of password shadowing does not support any repository other\n" .
		                 "than files. In order to convert your password database to shadowed passwords\n" .
				 "there can be no mention of nis, nisplus, compat, or dce in the passwd\n" .
				 "field of the \"$nsswitch_conf\" file.  Please make the necessary edits to\n" . 
				 "the $nsswitch_conf file and run Bastille again using the command:\n" .
				 "\"bastille -b\"\n";
		# Adding the shadowTODO comment to the TODO list.
		&B_TODO("$shadowTODO");
		# Notifing the user that the shadowed password coversion has failed.
		&B_log("ERROR","Password Shadowing Conversion Failed\n" .
			  "$shadowTODO");
		# exiting the subroutine.
		return 0;
	    }
	    
	}

	# convert the password file to a shadowed repository.
	if( &B_System("$echo \"yes\" | $pwconv","$pwunconv") ) {
	    &B_TODO( "\n---------------------------------\nShadowing Password File:\n" . 
		     "---------------------------------\n" .
		     "Your password file has been converted to use password shadowing.\n" .
		     "This version of password shadowing does not support any repository other\n" .
		     "than files. There can be no mention of nis, nisplus, compat, or dce\n" .
		     "in the passwd field of the \"$nsswitch_conf\" file.\n\n" );
	}
}

sub RemoveUnnecessaryAccounts {

    # This function removes unncessary accounts, as dictated by AccountSecurity.removeaccounts (Y/N) 
    # and AccountSecurity.removeaccounts_list (accounts to remove, comma-separated)

    if (&getGlobalConfig('AccountSecurity','removeaccounts') eq "Y") {
	my @accounts_to_remove = split /\s+/,&getGlobalConfig('AccountSecurity','removeaccounts_list');
	foreach $account (@accounts_to_remove) {
	    &B_userdel($account);
	}
    }

}

sub RemoveUnnecessaryGroups {

    # This function removes unncessary groups, as dictated by AccountSecurity.removegroups (Y/N) 
    # and AccountSecurity.removegroups_list (groups to remove, comma-separated)

    if (&getGlobalConfig('AccountSecurity','removegroups') eq "Y") {
	my @groups_to_remove = split /\s+/,&getGlobalConfig('AccountSecurity','removegroups_list');
	foreach $group (@groups_to_remove) {
	    &B_groupdel($group);
	}
    }

}
1;

