Beispiel #1
0
    def move_service_to_host(self, principal):
        """
        Used to move a host/ service principal created by kadmin.local from
        cn=kerberos to reside under the host entry.
        """

        service_dn = DN(('krbprincipalname', principal),
                        self.get_realm_suffix())
        service_entry = api.Backend.ldap2.get_entry(service_dn)
        api.Backend.ldap2.delete_entry(service_entry)

        # Create a host entry for this master
        host_dn = DN(('fqdn', self.fqdn), ('cn', 'computers'),
                     ('cn', 'accounts'), self.suffix)
        host_entry = api.Backend.ldap2.make_entry(
            host_dn,
            objectclass=[
                'top', 'ipaobject', 'nshost', 'ipahost', 'ipaservice',
                'pkiuser', 'krbprincipalaux', 'krbprincipal',
                'krbticketpolicyaux', 'ipasshhost'
            ],
            krbextradata=service_entry['krbextradata'],
            krblastpwdchange=service_entry['krblastpwdchange'],
            krbprincipalname=service_entry['krbprincipalname'],
            krbcanonicalname=service_entry['krbcanonicalname'],
            krbprincipalkey=service_entry['krbprincipalkey'],
            serverhostname=[self.fqdn.split('.', 1)[0]],
            cn=[self.fqdn],
            fqdn=[self.fqdn],
            ipauniqueid=['autogenerate'],
            managedby=[host_dn],
        )
        if 'krbpasswordexpiration' in service_entry:
            host_entry['krbpasswordexpiration'] = service_entry[
                'krbpasswordexpiration']
        if 'krbticketflags' in service_entry:
            host_entry['krbticketflags'] = service_entry['krbticketflags']
        api.Backend.ldap2.add_entry(host_entry)

        # Add the host to the ipaserver host group
        ld = ldapupdate.LDAPUpdate(ldapi=True)
        ld.update([
            os.path.join(paths.UPDATES_DIR, '20-ipaservers_hostgroup.update')
        ])
Beispiel #2
0
 def __enable_compat_plugin(self):
     ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password, sub_dict=self.sub_dict)
     rv = ld.update([paths.SCHEMA_COMPAT_ULDIF])
     if not rv:
         raise RuntimeError("Enabling compatibility plugin failed")
Beispiel #3
0
    def run(self):
        options = self.options
        super(Restore, self).run()

        self.backup_dir = self.args[0]
        if not os.path.isabs(self.backup_dir):
            self.backup_dir = os.path.join(paths.IPA_BACKUP_DIR,
                                           self.backup_dir)

        logger.info("Preparing restore from %s on %s", self.backup_dir, FQDN)

        self.header = os.path.join(self.backup_dir, 'header')

        try:
            self.read_header()
        except IOError as e:
            raise admintool.ScriptError("Cannot read backup metadata: %s" % e)

        if options.data_only:
            restore_type = 'DATA'
        else:
            restore_type = self.backup_type

        # These checks would normally be in the validate method but
        # we need to know the type of backup we're dealing with.
        if restore_type == 'FULL':
            if options.online:
                raise admintool.ScriptError(
                    "File restoration cannot be done online")
            if options.instance or options.backend:
                raise admintool.ScriptError(
                    "Restore must be in data-only mode when restoring a "
                    "specific instance or backend")
        else:
            installutils.check_server_configuration()

            self.init_api()

            if options.instance:
                instance_dir = (paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE %
                                options.instance)
                if not os.path.exists(instance_dir):
                    raise admintool.ScriptError("Instance %s does not exist" %
                                                options.instance)

                self.instances = [options.instance]

            if options.backend:
                for instance in self.instances:
                    db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE %
                              (instance, options.backend))
                    if os.path.exists(db_dir):
                        break
                else:
                    raise admintool.ScriptError("Backend %s does not exist" %
                                                options.backend)

                self.backends = [options.backend]

            for instance, backend in itertools.product(self.instances,
                                                       self.backends):
                db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE %
                          (instance, backend))
                if os.path.exists(db_dir):
                    break
            else:
                raise admintool.ScriptError(
                    "Cannot restore a data backup into an empty system")

        logger.info("Performing %s restore from %s backup", restore_type,
                    self.backup_type)

        if self.backup_host != FQDN:
            raise admintool.ScriptError(
                "Host name %s does not match backup name %s" %
                (FQDN, self.backup_host))

        if self.backup_ipa_version != str(version.VERSION):
            logger.warning(
                "Restoring data from a different release of IPA.\n"
                "Data is version %s.\n"
                "Server is running %s.", self.backup_ipa_version,
                str(version.VERSION))
            if (not options.unattended
                    and not user_input("Continue to restore?", False)):
                raise admintool.ScriptError("Aborted")

        # Check have optional dependencies been installed for extra
        # features from backup
        if restore_type == 'FULL':
            if 'ADTRUST' in self.backup_services:
                if not adtrustinstance or not adtrustinstance.check_inst():
                    raise admintool.ScriptError(
                        "Backup includes AD trust feature, it requires '{}' "
                        "package. Please install the package and "
                        "run ipa-restore again.".format(
                            constants.IPA_ADTRUST_PACKAGE_NAME))
            if 'DNS' in self.backup_services:
                if not os.path.isfile(paths.IPA_DNS_INSTALL):
                    raise admintool.ScriptError(
                        "Backup includes Integrated DNS feature, it requires "
                        "'{}' package. Please install the package and "
                        "run ipa-restore again.".format(
                            constants.IPA_DNS_PACKAGE_NAME))

        # Temporary directory for decrypting files before restoring
        self.top_dir = tempfile.mkdtemp("ipa")
        constants.DS_USER.chown(self.top_dir)
        os.chmod(self.top_dir, 0o750)
        self.dir = os.path.join(self.top_dir, "ipa")
        os.mkdir(self.dir)
        os.chmod(self.dir, 0o750)
        constants.DS_USER.chown(self.dir)

        logger.info("Temporary setting umask to 022")
        old_umask = os.umask(0o022)
        try:
            dirsrv = services.knownservices.dirsrv

            self.extract_backup()

            if restore_type == 'FULL':
                self.restore_default_conf()
                self.init_api(confdir=self.dir + paths.ETC_IPA)

            databases = []
            for instance in self.instances:
                for backend in self.backends:
                    database = (instance, backend)
                    ldiffile = os.path.join(self.dir, '%s-%s.ldif' % database)
                    if os.path.exists(ldiffile):
                        databases.append(database)

            if options.instance:
                for instance, backend in databases:
                    if instance == options.instance:
                        break
                else:
                    raise admintool.ScriptError(
                        "Instance %s not found in backup" % options.instance)

            if options.backend:
                for instance, backend in databases:
                    if backend == options.backend:
                        break
                else:
                    raise admintool.ScriptError(
                        "Backend %s not found in backup" % options.backend)

            # Big fat warning
            if (not options.unattended and not user_input(
                    "Restoring data will overwrite existing live data. Continue to restore?",
                    False)):
                raise admintool.ScriptError("Aborted")

            logger.info(
                "Each master will individually need to be re-initialized or")
            logger.info(
                "re-created from this one. The replication agreements on")
            logger.info(
                "masters running IPA 3.1 or earlier will need to be manually")
            logger.info("re-enabled. See the man page for details.")

            logger.info("Disabling all replication.")
            self.disable_agreements()

            if restore_type != 'FULL':
                if not options.online:
                    logger.info('Stopping Directory Server')
                    dirsrv.stop(capture_output=False)
                else:
                    logger.info('Starting Directory Server')
                    dirsrv.start(capture_output=False)
            else:
                logger.info('Stopping IPA services')
                result = run([paths.IPACTL, 'stop'], raiseonerr=False)
                if result.returncode not in [0, 6]:
                    logger.warning('Stopping IPA failed: %s', result.error_log)

                self.restore_selinux_booleans()

            http = httpinstance.HTTPInstance()

            # We do either a full file restore or we restore data.
            if restore_type == 'FULL':
                self.remove_old_files()
                self.clear_old_files()
                self.cert_restore_prepare()
                self.file_restore(options.no_logs)
                self.cert_restore()
                if 'CA' in self.backup_services:
                    self.__create_dogtag_log_dirs()

            # Always restore the data from ldif
            # We need to restore both userRoot and ipaca.
            for instance, backend in databases:
                self.ldif2db(instance, backend, online=options.online)

            if restore_type != 'FULL':
                if not options.online:
                    logger.info('Starting Directory Server')
                    dirsrv.start(capture_output=False)
            else:
                # restore access controll configuration
                auth_backup_path = os.path.join(paths.VAR_LIB_IPA,
                                                'auth_backup')
                if os.path.exists(auth_backup_path):
                    tasks.restore_auth_configuration(auth_backup_path)
                # explicitly enable then disable the pki tomcatd service to
                # re-register its instance. FIXME, this is really wierd.
                services.knownservices.pki_tomcatd.enable()
                services.knownservices.pki_tomcatd.disable()

                logger.info('Restarting GSS-proxy')
                gssproxy = services.service('gssproxy', api)
                gssproxy.reload_or_restart()
                logger.info('Starting IPA services')
                run([paths.IPACTL, 'start'])
                logger.info('Restarting SSSD')
                sssd = services.service('sssd', api)
                sssd.restart()
                logger.info('Restarting oddjobd')
                oddjobd = services.service('oddjobd', api)
                if not oddjobd.is_enabled():
                    logger.info("Enabling oddjobd")
                    oddjobd.enable()
                oddjobd.start()
                http.remove_httpd_ccaches()
                # update autobind configuration in case uid/gid have changed
                ld = ldapupdate.LDAPUpdate(api=api)
                autobind_update = os.path.join(paths.UPDATES_DIR,
                                               "49-autobind-services.update")
                ld.update([autobind_update])
                # have the daemons pick up their restored configs
                tasks.systemd_daemon_reload()
                # Restart IPA a final time.
                # Starting then restarting is necessary to make sure some
                # daemons like httpd are restarted
                # (https://pagure.io/freeipa/issue/8226).
                logger.info('Restarting IPA services')
                result = run([paths.IPACTL, 'restart'], raiseonerr=False)
                if result.returncode != 0:
                    logger.error('Restarting IPA failed: %s', result.error_log)
        finally:
            shutil.rmtree(self.top_dir)
            logger.info("Restoring umask to %s", old_umask)
            os.umask(old_umask)
Beispiel #4
0
 def __enable_compat_plugin(self):
     ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password,
                                sub_dict=self.sub_dict)
     rv = ld.update(['/usr/share/ipa/schema_compat.uldif'])
     if not rv:
         raise RuntimeError("Enabling compatibility plugin failed")
Beispiel #5
0
 def apply_updates(self):
     ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password,
                                sub_dict=self.sub_dict,
                                plugins=True)
     files = ld.get_all_files(ldapupdate.UPDATES_DIR)
     ld.update(files, ordered=True)