Encode passwords using SHA-512 by default. Users can override this in a Kickstart file using the 'auth' command. The options below determine the algorithm used: --enablemd5 -or- --passalgo=md5 MD5 --passalgo=sha256 SHA-256 --passalgo=sha512 SHA-512 The previous default was MD5. glibc now supports SHA-256 and SHA-512, so we are using the strongest of those choices by default now. --- instdata.py | 50 +++++++++++++++++++++++++++++++----------------- users.py | 60 ++++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 69 insertions(+), 41 deletions(-) diff --git a/instdata.py b/instdata.py index b90af8d..e1175f2 100644 --- a/instdata.py +++ b/instdata.py @@ -72,7 +72,7 @@ class InstallData: self.timezone.setTimezoneInfo(self.instLanguage.getDefaultTimeZone()) self.users = None self.rootPassword = { "isCrypted": False, "password": "", "lock": False } - self.auth = "--enableshadow --enablemd5" + self.auth = "--enableshadow --passalgo=sha512" self.desktop = desktop.Desktop() self.upgrade = None if flags.cmdline.has_key("doupgrade"): @@ -150,12 +150,20 @@ class InstallData: def setUpgrade (self, bool): self.upgrade = bool - def write(self): - if self.auth.find("--enablemd5"): - useMD5 = True + # Reads the auth string and returns a string indicating our desired + # password encoding algorithm. + def getPassAlgo(self): + if self.auth.find("--enablemd5") != -1 or \ + self.auth.find("--passalgo=md5") != -1: + return 'md5' + elif self.auth.find("--passalgo=sha256") != -1: + return 'sha256' + elif self.auth.find("--passalgo=sha512") != -1: + return 'sha512' else: - useMD5 = False + return None + def write(self): self.instLanguage.write (self.anaconda.rootPath) if not self.isHeadless: @@ -175,16 +183,21 @@ class InstallData: except RuntimeError, msg: log.error("Error running %s: %s", args, msg) - self.network.write (self.anaconda.rootPath) - self.firewall.write (self.anaconda.rootPath) + self.network.write (self.anaconda.rootPath) + self.firewall.write (self.anaconda.rootPath) self.security.write (self.anaconda.rootPath) self.users = users.Users() + # make sure crypt_style in libuser.conf matches the salt we're using + users.createLuserConf(self.anaconda.rootPath, + algoname=self.getPassAlgo()) + # User should already exist, just without a password. self.users.setRootPassword(self.rootPassword["password"], - self.rootPassword["isCrypted"], useMD5, - self.rootPassword["lock"]) + self.rootPassword["isCrypted"], + self.rootPassword["lock"], + algo=self.getPassAlgo()) self.users.reset() @@ -202,19 +215,20 @@ class InstallData: root=self.anaconda.rootPath) for ud in self.ksdata.user.userList: - if not self.users.createUser(ud.name, ud.password, ud.isCrypted, - ud.groups, ud.homedir, ud.shell, - ud.uid, ud.lock, + if not self.users.createUser(name=ud.name, + password=ud.password, + isCrypted=ud.isCrypted, + groups=ud.groups, + homedir=ud.homedir, + shell=ud.shell, + uid=ud.uid, + algo=self.getPassAlgo(), + lock=ud.lock, root=self.anaconda.rootPath): log.error("User %s already exists, not creating." % ud.name) def writeKS(self, filename): - if self.auth.find("--enablemd5"): - useMD5 = True - else: - useMD5 = False - f = open(filename, "w") f.write("# Kickstart file automatically generated by anaconda.\n\n") @@ -243,7 +257,7 @@ class InstallData: if self.rootPassword["isCrypted"]: args = " --iscrypted %s" % self.rootPassword["password"] else: - args = " --iscrypted %s" % users.cryptPassword(self.rootPassword["password"], useMD5) + args = " --iscrypted %s" % users.cryptPassword(self.rootPassword["password"], algo=self.getPassAlgo()) if self.rootPassword["lock"]: args += " --lock" diff --git a/users.py b/users.py index fe5751f..799fa12 100644 --- a/users.py +++ b/users.py @@ -30,39 +30,51 @@ import os.path import logging log = logging.getLogger("anaconda") -def createLuserConf(instPath): +def createLuserConf(instPath, algoname='md5'): """Writes a libuser.conf for instPath.""" - (fd, fn) = tempfile.mkstemp(prefix="libuser.") + if os.getenv("LIBUSER_CONF") and \ + os.access(os.environ["LIBUSER_CONF"], os.R_OK): + fn = os.environ["LIBUSER_CONF"] + fd = open(fn, 'w') + else: + (fp, fn) = tempfile.mkstemp(prefix="libuser.") + fd = os.fdopen(fp, 'w') + buf = """ [defaults] skeleton = %(instPath)s/etc/skel mailspooldir = %(instPath)s/var/mail -crypt_style = md5 +crypt_style = %(algo)s modules = files shadow create_modules = files shadow [files] directory = %(instPath)s/etc [shadow] directory = %(instPath)s/etc -""" % {"instPath": instPath} - os.write(fd, buf) - os.close(fd) +""" % {"instPath": instPath, "algo": algoname} + fd.write(buf) + fd.close() os.environ["LIBUSER_CONF"] = fn -def cryptPassword(password, useMD5): - if useMD5: - salt = "$1$" - saltLen = 8 - else: - salt = "" - saltLen = 2 +# These are explained in crypt/crypt-entry.c in glibc's code. The prefixes +# we use for the different crypt salts: +# $1$ MD5 +# $5$ SHA256 +# $6$ SHA512 +def cryptPassword(password, algo=None): + salts = {'md5': '$1$', 'sha256': '$5$', 'sha512': '$6$', None: ''} + saltstr = salts[algo] + saltlen = 2 + + if algo == 'md5' or algo == 'sha256' or algo == 'sha512': + saltlen = 16 - for i in range(saltLen): - salt = salt + random.choice (string.letters + - string.digits + './') + for i in range(saltlen): + saltstr = saltstr + random.choice (string.letters + + string.digits + './') - return crypt.crypt (password, salt) + return crypt.crypt (password, saltstr) class Users: def __init__ (self): @@ -72,8 +84,8 @@ class Users: os.unsetenv("LIBUSER_CONF") self.admin = libuser.admin() - def createUser (self, name, password=None, isCrypted=False, groups=[], - homedir=None, shell=None, uid=None, lock=False, + def createUser (self, name=None, password=None, isCrypted=False, groups=[], + homedir=None, shell=None, uid=None, algo=None, lock=False, root="/mnt/sysimage"): childpid = os.fork() @@ -108,9 +120,11 @@ class Users: if password: if isCrypted: - self.admin.setpassUser(userEnt, password, isCrypted) + self.admin.setpassUser(userEnt, password, True) else: - self.admin.setpassUser(userEnt, cryptPassword(password, True), isCrypted) + self.admin.setpassUser(userEnt, + cryptPassword(password, algo=algo), + True) if lock: self.admin.lockUser(userEnt) @@ -136,13 +150,13 @@ class Users: else: return False - def setRootPassword(self, password, isCrypted, useMD5, lock): + def setRootPassword(self, password, isCrypted, lock, algo=None): rootUser = self.admin.lookupUserByName("root") if isCrypted: self.admin.setpassUser(rootUser, password, True) else: - self.admin.setpassUser(rootUser, cryptPassword(password, useMD5), True) + self.admin.setpassUser(rootUser, cryptPassword(password, algo=algo), True) if lock: self.admin.lockUser(rootUser) -- 1.5.4.1 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list