1#!/usr/bin/python3 2 3import dbus 4import dbus.service 5import dbus.mainloop.glib 6from gi.repository import GObject 7import slip.dbus.service 8from slip.dbus import polkit 9import os 10import selinux 11from subprocess import Popen, PIPE, STDOUT 12 13 14class selinux_server(slip.dbus.service.Object): 15 default_polkit_auth_required = "org.selinux.semanage" 16 17 def __init__(self, *p, **k): 18 super(selinux_server, self).__init__(*p, **k) 19 20 # 21 # The semanage method runs a transaction on a series of semanage commands, 22 # these commands can take the output of customized 23 # 24 @slip.dbus.polkit.require_auth("org.selinux.semanage") 25 @dbus.service.method("org.selinux", in_signature='s') 26 def semanage(self, buf): 27 p = Popen(["/usr/sbin/semanage", "import"], stdout=PIPE, stderr=PIPE, stdin=PIPE, universal_newlines=True) 28 p.stdin.write(buf) 29 output = p.communicate() 30 if p.returncode and p.returncode != 0: 31 raise dbus.exceptions.DBusException(output[1]) 32 33 # 34 # The customized method will return all of the custommizations for policy 35 # on the server. This output can be used with the semanage method on 36 # another server to make the two systems have duplicate policy. 37 # 38 @slip.dbus.polkit.require_auth("org.selinux.customized") 39 @dbus.service.method("org.selinux", in_signature='', out_signature='s') 40 def customized(self): 41 p = Popen(["/usr/sbin/semanage", "export"], stdout=PIPE, stderr=PIPE, universal_newlines=True) 42 buf = p.stdout.read() 43 output = p.communicate() 44 if p.returncode and p.returncode != 0: 45 raise OSError("Failed to read SELinux configuration: %s", output) 46 return buf 47 48 # 49 # The semodule_list method will return the output of semodule --list=full, using the customized polkit, 50 # since this is a readonly behaviour 51 # 52 @slip.dbus.polkit.require_auth("org.selinux.semodule_list") 53 @dbus.service.method("org.selinux", in_signature='', out_signature='s') 54 def semodule_list(self): 55 p = Popen(["/usr/sbin/semodule", "--list=full"], stdout=PIPE, stderr=PIPE, universal_newlines=True) 56 buf = p.stdout.read() 57 output = p.communicate() 58 if p.returncode and p.returncode != 0: 59 raise OSError("Failed to list SELinux modules: %s", output) 60 return buf 61 62 # 63 # The restorecon method modifies any file path to the default system label 64 # 65 @slip.dbus.polkit.require_auth("org.selinux.restorecon") 66 @dbus.service.method("org.selinux", in_signature='s') 67 def restorecon(self, path): 68 selinux.restorecon(str(path), recursive=1) 69 70 # 71 # The setenforce method turns off the current enforcement of SELinux 72 # 73 @slip.dbus.polkit.require_auth("org.selinux.setenforce") 74 @dbus.service.method("org.selinux", in_signature='i') 75 def setenforce(self, value): 76 selinux.security_setenforce(value) 77 78 # 79 # The setenforce method turns off the current enforcement of SELinux 80 # 81 @slip.dbus.polkit.require_auth("org.selinux.relabel_on_boot") 82 @dbus.service.method("org.selinux", in_signature='i') 83 def relabel_on_boot(self, value): 84 if value == 1: 85 fd = open("/.autorelabel", "w") 86 fd.close() 87 else: 88 try: 89 os.unlink("/.autorelabel") 90 except FileNotFoundError: 91 pass 92 93 def write_selinux_config(self, enforcing=None, policy=None): 94 path = selinux.selinux_path() + "config" 95 backup_path = path + ".bck" 96 fd = open(path) 97 lines = fd.readlines() 98 fd.close() 99 fd = open(backup_path, "w") 100 for l in lines: 101 if enforcing and l.startswith("SELINUX="): 102 fd.write("SELINUX=%s\n" % enforcing) 103 continue 104 if policy and l.startswith("SELINUXTYPE="): 105 fd.write("SELINUXTYPE=%s\n" % policy) 106 continue 107 fd.write(l) 108 fd.close() 109 os.rename(backup_path, path) 110 111 # 112 # The change_default_enforcement modifies the current enforcement mode 113 # 114 @slip.dbus.polkit.require_auth("org.selinux.change_default_mode") 115 @dbus.service.method("org.selinux", in_signature='s') 116 def change_default_mode(self, value): 117 values = ["enforcing", "permissive", "disabled"] 118 if value not in values: 119 raise ValueError("Enforcement mode must be %s" % ", ".join(values)) 120 self.write_selinux_config(enforcing=value) 121 122 # 123 # The change_default_policy method modifies the policy type 124 # 125 @slip.dbus.polkit.require_auth("org.selinux.change_default_policy") 126 @dbus.service.method("org.selinux", in_signature='s') 127 def change_default_policy(self, value): 128 path = selinux.selinux_path() + value 129 if os.path.isdir(path): 130 return self.write_selinux_config(policy=value) 131 raise ValueError("%s does not exist" % path) 132 133if __name__ == "__main__": 134 mainloop = GObject.MainLoop() 135 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 136 system_bus = dbus.SystemBus() 137 name = dbus.service.BusName("org.selinux", system_bus) 138 object = selinux_server(system_bus, "/org/selinux/object") 139 slip.dbus.service.set_mainloop(mainloop) 140 mainloop.run() 141