qubes-installer-qubes-os/firstboot/modules/create_user.py
2011-04-05 19:17:36 +02:00

332 lines
12 KiB
Python

#
# Chris Lumens <clumens@redhat.com>
#
# Copyright 2008 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use, modify,
# copy, or redistribute it subject to the terms and conditions of the GNU
# General Public License v.2. This program is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
# implied warranties 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., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
# trademarks that are incorporated in the source code or documentation are not
# subject to the GNU General Public License and may only be used or replicated
# with the express permission of Red Hat, Inc.
#
import gtk
import libuser
import os, string, sys, time
import os.path
from firstboot.config import *
from firstboot.constants import *
from firstboot.functions import *
from firstboot.module import *
import gettext
_ = lambda x: gettext.ldgettext("firstboot", x)
N_ = lambda x: x
sys.path.append("/usr/share/system-config-users")
import userGroupCheck
class moduleClass(Module):
def __init__(self):
Module.__init__(self)
self.priority = 100
self.sidebarTitle = N_("Create User")
self.title = N_("Create User")
self.icon = "create-user.png"
self.admin = libuser.admin()
self.nisFlag = None
self._problemFiles = []
self._count = 0
def _chown(self, arg, dirname, names):
for n in names:
try:
os.lchown("%s/%s" % (dirname, n), arg[0], arg[1])
# Update the UI from time to time, but not so often as to
# really slow down the chown.
self._count += 1
if self._count % 100 == 0:
while gtk.events_pending():
gtk.main_iteration(False)
except:
self._problemFiles.append("%s/%s" % (dirname, n))
def apply(self, interface, testing=False):
if testing:
return RESULT_SUCCESS
username = self.usernameEntry.get_text()
username = string.strip(username)
if username == "" and self.nisFlag:
# If they've run authconfig, don't pop up messageDialog
return RESULT_SUCCESS
if username == "":
# Only allow not creating a user if there is at least
# one non-system account already on the system
if self.admin.getFirstUnusedUid() > 500:
return RESULT_SUCCESS
else:
self._showErrorMessage(_("You must create a user account for this system."))
self.usernameEntry.grab_focus()
return RESULT_FAILURE
if not userGroupCheck.isUsernameOk(username, self.usernameEntry):
return RESULT_FAILURE
password = self.passwordEntry.get_text()
confirm = self.confirmEntry.get_text()
if not password or not confirm:
self._showErrorMessage(_("You must enter and confirm a password for this user."))
self.passwordEntry.set_text("")
self.confirmEntry.set_text("")
self.passwordEntry.grab_focus()
return RESULT_FAILURE
if password != confirm:
self._showErrorMessage(_("The passwords do not match. Please enter "
"the password again."))
self.passwordEntry.set_text("")
self.confirmEntry.set_text("")
self.passwordEntry.grab_focus()
return RESULT_FAILURE
elif not userGroupCheck.isPasswordOk(password, self.passwordEntry):
return RESULT_FAILURE
user = self.admin.lookupUserByName(username)
if user != None and user.get(libuser.UIDNUMBER)[0] < 500:
self._showErrorMessage(_("The username '%s' is a reserved system "
"account. Please specify another username."
% username))
self.usernameEntry.set_text("")
self.usernameEntry.grab_focus()
return RESULT_FAILURE
fullName = self.fullnameEntry.get_text()
# Check for valid strings
if not userGroupCheck.isNameOk(fullName, self.fullnameEntry):
return RESULT_FAILURE
# If a home directory for the user already exists, offer to reuse it
# for the new user.
try:
os.stat("/home/%s" % username)
dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO,
_("A home directory for user %s already exists. "
"Would you like to continue, making the new "
"user the owner of this directory and all its "
"contents? Doing so may take a while to reset "
"permissions and any SELinux labels. Would "
"you like to reuse this home directory? If "
"not, please choose a different username.") % username)
dlg.set_position(gtk.WIN_POS_CENTER)
dlg.set_modal(True)
rc = dlg.run()
dlg.destroy()
if rc == gtk.RESPONSE_NO:
self.usernameEntry.set_text("")
self.usernameEntry.grab_focus()
return RESULT_FAILURE
mkhomedir = False
except:
mkhomedir = True
# If we get to this point, all the input seems to be valid.
# Let's add the user.
if user == None:
#if the user doesn't already exist
userEnt = self.admin.initUser(username)
else:
userEnt = user
userEnt.set(libuser.GECOS, [fullName])
uidNumber = userEnt.get(libuser.UIDNUMBER)[0]
groupEnt = self.admin.initGroup(username)
gidNumber = groupEnt.get(libuser.GIDNUMBER)[0]
userEnt.set(libuser.GIDNUMBER, [gidNumber])
if user == None:
self.admin.addUser(userEnt, mkhomedir=mkhomedir)
self.admin.addGroup(groupEnt)
if not mkhomedir:
self._problemFiles = []
dlg = self._waitWindow(_("Fixing attributes on the home directory "
"for %s. This may take a few minutes.") % username)
dlg.show_all()
while gtk.events_pending():
gtk.main_iteration(False)
os.chown("/home/%s" % username, uidNumber, gidNumber)
os.path.walk("/home/%s" % username, self._chown, (uidNumber, gidNumber))
dlg.destroy()
if len(self._problemFiles) > 0:
import tempfile
(fd, path) = tempfile.mkstemp("", "firstboot-homedir-", "/tmp")
fo = os.fdopen(fd, "w")
for f in self._problemFiles:
fo.write("%s\n" % f)
fo.close()
text = _("Problems were encountered fixing the attributes on "
"some files in the home directory for %s. Please refer "
"to %s for which files caused the errors.") % (username, path)
self._showErrorMessage(text)
else:
self.admin.modifyUser(userEnt)
self.admin.modifyGroup(groupEnt)
os.chown(userEnt.get(libuser.HOMEDIRECTORY)[0],
userEnt.get(libuser.UIDNUMBER)[0],
userEnt.get(libuser.GIDNUMBER)[0])
self.admin.setpassUser(userEnt, self.passwordEntry.get_text(), 0)
os.system("usermod -a -G qubes %s" % username)
return RESULT_SUCCESS
def createScreen(self):
self.vbox = gtk.VBox(spacing=10)
label = gtk.Label(_("You must create a 'user' account.\n\n"
"In practice this is used only for locking your screen (via screensaver and KDM). This account is not accessible from the"
"network in any way (because there is no networking in the VM where the GUI runs and where you log in)"))
label.set_line_wrap(True)
label.set_alignment(0.0, 0.5)
label.set_size_request(500, -1)
self.usernameEntry = gtk.Entry()
self.fullnameEntry = gtk.Entry()
self.passwordEntry = gtk.Entry()
self.passwordEntry.set_visibility(False)
self.confirmEntry = gtk.Entry()
self.confirmEntry.set_visibility(False)
self.vbox.pack_start(label, False, True)
table = gtk.Table(2, 4)
table.set_row_spacings(6)
table.set_col_spacings(6)
label = gtk.Label(_("_Username:"))
label.set_use_underline(True)
label.set_mnemonic_widget(self.usernameEntry)
label.set_alignment(0.0, 0.5)
table.attach(label, 0, 1, 0, 1, gtk.FILL)
table.attach(self.usernameEntry, 1, 2, 0, 1, gtk.SHRINK, gtk.FILL, 5)
label = gtk.Label(_("Full Nam_e:"))
label.set_use_underline(True)
label.set_mnemonic_widget(self.fullnameEntry)
label.set_alignment(0.0, 0.5)
table.attach(label, 0, 1, 1, 2, gtk.FILL)
table.attach(self.fullnameEntry, 1, 2, 1, 2, gtk.SHRINK, gtk.FILL, 5)
label = gtk.Label(_("_Password:"))
label.set_use_underline(True)
label.set_mnemonic_widget(self.passwordEntry)
label.set_alignment(0.0, 0.5)
table.attach(label, 0, 1, 2, 3, gtk.FILL)
table.attach(self.passwordEntry, 1, 2, 2, 3, gtk.SHRINK, gtk.FILL, 5)
label = gtk.Label(_("Confir_m Password:"))
label.set_use_underline(True)
label.set_mnemonic_widget(self.confirmEntry)
label.set_alignment(0.0, 0.5)
table.attach(label, 0, 1, 3, 4, gtk.FILL)
table.attach(self.confirmEntry, 1, 2, 3, 4, gtk.SHRINK, gtk.FILL, 5)
self.vbox.pack_start(table, False)
# label = gtk.Label(_("If you need to use network authentication, such as Kerberos or NIS, "
# "please click the Use Network Login button."))
#
# label.set_line_wrap(True)
# label.set_alignment(0.0, 0.5)
# label.set_size_request(500, -1)
# self.vbox.pack_start(label, False, True, padding=20)
#
# authHBox = gtk.HBox()
# authButton = gtk.Button(_("Use Network _Login..."))
# authButton.connect("clicked", self._runAuthconfig)
# align = gtk.Alignment()
# align.add(authButton)
# align.set(0.0, 0.5, 0.0, 1.0)
# authHBox.pack_start(align, True)
# self.vbox.pack_start(authHBox, False, False)
def focus(self):
self.usernameEntry.grab_focus()
def initializeUI(self):
pass
def _runAuthconfig(self, *args):
self.nisFlag = 1
# Create a gtkInvisible to block until authconfig is done.
i = gtk.Invisible()
i.grab_add()
pid = start_process("/usr/bin/authconfig-gtk", "--firstboot")
while True:
while gtk.events_pending():
gtk.main_iteration_do()
child_pid, status = os.waitpid(pid, os.WNOHANG)
if child_pid == pid:
break
else:
time.sleep(0.1)
i.grab_remove()
def _waitWindow(self, text):
# Shamelessly copied from gui.py in anaconda.
win = gtk.Window()
win.set_title(_("Please wait"))
win.set_position(gtk.WIN_POS_CENTER)
label = gtk.Label(text)
box = gtk.Frame()
box.set_border_width(10)
box.add(label)
box.set_shadow_type(gtk.SHADOW_NONE)
win.add(box)
win.set_default_size(-1, -1)
return win
def _showErrorMessage(self, text):
dlg = gtk.MessageDialog(None, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, text)
dlg.set_position(gtk.WIN_POS_CENTER)
dlg.set_modal(True)
rc = dlg.run()
dlg.destroy()
return None