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