[PATCH] Use SHA-512 by default for password encryption.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux