libsemanage: semanage store migration script

We created a migration script to ease the burden of transition from the
old libsemanage store layout to the new. The script will detect all the
stores in /etc/selinux using the old layout and convert them to the new
layout in /var/lib/selinux. It also allows you to specify the default
priority to use with -p and store to operate on with -s. After migration
the script by default will leave the old store unchanged, but can be
told to remove the old modules directory with -c. Reloading policy post
migration can be disabled with the -n option.

Examples:

semanage_migrate_store

Migrating from /etc/selinux/targeted/modules/active to /var/lib/selinux/targeted/active
Attempting to rebuild policy from /var/lib/selinux

semanage_migrate_store -s targeted

Migrating from /etc/selinux/targeted/modules/active to /var/lib/selinux/targeted/active
Attempting to rebuild policy from /var/lib/selinux

semanage_migrate_store -p 150

Migrating from /etc/selinux/targeted/modules/active to /var/lib/selinux/targeted/active
Attempting to rebuild policy from /var/lib/selinux

Signed-off-by: Chad Sellers <csellers@tresys.com>
Signed-off-by: Steve Lawrence <slawrence@tresys.com>
This commit is contained in:
Caleb Case 2009-12-23 18:26:00 -05:00 committed by Steve Lawrence
parent ddaa6e6eca
commit 6d4e8591a3
3 changed files with 334 additions and 0 deletions

View File

@ -14,6 +14,7 @@ install:
$(MAKE) -C include install
$(MAKE) -C src install
$(MAKE) -C man install
$(MAKE) -C utils install
install-pywrap:
$(MAKE) -C src install-pywrap

View File

@ -0,0 +1,19 @@
# Installation directories.
PREFIX ?= $(DESTDIR)/usr
LIBEXECDIR ?= $(PREFIX)/libexec
SELINUXEXECDIR ?= $(LIBEXECDIR)/selinux/
all:
install: all
-mkdir -p $(SELINUXEXECDIR)
install -m 755 semanage_migrate_store $(SELINUXEXECDIR)
clean:
distclean: clean
indent:
relabel:

View File

@ -0,0 +1,314 @@
#!/usr/bin/python -E
import os
import errno
import shutil
import sys
from optparse import OptionParser
import bz2
import ctypes
sepol = ctypes.cdll.LoadLibrary('libsepol.so')
try:
import selinux
import semanage
except:
print >> sys.stderr, "You must install libselinux-python and libsemanage-python before running this tool"
exit(1)
# For some reason this function doesn't exist in libselinux :\
def copy_with_context(src, dst):
if DEBUG:
print "copying %s to %s" % (src, dst)
try:
con = selinux.lgetfilecon_raw(src)[1]
except:
print >> sys.stderr, "Could not get file context of %s" % src
exit(1)
try:
selinux.setfscreatecon_raw(con)
except:
print >> sys.stderr, "Could not set fs create context: %s" %con
exit(1)
try:
shutil.copy2(src, dst)
except OSError as (err, strerr):
print >> sys.stderr, "Could not copy %s to %s, %s" %(src, dst, strerr)
exit(1)
try:
selinux.setfscreatecon_raw(None)
except:
print >> sys.stderr, "Could not reset fs create context. May need to relabel system."
def create_dir_from(src, dst, mode):
if DEBUG: print "Making directory %s" % dst
try:
con = selinux.lgetfilecon_raw(src)[1]
selinux.setfscreatecon_raw(con)
os.makedirs(dst, mode)
except OSError as (err, stderr):
if err == errno.EEXIST:
pass
else:
print >> sys.stderr, "Error creating %s" % dst
exit(1)
try:
selinux.setfscreatecon_raw(None)
except:
print >> sys.stderr, "Could not reset fs create context. May need to relabel system."
def create_file_from(src, dst):
if DEBUG: print "Making file %s" % dst
try:
con = selinux.lgetfilecon_raw(src)[1]
selinux.setfscreatecon_raw(con)
open(dst, 'a').close()
except OSError as (err, stderr):
print >> sys.stderr, "Error creating %s" % dst
exit(1)
try:
selinux.setfscreatecon_raw(None)
except:
print >> sys.stderr, "Could not reset fs create context. May need to relabel system."
def copy_module(store, name, con, base):
if DEBUG: print "Install module %s" % name
(file, ext) = os.path.splitext(name)
if ext != ".pp":
# Stray non-pp file in modules directory, skip
print >> sys.stderr, "warning: %s has invalid extension, skipping" % name
return
try:
selinux.setfscreatecon_raw(con)
if base:
root = oldstore_path(store)
else:
root = oldmodules_path(store)
bottomdir = bottomdir_path(store)
os.mkdir("%s/%s" % (bottomdir, file))
copy_with_context(os.path.join(root, name), "%s/%s/hll" % (bottomdir, file))
# This is the ext file that will eventually be used to choose a compiler
efile = open("%s/%s/lang_ext" % (bottomdir, file), "w+", 0600)
efile.write("pp")
efile.close()
except:
print >> sys.stderr, "Error installing module %s" % name
exit(1)
try:
selinux.setfscreatecon_raw(None)
except:
print >> sys.stderr, "Could not reset fs create context. May need to relabel system."
def disable_module(file, root, name, disabledmodules):
if DEBUG: print "Disabling %s" % name
(disabledname, disabledext) = os.path.splitext(file)
create_file_from(os.path.join(root, name), "%s/%s" % (disabledmodules, disabledname))
def migrate_store(store):
oldstore = oldstore_path(store);
oldmodules = oldmodules_path(store);
disabledmodules = disabledmodules_path(store);
newstore = newstore_path(store);
newmodules = newmodules_path(store);
bottomdir = bottomdir_path(store);
print "Migrating from %s to %s" % (oldstore, newstore)
# Build up new directory structure
create_dir_from(selinux.selinux_policy_root(), "%s/%s" % (newroot_path(), store), 0755)
create_dir_from(oldmodules, newstore, 0700)
create_dir_from(oldstore, newmodules, 0700)
create_dir_from(oldstore, bottomdir, 0700)
create_dir_from(oldstore, disabledmodules, 0700)
# use whatever the file context of bottomdir is for the module directories
con = selinux.lgetfilecon_raw(bottomdir)[1]
# Special case for base since it was in a different location
copy_module(store, "base.pp", con, 1)
# Dir structure built, start copying files
for root, dirs, files in os.walk(oldstore):
if root == oldstore:
# This is the top level directory, need to move
for name in files:
# Check to see if it is in TOPPATHS and copy if so
if name in TOPPATHS:
if name == "seusers":
newname = "seusers.local"
else:
newname = name
copy_with_context(os.path.join(root, name), os.path.join(newstore, newname))
elif root == oldmodules:
# This should be the modules directory
for name in files:
(file, ext) = os.path.splitext(name)
if name == "base.pp":
print >> sys.stderr, "Error installing module %s, name conflicts with base" % name
exit(1)
elif ext == ".disabled":
disable_module(file, root, name, disabledmodules)
else:
copy_module(store, name, con, 0)
def rebuild_policy():
# Ok, the modules are loaded, lets try to rebuild the policy
print "Attempting to rebuild policy from %s" % newroot_path()
curstore = selinux.selinux_getpolicytype()[1]
handle = semanage.semanage_handle_create()
if not handle:
print >> sys.stderr, "Could not create semanage handle"
exit(1)
semanage.semanage_select_store(handle, curstore, semanage.SEMANAGE_CON_DIRECT)
if not semanage.semanage_is_managed(handle):
semanage.semanage_handle_destroy(handle)
print >> sys.stderr, "SELinux policy is not managed or store cannot be accessed."
exit(1)
rc = semanage.semanage_access_check(handle)
if rc < semanage.SEMANAGE_CAN_WRITE:
semanage.semanage_handle_destroy(handle)
print >> sys.stderr, "Cannot write to policy store."
exit(1)
rc = semanage.semanage_connect(handle)
if rc < 0:
semanage.semanage_handle_destroy(handle)
print >> sys.stderr, "Could not establish semanage connection"
exit(1)
semanage.semanage_set_rebuild(handle, 1)
rc = semanage.semanage_begin_transaction(handle)
if rc < 0:
semanage.semanage_handle_destroy(handle)
print >> sys.stderr, "Could not begin transaction"
exit(1)
rc = semanage.semanage_commit(handle)
if rc < 0:
print >> sys.stderr, "Could not commit transaction"
semanage.semanage_handle_destroy(handle)
def oldroot_path():
return "/etc/selinux"
def oldstore_path(store):
return "%s/%s/modules/active" % (oldroot_path(), store)
def oldmodules_path(store):
return "%s/modules" % oldstore_path(store)
def disabledmodules_path(store):
return "%s/disabled" % newmodules_path(store)
def newroot_path():
return PATH
def newstore_path(store):
return "%s/%s/active" % (newroot_path(), store)
def newmodules_path(store):
return "%s/modules" % newstore_path(store)
def bottomdir_path(store):
return "%s/%s" % (newmodules_path(store), PRIORITY)
if __name__ == "__main__":
parser = OptionParser()
parser.add_option("-p", "--priority", dest="priority", default="100",
help="Set priority of modules in new store (default: 100)")
parser.add_option("-s", "--store", dest="store", default=None,
help="Store to read from and write to")
parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False,
help="Output debug information")
parser.add_option("-c", "--clean", dest="clean", action="store_true", default=False,
help="Clean old modules directory after migrate (default: no)")
parser.add_option("-n", "--norebuild", dest="norebuild", action="store_true", default=False,
help="Disable rebuilding policy after migration (default: no)")
parser.add_option("-P", "--path", dest="path",
help="Set path for the policy store (default: /var/lib/selinux)")
(options, args) = parser.parse_args()
DEBUG = options.debug
PRIORITY = options.priority
TYPE = options.store
CLEAN = options.clean
NOREBUILD = options.norebuild
PATH = options.path
if PATH is None:
PATH = "/var/lib/selinux"
# List of paths that go in the active 'root'
TOPPATHS = [
"commit_num",
"ports.local",
"interfaces.local",
"nodes.local",
"booleans.local",
"file_contexts.local",
"seusers",
"users.local",
"users_extra.local",
"disable_dontaudit",
"preserve_tunables" ]
create_dir_from(oldroot_path(), newroot_path(), 0755)
stores = None
if TYPE is not None:
stores = [TYPE]
else:
stores = os.listdir(oldroot_path())
# find stores in oldroot and migrate them to newroot if necessary
for store in stores:
if not os.path.isdir(oldmodules_path(store)):
# already migrated or not an selinux store
continue
if os.path.isdir(newstore_path(store)):
# store has already been migrated, but old modules dir still exits
print >> sys.stderr, "warning: Policy type %s has already been migrated, but modules still exist in the old store. Skipping store." % store
continue
migrate_store(store)
if CLEAN is True:
def remove_error(function, path, execinfo):
print >> sys.stderr, "warning: Unable to remove old store modules directory %s. Cleaning failed." % oldmodules_path(store)
shutil.rmtree(oldmodules_path(store), onerror=remove_error)
if NOREBUILD is False:
rebuild_policy()