Пример #1
0
def get_port(port, default_port, secure=False):
    # Get the port number for the interactive installer and validate it
    while 1:
        if secure:
            val = input('\nEnter secure port number [{}]: '.format(default_port)).rstrip()
        else:
            val = input('\nEnter port number [{}]: '.format(default_port)).rstrip()

        if val != "" or default_port == "":
            # Validate port is number and in a valid range
            try:
                port = int(val)
                if port < 1 or port > 65535:
                    print("Port number {} is not in range (1 thru 65535)".format(port))
                    continue
            except ValueError:
                # not a number
                print('Port number {} is not a number'.format(val))
                continue

            # Validate port is available
            if socket_check_open('::1', port):
                print('Port number {} is already in use, please choose a different port number'.format(port))
                continue

            # It's a good port
            return port
        elif val == "" and default_port == "":
            print('You must specify a port number')
            continue
        else:
            # Use default
            return default_port
Пример #2
0
    def _prepare_ds(self, general, slapd, backends):
        self.log.info("Validate installation settings ...")
        assert_c(general['defaults'] is not None,
                 "Configuration defaults in section [general] not found")
        self.log.debug("PASSED: using config settings %s" %
                       general['defaults'])
        # Validate our arguments.
        assert_c(slapd['user'] is not None,
                 "Configuration user in section [slapd] not found")
        # check the user exists
        assert_c(pwd.getpwnam(slapd['user']),
                 "user %s not found on system" % slapd['user'])
        slapd['user_uid'] = pwd.getpwnam(slapd['user']).pw_uid
        assert_c(slapd['group'] is not None,
                 "Configuration group in section [slapd] not found")
        assert_c(grp.getgrnam(slapd['group']),
                 "group %s not found on system" % slapd['group'])
        slapd['group_gid'] = grp.getgrnam(slapd['group']).gr_gid
        # check this group exists
        # Check that we are running as this user / group, or that we are root.
        assert_c(
            os.geteuid() == 0 or getpass.getuser() == slapd['user'],
            "Not running as user root or %s, may not have permission to continue"
            % slapd['user'])

        self.log.debug("PASSED: user / group checking")

        assert_c(
            general['full_machine_name'] is not None,
            "Configuration full_machine_name in section [general] not found")
        assert_c(
            general['strict_host_checking'] is not None,
            "Configuration strict_host_checking in section [general] not found"
        )
        if general['strict_host_checking'] is True:
            # Check it resolves with dns
            assert_c(
                socket.gethostbyname(general['full_machine_name']),
                "Strict hostname check failed. Check your DNS records for %s" %
                general['full_machine_name'])
            self.log.debug("PASSED: Hostname strict checking")

        assert_c(slapd['prefix'] is not None,
                 "Configuration prefix in section [slapd] not found")
        if (slapd['prefix'] != ""):
            assert_c(os.path.exists(slapd['prefix']),
                     "Prefix location '%s' not found" % slapd['prefix'])
        self.log.debug("PASSED: prefix checking")

        # We need to know the prefix before we can do the instance checks
        assert_c(slapd['instance_name'] is not None,
                 "Configuration instance_name in section [slapd] not found")
        assert_c(
            len(slapd['instance_name']) <= 80,
            "Server identifier should not be longer than 80 symbols")
        assert_c(all(ord(c) < 128 for c in slapd['instance_name']),
                 "Server identifier can not contain non ascii characters")
        assert_c(' ' not in slapd['instance_name'],
                 "Server identifier can not contain a space")
        assert_c(
            slapd['instance_name'] != 'admin',
            "Server identifier \"admin\" is reserved, please choose a different identifier"
        )

        # Check that valid characters are used
        safe = re.compile(r'^[:\w@_-]+$').search
        assert_c(
            bool(safe(slapd['instance_name'])),
            "Server identifier has invalid characters, please choose a different value"
        )

        # Check if the instance exists or not.
        # Should I move this import? I think this prevents some recursion
        from lib389 import DirSrv
        ds = DirSrv(verbose=self.verbose)
        ds.containerised = self.containerised
        ds.prefix = slapd['prefix']
        insts = ds.list(serverid=slapd['instance_name'])
        assert_c(
            len(insts) == 0, "Another instance named '%s' may already exist" %
            slapd['instance_name'])

        self.log.debug("PASSED: instance checking")

        assert_c(slapd['root_dn'] is not None,
                 "Configuration root_dn in section [slapd] not found")
        # Assert this is a valid DN
        assert_c(is_a_dn(slapd['root_dn']),
                 "root_dn in section [slapd] is not a well formed LDAP DN")
        assert_c(
            slapd['root_password'] is not None
            and slapd['root_password'] != '',
            "Configuration attribute 'root_password' in section [slapd] not found"
        )
        if len(slapd['root_password']) < 8:
            raise ValueError(
                "root_password must be at least 8 characters long")

        # Check if pre-hashed or not.
        # !!!!!!!!!!!!!!

        # Right now, the way that rootpw works on ns-slapd works, it force hashes the pw
        # see https://fedorahosted.org/389/ticket/48859
        if not re.match('^([A-Z0-9]+).*$', slapd['root_password']):
            # We need to hash it. Call pwdhash-bin.
            # slapd['root_password'] = password_hash(slapd['root_password'], prefix=slapd['prefix'])
            pass
        else:
            pass

        # Create a random string
        # Hash it.
        # This will be our temporary rootdn password so that we can do
        # live mods and setup rather than static ldif manipulations.
        self._raw_secure_password = password_generate()
        self._secure_password = password_hash(self._raw_secure_password,
                                              bin_dir=slapd['bin_dir'])

        self.log.debug("INFO: temp root password set to %s" %
                       self._raw_secure_password)
        self.log.debug("PASSED: root user checking")

        assert_c(slapd['port'] is not None,
                 "Configuration port in section [slapd] not found")

        if self.containerised:
            if slapd['port'] <= 1024:
                self.log.warning(
                    "WARNING: slapd port %s may not work without NET_BIND_SERVICE in containers"
                    % slapd['port'])
            if slapd['secure_port'] <= 1024:
                self.log.warning(
                    "WARNING: slapd secure_port %s may not work without NET_BIND_SERVICE in containers"
                    % slapd['secure_port'])
        assert_c(
            socket_check_open('::1', slapd['port']) is False,
            "port %s is already in use, or missing NET_BIND_SERVICE" %
            slapd['port'])
        # We enable secure port by default.
        assert_c(slapd['secure_port'] is not None,
                 "Configuration secure_port in section [slapd] not found")
        assert_c(
            socket_check_open('::1', slapd['secure_port']) is False,
            "secure_port %s is already in use, or missing NET_BIND_SERVICE" %
            slapd['secure_port'])
        self.log.debug("PASSED: network avaliability checking")

        # Make assertions of the paths?

        # Make assertions of the backends?
        # First fix some compat shenanigans. I hate legacy ...
        for be in backends:
            for k in BACKEND_PROPNAME_TO_ATTRNAME:
                if k in be:
                    be[BACKEND_PROPNAME_TO_ATTRNAME[k]] = be[k]
                    del (be[k])
        for be in backends:
            assert_c('nsslapd-suffix' in be)
            assert_c('cn' in be)
Пример #3
0
    def create_from_cli(self):
        # Ask questions to generate general, slapd, and backends
        print('Install Directory Server (interactive mode)')
        print('===========================================')

        # Set the defaults
        general = {
            'config_version': 2,
            'full_machine_name': socket.getfqdn(),
            'strict_host_checking': False,
            'selinux': True,
            'systemd': ds_paths.with_systemd,
            'defaults': '999999999',
            'start': True
        }

        slapd = {
            'self_sign_cert_valid_months': 24,
            'group': ds_paths.group,
            'root_dn': ds_paths.root_dn,
            'initconfig_dir': ds_paths.initconfig_dir,
            'self_sign_cert': True,
            'root_password': '',
            'port': 389,
            'instance_name': 'localhost',
            'user': ds_paths.user,
            'secure_port': 636,
            'prefix': ds_paths.prefix,
            'bin_dir': ds_paths.bin_dir,
            'sbin_dir': ds_paths.sbin_dir,
            'sysconf_dir': ds_paths.sysconf_dir,
            'data_dir': ds_paths.data_dir,
            'local_state_dir': ds_paths.local_state_dir,
            'ldapi': ds_paths.ldapi,
            'lib_dir': ds_paths.lib_dir,
            'run_dir': ds_paths.run_dir,
            'tmp_dir': ds_paths.tmp_dir,
            'cert_dir': ds_paths.cert_dir,
            'config_dir': ds_paths.config_dir,
            'inst_dir': ds_paths.inst_dir,
            'backup_dir': ds_paths.backup_dir,
            'db_dir': ds_paths.db_dir,
            'db_home_dir': ds_paths.db_home_dir,
            'db_lib': get_default_db_lib(),
            'ldif_dir': ds_paths.ldif_dir,
            'lock_dir': ds_paths.lock_dir,
            'log_dir': ds_paths.log_dir,
            'schema_dir': ds_paths.schema_dir
        }

        # Let them know about the selinux status
        if not selinux_present():
            val = input(
                '\nSelinux support will be disabled, continue? [yes]: ')
            if val.strip().lower().startswith('n'):
                return

        # Start asking questions, beginning with the hostname...
        val = input('\nEnter system\'s hostname [{}]: '.format(
            general['full_machine_name'])).rstrip()
        if val != "":
            general['full_machine_name'] = val

        # Instance name - adjust defaults once set
        while 1:
            slapd['instance_name'] = general['full_machine_name'].split(
                '.', 1)[0]

            # Check if default server id is taken
            if self._server_id_taken(slapd['instance_name'],
                                     prefix=slapd['prefix']):
                slapd['instance_name'] = ""

            val = input('\nEnter the instance name [{}]: '.format(
                slapd['instance_name'])).rstrip()
            if val != "":
                if len(val) > 80:
                    print(
                        "Server identifier should not be longer than 80 symbols"
                    )
                    continue
                if not all(ord(c) < 128 for c in val):
                    print(
                        "Server identifier can not contain non ascii characters"
                    )
                    continue
                if ' ' in val:
                    print("Server identifier can not contain a space")
                    continue
                if val == 'admin':
                    print(
                        "Server identifier \"admin\" is reserved, please choose a different identifier"
                    )
                    continue

                # Check that valid characters are used
                safe = re.compile(r'^[#%:\w@_-]+$').search
                if not bool(safe(val)):
                    print(
                        "Server identifier has invalid characters, please choose a different value"
                    )
                    continue

                # Check if server id is taken
                if self._server_id_taken(val, prefix=slapd['prefix']):
                    print(
                        "Server identifier \"{}\" is already taken, please choose a new name"
                        .format(val))
                    continue

                # instance name is good
                slapd['instance_name'] = val
                break
            elif slapd['instance_name'] == "":
                continue
            else:
                # Check if default server id is taken
                if self._server_id_taken(slapd['instance_name'],
                                         prefix=slapd['prefix']):
                    print(
                        "Server identifier \"{}\" is already taken, please choose a new name"
                        .format(slapd['instance_name']))
                    continue
                break

        # Finally have a good server id, adjust the default paths
        for key, value in slapd.items():
            if isinstance(value, str):
                slapd[key] = value.format(instance_name=slapd['instance_name'])

        # Non-Secure Port
        if not socket_check_open('::1', slapd['port']):
            port = get_port(slapd['port'], slapd['port'])
        else:
            # Port 389 is already taken, pick another port
            port = get_port(slapd['port'], "")
        slapd['port'] = port

        # Self-Signed Cert DB
        while 1:
            val = input('\nCreate self-signed certificate database [yes]: '
                        ).rstrip().lower()
            if val != "":
                if val == 'no' or val == "n":
                    slapd['self_sign_cert'] = False
                    break
                elif val == "yes" or val == "y":
                    # Default value is already yes
                    break
                else:
                    print('Invalid value "{}", please use "yes" or "no"')
                    continue
            else:
                # use default
                break

        # Secure Port (only if using self signed cert)
        if slapd['self_sign_cert']:
            if not socket_check_open('::1', slapd['secure_port']):
                port = get_port(slapd['secure_port'],
                                slapd['secure_port'],
                                secure=True)
            else:
                # 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:
            val = input('\nEnter Directory Manager DN [{}]: '.format(
                slapd['root_dn'])).rstrip()
            if val != '':
                # Validate value is a DN
                if is_a_dn(val, allow_anon=False):
                    slapd['root_dn'] = val
                    break
                else:
                    print('The value "{}" is not a valid DN'.format(val))
                    continue
            else:
                # use default
                break

        # Root DN Password
        while 1:
            rootpw1 = getpass.getpass(
                '\nEnter the Directory Manager password: '******'':
                print('Password can not be empty')
                continue

            if len(rootpw1) < 8:
                print('Password must be at least 8 characters long')
                continue

            rootpw2 = getpass.getpass(
                'Confirm the Directory Manager Password: '******'Passwords do not match')
                continue

            # Passwords match, set it
            slapd['root_password'] = rootpw1
            break

        # Backend   [{'name': 'userroot', 'suffix': 'dc=example,dc=com'}]
        backend = {'name': 'userroot', 'suffix': ''}
        backends = [backend]
        suffix = ''
        domain_comps = general['full_machine_name'].split('.')
        for comp in domain_comps:
            if suffix == '':
                suffix = "dc=" + comp
            else:
                suffix += ",dc=" + comp

        while 1:
            val = input(
                "\nEnter the database suffix (or enter \"none\" to skip) [{}]: "
                .format(suffix)).rstrip()
            if val != '':
                if val.lower() == "none":
                    # No database, no problem
                    backends = []
                    break
                if is_a_dn(val, allow_anon=False):
                    backend['suffix'] = val
                    break
                else:
                    print("The suffix \"{}\" is not a valid DN".format(val))
                    continue
            else:
                backend['suffix'] = suffix
                break

        # Add sample entries or root suffix entry?
        if len(backends) > 0:
            while 1:
                val = input("\nCreate sample entries in the suffix [no]: "
                            ).rstrip().lower()
                if val != "":
                    if val == "no" or val == "n":
                        break
                    if val == "yes" or val == "y":
                        backend['sample_entries'] = INSTALL_LATEST_CONFIG
                        break

                    # Unknown value
                    print(
                        "Value \"{}\" is invalid, please use \"yes\" or \"no\""
                        .format(val))
                    continue
                else:
                    break

            if 'sample_entries' not in backend:
                # Check if they want to create the root node entry instead
                while 1:
                    val = input("\nCreate just the top suffix entry [no]: "
                                ).rstrip().lower()
                    if val != "":
                        if val == "no" or val == "n":
                            break
                        if val == "yes" or val == "y":
                            backend['create_suffix_entry'] = True
                            break

                        # Unknown value
                        print(
                            "Value \"{}\" is invalid, please use \"yes\" or \"no\""
                            .format(val))
                        continue
                    else:
                        break

        # Start the instance?
        while 1:
            val = input(
                '\nDo you want to start the instance after the installation? [yes]: '
            ).rstrip().lower()
            if val == '' or val == 'yes' or val == 'y':
                # Default behaviour
                break
            elif val == "no" or val == 'n':
                general['start'] = False
                break
            else:
                print('Invalid value, please use \"yes\" or \"no\"')
                continue

        # Are you ready?
        while 1:
            val = input('\nAre you ready to install? [no]: ').rstrip().lower()
            if val == '' or val == "no" or val == 'n':
                print('Aborting installation...')
                sys.exit(0)
            elif val == 'yes' or val == 'y':
                # lets do it!
                break
            else:
                print('Invalid value, please use \"yes\" or \"no\"')
                continue

        self.create_from_args(general, slapd, backends, self.extra)

        return True
Пример #4
0
    def _prepare_ds(self, general, slapd, backends):

        assert(general['defaults'] is not None)
        if self.verbose:
            self.log.info("PASSED: using config settings %s" % general['defaults'])
        # Validate our arguments.
        assert(slapd['user'] is not None)
        # check the user exists
        assert(pwd.getpwnam(slapd['user']))
        slapd['user_uid'] = pwd.getpwnam(slapd['user']).pw_uid
        assert(slapd['group'] is not None)
        assert(grp.getgrnam(slapd['group']))
        slapd['group_gid'] = grp.getgrnam(slapd['group']).gr_gid
        # check this group exists
        # Check that we are running as this user / group, or that we are root.
        assert(os.geteuid() == 0 or getpass.getuser() == slapd['user'])

        if self.verbose:
            self.log.info("PASSED: user / group checking")

        assert(general['full_machine_name'] is not None)
        assert(general['strict_host_checking'] is not None)
        if general['strict_host_checking'] is True:
            # Check it resolves with dns
            assert(socket.gethostbyname(general['full_machine_name']))
            if self.verbose:
                self.log.info("PASSED: Hostname strict checking")

        assert(slapd['prefix'] is not None)
        if (slapd['prefix'] != ""):
            assert(os.path.exists(slapd['prefix']))
        if self.verbose:
            self.log.info("PASSED: prefix checking")

        # We need to know the prefix before we can do the instance checks
        assert(slapd['instance_name'] is not None)
        # Check if the instance exists or not.
        # Should I move this import? I think this prevents some recursion
        from lib389 import DirSrv
        ds = DirSrv(verbose=self.verbose)
        ds.containerised = self.containerised
        ds.prefix = slapd['prefix']
        insts = ds.list(serverid=slapd['instance_name'])
        assert(len(insts) == 0)

        if self.verbose:
            self.log.info("PASSED: instance checking")

        assert(slapd['root_dn'] is not None)
        # Assert this is a valid DN
        assert(is_a_dn(slapd['root_dn']))
        assert(slapd['root_password'] is not None)
        # Check if pre-hashed or not.
        # !!!!!!!!!!!!!!

        # Right now, the way that rootpw works on ns-slapd works, it force hashes the pw
        # see https://fedorahosted.org/389/ticket/48859
        if not re.match('^\{[A-Z0-9]+\}.*$', slapd['root_password']):
            # We need to hash it. Call pwdhash-bin.
            # slapd['root_password'] = password_hash(slapd['root_password'], prefix=slapd['prefix'])
            pass
        else:
            pass

        # Create a random string
        # Hash it.
        # This will be our temporary rootdn password so that we can do
        # live mods and setup rather than static ldif manipulations.
        self._raw_secure_password = password_generate()
        self._secure_password = password_hash(self._raw_secure_password, bin_dir=slapd['bin_dir'])

        if self.verbose:
            self.log.info("PASSED: root user checking")

        assert(slapd['port'] is not None)
        assert(socket_check_open('::1', slapd['port']) is False)
        assert(slapd['secure_port'] is not None)
        assert(socket_check_open('::1', slapd['secure_port']) is False)
        if self.verbose:
            self.log.info("PASSED: network avaliability checking")
Пример #5
0
    def _prepare_ds(self, general, slapd, backends):

        assert_c(general['defaults'] is not None, "Configuration defaults in section [general] not found")
        if self.verbose:
            self.log.info("PASSED: using config settings %s" % general['defaults'])
        # Validate our arguments.
        assert_c(slapd['user'] is not None, "Configuration user in section [slapd] not found")
        # check the user exists
        assert_c(pwd.getpwnam(slapd['user']), "user %s not found on system" % slapd['user'])
        slapd['user_uid'] = pwd.getpwnam(slapd['user']).pw_uid
        assert_c(slapd['group'] is not None, "Configuration group in section [slapd] not found")
        assert_c(grp.getgrnam(slapd['group']), "group %s not found on system" % slapd['group'])
        slapd['group_gid'] = grp.getgrnam(slapd['group']).gr_gid
        # check this group exists
        # Check that we are running as this user / group, or that we are root.
        assert_c(os.geteuid() == 0 or getpass.getuser() == slapd['user'], "Not running as user root or %s, may not have permission to continue" % slapd['user'])

        if self.verbose:
            self.log.info("PASSED: user / group checking")

        assert_c(general['full_machine_name'] is not None, "Configuration full_machine_name in section [general] not found")
        assert_c(general['strict_host_checking'] is not None, "Configuration strict_host_checking in section [general] not found")
        if general['strict_host_checking'] is True:
            # Check it resolves with dns
            assert_c(socket.gethostbyname(general['full_machine_name']), "Strict hostname check failed. Check your DNS records for %s" % general['full_machine_name'])
            if self.verbose:
                self.log.info("PASSED: Hostname strict checking")

        assert_c(slapd['prefix'] is not None, "Configuration prefix in section [slapd] not found")
        if (slapd['prefix'] != ""):
            assert_c(os.path.exists(slapd['prefix']), "Prefix location '%s' not found" % slapd['prefix'])
        if self.verbose:
            self.log.info("PASSED: prefix checking")

        # We need to know the prefix before we can do the instance checks
        assert_c(slapd['instance_name'] is not None, "Configuration instance_name in section [slapd] not found")
        # Check if the instance exists or not.
        # Should I move this import? I think this prevents some recursion
        from lib389 import DirSrv
        ds = DirSrv(verbose=self.verbose)
        ds.containerised = self.containerised
        ds.prefix = slapd['prefix']
        insts = ds.list(serverid=slapd['instance_name'])
        assert_c(len(insts) == 0, "Another instance named '%s' may already exist" % slapd['instance_name'])

        if self.verbose:
            self.log.info("PASSED: instance checking")

        assert_c(slapd['root_dn'] is not None, "Configuration root_dn in section [slapd] not found")
        # Assert this is a valid DN
        assert_c(is_a_dn(slapd['root_dn']), "root_dn in section [slapd] is not a well formed LDAP DN")
        assert_c(slapd['root_password'] is not None, "Configuration root_password in section [slapd] not found")
        # Check if pre-hashed or not.
        # !!!!!!!!!!!!!!

        # Right now, the way that rootpw works on ns-slapd works, it force hashes the pw
        # see https://fedorahosted.org/389/ticket/48859
        if not re.match('^\{[A-Z0-9]+\}.*$', slapd['root_password']):
            # We need to hash it. Call pwdhash-bin.
            # slapd['root_password'] = password_hash(slapd['root_password'], prefix=slapd['prefix'])
            pass
        else:
            pass

        # Create a random string
        # Hash it.
        # This will be our temporary rootdn password so that we can do
        # live mods and setup rather than static ldif manipulations.
        self._raw_secure_password = password_generate()
        self._secure_password = password_hash(self._raw_secure_password, bin_dir=slapd['bin_dir'])

        if self.verbose:
            self.log.info("INFO: temp root password set to %s" % self._raw_secure_password)
            self.log.info("PASSED: root user checking")

        assert_c(slapd['port'] is not None, "Configuration port in section [slapd] not found")
        assert_c(socket_check_open('::1', slapd['port']) is False, "port %s is already in use" % slapd['port'])
        # We enable secure port by default.
        assert_c(slapd['secure_port'] is not None, "Configuration secure_port in section [slapd] not found")
        assert_c(socket_check_open('::1', slapd['secure_port']) is False, "secure_port %s is already in use" % slapd['secure_port'])
        if self.verbose:
            self.log.info("PASSED: network avaliability checking")