#!/usr/bin/env python

# This file is part of Window-Switch.
# Copyright (c) 2009-2013 Antoine Martin <antoine@nagafix.co.uk>
# Window-Switch is released under the terms of the GNU GPL v3

import sys
from winswitch.util.simple_logger import Logger

PAM_SERVICE = 'login'
PAM_PASSWORD = "password"
has_win32security = False
if sys.platform.startswith("win"):
	try:
		import win32security			#@UnresolvedImport
		assert win32security			#avoid pydev warning
		has_win32security = True
	except:
		pass
else:
	try:
		import PAM						#@UnresolvedImport
		has_PAM = True
	except:
		has_PAM = False
	try:
		from winswitch.util import pam
		assert pam
		has_pam = True
	except:
		has_pam = False


magic_password = None
MAGIC_PASSWORD = "--magic_password="
for arg in sys.argv:
	if arg.startswith(MAGIC_PASSWORD):
		magic_password = arg[len(MAGIC_PASSWORD):]


class PasswordChecker:

	def __init__(self, username, password):
		Logger(self, log_colour=Logger.HIGHLIGHTED_BLUE).add_methods(self)
		self.username = username
		self.password = password

	def check(self):
		if magic_password and self.password==magic_password:
			return	True
		if has_win32security:
			return self.win_logon_check()
		if not has_PAM and not has_pam:
			self.serror("no PAM modules available! cannot authenticate with password!")
			return	False
		if has_pam:
			return self.check_pam()
		if has_PAM:
			return self.check_PAM()
		return False

	def win_logon_check(self):
		try:
			win32security.LogonUser(self.username, '', self.password, win32security.LOGON32_LOGON_NETWORK, win32security.LOGON32_PROVIDER_DEFAULT)
			return	True
		except win32security.error, e:
			self.serr(None, e)
			return	False

	def check_pam(self):
		return pam.authenticate(self.username, self.password)

	def check_PAM(self):
		auth = PAM.pam()
		auth.start(PAM_SERVICE)
		auth.set_item(PAM.PAM_USER, self.username)
		auth.set_item(PAM.PAM_CONV, self.pam_conv_password)
		try:
			auth.authenticate()
			#auth.acct_mgmt()
		except PAM.error, resp:
			self.error("check() PAM error: %s" % str(resp))
			return	False
		except Exception, e:
			self.error("check() internal error!", e)
			return	False
		return	True

	def pam_conv_password(self, auth, query_list, *args):
		try:
			sig = "pam_conv_password(%s,%s)" % (str(auth), str(query_list))
			resp = []
			for i in range(len(query_list)):
				query, pam_type = query_list[i]
				if pam_type == PAM.PAM_PROMPT_ECHO_ON or pam_type == PAM.PAM_PROMPT_ECHO_OFF:
					resp.append((self.password, 0))
				elif pam_type == PAM.PAM_PROMPT_ERROR_MSG or pam_type == PAM.PAM_PROMPT_TEXT_INFO:
					self.log(sig+" ERROR/INFO: '%s'" % query)
					resp.append(('', 0))
				else:
					self.error(sig+" unknown type: '%s'" % pam_type)
		except Exception, e:
			self.error(sig, e)
		return	resp
