# -*- coding: utf-8 -*-
#
# (c) Copyright @ 2015 HP Development Company, L.P.
#
# 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Amarnath Chitumalla
#
import os
import getpass
import time
import string
from . import utils, tui
from .g import *
from .sixext import BytesIO, StringIO
from .sixext.moves import input
from . import pexpect
PASSWORD_RETRY_COUNT = 3
AUTH_TYPES = {'mepis': 'su',
'debian': 'su',
'suse': 'su',
'mandriva': 'su',
'fedora': 'su',
'fedora28': 'sudo',
'redhat': 'su',
'rhel': 'su',
'slackware': 'su',
'gentoo': 'su',
'redflag': 'su',
'ubuntu': 'sudo',
'xandros': 'su',
'freebsd': 'su',
'linspire': 'su',
'ark': 'su',
'pclinuxos': 'su',
'centos': 'su',
'igos': 'su',
'linuxmint': 'sudo',
'linpus': 'sudo',
'gos': 'sudo',
'boss': 'su',
'lfs': 'su',
'manjarolinux': 'sudo',
}
# This function promts for the username and password and returns
# (username,password)
def showPasswordPrompt(prompt):
import getpass
print ("")
print ("")
print (log.bold(prompt))
username = input("Username: ")
password = getpass.getpass("Password: ")
return (username, password)
# TBD this function shoud be removed once distro class implemented
def get_distro_name():
import distro
return distro.linux_distribution(full_distribution_name=False)[0]
class Password(object):
def __init__(self, Mode=INTERACTIVE_MODE):
self.__password = ""
self.__password_prompt_str = ""
self.__passwordValidated = False
self.__mode = Mode
self.__readAuthType() # self.__authType
self.__expectList = []
if not utils.to_bool(sys_conf.get('configure', 'qt5', '0')) and not not utils.to_bool(sys_conf.get('configure', 'qt4', '0')) and utils.to_bool(sys_conf.get('configure', 'qt3', '0')):
self.__ui_toolkit = 'qt3'
elif not utils.to_bool(sys_conf.get('configure', 'qt5', '0')) and not utils.to_bool(sys_conf.get('configure', 'qt3', '0')) and utils.to_bool(sys_conf.get('configure', 'qt4', '0')):
self.__ui_toolkit = 'qt4'
elif not utils.to_bool(sys_conf.get('configure', 'qt3', '0')) and not utils.to_bool(sys_conf.get('configure', 'qt4', '0')) and utils.to_bool(sys_conf.get('configure', 'qt5', '0')):
self.__ui_toolkit = 'qt5'
for s in utils.EXPECT_WORD_LIST:
try:
p = re.compile(s, re.I)
except TypeError:
self.__expectList.append(s)
else:
self.__expectList.append(p)
##################### Private functions ######################
def __readAuthType(self):
# TBD: Getting distro name should get distro class
distro_name = get_distro_name().lower()
self.__authType = user_conf.get('authentication', 'su_sudo', '')
if self.__authType != "su" and self.__authType != "sudo":
try:
self.__authType = AUTH_TYPES[distro_name]
if distro_name == 'fedora':
import platform
try:
ver = int(platform.dist()[1])
except AttributeError:
import distro
ver = int(distro.linux_distribution()[1])
if ver >= 28:
self.__authType = AUTH_TYPES['fedora28']
except KeyError:
log.warn("%s distro is not found in AUTH_TYPES" % distro_name)
self.__authType = 'su'
def __getPasswordDisplayString(self):
if self.__authType == "su":
return "Please enter the root/superuser password: "
else:
return "Please enter the sudoer (%s)'s password: " % os.getenv('USER')
def __changeAuthType(self):
if self.__authType == "sudo":
self.__authType = "su"
else:
self.__authType = "sudo"
user_conf.set('authentication', 'su_sudo', self.__authType)
def __get_password(self, pswd_msg=''):
if pswd_msg == '':
if self.__authType == "su":
pswd_msg = "Please enter the root/superuser password: "
else:
pswd_msg = "Please enter the sudoer (%s)'s password: " % os.getenv(
'USER')
return getpass.getpass(log.bold(pswd_msg))
def __get_password_ui(self, pswd_msg='', user="root"):
if pswd_msg == '':
pswd_msg = "Your HP Device requires to install HP proprietary plugin\nPlease enter root/superuser password to continue"
if self.__ui_toolkit == "qt3":
from ui.setupform import showPasswordUI
username, password = showPasswordUI(pswd_msg, user, False)
elif self.__ui_toolkit == "qt5":
from ui5.setupdialog import showPasswordUI
username, password = showPasswordUI(pswd_msg, user, False)
else: # self.__ui_toolkit == "qt4" --> default qt4
from ui4.setupdialog import showPasswordUI
username, password = showPasswordUI(pswd_msg, user, False)
if username == "" and password == "":
raise Exception("User Cancel")
return password
def __password_check(self, cmd, timeout=10):
import io
output = io.StringIO()
ok, ret = False, ''
try:
child = pexpect.spawnu(cmd, timeout=timeout)
except pexpect.ExceptionPexpect:
return 1, ''
try:
try:
start = time.time()
while True:
update_spinner()
i = child.expect(self.__expectList)
cb = child.before
if cb:
start = time.time()
output.write(cb)
if i == 0: # EOF
ok, ret = True, output.getvalue()
break
elif i == 1: # TIMEOUT
if('true' in cmd and self.__password_prompt_str == ""): # sudo true or su -c "true"
cb = cb.replace("[", "\[")
cb = cb.replace("]", "\]")
self.__password_prompt_str = cb
try:
p = re.compile(cb, re.I)
except TypeError:
self.__expectList.append(cb)
else:
self.__expectList.append(p)
log.debug(
"Adding missing password prompt string [%s]" % self.__password_prompt_str)
continue
else: # password
if(self.__password_prompt_str == ""):
self.__password_prompt_str = utils.EXPECT_WORD_LIST[
i]
log.debug(
"Updating password prompt string [%s]" % self.__password_prompt_str)
child.sendline(self.__password)
except (Exception, pexpect.ExceptionPexpect) as e:
log.exception()
finally:
cleanup_spinner()
try:
child.close()
except OSError:
pass
if ok:
return child.exitstatus, ret
else:
return 1, ''
def __validatePassword(self, pswd_msg):
x = 1
while True:
if self.__mode == INTERACTIVE_MODE:
self.__password = self.__get_password(pswd_msg)
else:
try:
if self.getAuthType() == 'su':
self.__password = self.__get_password_ui(
pswd_msg, "root")
else:
self.__password = self.__get_password_ui(
pswd_msg, os.getenv("USER"))
except Exception as ex:
log.debug(ex)
break
cmd = self.getAuthCmd() % "true"
log.debug(cmd)
status, output = self.__password_check(cmd)
log.debug("status = %s output=%s " % (status, output))
if self.__mode == GUI_MODE:
if self.__ui_toolkit == "qt4":
from ui4.setupdialog import FailureMessageUI
elif self.__ui_toolkit == "qt5":
from ui5.setupdialog import FailureMessageUI
elif self.__ui_toolkit == "qt3":
from ui.setupform import FailureMessageUI
if status == 0:
self.__passwordValidated = True
break
elif "not in the sudoers file" in output:
# TBD.. IF user doesn't have sudo permissions, needs to change
# to "su" type and query for password
self.__changeAuthType()
msg = "User doesn't have sudo permissions.\nChanging Authentication Type. Try again."
if self.__mode == GUI_MODE:
FailureMessageUI(msg)
else:
log.error(msg)
raise Exception("User is not in the sudoers file.")
else:
self.__password = ""
x += 1
if self.__mode == GUI_MODE:
if x > PASSWORD_RETRY_COUNT:
FailureMessageUI("Password incorrect. ")
return
else:
FailureMessageUI("Password incorrect. %d attempt(s) left." % (
PASSWORD_RETRY_COUNT + 1 - x))
else:
if x > PASSWORD_RETRY_COUNT:
log.error("Password incorrect. ")
return
else:
log.error("Password incorrect. %d attempt(s) left." % (
PASSWORD_RETRY_COUNT + 1 - x))
def __get_password_utils(self):
if self.__authType == "su":
AuthType, AuthCmd = 'su', 'su -c "%s"'
else:
AuthType, AuthCmd = 'sudo', 'sudo %s'
return AuthType, AuthCmd
def __get_password_utils_ui(self):
distro_name = get_distro_name().lower()
if self.__authType == "sudo":
AuthType, AuthCmd = 'sudo', 'sudo %s'
else:
AuthType, AuthCmd = 'su', 'su -c "%s"'
'''
if utils.which('kdesu'):
AuthType, AuthCmd = 'kdesu', 'kdesu -- %s'
elif utils.which('kdesudo'):
AuthType, AuthCmd = 'kdesudo', 'kdesudo -- %s'
elif utils.which('gnomesu'):
AuthType, AuthCmd = 'gnomesu', 'gnomesu -c "%s"'
elif utils.which('gksu'):
AuthType, AuthCmd = 'gksu' , 'gksu "%s"'
'''
return AuthType, AuthCmd
##################### Public functions ######################
def clearPassword(self):
log.debug("Clearing password...")
self.__password = ""
self.__passwordValidated = False
if self.__authType == 'sudo':
utils.run("sudo -K")
def getAuthType(self):
if self.__mode == INTERACTIVE_MODE:
retValue = self.__authType
else:
retValue, AuthCmd = self.__get_password_utils_ui()
return retValue
def getAuthCmd(self):
if self.__mode == INTERACTIVE_MODE:
AuthType, AuthCmd = self.__get_password_utils()
else:
AuthType, AuthCmd = self.__get_password_utils_ui()
return AuthCmd
def getPassword(self, pswd_msg='', psswd_queried_cnt=0):
if self.__passwordValidated:
return self.__password
if psswd_queried_cnt:
return self.__password
self.__validatePassword(pswd_msg)
return self.__password
def getPasswordPromptString(self):
return self.__password_prompt_str