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') ])
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")
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)
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")
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)