Example #1
0
def cacert_list(inst, basedn, log, args):
    """List all CA certs
    """
    cert_list = []
    tlsdb = NssSsl(dirsrv=inst)
    certs = tlsdb.list_certs(ca=True)
    for cert in certs:
        if args.json:
            cert_list.append({
                "type": "certificate",
                "attrs": {
                    'nickname': cert[0],
                    'subject': cert[1],
                    'issuer': cert[2],
                    'expires': cert[3],
                    'flags': cert[4],
                }
            })
        else:
            log.info('Certificate Name: {}'.format(cert[0]))
            log.info('Subject DN: {}'.format(cert[1]))
            log.info('Issuer DN: {}'.format(cert[2]))
            log.info('Expires: {}'.format(cert[3]))
            log.info('Trust Flags: {}\n'.format(cert[4]))
    if args.json:
        log.info(json.dumps(cert_list, indent=4))
Example #2
0
def test_nss_ssca_users(topo):
    """
    Validate that we can submit user certs to the ds ca for signing.

    :id: a47e47ed-2056-440b-8797-d13fa89098f6
    :steps:
        1. Find the ssca path.
        2. Assert it exists
        3. Create user certificates from the ssca
    :expectedresults:
        1. It works.
        2. It works.
        3. It works.
    """
    ssca = NssSsl(dbpath=topo.standalone.get_ssca_dir())

    if not ssca._rsa_ca_exists():
        ssca.reinit()
        ssca.create_rsa_ca()

    # It better exist now!
    assert(ssca._rsa_ca_exists() is True)

    # Check making users certs. They should never conflict
    for user in ('william', 'noriko', 'mark'):
        # Create the user cert
        assert(ssca.create_rsa_user(user) is True)
        # Assert it exists now
        assert(ssca._rsa_user_exists(user) is True)
Example #3
0
def cert_get(inst, basedn, log, args):
    """Get the details about a server certificate
    """
    tlsdb = NssSsl(dirsrv=inst)
    details = tlsdb.get_cert_details(args.name)
    if args.json:
        log.info(
            json.dumps(
                {
                    "type": "certificate",
                    "attrs": {
                        'nickname': details[0],
                        'subject': details[1],
                        'issuer': details[2],
                        'expires': details[3],
                        'flags': details[4],
                    }
                },
                indent=4))
    else:
        log.info('Certificate Name: {}'.format(details[0]))
        log.info('Subject DN: {}'.format(details[1]))
        log.info('Issuer DN: {}'.format(details[2]))
        log.info('Expires: {}'.format(details[3]))
        log.info('Trust Flags: {}'.format(details[4]))
Example #4
0
def test_init(topology_st):
    """
    Generate self signed cert and import it to the DS cert db.
    Enable SSL
    """
    _header(topology_st, 'Testing Ticket 48194 - harden the list of ciphers available by default')

    nss_ssl = NssSsl(dbpath=topology_st.standalone.get_cert_dir())
    nss_ssl.reinit()
    nss_ssl.create_rsa_ca()
    nss_ssl.create_rsa_key_and_cert()

    log.info("\n######################### enable SSL in the directory server with all ciphers ######################\n")
    topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
    topology_st.standalone.modify_s(ENCRYPTION_DN, [(ldap.MOD_REPLACE, 'nsSSL3', b'off'),
                                                    (ldap.MOD_REPLACE, 'nsTLS1', b'on'),
                                                    (ldap.MOD_REPLACE, 'nsSSLClientAuth', b'allowed'),
                                                    (ldap.MOD_REPLACE, 'allowWeakCipher', b'on'),
                                                    (ldap.MOD_REPLACE, 'nsSSL3Ciphers', b'+all')])

    topology_st.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-security', b'on'),
                                                (ldap.MOD_REPLACE, 'nsslapd-ssl-check-hostname', b'off'),
                                                (ldap.MOD_REPLACE, 'nsslapd-secureport', ensure_bytes(LDAPSPORT))])

    if ds_is_older('1.4.0'):
        topology_st.standalone.add_s(Entry((RSA_DN, {'objectclass': "top nsEncryptionModule".split(),
                                                     'cn': RSA,
                                                     'nsSSLPersonalitySSL': SERVERCERT,
                                                     'nsSSLToken': 'internal (software)',
                                                     'nsSSLActivation': 'on'})))
Example #5
0
def security_enable(inst, basedn, log, args):
    dbpath = inst.get_cert_dir()
    tlsdb = NssSsl(dbpath=dbpath)
    certs = tlsdb.list_certs()
    if len(certs) == 0:
        raise ValueError('There are no server certificates in the security ' +
                         'database, security can not be enabled.')

    if len(certs) == 1:
        # If there is only cert make sure it is set as the server certificate
        RSA(inst).set('nsSSLPersonalitySSL', certs[0][0])
    elif args.cert_name is not None:
        # A certificate nickname was provided, set it as the server certificate
        RSA(inst).set('nsSSLPersonalitySSL', args.cert_name)

    # it should now be safe to enable security
    Config(inst).set('nsslapd-security', 'on')
Example #6
0
def enable_ssl(server, ldapsport):
    server.stop()
    nss_ssl = NssSsl(dbpath=server.get_cert_dir())
    nss_ssl.reinit()
    nss_ssl.create_rsa_ca()
    nss_ssl.create_rsa_key_and_cert()
    server.start()
    server.config.set('nsslapd-secureport', '%s' % ldapsport)
    server.config.set('nsslapd-security', 'on')
    server.sslport = SECUREPORT_STANDALONE1
    server.restart()
Example #7
0
def cacert_add(inst, basedn, log, args):
    """Add CA certificate
    """
    # Verify file and certificate name
    os.path.isfile(args.file)
    tlsdb = NssSsl(dirsrv=inst)
    if not tlsdb._db_exists(even_partial=True):  # we want to be very careful
        log.info('Security database does not exist. Creating a new one in {}.'.
                 format(inst.get_cert_dir()))
        tlsdb.reinit()

    try:
        tlsdb.get_cert_details(args.name)
        raise ValueError("Certificate already exists with the same name")
    except ValueError:
        pass

    # Add the cert
    tlsdb.add_cert(args.name, args.file, ca=True)
Example #8
0
def import_ca(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    cert_path = args.cert_path
    nickname = args.nickname
    if nickname.lower() == CERT_NAME.lower() or nickname.lower(
    ) == CA_NAME.lower():
        log.error("You may not import a CA with the nickname %s or %s" %
                  (CERT_NAME, CA_NAME))
        return
    tls.add_cert(nickname=nickname, input_file=cert_path)
    tls.edit_cert_trust(nickname, "C,,")
Example #9
0
def cert_add(inst, basedn, log, args):
    """Add server certificate
    """
    # Verify file and certificate name
    os.path.isfile(args.file)
    tlsdb = NssSsl(dirsrv=inst)
    if not tlsdb._db_exists(even_partial=True):  # we want to be very careful
        log.info('Security database does not exist. Creating a new one in {}.'.
                 format(inst.get_cert_dir()))
        tlsdb.reinit()

    try:
        tlsdb.get_cert_details(args.name)
        raise ValueError("Certificate already exists with the same name")
    except ValueError:
        pass

    if args.primary_cert:
        # This is the server's primary certificate, update RSA entry
        RSA(inst).set('nsSSLPersonalitySSL', args.name)

    # Add the cert
    tlsdb.add_cert(args.name, args.file)
Example #10
0
def test_positive(topo):
    """Test User certificate field

        :id: e984ac40-63d1-4176-ad1e-0cbe71391b5f
        :setup: Standalone
        :steps:
            1. Create entries with userCertificate field.
            2. Try to search/filter them with userCertificate field.
        :expected results:
            1. Pass
            2. Pass
    """
    # SETUP TLS
    topo.standalone.stop()
    NssSsl(topo.standalone).reinit()
    NssSsl(topo.standalone).create_rsa_ca()
    NssSsl(topo.standalone).create_rsa_key_and_cert()
    # Create  user
    NssSsl(topo.standalone).create_rsa_user('testuser1')
    NssSsl(topo.standalone).create_rsa_user('testuser2')
    # Creating cert users
    topo.standalone.start()
    users_people = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
    for count in range(1, 3):
        user = users_people.create_test_user(uid=count, gid=count)
        tls_locs = NssSsl(topo.standalone).get_rsa_user(f'testuser{count}')
        #  {'ca': ca_path, 'key': key_path, 'crt': crt_path}
        user.enroll_certificate(tls_locs['crt_der_path'])

    assert Accounts(topo.standalone,
                    DEFAULT_SUFFIX).filter("(usercertificate=*)")
    assert Accounts(topo.standalone,
                    DEFAULT_SUFFIX).filter("(userCertificate;binary=*)")
    user1_cert = users_people.list()[0].get_attr_val("userCertificate;binary")
    assert Accounts(topo.standalone, DEFAULT_SUFFIX).filter(
        f'(userCertificate;binary={search_filter_escape_bytes(user1_cert)})')[0].dn == \
           'uid=test_user_1,ou=people,dc=example,dc=com'
    user2_cert = users_people.list()[1].get_attr_val("userCertificate;binary")
    assert Accounts(topo.standalone, DEFAULT_SUFFIX).filter(
        f'(userCertificate;binary={search_filter_escape_bytes(user2_cert)})')[0].dn == \
           'uid=test_user_2,ou=people,dc=example,dc=com'
def test_tls_import_chain(topology_st):
    """Test that TLS import will correct report errors when there are multiple
    files in a chain.

    :id: b7ba71bd-112a-44a1-8a7e-8968249da419

    :steps:
        1. Attempt to import a ca chain

    :expectedresults:
        1. The chain is rejected
    """
    topology_st.standalone.stop()
    tls = NssSsl(dirsrv=topology_st.standalone)
    tls.reinit()

    with pytest.raises(ValueError):
        tls.add_cert(nickname='CA_CHAIN_1', input_file=CA_CHAIN_FILE)

    with pytest.raises(ValueError):
        tls.add_server_key_and_cert(KEY_FILE, CRT_CHAIN_FILE)
    with pytest.raises(ValueError):
        tls.add_server_key_and_cert(KEY_CHAIN_FILE, CRT_CHAIN_FILE)
    with pytest.raises(ValueError):
        tls.add_server_key_and_cert(KEY_FILE, KEY_CHAIN_FILE)

    with pytest.raises(ValueError):
        tls.import_rsa_crt(crt=CRT_CHAIN_FILE)
    with pytest.raises(ValueError):
        tls.import_rsa_crt(ca=CA_CHAIN_FILE)
Example #12
0
def show_servercert(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    log.info(tls.display_cert_details(CERT_NAME))
Example #13
0
def show_cert(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    nickname = args.nickname
    log.info(tls.display_cert_details(nickname))
Example #14
0
def generate_key_csr(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    alt_names = args.alt_names
    subject = args.subject
    out_path = tls.create_rsa_key_and_csr(alt_names, subject)
    log.info(out_path)
Example #15
0
def import_key_cert_pair(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    key_path = args.key_path
    cert_path = args.cert_path
    tls.add_server_key_and_cert(key_path, cert_path)
Example #16
0
    def _install_ds(self, general, slapd, backends):
        """
        Actually install the Ds from the dicts provided.

        You should never call this directly, as it bypasses assertions.
        """
        ######################## WARNING #############################
        # DO NOT CHANGE THIS FUNCTION OR ITS CONTENTS WITHOUT READING
        # ALL OF THE COMMENTS FIRST. THERE ARE VERY DELICATE
        # AND DETAILED INTERACTIONS OF COMPONENTS IN THIS FUNCTION.
        #
        # IF IN DOUBT CONTACT WILLIAM BROWN <*****@*****.**>

        ### This first section is about creating the *minimal* required paths and config to get
        # directory server to start: After this, we then perform all configuration as online
        # changes from after this point.

        # Create dse.ldif with a temporary root password.
        # This is done first, because instances are found for removal and listing by detecting
        # the present of their dse.ldif!!!!
        # The template is in slapd['data_dir']/dirsrv/data/template-dse.ldif
        # Variables are done with %KEY%.
        self.log.debug("ACTION: Creating dse.ldif")
        try:
            os.umask(
                0o007
            )  # For parent dirs that get created -> sets 770 for perms
            os.makedirs(slapd['config_dir'], mode=0o770)
        except OSError:
            pass

        # Get suffix for some plugin defaults (if possible)
        # annoyingly for legacy compat backend takes TWO key types
        # and we have to now deal with that ....
        #
        # Create ds_suffix here else it won't be in scope ....
        ds_suffix = ''
        if len(backends) > 0:
            ds_suffix = normalizeDN(backends[0]['nsslapd-suffix'])

        dse = ""
        with open(
                os.path.join(slapd['data_dir'], 'dirsrv', 'data',
                             'template-dse.ldif')) as template_dse:
            for line in template_dse.readlines():
                dse += line.replace('%', '{', 1).replace('%', '}', 1)

        # Check if we are in a container, if so don't use /dev/shm for the db home dir
        # as containers typically don't allocate enough space for dev/shm and we don't
        # want to unexpectedly break the server after an upgrade
        #
        # If we know we are are in a container, we don't need to re-detect on systemd.
        # It actually turns out if you add systemd-detect-virt, that pulls in system
        # which subsequently breaks containers starting as instance.start then believes
        # it COULD check the ds status. The times we need to check for systemd are mainly
        # in other environments that use systemd natively in their containers.
        container_result = 1
        if not self.containerised:
            container_result = subprocess.run(["systemd-detect-virt", "-c"],
                                              stdout=subprocess.PIPE)
        if self.containerised or container_result.returncode == 0:
            # In a container, set the db_home_dir to the db path
            self.log.debug(
                "Container detected setting db home directory to db directory."
            )
            slapd['db_home_dir'] = slapd['db_dir']

        with open(os.path.join(slapd['config_dir'], 'dse.ldif'),
                  'w') as file_dse:
            dse_fmt = dse.format(
                schema_dir=slapd['schema_dir'],
                lock_dir=slapd['lock_dir'],
                tmp_dir=slapd['tmp_dir'],
                cert_dir=slapd['cert_dir'],
                ldif_dir=slapd['ldif_dir'],
                bak_dir=slapd['backup_dir'],
                run_dir=slapd['run_dir'],
                inst_dir=slapd['inst_dir'],
                log_dir=slapd['log_dir'],
                fqdn=general['full_machine_name'],
                ds_port=slapd['port'],
                ds_user=slapd['user'],
                rootdn=slapd['root_dn'],
                instance_name=slapd['instance_name'],
                ds_passwd=self.
                _secure_password,  # We set our own password here, so we can connect and mod.
                # This is because we never know the users input root password as they can validly give
                # us a *hashed* input.
                ds_suffix=ds_suffix,
                config_dir=slapd['config_dir'],
                db_dir=slapd['db_dir'],
                db_home_dir=slapd['db_home_dir'],
                db_lib=slapd['db_lib'],
                ldapi_enabled="on",
                ldapi=slapd['ldapi'],
                ldapi_autobind="on",
            )
            file_dse.write(dse_fmt)

        self.log.info("Create file system structures ...")
        # Create all the needed paths
        # we should only need to make bak_dir, cert_dir, config_dir, db_dir, ldif_dir, lock_dir, log_dir, run_dir?
        for path in ('backup_dir', 'cert_dir', 'db_dir', 'db_home_dir',
                     'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'):
            self.log.debug("ACTION: creating %s", slapd[path])
            try:
                os.umask(
                    0o007
                )  # For parent dirs that get created -> sets 770 for perms
                os.makedirs(slapd[path], mode=0o770)
            except OSError:
                pass
            os.chown(slapd[path], slapd['user_uid'], slapd['group_gid'])

        # /var/lock/dirsrv needs special attention...
        parentdir = os.path.abspath(os.path.join(slapd['lock_dir'], os.pardir))
        os.chown(parentdir, slapd['user_uid'], slapd['group_gid'])

        ### Warning! We need to down the directory under db too for .restore to work.
        # During a restore, the db dir is deleted and recreated, which is why we need
        # to own it for a restore.
        #
        # However, in a container, we can't always guarantee this due to how the volumes
        # work and are mounted. Specifically, if we have an anonymous volume we will
        # NEVER be able to own it, but in a true deployment it is reasonable to expect
        # we DO own it. Thus why we skip it in this specific context
        if not self.containerised:
            db_parent = os.path.join(slapd['db_dir'], '..')
            os.chown(db_parent, slapd['user_uid'], slapd['group_gid'])

        # Copy correct data to the paths.
        # Copy in the schema
        #  This is a little fragile, make it better.
        # It won't matter when we move schema to usr anyway ...

        _ds_shutil_copytree(
            os.path.join(slapd['sysconf_dir'], 'dirsrv/schema'),
            slapd['schema_dir'])
        os.chown(slapd['schema_dir'], slapd['user_uid'], slapd['group_gid'])
        os.chmod(slapd['schema_dir'], 0o770)

        # Copy in the collation
        srcfile = os.path.join(slapd['sysconf_dir'],
                               'dirsrv/config/slapd-collations.conf')
        dstfile = os.path.join(slapd['config_dir'], 'slapd-collations.conf')
        shutil.copy(srcfile, dstfile)
        os.chown(dstfile, slapd['user_uid'], slapd['group_gid'])
        os.chmod(dstfile, 0o440)

        # Copy in the certmap configuration
        srcfile = os.path.join(slapd['sysconf_dir'],
                               'dirsrv/config/certmap.conf')
        dstfile = os.path.join(slapd['config_dir'], 'certmap.conf')
        shutil.copy(srcfile, dstfile)
        os.chown(dstfile, slapd['user_uid'], slapd['group_gid'])
        os.chmod(dstfile, 0o440)

        # If we are on the correct platform settings, systemd
        if general['systemd']:
            # Should create the symlink we need, but without starting it.
            result = subprocess.run(
                ["systemctl", "enable",
                 "dirsrv@%s" % slapd['instance_name']],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE)
            args = ' '.join(ensure_list_str(result.args))
            stdout = ensure_str(result.stdout)
            stderr = ensure_str(result.stderr)
            # Systemd encodes some odd charecters into it's symlink output on newer versions which
            # can trip up the logger.
            self.log.debug(
                f"CMD: {args} ; STDOUT: {stdout} ; STDERR: {stderr}".encode(
                    "utf-8"))

            # Setup tmpfiles_d
            tmpfile_d = ds_paths.tmpfiles_d + "/dirsrv-" + slapd[
                'instance_name'] + ".conf"
            with open(tmpfile_d, "w") as TMPFILE_D:
                TMPFILE_D.write("d {} 0770 {} {}\n".format(
                    slapd['run_dir'], slapd['user'], slapd['group']))
                TMPFILE_D.write("d {} 0770 {} {}\n".format(
                    slapd['lock_dir'].replace(
                        "slapd-" + slapd['instance_name'], ""), slapd['user'],
                    slapd['group']))
                TMPFILE_D.write("d {} 0770 {} {}\n".format(
                    slapd['lock_dir'], slapd['user'], slapd['group']))

        # Else we need to detect other init scripts?
        # WB: No, we just install and assume that docker will start us ...

        # Bind sockets to our type?

        # Create certdb in sysconfidir
        self.log.debug("ACTION: Creating certificate database is %s",
                       slapd['cert_dir'])

        # BELOW THIS LINE - all actions are now ONLINE changes to the directory server.
        # if it all possible, ALWAYS ADD NEW INSTALLER CHANGES AS ONLINE ACTIONS.

        # Should I move this import? I think this prevents some recursion
        from lib389 import DirSrv
        ds_instance = DirSrv(self.verbose, containerised=self.containerised)
        if self.containerised:
            ds_instance.systemd_override = general['systemd']

        # By default SUSE does something extremely silly - it creates a hostname
        # that CANT be resolved by DNS. As a result this causes all installs to
        # fail. We need to guarantee that we only connect to localhost here, as
        # it's the only stable and guaranteed way to connect to the instance
        # at this point.
        #
        # Use ldapi which would prevent the need
        # to configure a temp root pw in the setup phase.
        args = {
            SER_HOST: "localhost",
            SER_PORT: slapd['port'],
            SER_SERVERID_PROP: slapd['instance_name'],
            SER_ROOT_DN: slapd['root_dn'],
            SER_ROOT_PW: self._raw_secure_password,
            SER_DEPLOYED_DIR: slapd['prefix'],
            SER_LDAPI_ENABLED: 'on',
            SER_LDAPI_SOCKET: slapd['ldapi'],
            SER_LDAPI_AUTOBIND: 'on'
        }

        ds_instance.allocate(args)
        # Does this work?
        assert_c(ds_instance.exists(),
                 "Instance failed to install, does not exist when expected")

        # Create a certificate database.
        tlsdb = NssSsl(dirsrv=ds_instance, dbpath=slapd['cert_dir'])
        if not tlsdb._db_exists():
            tlsdb.reinit()

        if slapd['self_sign_cert']:
            self.log.info("Create self-signed certificate database ...")
            etc_dirsrv_path = os.path.join(slapd['sysconf_dir'], 'dirsrv/')
            ssca_path = os.path.join(etc_dirsrv_path, 'ssca/')
            ssca = NssSsl(dbpath=ssca_path)
            # If it doesn't exist, create a CA DB
            if not ssca._db_exists():
                ssca.reinit()
                ssca.create_rsa_ca(months=slapd['self_sign_cert_valid_months'])
            # If CA is expired or will expire soon,
            # Reissue it and resign the existing certs that were signed by the cert previously
            elif ssca.rsa_ca_needs_renew():
                ca = ssca.renew_rsa_ca(
                    months=slapd['self_sign_cert_valid_months'])
                # Import CA to the existing instances except the one we install now (we import it later)
                for dir in os.listdir(etc_dirsrv_path):
                    if dir.startswith("slapd-") and dir != slapd['cert_dir']:
                        tlsdb_inst = NssSsl(
                            dbpath=os.path.join(etc_dirsrv_path, dir))
                        tlsdb_inst.import_rsa_crt(ca)

            csr = tlsdb.create_rsa_key_and_csr(
                alt_names=[general['full_machine_name']])
            (ca, crt) = ssca.rsa_ca_sign_csr(csr)
            tlsdb.import_rsa_crt(ca, crt)
            if general['selinux']:
                # Set selinux port label
                selinux_label_port(slapd['secure_port'])

        # Do selinux fixups
        if general['selinux']:
            self.log.info("Perform SELinux labeling ...")
            selinux_paths = ('backup_dir', 'cert_dir', 'config_dir', 'db_dir',
                             'ldif_dir', 'lock_dir', 'log_dir', 'db_home_dir',
                             'run_dir', 'schema_dir', 'tmp_dir')
            for path in selinux_paths:
                selinux_restorecon(slapd[path])

            selinux_label_port(slapd['port'])

        # Start the server
        # Make changes using the temp root
        self.log.debug(f"asan_enabled={ds_instance.has_asan()}")
        self.log.debug(
            f"libfaketime installed ={'libfaketime' in sys.modules}")
        assert_c(
            not ds_instance.has_asan() or 'libfaketime' not in sys.modules,
            "libfaketime python module is incompatible with ASAN build.")
        ds_instance.start(timeout=60)
        ds_instance.open()

        # In some cases we may want to change log settings
        # ds_instance.config.enable_log('audit')

        # Create the configs related to this version.
        base_config = get_config(general['defaults'])
        base_config_inst = base_config(ds_instance)
        base_config_inst.apply_config(install=True)

        # Setup TLS with the instance.

        # We *ALWAYS* set secure port, even if security is off, because it breaks
        # tests with standalone.enable_tls if we do not. It's only when security; on
        # that we actually start listening on it.
        if not slapd['secure_port']:
            slapd['secure_port'] = "636"
        ds_instance.config.set('nsslapd-secureport',
                               '%s' % slapd['secure_port'])
        if slapd['self_sign_cert']:
            ds_instance.config.set('nsslapd-security', 'on')

        # Before we create any backends, create any extra default indexes that may be
        # dynamically provisioned, rather than from template-dse.ldif. Looking at you
        # entryUUID (requires rust enabled).
        #
        # Indexes defaults to default_index_dn
        indexes = Indexes(ds_instance)
        if ds_instance.ds_paths.rust_enabled:
            indexes.create(
                properties={
                    'cn': 'entryUUID',
                    'nsSystemIndex': 'false',
                    'nsIndexType': ['eq', 'pres'],
                })

        # Create the backends as listed
        # Load example data if needed.
        for backend in backends:
            self.log.info(
                f"Create database backend: {backend['nsslapd-suffix']} ...")
            is_sample_entries_in_props = "sample_entries" in backend
            create_suffix_entry_in_props = backend.pop('create_suffix_entry',
                                                       False)
            ds_instance.backends.create(properties=backend)
            if not is_sample_entries_in_props and create_suffix_entry_in_props:
                # Set basic ACIs
                c_aci = '(targetattr="c || description || objectClass")(targetfilter="(objectClass=country)")(version 3.0; acl "Enable anyone c read"; allow (read, search, compare)(userdn="ldap:///anyone");)'
                o_aci = '(targetattr="o || description || objectClass")(targetfilter="(objectClass=organization)")(version 3.0; acl "Enable anyone o read"; allow (read, search, compare)(userdn="ldap:///anyone");)'
                dc_aci = '(targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)'
                ou_aci = '(targetattr="ou || description || objectClass")(targetfilter="(objectClass=organizationalUnit)")(version 3.0; acl "Enable anyone ou read"; allow (read, search, compare)(userdn="ldap:///anyone");)'
                cn_aci = '(targetattr="cn || description || objectClass")(targetfilter="(objectClass=nscontainer)")(version 3.0; acl "Enable anyone cn read"; allow (read, search, compare)(userdn="ldap:///anyone");)'
                suffix_rdn_attr = backend['nsslapd-suffix'].split(
                    '=')[0].lower()
                if suffix_rdn_attr == 'dc':
                    domain = create_base_domain(ds_instance,
                                                backend['nsslapd-suffix'])
                    domain.add('aci', dc_aci)
                elif suffix_rdn_attr == 'o':
                    org = create_base_org(ds_instance,
                                          backend['nsslapd-suffix'])
                    org.add('aci', o_aci)
                elif suffix_rdn_attr == 'ou':
                    orgunit = create_base_orgunit(ds_instance,
                                                  backend['nsslapd-suffix'])
                    orgunit.add('aci', ou_aci)
                elif suffix_rdn_attr == 'cn':
                    cn = create_base_cn(ds_instance, backend['nsslapd-suffix'])
                    cn.add('aci', cn_aci)
                elif suffix_rdn_attr == 'c':
                    c = create_base_c(ds_instance, backend['nsslapd-suffix'])
                    c.add('aci', c_aci)
                else:
                    # Unsupported rdn
                    raise ValueError(
                        "Suffix RDN '{}' in '{}' is not supported.  Supported RDN's are: 'c', 'cn', 'dc', 'o', and 'ou'"
                        .format(suffix_rdn_attr, backend['nsslapd-suffix']))

        # Create all required sasl maps: if we have a single backend ...
        # our default maps are really really bad, and we should feel bad.
        # they basically only work with a single backend, and they'll break
        # GSSAPI in some cases too :(
        if len(backends) > 0:
            self.log.debug("Adding sasl maps for suffix %s" %
                           backend['nsslapd-suffix'])
            backend = backends[0]
            saslmappings = SaslMappings(ds_instance)
            saslmappings.create(
                properties={
                    'cn': 'rfc 2829 u syntax',
                    'nsSaslMapRegexString': '^u:\\(.*\\)',
                    'nsSaslMapBaseDNTemplate': backend['nsslapd-suffix'],
                    'nsSaslMapFilterTemplate': '(uid=\\1)'
                })
            # I think this is for LDAPI
            saslmappings.create(
                properties={
                    'cn': 'uid mapping',
                    'nsSaslMapRegexString': '^[^:@]+$',
                    'nsSaslMapBaseDNTemplate': backend['nsslapd-suffix'],
                    'nsSaslMapFilterTemplate': '(uid=&)'
                })
        else:
            self.log.debug("Skipping default SASL maps - no backend found!")

        self.log.info("Perform post-installation tasks ...")
        # Change the root password finally
        ds_instance.config.set('nsslapd-rootpw', slapd['root_password'])

        # We need to log the password when containerised
        if self.containerised:
            self.log.debug("Root DN password: {}".format(
                slapd['root_password']))

        # Complete.
        if general['start']:
            # Restart for changes to take effect - this could be removed later
            ds_instance.restart(post_open=False)
        else:
            # Just stop the instance now.
            ds_instance.stop()

        self.log.debug(" 🎉 Instance setup complete")
Example #17
0
def import_server_cert(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    cert_path = args.cert_path
    tls.import_rsa_crt(crt=cert_path)
Example #18
0
    def _install_ds(self, general, slapd, backends):
        """
        Actually install the Ds from the dicts provided.

        You should never call this directly, as it bypasses assertions.
        """
        ######################## WARNING #############################
        # DO NOT CHANGE THIS FUNCTION OR ITS CONTENTS WITHOUT READING
        # ALL OF THE COMMENTS FIRST. THERE ARE VERY DELICATE
        # AND DETAILED INTERACTIONS OF COMPONENTS IN THIS FUNCTION.
        #
        # IF IN DOUBT CONTACT WILLIAM BROWN <*****@*****.**>


        ### This first section is about creating the *minimal* required paths and config to get
        # directory server to start: After this, we then perform all configuration as online
        # changes from after this point.

        # Create dse.ldif with a temporary root password.
        # This is done first, because instances are found for removal and listing by detecting
        # the present of their dse.ldif!!!!
        # The template is in slapd['data_dir']/dirsrv/data/template-dse.ldif
        # Variables are done with %KEY%.
        self.log.debug("ACTION: Creating dse.ldif")
        try:
            os.umask(0o007)  # For parent dirs that get created -> sets 770 for perms
            os.makedirs(slapd['config_dir'], mode=0o770)
        except OSError:
            pass

        # Get suffix for some plugin defaults (if possible)
        # annoyingly for legacy compat backend takes TWO key types
        # and we have to now deal with that ....
        #
        # Create ds_suffix here else it won't be in scope ....
        ds_suffix = ''
        if len(backends) > 0:
            ds_suffix = normalizeDN(backends[0]['nsslapd-suffix'])

        dse = ""
        with open(os.path.join(slapd['data_dir'], 'dirsrv', 'data', 'template-dse.ldif')) as template_dse:
            for line in template_dse.readlines():
                dse += line.replace('%', '{', 1).replace('%', '}', 1)

        with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse:
            file_dse.write(dse.format(
                schema_dir=slapd['schema_dir'],
                lock_dir=slapd['lock_dir'],
                tmp_dir=slapd['tmp_dir'],
                cert_dir=slapd['cert_dir'],
                ldif_dir=slapd['ldif_dir'],
                bak_dir=slapd['backup_dir'],
                run_dir=slapd['run_dir'],
                inst_dir=slapd['inst_dir'],
                log_dir=slapd['log_dir'],
                fqdn=general['full_machine_name'],
                ds_port=slapd['port'],
                ds_user=slapd['user'],
                rootdn=slapd['root_dn'],
                ds_passwd=self._secure_password,  # We set our own password here, so we can connect and mod.
                # This is because we never know the users input root password as they can validily give
                # us a *hashed* input.
                ds_suffix=ds_suffix,
                config_dir=slapd['config_dir'],
                db_dir=slapd['db_dir'],
            ))

        # Create all the needed paths
        # we should only need to make bak_dir, cert_dir, config_dir, db_dir, ldif_dir, lock_dir, log_dir, run_dir?
        for path in ('backup_dir', 'cert_dir', 'db_dir', 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'):
            self.log.debug("ACTION: creating %s", slapd[path])
            try:
                os.umask(0o007)  # For parent dirs that get created -> sets 770 for perms
                os.makedirs(slapd[path], mode=0o770)
            except OSError:
                pass
            os.chown(slapd[path], slapd['user_uid'], slapd['group_gid'])

        # /var/lock/dirsrv needs special attention...
        parentdir = os.path.abspath(os.path.join(slapd['lock_dir'], os.pardir))
        os.chown(parentdir, slapd['user_uid'], slapd['group_gid'])

        ### Warning! We need to down the directory under db too for .restore to work.
        # See dblayer.c for more!
        db_parent = os.path.join(slapd['db_dir'], '..')
        os.chown(db_parent, slapd['user_uid'], slapd['group_gid'])

        # Copy correct data to the paths.
        # Copy in the schema
        #  This is a little fragile, make it better.
        # It won't matter when we move schema to usr anyway ...

        _ds_shutil_copytree(os.path.join(slapd['sysconf_dir'], 'dirsrv/schema'), slapd['schema_dir'])
        os.chown(slapd['schema_dir'], slapd['user_uid'], slapd['group_gid'])
        os.chmod(slapd['schema_dir'], 0o770)

        # Copy in the collation
        srcfile = os.path.join(slapd['sysconf_dir'], 'dirsrv/config/slapd-collations.conf')
        dstfile = os.path.join(slapd['config_dir'], 'slapd-collations.conf')
        shutil.copy2(srcfile, dstfile)
        os.chown(dstfile, slapd['user_uid'], slapd['group_gid'])
        os.chmod(dstfile, 0o440)

        # Copy in the certmap configuration
        srcfile = os.path.join(slapd['sysconf_dir'], 'dirsrv/config/certmap.conf')
        dstfile = os.path.join(slapd['config_dir'], 'certmap.conf')
        shutil.copy2(srcfile, dstfile)
        os.chown(dstfile, slapd['user_uid'], slapd['group_gid'])
        os.chmod(dstfile, 0o440)

        # If we are on the correct platform settings, systemd
        if general['systemd']:
            # Should create the symlink we need, but without starting it.
            subprocess.check_call(["systemctl",
                                   "enable",
                                   "dirsrv@%s" % slapd['instance_name']])

            # Setup tmpfiles_d
            tmpfile_d = ds_paths.tmpfiles_d + "/dirsrv-" + slapd['instance_name'] + ".conf"
            with open(tmpfile_d, "w") as TMPFILE_D:
                TMPFILE_D.write("d {} 0770 {} {}\n".format(slapd['run_dir'], slapd['user'], slapd['group']))
                TMPFILE_D.write("d {} 0770 {} {}\n".format(slapd['lock_dir'].replace("slapd-" + slapd['instance_name'], ""),
                                                           slapd['user'], slapd['group']))
                TMPFILE_D.write("d {} 0770 {} {}\n".format(slapd['lock_dir'], slapd['user'], slapd['group']))

        # Else we need to detect other init scripts?
        # WB: No, we just install and assume that docker will start us ...

        # Bind sockets to our type?


        # Create certdb in sysconfidir
        self.log.debug("ACTION: Creating certificate database is %s", slapd['cert_dir'])

        # BELOWE THIS LINE - all actions are now ONLINE changes to the directory server.
        # if it all possible, ALWAYS ADD NEW INSTALLER CHANGES AS ONLINE ACTIONS.

        # Should I move this import? I think this prevents some recursion
        from lib389 import DirSrv
        ds_instance = DirSrv(self.verbose)
        if self.containerised:
            ds_instance.systemd = general['systemd']
        args = {
            SER_PORT: slapd['port'],
            SER_SERVERID_PROP: slapd['instance_name'],
            SER_ROOT_DN: slapd['root_dn'],
            SER_ROOT_PW: self._raw_secure_password,
            SER_DEPLOYED_DIR: slapd['prefix']
        }

        ds_instance.allocate(args)
        # Does this work?
        assert_c(ds_instance.exists(), "Instance failed to install, does not exist when expected")

        # Create a certificate database.
        tlsdb = NssSsl(dbpath=slapd['cert_dir'])
        if not tlsdb._db_exists():
            tlsdb.reinit()

        if slapd['self_sign_cert']:
            etc_dirsrv_path = os.path.join(slapd['sysconf_dir'], 'dirsrv/')
            ssca_path = os.path.join(etc_dirsrv_path, 'ssca/')
            ssca = NssSsl(dbpath=ssca_path)
            # If it doesn't exist, create a CA DB
            if not ssca._db_exists():
                ssca.reinit()
                ssca.create_rsa_ca(months=slapd['self_sign_cert_valid_months'])
            # If CA is expired or will expire soon,
            # Reissue it and resign the existing certs that were signed by the cert previously
            elif ssca.rsa_ca_needs_renew():
                ca = ssca.renew_rsa_ca(months=slapd['self_sign_cert_valid_months'])
                # Import CA to the existing instances except the one we install now (we import it later)
                for dir in os.listdir(etc_dirsrv_path):
                    if dir.startswith("slapd-") and dir != slapd['cert_dir']:
                        tlsdb_inst = NssSsl(dbpath=os.path.join(etc_dirsrv_path, dir))
                        tlsdb_inst.import_rsa_crt(ca)

            csr = tlsdb.create_rsa_key_and_csr()
            (ca, crt) = ssca.rsa_ca_sign_csr(csr)
            tlsdb.import_rsa_crt(ca, crt)
            if general['selinux']:
                # Set selinux port label
                selinux_label_port(slapd['secure_port'])

        # Do selinux fixups
        if general['selinux']:
            selinux_paths = ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', 'ldif_dir',
                             'lock_dir', 'log_dir', 'run_dir', 'schema_dir', 'tmp_dir')
            for path in selinux_paths:
                selinux_restorecon(slapd[path])

            selinux_label_port(slapd['port'])

        # Start the server
        # Make changes using the temp root
        ds_instance.start(timeout=60)
        ds_instance.open()

        # In some cases we may want to change log settings
        # ds_instance.config.enable_log('audit')

        # Create the configs related to this version.
        base_config = get_config(general['defaults'])
        base_config_inst = base_config(ds_instance)
        base_config_inst.apply_config(install=True)

        # Setup TLS with the instance.

        # We *ALWAYS* set secure port, even if security is off, because it breaks
        # tests with standalone.enable_tls if we do not. It's only when security; on
        # that we actually start listening on it.
        if not slapd['secure_port']:
            slapd['secure_port'] = "636"
        ds_instance.config.set('nsslapd-secureport', '%s' % slapd['secure_port'])
        if slapd['self_sign_cert']:
            ds_instance.config.set('nsslapd-security', 'on')

        # Create the backends as listed
        # Load example data if needed.
        for backend in backends:
            is_sample_entries_in_props = "sample_entries" in backend
            create_suffix_entry_in_props = backend.pop('create_suffix_entry', False)
            ds_instance.backends.create(properties=backend)
            if not is_sample_entries_in_props and create_suffix_entry_in_props:
                domain = create_base_domain(ds_instance, backend['nsslapd-suffix'])
                # Set basic ACI
                domain.add('aci', [
                    # Allow reading the base domain object
                    '(targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)',
                    # Allow reading the ou
                    '(targetattr="ou || objectClass")(targetfilter="(objectClass=organizationalUnit)")(version 3.0; acl "Enable anyone ou read"; allow (read, search, compare)(userdn="ldap:///anyone");)'
                ])

        # Initialise ldapi socket information. IPA expects this ....
        ldapi_path = os.path.join(slapd['local_state_dir'], "run/slapd-%s.socket" % slapd['instance_name'])
        ds_instance.config.set('nsslapd-ldapifilepath', ldapi_path)
        ds_instance.config.set('nsslapd-ldapilisten', 'on')
        ds_instance.config.set('nsslapd-ldapiautobind', 'on')
        ds_instance.config.set('nsslapd-ldapimaprootdn', slapd['root_dn'])


        # Create all required sasl maps: if we have a single backend ...
        # our default maps are really really bad, and we should feel bad.
        # they basically only work with a single backend, and they'll break
        # GSSAPI in some cases too :(
        if len(backends) > 0:
            self.log.debug("Adding sasl maps for suffix %s" % backend['nsslapd-suffix'])
            backend = backends[0]
            saslmappings = SaslMappings(ds_instance)
            saslmappings.create(properties={
                'cn': 'rfc 2829 u syntax',
                'nsSaslMapRegexString': '^u:\\(.*\\)',
                'nsSaslMapBaseDNTemplate': backend['nsslapd-suffix'],
                'nsSaslMapFilterTemplate': '(uid=\\1)'
            })
            # I think this is for LDAPI
            saslmappings.create(properties={
                'cn': 'uid mapping',
                'nsSaslMapRegexString': '^[^:@]+$',
                'nsSaslMapBaseDNTemplate': backend['nsslapd-suffix'],
                'nsSaslMapFilterTemplate': '(uid=&)'
            })
        else:
            self.log.debug("Skipping default SASL maps - no backend found!")

        # Change the root password finally
        ds_instance.config.set('nsslapd-rootpw', slapd['root_password'])

        # We need to log the password when containerised
        if self.containerised:
            self.log.debug("Root DN password: {}".format(slapd['root_password']))

        # Complete.
        if general['start']:
            # Restart for changes to take effect - this could be removed later
            ds_instance.restart(post_open=False)
        else:
            # Just stop the instance now.
            ds_instance.stop()
Example #19
0
def remove_cert(inst, log, args, warn=True):
    tls = NssSsl(dirsrv=inst)
    nickname = args.nickname
    if warn:
        _warn(nickname, msg="Deleting certificate %s" % nickname)
    tls.del_cert(nickname)
Example #20
0
def remove_ds_instance(dirsrv, force=False):
    """
    This will delete the instance as it is define. This must be a local instance. This is
    designed to raise exceptions quickly and often if *any* error is hit. However, this can
    be run repeatedly, and only when the instance is truely removed, will this program fail
    to run further.

    :param dirsrv: A directory server instance
    :type dirsrv: DirSrv
    :param force: A psycological aid, for people who think force means do something, harder. Does
        literally nothing in this program because state machines are a thing.
    :type force: bool
    """
    _log = dirsrv.log.getChild('remove_ds')
    _log.debug("Removing instance %s" % dirsrv.serverid)

    # Copy all the paths we are about to tamper with
    remove_paths = {}
    remove_paths['backup_dir'] = dirsrv.ds_paths.backup_dir
    remove_paths['cert_dir'] = dirsrv.ds_paths.cert_dir
    remove_paths['config_dir'] = dirsrv.ds_paths.config_dir
    remove_paths['db_dir'] = dirsrv.ds_paths.db_dir
    remove_paths['db_dir_parent'] = dirsrv.ds_paths.db_dir + "/../"
    ### WARNING: The changelogdb isn't removed. we assume it's in:
    # db_dir ../changelogdb. So remove that too!
    # abspath will resolve the ".." down.
    remove_paths['changelogdb_dir'] = dirsrv.get_changelog_dir()
    remove_paths['ldif_dir'] = dirsrv.ds_paths.ldif_dir
    remove_paths['lock_dir'] = dirsrv.ds_paths.lock_dir
    remove_paths['log_dir'] = dirsrv.ds_paths.log_dir
    # remove_paths['run_dir'] = dirsrv.ds_paths.run_dir
    remove_paths['inst_dir'] = dirsrv.ds_paths.inst_dir
    remove_paths['etc_sysconfig'] = "%s/sysconfig/dirsrv-%s" % (
        dirsrv.ds_paths.sysconf_dir, dirsrv.serverid)

    tmpfiles_d_path = dirsrv.ds_paths.tmpfiles_d + "/dirsrv-" + dirsrv.serverid + ".conf"

    # These are handled in a special way.
    dse_ldif_path = os.path.join(dirsrv.ds_paths.config_dir, 'dse.ldif')

    # Check the marker exists. If it *does not* warn about this, and say that to
    # force removal you should touch this file.

    _log.debug("Checking for instance marker at %s" % dse_ldif_path)
    if not os.path.exists(dse_ldif_path):
        _log.info("Instance configuration not found, no action will be taken")
        _log.info("If you want us to cleanup anyway, recreate '%s'" %
                  dse_ldif_path)
        return
    _log.debug("Found instance marker at %s! Proceeding to remove ..." %
               dse_ldif_path)

    # Stop the instance (if running) and now we know it really does exist
    # and hopefully have permission to access it ...
    _log.debug("Stopping instance %s" % dirsrv.serverid)
    dirsrv.stop()

    _log.debug("Found instance marker at %s! Proceeding to remove ..." %
               dse_ldif_path)

    # Stop the instance (if running) and now we know it really does exist
    # and hopefully have permission to access it ...
    _log.debug("Stopping instance %s" % dirsrv.serverid)
    dirsrv.stop()

    ### ANY NEW REMOVAL ACTION MUST BE BELOW THIS LINE!!!

    # Remove these paths:
    # for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir',
    #             'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'):
    for path_k in remove_paths:
        _log.debug("Removing %s" % remove_paths[path_k])
        shutil.rmtree(remove_paths[path_k], ignore_errors=True)

    # Remove parent (/var/lib/dirsrv/slapd-INST)
    shutil.rmtree(remove_paths['db_dir'].replace('db', ''), ignore_errors=True)

    # We can not assume we have systemd ...
    if dirsrv.ds_paths.with_systemd:
        # Remove the systemd symlink
        _log.debug("Removing the systemd symlink")
        subprocess.check_call(
            ["systemctl", "disable", "dirsrv@{}".format(dirsrv.serverid)])

        _log.debug("Removing %s" % tmpfiles_d_path)
        shutil.rmtree(tmpfiles_d_path, ignore_errors=True)

    # Nor can we assume we have selinux. Try docker sometime ;)
    if dirsrv.ds_paths.with_selinux:
        # Remove selinux port label
        _log.debug("Removing the port labels")
        selinux_label_port(dirsrv.port, remove_label=True)

        # This is a compatability with ancient installs, all modern install have tls port
        if dirsrv.sslport is not None:
            selinux_label_port(dirsrv.sslport, remove_label=True)

    # If this was the last instance, remove the ssca instance
    insts = dirsrv.list(all=True)
    if len(insts) == 0:
        ssca = NssSsl(dbpath=dirsrv.get_ssca_dir())
        ssca.remove_db()

    ### ANY NEW REMOVAL ACTIONS MUST BE ABOVE THIS LINE!!!

    # Finally means FINALLY, the last thing, the LAST LAST thing. By doing this absolutely
    # last, it means that we can have any failure above, and continue to re-run until resolved
    # because this instance marker (dse.ldif) continues to exist!
    # Move the config_dir to config_dir.removed
    config_dir = dirsrv.ds_paths.config_dir
    config_dir_rm = "{}.removed".format(config_dir)

    if os.path.exists(config_dir_rm):
        _log.debug("Removing previously existed %s" % config_dir_rm)
        shutil.rmtree(config_dir_rm)

    assert_c(not os.path.exists(config_dir_rm))

    # That's it, everything before this MUST have suceeded, so now we can move the
    # config dir (containing dse.ldif, the marker) out of the way.
    _log.debug("Moving %s to %s" % (config_dir, config_dir_rm))
    try:
        shutil.move(config_dir, config_dir_rm)
    except FileNotFoundError:
        pass

    # DO NOT PUT ANY CODE BELOW THIS COMMENT BECAUSE THAT WOULD VIOLATE THE ASSERTIONS OF THE
    # ABOVE CODE.

    # Done!
    _log.debug("Complete")
Example #21
0
def cert_edit(inst, basedn, log, args):
    """Edit cert
    """
    tlsdb = NssSsl(dirsrv=inst)
    tlsdb.edit_cert_trust(args.name, args.flags)
Example #22
0
def list_client_cas(inst, log, args):
    tls = NssSsl(dirsrv=inst)
    # This turns an array of [('CA', 'C,,')]
    for c in tls.list_client_ca_certs():
        log.info(c[0])
Example #23
0
def cert_del(inst, basedn, log, args):
    """Delete cert
    """
    tlsdb = NssSsl(dirsrv=inst)
    tlsdb.del_cert(args.name)
Example #24
0
def _remove_ssca_db(topology):
    ssca = NssSsl(dbpath=topology[0].get_ssca_dir())
    if ssca._db_exists():
        return ssca.remove_db()
    else:
        return True
Example #25
0
def test_external_ca():
    """Test the behaviour of our system ca database.

    :id: 321c85c1-9cf3-413f-9e26-99a8b327509c

    :steps:
        1. Create the system CA.
        2. Create an nss db
        3. Submit a CSR to the system ca
        4. Import the crt to the db
    :expectedresults:
        1. It works.
        2. It works.
        3. It works.
        4. It works.
    """
    # If it doesn't exist, create a cadb.
    ssca = NssSsl(dbpath='/tmp/lib389-ssca')
    ssca.reinit()
    ssca.create_rsa_ca()

    # Create certificate database.
    tlsdb = NssSsl(dbpath='/tmp/lib389-tlsdb')
    tlsdb.reinit()

    csr = tlsdb.create_rsa_key_and_csr()
    (ca, crt) = ssca.rsa_ca_sign_csr(csr)
    tlsdb.import_rsa_crt(ca, crt)
Example #26
0
    def _install_ds(self, general, slapd, backends):
        """
        Actually install the Ds from the dicts provided.

        You should never call this directly, as it bypasses assert_cions.
        """
        # register the instance to /etc/sysconfig
        # We do this first so that we can trick remove-ds.pl if needed.
        # There may be a way to create this from template like the dse.ldif ...
        initconfig = ""
        with open("%s/dirsrv/config/template-initconfig" % slapd['sysconf_dir']) as template_init:
            for line in template_init.readlines():
                initconfig += line.replace('{{', '{', 1).replace('}}', '}', 1).replace('-', '_')
        try:
            os.makedirs("%s/sysconfig" % slapd['sysconf_dir'], mode=0o775)
        except FileExistsError:
            pass
        with open("%s/sysconfig/dirsrv-%s" % (slapd['sysconf_dir'], slapd['instance_name']), 'w') as f:
            f.write(initconfig.format(
                SERVER_DIR=slapd['lib_dir'],
                SERVERBIN_DIR=slapd['sbin_dir'],
                CONFIG_DIR=slapd['config_dir'],
                INST_DIR=slapd['inst_dir'],
                RUN_DIR=slapd['run_dir'],
                DS_ROOT='',
                PRODUCT_NAME='slapd',
            ))

        # Create all the needed paths
        # we should only need to make bak_dir, cert_dir, config_dir, db_dir, ldif_dir, lock_dir, log_dir, run_dir? schema_dir,
        for path in ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', 'ldif_dir', 'lock_dir', 'log_dir', 'run_dir'):
            if self.verbose:
                self.log.info("ACTION: creating %s" % slapd[path])
            try:
                os.makedirs(slapd[path], mode=0o775)
            except OSError:
                pass
            os.chown(slapd[path], slapd['user_uid'], slapd['group_gid'])
        ### Warning! We need to down the directory under db too for .restore to work.
        # See dblayer.c for more!
        db_parent = os.path.join(slapd['db_dir'], '..')
        os.chown(db_parent, slapd['user_uid'], slapd['group_gid'])

        # Copy correct data to the paths.
        # Copy in the schema
        #  This is a little fragile, make it better.
        # It won't matter when we move schema to usr anyway ...

        _ds_shutil_copytree(os.path.join(slapd['sysconf_dir'], 'dirsrv/schema'), slapd['schema_dir'])
        os.chown(slapd['schema_dir'], slapd['user_uid'], slapd['group_gid'])

        # Copy in the collation
        srcfile = os.path.join(slapd['sysconf_dir'], 'dirsrv/config/slapd-collations.conf')
        dstfile = os.path.join(slapd['config_dir'], 'slapd-collations.conf')
        shutil.copy2(srcfile, dstfile)
        os.chown(dstfile, slapd['user_uid'], slapd['group_gid'])

        # Copy in the certmap configuration
        srcfile = os.path.join(slapd['sysconf_dir'], 'dirsrv/config/certmap.conf')
        dstfile = os.path.join(slapd['config_dir'], 'certmap.conf')
        shutil.copy2(srcfile, dstfile)
        os.chown(dstfile, slapd['user_uid'], slapd['group_gid'])

        # If we are on the correct platform settings, systemd
        if general['systemd'] and not self.containerised:
            # Should create the symlink we need, but without starting it.
            subprocess.check_call(["/usr/bin/systemctl",
                                    "enable",
                                    "dirsrv@%s" % slapd['instance_name']])
        # Else we need to detect other init scripts?

        # Bind sockets to our type?

        # Create certdb in sysconfidir
        if self.verbose:
            self.log.info("ACTION: Creating certificate database is %s" % slapd['cert_dir'])

        # Create dse.ldif with a temporary root password.
        # The template is in slapd['data_dir']/dirsrv/data/template-dse.ldif
        # Variables are done with %KEY%.
        # You could cheat and read it in, do a replace of % to { and } then use format?
        if self.verbose:
            self.log.info("ACTION: Creating dse.ldif")
        dse = ""
        with open(os.path.join(slapd['data_dir'], 'dirsrv', 'data', 'template-dse.ldif')) as template_dse:
            for line in template_dse.readlines():
                dse += line.replace('%', '{', 1).replace('%', '}', 1)

        with open(os.path.join(slapd['config_dir'], 'dse.ldif'), 'w') as file_dse:
            file_dse.write(dse.format(
                schema_dir=slapd['schema_dir'],
                lock_dir=slapd['lock_dir'],
                tmp_dir=slapd['tmp_dir'],
                cert_dir=slapd['cert_dir'],
                ldif_dir=slapd['ldif_dir'],
                bak_dir=slapd['backup_dir'],
                run_dir=slapd['run_dir'],
                inst_dir="",
                log_dir=slapd['log_dir'],
                fqdn=general['full_machine_name'],
                ds_port=slapd['port'],
                ds_user=slapd['user'],
                rootdn=slapd['root_dn'],
                # ds_passwd=slapd['root_password'],
                ds_passwd=self._secure_password,  # We set our own password here, so we can connect and mod.
                ds_suffix='',
                config_dir=slapd['config_dir'],
                db_dir=slapd['db_dir'],
            ))

        # open the connection to the instance.

        # Should I move this import? I think this prevents some recursion
        from lib389 import DirSrv
        ds_instance = DirSrv(self.verbose)
        ds_instance.containerised = self.containerised
        args = {
            SER_PORT: slapd['port'],
            SER_SERVERID_PROP: slapd['instance_name'],
            SER_ROOT_DN: slapd['root_dn'],
            SER_ROOT_PW: self._raw_secure_password,
            SER_DEPLOYED_DIR: slapd['prefix']
        }

        ds_instance.allocate(args)
        # Does this work?
        assert_c(ds_instance.exists(), "Instance failed to install, does not exist when expected")


        # Create a certificate database.
        tlsdb = NssSsl(dbpath=slapd['cert_dir'])
        if not tlsdb._db_exists():
            tlsdb.reinit()

        if slapd['self_sign_cert']:
            # If it doesn't exist, create a cadb.
            ssca_path = os.path.join(slapd['sysconf_dir'], 'dirsrv/ssca/')
            ssca = NssSsl(dbpath=ssca_path)
            if not ssca._db_exists():
                ssca.reinit()
                ssca.create_rsa_ca()

            csr = tlsdb.create_rsa_key_and_csr()
            (ca, crt) = ssca.rsa_ca_sign_csr(csr)
            tlsdb.import_rsa_crt(ca, crt)

        ## LAST CHANCE, FIX PERMISSIONS.
        # Selinux fixups?
        # Restorecon of paths?

        # Start the server
        ds_instance.start(timeout=60)
        ds_instance.open()

        # In some cases we may want to change log settings
        # ds_instance.config.enable_log('audit')

        # Create the configs related to this version.
        base_config = get_config(general['defaults'])
        base_config_inst = base_config(ds_instance)
        base_config_inst.apply_config(install=True)

        # Setup TLS with the instance.
        ds_instance.config.set('nsslapd-secureport', '%s' % slapd['secure_port'])
        if slapd['self_sign_cert']:
            ds_instance.config.set('nsslapd-security', 'on')

        # Create the backends as listed
        # Load example data if needed.
        for backend in backends:
            ds_instance.backends.create(properties=backend)

        # Make changes using the temp root
        # Change the root password finally

        # Initialise ldapi socket information. IPA expects this ....
        ds_instance.config.set('nsslapd-ldapifilepath', ds_instance.get_ldapi_path())
        ds_instance.config.set('nsslapd-ldapilisten', 'on')

        # Complete.
        ds_instance.config.set('nsslapd-rootpw',
                               ensure_str(slapd['root_password']))

        if self.containerised:
            # In a container build we need to stop DirSrv at the end
            ds_instance.stop()
        else:
            # Restart for changes to take effect - this could be removed later
            ds_instance.restart(post_open=False)