From 3571bac00b5312e38f9705eb888ce56c7782516d Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Oct 24 2018 16:51:00 +0000 Subject: 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!!) --- diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in index 0756264..8c72b83 100644 --- a/rpm/389-ds-base.spec.in +++ b/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 diff --git a/src/lib389/lib389/instance/remove.py b/src/lib389/lib389/instance/remove.py index c628b9e..0245db7 100644 --- a/src/lib389/lib389/instance/remove.py +++ b/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") diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py index 5b0c421..0f4a257 100644 --- a/src/lib389/lib389/instance/setup.py +++ b/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 diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py index beecd3a..68a06e3 100644 --- a/src/lib389/lib389/utils.py +++ b/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: