aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
committerwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
commit2590d96369d0217e31dc2812690dde61dac417b5 (patch)
tree82276f787b08a28548e342c7921486f1acefab9f /users.py
parentfirst commit (diff)
downloadanaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.gz
anaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.bz2
anaconda-2590d96369d0217e31dc2812690dde61dac417b5.zip
Initial import from Sabayon (ver 0.9.9.56)
Diffstat (limited to 'users.py')
-rw-r--r--users.py322
1 files changed, 322 insertions, 0 deletions
diff --git a/users.py b/users.py
new file mode 100644
index 0000000..a940a9a
--- /dev/null
+++ b/users.py
@@ -0,0 +1,322 @@
+#
+# users.py: Code for creating user accounts and setting the root password
+#
+# Copyright (C) 2006, 2007, 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): Chris Lumens <clumens@redhat.com>
+#
+
+import libuser
+import string
+import crypt
+import random
+import tempfile
+import os
+import os.path
+
+import logging
+log = logging.getLogger("anaconda")
+
+def createLuserConf(instPath, algoname='sha512'):
+ """Writes a libuser.conf for instPath."""
+ createTmp = False
+ try:
+ fn = os.environ["LIBUSER_CONF"]
+ if os.access(fn, os.F_OK):
+ log.info("removing libuser.conf at %s" % (os.getenv("LIBUSER_CONF")))
+ os.unlink(fn)
+ log.info("created new libuser.conf at %s with instPath=\"%s\"" % \
+ (fn,instPath))
+ fd = open(fn, 'w')
+ except:
+ createTmp = True
+
+ if createTmp:
+ (fp, fn) = tempfile.mkstemp(prefix="libuser.")
+ log.info("created new libuser.conf at %s with instPath=\"%s\"" % \
+ (fn,instPath))
+ fd = os.fdopen(fp, 'w')
+
+ buf = """
+[defaults]
+skeleton = %(instPath)s/etc/skel
+mailspooldir = %(instPath)s/var/mail
+crypt_style = %(algo)s
+modules = files shadow
+create_modules = files shadow
+[files]
+directory = %(instPath)s/etc
+[shadow]
+directory = %(instPath)s/etc
+""" % {"instPath": instPath, "algo": algoname}
+
+ fd.write(buf)
+ fd.close()
+ os.environ["LIBUSER_CONF"] = fn
+
+ return fn
+
+# 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$'}
+ saltlen = 2
+
+ if algo is None:
+ algo = 'sha512'
+
+ if algo == 'md5' or algo == 'sha256' or algo == 'sha512':
+ saltlen = 16
+
+ saltstr = salts[algo]
+
+ for i in range(saltlen):
+ saltstr = saltstr + random.choice (string.letters +
+ string.digits + './')
+
+ return crypt.crypt (password, saltstr)
+
+class Users:
+ def __init__ (self, anaconda):
+ self.anaconda = anaconda
+ self.admin = libuser.admin()
+ self.rootPassword = { "isCrypted": False, "password": "", "lock": False }
+ # dict composed by username as key
+ # 'fullname' => full name
+ # 'password' => password
+ # 'groups' => list of groups
+ # 'group' => main group
+ self.otherUsers = {}
+
+ def createGroup (self, name=None, gid=None, root="/mnt/sysimage"):
+ childpid = os.fork()
+
+ if not childpid:
+ if not root in ["","/"]:
+ os.chroot(root)
+ del(os.environ["LIBUSER_CONF"])
+
+ self.admin = libuser.admin()
+
+ try:
+ if self.admin.lookupGroupByName(name):
+ os._exit(1)
+
+ groupEnt = self.admin.initGroup(name)
+
+ if gid >= 0:
+ groupEnt.set(libuser.GIDNUMBER, gid)
+
+ self.admin.addGroup(groupEnt)
+ os._exit(0)
+ except Exception, e:
+ log.critical("Error when creating new group: %s" % str(e))
+ os._exit(1)
+
+ try:
+ (pid, status) = os.waitpid(childpid, 0)
+ except OSError as e:
+ log.critical("exception from waitpid while creating a group: %s %s" % (e.errno, e.strerror))
+ return False
+
+ if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0):
+ return True
+ else:
+ return False
+
+ def createUser (self, name=None, password=None, isCrypted=False, groups=[],
+ homedir=None, shell=None, uid=None, algo=None, lock=False,
+ root="/mnt/sysimage", gecos=None):
+ childpid = os.fork()
+
+ if not childpid:
+ if not root in ["","/"]:
+ os.chroot(root)
+ del(os.environ["LIBUSER_CONF"])
+
+ self.admin = libuser.admin()
+
+ try:
+ if self.admin.lookupUserByName(name):
+ os._exit(1)
+
+ userEnt = self.admin.initUser(name)
+ groupEnt = self.admin.initGroup(name)
+
+ grpLst = filter(lambda grp: grp,
+ map(lambda name: self.admin.lookupGroupByName(name), groups))
+ userEnt.set(libuser.GIDNUMBER, [groupEnt.get(libuser.GIDNUMBER)[0]] +
+ map(lambda grp: grp.get(libuser.GIDNUMBER)[0], grpLst))
+
+ if not homedir:
+ homedir = "/home/" + name
+
+ userEnt.set(libuser.HOMEDIRECTORY, homedir)
+
+ if shell:
+ userEnt.set(libuser.LOGINSHELL, shell)
+
+ if uid >= 0:
+ userEnt.set(libuser.UIDNUMBER, uid)
+
+ if gecos:
+ userEnt.set(libuser.GECOS, gecos)
+
+ self.admin.addUser(userEnt)
+ self.admin.addGroup(groupEnt)
+
+ if password:
+ if isCrypted:
+ self.admin.setpassUser(userEnt, password, True)
+ else:
+ self.admin.setpassUser(userEnt,
+ cryptPassword(password, algo=algo),
+ True)
+
+ if lock:
+ self.admin.lockUser(userEnt)
+
+ # Add the user to all the groups they should be part of.
+ grpLst.append(self.admin.lookupGroupByName(name))
+ for grp in grpLst:
+ grp.add(libuser.MEMBERNAME, name)
+ self.admin.modifyGroup(grp)
+
+ os._exit(0)
+ except Exception, e:
+ log.critical("Error when creating new user: %s" % str(e))
+ os._exit(1)
+
+ try:
+ (pid, status) = os.waitpid(childpid, 0)
+ except OSError as e:
+ log.critical("exception from waitpid while creating a user: %s %s" % (e.errno, e.strerror))
+ return False
+
+ if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0):
+ return True
+ else:
+ return False
+
+ def checkUserExists(self, username, root="/mnt/sysimage"):
+ childpid = os.fork()
+
+ if not childpid:
+ if not root in ["","/"]:
+ os.chroot(root)
+ del(os.environ["LIBUSER_CONF"])
+
+ self.admin = libuser.admin()
+
+ try:
+ if self.admin.lookupUserByName(username):
+ os._exit(0)
+ except Exception, e:
+ log.critical("Error when searching for user: %s" % str(e))
+ os._exit(1)
+
+ try:
+ (pid, status) = os.waitpid(childpid, 0)
+ except OSError as e:
+ log.critical("exception from waitpid while creating a user: %s %s" % (e.errno, e.strerror))
+ return False
+
+ if os.WIFEXITED(status) and (os.WEXITSTATUS(status) == 0):
+ return True
+ else:
+ return False
+
+ # Reads the auth string and returns a string indicating our desired
+ # password encoding algorithm.
+ def getPassAlgo(self):
+ if self.anaconda.security.auth.find("--enablemd5") != -1 or \
+ self.anaconda.security.auth.find("--passalgo=md5") != -1:
+ return 'md5'
+ elif self.anaconda.security.auth.find("--passalgo=sha256") != -1:
+ return 'sha256'
+ elif self.anaconda.security.auth.find("--passalgo=sha512") != -1:
+ return 'sha512'
+ else:
+ return None
+
+ def setUserPassword(self, username, password, isCrypted, lock, algo=None):
+ user = self.admin.lookupUserByName(username)
+
+ if isCrypted:
+ self.admin.setpassUser(user, password, True)
+ else:
+ self.admin.setpassUser(user, cryptPassword(password, algo=algo), True)
+
+ if lock:
+ self.admin.lockUser(user)
+
+ self.admin.modifyUser(user)
+
+ def setRootPassword(self, algo=None):
+ return self.setUserPassword("root", self.rootPassword["password"],
+ self.rootPassword["isCrypted"],
+ self.rootPassword["lock"], algo)
+
+ def write(self, instPath):
+ # make sure crypt_style in libuser.conf matches the salt we're using
+ createLuserConf(instPath, algoname=self.getPassAlgo())
+
+ # User should already exist, just without a password.
+ self.setRootPassword(algo=self.getPassAlgo())
+
+ for user, udata in self.otherUsers.items():
+ self.createUser(name=udata['username'],
+ password=udata['password'],
+ groups=udata['groups'],
+ algo=self.getPassAlgo(),
+ gecos=udata.get('fullname', None),
+ root=instPath
+ )
+
+ if self.anaconda.ksdata:
+ for gd in self.anaconda.ksdata.group.groupList:
+ if not self.createGroup(name=gd.name,
+ gid=gd.gid,
+ root=instPath):
+ log.error("Group %s already exists, not creating." % gd.name)
+
+ for ud in self.anaconda.ksdata.user.userList:
+ if not self.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=instPath,
+ gecos=ud.gecos):
+ log.error("User %s already exists, not creating." % ud.name)
+
+ def writeKS(self, f):
+ if self.rootPassword["isCrypted"]:
+ args = " --iscrypted %s" % self.rootPassword["password"]
+ else:
+ args = " --iscrypted %s" % cryptPassword(self.rootPassword["password"], algo=self.getPassAlgo())
+
+ if self.rootPassword["lock"]:
+ args += " --lock"
+
+ f.write("rootpw %s\n" % args)