Bläddra i källkod

Ticket 49814 - dscreate should set the port selinux labels

Description:

dscreate was not setting the selinux labels on the ports, so if you specified
a non-standard port the instance would not start.  This fix sets/removes
selinux labels during instance creation and removal

Also moved ds_selinux_port_query & ds_selinux_enabled to the legacy tools
package as they are only used by setup-ds.pl

https://pagure.io/389-ds-base/issue/49814

Reviewed by: firstyear & mhonek (Thanks!!)
Mark Reynolds 7 år sedan
förälder
incheckning
3571bac00b

+ 3 - 3
rpm/389-ds-base.spec.in

@@ -55,7 +55,7 @@ Name:             389-ds-base
 Version:          __VERSION__
 Release:          __RELEASE__%{?dist}
 License:          GPLv3+
-URL:              http://www.port389.org/
+URL:              https://www.port389.org/
 Group:            System Environment/Daemons
 # Is this still needed?
 BuildRoot:        %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -623,8 +623,6 @@ exit 0
 # We have to seperate this from being a glob to ensure the caps are applied.
 %caps(CAP_NET_BIND_SERVICE=pe) %{_sbindir}/ns-slapd
 %{_mandir}/man8/ns-slapd.8.gz
-%{_libexecdir}/%{pkgname}/ds_selinux_enabled
-%{_libexecdir}/%{pkgname}/ds_selinux_port_query
 %{_libexecdir}/%{pkgname}/ds_systemd_ask_password_acl
 %{_sbindir}/bak2db
 %{_mandir}/man8/bak2db.8.gz
@@ -794,6 +792,8 @@ exit 0
 %{_sbindir}/verify-db.pl
 %{_mandir}/man8/verify-db.pl.8.gz
 %{_libdir}/%{pkgname}/perl
+%{_libexecdir}/%{pkgname}/ds_selinux_enabled
+%{_libexecdir}/%{pkgname}/ds_selinux_port_query
 %endif
 
 %files snmp

+ 6 - 0
src/lib389/lib389/instance/remove.py

@@ -9,6 +9,7 @@
 import os
 import shutil
 import subprocess
+from lib389.utils import selinux_label_port
 
 
 def remove_ds_instance(dirsrv):
@@ -76,6 +77,11 @@ def remove_ds_instance(dirsrv):
     _log.debug("Removing the systemd symlink")
     subprocess.check_call(["systemctl", "disable", "dirsrv@{}".format(dirsrv.serverid)])
 
+    # Remove selinux port label
+    selinux_label_port(dirsrv.port, remove_label=True)
+    if dirsrv.sslport is not None:
+        selinux_label_port(dirsrv.sslport, remove_label=True)
+
     # Done!
     _log.debug("Complete")
 

+ 10 - 4
src/lib389/lib389/instance/setup.py

@@ -29,7 +29,8 @@ from lib389.utils import (
     assert_c,
     is_a_dn,
     ensure_str,
-    socket_check_open,)
+    socket_check_open,
+    selinux_label_port)
 
 ds_paths = Paths()
 
@@ -226,7 +227,7 @@ class SetupDs(object):
                  'sysconf_dir': ds_paths.sysconf_dir,
                  'data_dir': ds_paths.data_dir,
                  'local_state_dir': ds_paths.local_state_dir,
-                 'ldapi' : ds_paths.ldapi,
+                 'ldapi': ds_paths.ldapi,
                  'lib_dir': ds_paths.lib_dir,
                  'run_dir': ds_paths.run_dir,
                  'tmp_dir': ds_paths.tmp_dir,
@@ -339,6 +340,8 @@ class SetupDs(object):
                 # Port 636 is already taken, pick another port
                 port = get_port(slapd['secure_port'], "", secure=True)
             slapd['secure_port'] = port
+        else:
+            slapd['secure_port'] = False
 
         # Root DN
         while 1:
@@ -548,8 +551,6 @@ class SetupDs(object):
             assert_c('cn' in be)
         # Add an assertion that we don't double suffix or double CN here ...
 
-
-
     def create_from_args(self, general, slapd, backends=[], extra=None):
         """
         Actually does the setup. this is what you want to call as an api.
@@ -753,10 +754,15 @@ class SetupDs(object):
             csr = tlsdb.create_rsa_key_and_csr()
             (ca, crt) = ssca.rsa_ca_sign_csr(csr)
             tlsdb.import_rsa_crt(ca, crt)
+            if not self.containerised and general['selinux']:
+                # Set selinux port label
+                selinux_label_port(slapd['secure_port'])
 
         ## LAST CHANCE, FIX PERMISSIONS.
         # Selinux fixups?
         # Restorecon of paths?
+        if not self.containerised and general['selinux']:
+            selinux_label_port(slapd['port'])
 
         # Start the server
         # Make changes using the temp root

+ 47 - 0
src/lib389/lib389/utils.py

@@ -34,6 +34,9 @@ import sys
 import filecmp
 import six
 import shlex
+import selinux
+import sepolicy
+import subprocess
 from socket import getfqdn
 from ldapurl import LDAPUrl
 from contextlib import closing
@@ -170,6 +173,50 @@ _chars = {
 #
 
 
+def selinux_label_port(port, remove_label=False):
+    """
+    Either set or remove an SELinux label(ldap_port_t) for a TCP port
+
+    :param port: The TCP port to be labelled
+    :type port: str
+    :param remove_label: Set True if the port label should be removed
+    :type remove_label: boolean
+    :raises: ValueError: Error message
+    """
+
+    if not selinux.is_selinux_enabled():
+        return
+
+    label_set = False
+    label_ex = None
+
+    policies = [p for p in sepolicy.info(sepolicy.PORT)
+                if p['protocol'] == 'tcp'
+                if port in range(p['low'], p['high'] + 1)
+                if p['type'] not in ['unreserved_port_t', 'reserved_port_t', 'ephemeral_port_t']]
+
+    for policy in policies:
+        if "ldap_port_t" == policy['type']:
+            label_set = True  # Port already has our label
+            break
+        else:
+            # Port belongs to someone else (bad)
+            raise ValueError("Port " + port + " was already labelled with: " + policy['type'])
+
+    if (remove_label and label_set) or (not remove_label and not label_set):
+        for i in range(3):
+            try:
+                subprocess.check_call(["semanage", "port",
+                                       "-d" if remove_label else "-a",
+                                       "-t", "ldap_port_t",
+                                       "-p", "tcp", str(port)])
+                return
+            except (OSError, subprocess.CalledProcessError) as e:
+                label_ex = e
+                time.sleep(3)
+        raise ValueError("Failed to mangle port label: " + str(label_ex))
+
+
 def is_a_dn(dn, allow_anon=True):
     """Returns True if the given string is a DN, False otherwise."""
     try: