All of lore.kernel.org
 help / color / mirror / Atom feed
* Semanage Patch
       [not found] <C92C0B59.BBA5F%csellers@tresys.com>
@ 2010-12-14 13:23 ` Daniel J Walsh
  0 siblings, 0 replies; 6+ messages in thread
From: Daniel J Walsh @ 2010-12-14 13:23 UTC (permalink / raw)
  To: Chad Sellers, SELinux

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

This patch adds handling of modules.
Fixes up lots of --help and man pages to match reality
Adds disable/enable module handling
Lots of bug fixes


If you want to discuss sections we can do that.  Breaking it up into
several different patches would be difficult now.  But if you take the
easy stuff,  We can discuss more difficult sections.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAk0Hb8EACgkQrlYvE4MpobM5qACfY+vmOtJIm7S+k88z7qNfW6EG
5+EAn2FQDnIIobmshGHUrDJAth2Ohm7j
=TBte
-----END PGP SIGNATURE-----

[-- Attachment #2: policycoreutils-semanage.patch --]
[-- Type: text/plain, Size: 51548 bytes --]

diff --git a/policycoreutils/semanage/semanage b/policycoreutils/semanage/semanage
index ffaca5b..75b53e8 100644
--- a/policycoreutils/semanage/semanage
+++ b/policycoreutils/semanage/semanage
@@ -1,4 +1,4 @@
-#! /usr/bin/python -E
+#! /usr/bin/python -Es
 # Copyright (C) 2005, 2006, 2007 Red Hat 
 # see file 'COPYING' for use and warranty information
 #
@@ -20,6 +20,7 @@
 #                                        02111-1307  USA
 #
 #  
+import policycoreutils.default_encoding_utf8
 import sys, getopt, re
 import seobject
 import selinux
@@ -32,27 +33,36 @@ gettext.textdomain(PROGNAME)
 try:
        gettext.install(PROGNAME,
                        localedir="/usr/share/locale",
-                       unicode=False,
+                       unicode=True,
                        codeset = 'utf-8')
 except IOError:
        import __builtin__
        __builtin__.__dict__['_'] = unicode
 
 if __name__ == '__main__':
-
+        action  = False
+        manageditems=[ "boolean", "login", "user", "port", "interface", "node", "fcontext"]
+        def set_action(option):
+               global action
+               if action:
+                      raise ValueError(_("%s bad option") % option)
+               action = True
+                      
 	def usage(message = ""):
                text = _("""
 semanage [ -S store ] -i [ input_file | - ]
+semanage [ -S store ] -o [ output_file | - ]
 
-semanage {boolean|login|user|port|interface|node|fcontext} -{l|D} [-n]
+semanage {boolean|login|user|port|interface|module|node|fcontext} -{l|D|E} [-n]
 semanage login -{a|d|m} [-sr] login_name | %groupname
 semanage user -{a|d|m} [-LrRP] selinux_name
 semanage port -{a|d|m} [-tr] [ -p proto ] port | port_range
 semanage interface -{a|d|m} [-tr] interface_spec
+semanage module -{a|d|m} [--enable|--disable] module
 semanage node -{a|d|m} [-tr] [ -p protocol ] [-M netmask] addr
-semanage fcontext -{a|d|m} [-frst] file_spec
+semanage fcontext -{a|d|m} [-efrst] file_spec
 semanage boolean -{d|m} [--on|--off|-1|-0] -F boolean | boolean_file
-semanage permissive -{d|a} type
+semanage permissive -{d|a|l} type 
 semanage dontaudit [ on | off ]
 
 Primary Options:
@@ -61,7 +71,9 @@ Primary Options:
 	-d, --delete     Delete a OBJECT record NAME
 	-m, --modify     Modify a OBJECT record NAME
         -i, --input      Input multiple semange commands in a transaction 
+        -o, --output     Output current customizations as semange commands 
 	-l, --list       List the OBJECTS
+	-E, --extract    extract customizable commands
 	-C, --locallist  List OBJECTS local customizations
 	-D, --deleteall  Remove all OBJECTS local customizations
 
@@ -84,12 +96,15 @@ Object-specific Options (see above):
         -F, --file       Treat target as an input file for command, change multiple settings
 	-p, --proto      Port protocol (tcp or udp) or internet protocol version of node (ipv4 or ipv6)
 	-M, --mask       Netmask
+        -e, --equal      Substitue source path for dest path when labeling
 	-P, --prefix     Prefix for home directory labeling
 	-L, --level      Default SELinux Level (MLS/MCS Systems only)
 	-R, --roles      SELinux Roles (ex: "sysadm_r staff_r")
 	-s, --seuser     SELinux User Name
 	-t, --type       SELinux Type for the object
 	-r, --range      MLS/MCS Security Range (MLS/MCS Systems only)
+        --enable         Enable a module
+        --disable        Disable a module
 """)
                raise ValueError("%s\n%s" % (text, message))
 		
@@ -101,7 +116,7 @@ Object-specific Options (see above):
 
 	def get_options():
 		valid_option={}
-		valid_everyone=[ '-a', '--add', '-d', '--delete', '-m', '--modify', '-l', '--list', '-h', '--help', '-n', '--noheading', '-C', '--locallist', '-D', '--deleteall', '-S', '--store' ]
+		valid_everyone=[ '-a', '--add', '-d', '--delete', '-E', '--extract', '-m', '--modify', '-l', '--list', '-h', '--help', '-n', '--noheading', '-C', '--locallist', '-D', '--deleteall', '-S', '--store' ]
 		valid_option["login"] = []
 		valid_option["login"] += valid_everyone + [ '-s', '--seuser', '-r', '--range']
 		valid_option["user"] = []
@@ -112,8 +127,10 @@ Object-specific Options (see above):
 		valid_option["interface"] += valid_everyone + [ '-t', '--type', '-r', '--range']
 		valid_option["node"] = []
 		valid_option["node"] += valid_everyone + [ '-M', '--mask', '-t', '--type', '-r', '--range', '-p', '--protocol']
+		valid_option["module"] = []
+		valid_option["module"] += valid_everyone + [ '--enable', '--disable']
 		valid_option["fcontext"] = []
-		valid_option["fcontext"] += valid_everyone + [ '-f', '--ftype', '-s', '--seuser',  '-t', '--type', '-r', '--range'] 
+		valid_option["fcontext"] += valid_everyone + [ '-e', '--equal', '-f', '--ftype', '-s', '--seuser',  '-t', '--type', '-r', '--range'] 
 		valid_option["dontaudit"] = [ '-S', '--store' ]
 		valid_option["boolean"] = []
 		valid_option["boolean"] += valid_everyone + [ '--on', "--off", "-1", "-0", "-F", "--file"] 
@@ -168,6 +185,8 @@ Object-specific Options (see above):
                return ret
 
         def process_args(argv):
+                global action
+                action = False
 		serange = ""
 		port = ""
 		proto = ""
@@ -184,11 +203,17 @@ Object-specific Options (see above):
 		modify = False
 		delete = False
 		deleteall = False
+		enable = False
+		extract = False
+		disable = False
 		list = False
 		locallist = False
 		use_file = False
                 store = ""
+                equal=""
 			
+                if len(argv) == 0:
+                       return
 		object = argv[0]
 		option_dict=get_options()
 		if object not in option_dict.keys():
@@ -197,10 +222,14 @@ Object-specific Options (see above):
 		args = argv[1:]
 
 		gopts, cmds = getopt.getopt(args,
-					    '01adf:i:lhmnp:s:FCDR:L:r:t:P:S:M:',
+					    '01adEe:f:i:lhmnp:s:FCDR:L:r:t:P:S:M:',
 					    ['add',
 					     'delete',
 					     'deleteall',
+					     'equal=',
+					     'enable',
+					     'extract',
+					     'disable',
 					     'ftype=',
 					     'file',
 					     'help',
@@ -225,29 +254,47 @@ Object-specific Options (see above):
 		for o, a in gopts:
 			if o not in option_dict[object]:
 				sys.stderr.write(_("%s not valid for %s objects\n") % ( o, object) );
+
+                                return
 				
 		for o,a in gopts:
 			if o == "-a" or o == "--add":
-				if modify or delete:
-                                       raise ValueError(_("%s bad option") % o)
+                                set_action(o)
 				add = True
 				
 			if o == "-d"  or o == "--delete":
-				if modify or add:
-                                       raise ValueError(_("%s bad option") % o)
+                                set_action(o)
 				delete = True
+
 			if o == "-D"  or o == "--deleteall":
-				if modify:
-                                       raise ValueError(_("%s bad option") % o)
+                                set_action(o)
 				deleteall = True
+
+			if o == "-E"  or o == "--extract":
+                                set_action(o)
+				extract = True
 			if o == "-f"  or o == "--ftype":
 				ftype=a
 
+			if o == "-e"  or o == "--equal":
+				equal = a
+
+			if o == "--enable":
+                                if disable:
+                                       raise ValueError(_("You can't disable and enable at the same time"))
+
+				enable = True
+
+			if o == "--disable":
+                                if enable:
+                                       raise ValueError(_("You can't disable and enable at the same time"))
+				disable = True
+
 			if o == "-F"  or o == "--file":
 				use_file = True
 
 			if o == "-h" or o == "--help":
-                               raise ValueError(_("%s bad option") % o)
+                               raise usage()
 
 			if o == "-n" or o == "--noheading":
 				heading = False
@@ -256,8 +303,7 @@ Object-specific Options (see above):
 				locallist = True
 
 			if o == "-m"or o == "--modify":
-				if delete or add:
-                                       raise ValueError(_("%s bad option") % o)
+                                set_action(o)
 				modify = True
 				
 			if o == "-S" or o == '--store':
@@ -292,8 +338,10 @@ Object-specific Options (see above):
 
                         if o == "--on" or o == "-1":
                                value = "on"
+                               modify = True
                         if o == "--off" or o == "-0":
                                value = "off"
+                               modify = True
 
 		if object == "login":
 			OBJECT = seobject.loginRecords(store)
@@ -315,6 +363,11 @@ Object-specific Options (see above):
 		
 		if object == "boolean":
 			OBJECT = seobject.booleanRecords(store)
+                        if use_file:
+                               modify=True
+
+		if object == "module":
+			OBJECT = seobject.moduleRecords(store)
 		
 		if object == "permissive":
 			OBJECT = seobject.permissiveRecords(store)
@@ -330,65 +383,97 @@ Object-specific Options (see above):
 			OBJECT.deleteall()
                         return
 			
+		if extract:
+                        for i in OBJECT.customized():
+                               print "%s %s" % (object, str(i))
+                        return
+			
 		if len(cmds) != 1:
-                       raise ValueError(_("%s bad option") % o)
+                       raise ValueError(_("bad option"))
                         
                 target = cmds[0]
 
-
 		if object == "dontaudit":
-			OBJECT = seobject.dontauditClass(store)
-                        OBJECT.toggle(target)
-                        return
+                       OBJECT = seobject.dontauditClass(store)
+                       OBJECT.toggle(target)
+                       return
                               
 		if add:
 			if object == "login":
 				OBJECT.add(target, seuser, serange)
+                                return
 
 			if object == "user":
 				OBJECT.add(target, roles.split(), selevel, serange, prefix)
+                                return
 
 			if object == "port":
 				OBJECT.add(target, proto, serange, setype)
+                                return
 
 			if object == "interface":
 				OBJECT.add(target, serange, setype)
+                                return
+
+			if object == "module":
+				OBJECT.add(target)
+                                return
 
 			if object == "node":
 				OBJECT.add(target, mask, proto, serange, setype)
+                                return
 
 			if object == "fcontext":
-				OBJECT.add(target, setype, ftype, serange, seuser)
+                                if equal == "":
+                                       OBJECT.add(target, setype, ftype, serange, seuser)
+                                else:
+                                       OBJECT.add_equal(target, equal)
+                                return
 			if object == "permissive":
 				OBJECT.add(target)
+                                return
 
-                        return
-			
 		if modify:
 			if object == "boolean":
                                OBJECT.modify(target, value, use_file)
+                               return
 
 			if object == "login":
 				OBJECT.modify(target, seuser, serange)
+                                return
 
 			if object == "user":
 				rlist = roles.split()
 				OBJECT.modify(target, rlist, selevel, serange, prefix)
+                                return
+
+			if object == "module":
+                                if enable:
+                                       OBJECT.enable(target)
+                                elif disable:
+                                       OBJECT.disable(target)
+                                else:
+                                       OBJECT.modify(target)
+                                return
 
 			if object == "port":
 				OBJECT.modify(target, proto, serange, setype)
+                                return
 
 			if object == "interface":
 				OBJECT.modify(target, serange, setype)
+                                return
 
 			if object == "node":
 				OBJECT.modify(target, mask, proto, serange, setype)
+                                return
 
 			if object == "fcontext":
-				OBJECT.modify(target, setype, ftype, serange, seuser)
-
-                        return
-
+                                if equal == "":
+                                       OBJECT.modify(target, setype, ftype, serange, seuser)
+                                else:
+                                       OBJECT.modify_equal(target, equal)
+                                return
 		if delete:
 			if object == "port":
 				OBJECT.delete(target, proto)
@@ -401,15 +486,14 @@ Object-specific Options (see above):
 
 			else:
 				OBJECT.delete(target)
-
                         return
-
-                raise ValueError(_("Invalid command") % " ".join(argv))
+                raise ValueError(_("Invalid command: semanage %s") % " ".join(argv))
 
 	#
 	# 
 	#
 	try:
+               output = None
                input = None
                store = ""
 
@@ -417,7 +501,7 @@ Object-specific Options (see above):
                       usage(_("Requires 2 or more arguments"))
                 
                gopts, cmds = getopt.getopt(sys.argv[1:],
-                                           '01adf:i:lhmnp:s:FCDR:L:r:t:T:P:S:',
+                                           '01adf:i:lhmno:p:s:FCDR:L:r:t:T:P:S:',
                                            ['add',
                                             'delete',
                                             'deleteall',
@@ -431,6 +515,7 @@ Object-specific Options (see above):
                                             'localist',
                                             'off', 
                                             'on', 
+                                            'output=',
                                             'proto=',
                                             'seuser=',
                                             'store=',
@@ -438,6 +523,7 @@ Object-specific Options (see above):
                                             'level=',
                                             'roles=',
                                             'type=',
+                                            'trans=',
                                             'prefix='
                                             ])
                for o, a in gopts:
@@ -445,6 +531,16 @@ Object-specific Options (see above):
                              store = a
                       if o == "-i" or o == '--input':
                              input = a
+                      if o == "-o" or o == '--output':
+                             output = a
+
+               if output != None:
+                      if output != "-":
+                             sys.stdout = open(output, 'w')
+                      for i in manageditems:
+                             print "%s -D" % i
+                             process_args([i, "-E"])
+                      sys.exit(0)
 
                if input != None:
                       if input == "-":
@@ -467,3 +563,5 @@ Object-specific Options (see above):
 		errorExit(_("Invalid value %s") % error.args[0])
 	except IOError, error:
 		errorExit(error.args[1])
+	except OSError, error:
+		errorExit(error.args[1])
diff --git a/policycoreutils/semanage/semanage.8 b/policycoreutils/semanage/semanage.8
index 70d1a20..fb6a79b 100644
--- a/policycoreutils/semanage/semanage.8
+++ b/policycoreutils/semanage/semanage.8
@@ -1,29 +1,69 @@
-.TH "semanage" "8" "2005111103" "" ""
+.TH "semanage" "8" "20100223" "" ""
 .SH "NAME"
 semanage \- SELinux Policy Management tool
 
 .SH "SYNOPSIS"
-.B semanage {boolean|login|user|port|interface|node|fcontext} \-{l|D} [\-n] [\-S store]
+Output local customizations
 .br
-.B semanage boolean \-{d|m} [\-\-on|\-\-off|\-1|\-0] -F boolean | boolean_file
+.B semanage [ -S store ] -o [ output_file | - ]
+
+Input local customizations
+.br
+.B semanage [ -S store ] -i [ input_file | - ]
+
+Manage booleans.  Booleans allow the administrator to modify the confinement of 
+processes based on his configuration.
+.br
+.B semanage boolean [\-S store] \-{d|m|l|n|D} \-[\-on|\-off|\1|0] -F boolean | boolean_file
+
+Manage SELinux confined users (Roles and levels for an SELinux user)
+.br
+.B semanage user [\-S store] \-{a|d|m|l|n|D} [\-LrRP] selinux_name
+
+Manage login mappings between linux users and SELinux confined users.
+.br
+.B semanage login [\-S store] \-{a|d|m|l|n|D} [\-sr] login_name | %groupname
+
+Manage policy modules.
+.br
+.B semanage module [\-S store] \-{a|d|l} [-m [--enable | --disable] ] module_name
+
+Manage network port type definitions
 .br
-.B semanage login \-{a|d|m} [\-sr] login_name | %groupname
+.B semanage port [\-S store] \-{a|d|m|l|n|D} [\-tr] [\-p proto] port | port_range
 .br
-.B semanage user \-{a|d|m} [\-LrRP] selinux_name
+
+Manage network interface type definitions
+.br
+.B semanage interface [\-S store] \-{a|d|m|l|n|D} [\-tr] interface_spec
+
+Manage network node type definitions
 .br
-.B semanage port \-{a|d|m} [\-tr] [\-p proto] port | port_range
+.B semanage node [\-S store] -{a|d|m|l|n|D} [-tr] [ -p protocol ] [-M netmask] address
 .br
-.B semanage interface \-{a|d|m} [\-tr] interface_spec
+
+Manage file context mapping definitions
+.br
+.B semanage fcontext [\-S store] \-{a|d|m|l|n|D} [\-frst] file_spec
 .br
-.B semanage node -{a|d|m} [-tr] [ -p protocol ] [-M netmask] address
+.B semanage fcontext [\-S store] \-{a|d|m|l|n|D} \-e replacement target
 .br
-.B semanage fcontext \-{a|d|m} [\-frst] file_spec
+
+Manage processes type enforcement mode
 .br
-.B semanage permissive \-{a|d} type
+.B semanage permissive [\-S store] \-{a|d|l|n|D} type
 .br
-.B semanage dontaudit [ on | off ]
+
+Disable/Enable dontaudit rules in policy
+.br
+.B semanage dontaudit [\-S store] [ on | off ]
 .P
 
+Execute multiple commands within a single transaction.
+.br
+.B semanage [\-S store] \-i command-file
+.br
+
 .SH "DESCRIPTION"
 semanage is used to configure certain elements of
 SELinux policy without requiring modification to or recompilation
@@ -52,6 +92,22 @@ Delete a OBJECT record NAME
 .I                \-D, \-\-deleteall
 Remove all OBJECTS local customizations
 .TP
+.I                \-\-disable
+Disable a policy module, requires -m option
+
+Currently modules only.
+.TP
+.I                \-\-enable
+Enable a disabled policy module, requires -m option
+
+Currently modules only.
+.TP
+.I                \-e, \-\-equal
+Substitute target path with sourcepath when generating default label.  This is used with
+fcontext. Requires source and target path arguments.  The context
+labeling for the target subtree is made equivalent to that
+defined for the source.
+.TP
 .I                \-f, \-\-ftype
 File Type.   This is used with fcontext.
 Requires a file type as shown in the mode field by ls, e.g. use -d to match only directories or -- to match only regular files.
@@ -60,6 +116,7 @@ Requires a file type as shown in the mode field by ls, e.g. use -d to match only
 Set multiple records from the input file.  When used with the \-l \-\-list, it will output the current settings to stdout in the proper format.
 
 Currently booleans only.
+
 .TP
 .I                \-h, \-\-help       
 display this message
@@ -76,6 +133,9 @@ Default SELinux Level for SELinux use, s0 Default. (MLS/MCS Systems only)
 .I                \-m, \-\-modify     
 Modify a OBJECT record NAME
 .TP
+.I                \-M, \-\-mask
+Network Mask
+.TP
 .I                \-n, \-\-noheading  
 Do not print heading when listing OBJECTS.
 .TP
@@ -99,26 +159,67 @@ Select and alternate SELinux store to manage
 .TP
 .I                \-t, \-\-type       
 SELinux Type for the object
+.TP
+.I                \-i, \-\-input
+Take a set of commands from a specified file and load them in a single
+transaction.
 
 .SH EXAMPLE
 .nf
-# View SELinux user mappings
-$ semanage user -l
-# Allow joe to login as staff_u
-$ semanage login -a -s staff_u joe
-# Allow the group clerks to login as user_u
-$ semanage login -a -s user_u %clerks
-# Add file-context for everything under /web (used by restorecon)
-$ semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
-# Allow Apache to listen on port 81
-$ semanage port -a -t http_port_t -p tcp 81
-# Change apache to a permissive domain
-$ semanage permissive -a httpd_t
-# Turn off dontaudit rules
-$ semanage dontaudit off
+.B SELinux user 
+List SELinux users
+# semanage user -l
+
+.B SELinux login
+Change joe to login as staff_u
+# semanage login -a -s staff_u joe
+Change the group clerks to login as user_u
+# semanage login -a -s user_u %clerks
+
+.B File contexts
+.i remember to run restorecon after you set the file context
+Add file-context for everything under /web 
+# semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
+# restorecon -R -v /web
+
+Substitute /home1 with /home when setting file context
+# semanage fcontext -a -e /home /home1
+# restorecon -R -v /home1
+
+For home directories under top level directory, for example /disk6/home, 
+execute the following commands.  
+# semanage fcontext -a -t home_root_t "/disk6" 
+# semanage fcontext -a -e /home /disk6/home 
+# restorecon -R -v /disk6
+
+.B Port contexts
+Allow Apache to listen on tcp port 81
+# semanage port -a -t http_port_t -p tcp 81
+
+.B Change apache to a permissive domain
+# semanage permissive -a httpd_t
+
+.B Turn off dontaudit rules
+# semanage dontaudit off
+
+.B Managing multiple machines
+Multiple machines that need the same customizations.  
+Extract customizations off first machine, copy them 
+to second and import them.
+
+# semanage -o /tmp/local.selinux
+# scp /tmp/local.selinux secondmachine:/tmp
+# ssh secondmachine
+# semanage -i /tmp/local.selinux
+
+If these customizations include file context, you need to apply the 
+context using restorecon.
+
 .fi
 
 .SH "AUTHOR"
-This man page was written by Daniel Walsh <dwalsh@redhat.com> and
-Russell Coker <rcoker@redhat.com>.
+This man page was written by Daniel Walsh <dwalsh@redhat.com> 
+.br
+and Russell Coker <rcoker@redhat.com>.
+.br
 Examples by Thomas Bleher <ThomasBleher@gmx.de>.
diff --git a/policycoreutils/semanage/seobject.py b/policycoreutils/semanage/seobject.py
index b7d257b..40e57e9 100644
--- a/policycoreutils/semanage/seobject.py
+++ b/policycoreutils/semanage/seobject.py
@@ -29,47 +29,12 @@ import sepolgen.module as module
 import gettext
 gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
 gettext.textdomain(PROGNAME)
-try:
-       gettext.install(PROGNAME, localedir = "/usr/share/locale", unicode = 1)
-except IOError:
-       import __builtin__
-       __builtin__.__dict__['_'] = unicode
-
-import syslog
-
-handle = None
-
-def get_handle(store):
-       global handle
-       global is_mls_enabled
-
-       handle = semanage_handle_create()
-       if not handle:
-              raise ValueError(_("Could not create semanage handle"))
-       
-       if store != "":
-              semanage_select_store(handle, store, SEMANAGE_CON_DIRECT);
-
-       if not semanage_is_managed(handle):
-              semanage_handle_destroy(handle)
-              raise ValueError(_("SELinux policy is not managed or store cannot be accessed."))
-
-       rc = semanage_access_check(handle)
-       if rc < SEMANAGE_CAN_READ:
-              semanage_handle_destroy(handle)
-              raise ValueError(_("Cannot read policy store."))
-
-       rc = semanage_connect(handle)
-       if rc < 0:
-              semanage_handle_destroy(handle)
-              raise ValueError(_("Could not establish semanage connection"))
 
-       is_mls_enabled = semanage_mls_enabled(handle)
-       if is_mls_enabled < 0:
-              semanage_handle_destroy(handle)
-              raise ValueError(_("Could not test MLS enabled status"))
+import gettext
+translation=gettext.translation(PROGNAME, localedir = "/usr/share/locale", fallback=True)
+_=translation.ugettext
 
-       return handle
+import syslog
 
 file_types = {}
 file_types[""] = SEMANAGE_FCONTEXT_ALL;
@@ -194,45 +159,154 @@ def untranslate(trans, prepend = 1):
 		return trans
 	else:
 		return raw
-	
+
 class semanageRecords:
-	def __init__(self, store):
+        transaction = False
+        handle = None
+	store = None
+
+        def __init__(self, store):
                global handle
                       
-               if handle != None:
-                      self.sh = handle
-               else:
-                      self.sh = get_handle(store)
-               self.transaction = False
+               self.sh = self.get_handle(store)
+
+        def get_handle(self, store):
+               global is_mls_enabled
+
+               if semanageRecords.handle:
+                      return semanageRecords.handle
+
+               handle = semanage_handle_create()
+               if not handle:
+                      raise ValueError(_("Could not create semanage handle"))
+               
+               if not semanageRecords.transaction and store != "":
+                      semanage_select_store(handle, store, SEMANAGE_CON_DIRECT);
+		      semanageRecords.store = store
+                      
+               if not semanage_is_managed(handle):
+                      semanage_handle_destroy(handle)
+                      raise ValueError(_("SELinux policy is not managed or store cannot be accessed."))
+                      
+               rc = semanage_access_check(handle)
+               if rc < SEMANAGE_CAN_READ:
+                      semanage_handle_destroy(handle)
+                      raise ValueError(_("Cannot read policy store."))
+               
+               rc = semanage_connect(handle)
+               if rc < 0:
+                      semanage_handle_destroy(handle)
+                      raise ValueError(_("Could not establish semanage connection"))
+
+               is_mls_enabled = semanage_mls_enabled(handle)
+               if is_mls_enabled < 0:
+                      semanage_handle_destroy(handle)
+                      raise ValueError(_("Could not test MLS enabled status"))
+
+               semanageRecords.handle = handle
+               return semanageRecords.handle
 
         def deleteall(self):
                raise ValueError(_("Not yet implemented"))
 
         def start(self):
-               if self.transaction:
+               if semanageRecords.transaction:
                       raise ValueError(_("Semanage transaction already in progress"))
                self.begin()
-               self.transaction = True
-
+               semanageRecords.transaction = True
         def begin(self):
-               if self.transaction:
+               if semanageRecords.transaction:
                       return
                rc = semanage_begin_transaction(self.sh)
                if rc < 0:
                       raise ValueError(_("Could not start semanage transaction"))
+        def customized(self):
+               raise ValueError(_("Not yet implemented"))
+
         def commit(self):
-               if self.transaction:
+               if semanageRecords.transaction:
                       return
                rc = semanage_commit(self.sh) 
                if rc < 0:
                       raise ValueError(_("Could not commit semanage transaction"))
 
         def finish(self):
-               if not self.transaction:
+               if not semanageRecords.transaction:
                       raise ValueError(_("Semanage transaction not in progress"))
-               self.transaction = False
+               semanageRecords.transaction = False
                self.commit()
 
+class moduleRecords(semanageRecords):
+	def __init__(self, store):
+               semanageRecords.__init__(self, store)
+
+	def get_all(self):
+               l = []
+               (rc, mlist, number) = semanage_module_list(self.sh)
+               if rc < 0:
+                      raise ValueError(_("Could not list SELinux modules"))
+
+               for i in range(number):
+                      mod = semanage_module_list_nth(mlist, i)
+                      l.append((semanage_module_get_name(mod), semanage_module_get_version(mod), semanage_module_get_enabled(mod)))
+               return l
+
+	def list(self, heading = 1, locallist = 0):
+		if heading:
+			print "\n%-25s%-10s\n" % (_("Modules Name"), _("Version"))
+                for t in self.get_all():
+                       if t[2] == 0:
+                              disabled = _("Disabled")
+                       else:
+                              disabled = ""
+                       print "%-25s%-10s%s" % (t[0], t[1], disabled)
+
+	def add(self, file):
+               rc = semanage_module_install_file(self.sh, file);
+               if rc >= 0:
+                      self.commit()
+
+	def disable(self, module):
+               need_commit = False                      
+               for m in module.split():
+                      rc = semanage_module_disable(self.sh, m)
+                      if rc < 0 and rc != -3:
+                             raise ValueError(_("Could not disable module %s (remove failed)") % m)
+                      if rc != -3:
+                             need_commit = True 
+               if need_commit:
+                      self.commit()
+			
+	def enable(self, module):
+               need_commit = False                      
+               for m in module.split():
+                      rc = semanage_module_enable(self.sh, m)
+                      if rc < 0 and rc != -3:
+                             raise ValueError(_("Could not enable module %s (remove failed)") % m)
+                      if rc != -3:
+                             need_commit = True 
+               if need_commit:
+                      self.commit()
+
+	def modify(self, file):
+               rc = semanage_module_update_file(self.sh, file);
+               if rc >= 0:
+                      self.commit()
+
+	def delete(self, module):
+               for m in module.split():
+                      rc = semanage_module_remove(self.sh, m)
+                      if rc < 0 and rc != -2:
+                             raise ValueError(_("Could not remove module %s (remove failed)") % m)
+                      
+               self.commit()
+			
+	def deleteall(self):
+               l = self.get_all()
+               if len(l) > 0:
+                      all = " ".join(l[0])
+                      self.delete(all)
+
 class dontauditClass(semanageRecords):
 	def __init__(self, store):
                semanageRecords.__init__(self, store)
@@ -259,14 +333,23 @@ class permissiveRecords(semanageRecords):
                       name = semanage_module_get_name(mod)
                       if name and name.startswith("permissive_"):
                              l.append(name.split("permissive_")[1])
+
                return l
 
 	def list(self, heading = 1, locallist = 0):
-		if heading:
-			print "\n%-25s\n" % (_("Permissive Types"))
-                for t in self.get_all():
-                       print t
+		import setools
+		all = map(lambda y: y["name"], filter(lambda x: x["permissive"], setools.seinfo(setools.TYPE)))
 
+		if heading:
+			print "\n%-25s\n" % (_("Builtin Permissive Types"))
+		customized = self.get_all()
+                for t in all:
+			if t not in customized:
+				print t
+		if heading:
+			print "\n%-25s\n" % (_("Customized Permissive Types"))
+		for t in customized:
+			print t
 
 	def add(self, type):
                import glob
@@ -343,7 +426,9 @@ class loginRecords(semanageRecords):
 		if rc < 0:
 			raise ValueError(_("Could not check if login mapping for %s is defined") % name)
 		if exists:
-			raise ValueError(_("Login mapping for %s is already defined") % name)
+                       semanage_seuser_key_free(k)
+                       return self.__modify(name, sename, serange)
+
                 if name[0] == '%':
                        try:
                               grp.getgrnam(name[1:])
@@ -475,6 +560,16 @@ class loginRecords(semanageRecords):
 		
 		mylog.log(1, "delete SELinux user mapping", name);
 
+	def deleteall(self):
+		(rc, ulist) = semanage_seuser_list_local(self.sh)
+		if rc < 0:
+			raise ValueError(_("Could not list login mappings"))
+
+                self.begin()
+		for u in ulist:
+			self.__delete(semanage_seuser_get_name(u))
+                self.commit()
+
 	def get_all(self, locallist = 0):
 		ddict = {}
                 if locallist:
@@ -489,6 +584,15 @@ class loginRecords(semanageRecords):
 			ddict[name] = (semanage_seuser_get_sename(u), semanage_seuser_get_mlsrange(u))
 		return ddict
 
+        def customized(self):
+                l = []
+                ddict = self.get_all(True)
+                keys = ddict.keys()
+                keys.sort()
+                for k in keys:
+                       l.append("-a -s %s -r '%s' %s" % (ddict[k][0], ddict[k][1], k))
+                return l
+
 	def list(self,heading = 1, locallist = 0):
 		ddict = self.get_all(locallist)
 		keys = ddict.keys()
@@ -531,7 +635,8 @@ class seluserRecords(semanageRecords):
                 if rc < 0:
                        raise ValueError(_("Could not check if SELinux user %s is defined") % name)
                 if exists:
-                       raise ValueError(_("SELinux user %s is already defined") % name)
+                       semanage_user_key_free(k)
+                       return self.__modify(name, roles, selevel, serange, prefix)
 
                 (rc, u) = semanage_user_create(self.sh)
                 if rc < 0:
@@ -682,6 +787,16 @@ class seluserRecords(semanageRecords):
 		
 		mylog.log(1,"delete SELinux user record", name)
 
+	def deleteall(self):
+		(rc, ulist) = semanage_user_list_local(self.sh)
+		if rc < 0:
+			raise ValueError(_("Could not list login mappings"))
+
+                self.begin()
+		for u in ulist:
+			self.__delete(semanage_user_get_name(u))
+                self.commit()
+
 	def get_all(self, locallist = 0):
 		ddict = {}
                 if locallist:
@@ -702,6 +817,15 @@ class seluserRecords(semanageRecords):
 
 		return ddict
 
+        def customized(self):
+                l = []
+                ddict = self.get_all(True)
+                keys = ddict.keys()
+                keys.sort()
+                for k in keys:
+                       l.append("-a -r %s -R '%s' %s" % (ddict[k][2], ddict[k][3], k))
+                return l
+
 	def list(self, heading = 1, locallist = 0):
 		ddict = self.get_all(locallist)
 		keys = ddict.keys()
@@ -740,12 +864,16 @@ class portRecords(semanageRecords):
 			low = int(ports[0])
 			high = int(ports[1])
 
+                if high > 65536:
+                       raise ValueError(_("Invalid Port"))
+
 		(rc, k) = semanage_port_key_create(self.sh, low, high, proto_d)
 		if rc < 0:
 			raise ValueError(_("Could not create a key for %s/%s") % (proto, port))
 		return ( k, proto_d, low, high )
 
 	def __add(self, port, proto, serange, type):
+
 		if is_mls_enabled == 1:
 			if serange == "":
 				serange = "s0"
@@ -808,6 +936,7 @@ class portRecords(semanageRecords):
                 self.commit()
 
 	def __modify(self, port, proto, serange, setype):
+
 		if serange == "" and setype == "":
 			if is_mls_enabled == 1:
 				raise ValueError(_("Requires setype or serange"))
@@ -942,6 +1071,18 @@ class portRecords(semanageRecords):
 				ddict[(ctype,proto_str)].append("%d-%d" % (low, high))
 		return ddict
 
+        def customized(self):
+                l = []
+		ddict = self.get_all(True)
+		keys = ddict.keys()
+		keys.sort()
+                for k in keys:
+                       if k[0] == k[1]:
+                              l.append("-a -t %s -p %s %s" % (ddict[k][0], k[2], k[0]))
+                       else:
+                              l.append("-a -t %s -p %s %s-%s" % (ddict[k][0], k[2], k[0], k[1]))
+                return l
+
 	def list(self, heading = 1, locallist = 0):
 		if heading:
 			print "%-30s %-8s %s\n" % (_("SELinux Port Type"), _("Proto"), _("Port Number"))
@@ -958,7 +1099,8 @@ class portRecords(semanageRecords):
 class nodeRecords(semanageRecords):
        def __init__(self, store = ""):
                semanageRecords.__init__(self,store)
-
+               self.protocol = ["ipv4", "ipv6"]
+       
        def __add(self, addr, mask, proto, serange, ctype):
                if addr == "":
                        raise ValueError(_("Node Address is required"))
@@ -966,14 +1108,11 @@ class nodeRecords(semanageRecords):
                if mask == "":
                        raise ValueError(_("Node Netmask is required"))
 
-	       if proto == "ipv4":
-                       proto = 0
-               elif proto == "ipv6":
-                       proto = 1
-               else:
+               try:
+                      proto = self.protocol.index(proto)
+               except:
                       raise ValueError(_("Unknown or missing protocol"))
 
-
                if is_mls_enabled == 1:
                        if serange == "":
                                serange = "s0"
@@ -991,11 +1130,13 @@ class nodeRecords(semanageRecords):
 
                (rc, exists) = semanage_node_exists(self.sh, k)
                if exists:
-                       raise ValueError(_("Addr %s already defined") % addr)
+                       semanage_node_key_free(k)
+                       return self.__modify(addr, mask, self.protocol[proto], serange, ctype)
 
                (rc, node) = semanage_node_create(self.sh)
                if rc < 0:
                        raise ValueError(_("Could not create addr for %s") % addr)
+               semanage_node_set_proto(node, proto)
 
                rc = semanage_node_set_addr(self.sh, node, proto, addr)
                (rc, con) = semanage_context_create(self.sh)
@@ -1005,8 +1146,7 @@ class nodeRecords(semanageRecords):
                rc = semanage_node_set_mask(self.sh, node, proto, mask)
                if rc < 0:
                        raise ValueError(_("Could not set mask for %s") % addr)
-
-
+	       
                rc = semanage_context_set_user(self.sh, con, "system_u")
                if rc < 0:
                        raise ValueError(_("Could not set user in addr context for %s") % addr)
@@ -1047,13 +1187,10 @@ class nodeRecords(semanageRecords):
 
                if mask == "":
                        raise ValueError(_("Node Netmask is required"))
-               if proto == "ipv4":
-                       proto = 0
-               elif proto == "ipv6":
-                       proto = 1
-	       else:
-		      raise ValueError(_("Unknown or missing protocol"))
-
+               try:
+                      proto = self.protocol.index(proto)
+               except:
+                      raise ValueError(_("Unknown or missing protocol"))
 
                if serange == "" and setype == "":
                        raise ValueError(_("Requires setype or serange"))
@@ -1068,12 +1205,11 @@ class nodeRecords(semanageRecords):
                if not exists:
                        raise ValueError(_("Addr %s is not defined") % addr)
 
-               (rc, node) = semanage_node_query(self.sh, k)
+               (rc, node) = semanage_node_query_local(self.sh, k)
                if rc < 0:
                        raise ValueError(_("Could not query addr %s") % addr)
 
                con = semanage_node_get_con(node)
-
                if serange != "":
                        semanage_context_set_mls(self.sh, con, untranslate(serange))
                if setype != "":
@@ -1098,11 +1234,9 @@ class nodeRecords(semanageRecords):
                if mask == "":
                        raise ValueError(_("Node Netmask is required"))
 
-	       if proto == "ipv4":
-                       proto = 0
-               elif proto == "ipv6":
-                       proto = 1
-               else:
+               try:
+                      proto = self.protocol.index(proto)
+               except:
                       raise ValueError(_("Unknown or missing protocol"))
 
                (rc, k) = semanage_node_key_create(self.sh, addr, mask, proto)
@@ -1132,6 +1266,16 @@ class nodeRecords(semanageRecords):
               self.__delete(addr, mask, proto)
               self.commit()
 		
+       def deleteall(self):
+              (rc, nlist) = semanage_node_list_local(self.sh)
+              if rc < 0:
+                     raise ValueError(_("Could not deleteall node mappings"))
+              
+              self.begin()
+              for node in nlist:
+                     self.__delete(semanage_node_get_addr(self.sh, node)[1], semanage_node_get_mask(self.sh, node)[1], self.protocol[semanage_node_get_proto(node)])
+              self.commit()
+
        def get_all(self, locallist = 0):
                ddict = {}
 	       if locallist :
@@ -1145,15 +1289,20 @@ class nodeRecords(semanageRecords):
                        con = semanage_node_get_con(node)
                        addr = semanage_node_get_addr(self.sh, node)
                        mask = semanage_node_get_mask(self.sh, node)
-                       proto = semanage_node_get_proto(node)
-		       if proto == 0:
-				proto = "ipv4"
-		       elif proto == 1:
-				proto = "ipv6"
+                       proto = self.protocol[semanage_node_get_proto(node)]
                        ddict[(addr[1], mask[1], proto)] = (semanage_context_get_user(con), semanage_context_get_role(con), semanage_context_get_type(con), semanage_context_get_mls(con))
 
                return ddict
 
+       def customized(self):
+               l = []
+               ddict = self.get_all(True)
+               keys = ddict.keys()
+               keys.sort()
+               for k in keys:
+                      l.append("-a -M %s -p %s -t %s %s" % (k[1], k[2],ddict[k][2], k[0]))
+               return l
+
        def list(self, heading = 1, locallist = 0):
                if heading:
                        print "%-18s %-18s %-5s %-5s\n" % ("IP Address", "Netmask", "Protocol", "Context")
@@ -1193,7 +1342,8 @@ class interfaceRecords(semanageRecords):
 		if rc < 0:
 			raise ValueError(_("Could not check if interface %s is defined") % interface)
 		if exists:
-			raise ValueError(_("Interface %s already defined") % interface)
+                        semanage_iface_key_free(k)
+                        return self.__modify(interface, serange, ctype)
 
 		(rc, iface) = semanage_iface_create(self.sh)
 		if rc < 0:
@@ -1307,6 +1457,16 @@ class interfaceRecords(semanageRecords):
                 self.__delete(interface)
                 self.commit()
 		
+        def deleteall(self):
+		(rc, ulist) = semanage_iface_list_local(self.sh)
+		if rc < 0:
+			raise ValueError(_("Could not delete all interface  mappings"))
+
+                self.begin()
+		for i in ulist:
+			self.__delete(semanage_iface_get_name(i))
+                self.commit()
+
 	def get_all(self, locallist = 0):
 		ddict = {}
                 if locallist:
@@ -1322,6 +1482,15 @@ class interfaceRecords(semanageRecords):
 
 		return ddict
 			
+        def customized(self):
+                l = []
+                ddict = self.get_all(True)
+                keys = ddict.keys()
+                keys.sort()
+                for k in keys:
+                       l.append("-a -t %s %s" % (ddict[k][2], k))
+                return l
+
 	def list(self, heading = 1, locallist = 0):
 		if heading:
 			print "%-30s %s\n" % (_("SELinux Interface"), _("Context"))
@@ -1338,6 +1507,48 @@ class interfaceRecords(semanageRecords):
 class fcontextRecords(semanageRecords):
 	def __init__(self, store = ""):
 		semanageRecords.__init__(self, store)
+                self.equiv = {}
+                self.equal_ind = False
+                try:
+                       fd = open(selinux.selinux_file_context_subs_path(), "r")
+                       for i in fd.readlines():
+                              src, dst = i.split()
+                              self.equiv[src] = dst
+                       fd.close()
+                except IOError:
+                       pass
+
+        def commit(self):
+                if self.equal_ind:
+                       subs_file = selinux.selinux_file_context_subs_path()
+                       tmpfile = "%s.tmp" % subs_file
+                       fd = open(tmpfile, "w")
+                       for src in self.equiv.keys():
+                              fd.write("%s %s\n" % (src, self.equiv[src]))
+                       fd.close()
+                       try:
+                              os.chmod(tmpfile, os.stat(subs_file)[stat.ST_MODE])
+                       except:
+                              pass
+                       os.rename(tmpfile,subs_file)
+                       self.equal_ind = False
+		semanageRecords.commit(self)
+
+        def add_equal(self, src, dst):
+                self.begin()
+                if src in self.equiv.keys():
+                       raise ValueError(_("Equivalence class for %s already exists") % src)
+                self.equiv[src] = dst
+                self.equal_ind = True
+                self.commit()
+
+        def modify_equal(self, src, dst):
+                self.begin()
+                if src not in self.equiv.keys():
+                       raise ValueError(_("Equivalence class for %s does not exists") % src)
+                self.equiv[src] = dst
+                self.equal_ind = True
+                self.commit()
 
         def createcon(self, target, seuser = "system_u"):
                 (rc, con) = semanage_context_create(self.sh)
@@ -1364,6 +1575,8 @@ class fcontextRecords(semanageRecords):
         def validate(self, target):
                if target == "" or target.find("\n") >= 0:
                       raise ValueError(_("Invalid file specification"))
+               if target.find(" ") != -1:
+                      raise ValueError(_("File specification can not include spaces"))
                       
 	def __add(self, target, type, ftype = "", serange = "", seuser = "system_u"):
                 self.validate(target)
@@ -1388,7 +1601,8 @@ class fcontextRecords(semanageRecords):
                               raise ValueError(_("Could not check if file context for %s is defined") % target)
 
                 if exists:
-                       raise ValueError(_("File context for %s already defined") % target)
+                       semanage_fcontext_key_free(k)
+                       return self.__modify(target, type, ftype, serange, seuser)
 
 		(rc, fcontext) = semanage_fcontext_create(self.sh)
 		if rc < 0:
@@ -1504,9 +1718,16 @@ class fcontextRecords(semanageRecords):
                               raise ValueError(_("Could not delete the file context %s") % target)
                        semanage_fcontext_key_free(k)
 	
+                self.equiv = {}
+                self.equal_ind = True
                 self.commit()
 
 	def __delete(self, target, ftype):
+                if target in self.equiv.keys():
+                       self.equiv.pop(target)
+                       self.equal_ind = True
+                       return
+
 		(rc,k) = semanage_fcontext_key_create(self.sh, target, file_types[ftype])
 		if rc < 0:
 			raise ValueError(_("Could not create a key for %s") % target)
@@ -1561,12 +1782,22 @@ class fcontextRecords(semanageRecords):
 
 		return ddict
 			
+        def customized(self):
+               l = []
+               fcon_dict = self.get_all(True)
+               keys = fcon_dict.keys()
+               keys.sort()
+               for k in keys:
+                      if fcon_dict[k]:
+                             l.append("-a -f '%s' -t %s '%s'" % (k[1], fcon_dict[k][2], k[0]))
+               return l
+
 	def list(self, heading = 1, locallist = 0 ):
-		if heading:
-			print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context"))
 		fcon_dict = self.get_all(locallist)
                 keys = fcon_dict.keys()
                 keys.sort()
+                if len(keys) > 0 and heading:
+			print "%-50s %-18s %s\n" % (_("SELinux fcontext"), _("type"), _("Context"))
 		for k in keys:
 			if fcon_dict[k]:
 				if is_mls_enabled:
@@ -1575,6 +1806,12 @@ class fcontextRecords(semanageRecords):
 					print "%-50s %-18s %s:%s:%s " % (k[0], k[1], fcon_dict[k][0], fcon_dict[k][1],fcon_dict[k][2])
 			else:
 				print "%-50s %-18s <<None>>" % (k[0], k[1])
+                if len(self.equiv.keys()) > 0:
+                       if heading:
+                              print _("\nSELinux fcontext Equivalence \n")
+                       
+                       for src in self.equiv.keys():
+                              print "%s = %s" % (src, self.equiv[src])
 				
 class booleanRecords(semanageRecords):
 	def __init__(self, store = ""):
@@ -1587,6 +1824,18 @@ class booleanRecords(semanageRecords):
                 self.dict["1"] = 1
                 self.dict["0"] = 0
 
+		try:
+			rc, self.current_booleans = selinux.security_get_boolean_names()
+			rc, ptype = selinux.selinux_getpolicytype()
+		except:
+			self.current_booleans = []
+			ptype = None
+
+		if self.store == None or self.store == ptype:
+			self.modify_local = True
+		else:
+			self.modify_local = False
+
 	def __mod(self, name, value):
                 (rc, k) = semanage_bool_key_create(self.sh, name)
                 if rc < 0:
@@ -1606,9 +1855,10 @@ class booleanRecords(semanageRecords):
                 else:
                        raise ValueError(_("You must specify one of the following values: %s") % ", ".join(self.dict.keys()) )
                 
-                rc = semanage_bool_set_active(self.sh, k, b)
-                if rc < 0:
-                       raise ValueError(_("Could not set active value of boolean %s") % name)
+		if self.modify_local and name in self.current_booleans:
+			rc = semanage_bool_set_active(self.sh, k, b)
+			if rc < 0:
+				raise ValueError(_("Could not set active value of boolean %s") % name)
                 rc = semanage_bool_modify_local(self.sh, k, b)
                 if rc < 0:
                        raise ValueError(_("Could not modify boolean %s") % name)
@@ -1691,8 +1941,12 @@ class booleanRecords(semanageRecords):
                        value = []
                        name = semanage_bool_get_name(boolean)
                        value.append(semanage_bool_get_value(boolean))
-                       value.append(selinux.security_get_boolean_pending(name))
-                       value.append(selinux.security_get_boolean_active(name))
+		       if self.modify_local and boolean in self.current_booleans:
+			       value.append(selinux.security_get_boolean_pending(name))
+			       value.append(selinux.security_get_boolean_active(name))
+		       else:
+			       value.append(value[0])
+			       value.append(value[0])
                        ddict[name] = value
 
 		return ddict
@@ -1706,6 +1960,16 @@ class booleanRecords(semanageRecords):
                else:
                       return _("unknown")
 
+        def customized(self):
+               l = []
+               ddict = self.get_all(True)
+               keys = ddict.keys()
+               keys.sort()
+               for k in keys:
+                      if ddict[k]:
+                             l.append("-%s %s" %  (ddict[k][2], k))
+               return l
+
 	def list(self, heading = True, locallist = False, use_file = False):
                 on_off = (_("off"), _("on")) 
 		if use_file:

[-- Attachment #3: policycoreutils-semanage.patch.sig --]
[-- Type: application/pgp-signature, Size: 72 bytes --]

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: semanage patch
  2006-04-15  3:49   ` Russell Coker
@ 2006-04-15 13:05     ` Steve Grubb
  0 siblings, 0 replies; 6+ messages in thread
From: Steve Grubb @ 2006-04-15 13:05 UTC (permalink / raw)
  To: russell; +Cc: Stephen Smalley, SE-Linux, Daniel J Walsh

On Friday 14 April 2006 23:49, Russell Coker wrote:
> It might be worth considering splitting auditctl into two programs, one for
> adding/removing rules and another for the rest.

Auditctl is a focused application that does only one job - configure the 
kernel side of the audit system. It doesn't do anything else.

-Steve

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: semanage patch
  2006-04-14 17:08 ` Stephen Smalley
@ 2006-04-15  3:49   ` Russell Coker
  2006-04-15 13:05     ` Steve Grubb
  0 siblings, 1 reply; 6+ messages in thread
From: Russell Coker @ 2006-04-15  3:49 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE-Linux, Daniel J Walsh, Steve Grubb

On Saturday 15 April 2006 03:08, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> On Fri, 2006-04-14 at 21:08 +1000, Russell Coker wrote:
> > The attached patch against the semanage utility in rawhide allows it to
> > create and modify prefixes.
>
> Thanks, merged as of policycoreutils 1.30.6.  Note that adding further
> examples in the man page to the EXAMPLES section introduced by Thomas
> Bleher would be helpful.

Updating the man page is the next stage.

> > Also when testing semanage I noticed that it let me remove a SE Linux
> > user when a login still referred to it.  After doing so it then wouldn't
> > let me recreate the user (with a confusing error message).  But as that
> > bug didn't stop me from doing my work I haven't taken the time to fix it.
> >
> > As the complexity of the semanage utility continues to increase I think
> > that we need to split it into separate programs selogin, seuser, seport,
> > seinterface, sefcontext, and setranslation.  This will make the man page
> > easier to understand and generally increase ease of use.  It will also
> > allow shell command-completion to do more of the work for the sysadmin. 
> > What do you think?
>
> Not clear to me whether this will ultimately be helpful to users or more
> confusing.  iptables, auditctl, etc. don't split up the interface like
> this.  More useful to users would likely just be a more extensive
> description in the man page and more examples there.

iptables doesn't split the interface because there are two main functions, 
adding/removing rules from tables and setting table policy for built-in 
tables.  The latter being such a small part of iptables functionality that it 
doesn't justify a separate program.

It might be worth considering splitting auditctl into two programs, one for 
adding/removing rules and another for the rest.

There are other examples of the benefits and problems of the two approaches.  
The best example I can think of is raidtools2 vs mdadm.  With raidtools2 
there was a separate program for each operation, to add a device to a 
degraded array it was "raidhotadd /dev/mdX /dev/hdcX", to remove a device 
from an array that was complete it was "raidsetfaulty /dev/mdX /dev/hdcX ; 
raidhotremove /dev/mdX /dev/hdcX".  The fact that I can still remember all 
the old raidtools2 commands but can't remember any of the mdadm commands is 
noteworthy.

But back to semanage, most of the classes of operations have different 
parameters.  The -r option to specify range is the most commonly used 
parameter (used in all classes of operations apart from translation).  The 
next most common option is -t which is used in 3/6 of the operation classes.

I think that the great divergance of functionality between the different 
operations that semanage performs is justification for separate programs.  
The user and login sections could be kept in the same program because they 
are tightly linked (in fact having a single command that creates both a user 
and a login at the same time along with an optional Unix account would be 
beneficial).  But the other four are different enough that I think they 
deserve separate programs.

-- 
http://www.coker.com.au/selinux/   My NSA Security Enhanced Linux packages
http://www.coker.com.au/bonnie++/  Bonnie++ hard drive benchmark
http://www.coker.com.au/postal/    Postal SMTP/POP benchmark
http://www.coker.com.au/~russell/  My home page

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: semanage patch
  2006-04-14 11:08 semanage patch Russell Coker
@ 2006-04-14 17:08 ` Stephen Smalley
  2006-04-15  3:49   ` Russell Coker
  0 siblings, 1 reply; 6+ messages in thread
From: Stephen Smalley @ 2006-04-14 17:08 UTC (permalink / raw)
  To: russell; +Cc: SE-Linux, Daniel J Walsh

On Fri, 2006-04-14 at 21:08 +1000, Russell Coker wrote:
> The attached patch against the semanage utility in rawhide allows it to create 
> and modify prefixes.

Thanks, merged as of policycoreutils 1.30.6.  Note that adding further
examples in the man page to the EXAMPLES section introduced by Thomas
Bleher would be helpful.

> Also when testing semanage I noticed that it let me remove a SE Linux user 
> when a login still referred to it.  After doing so it then wouldn't let me 
> recreate the user (with a confusing error message).  But as that bug didn't 
> stop me from doing my work I haven't taken the time to fix it.
> 
> As the complexity of the semanage utility continues to increase I think that 
> we need to split it into separate programs selogin, seuser, seport, 
> seinterface, sefcontext, and setranslation.  This will make the man page 
> easier to understand and generally increase ease of use.  It will also allow 
> shell command-completion to do more of the work for the sysadmin.  What do 
> you think?

Not clear to me whether this will ultimately be helpful to users or more
confusing.  iptables, auditctl, etc. don't split up the interface like
this.  More useful to users would likely just be a more extensive
description in the man page and more examples there.

-- 
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* semanage patch
@ 2006-04-14 11:08 Russell Coker
  2006-04-14 17:08 ` Stephen Smalley
  0 siblings, 1 reply; 6+ messages in thread
From: Russell Coker @ 2006-04-14 11:08 UTC (permalink / raw)
  To: SE-Linux; +Cc: Daniel J Walsh

[-- Attachment #1: Type: text/plain, Size: 1035 bytes --]

The attached patch against the semanage utility in rawhide allows it to create 
and modify prefixes.

Also when testing semanage I noticed that it let me remove a SE Linux user 
when a login still referred to it.  After doing so it then wouldn't let me 
recreate the user (with a confusing error message).  But as that bug didn't 
stop me from doing my work I haven't taken the time to fix it.

As the complexity of the semanage utility continues to increase I think that 
we need to split it into separate programs selogin, seuser, seport, 
seinterface, sefcontext, and setranslation.  This will make the man page 
easier to understand and generally increase ease of use.  It will also allow 
shell command-completion to do more of the work for the sysadmin.  What do 
you think?

-- 
http://www.coker.com.au/selinux/   My NSA Security Enhanced Linux packages
http://www.coker.com.au/bonnie++/  Bonnie++ hard drive benchmark
http://www.coker.com.au/postal/    Postal SMTP/POP benchmark
http://www.coker.com.au/~russell/  My home page

[-- Attachment #2: diff --]
[-- Type: text/x-diff, Size: 4170 bytes --]

--- seobject.py	2006-04-14 20:36:08.000000000 +1000
+++ /usr/lib/python2.4/site-packages/seobject.py	2006-04-14 20:56:04.000000000 +1000
@@ -381,7 +381,7 @@
 	def __init__(self):
 		semanageRecords.__init__(self)
 
-	def add(self, name, roles, selevel, serange):
+	def add(self, name, roles, selevel, serange, prefix):
 		if is_mls_enabled == 1:
 			if serange == "":
 				serange = "s0"
@@ -427,6 +427,9 @@
 				if rc < 0:
 					raise ValueError("Could not set MLS level for %s" % name)
 
+			rc = semanage_user_set_prefix(self.sh, u, prefix)
+			if rc < 0:
+				raise ValueError("Could not add prefix %s for %s" % (r, prefix))
 			(rc,key) = semanage_user_key_extract(self.sh,u)
 			if rc < 0:
 				raise ValueError("Could not extract key for %s" % name)
@@ -451,13 +454,13 @@
 		semanage_user_key_free(k)
 		semanage_user_free(u)
 
-	def modify(self, name, roles = [], selevel = "", serange = ""):
+	def modify(self, name, roles = [], selevel = "", serange = "", prefix = ""):
 		try:
-			if len(roles) == 0  and serange == "" and selevel == "":
+			if prefix == "" and len(roles) == 0  and serange == "" and selevel == "":
 				if is_mls_enabled == 1:
-					raise ValueError("Requires roles, level or range")
+					raise ValueError("Requires prefix, roles, level or range")
 				else:
-					raise ValueError("Requires roles")
+					raise ValueError("Requires prefix or roles")
 
 			(rc,k) = semanage_user_key_create(self.sh, name)
 			if rc < 0:
@@ -478,6 +481,9 @@
 			if selevel != "":
 				semanage_user_set_mlslevel(self.sh, u, untranslate(selevel))
 
+			if prefix != "":
+				semanage_user_set_prefix(self.sh, u, prefix)
+
 			if len(roles) != 0:
 				for r in roles:
 					semanage_user_add_role(self.sh, u, r)
--- semanage	2006-04-14 20:46:23.000000000 +1000
+++ /usr/sbin/semanage	2006-04-14 20:56:56.000000000 +1000
@@ -32,7 +32,7 @@
 		print '\
 semanage {login|user|port|interface|fcontext|translation} -l [-n] \n\
 semanage login -{a|d|m} [-sr] login_name\n\
-semanage user -{a|d|m} [-LrR] selinux_name\n\
+semanage user -{a|d|m} [-LrRP] selinux_name\n\
 semanage port -{a|d|m} [-tr] [ -p protocol ] port | port_range\n\
 semanage interface -{a|d|m} [-tr] interface_spec\n\
 semanage fcontext -{a|d|m} [-frst] file_spec\n\
@@ -60,6 +60,7 @@
 		-p (named pipe) \n\n\
 \
 	-p, --proto      Port protocol (tcp or udp)\n\
+	-P, --prefix     Prefix for home directory labeling\n\
 	-L, --level      Default SELinux Level (MLS/MCS Systems only)\n\
 	-R, --roles      SELinux Roles (ex: "sysadm_r staff_r")\n\
 	-T, --trans      SELinux Level Translation (MLS/MCS Systems only)\n\n\
@@ -83,7 +84,7 @@
 		valid_option["login"] = []
 		valid_option["login"] += valid_everyone + [ '-s', '--seuser', '-r', '--range']
 		valid_option["user"] = []
-		valid_option["user"] += valid_everyone + [ '-L', '--level', '-r', '--range', '-R', '--roles' ] 
+		valid_option["user"] += valid_everyone + [ '-L', '--level', '-r', '--range', '-R', '--roles', '-P', '--prefix' ] 
 		valid_option["port"] = []
 		valid_option["port"] += valid_everyone + [ '-t', '--type', '-r', '--range', '-p', '--protocol' ] 
 		valid_option["interface"] = []
@@ -109,6 +110,7 @@
 		setrans = ""
 		roles = ""
 		seuser = ""
+		prefix = ""
 		heading=1
 
 		add = 0
@@ -126,7 +128,7 @@
 		args = sys.argv[2:]
 
 		gopts, cmds = getopt.getopt(args,
-					    'adf:lhmnp:s:R:L:r:t:T:',
+					    'adf:lhmnp:s:R:L:r:t:T:P:',
 					    ['add',
 					     'delete',
 					     'ftype=',
@@ -140,7 +142,8 @@
 					     'level=',
 					     'roles=',
 					     'type=',
-					     'trans='
+					     'trans=',
+					     'prefix='
 					     ])
 		for o, a in gopts:
 			if o not in option_dict[object]:
@@ -185,6 +188,9 @@
 			if o == "-p" or o == '--proto':
 				proto = a
 
+			if o == "-P" or o == '--prefix':
+				prefix = a
+
 			if o == "-R" or o == '--roles':
 				roles = roles + " " + a
 
@@ -235,7 +241,7 @@
 				rlist = roles.split()
 				if len(rlist) == 0:
 					raise ValueError("You must specify a role")
-				OBJECT.add(target, rlist, selevel, serange)
+				OBJECT.add(target, rlist, selevel, serange, prefix)
 
 			if object == "port":
 				OBJECT.add(target, proto, serange, setype)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* semanage patch
@ 2006-01-14 11:19 Russell Coker
  0 siblings, 0 replies; 6+ messages in thread
From: Russell Coker @ 2006-01-14 11:19 UTC (permalink / raw)
  To: SE-Linux, Daniel Walsh

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

The attached patch fixes a bug in a check for user existence that prevented 
adding a new user, allows specifying the default level for users via the -L 
option, and fixes a mis-spelling of "delete" in code.

Also attached a re-written man page that uses better formatting and more 
precision in the SYNOPSIS section.  The changes were significant enough that 
diff wouldn't do anything useful.

-- 
http://www.coker.com.au/selinux/   My NSA Security Enhanced Linux packages
http://www.coker.com.au/bonnie++/  Bonnie++ hard drive benchmark
http://www.coker.com.au/postal/    Postal SMTP/POP benchmark
http://www.coker.com.au/~russell/  My home page

[-- Attachment #2: diff --]
[-- Type: text/x-diff, Size: 1233 bytes --]

--- seobject.py.orig	2006-01-15 07:06:59.000000000 +1100
+++ seobject.py	2006-01-15 07:07:03.000000000 +1100
@@ -134,7 +134,7 @@
 			raise ValueError("Could not create a key for %s" % name)
 
 		(rc,exists) = semanage_user_exists(self.sh, k)
-		if not exists:
+		if exists:
 			raise ValueError("SELinux user %s is already defined." % name)
 
 		(rc,u) = semanage_user_create(self.sh)
--- semanage.orig	2006-01-15 07:03:30.000000000 +1100
+++ semanage	2006-01-15 07:08:52.000000000 +1100
@@ -84,7 +84,7 @@
 			
 		args = sys.argv[2:]
 		gopts, cmds = getopt.getopt(args,
-					    'adf:lhmnp:P:s:R:r:t:v',
+					    'adf:lhmnp:P:s:R:L:r:t:v',
 					    ['add',
 					     'delete',
 					     'ftype=',
@@ -96,6 +96,7 @@
 					     'proto=',
 					     'seuser=',
 					     'range=',
+					     'level=',
 					     'roles=',
 					     'type=',
 					     'verbose'
@@ -106,7 +107,7 @@
 					usage()
 				add = 1
 				
-			if o == "-d"  or o == "--delese":
+			if o == "-d"  or o == "--delete":
 				if modify or add:
 					usage()
 				delete = 1
@@ -126,6 +127,9 @@
 			if o == "-r" or o == '--range':
 				serange = a
 
+			if o == "-L" or o == '--level':
+				selevel = a
+
 			if o == "-P" or o == '--proto':
 				proto = a
 

[-- Attachment #3: semanage.8 --]
[-- Type: application/x-troff, Size: 1299 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-12-14 13:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <C92C0B59.BBA5F%csellers@tresys.com>
2010-12-14 13:23 ` Semanage Patch Daniel J Walsh
2006-04-14 11:08 semanage patch Russell Coker
2006-04-14 17:08 ` Stephen Smalley
2006-04-15  3:49   ` Russell Coker
2006-04-15 13:05     ` Steve Grubb
  -- strict thread matches above, loose matches on Subject: below --
2006-01-14 11:19 Russell Coker

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.