Viewing file: genhomedircon (11.36 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) | #! /usr/bin/python -E
# Copyright (C) 2004 Tresys Technology, LLC
# see file 'COPYING' for use and warranty information
#
# genhomedircon - this script is used to generate file context
# configuration entries for user home directories based on their
# default prefixes and is run when building the policy. Specifically, we
# replace HOME_ROOT, HOME_DIR, and ROLE macros in .fc files with
# generic and user-specific values.
#
# Based off original script by Dan Walsh,
#
# ASSUMPTIONS:
#
# The file CONTEXTDIR/files/homedir_template exists. This file is used to
# set up the home directory context for each real user.
#
# If a user is not listed in CONTEXTDIR/seusers, he will default to user_u, prefix user
#
# "Real" users (as opposed to system users) are those whose UID is greater than
# or equal STARTING_UID (usually 500) and whose login is not a member of
# EXCLUDE_LOGINS. Users who are explicitly defined in CONTEXTDIR/seusers
# are always "real" (including root, in the default configuration).
#
#
import sys, os, pwd, string, getopt, re
from semanage import *;
import selinux
import gettext
gettext.install('policycoreutils')
def grep(file, var):
ret = ""
fd = open(file, 'r')
for i in fd.readlines():
if re.search(var, i, 0) != None:
ret = i
break
fd.close()
return ret
def findval(file, var, delim = ""):
val = ""
try:
fd = open(file, 'r')
for i in fd.readlines():
if i.startswith(var) == 1:
if delim == "":
val = i.split()[1]
else:
val = i.split(delim)[1]
val = val.split("#")[0]
val = val.strip()
fd.close()
except:
val = ""
return val
def getStartingUID():
starting_uid = sys.maxint
uid_min = findval("/etc/login.defs", "UID_MIN")
if uid_min != "":
uid_min = uid_min.split("#")[0]
uid_min = uid_min.strip()
if int(uid_min) < starting_uid:
starting_uid = int(uid_min)
uid_min = findval("/etc/libuser.conf", "LU_UIDNUMBER", "=")
if uid_min != "":
uid_min = uid_min.split("#")[0]
uid_min = uid_min.strip()
if int(uid_min) < starting_uid:
starting_uid = int(uid_min)
if starting_uid == sys.maxint:
starting_uid = 500
return starting_uid
def getDefaultHomeDir():
ret = []
homedir = findval("/etc/default/useradd", "HOME", "=")
if homedir != "" and not homedir in ret:
ret.append(homedir)
homedir = findval("/etc/libuser.conf", "LU_HOMEDIRECTORY", "=")
if homedir != "" and not homedir in ret:
ret.append(homedir)
if ret == []:
ret.append("/home")
# Add /export/home if it exists
# Some customers use this for automounted homedirs
if os.path.exists("/export/home"):
ret.append("/export/home")
return ret
def getSELinuxType(directory):
val = findval(directory+"/config", "SELINUXTYPE", "=")
if val != "":
return val
return "targeted"
def usage(rc=0, error = ""):
if error != "":
sys.stderr.write("%s\n" % error)
rc = 1
sys.stderr.write("Usage: %s [ -d selinuxdir ] [-n | --nopasswd] [-t selinuxtype ]\n" % sys.argv[0])
sys.stderr.flush()
sys.exit(rc)
def warning(warning = ""):
sys.stderr.write("%s\n" % warning)
sys.stderr.flush()
def errorExit(error):
sys.stderr.write("%s exiting for: " % sys.argv[0])
sys.stderr.write("%s\n" % error)
sys.stderr.flush()
sys.exit(1)
class selinuxConfig:
def __init__(self, selinuxdir = "/etc/selinux", type = "targeted", usepwd = 1):
self.semanageHandle = semanage_handle_create()
self.semanaged = semanage_is_managed(self.semanageHandle)
if self.semanaged:
rc = semanage_connect(self.semanageHandle)
if rc:
errorExit("Unable to connect to semanage")
(status, self.ulist) = semanage_user_list(self.semanageHandle)
self.type = type
self.selinuxdir = selinuxdir +"/"
self.contextdir = "/contexts"
self.filecontextdir = self.contextdir+"/files"
self.usepwd = usepwd
self.default_user = "user_u"
self.default_prefix = "user"
self.users = self.getUsers()
def getFileContextDir(self):
return self.selinuxdir+self.type+self.filecontextdir
def getFileContextFile(self):
return self.getFileContextDir()+"/file_contexts"
def getContextDir(self):
return self.selinuxdir+self.type+self.contextdir
def getHomeDirTemplate(self):
return self.getFileContextDir()+"/homedir_template"
def getHomeRootContext(self, homedir):
ret = ""
fd = open(self.getHomeDirTemplate(), 'r')
for i in fd.readlines():
if i.find("HOME_ROOT") == 0:
i = i.replace("HOME_ROOT", homedir)
ret += i
fd.close()
if ret == "":
errorExit("No Home Root Context Found")
return ret
def heading(self):
ret = "\n#\n#\n# User-specific file contexts, generated via %s\n" % sys.argv[0]
if self.semanaged:
ret += "# use semanage command to manage system users in order to change the file_context\n#\n#\n"
else:
ret += "# edit %s to change file_context\n#\n#\n" % (self.selinuxdir+self.type+"/seusers")
return ret
def get_default_prefix(self, name):
for user in self.ulist:
if semanage_user_get_name(user) == name:
return semanage_user_get_prefix(user)
return name
def get_old_prefix(self, user):
rc = grep(self.selinuxdir+self.type+"/users/system.users", "^user %s" % user)
if rc == "":
rc = grep(self.selinuxdir+self.type+"/users/local.users", "^user %s" % user)
if rc != "":
user = rc.split()
prefix = user[3]
if prefix == "{":
prefix = user[4]
if len(prefix) > 2 and (prefix[-2:] == "_r" or prefix[-2:] == "_u"):
prefix = prefix[:-2]
return prefix
def adduser(self, udict, user, seuser, prefix):
if seuser == self.default_user or user == "__default__" or user == "system_u":
return
# !!! chooses first prefix in the list to use in the file context !!!
try:
home = pwd.getpwnam(user)[5]
if home == "/":
# Probably install so hard code to /root
if user == "root":
home = "/root"
else:
return
except KeyError:
if user == "root":
home = "/root"
else:
sys.stderr.write("The user \"%s\" is not present in the passwd file, skipping...\n" % user)
return
prefs = {}
prefs["seuser"] = seuser
prefs["prefix"] = prefix
prefs["home"] = home
udict[user] = prefs
def setDefaultUser(self, user, prefix):
self.default_user = user
self.default_prefix = prefix
def getUsers(self):
udict = {}
if self.semanaged:
(status, list) = semanage_seuser_list(self.semanageHandle)
for seuser in list:
user = []
seusername = semanage_seuser_get_sename(seuser)
prefix = self.get_default_prefix(seusername)
if semanage_seuser_get_name(seuser) == "__default__":
self.setDefaultUser(seusername, prefix)
self.adduser(udict, semanage_seuser_get_name(seuser), seusername, prefix)
else:
try:
fd = open(self.selinuxdir+self.type+"/seusers")
for u in fd.readlines():
u = u.strip()
if len(u) == 0 or u[0] == "#":
continue
user = u.split(":")
if len(user) < 2:
continue
prefix = self.get_old_prefix(user[1])
self.adduser(udict, user[0], user[1], prefix)
fd.close()
except IOError, error:
# Must be install so force add of root
self.adduser(udict, "root", "root", "root")
return udict
def getHomeDirContext(self, user, seuser, home, prefix):
ret = "\n\n#\n# Home Context for user %s\n#\n\n" % user
fd = open(self.getHomeDirTemplate(), 'r')
for i in fd.readlines():
if i.startswith("HOME_DIR") == 1:
i = i.replace("HOME_DIR", home)
i = i.replace("ROLE", prefix)
i = i.replace("system_u", seuser)
# Validate if the generated context exists. Some user types may not exist
scon = i.split()[-1]
if selinux.is_selinux_enabled() < 1 or scon == '<>' or selinux.security_check_context(scon) == 0:
ret = ret+i
fd.close()
return ret
def getUserContext(self, user, sel_user, prefix):
ret = ""
fd = open(self.getHomeDirTemplate(), 'r')
for i in fd.readlines():
if i.find("USER") == 1:
i = i.replace("USER", user)
i = i.replace("ROLE", prefix)
i = i.replace("system_u", sel_user)
ret = ret+i
fd.close()
return ret
def genHomeDirContext(self):
ret = ""
# Fill in HOME and prefix for users that are defined
for u in self.users.keys():
ret += self.getHomeDirContext (u, self.users[u]["seuser"], self.users[u]["home"], self.users[u]["prefix"])
ret += self.getUserContext (u, self.users[u]["seuser"], self.users[u]["prefix"])
return ret+"\n"
def checkExists(self, home):
fd = open(self.getFileContextFile())
for i in fd.readlines():
if len(i) == 0:
continue
try:
regex = i.split()[0]
#match a trailing .+
regex = re.sub("\.+$", "", regex)
regex = re.sub("\.\*$", "", regex)
#strip a (/.*)? which matches anything trailing to a /*$ which matches trailing /'s
regex = re.sub("\(\/\.\*\)\?", "", regex)
regex = regex + "/*$"
if re.match(home, regex):
return 1
except:
continue
return 0
def getHomeDirs(self):
homedirs = getDefaultHomeDir()
starting_uid = getStartingUID()
if self.usepwd == 0:
return homedirs
ulist = pwd.getpwall()
for u in ulist:
if u[2] >= starting_uid and \
u[6] in VALID_SHELLS and \
u[5] != "/" and \
string.count(u[5], "/") > 1:
homedir = u[5][:string.rfind(u[5], "/")]
if not homedir in homedirs:
if self.checkExists(homedir) == 1:
warning("%s homedir %s or its parent directory conflicts with a\ndefined context in %s,\n%s will not create a new context. This usually indicates an incorrectly defined system account. If it is a system account please make sure its login shell is /sbin/nologin." % (u[0], u[5], self.getFileContextFile(), sys.argv[0]))
else:
homedirs.append(homedir)
homedirs.sort()
return homedirs
def genoutput(self):
ret = self.heading()
for h in self.getHomeDirs():
ret += self.getHomeDirContext (self.default_user, self.default_user, h+'/[^/]*', self.default_prefix)
ret += self.getHomeRootContext(h)
ret += self.getUserContext(".*", self.default_user, self.default_prefix) + "\n"
ret += self.genHomeDirContext()
return ret
def printout(self):
print self.genoutput()
def write(self):
fd = open(self.getFileContextDir()+"/file_contexts.homedirs", "w")
fd.write(self.genoutput())
fd.close()
if os.getuid() > 0 or os.geteuid() > 0:
print _("You must be root to run %s.") % sys.argv[0]
sys.exit(1)
try:
fd = open("/etc/shells", 'r')
VALID_SHELLS = fd.read().split("\n")
fd.close()
if "/sbin/nologin" in VALID_SHELLS:
VALID_SHELLS.remove("/sbin/nologin")
if "" in VALID_SHELLS:
VALID_SHELLS.remove("")
except:
VALID_SHELLS = ['/bin/sh', '/bin/bash', '/bin/ash', '/bin/bsh', '/bin/ksh', '/usr/bin/ksh', '/usr/bin/pdksh', '/bin/tcsh', '/bin/csh', '/bin/zsh']
#
# This script will generate home dir file context
# based off the homedir_template file, entries in the password file, and
#
try:
usepwd = 1
directory = "/etc/selinux"
type = None
gopts, cmds = getopt.getopt(sys.argv[1:], 'hnd:t:', ['help',
'type=',
'nopasswd',
'dir='])
for o,a in gopts:
if o == '--type' or o == "-t":
type = a
if o == '--nopasswd' or o == "-n":
usepwd = 0
if o == '--dir' or o == "-d":
directory = a
if o == '--help' or o == "-h":
usage()
except getopt.error, error:
errorExit(_("Options Error %s ") % error)
if type == None:
type = getSELinuxType(directory)
if len(cmds) != 0:
usage(1)
selconf = selinuxConfig(directory, type, usepwd)
try:
selconf.write()
except IOError, error:
sys.stderr.write("%s: %s\n" % ( sys.argv[0], error ))
sys.exit(1)
|