# # Chris Lumens # # 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