diff --git a/AUTHORS b/AUTHORS
index 6f5b94a..dbcc2c1 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,3 +11,4 @@ Nikhil Lanjewar <nikhil@lanjewar.com>
 Sahil Muthoo <sahilm@thoughtworks.com>
 Sahil Aggarwal <sahilagg@gmail.com>
 Saager Mhatre <saager.mhatre@gmail.com>
+Iain Douglas <centos@1n6.org.uk>
diff --git a/tests/p_passwd/0_install_passwd b/tests/p_passwd/0_install_passwd
new file mode 100755
index 0000000..62e1bba
--- /dev/null
+++ b/tests/p_passwd/0_install_passwd
@@ -0,0 +1,6 @@
+#!/bin/bash
+# Author: Iain Douglas <centos@1n6.org.uk>
+
+# Ensure packages we use are installed
+t_Log "Running $0 installing required packages"
+t_InstallPackage passwd  expect
diff --git a/tests/p_passwd/10_passwd_basic_test b/tests/p_passwd/10_passwd_basic_test
new file mode 100755
index 0000000..d33545b
--- /dev/null
+++ b/tests/p_passwd/10_passwd_basic_test
@@ -0,0 +1,8 @@
+#!/bin/bash
+#Author: Iain Douglas <centos@1n6.org.uk>
+#
+t_Log "Running $0 - Basic passwd functionality checks"
+
+userdel -rf passtest; useradd passtest  &>/dev/null
+echo passtest | passwd --stdin passtest &>/dev/null
+t_CheckExitStatus $?
diff --git a/tests/p_passwd/20_root_tests b/tests/p_passwd/20_root_tests
new file mode 100755
index 0000000..c2cb9a1
--- /dev/null
+++ b/tests/p_passwd/20_root_tests
@@ -0,0 +1,122 @@
+#!/bin/bash
+# Author: Iain Douglas <centos@1n6.org.uk>
+#
+
+function ExitFail
+{
+    t_Log "FAIL"
+    exit $FAIL
+}
+#
+# Test the command line options for passwd that are restricted to root.
+#
+
+t_Log "Running $0 - Check root only actions"
+t_Log "Create test user passtest"
+userdel -rf passtest; useradd passtest && echo passtest | passwd --stdin passtest &>/dev/null
+t_CheckExitStatus $?
+
+# Check that passwd -l locks the password - the field in /etc/shadow has 
+# a ! prepended
+t_Log "Check account can be locked"
+passwd -l passtest &>/dev/null
+
+if [ $? -eq "0" ]
+then
+    getent shadow passtest | cut -f2 -d: | grep '^!' &>/dev/null
+    t_CheckExitStatus $?
+else
+    ExitFail
+fi
+
+# Check that passwd -u will unlock the account - removes the ! from the 
+# start of the password field in /etc/shadow
+t_Log "Check account can be unlocked"
+passwd -u passtest &>/dev/null
+
+if [ $? -eq "0" ]
+then
+    getent shadow passtest | cut -f2 -d: | grep -v '^!' &>/dev/null
+    t_CheckExitStatus $?
+else
+    ExitFail
+fi
+
+# Check that passwd -e expires an account. Field 3 of /etc/shadow is set to 0
+t_Log "Check password can be expired"
+passwd -e passtest &>/dev/null
+
+if [ $? -eq "0" ]
+then
+    getent shadow passtest | cut -f3 -d: | grep '^0' &>/dev/null 
+    t_CheckExitStatus $?
+    echo passtest | passwd --stdin passtest &>/dev/null
+else
+    ExitFail
+fi
+
+# Check that passwd -n, -x, -w -i set the mindays, maxdays, warndays and
+# inactive fields (4-7) in /etc/shadow
+t_Log "Check password aging data can be set"
+passwd -n 11 -x 22 -w 33 -i 44 passtest &>/dev/null
+
+if [ $? -eq "0" ]
+then
+    getent shadow passtest | cut -f4-7 -d: | grep '^11:22:33:44' &>/dev/null
+    t_CheckExitStatus $?
+else
+    ExitFail
+fi
+
+# Check that passwd -d deletes the password - the field in /etc/shadow is
+# cleared
+t_Log "Check password can be deleted"
+passwd -d passtest &>/dev/null
+
+if [ $? -eq "0" ]
+then
+    password=$(getent shadow passtest | cut -f2 -d:)
+    if [ -z "${password}" ]
+    then
+        t_Log "PASS"
+    else
+        ExitFail
+    fi
+else
+    ExitFail
+fi
+
+# Passwd won't, without being forced, unlock an account with a blank password
+# so check this is the case.
+t_Log "Check blank password cannot be unlocked"
+passwd -l passtest &>/dev/null
+passwd -u passtest &>/dev/null 
+
+if [ $? -ne "0" ]
+then
+    t_Log PASS
+else
+    ExitFail
+fi
+
+# Force passwd to unlock an account with a blank password passwd -uf.
+t_Log "Check blank password can be force unlocked"
+passwd -uf passtest &>/dev/null
+t_CheckExitStatus $?
+
+# Check the output of passwd -S at this point it should be
+# passtest NP YYYY-MM-DD  11 22 33 44 (Empty password.)
+# It's possible that this will run on a different side of midnight to earlier 
+# commands so if checking the output for today fails check yesterday too
+t_Log "Check output of passwd -S"
+
+expected="passtest NP "$(date +'%F')" 11 22 33 44 (Empty password.)"
+passwd -S passtest | grep "$expected" &>/dev/null
+if [ $? -eq "0" ]
+then
+    t_Log "PASS"
+else
+    expected="passtest NP "$(date +'%F' -d yesterday)" 11 22 33 44 (Empty password.)"
+    passwd -S passtest | grep "$expected" &>/dev/null
+    t_CheckExitStatus $?
+fi 
diff --git a/tests/p_passwd/30_user_tests b/tests/p_passwd/30_user_tests
new file mode 100755
index 0000000..b9714ec
--- /dev/null
+++ b/tests/p_passwd/30_user_tests
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Author: Iain Douglas <centos@1n6.org.uk>
+#
+
+function ExitFail {
+    t_Log "FAIL"
+    exit $FAIL
+}
+
+t_Log "Runing $0 - normal user password tests"
+# Check that the passtest user cannot use the root only options 
+
+t_Log "Checking a normal user cannot use root options"
+
+su passtest -c "passwd -l passtest" &>/dev/null && ExitFail
+su passtest -c "passwd -u passtest" &>/dev/null && ExitFail
+su passtest -c "passwd -e passtest" &>/dev/null && ExitFail
+su passtest -c "passwd -n 10 passtest" &>/dev/null && ExitFail
+su passtest -d "passwd -d passtest" &>/dev/null && ExitFail
+su passtest -d "passwd -S passtest" &>/dev/null && ExitFail
+t_Log "Pass"
+
+# Check the user can change their own password. Reset it to passtest and
+# turn off min change days before trying. Password becomes ano24ther
+
+t_Log "Test user can change own password"
+
+echo "passtest" | passwd --stdin passtest &>/dev/null
+passwd -n 0 passtest &>/dev/null
+./tests/p_passwd/_user_password.expect &>/dev/null
+t_CheckExitStatus $?
+
+# Check that sending the wrong current password fails we send passtest
+
+t_Log "Check sending incorrect current password fails"
+./tests/p_passwd/_user_password.expect &>/dev/null
+
+if [ $? -eq "3" ]
+then
+    t_Log "PASS"
+else
+    ExitFail
+fi
+
+# Check that user cannot immediately change password if minimum password
+# lifeftime is enabled.
+
+t_Log "Testing Minimum password lifetine is enforced"
+echo "passtest" | passwd --stdin passtest &>/dev/null
+passwd -n 1 passtest &>/dev/null
+./tests/p_passwd/_user_password.expect  &>/dev/null
+
+if [ $? -eq "2" ]
+then
+    t_Log "PASS"
+else
+    ExitFail
+fi
+
+# Password complexity tests
+echo "passtest" | passwd --stdin passtest &>/dev/null
+passwd -n 0 passtest &>/dev/null
+
+# Check very short password is rejected (single letter)
+t_Log "Test very short password is rejected (1 character)"
+./tests/p_passwd/_password_complexity.expect a &>/dev/null
+t_CheckExitStatus $?
+
+# Check a short password is rejected (4 chars)
+t_Log "Test short password is rejected (4 charaters)"
+./tests/p_passwd/_password_complexity.expect athe &>/dev/null
+t_CheckExitStatus $?
+
+# Check password is rejected with insufficient complexity
+t_Log "Test insufficiently complex password is rejected"
+./tests/p_passwd/_password_complexity.expect betabeta &>/dev/null
+t_CheckExitStatus $?
+
+# Check palindromic password is rejected
+t_Log "Check palindromic password is rejected"
+./tests/p_passwd/_password_complexity.expect qwe123321ewq &>/dev/null
+t_CheckExitStatus $?
diff --git a/tests/p_passwd/TODO b/tests/p_passwd/TODO
new file mode 100644
index 0000000..b49d195
--- /dev/null
+++ b/tests/p_passwd/TODO
@@ -0,0 +1,3 @@
+# I don't understand what -k is supposed to do.
+# Without changing the date and time I can't think of a way to test
+# that -x -w and -i are working
diff --git a/tests/p_passwd/_password_complexity.expect b/tests/p_passwd/_password_complexity.expect
new file mode 100755
index 0000000..6b73c62
--- /dev/null
+++ b/tests/p_passwd/_password_complexity.expect
@@ -0,0 +1,22 @@
+#!/usr/bin/expect -f
+# Author: Iain Douglas <centos@1n6.org.uk>
+#
+
+set testpassword [lindex $argv 0]
+set timeout 10
+match_max 6000
+
+spawn su passtest -c passwd
+expect "UNIX password:" { send -- "passtest\r" }
+expect {
+    "password:" {
+         send "$testpassword\r"
+         expect {
+             "BAD PASSWORD: it is WAY too short" { exit 0 }
+             "BAD PASSWORD: it is too short" { exit 0 }
+             "BAD PASSWORD: it does not contain enough DIFFERENT characters" { exit 0 }
+             "BAD PASSWORD: is a palindrome" { exit 0 }
+         }
+     }
+}
+exit 1
diff --git a/tests/p_passwd/_user_password.expect b/tests/p_passwd/_user_password.expect
new file mode 100755
index 0000000..04a78c2
--- /dev/null
+++ b/tests/p_passwd/_user_password.expect
@@ -0,0 +1,24 @@
+#!/usr/bin/expect -f
+# Author: Iain Douglas <centos@1n6.org.uk>
+
+set timeout 10
+match_max 6000
+spawn su passtest -c passwd
+expect  "UNIX password:" { send -- "passtest\r" }
+expect { 
+         "You must wait longer to change your password" 
+             {
+              exit 2 
+             }
+         "Authentication token manipulation error"
+             {
+              exit 3
+             }
+         "password:" 
+             {
+              send -- "ano24ther\r"
+              expect "*?password:*"
+              send -- "ano24ther\r"
+              expect eof 
+             }
+       }