#!/usr/bin/perl
#*********************************************************************
#   Copyright (C) International Business Machines  Corp., 2003
#
#   This program is free software;  you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY;  without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
#   the GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this pronram;  if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#
#
#  FILE   : pam01
#
#  PURPOSE: Tests that required pam restrictions on user passwords
#             are enforced.
#
#  SETUP: This script requires perl, as well as the Expect module
#           for perl.  The script must be run by "root". 
#
#  HISTORY:
#    03/03 originated by Dustin Kirkland (k1rkland@us.ibm.com)
#
#*********************************************************************
#!/usr/bin/perl

use Expect;
use strict;
use warnings;

require "utils.plib";

my $username1 = "pam_user";
my $initial_password = "ltp_test_pass";
my $initial_encrypted_password = "\\\$1\\\$1yzzszzz\\\$7P9AphbzAN43pTktT\/kpp\/";
my $good_password1 = "brand_new_phrase_for_test";
#my $good_password1 = "long_difficult_password";
my $good_password2 = "this_passphrase_is_different";
my $good_password3 = "yet_another_password-phrase";


# This two dimensional array contains the information for each test.  This includes:
#   - expected_exit_code1: The expected exit code of the password change
#   - expected_exit_code2: The expected exit code of the command to run after the attempted
#                          password change
#   - description_of_test: A brief textual description of the test
#   - password_to_try    : The textual password to try
my @test = (
#           [ expected_exit_code1, expected_exit_code2, description_of_test, password_to_try ]
            [7, 0, "password not a new password", "$initial_password"],                      # 0
            [7, 0, "password too short", "a"],                                               # 1
            [7, 0, "password too simple", "wxyz9876"],                                       # 2
            [7, 0, "password case changes only", uc($initial_password)],                     # 3
            [7, 0, "password too similar", substr($initial_password, 0, -1)],                # 4
            [7, 0, "password rotated", substr($initial_password.$initial_password, 0, 8)],   # 5 
            [7, 0, "password based on a dictionary word", "computer"],                       # 6
            [7, 0, "password based on username", substr($username1.$username1, 0, 8)],       # 7
            [7, 0, "password does not contain enough DIFFERENT characters", "aabbccdd"],     # 8
            [7, 0, "password is a palindrome", "abcddcba"],                                  # 9
            [0, 0, "password is acceptable", $good_password1],                     # 10
            [7, 0, "password is acceptable, but previously used", $good_password1] # 11
           );
my @result;
my $password;
my $exit_code = 0;
my %ARGV;
# Write the @ARGV command line arguments into a hash
foreach $_ (@ARGV) {
  $ARGV{$_} = 1;
}


#################
# Begin Testing #
#################

print("========================================================================\n");
print("Begin execution of pam01\n");
print("Testing that required pam restrictions on user passwords are enforced.\n");
print("========================================================================\n");

print("Username: [$username1]\n");
print("Password: [$initial_password]\n");

# Remove /etc/security/opasswd to ensure any acceptable password has never been used in this context
unlink("/etc/security/opasswd");

for (my $i=0; $i<@test; $i++) {
# By default, this script executes all tests.  Optionally, the user may specify the 
# indices of the tests to run on the command line.
  if ((@ARGV) && (!$ARGV{$i})) {
    next;
  }

# Create the users for testing purposes
  $Expect::Log_Stdout = 0;
  create_user($username1);

# Set the user's initial password
  set_encrypted_password($username1, $initial_encrypted_password);
  $Expect::Log_Stdout = 1;

# Set the system time ahead 2 days
  my $current_time = advance_system_time(2);

  print("\n-> Test \#$i : Trying $test[$i][2] for user [$username1] with new password [$test[$i][3]]\n");
# Attempt to change the password, save the exit status
  unlink("/etc/security/opasswd");
  my $status1 = change_password($username1, $initial_password, $test[$i][3]);
  if ($i == 11) {
# if we're testing password reuse, change password twice in a row
    advance_system_time(2);
    $status1 = change_password($username1, $good_password1, $good_password2);
    $status1 = change_password($username1, $good_password2, $good_password1);
    $initial_password = $good_password2;
  }
  unlink("/etc/security/opasswd");
  my $lower1 = $status1 / 256;
  my $upper1 = $status1 % 256;
# Attempt to login as the user with the password as it should be
  if ($test[$i][0] == 0) {
    $password = $test[$i][3];
  } else {
    $password = $initial_password;
  }
  my $status2 = run_as_user($username1, $password, "pwd");
  my $lower2 = $status2 / 256;
  my $upper2 = $status2 % 256;
 
  $result[$i] = "==> Test \#$i : ";
  if (($upper1 == 0) && ($upper2 == 0) && ($lower1 == $test[$i][0]) && ($lower2 == $test[$i][1])) {
    $result[$i] .= "PASS ($test[$i][2])\n";
  } else {
    $result[$i] .= "FAIL ($test[$i][2])\n *** Text \#$i expected exit codes [$test[$i][0], $test[$i][1]] but got [$lower1, $lower2]\n";
    $exit_code = 1;
  }
  print($result[$i]);

# Set system time back
  revert_system_time($current_time);

# Delete the users that was created for this test
  $Expect::Log_Stdout = 0;
  delete_user($username1);
  $Expect::Log_Stdout = 1;
}

###############
# End Testing #
###############

# Print rolled up results
print("\nSummary of Results\n");
foreach my $result (@result) {
  if ($result) { 
    print($result);
  }
}

print("========================================================================\n");
print("End execution of pam01\n");
print("========================================================================\n");


exit $exit_code;

