#!/usr/bin/python

import PAM
import subprocess

config = {
    'db': 'pam',
    'db_user': 'pam',
    'db_password': 'pampasswd',
    'db_table': 'users',
    'user_column': 'username',
    'password_column': 'password',
    'test_user': 'foo',
    'test_password': 'foopwd',
    'pam_service': 'pamtest',
    'config_file': '/etc/pam-mysql.conf'
}

mysql = subprocess.Popen('mysql', stdin=subprocess.PIPE)
mysql.communicate('''\
CREATE DATABASE {db};
USE {db};
CREATE TABLE {db_table} (
  {user_column} VARCHAR (10) NOT NULL,
  {password_column} VARCHAR (10) NOT NULL
);
INSERT INTO {db_table} ({user_column}, {password_column})
  VALUES ('{test_user}','{test_password}');
CREATE USER {db_user}@localhost IDENTIFIED BY '{db_password}';
GRANT SELECT ON {db}.{db_table} TO {db_user}@localhost;
'''.format(**config))

pam_mysql_conf = open(config['config_file'], 'w')
pam_mysql_conf.write('''\
users.host 		= localhost
users.database 		= {db}
users.db_user 		= {db_user}
users.db_passwd		= {db_password}
users.table 		= {db_table}
users.user_column 	= {user_column}
users.password_column 	= {password_column}
users.password_crypt 	= 0
'''.format(**config))
pam_mysql_conf.close()

pam_conf = open('/etc/pam.d/{pam_service}'.format(**config), 'w')
pam_conf.write('''\
auth required pam_mysql.so config_file={config_file}
'''.format(**config))
pam_conf.close()

def pam_conv(auth, query_list, userData):
    if query_list != [('Password:', PAM.PAM_PROMPT_ECHO_OFF)]:
        print('Unexpected query_list', query_list)
        return None
    return [(userData,0)]

correct = PAM.pam()
correct.start(config['pam_service'], config['test_user'], pam_conv)
correct.setUserData(config['test_password'])
correct.authenticate()
print('OK: success with correct password')

incorrect = PAM.pam()
incorrect.start(config['pam_service'], config['test_user'], pam_conv)
incorrect.setUserData('wrong_password')
try:
    incorrect.authenticate()
except PAM.error as err:
    if err.args == ('Authentication failure', 7):
        print('OK: failure with incorrect password')
    else:
        raise
else:
    raise PAM.error('Erroneous successful authentication', PAM.PAM_SUCCESS)
