#
# 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 .
#
# Author(s): Chris Lumens
#
import libuser
import string
import crypt
import random
import tempfile
import os
import os.path
import iutil
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):
self.admin = libuser.admin()
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, mkmailspool=True):
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:
iutil.mkdirChain('/home')
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, mkmailspool=mkmailspool)
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
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, password, isCrypted, lock, algo=None):
return self.setUserPassword("root", password, isCrypted, lock, algo)