[PATCH] Allow users to select MD5, SHA256, or SHA512 for encryption.

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

 



Since glibc now has SHA-256 and SHA-512 support for crypt(3),
and the userspace tools like authconfig and libuser all support
it, we should offer users the option of which encoding algorithm
they want to user for passwords.

Via kickstart, users can use the following options for the auth
command:
    --enablemd5  -or-  --passalgo=md5      MD5
    --passalgo=sha256                      SHA-256
    --passalgo-sha512                      SHA-512

In the text and gtk user interfaces, the root password screen
now shows a combo box of some sort that lets users pick the
algorithm.  The default is MD5 since we've always done that.

All user accounts specified in the kickstart file as well as the
root password will be encrypted using the specified algorithm.
The /etc/libuser.conf file on the target system will have the
crypt_style setting modified based on the user's choice.  And
passwords in /etc/shadow will be much bigger if the user chooses
SHA-256 or SHA-512.
---
 instdata.py            |   68 +++++++---
 iw/account_gui.py      |  193 ++++++++++++--------------
 textw/userauth_text.py |  117 ++++++++++-------
 ui/account.glade       |  355 ++++++++++++++++++++++++++++++++++++++++++++++++
 ui/autopart.glade      |    2 -
 users.py               |   60 +++++---
 6 files changed, 599 insertions(+), 196 deletions(-)
 create mode 100644 ui/account.glade

diff --git a/instdata.py b/instdata.py
index b90af8d..5fde6d3 100644
--- a/instdata.py
+++ b/instdata.py
@@ -150,12 +150,40 @@ class InstallData:
     def setUpgrade (self, bool):
         self.upgrade = bool
 
-    def write(self):
-        if self.auth.find("--enablemd5"):
-            useMD5 = True
+    # Update the auth string to contain the correct password algorithm opts
+    # 'algo' can be any of 'md5', 'sha256', 'sha512'.  The empty string or
+    # None for algo gives md5.
+    def updatePassAlgo(self, algo):
+        newauth = ''
+
+        for arg in self.auth.lower().split(' '):
+            if arg != '--enablemd5' and arg != '--passalgo=md5' and \
+               arg != '--passalgo=sha256' and arg != '--passalgo=sha512':
+                newauth += ' ' + arg
+
+        if algo is None or algo == '':
+            algo = 'md5'
+
+        if algo != 'md5' and algo != 'sha256' and algo != 'sha512':
+            algo = 'md5'
+
+        newauth += ' --passalgo=%s' % (algo,)
+        self.auth = newauth.strip()
+
+    # 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 +203,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 +235,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 +277,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/iw/account_gui.py b/iw/account_gui.py
index c4eb334..2afb151 100644
--- a/iw/account_gui.py
+++ b/iw/account_gui.py
@@ -1,7 +1,8 @@
 #
-# account_gui.py: gui root password and user creation dialog
+# account_gui.py: gui root password and crypt algorithm dialog
 #
-# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007  Red Hat, Inc.
+# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,  Red Hat Inc.
+#               2006, 2007, 2008
 # All rights reserved.
 #
 # This program is free software; you can redistribute it and/or modify
@@ -19,34 +20,88 @@
 #
 
 import gtk
+import gobject
 import string
 import gui
 from iw_gui import *
-from rhpl.translate import _, N_
+from rhpl.translate import _
 from flags import flags
 import cracklib
 
-def handleCapsLockRelease(window, event, label):
-    if event.keyval == gtk.keysyms.Caps_Lock and event.state & gtk.gdk.LOCK_MASK:
-        if label.get_text() == "":
-            label.set_text(_("<b>Caps Lock is on.</b>"))
-            label.set_use_markup(True)
-        else:
-            label.set_text("")
-
 class AccountWindow (InstallWindow):
+    def getScreen(self, anaconda):
+        self.anaconda = anaconda
+        self.rootPassword = anaconda.id.rootPassword
+        self.intf = anaconda.intf
+
+        (self.xml, self.align) = gui.getGladeWidget("account.glade",
+                                                    "account_align")
+        self.icon = self.xml.get_widget("icon")
+        self.capslock = self.xml.get_widget("capslock")
+        self.pwlabel = self.xml.get_widget("pwlabel")
+        self.pw = self.xml.get_widget("pw")
+        self.confirmlabel = self.xml.get_widget("confirmlabel")
+        self.confirm = self.xml.get_widget("confirm")
+        self.algorithms = self.xml.get_widget("algorithms")
+
+        # load the icon
+        gui.readImageFromFile("root-password.png", image=self.icon)
+
+        # populate encoding algorithm combo box
+        store = gtk.ListStore(gobject.TYPE_STRING)
+        cell = gtk.CellRendererText()
+        self.algorithms.set_model(store)
+        self.algorithms.pack_start(cell, True)
+        self.algorithms.set_attributes(cell, text=0)
+
+        self.algorithms.append_text("MD5")
+        self.algorithms.append_text("SHA-256")
+        self.algorithms.append_text("SHA-512")
+
+        # connect hotkeys
+        self.pwlabel.set_text_with_mnemonic(_("Root _Password:"))
+        self.pwlabel.set_mnemonic_widget(self.pw)
+        self.confirmlabel.set_text_with_mnemonic(_("_Confirm:"))
+        self.confirmlabel.set_mnemonic_widget(self.confirm)
+
+        # watch for Caps Lock so we can warn the user
+        self.intf.icw.window.connect("key-release-event",
+            lambda w, e: self.handleCapsLockRelease(w, e, self.capslock))
+
+        # we might have a root password already
+        if not self.rootPassword['isCrypted']:
+            self.pw.set_text(self.rootPassword['password'])
+            self.confirm.set_text(self.rootPassword['password'])
+
+        return self.align
+
+    def passwordError(self):
+        self.pw.set_text("")
+        self.confirm.set_text("")
+        self.pw.grab_focus()
+        raise gui.StayOnScreen
+
+    def handleCapsLockRelease(self, window, event, label):
+        if event.keyval == gtk.keysyms.Caps_Lock and \
+           event.state & gtk.gdk.LOCK_MASK:
+            if label.get_text() == "":
+                label.set_text("<b>" + _("Caps Lock is on.") + "</b>")
+                label.set_use_markup(True)
+            else:
+                label.set_text("")
+
+    def getSelectedAlgo(self):
+        model = self.algorithms.get_model()
+        active = self.algorithms.get_active()
+
+        if active < 0:
+            algo = "md5"
+        else:
+            algo = model[active][0].lower().replace('-', '')
 
-    windowTitle = N_("Set Root Password")
+        return algo
 
     def getNext (self):
-        def passwordError():
-            self.pw.set_text("")
-            self.confirm.set_text("")
-            self.pw.grab_focus()            
-            raise gui.StayOnScreen
-            
-	if not self.__dict__.has_key("pw"): return None
-
         pw = self.pw.get_text()
         confirm = self.confirm.get_text()
 
@@ -56,119 +111,45 @@ class AccountWindow (InstallWindow):
                                       "and confirm it by typing it a second "
                                       "time to continue."),
                                     custom_icon="error")
-            passwordError()
+            self.passwordError()
 
         if pw != confirm:
             self.intf.messageWindow(_("Error with Password"),
                                     _("The passwords you entered were "
                                       "different.  Please try again."),
                                     custom_icon="error")
-            passwordError()
+            self.passwordError()
 
         if len(pw) < 6:
             self.intf.messageWindow(_("Error with Password"),
                                     _("The root password must be at least "
                                       "six characters long."),
                                     custom_icon="error")
-            passwordError()
+            self.passwordError()
 
         msg = cracklib.FascistCheck(pw)
         if msg is not None:
             ret = self.intf.messageWindow(_("Weak Password"),
                                           _("Weak password provided: %s"
                                             "\n\n"
-                                            "Would you like to continue with this "
-                                            "password?" % (msg, )),
+                                            "Would you like to continue with "
+                                            "this password?" % (msg, )),
                                           type = "yesno")
             if ret == 0:
-                passwordError()
-        
-        allowed = string.digits + string.ascii_letters + string.punctuation + " "
+                self.passwordError()
+
+        legal = string.digits + string.ascii_letters + string.punctuation + " "
         for letter in pw:
-            if letter not in allowed:
+            if letter not in legal:
                 self.intf.messageWindow(_("Error with Password"),
                                         _("Requested password contains "
                                           "non-ASCII characters, which are "
                                           "not allowed."),
                                         custom_icon="error")
-                passwordError()
+                self.passwordError()
 
         self.rootPassword["password"] = self.pw.get_text()
         self.rootPassword["isCrypted"] = False
-        return None
-
-    def setFocus (self, area, data):
-        self.pw.grab_focus ()
-
-    # AccountWindow tag="accts"
-    def getScreen (self, anaconda):
-	self.rootPassword = anaconda.id.rootPassword
-        self.intf = anaconda.intf
+        self.anaconda.id.updatePassAlgo(self.getSelectedAlgo())
 
-        self.capsLabel = gtk.Label()
-        self.capsLabel.set_alignment(0.0, 0.5)
-
-        self.intf.icw.window.connect("key-release-event",
-                                     lambda w, e: handleCapsLockRelease(w, e, self.capsLabel))
-
-	self.passwords = {}
-
-        box = gtk.VBox ()
-        box.set_border_width(5)
-
-        hbox = gtk.HBox()
-        pix = gui.readImageFromFile ("root-password.png")
-        if pix:
-            hbox.pack_start (pix, False)
-
-        label = gui.WrappingLabel (_("The root account is used for "
-                                     "administering the system.  Enter "
-                                     "a password for the root user."))
-        label.set_line_wrap(True)
-        label.set_size_request(350, -1)
-        label.set_alignment(0.0, 0.5)
-        hbox.pack_start(label, False)
-
-        box.pack_start(hbox, False)
-       
-        table = gtk.Table (3, 2)
-        table.set_size_request(365, -1)
-        table.set_row_spacings (5)
-	table.set_col_spacings (5)
-
-        pass1 = gui.MnemonicLabel (_("Root _Password: "))
-        pass1.set_alignment (0.0, 0.5)
-        table.attach (pass1, 0, 1, 0, 1, gtk.FILL, 0, 10)
-        pass2 = gui.MnemonicLabel (_("_Confirm: "))
-        pass2.set_alignment (0.0, 0.5)
-        table.attach (pass2, 0, 1, 1, 2, gtk.FILL, 0, 10)
-        self.pw = gtk.Entry (128)
-        pass1.set_mnemonic_widget(self.pw)
-        
-        self.pw.connect ("activate", lambda widget, box=box: box.emit("focus", gtk.DIR_TAB_FORWARD))
-        self.pw.connect ("map-event", self.setFocus)
-        self.pw.set_visibility (False)
-        self.confirm = gtk.Entry (128)
-        pass2.set_mnemonic_widget(self.confirm)
-        self.confirm.connect ("activate", lambda widget, box=box: self.ics.setGrabNext(1))
-        self.confirm.set_visibility (False)
-        table.attach (self.pw,        1, 2, 0, 1, gtk.FILL|gtk.EXPAND, 5)
-        table.attach (self.confirm,   1, 2, 1, 2, gtk.FILL|gtk.EXPAND, 5)
-        table.attach (self.capsLabel, 1, 2, 2, 3, gtk.FILL|gtk.EXPAND, 5)
-
-        hbox = gtk.HBox()
-        hbox.pack_start(table, False)
-
-        box.pack_start (hbox, False)
-
-        # root password statusbar
-        self.rootStatus = gtk.Label ("")
-        wrapper = gtk.HBox(0, False)
-        wrapper.pack_start (self.rootStatus)
-        box.pack_start (wrapper, False)
-
-        if not self.rootPassword["isCrypted"]:
-	    self.pw.set_text(self.rootPassword["password"])
-	    self.confirm.set_text(self.rootPassword["password"])
-
-        return box
+        return None
diff --git a/textw/userauth_text.py b/textw/userauth_text.py
index 81331d5..b359782 100644
--- a/textw/userauth_text.py
+++ b/textw/userauth_text.py
@@ -1,7 +1,7 @@
 #
 # userauth_text.py: text mode authentication setup dialogs
 #
-# Copyright (C) 2000, 2001, 2002  Red Hat, Inc.  All rights reserved.
+# Copyright (C) 2000, 2001, 2002, 2008  Red Hat, Inc.  All rights reserved.
 #
 # 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
@@ -22,79 +22,100 @@ from constants_text import *
 from rhpl.translate import _
 import cracklib
 
-def has_bad_chars(pw):
-    allowed = string.digits + string.ascii_letters + string.punctuation + " "
-    for letter in pw:
-        if letter not in allowed:
-            return 1
-    return 0
-
 class RootPasswordWindow:
     def __call__ (self, screen, anaconda):
-        toplevel = GridFormHelp (screen, _("Root Password"), "rootpw", 1, 3)
+        toplevel = GridFormHelp(screen, _("Root Password"), "rootpw", 1, 6)
+
+        toplevel.add(TextboxReflowed(55,
+                                     _("Pick a root password. You must "
+                                       "type it twice to ensure you know "
+                                       "it and do not make a typing "
+                                       "mistake. ")),
+                     0, 0, (0, 0, 0, 1))
+
+        algogrid = Grid(1, 4)
+        algogroup = RadioGroup()
+
+        algogrid.setField(TextboxReflowed(55,
+                                          _("Select default system password "
+                                            "encoding algorithm:")),
+                          0, 0, (0, 0, 0, 1))
+        md5Cb = algogroup.add(_("MD5"), "md5", True)
+        algogrid.setField(md5Cb, 0, 1, growx=1, anchorLeft=1)
 
-        toplevel.add (TextboxReflowed(37, _("Pick a root password. You must "
-				"type it twice to ensure you know "
-				"it and do not make a typing mistake. "
-				"Remember that the "
-				"root password is a critical part "
-				"of system security!")), 0, 0, (0, 0, 0, 1))
+        sha256Cb = algogroup.add(_("SHA-256"), "sha256", False)
+        algogrid.setField(sha256Cb, 0, 2, growx=1, anchorLeft=1)
+
+        sha512Cb = algogroup.add(_("SHA-512"), "sha512", False)
+        algogrid.setField(sha512Cb, 0, 3, growx=1, anchorLeft=1)
+
+        toplevel.add(algogrid, 0, 1, (0, 0, 0, 1))
 
         if anaconda.id.rootPassword["isCrypted"]:
             anaconda.id.rootPassword["password"] = ""
 
-        entry1 = Entry (24, password = 1, text = anaconda.id.rootPassword["password"])
-        entry2 = Entry (24, password = 1, text = anaconda.id.rootPassword["password"])
-        passgrid = Grid (2, 2)
-        passgrid.setField (Label (_("Password:")), 0, 0, (0, 0, 1, 0), anchorLeft = 1)
-        passgrid.setField (Label (_("Password (confirm):")), 0, 1, (0, 0, 1, 0), anchorLeft = 1)
-        passgrid.setField (entry1, 1, 0)
-        passgrid.setField (entry2, 1, 1)
-        toplevel.add (passgrid, 0, 1, (0, 0, 0, 1))
-        
-        bb = ButtonBar (screen, (TEXT_OK_BUTTON, TEXT_BACK_BUTTON))
-        toplevel.add (bb, 0, 2, growx = 1)
+        entry1 = Entry(24, password=1,
+                       text=anaconda.id.rootPassword["password"])
+        entry2 = Entry(24, password=1,
+                       text=anaconda.id.rootPassword["password"])
+        passgrid = Grid(2, 2)
+        passgrid.setField(Label(_("Password:")), 0, 0, (0, 0, 1, 0),
+                          anchorLeft=1)
+        passgrid.setField(Label(_("Password (confirm):")), 0, 1, (0, 0, 1, 0),
+                          anchorLeft=1)
+        passgrid.setField(entry1, 1, 0)
+        passgrid.setField(entry2, 1, 1)
+        toplevel.add(passgrid, 0, 2, (0, 0, 0, 1))
+
+        bb = ButtonBar(screen, (TEXT_OK_BUTTON, TEXT_BACK_BUTTON))
+        toplevel.add(bb, 0, 3, growx = 1)
 
         while 1:
-            toplevel.setCurrent (entry1)
-            result = toplevel.run ()
-            rc = bb.buttonPressed (result)
+            toplevel.setCurrent(entry1)
+            result = toplevel.run()
+            rc = bb.buttonPressed(result)
             if rc == TEXT_BACK_CHECK:
                 screen.popWindow()
                 return INSTALL_BACK
-            if len (entry1.value ()) < 6:
+            if len(entry1.value()) < 6:
                 ButtonChoiceWindow(screen, _("Password Length"),
-		       _("The root password must be at least 6 characters "
-			 "long."),
-		       buttons = [ TEXT_OK_BUTTON ], width = 50)
-            elif entry1.value () != entry2.value ():
+                    _("The root password must be at least 6 characters long."),
+                    buttons = [ TEXT_OK_BUTTON ], width = 50)
+            elif entry1.value() != entry2.value():
                 ButtonChoiceWindow(screen, _("Password Mismatch"),
-		       _("The passwords you entered were different. Please "
-			 "try again."),
-		       buttons = [ TEXT_OK_BUTTON ], width = 50)
-            elif has_bad_chars(entry1.value()):
+                    _("The passwords you entered were different. Please "
+                      "try again."), buttons = [ TEXT_OK_BUTTON ], width = 50)
+            elif self.hasBadChars(entry1.value()):
                 ButtonChoiceWindow(screen, _("Error with Password"),
-		       _("Requested password contains non-ASCII characters, "
-                         "which are not allowed."),
-		       buttons = [ TEXT_OK_BUTTON ], width = 50)
+                    _("Requested password contains non-ASCII characters, "
+                      "which are not allowed."),
+                    buttons = [ TEXT_OK_BUTTON ], width = 50)
             else:
                 msg = cracklib.FascistCheck(entry1.value())
                 if msg is not None:
                     ret = anaconda.intf.messageWindow(_("Weak Password"),
-                                                  _("Weak password provided: %s"
-                                                    "\n\n"
-                                                    "Would you like to continue with this "
-                                                    "password?" % (msg, )),
-                                                  type = "yesno", default="no")
+                             _("Weak password provided: %s\n\n"
+                               "Would you like to continue with this password?"
+                               % (msg, )),
+                             type = "yesno", default="no")
                     if ret == 1:
                         break
                 else:
                     break
 
-            entry1.set ("")
-            entry2.set ("")
+            entry1.set("")
+            entry2.set("")
 
         screen.popWindow()
         anaconda.id.rootPassword["password"] = entry1.value()
         anaconda.id.rootPassword["isCrypted"] = False
+        anaconda.id.updatePassAlgo(algogroup.getSelection())
         return INSTALL_OK
+
+    def hasBadChars(self, pw):
+        allowed = string.digits + string.ascii_letters + \
+                  string.punctuation + " "
+        for letter in pw:
+            if letter not in allowed:
+                return True
+        return False
diff --git a/ui/account.glade b/ui/account.glade
new file mode 100644
index 0000000..cd394d1
--- /dev/null
+++ b/ui/account.glade
@@ -0,0 +1,355 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd";>
+
+<glade-interface>
+
+<widget class="GtkWindow" id="account_window">
+  <property name="border_width">18</property>
+  <property name="title" translatable="yes" context="yes"></property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <property name="focus_on_map">True</property>
+  <property name="urgency_hint">False</property>
+
+  <child>
+    <widget class="GtkAlignment" id="account_align">
+      <property name="width_request">400</property>
+      <property name="visible">True</property>
+      <property name="xalign">0</property>
+      <property name="yalign">0</property>
+      <property name="xscale">1</property>
+      <property name="yscale">1</property>
+      <property name="top_padding">0</property>
+      <property name="bottom_padding">0</property>
+      <property name="left_padding">0</property>
+      <property name="right_padding">0</property>
+
+      <child>
+	<widget class="GtkVBox" id="account_box">
+	  <property name="border_width">5</property>
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">10</property>
+
+	  <child>
+	    <widget class="GtkAlignment" id="alignment2">
+	      <property name="visible">True</property>
+	      <property name="xalign">0</property>
+	      <property name="yalign">0</property>
+	      <property name="xscale">1</property>
+	      <property name="yscale">1</property>
+	      <property name="top_padding">0</property>
+	      <property name="bottom_padding">0</property>
+	      <property name="left_padding">0</property>
+	      <property name="right_padding">0</property>
+
+	      <child>
+		<widget class="GtkHBox" id="desc_box">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkImage" id="icon">
+		      <property name="visible">True</property>
+		      <property name="pixbuf">root-password.png</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="desc">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">The root account is used for administering the system.  Enter a password for the root user.</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">True</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkAlignment" id="alignment3">
+	      <property name="visible">True</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xscale">1</property>
+	      <property name="yscale">1</property>
+	      <property name="top_padding">0</property>
+	      <property name="bottom_padding">0</property>
+	      <property name="left_padding">0</property>
+	      <property name="right_padding">0</property>
+
+	      <child>
+		<widget class="GtkVBox" id="algovbox">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="label2">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Select default system password encoding algorithm:</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">True</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkAlignment" id="alignment5">
+		      <property name="visible">True</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xscale">1</property>
+		      <property name="yscale">1</property>
+		      <property name="top_padding">0</property>
+		      <property name="bottom_padding">0</property>
+		      <property name="left_padding">40</property>
+		      <property name="right_padding">600</property>
+
+		      <child>
+			<widget class="GtkComboBox" id="algorithms">
+			  <property name="visible">True</property>
+			  <property name="add_tearoffs">False</property>
+			  <property name="focus_on_click">True</property>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkAlignment" id="alignment4">
+	      <property name="visible">True</property>
+	      <property name="xalign">0.5</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xscale">1</property>
+	      <property name="yscale">1</property>
+	      <property name="top_padding">0</property>
+	      <property name="bottom_padding">0</property>
+	      <property name="left_padding">0</property>
+	      <property name="right_padding">0</property>
+
+	      <child>
+		<widget class="GtkTable" id="table1">
+		  <property name="width_request">365</property>
+		  <property name="visible">True</property>
+		  <property name="n_rows">3</property>
+		  <property name="n_columns">2</property>
+		  <property name="homogeneous">False</property>
+		  <property name="row_spacing">5</property>
+		  <property name="column_spacing">5</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="pwlabel">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Root Password:</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">True</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">0</property>
+		      <property name="bottom_attach">1</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="confirmlabel">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Confirm:</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">True</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">1</property>
+		      <property name="bottom_attach">2</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="capslock">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes"></property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">True</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">2</property>
+		      <property name="top_attach">2</property>
+		      <property name="bottom_attach">3</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="pw">
+		      <property name="width_request">256</property>
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">False</property>
+		      <property name="max_length">0</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char">â?¢</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">2</property>
+		      <property name="top_attach">0</property>
+		      <property name="bottom_attach">1</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="confirm">
+		      <property name="width_request">256</property>
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">False</property>
+		      <property name="max_length">0</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char">â?¢</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">2</property>
+		      <property name="top_attach">1</property>
+		      <property name="bottom_attach">2</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+		</widget>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+	</widget>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/ui/autopart.glade b/ui/autopart.glade
index f607a43..3e20709 100644
--- a/ui/autopart.glade
+++ b/ui/autopart.glade
@@ -9,8 +9,6 @@
   <property name="type">GTK_WINDOW_TOPLEVEL</property>
   <property name="window_position">GTK_WIN_POS_NONE</property>
   <property name="modal">False</property>
-  <property name="default_width">440</property>
-  <property name="default_height">250</property>
   <property name="resizable">True</property>
   <property name="destroy_with_parent">False</property>
   <property name="decorated">True</property>
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