diff --git a/SOURCES/0160-Fix-version-comparison.patch b/SOURCES/0160-Fix-version-comparison.patch
new file mode 100644
index 0000000..a3857f1
--- /dev/null
+++ b/SOURCES/0160-Fix-version-comparison.patch
@@ -0,0 +1,114 @@
+From 30902db32fcc04dccbaf40839f44cdf4f505f588 Mon Sep 17 00:00:00 2001
+From: Martin Basti <mbasti@redhat.com>
+Date: Wed, 9 Dec 2015 18:53:35 +0100
+Subject: [PATCH] Fix version comparison
+
+Use RPM library to compare vendor versions of IPA for redhat platform
+
+https://fedorahosted.org/freeipa/ticket/5535
+
+Reviewed-By: Tomas Babej <tbabej@redhat.com>
+---
+ freeipa.spec.in             |  1 +
+ ipaplatform/redhat/tasks.py | 53 +++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 54 insertions(+)
+
+diff --git a/freeipa.spec.in b/freeipa.spec.in
+index 6527109b422a1e3065d5a540c3e2a3af670f2ebf..01d42bc621c83541af7517d6d91eb37fd5b5c5cc 100644
+--- a/freeipa.spec.in
++++ b/freeipa.spec.in
+@@ -159,6 +159,7 @@ Requires: p11-kit
+ Requires: systemd-python
+ Requires: %{etc_systemd_dir}
+ Requires: gzip
++Requires: rpm-python
+ 
+ Conflicts: %{alt_name}-server
+ Obsoletes: %{alt_name}-server < %{version}
+diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py
+index db31cd04cb234fac8fee97f3579ba2ca919f3262..2e894d776dcd5542e6c11cc0210add8ad9d90298 100644
+--- a/ipaplatform/redhat/tasks.py
++++ b/ipaplatform/redhat/tasks.py
+@@ -30,6 +30,8 @@ import socket
+ import sys
+ import urllib
+ import base64
++import rpm
++from functools import total_ordering
+ 
+ from subprocess import CalledProcessError
+ from nss.error import NSPRError
+@@ -46,6 +48,35 @@ from ipaplatform.redhat.authconfig import RedHatAuthConfig
+ from ipaplatform.base.tasks import BaseTaskNamespace
+ 
+ 
++# copied from rpmUtils/miscutils.py
++def stringToVersion(verstring):
++    if verstring in [None, '']:
++        return (None, None, None)
++    i = verstring.find(':')
++    if i != -1:
++        try:
++            epoch = str(long(verstring[:i]))
++        except ValueError:
++            # look, garbage in the epoch field, how fun, kill it
++            epoch = '0' # this is our fallback, deal
++    else:
++        epoch = '0'
++    j = verstring.find('-')
++    if j != -1:
++        if verstring[i + 1:j] == '':
++            version = None
++        else:
++            version = verstring[i + 1:j]
++        release = verstring[j + 1:]
++    else:
++        if verstring[i + 1:] == '':
++            version = None
++        else:
++            version = verstring[i + 1:]
++        release = None
++    return (epoch, version, release)
++
++
+ log = log_mgr.get_logger(__name__)
+ 
+ 
+@@ -65,6 +96,21 @@ def selinux_enabled():
+         return False
+ 
+ 
++@total_ordering
++class IPAVersion(object):
++
++    def __init__(self, version):
++        self.version_tuple = stringToVersion(version)
++
++    def __eq__(self, other):
++        assert isinstance(other, IPAVersion)
++        return rpm.labelCompare(self.version_tuple, other.version_tuple) == 0
++
++    def __lt__(self, other):
++        assert isinstance(other, IPAVersion)
++        return rpm.labelCompare(self.version_tuple, other.version_tuple) == -1
++
++
+ class RedHatTaskNamespace(BaseTaskNamespace):
+ 
+     def restore_context(self, filepath, restorecon=paths.SBIN_RESTORECON):
+@@ -422,5 +468,12 @@ class RedHatTaskNamespace(BaseTaskNamespace):
+         super(RedHatTaskNamespace, self).create_system_user(name, group,
+             homedir, shell, uid, gid, comment, create_homedir)
+ 
++    def parse_ipa_version(self, version):
++        """
++        :param version: textual version
++        :return: object implementing proper __cmp__ method for version compare
++        """
++        return IPAVersion(version)
++
+ 
+ tasks = RedHatTaskNamespace()
+-- 
+2.4.3
+
diff --git a/SOURCES/0161-DNS-fix-file-permissions.patch b/SOURCES/0161-DNS-fix-file-permissions.patch
new file mode 100644
index 0000000..d8a0304
--- /dev/null
+++ b/SOURCES/0161-DNS-fix-file-permissions.patch
@@ -0,0 +1,40 @@
+From 7aae209ba77a09de7cb09792d6ac16bb80683a2f Mon Sep 17 00:00:00 2001
+From: Martin Basti <mbasti@redhat.com>
+Date: Wed, 9 Dec 2015 12:12:22 +0100
+Subject: [PATCH] DNS: fix file permissions
+
+With non default umask named-pkcs11 cannot access the softhsm token storage
+
+https://fedorahosted.org/freeipa/ticket/5520
+
+Reviewed-By: Tomas Babej <tbabej@redhat.com>
+---
+ ipaserver/install/dnskeysyncinstance.py | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py
+index 7d1351ccc57a5dbd7d537741545ad44d0dcd5eb1..590343c4e97fc882f296ac1aa69e43de9d35ed65 100644
+--- a/ipaserver/install/dnskeysyncinstance.py
++++ b/ipaserver/install/dnskeysyncinstance.py
+@@ -200,7 +200,9 @@ class DNSKeySyncInstance(service.Service):
+         # create dnssec directory
+         if not os.path.exists(paths.IPA_DNSSEC_DIR):
+             self.logger.debug("Creating %s directory", paths.IPA_DNSSEC_DIR)
+-            os.mkdir(paths.IPA_DNSSEC_DIR, 0770)
++            os.mkdir(paths.IPA_DNSSEC_DIR)
++            os.chmod(paths.IPA_DNSSEC_DIR, 0770)
++
+             # chown ods:named
+             os.chown(paths.IPA_DNSSEC_DIR, self.ods_uid, self.named_gid)
+ 
+@@ -217,6 +219,7 @@ class DNSKeySyncInstance(service.Service):
+         named_fd.truncate(0)
+         named_fd.write(softhsm_conf_txt)
+         named_fd.close()
++        os.chmod(paths.DNSSEC_SOFTHSM2_CONF, 0644)
+ 
+         # setting up named to use softhsm2
+         if not self.fstore.has_file(paths.SYSCONFIG_NAMED):
+-- 
+2.4.3
+
diff --git a/SOURCES/0162-Explicitly-call-chmod-on-newly-created-directories.patch b/SOURCES/0162-Explicitly-call-chmod-on-newly-created-directories.patch
new file mode 100644
index 0000000..e85ee8f
--- /dev/null
+++ b/SOURCES/0162-Explicitly-call-chmod-on-newly-created-directories.patch
@@ -0,0 +1,121 @@
+From 7d7bb4789504a3f84e8ccf52abc06e8de109289a Mon Sep 17 00:00:00 2001
+From: Martin Basti <mbasti@redhat.com>
+Date: Wed, 9 Dec 2015 13:40:04 +0100
+Subject: [PATCH] Explicitly call chmod on newly created directories
+
+Without calling os.chmod(), umask is effective and may cause that
+directory is created with permission that causes failure.
+
+This can be related to https://fedorahosted.org/freeipa/ticket/5520
+
+Reviewed-By: Tomas Babej <tbabej@redhat.com>
+---
+ ipaplatform/base/services.py             |  2 +-
+ ipaserver/install/cainstance.py          |  1 +
+ ipaserver/install/ipa_backup.py          |  7 ++++---
+ ipaserver/install/ipa_replica_prepare.py |  3 ++-
+ ipaserver/install/ipa_restore.py         | 10 ++++++----
+ 5 files changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py
+index 56e959e919e42281431240451071a2d4b8048e4a..b068a2f3b00549fffa20feffb6a3158382fc7e9a 100644
+--- a/ipaplatform/base/services.py
++++ b/ipaplatform/base/services.py
+@@ -421,7 +421,7 @@ class SystemdService(PlatformService):
+ 
+             try:
+                 if not ipautil.dir_exists(srv_tgt):
+-                    os.mkdir(srv_tgt)
++                    os.mkdir(srv_tgt, 0755)
+                 if os.path.exists(srv_lnk):
+                     # Remove old link
+                     os.unlink(srv_lnk)
+diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
+index c20bf39c12cff0777d90efad2b0d8d136ee37ec9..d9bf4f31af5a922dd6f977a5011f50ce7cea8896 100644
+--- a/ipaserver/install/cainstance.py
++++ b/ipaserver/install/cainstance.py
+@@ -978,6 +978,7 @@ class CAInstance(DogtagInstance):
+ 
+         if not ipautil.dir_exists(self.ra_agent_db):
+             os.mkdir(self.ra_agent_db)
++            os.chmod(self.ra_agent_db, 0755)
+ 
+         # Create the password file for this db
+         hex_str = binascii.hexlify(os.urandom(10))
+diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
+index 3bd2ef0203c1b5b596e092987acd894491ecae26..a5a4bef0a17f641fcea565d9a79c3e6887a064a7 100644
+--- a/ipaserver/install/ipa_backup.py
++++ b/ipaserver/install/ipa_backup.py
+@@ -279,8 +279,8 @@ class Backup(admintool.AdminTool):
+         os.chown(self.top_dir, pent.pw_uid, pent.pw_gid)
+         os.chmod(self.top_dir, 0750)
+         self.dir = os.path.join(self.top_dir, "ipa")
+-        os.mkdir(self.dir, 0750)
+-
++        os.mkdir(self.dir)
++        os.chmod(self.dir, 0750)
+         os.chown(self.dir, pent.pw_uid, pent.pw_gid)
+ 
+         self.header = os.path.join(self.top_dir, 'header')
+@@ -605,7 +605,8 @@ class Backup(admintool.AdminTool):
+             backup_dir = os.path.join(paths.IPA_BACKUP_DIR, time.strftime('ipa-full-%Y-%m-%d-%H-%M-%S'))
+             filename = os.path.join(backup_dir, "ipa-full.tar")
+ 
+-        os.mkdir(backup_dir, 0700)
++        os.mkdir(backup_dir)
++        os.chmod(backup_dir, 0700)
+ 
+         cwd = os.getcwd()
+         os.chdir(self.dir)
+diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py
+index 5246f5f5469c85571d04c99d872f38018802abaa..b9ae60e9bc9d40be5f86e312980846b2ad80f67d 100644
+--- a/ipaserver/install/ipa_replica_prepare.py
++++ b/ipaserver/install/ipa_replica_prepare.py
+@@ -345,7 +345,8 @@ class ReplicaPrepare(admintool.AdminTool):
+ 
+         self.top_dir = tempfile.mkdtemp("ipa")
+         self.dir = os.path.join(self.top_dir, "realm_info")
+-        os.mkdir(self.dir, 0700)
++        os.mkdir(self.dir)
++        os.chmod(self.dir, 0700)
+         try:
+             self.copy_ds_certificate()
+ 
+diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
+index 57d5deb1e68af6e9ceb51f4dd751b8a59d9ac513..cdc460301ad8aeb658fec18da565238a376d1c0c 100644
+--- a/ipaserver/install/ipa_restore.py
++++ b/ipaserver/install/ipa_restore.py
+@@ -300,8 +300,8 @@ class Restore(admintool.AdminTool):
+         os.chown(self.top_dir, pent.pw_uid, pent.pw_gid)
+         os.chmod(self.top_dir, 0750)
+         self.dir = os.path.join(self.top_dir, "ipa")
+-        os.mkdir(self.dir, 0750)
+-
++        os.mkdir(self.dir)
++        os.chmod(self.dir, 0750)
+         os.chown(self.dir, pent.pw_uid, pent.pw_gid)
+ 
+         cwd = os.getcwd()
+@@ -527,7 +527,8 @@ class Restore(admintool.AdminTool):
+ 
+         if not os.path.exists(ldifdir):
+             pent = pwd.getpwnam(DS_USER)
+-            os.mkdir(ldifdir, 0770)
++            os.mkdir(ldifdir)
++            os.chmod(ldifdir, 0770)
+             os.chown(ldifdir, pent.pw_uid, pent.pw_gid)
+ 
+         ipautil.backup_file(ldiffile)
+@@ -804,7 +805,8 @@ class Restore(admintool.AdminTool):
+         for dir in dirs:
+             try:
+                 self.log.debug('Creating %s' % dir)
+-                os.mkdir(dir, 0770)
++                os.mkdir(dir)
++                os.chmod(dir, 0770)
+                 os.chown(dir, pent.pw_uid, pent.pw_gid)
+                 tasks.restore_context(dir)
+             except Exception, e:
+-- 
+2.4.3
+
diff --git a/SOURCES/0163-Fix-replace-mkdir-with-chmod.patch b/SOURCES/0163-Fix-replace-mkdir-with-chmod.patch
new file mode 100644
index 0000000..433a1d6
--- /dev/null
+++ b/SOURCES/0163-Fix-replace-mkdir-with-chmod.patch
@@ -0,0 +1,31 @@
+From a600614ba36e192b168fcb4f9547c70fdc304707 Mon Sep 17 00:00:00 2001
+From: Martin Basti <mbasti@redhat.com>
+Date: Tue, 22 Dec 2015 16:34:32 +0100
+Subject: [PATCH] Fix: replace mkdir with chmod
+
+In original patches, extra mkdir has been added instead of chmod.
+
+https://fedorahosted.org/freeipa/ticket/5520
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipaplatform/base/services.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py
+index b068a2f3b00549fffa20feffb6a3158382fc7e9a..d280557c4f1c8ba353ba093736d577cc6c2a47a9 100644
+--- a/ipaplatform/base/services.py
++++ b/ipaplatform/base/services.py
+@@ -421,7 +421,8 @@ class SystemdService(PlatformService):
+ 
+             try:
+                 if not ipautil.dir_exists(srv_tgt):
+-                    os.mkdir(srv_tgt, 0755)
++                    os.mkdir(srv_tgt)
++                    os.chmod(srv_tgt, 0755)
+                 if os.path.exists(srv_lnk):
+                     # Remove old link
+                     os.unlink(srv_lnk)
+-- 
+2.4.3
+
diff --git a/SOURCES/0164-DNSSEC-Improve-error-reporting-from-ipa-ods-exporter.patch b/SOURCES/0164-DNSSEC-Improve-error-reporting-from-ipa-ods-exporter.patch
new file mode 100644
index 0000000..b646527
--- /dev/null
+++ b/SOURCES/0164-DNSSEC-Improve-error-reporting-from-ipa-ods-exporter.patch
@@ -0,0 +1,38 @@
+From 06df4a281c5e4b2be4840fb42129478279792a9d Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Thu, 26 Nov 2015 14:56:00 +0100
+Subject: [PATCH] DNSSEC: Improve error reporting from ipa-ods-exporter
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ daemons/dnssec/ipa-ods-exporter | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
+index f30a2253a713d857aa4e7566e52a0a45f7bd50c2..12a9294ae05d2ce8d206a2bbf74cc00d81259efa 100755
+--- a/daemons/dnssec/ipa-ods-exporter
++++ b/daemons/dnssec/ipa-ods-exporter
+@@ -31,6 +31,7 @@ import systemd.daemon
+ import systemd.journal
+ import sqlite3
+ import time
++import traceback
+ 
+ import ipalib
+ from ipapython.dn import DN
+@@ -576,7 +577,8 @@ try:
+             sync_zone(log, ldap, dns_dn, zone_row['name'])
+ 
+ except Exception as ex:
+-    msg = "ipa-ods-exporter exception: %s" % ex
++    msg = "ipa-ods-exporter exception: %s" % traceback.format_exc(ex)
++    log.exception(ex)
+     raise ex
+ 
+ finally:
+-- 
+2.4.3
+
diff --git a/SOURCES/0165-DNSSEC-Make-sure-that-current-state-in-OpenDNSSEC-ma.patch b/SOURCES/0165-DNSSEC-Make-sure-that-current-state-in-OpenDNSSEC-ma.patch
new file mode 100644
index 0000000..a8906ff
--- /dev/null
+++ b/SOURCES/0165-DNSSEC-Make-sure-that-current-state-in-OpenDNSSEC-ma.patch
@@ -0,0 +1,174 @@
+From 6c012544655b3730ebb0a1551cdbce04ab686cfb Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Tue, 24 Nov 2015 12:49:40 +0100
+Subject: [PATCH] DNSSEC: Make sure that current state in OpenDNSSEC matches
+ key state in LDAP
+
+Previously we published timestamps of planned state changes in LDAP.
+This led to situations where state transition in OpenDNSSEC was blocked
+by an additional condition (or unavailability of OpenDNSSEC) but BIND
+actually did the transition as planned.
+
+Additionally key state mapping was incorrect for KSK so sometimes KSK
+was not used for signing when it should.
+
+Example (for code without this fix):
+- Add a zone and let OpenDNSSEC to generate keys.
+- Wait until keys are in state "published" and next state is "inactive".
+- Shutdown OpenDNSSEC or break replication from DNSSEC key master.
+- See that keys on DNS replicas will transition to state "inactive" even
+  though it should not happen because OpenDNSSEC is not available
+  (i.e. new keys may not be available).
+- End result is that affected zone will not be signed anymore, even
+  though it should stay signed with the old keys.
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ daemons/dnssec/ipa-ods-exporter | 105 ++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 95 insertions(+), 10 deletions(-)
+
+diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
+index 12a9294ae05d2ce8d206a2bbf74cc00d81259efa..6ed7588847042e742abeef724940eec31f23ca8f 100755
+--- a/daemons/dnssec/ipa-ods-exporter
++++ b/daemons/dnssec/ipa-ods-exporter
+@@ -57,6 +57,14 @@ ODS_DB_LOCK_PATH = "%s%s" % (paths.OPENDNSSEC_KASP_DB, '.our_lock')
+ SECRETKEY_WRAPPING_MECH = 'rsaPkcsOaep'
+ PRIVKEY_WRAPPING_MECH = 'aesKeyWrapPad'
+ 
++# Constants from OpenDNSSEC's enforcer/ksm/include/ksm/ksm.h
++KSM_STATE_PUBLISH    = 2
++KSM_STATE_READY      = 3
++KSM_STATE_ACTIVE     = 4
++KSM_STATE_RETIRE     = 5
++KSM_STATE_DEAD       = 6
++KSM_STATE_KEYPUBLISH = 10
++
+ # DNSKEY flag constants
+ dnskey_flag_by_value = {
+     0x0001: 'SEP',
+@@ -122,6 +130,77 @@ def sql2ldap_keyid(sql_keyid):
+     #uri += '%'.join(sql_keyid[i:i+2] for i in range(0, len(sql_keyid), 2))
+     return {"idnsSecKeyRef": uri}
+ 
++def ods2bind_timestamps(key_state, key_type, ods_times):
++    """Transform (timestamps and key states) from ODS to set of BIND timestamps
++    with equivalent meaning. At the same time, remove timestamps
++    for future/planned state transitions to prevent ODS & BIND
++    from desynchronizing.
++
++    OpenDNSSEC database may contain timestamps for state transitions planned
++    in the future, but timestamp itself is not sufficient information because
++    there could be some additional condition which is guaded by OpenDNSSEC
++    itself.
++
++    BIND works directly with timestamps without any additional conditions.
++    This difference causes problem when state transition planned in OpenDNSSEC
++    does not happen as originally planned for some reason.
++
++    At the same time, this difference causes problem when OpenDNSSEC on DNSSEC
++    key master and BIND instances on replicas are not synchronized. This
++    happens when DNSSEC key master is down, or a replication is down. Even
++    a temporary desynchronization could cause DNSSEC validation failures
++    which could have huge impact.
++
++    To prevent this problem, this function removes all timestamps corresponding
++    to future state transitions. As a result, BIND will not do state transition
++    until it happens in OpenDNSSEC first and until the change is replicated.
++
++    Also, timestamp mapping depends on key type and is not 1:1.
++    For detailed description of the mapping please see
++    https://fedorahosted.org/bind-dyndb-ldap/wiki/BIND9/Design/DNSSEC/OpenDNSSEC2BINDKeyStates
++    """
++    bind_times = {}
++    # idnsSecKeyCreated is equivalent to SQL column 'created'
++    bind_times['idnsSecKeyCreated'] = ods_times['idnsSecKeyCreated']
++
++    # set of key states where publishing in DNS zone is desired is taken from
++    # opendnssec/enforcer/ksm/ksm_request.c:KsmRequestIssueKeys()
++    # TODO: support for RFC 5011, requires OpenDNSSEC v1.4.8+
++    if ('idnsSecKeyPublish' in ods_times and
++        key_state in {KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE,
++                      KSM_STATE_RETIRE, KSM_STATE_KEYPUBLISH}):
++        bind_times['idnsSecKeyPublish'] = ods_times['idnsSecKeyPublish']
++
++    # ZSK and KSK handling differs in enforcerd, see
++    # opendnssec/enforcer/enforcerd/enforcer.c:commKeyConfig()
++    if key_type == 'ZSK':
++        # idnsSecKeyActivate cannot be set before the key reaches ACTIVE state
++        if ('idnsSecKeyActivate' in ods_times and
++            key_state in {KSM_STATE_ACTIVE, KSM_STATE_RETIRE, KSM_STATE_DEAD}):
++                bind_times['idnsSecKeyActivate'] = ods_times['idnsSecKeyActivate']
++
++        # idnsSecKeyInactive cannot be set before the key reaches RETIRE state
++        if ('idnsSecKeyInactive' in ods_times and
++            key_state in {KSM_STATE_RETIRE, KSM_STATE_DEAD}):
++                bind_times['idnsSecKeyInactive'] = ods_times['idnsSecKeyInactive']
++
++    elif key_type == 'KSK':
++        # KSK is special: it is used for signing as long as it is in zone
++        if ('idnsSecKeyPublish' in ods_times and
++            key_state in {KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE,
++                          KSM_STATE_RETIRE, KSM_STATE_KEYPUBLISH}):
++            bind_times['idnsSecKeyActivate'] = ods_times['idnsSecKeyPublish']
++        # idnsSecKeyInactive is ignored for KSK on purpose
++
++    else:
++        assert False, "unsupported key type %s" % key_type
++
++    # idnsSecKeyDelete is relevant only in DEAD state
++    if 'idnsSecKeyDelete' in ods_times and key_state == KSM_STATE_DEAD:
++        bind_times['idnsSecKeyDelete'] = ods_times['idnsSecKeyDelete']
++
++    return bind_times
++
+ class ods_db_lock(object):
+     def __enter__(self):
+         self.f = open(ODS_DB_LOCK_PATH, 'w')
+@@ -172,18 +251,20 @@ def get_ods_keys(zone_name):
+     assert len(rows) == 1, "exactly one DNS zone should exist in ODS DB"
+     zone_id = rows[0][0]
+ 
+-    # get all keys for given zone ID
+-    cur = db.execute("SELECT kp.HSMkey_id, kp.generate, kp.algorithm, dnsk.publish, dnsk.active, dnsk.retire, dnsk.dead, dnsk.keytype "
+-             "FROM keypairs AS kp JOIN dnsseckeys AS dnsk ON kp.id = dnsk.keypair_id "
+-             "WHERE dnsk.zone_id = ?", (zone_id,))
++    # get relevant keys for given zone ID:
++    # ignore keys which were generated but not used yet
++    # key state check is using constants from
++    # OpenDNSSEC's enforcer/ksm/include/ksm/ksm.h
++    # WARNING! OpenDNSSEC version 1 and 2 are using different constants!
++    cur = db.execute("SELECT kp.HSMkey_id, kp.generate, kp.algorithm, "
++                     "dnsk.publish, dnsk.active, dnsk.retire, dnsk.dead, "
++                     "dnsk.keytype, dnsk.state "
++                     "FROM keypairs AS kp "
++                     "JOIN dnsseckeys AS dnsk ON kp.id = dnsk.keypair_id "
++                     "WHERE dnsk.zone_id = ?", (zone_id,))
+     keys = {}
+     for row in cur:
+-        key_data = sql2datetimes(row)
+-        if 'idnsSecKeyDelete' in key_data \
+-            and key_data['idnsSecKeyDelete'] > datetime.now():
+-                continue  # ignore deleted keys
+-
+-        key_data.update(sql2ldap_flags(row['keytype']))
++        key_data = sql2ldap_flags(row['keytype'])
+         assert key_data.get('idnsSecKeyZONE', None) == 'TRUE', \
+                 'unexpected key type 0x%x' % row['keytype']
+         if key_data.get('idnsSecKeySEP', 'FALSE') == 'TRUE':
+@@ -191,6 +272,10 @@ def get_ods_keys(zone_name):
+         else:
+             key_type = 'ZSK'
+ 
++        # transform key state to timestamps for BIND with equivalent semantics
++        ods_times = sql2datetimes(row)
++        key_data.update(ods2bind_timestamps(row['state'], key_type, ods_times))
++
+         key_data.update(sql2ldap_algorithm(row['algorithm']))
+         key_id = "%s-%s-%s" % (key_type,
+                                datetime2ldap(key_data['idnsSecKeyCreated']),
+-- 
+2.4.3
+
diff --git a/SOURCES/0166-DNSSEC-Make-sure-that-current-key-state-in-LDAP-matc.patch b/SOURCES/0166-DNSSEC-Make-sure-that-current-key-state-in-LDAP-matc.patch
new file mode 100644
index 0000000..532001c
--- /dev/null
+++ b/SOURCES/0166-DNSSEC-Make-sure-that-current-key-state-in-LDAP-matc.patch
@@ -0,0 +1,51 @@
+From 31a9cec3fc366954b3cb8943621834fdfce04bd3 Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Thu, 26 Nov 2015 15:19:03 +0100
+Subject: [PATCH] DNSSEC: Make sure that current key state in LDAP matches key
+ state in BIND
+
+We have to explicitly specify "none" value to prevent dnssec-keyfromlabel
+utility from using current time for keys without "publish" and "activate"
+timestamps.
+
+Previously this lead to situation where key was in (intermediate) state
+"generated" in OpenDNSSEC but BIND started to use this key for signing.
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipapython/dnssec/bindmgr.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/ipapython/dnssec/bindmgr.py b/ipapython/dnssec/bindmgr.py
+index 2c6781609594fa27812af3a01d16318198a3e120..70caaf4ee74f594c652cd82bccb8964e172bc719 100644
+--- a/ipapython/dnssec/bindmgr.py
++++ b/ipapython/dnssec/bindmgr.py
+@@ -58,6 +58,8 @@ class BINDMgr(object):
+         return dt.strftime(time_bindfmt)
+ 
+     def dates2params(self, ldap_attrs):
++        """Convert LDAP timestamps to list of parameters suitable
++        for dnssec-keyfromlabel utility"""
+         attr2param = {'idnsseckeypublish': '-P',
+                 'idnsseckeyactivate': '-A',
+                 'idnsseckeyinactive': '-I',
+@@ -65,10 +67,12 @@ class BINDMgr(object):
+ 
+         params = []
+         for attr, param in attr2param.items():
++            params.append(param)
+             if attr in ldap_attrs:
+-                params.append(param)
+                 assert len(ldap_attrs[attr]) == 1, 'Timestamp %s is expected to be single-valued' % attr
+                 params.append(self.time_ldap2bindfmt(ldap_attrs[attr][0]))
++            else:
++                params.append('none')
+ 
+         return params
+ 
+-- 
+2.4.3
+
diff --git a/SOURCES/0167-DNSSEC-remove-obsolete-TODO-note.patch b/SOURCES/0167-DNSSEC-remove-obsolete-TODO-note.patch
new file mode 100644
index 0000000..55a9a89
--- /dev/null
+++ b/SOURCES/0167-DNSSEC-remove-obsolete-TODO-note.patch
@@ -0,0 +1,28 @@
+From bb592115d2fbab6ca9a1b664c3d9bf1bcad5ba0f Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Wed, 2 Dec 2015 12:58:23 +0100
+Subject: [PATCH] DNSSEC: remove obsolete TODO note
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipapython/dnssec/ldapkeydb.py | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/ipapython/dnssec/ldapkeydb.py b/ipapython/dnssec/ldapkeydb.py
+index 23e6b019c2f2d2644bd389ffec4772b99b8cfc37..74371ae19ca2fb7564a343cc79be20798b99f6d2 100644
+--- a/ipapython/dnssec/ldapkeydb.py
++++ b/ipapython/dnssec/ldapkeydb.py
+@@ -181,7 +181,6 @@ class MasterKey(Key):
+         # TODO: replace this with 'autogenerate' to prevent collisions
+         uuid_rdn = DN('ipk11UniqueId=%s' % uuid.uuid1())
+         entry_dn = DN(uuid_rdn, self.ldapkeydb.base_dn)
+-        # TODO: add ipaWrappingMech attribute
+         entry = self.ldap.make_entry(entry_dn,
+                    objectClass=['ipaSecretKeyObject', 'ipk11Object'],
+                    ipaSecretKey=data,
+-- 
+2.4.3
+
diff --git a/SOURCES/0168-DNSSEC-add-debug-mode-to-ldapkeydb.py.patch b/SOURCES/0168-DNSSEC-add-debug-mode-to-ldapkeydb.py.patch
new file mode 100644
index 0000000..7c1e7fb
--- /dev/null
+++ b/SOURCES/0168-DNSSEC-add-debug-mode-to-ldapkeydb.py.patch
@@ -0,0 +1,105 @@
+From 3daffad0d0e14790147fb7a3ba9be7072b79f3e2 Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Tue, 15 Dec 2015 14:13:23 +0100
+Subject: [PATCH] DNSSEC: add debug mode to ldapkeydb.py
+
+ldapkeydb.py can be executed directly now. In that case it will print
+out key metadata as obtained using IPA LDAP API.
+
+Kerberos credential cache has to be filled with principal posessing
+appropriate access rights before the script is execured.
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipapython/dnssec/ldapkeydb.py | 54 +++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 52 insertions(+), 2 deletions(-)
+
+diff --git a/ipapython/dnssec/ldapkeydb.py b/ipapython/dnssec/ldapkeydb.py
+index 74371ae19ca2fb7564a343cc79be20798b99f6d2..54a1fba1d2db8f27c9c9b881ff42201365852587 100644
+--- a/ipapython/dnssec/ldapkeydb.py
++++ b/ipapython/dnssec/ldapkeydb.py
+@@ -4,6 +4,8 @@
+ 
+ from binascii import hexlify
+ import collections
++import logging
++from pprint import pprint
+ import sys
+ import time
+ 
+@@ -11,6 +13,7 @@ import ipalib
+ from ipapython.dn import DN
+ from ipapython import ipaldap
+ from ipapython import ipautil
++from ipapython import ipa_log_manager
+ from ipaplatform.paths import paths
+ 
+ from abshsm import attrs_name2id, attrs_id2name, bool_attr_names, populate_pkcs11_metadata, AbstractHSM
+@@ -135,8 +138,12 @@ class Key(collections.MutableMapping):
+     def __len__(self):
+         return len(self.entry)
+ 
+-    def __str__(self):
+-        return str(self.entry)
++    def __repr__(self):
++        sanitized = dict(self.entry)
++        for attr in ['ipaPrivateKey', 'ipaPublicKey', 'ipk11publickeyinfo']:
++            if attr in sanitized:
++                del sanitized[attr]
++        return repr(sanitized)
+ 
+     def _cleanup_key(self):
+         """remove default values from LDAP entry"""
+@@ -347,3 +354,46 @@ class LdapKeyDB(AbstractHSM):
+                 '(&(objectClass=ipk11PrivateKey)(objectClass=ipaPrivateKeyObject)(objectClass=ipk11PublicKey)(objectClass=ipaPublicKeyObject))'))
+ 
+         return self.cache_zone_keypairs
++
++if __name__ == '__main__':
++    # this is debugging mode
++    # print information we think are useful to stdout
++    # other garbage goes via logger to stderr
++    ipa_log_manager.standard_logging_setup(debug=True)
++    log = ipa_log_manager.root_logger
++
++    # IPA framework initialization
++    ipalib.api.bootstrap(in_server=True, log=None)  # no logging to file
++    ipalib.api.finalize()
++
++    # LDAP initialization
++    dns_dn = DN(ipalib.api.env.container_dns, ipalib.api.env.basedn)
++    ldap = ipaldap.LDAPClient(ipalib.api.env.ldap_uri)
++    log.debug('Connecting to LDAP')
++    # GSSAPI will be used, used has to be kinited already
++    ldap.gssapi_bind()
++    log.debug('Connected')
++
++    ldapkeydb = LdapKeyDB(log, ldap, DN(('cn', 'keys'), ('cn', 'sec'),
++                          ipalib.api.env.container_dns,
++                          ipalib.api.env.basedn))
++
++    print('replica public keys: CKA_WRAP = TRUE')
++    print('====================================')
++    for pubkey_id, pubkey in ldapkeydb.replica_pubkeys_wrap.items():
++        print(hexlify(pubkey_id))
++        pprint(pubkey)
++
++    print('')
++    print('master keys')
++    print('===========')
++    for mkey_id, mkey in ldapkeydb.master_keys.items():
++        print(hexlify(mkey_id))
++        pprint(mkey)
++
++    print('')
++    print('zone key pairs')
++    print('==============')
++    for key_id, key in ldapkeydb.zone_keypairs.items():
++        print(hexlify(key_id))
++        pprint(key)
+-- 
+2.4.3
+
diff --git a/SOURCES/0169-DNSSEC-logging-improvements-in-ipa-ods-exporter.patch b/SOURCES/0169-DNSSEC-logging-improvements-in-ipa-ods-exporter.patch
new file mode 100644
index 0000000..1c357a0
--- /dev/null
+++ b/SOURCES/0169-DNSSEC-logging-improvements-in-ipa-ods-exporter.patch
@@ -0,0 +1,69 @@
+From 7398819200c9a3a32effa52793240a054bc4b10f Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Tue, 15 Dec 2015 14:16:52 +0100
+Subject: [PATCH] DNSSEC: logging improvements in ipa-ods-exporter
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ daemons/dnssec/ipa-ods-exporter | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
+index 6ed7588847042e742abeef724940eec31f23ca8f..051fa53a950f7afbea5e9b1e541a9435aa02bc17 100755
+--- a/daemons/dnssec/ipa-ods-exporter
++++ b/daemons/dnssec/ipa-ods-exporter
+@@ -491,6 +491,11 @@ def cmd2ods_zone_name(cmd):
+     return zone_name
+ 
+ def sync_zone(log, ldap, dns_dn, zone_name):
++    """synchronize metadata about zone keys for single DNS zone
++
++    Key material has to be synchronized elsewhere.
++    Keep in mind that keys could be shared among multiple zones!"""
++    log.getChild("%s.%s" % (__name__, zone_name))
+     log.debug('synchronizing zone "%s"', zone_name)
+     ods_keys = get_ods_keys(zone_name)
+     ods_keys_id = set(ods_keys.keys())
+@@ -523,30 +528,30 @@ def sync_zone(log, ldap, dns_dn, zone_name):
+     ldap_keys_id = set(ldap_keys.keys())
+ 
+     new_keys_id = ods_keys_id - ldap_keys_id
+-    log.info('new keys from ODS: %s', new_keys_id)
++    log.info('new key metadata from ODS: %s', new_keys_id)
+     for key_id in new_keys_id:
+         cn = "cn=%s" % key_id
+         key_dn = DN(cn, keys_dn)
+-        log.debug('adding key "%s" to LDAP', key_dn)
++        log.debug('adding key metadata "%s" to LDAP', key_dn)
+         ldap_key = ldap.make_entry(key_dn,
+                                    objectClass=['idnsSecKey'],
+                                    **ods_keys[key_id])
+         ldap.add_entry(ldap_key)
+ 
+     deleted_keys_id = ldap_keys_id - ods_keys_id
+-    log.info('deleted keys in LDAP: %s', deleted_keys_id)
++    log.info('deleted key metadata in LDAP: %s', deleted_keys_id)
+     for key_id in deleted_keys_id:
+         cn = "cn=%s" % key_id
+         key_dn = DN(cn, keys_dn)
+-        log.debug('deleting key "%s" from LDAP', key_dn)
++        log.debug('deleting key metadata "%s" from LDAP', key_dn)
+         ldap.delete_entry(key_dn)
+ 
+     update_keys_id = ldap_keys_id.intersection(ods_keys_id)
+-    log.info('keys in LDAP & ODS: %s', update_keys_id)
++    log.info('key metadata in LDAP & ODS: %s', update_keys_id)
+     for key_id in update_keys_id:
+         ldap_key = ldap_keys[key_id]
+         ods_key = ods_keys[key_id]
+-        log.debug('updating key "%s" in LDAP', ldap_key.dn)
++        log.debug('updating key metadata "%s" in LDAP', ldap_key.dn)
+         ldap_key.update(ods_key)
+         try:
+             ldap.update_entry(ldap_key)
+-- 
+2.4.3
+
diff --git a/SOURCES/0170-DNSSEC-remove-keys-purged-by-OpenDNSSEC-from-master-.patch b/SOURCES/0170-DNSSEC-remove-keys-purged-by-OpenDNSSEC-from-master-.patch
new file mode 100644
index 0000000..c204e3c
--- /dev/null
+++ b/SOURCES/0170-DNSSEC-remove-keys-purged-by-OpenDNSSEC-from-master-.patch
@@ -0,0 +1,248 @@
+From db24ab9357ea63deaf25e8b9c5b3ad2d08a0c82b Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Tue, 15 Dec 2015 15:22:45 +0100
+Subject: [PATCH] DNSSEC: remove keys purged by OpenDNSSEC from master HSM from
+ LDAP
+
+Key purging has to be only only after key metadata purging so
+ipa-dnskeysyncd on replices does not fail while dereferencing
+non-existing keys.
+
+https://fedorahosted.org/freeipa/ticket/5334
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ daemons/dnssec/ipa-ods-exporter | 45 ++++++++++++++++++++++----
+ ipapython/dnssec/ldapkeydb.py   | 72 ++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 99 insertions(+), 18 deletions(-)
+
+diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
+index 051fa53a950f7afbea5e9b1e541a9435aa02bc17..2a1cc4315355569b24ec6ef42a68f4d64fee9f4f 100755
+--- a/daemons/dnssec/ipa-ods-exporter
++++ b/daemons/dnssec/ipa-ods-exporter
+@@ -387,7 +387,10 @@ def master2ldap_master_keys_sync(log, ldapkeydb, localhsm):
+     ldapkeydb.flush()
+ 
+ def master2ldap_zone_keys_sync(log, ldapkeydb, localhsm):
+-    # synchroniza zone keys
++    """add and update zone key material from local HSM to LDAP
++
++    No key material will be removed, only new keys will be added or updated.
++    Key removal is hanled by master2ldap_zone_keys_purge()."""
+     log = log.getChild('master2ldap_zone_keys')
+     keypairs_ldap = ldapkeydb.zone_keypairs
+     log.debug("zone keys in LDAP: %s", hex_set(keypairs_ldap))
+@@ -396,10 +399,10 @@ def master2ldap_zone_keys_sync(log, ldapkeydb, localhsm):
+     privkeys_local = localhsm.zone_privkeys
+     log.debug("zone keys in local HSM: %s", hex_set(privkeys_local))
+ 
+-    assert set(pubkeys_local) == set(privkeys_local), \
+-            "IDs of private and public keys for DNS zones in local HSM does " \
+-            "not match to key pairs: %s vs. %s" % \
+-            (hex_set(pubkeys_local), hex_set(privkeys_local))
++    assert set(pubkeys_local) == set(privkeys_local), (
++            "IDs of private and public keys for DNS zones in local HSM does "
++            "not match to key pairs: %s vs. %s" %
++            (hex_set(pubkeys_local), hex_set(privkeys_local)))
+ 
+     new_keys = set(pubkeys_local) - set(keypairs_ldap)
+     log.debug("new zone keys in local HSM: %s", hex_set(new_keys))
+@@ -420,6 +423,29 @@ def master2ldap_zone_keys_sync(log, ldapkeydb, localhsm):
+     sync_set_metadata_2ldap(log, privkeys_local, keypairs_ldap)
+     ldapkeydb.flush()
+ 
++def master2ldap_zone_keys_purge(log, ldapkeydb, localhsm):
++    """purge removed key material from LDAP (but not metadata)
++
++    Keys which are present in LDAP but not in local HSM will be removed.
++    Key metadata must be removed first so references to removed key material
++    are removed before actually removing the keys."""
++    keypairs_ldap = ldapkeydb.zone_keypairs
++    log.debug("zone keys in LDAP: %s", hex_set(keypairs_ldap))
++
++    pubkeys_local = localhsm.zone_pubkeys
++    privkeys_local = localhsm.zone_privkeys
++    log.debug("zone keys in local HSM: %s", hex_set(privkeys_local))
++    assert set(pubkeys_local) == set(privkeys_local), \
++            "IDs of private and public keys for DNS zones in local HSM does " \
++            "not match to key pairs: %s vs. %s" % \
++            (hex_set(pubkeys_local), hex_set(privkeys_local))
++
++    deleted_key_ids = set(keypairs_ldap) - set(pubkeys_local)
++    log.debug("zone keys deleted from local HSM but present in LDAP: %s",
++            hex_set(deleted_key_ids))
++    for zkey_id in deleted_key_ids:
++        keypairs_ldap[zkey_id].schedule_deletion()
++    ldapkeydb.flush()
+ 
+ def hex_set(s):
+     out = set()
+@@ -600,7 +626,7 @@ ldap.connect(ccache=ccache_name)
+ log.debug('Connected')
+ 
+ 
+-### DNSSEC master: key synchronization
++### DNSSEC master: key material upload & synchronization (but not deletion)
+ ldapkeydb = LdapKeyDB(log, ldap, DN(('cn', 'keys'), ('cn', 'sec'),
+                                     ipalib.api.env.container_dns,
+                                     ipalib.api.env.basedn))
+@@ -612,7 +638,7 @@ master2ldap_master_keys_sync(log, ldapkeydb, localhsm)
+ master2ldap_zone_keys_sync(log, ldapkeydb, localhsm)
+ 
+ 
+-### DNSSEC master: DNSSEC key metadata upload
++### DNSSEC master: DNSSEC key metadata upload & synchronization & deletion
+ # command receive is delayed so the command will stay in socket queue until
+ # the problem with LDAP server or HSM is fixed
+ try:
+@@ -666,6 +692,11 @@ try:
+         for zone_row in db.execute("SELECT name FROM zones"):
+             sync_zone(log, ldap, dns_dn, zone_row['name'])
+ 
++    ### DNSSEC master: DNSSEC key material purging
++    # references to old key material were removed above in sync_zone()
++    # so now we can purge old key material from LDAP
++    master2ldap_zone_keys_purge(log, ldapkeydb, localhsm)
++
+ except Exception as ex:
+     msg = "ipa-ods-exporter exception: %s" % traceback.format_exc(ex)
+     log.exception(ex)
+diff --git a/ipapython/dnssec/ldapkeydb.py b/ipapython/dnssec/ldapkeydb.py
+index 54a1fba1d2db8f27c9c9b881ff42201365852587..2131508cc6779d1cc99c417a31da866b7fdcf2c2 100644
+--- a/ipapython/dnssec/ldapkeydb.py
++++ b/ipapython/dnssec/ldapkeydb.py
+@@ -105,40 +105,56 @@ def get_default_attrs(object_classes):
+         result.update(defaults[cls])
+     return result
+ 
++
+ class Key(collections.MutableMapping):
+     """abstraction to hide LDAP entry weirdnesses:
+         - non-normalized attribute names
+         - boolean attributes returned as strings
++        - planned entry deletion prevents subsequent use of the instance
+     """
+     def __init__(self, entry, ldap, ldapkeydb):
+         self.entry = entry
++        self._delentry = None  # indicates that object was deleted
+         self.ldap = ldap
+         self.ldapkeydb = ldapkeydb
+         self.log = ldap.log.getChild(__name__)
+ 
++    def __assert_not_deleted(self):
++        assert self.entry and not self._delentry, (
++            "attempt to use to-be-deleted entry %s detected"
++            % self._delentry.dn)
++
+     def __getitem__(self, key):
++        self.__assert_not_deleted()
+         val = self.entry.single_value[key]
+         if key.lower() in bool_attr_names:
+             val = ldap_bool(val)
+         return val
+ 
+     def __setitem__(self, key, value):
++        self.__assert_not_deleted()
+         self.entry[key] = value
+ 
+     def __delitem__(self, key):
++        self.__assert_not_deleted()
+         del self.entry[key]
+ 
+     def __iter__(self):
+         """generates list of ipa names of all PKCS#11 attributes present in the object"""
++        self.__assert_not_deleted()
+         for ipa_name in self.entry.keys():
+             lowercase = ipa_name.lower()
+             if lowercase in attrs_name2id:
+                 yield lowercase
+ 
+     def __len__(self):
++        self.__assert_not_deleted()
+         return len(self.entry)
+ 
+     def __repr__(self):
++        if self._delentry:
++            return 'deleted entry: %s' % repr(self._delentry)
++
+         sanitized = dict(self.entry)
+         for attr in ['ipaPrivateKey', 'ipaPublicKey', 'ipk11publickeyinfo']:
+             if attr in sanitized:
+@@ -153,6 +169,49 @@ class Key(collections.MutableMapping):
+             if self.get(attr, empty) == default_attrs[attr]:
+                 del self[attr]
+ 
++    def _update_key(self):
++        """remove default values from LDAP entry and write back changes"""
++        if self._delentry:
++            self._delete_key()
++            return
++
++        self._cleanup_key()
++
++        try:
++            self.ldap.update_entry(self.entry)
++        except ipalib.errors.EmptyModlist:
++            pass
++
++    def _delete_key(self):
++        """remove key metadata entry from LDAP
++
++        After calling this, the python object is no longer valid and all
++        subsequent method calls on it will fail.
++        """
++        assert not self.entry, (
++            "Key._delete_key() called before Key.schedule_deletion()")
++        assert self._delentry, "Key._delete_key() called more than once"
++        self.log.debug('deleting key id 0x%s DN %s from LDAP',
++                       hexlify(self._delentry.single_value['ipk11id']),
++                       self._delentry.dn)
++        self.ldap.delete_entry(self._delentry)
++        self._delentry = None
++        self.ldap = None
++        self.ldapkeydb = None
++
++    def schedule_deletion(self):
++        """schedule key deletion from LDAP
++
++        Calling schedule_deletion() will make this object incompatible with
++        normal Key. After that the object must not be read or modified.
++        Key metadata will be actually deleted when LdapKeyDB.flush() is called.
++        """
++        assert not self._delentry, (
++            "Key.schedule_deletion() called more than once")
++        self._delentry = self.entry
++        self.entry = None
++
++
+ class ReplicaKey(Key):
+     # TODO: object class assert
+     def __init__(self, entry, ldap, ldapkeydb):
+@@ -239,21 +298,12 @@ class LdapKeyDB(AbstractHSM):
+         self._update_keys()
+         return keys
+ 
+-    def _update_key(self, key):
+-        """remove default values from LDAP entry and write back changes"""
+-        key._cleanup_key()
+-
+-        try:
+-            self.ldap.update_entry(key.entry)
+-        except ipalib.errors.EmptyModlist:
+-            pass
+-
+     def _update_keys(self):
+         for cache in [self.cache_masterkeys, self.cache_replica_pubkeys_wrap,
+-                self.cache_zone_keypairs]:
++                      self.cache_zone_keypairs]:
+             if cache:
+                 for key in cache.itervalues():
+-                    self._update_key(key)
++                    key._update_key()
+ 
+     def flush(self):
+         """write back content of caches to LDAP"""
+-- 
+2.4.3
+
diff --git a/SOURCES/0171-DNSSEC-ipa-dnskeysyncd-Skip-zones-with-old-DNSSEC-me.patch b/SOURCES/0171-DNSSEC-ipa-dnskeysyncd-Skip-zones-with-old-DNSSEC-me.patch
new file mode 100644
index 0000000..d248eb3
--- /dev/null
+++ b/SOURCES/0171-DNSSEC-ipa-dnskeysyncd-Skip-zones-with-old-DNSSEC-me.patch
@@ -0,0 +1,125 @@
+From 96695bb8e414be941e07d43652516a99cfd89a24 Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Sun, 20 Dec 2015 18:36:48 +0100
+Subject: [PATCH] DNSSEC: ipa-dnskeysyncd: Skip zones with old DNSSEC metadata
+ in LDAP
+
+This filtering is useful in cases where LDAP contains DNS zones which
+have old metadata objects and DNSSEC disabled. Such zones must be
+ignored to prevent errors while calling dnssec-keyfromlabel or rndc.
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipapython/dnssec/bindmgr.py   | 16 +++++++++++++---
+ ipapython/dnssec/keysyncer.py | 24 ++++++++++++++++++------
+ 2 files changed, 31 insertions(+), 9 deletions(-)
+
+diff --git a/ipapython/dnssec/bindmgr.py b/ipapython/dnssec/bindmgr.py
+index 70caaf4ee74f594c652cd82bccb8964e172bc719..d81dad940df49e79f4534c2224c10ecf192794ba 100644
+--- a/ipapython/dnssec/bindmgr.py
++++ b/ipapython/dnssec/bindmgr.py
+@@ -191,10 +191,20 @@ class BINDMgr(object):
+ 
+         self.notify_zone(zone)
+ 
+-    def sync(self):
+-        """Synchronize list of zones in LDAP with BIND."""
++    def sync(self, dnssec_zones):
++        """Synchronize list of zones in LDAP with BIND.
++
++        dnssec_zones lists zones which should be processed. All other zones
++        will be ignored even though they were modified using ldap_event().
++
++        This filter is useful in cases where LDAP contains DNS zones which
++        have old metadata objects and DNSSEC disabled. Such zones must be
++        ignored to prevent errors while calling dnssec-keyfromlabel or rndc.
++        """
+         self.log.debug('Key metadata in LDAP: %s' % self.ldap_keys)
+-        for zone in self.modified_zones:
++        self.log.debug('Zones modified but skipped during bindmgr.sync: %s',
++                       self.modified_zones - dnssec_zones)
++        for zone in self.modified_zones.intersection(dnssec_zones):
+             self.sync_zone(zone)
+ 
+         self.modified_zones = set()
+diff --git a/ipapython/dnssec/keysyncer.py b/ipapython/dnssec/keysyncer.py
+index de5b5aa5f670db4c58fb92b989e181d45d887b55..5ba9baaab30b07d2f4e4ae3a3507898d08a0d6c1 100644
+--- a/ipapython/dnssec/keysyncer.py
++++ b/ipapython/dnssec/keysyncer.py
+@@ -6,6 +6,8 @@ import logging
+ import ldap.dn
+ import os
+ 
++import dns.name
++
+ from ipaplatform.paths import paths
+ from ipapython import ipautil
+ 
+@@ -33,6 +35,7 @@ class KeySyncer(SyncReplConsumer):
+ 
+         self.bindmgr = BINDMgr(self.api)
+         self.init_done = False
++        self.dnssec_zones = set()
+         SyncReplConsumer.__init__(self, *args, **kwargs)
+ 
+     def _get_objclass(self, attrs):
+@@ -112,7 +115,7 @@ class KeySyncer(SyncReplConsumer):
+         self.ods_sync()
+         self.hsm_replica_sync()
+         self.hsm_master_sync()
+-        self.bindmgr.sync()
++        self.bindmgr.sync(self.dnssec_zones)
+ 
+     # idnsSecKey wrapper
+     # Assumption: metadata points to the same key blob all the time,
+@@ -121,23 +124,29 @@ class KeySyncer(SyncReplConsumer):
+     def key_meta_add(self, uuid, dn, newattrs):
+         self.hsm_replica_sync()
+         self.bindmgr.ldap_event('add', uuid, newattrs)
+-        self.bindmgr_sync()
++        self.bindmgr_sync(self.dnssec_zones)
+ 
+     def key_meta_del(self, uuid, dn, oldattrs):
+         self.bindmgr.ldap_event('del', uuid, oldattrs)
+-        self.bindmgr_sync()
++        self.bindmgr_sync(self.dnssec_zones)
+         self.hsm_replica_sync()
+ 
+     def key_metadata_sync(self, uuid, dn, oldattrs, newattrs):
+         self.bindmgr.ldap_event('mod', uuid, newattrs)
+-        self.bindmgr_sync()
++        self.bindmgr_sync(self.dnssec_zones)
+ 
+-    def bindmgr_sync(self):
++    def bindmgr_sync(self, dnssec_zones):
+         if self.init_done:
+-            self.bindmgr.sync()
++            self.bindmgr.sync(dnssec_zones)
+ 
+     # idnsZone wrapper
+     def zone_add(self, uuid, dn, newattrs):
++        zone = dns.name.from_text(newattrs['idnsname'][0])
++        if self.__is_dnssec_enabled(newattrs):
++            self.dnssec_zones.add(zone)
++        else:
++            self.dnssec_zones.discard(zone)
++
+         if not self.ismaster:
+             return
+ 
+@@ -146,6 +155,9 @@ class KeySyncer(SyncReplConsumer):
+         self.ods_sync()
+ 
+     def zone_del(self, uuid, dn, oldattrs):
++        zone = dns.name.from_text(oldattrs['idnsname'][0])
++        self.dnssec_zones.discard(zone)
++
+         if not self.ismaster:
+             return
+ 
+-- 
+2.4.3
+
diff --git a/SOURCES/0172-DNSSEC-ipa-ods-exporter-add-ldap-cleanup-command.patch b/SOURCES/0172-DNSSEC-ipa-ods-exporter-add-ldap-cleanup-command.patch
new file mode 100644
index 0000000..d28cb57
--- /dev/null
+++ b/SOURCES/0172-DNSSEC-ipa-ods-exporter-add-ldap-cleanup-command.patch
@@ -0,0 +1,142 @@
+From a5687f3070877fc28435d9db4d5fed8c521dbf41 Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Sun, 20 Dec 2015 19:19:28 +0100
+Subject: [PATCH] DNSSEC: ipa-ods-exporter: add ldap-cleanup command
+
+Command "ldap-cleanup <zone name>" will remove all key metadata from
+LDAP. This can be used manually in sequence like:
+ldap-cleanup <zone name>
+update <zone name>
+to delete all key metadata from LDAP and re-export them from OpenDNSSEC.
+
+ldap-cleanup command should be called when disabling DNSSEC on a DNS
+zone to remove stale key metadata from LDAP.
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ daemons/dnssec/ipa-ods-exporter | 60 ++++++++++++++++++++++++++++++++---------
+ 1 file changed, 48 insertions(+), 12 deletions(-)
+
+diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
+index 2a1cc4315355569b24ec6ef42a68f4d64fee9f4f..8abb5cf7c6d1e5e8ea996b8925d2e8cffc44133c 100755
+--- a/daemons/dnssec/ipa-ods-exporter
++++ b/daemons/dnssec/ipa-ods-exporter
+@@ -227,7 +227,9 @@ def get_ldap_zone(ldap, dns_base, name):
+         except ipalib.errors.NotFound:
+             continue
+ 
+-    assert ldap_zone is not None, 'DNS zone "%s" should exist in LDAP' % name
++    if ldap_zone is None:
++        raise ipalib.errors.NotFound(
++            reason='DNS zone "%s" not found in LDAP' % name)
+ 
+     return ldap_zone
+ 
+@@ -481,25 +483,37 @@ def parse_command(cmd):
+     if cmd == 'ipa-hsm-update':
+         return (0,
+                 'HSM synchronization finished, skipping zone synchronization.',
+-                None)
++                None,
++                cmd)
+ 
+     elif cmd == 'ipa-full-update':
+         return (None,
+                 'Synchronization of all zones was finished.',
+-                None)
++                None,
++                cmd)
++
++    elif cmd.startswith('ldap-cleanup '):
++        zone_name = cmd2ods_zone_name(cmd)
++        return (None,
++                'Zone "%s" metadata will be removed from LDAP.\n' % zone_name,
++                zone_name,
++                'ldap-cleanup')
+ 
+-    elif not cmd.startswith('update '):
++    elif cmd.startswith('update '):
++        zone_name = cmd2ods_zone_name(cmd)
++        return (None,
++                'Zone "%s" metadata will be updated in LDAP.\n' % zone_name,
++                zone_name,
++                'update')
++
++    else:
+         return (0,
+                 'Command "%s" is not supported by IPA; '
+                 'HSM synchronization was finished and the command '
+                 'will be ignored.' % cmd,
++                None,
+                 None)
+ 
+-    else:
+-        zone_name = cmd2ods_zone_name(cmd)
+-        return (None,
+-                'Zone was "%s" updated.\n' % zone_name,
+-                zone_name)
+ 
+ def send_systemd_reply(conn, reply):
+         # Reply & close connection early.
+@@ -510,7 +524,7 @@ def send_systemd_reply(conn, reply):
+ 
+ def cmd2ods_zone_name(cmd):
+     # ODS stores zone name without trailing period
+-    zone_name = cmd[7:].strip()
++    zone_name = cmd.split(' ', 1)[1].strip()
+     if len(zone_name) > 1 and zone_name[-1] == '.':
+         zone_name = zone_name[:-1]
+ 
+@@ -584,6 +598,25 @@ def sync_zone(log, ldap, dns_dn, zone_name):
+         except ipalib.errors.EmptyModlist:
+             continue
+ 
++def cleanup_ldap_zone(log, ldap, dns_dn, zone_name):
++    """delete all key metadata about zone keys for single DNS zone
++
++    Key material has to be synchronized elsewhere.
++    Keep in mind that keys could be shared among multiple zones!"""
++    log = log.getChild("%s.%s" % (__name__, zone_name))
++    log.debug('cleaning up key metadata from zone "%s"', zone_name)
++
++    try:
++        ldap_zone = get_ldap_zone(ldap, dns_dn, zone_name)
++        ldap_keys = get_ldap_keys(ldap, ldap_zone.dn)
++    except ipalib.errors.NotFound as ex:
++        # zone or cn=keys container does not exist, we are done
++        log.debug(str(ex))
++        return
++
++    for ldap_key in ldap_keys:
++        log.debug('deleting key metadata "%s"', ldap_key.dn)
++        ldap.delete_entry(ldap_key)
+ 
+ log = logging.getLogger('root')
+ # this service is usually socket-activated
+@@ -656,7 +689,7 @@ except KeyError as e:
+     conn = None
+     cmd = sys.argv[1]
+ 
+-exitcode, msg, zone_name = parse_command(cmd)
++exitcode, msg, zone_name, cmd = parse_command(cmd)
+ 
+ if exitcode is not None:
+     if conn:
+@@ -686,7 +719,10 @@ try:
+ 
+     if zone_name is not None:
+         # only one zone should be processed
+-        sync_zone(log, ldap, dns_dn, zone_name)
++        if cmd == 'update':
++            sync_zone(log, ldap, dns_dn, zone_name)
++        elif cmd == 'ldap-cleanup':
++            cleanup_ldap_zone(log, ldap, dns_dn, zone_name)
+     else:
+         # process all zones
+         for zone_row in db.execute("SELECT name FROM zones"):
+-- 
+2.4.3
+
diff --git a/SOURCES/0173-DNSSEC-ipa-dnskeysyncd-call-ods-signer-ldap-cleanup-.patch b/SOURCES/0173-DNSSEC-ipa-dnskeysyncd-call-ods-signer-ldap-cleanup-.patch
new file mode 100644
index 0000000..2f5d404
--- /dev/null
+++ b/SOURCES/0173-DNSSEC-ipa-dnskeysyncd-call-ods-signer-ldap-cleanup-.patch
@@ -0,0 +1,44 @@
+From dbb7b91bf052bc4d5a4f545044e8949b67b511db Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Sun, 20 Dec 2015 19:35:55 +0100
+Subject: [PATCH] DNSSEC: ipa-dnskeysyncd: call ods-signer ldap-cleanup on zone
+ removal
+
+Command "ldap-cleanup <zone name>" is called to remove all key metadata from
+LDAP. This command is now called when disabling DNSSEC on a DNS zone. The stale
+metadata were causing problems when re-enabling DNSSEC on the same zone.
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipapython/dnssec/odsmgr.py | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/ipapython/dnssec/odsmgr.py b/ipapython/dnssec/odsmgr.py
+index efbe16cc6ebf050d9cf347ed97b2b2e4b37c8a6e..44d94ac3ab9e68feba067e8f14530894bda22855 100644
+--- a/ipapython/dnssec/odsmgr.py
++++ b/ipapython/dnssec/odsmgr.py
+@@ -152,12 +152,18 @@ class ODSMgr(object):
+         output = self.ksmutil(cmd)
+         self.log.info(output)
+         self.notify_enforcer()
++        self.cleanup_signer(name)
+ 
+     def notify_enforcer(self):
+         cmd = ['notify']
+         output = self.ksmutil(cmd)
+         self.log.info(output)
+ 
++    def cleanup_signer(self, zone_name):
++        cmd = ['ods-signer', 'ldap-cleanup', str(zone_name)]
++        output = ipautil.run(cmd, capture_output=True)
++        self.log.info(output)
++
+     def ldap_event(self, op, uuid, attrs):
+         """Record single LDAP event - zone addition or deletion.
+ 
+-- 
+2.4.3
+
diff --git a/SOURCES/0174-DNSSEC-Log-debug-messages-at-log-level-DEBUG.patch b/SOURCES/0174-DNSSEC-Log-debug-messages-at-log-level-DEBUG.patch
new file mode 100644
index 0000000..1388c9d
--- /dev/null
+++ b/SOURCES/0174-DNSSEC-Log-debug-messages-at-log-level-DEBUG.patch
@@ -0,0 +1,29 @@
+From d3c3377ecf597787af7d8975f6d0a822798585f9 Mon Sep 17 00:00:00 2001
+From: Petr Spacek <pspacek@redhat.com>
+Date: Tue, 24 Nov 2015 12:49:16 +0100
+Subject: [PATCH] DNSSEC: Log debug messages at log level DEBUG
+
+https://fedorahosted.org/freeipa/ticket/5348
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ daemons/dnssec/ipa-ods-exporter | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter
+index 8abb5cf7c6d1e5e8ea996b8925d2e8cffc44133c..2b71b0c38eeb9c5f61adecdb802c081433e3db27 100755
+--- a/daemons/dnssec/ipa-ods-exporter
++++ b/daemons/dnssec/ipa-ods-exporter
+@@ -310,7 +310,7 @@ def ldap2master_replica_keys_sync(log, ldapkeydb, localhsm):
+     log.info("new replica keys in LDAP: %s", hex_set(new_replica_keys))
+     for key_id in new_replica_keys:
+         new_key_ldap = ldapkeydb.replica_pubkeys_wrap[key_id]
+-        log.error('label=%s,  id=%s, data=%s',
++        log.debug('label=%s, id=%s, data=%s',
+                 new_key_ldap['ipk11label'],
+                 hexlify(new_key_ldap['ipk11id']),
+                 hexlify(new_key_ldap['ipapublickey']))
+-- 
+2.4.3
+
diff --git a/SOURCES/0175-Allow-to-used-mixed-case-for-sysrestore.patch b/SOURCES/0175-Allow-to-used-mixed-case-for-sysrestore.patch
new file mode 100644
index 0000000..24d9208
--- /dev/null
+++ b/SOURCES/0175-Allow-to-used-mixed-case-for-sysrestore.patch
@@ -0,0 +1,86 @@
+From f7e06707be5c590ce03a50117da483931a0680c6 Mon Sep 17 00:00:00 2001
+From: Martin Basti <mbasti@redhat.com>
+Date: Tue, 5 Jan 2016 17:58:49 +0100
+Subject: [PATCH] Allow to used mixed case for sysrestore
+
+This commit allows to use mixed case of keys for sysrestore, before this
+commit all keys were saved in lowercase what prevents to accesing them.
+
+Original usage of mixed case for sysretore key in opendssecinstance had
+to be changed to lowercase to prevent issues on already installed
+systems.
+
+https://fedorahosted.org/freeipa/ticket/5574
+
+Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
+---
+ ipapython/sysrestore.py                 | 4 ++++
+ ipaserver/install/opendnssecinstance.py | 6 ++++--
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/ipapython/sysrestore.py b/ipapython/sysrestore.py
+index 1a111258bc0f6dd503673028d3a990821f077fef..97f0d760ae58c8d4bd0409565bf47167a689a06c 100644
+--- a/ipapython/sysrestore.py
++++ b/ipapython/sysrestore.py
+@@ -67,6 +67,7 @@ class FileStore:
+         self.files = {}
+ 
+         p = ConfigParser.SafeConfigParser()
++        p.optionxform = str
+         p.read(self._index)
+ 
+         for section in p.sections():
+@@ -88,6 +89,7 @@ class FileStore:
+             return
+ 
+         p = ConfigParser.SafeConfigParser()
++        p.optionxform = str
+ 
+         p.add_section('files')
+         for (key, value) in self.files.items():
+@@ -324,6 +326,7 @@ class StateFile:
+         self.modules = {}
+ 
+         p = ConfigParser.SafeConfigParser()
++        p.optionxform = str
+         p.read(self._path)
+ 
+         for module in p.sections():
+@@ -352,6 +355,7 @@ class StateFile:
+             return
+ 
+         p = ConfigParser.SafeConfigParser()
++        p.optionxform = str
+ 
+         for module in self.modules.keys():
+             p.add_section(module)
+diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py
+index c5377d910d8f38a1ea0e05461ecf1b92f05ca2ca..2ab320b8e5db6c7c4e03850ecfe26e0e178d04a1 100644
+--- a/ipaserver/install/opendnssecinstance.py
++++ b/ipaserver/install/opendnssecinstance.py
+@@ -265,11 +265,11 @@ class OpenDNSSECInstance(service.Service):
+ 
+     def __setup_dnssec(self):
+         # run once only
+-        if self.get_state("KASP_DB_configured") and not self.kasp_db_file:
++        if self.get_state("kasp_db_configured") and not self.kasp_db_file:
+             root_logger.debug("Already configured, skipping step")
+             return
+ 
+-        self.backup_state("KASP_DB_configured", True)
++        self.backup_state("kasp_db_configured", True)
+ 
+         if not self.fstore.has_file(paths.OPENDNSSEC_KASP_DB):
+             self.fstore.backup_file(paths.OPENDNSSEC_KASP_DB)
+@@ -368,6 +368,8 @@ class OpenDNSSECInstance(service.Service):
+                 root_logger.debug(error)
+                 pass
+ 
++        self.restore_state("kasp_db_configured")  # just eat state
++
+         # disabled by default, by ldap_enable()
+         if enabled:
+             self.enable()
+-- 
+2.4.3
+
diff --git a/SOURCES/0176-prevent-crash-of-CA-less-server-upgrade-due-to-absen.patch b/SOURCES/0176-prevent-crash-of-CA-less-server-upgrade-due-to-absen.patch
new file mode 100644
index 0000000..b24e5d7
--- /dev/null
+++ b/SOURCES/0176-prevent-crash-of-CA-less-server-upgrade-due-to-absen.patch
@@ -0,0 +1,77 @@
+From 61f54afcde1df217fec01aa9ab38b0b9b704c501 Mon Sep 17 00:00:00 2001
+From: Martin Babinsky <mbabinsk@redhat.com>
+Date: Tue, 5 Jan 2016 13:00:24 +0100
+Subject: [PATCH] prevent crash of CA-less server upgrade due to absent
+ certmonger
+
+ipa-server-upgrade tests whether certmonger service is running before
+attempting to upgrade IPA master. This causes the upgrader to always fail when
+there is no CA installer and certmonger is not needed, effectively preventing
+CA-less IPA master to upgrade succefuly.
+
+This test is now skipped if CA is not enabled.
+
+https://fedorahosted.org/freeipa/ticket/5519
+
+Reviewed-By: Jan Cholasta <jcholast@redhat.com>
+---
+ ipaserver/install/server/upgrade.py | 29 +++++++++++++++++++++++++++--
+ 1 file changed, 27 insertions(+), 2 deletions(-)
+
+diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
+index 945cb3ebd63767cb1d57083e1da7c5605ac5a2f9..616fba5c1a5b3737481aecbb09ab5344641a3b04 100644
+--- a/ipaserver/install/server/upgrade.py
++++ b/ipaserver/install/server/upgrade.py
+@@ -292,6 +292,24 @@ def setup_firefox_extension(fstore):
+     http.setup_firefox_extension(realm, domain)
+ 
+ 
++def is_ca_enabled():
++    """
++    check whether there is an active CA master
++    :return: True if there is an active CA in topology, False otherwise
++    """
++    ldap2 = api.Backend.ldap2
++    was_connected = ldap2.isconnected()
++
++    if not was_connected:
++        ldap2.connect()
++
++    try:
++        return api.Command.ca_is_enabled()['result']
++    finally:
++        if not was_connected:
++            ldap2.disconnect()
++
++
+ def ca_configure_profiles_acl(ca):
+     root_logger.info('[Authorizing RA Agent to modify profiles]')
+ 
+@@ -1416,7 +1434,9 @@ def upgrade_configuration():
+     http = httpinstance.HTTPInstance(fstore)
+     http.configure_selinux_for_httpd()
+     http.change_mod_nss_port_from_http()
+-    http.configure_certmonger_renewal_guard()
++
++    if is_ca_enabled():
++        http.configure_certmonger_renewal_guard()
+ 
+     ds.configure_dirsrv_ccache()
+ 
+@@ -1562,7 +1582,12 @@ def upgrade_check(options):
+         print unicode(e)
+         sys.exit(1)
+ 
+-    if not services.knownservices.certmonger.is_running():
++    try:
++        ca_is_enabled = is_ca_enabled()
++    except Exception as e:
++        raise RuntimeError("Cannot connect to LDAP server: {0}".format(e))
++
++    if not services.knownservices.certmonger.is_running() and ca_is_enabled:
+         raise RuntimeError('Certmonger is not running. Start certmonger and run upgrade again.')
+ 
+     if not options.skip_version_check:
+-- 
+2.4.3
+
diff --git a/SOURCES/0177-Upgrade-Fix-upgrade-of-NIS-Server-configuration.patch b/SOURCES/0177-Upgrade-Fix-upgrade-of-NIS-Server-configuration.patch
new file mode 100644
index 0000000..6dd6c5d
--- /dev/null
+++ b/SOURCES/0177-Upgrade-Fix-upgrade-of-NIS-Server-configuration.patch
@@ -0,0 +1,251 @@
+From e22b4320033803331ce8960d05113666fe9192ec Mon Sep 17 00:00:00 2001
+From: Martin Basti <mbasti@redhat.com>
+Date: Wed, 6 Jan 2016 19:47:22 +0100
+Subject: [PATCH] Upgrade: Fix upgrade of NIS Server configuration
+
+Former upgrade file always created the NIS Server container, that caused
+the ipa-nis-manage did not set all required NIS maps. Default creation
+of container has been removed.
+
+Updating of NIS Server configuration and
+NIS maps is done only if the NIS Server container exists.
+
+https://fedorahosted.org/freeipa/ticket/5507
+
+Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
+---
+ install/share/Makefile.am               |  1 +
+ install/share/nis-update.uldif          | 38 +++++++++++++++
+ install/updates/50-nis.update           | 58 ++--------------------
+ ipaplatform/base/paths.py               |  1 +
+ ipaserver/install/plugins/update_nis.py | 86 +++++++++++++++++++++++++++++++++
+ 5 files changed, 129 insertions(+), 55 deletions(-)
+ create mode 100644 install/share/nis-update.uldif
+ create mode 100644 ipaserver/install/plugins/update_nis.py
+
+diff --git a/install/share/Makefile.am b/install/share/Makefile.am
+index e4cca8708ab0042d6cb37eba31341e53e3cdac4d..09a341ce177e16e14e7d606e5628e6ca21ddf872 100644
+--- a/install/share/Makefile.am
++++ b/install/share/Makefile.am
+@@ -60,6 +60,7 @@ app_DATA =				\
+ 	memberof-task.ldif		\
+ 	memberof-conf.ldif		\
+ 	nis.uldif			\
++	nis-update.uldif			\
+ 	opendnssec_conf.template	\
+ 	opendnssec_kasp.template	\
+ 	unique-attributes.ldif		\
+diff --git a/install/share/nis-update.uldif b/install/share/nis-update.uldif
+new file mode 100644
+index 0000000000000000000000000000000000000000..e602c1de061fbcece349b2d86970c4db5051473b
+--- /dev/null
++++ b/install/share/nis-update.uldif
+@@ -0,0 +1,38 @@
++# Updates for NIS
++
++# Correct syntax error that caused users to not appear
++dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config
++replace:nis-value-format: %merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")
++
++# Correct syntax error that caused nested netgroups to not work
++# https://bugzilla.redhat.com/show_bug.cgi?id=788625
++dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config
++replace:nis-value-format: %merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")
++
++# Make the padding an expression so usercat and hostcat always gets
++# evaluated when displaying entries.
++# https://bugzilla.redhat.com/show_bug.cgi?id=767372
++dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config
++replace:nis-value-format: %merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\"),%{nisDomainName:-})")
++
++dn: nis-domain=$DOMAIN+nis-map=ethers.byaddr, cn=NIS Server, cn=plugins, cn=config
++default:objectclass: top
++default:objectclass: extensibleObject
++default:nis-domain: $DOMAIN
++default:nis-map: ethers.byaddr
++default:nis-base: cn=computers, cn=accounts, $SUFFIX
++default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost))
++default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6")
++default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7")
++default:nis-secure: no
++
++dn: nis-domain=$DOMAIN+nis-map=ethers.byname, cn=NIS Server, cn=plugins, cn=config
++default:objectclass: top
++default:objectclass: extensibleObject
++default:nis-domain: $DOMAIN
++default:nis-map: ethers.byname
++default:nis-base: cn=computers, cn=accounts, $SUFFIX
++default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost))
++default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%7")
++default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7")
++default:nis-secure: no
+diff --git a/install/updates/50-nis.update b/install/updates/50-nis.update
+index 149889ec7bdb38073eb6df88628792526cfe58e6..05a166f003aefc50fc25f10f01f7364d752425bc 100644
+--- a/install/updates/50-nis.update
++++ b/install/updates/50-nis.update
+@@ -1,55 +1,3 @@
+-# NIS Server plugin must be disabled by default
+-# command 'ipa-nis-manage enable' enables NIS server
+-dn: cn=NIS Server,cn=plugins,cn=config
+-default:objectclass: top
+-default:objectclass: nsSlapdPlugin
+-default:objectclass: extensibleObject
+-default:cn: NIS Server
+-default:nsslapd-pluginpath: /usr/lib$LIBARCH/dirsrv/plugins/nisserver-plugin.so
+-default:nsslapd-plugininitfunc: nis_plugin_init
+-default:nsslapd-plugintype: object
+-default:nsslapd-pluginbetxn: on
+-default:nsslapd-pluginenabled: off
+-default:nsslapd-pluginid: nis-server
+-default:nsslapd-pluginversion: 0.10
+-default:nsslapd-pluginvendor: redhat.com
+-default:nsslapd-plugindescription: NIS Server Plugin
+-default:nis-tcp-wrappers-name: nis-server
+-
+-# Correct syntax error that caused users to not appear
+-dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config
+-replace:nis-value-format: %merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")
+-
+-# Correct syntax error that caused nested netgroups to not work
+-# https://bugzilla.redhat.com/show_bug.cgi?id=788625
+-dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config
+-replace:nis-value-format: %merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")
+-
+-# Make the padding an expression so usercat and hostcat always gets
+-# evaluated when displaying entries.
+-# https://bugzilla.redhat.com/show_bug.cgi?id=767372
+-dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config
+-replace:nis-value-format: %merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\"),%{nisDomainName:-})")
+-
+-dn: nis-domain=$DOMAIN+nis-map=ethers.byaddr, cn=NIS Server, cn=plugins, cn=config
+-default:objectclass: top
+-default:objectclass: extensibleObject
+-default:nis-domain: $DOMAIN
+-default:nis-map: ethers.byaddr
+-default:nis-base: cn=computers, cn=accounts, $SUFFIX
+-default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost))
+-default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6")
+-default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7")
+-default:nis-secure: no
+-
+-dn: nis-domain=$DOMAIN+nis-map=ethers.byname, cn=NIS Server, cn=plugins, cn=config
+-default:objectclass: top
+-default:objectclass: extensibleObject
+-default:nis-domain: $DOMAIN
+-default:nis-map: ethers.byname
+-default:nis-base: cn=computers, cn=accounts, $SUFFIX
+-default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost))
+-default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%7")
+-default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7")
+-default:nis-secure: no
+-
++# Updates are applied only if NIS plugin has been configured
++# update definitions are located in install/share/nis-update.uldif
++plugin: update_nis_configuration
+diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
+index 215caf90ea1ca4e5db8f43f8f09002ce5d5cd280..12eb50bb2edd1680313c1e23c7ec83ede9fbd70c 100644
+--- a/ipaplatform/base/paths.py
++++ b/ipaplatform/base/paths.py
+@@ -247,6 +247,7 @@ class BasePathNamespace(object):
+     HTML_KRBREALM_CON = "/usr/share/ipa/html/krbrealm.con"
+     PREFERENCES_HTML = "/usr/share/ipa/html/preferences.html"
+     NIS_ULDIF = "/usr/share/ipa/nis.uldif"
++    NIS_UPDATE_ULDIF = "/usr/share/ipa/nis-update.uldif"
+     IPA_PLUGINS = "/usr/share/ipa/plugins"
+     SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/schema_compat.uldif"
+     IPA_JS_PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins"
+diff --git a/ipaserver/install/plugins/update_nis.py b/ipaserver/install/plugins/update_nis.py
+new file mode 100644
+index 0000000000000000000000000000000000000000..6e12fed8c26cd3b12052700f4d4be5734121fc64
+--- /dev/null
++++ b/ipaserver/install/plugins/update_nis.py
+@@ -0,0 +1,86 @@
++#
++# Copyright (C) 2015  FreeIPA Contributors see COPYING for license
++#
++
++from ipalib.plugable import Registry
++from ipalib import errors
++from ipalib import Updater
++from ipaplatform.paths import paths
++from ipapython.dn import DN
++from ipaserver.install import sysupgrade
++from ipaserver.install.ldapupdate import LDAPUpdate
++
++register = Registry()
++
++
++@register()
++class update_nis_configuration(Updater):
++    """Update NIS configuration
++
++    NIS configuration can be updated only if NIS Server was configured via
++    ipa-nis-manage command.
++    """
++
++    def __recover_from_missing_maps(self, ldap):
++        # https://fedorahosted.org/freeipa/ticket/5507
++        # if all following DNs are missing, but 'NIS Server' container exists
++        # we are experiencig bug and maps should be fixed
++
++        if sysupgrade.get_upgrade_state('nis',
++                                        'done_recover_from_missing_maps'):
++            # this recover must be done only once, a user may deleted some
++            # maps, we do not want to restore them again
++            return
++
++        self.log.debug("Recovering from missing NIS maps bug")
++
++        suffix = "cn=NIS Server,cn=plugins,cn=config"
++        domain = self.api.env.domain
++        missing_dn_list = [
++            DN(nis_map.format(domain=domain, suffix=suffix)) for nis_map in [
++                "nis-domain={domain}+nis-map=passwd.byname,{suffix}",
++                "nis-domain={domain}+nis-map=passwd.byuid,{suffix}",
++                "nis-domain={domain}+nis-map=group.byname,{suffix}",
++                "nis-domain={domain}+nis-map=group.bygid,{suffix}",
++                "nis-domain={domain}+nis-map=netid.byname,{suffix}",
++                "nis-domain={domain}+nis-map=netgroup,{suffix}",
++            ]
++        ]
++
++        for dn in missing_dn_list:
++            try:
++                ldap.get_entry(dn, attrs_list=['cn'])
++            except errors.NotFound:
++                pass
++            else:
++                # bug is not effective, at least one of 'possible missing'
++                # maps was detected
++                return
++
++        sysupgrade.set_upgrade_state('nis', 'done_recover_from_missing_maps',
++                                     True)
++
++        # bug is effective run update to recreate missing maps
++        ld = LDAPUpdate(sub_dict={}, ldapi=True)
++        ld.update([paths.NIS_ULDIF])
++
++    def execute(self, **options):
++        ldap = self.api.Backend.ldap2
++        dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config'))
++        try:
++            ldap.get_entry(dn, attrs_list=['cn'])
++        except errors.NotFound:
++            # NIS is not configured on system, do not execute update
++            self.log.debug("Skipping NIS update, NIS Server is not configured")
++
++            # container does not exist, bug #5507 is not effective
++            sysupgrade.set_upgrade_state(
++                'nis', 'done_recover_from_missing_maps', True)
++        else:
++            self.__recover_from_missing_maps(ldap)
++
++            self.log.debug("Executing NIS Server update")
++            ld = LDAPUpdate(sub_dict={}, ldapi=True)
++            ld.update([paths.NIS_UPDATE_ULDIF])
++
++        return False, ()
+-- 
+2.4.3
+
diff --git a/SOURCES/0178-use-FFI-call-to-rpmvercmp-function-for-version-compa.patch b/SOURCES/0178-use-FFI-call-to-rpmvercmp-function-for-version-compa.patch
new file mode 100644
index 0000000..efe0431
--- /dev/null
+++ b/SOURCES/0178-use-FFI-call-to-rpmvercmp-function-for-version-compa.patch
@@ -0,0 +1,112 @@
+From fcdfeb962a0643dca7f2e1a32f0a5e9f8ff5595d Mon Sep 17 00:00:00 2001
+From: Martin Babinsky <mbabinsk@redhat.com>
+Date: Mon, 11 Jan 2016 16:22:40 +0100
+Subject: [PATCH] use FFI call to rpmvercmp function for version comparison
+
+Stop using rpm-python to compare package versions since the implicit NSS
+initialization upon  the module import breaks NSS handling in IPA code. Call
+rpm-libs C-API function via CFFI instead.
+
+Big thanks to Martin Kosek <mkosek@redhat.com> for sharing the code snippet
+that spurred this patch.
+
+https://fedorahosted.org/freeipa/ticket/5572
+
+Reviewed-By: Jan Cholasta <jcholast@redhat.com>
+---
+ freeipa.spec.in             |  2 +-
+ ipaplatform/redhat/tasks.py | 44 ++++++++++++--------------------------------
+ 2 files changed, 13 insertions(+), 33 deletions(-)
+
+diff --git a/freeipa.spec.in b/freeipa.spec.in
+index 01d42bc621c83541af7517d6d91eb37fd5b5c5cc..cd26d4ce66e320f8b8bf6aaa3e738b4c11f89aa9 100644
+--- a/freeipa.spec.in
++++ b/freeipa.spec.in
+@@ -159,7 +159,7 @@ Requires: p11-kit
+ Requires: systemd-python
+ Requires: %{etc_systemd_dir}
+ Requires: gzip
+-Requires: rpm-python
++Requires: rpm-libs
+ 
+ Conflicts: %{alt_name}-server
+ Obsoletes: %{alt_name}-server < %{version}
+diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py
+index 2e894d776dcd5542e6c11cc0210add8ad9d90298..9be3ef664e6d15c31e53b7a8123de7b6bb2b81fe 100644
+--- a/ipaplatform/redhat/tasks.py
++++ b/ipaplatform/redhat/tasks.py
+@@ -30,7 +30,8 @@ import socket
+ import sys
+ import urllib
+ import base64
+-import rpm
++from cffi import FFI
++from ctypes.util import find_library
+ from functools import total_ordering
+ 
+ from subprocess import CalledProcessError
+@@ -47,35 +48,14 @@ from ipaplatform.paths import paths
+ from ipaplatform.redhat.authconfig import RedHatAuthConfig
+ from ipaplatform.base.tasks import BaseTaskNamespace
+ 
++_ffi = FFI()
++_ffi.cdef("""
++int rpmvercmp (const char *a, const char *b);
++""")
+ 
+-# copied from rpmUtils/miscutils.py
+-def stringToVersion(verstring):
+-    if verstring in [None, '']:
+-        return (None, None, None)
+-    i = verstring.find(':')
+-    if i != -1:
+-        try:
+-            epoch = str(long(verstring[:i]))
+-        except ValueError:
+-            # look, garbage in the epoch field, how fun, kill it
+-            epoch = '0' # this is our fallback, deal
+-    else:
+-        epoch = '0'
+-    j = verstring.find('-')
+-    if j != -1:
+-        if verstring[i + 1:j] == '':
+-            version = None
+-        else:
+-            version = verstring[i + 1:j]
+-        release = verstring[j + 1:]
+-    else:
+-        if verstring[i + 1:] == '':
+-            version = None
+-        else:
+-            version = verstring[i + 1:]
+-        release = None
+-    return (epoch, version, release)
+-
++# use ctypes loader to get correct librpm.so library version according to
++# https://cffi.readthedocs.org/en/latest/overview.html#id8
++_librpm = _ffi.dlopen(find_library("rpm"))
+ 
+ log = log_mgr.get_logger(__name__)
+ 
+@@ -100,15 +80,15 @@ def selinux_enabled():
+ class IPAVersion(object):
+ 
+     def __init__(self, version):
+-        self.version_tuple = stringToVersion(version)
++        self.version = version
+ 
+     def __eq__(self, other):
+         assert isinstance(other, IPAVersion)
+-        return rpm.labelCompare(self.version_tuple, other.version_tuple) == 0
++        return _librpm.rpmvercmp(self.version, other.version) == 0
+ 
+     def __lt__(self, other):
+         assert isinstance(other, IPAVersion)
+-        return rpm.labelCompare(self.version_tuple, other.version_tuple) == -1
++        return _librpm.rpmvercmp(self.version, other.version) < 0
+ 
+ 
+ class RedHatTaskNamespace(BaseTaskNamespace):
+-- 
+2.4.3
+
diff --git a/SOURCES/0179-ipalib-assume-version-2.0-when-skip_version_check-is.patch b/SOURCES/0179-ipalib-assume-version-2.0-when-skip_version_check-is.patch
new file mode 100644
index 0000000..1563374
--- /dev/null
+++ b/SOURCES/0179-ipalib-assume-version-2.0-when-skip_version_check-is.patch
@@ -0,0 +1,36 @@
+From 88c057bc798b2606bafbed5c0b76475b0640b5e8 Mon Sep 17 00:00:00 2001
+From: Jan Cholasta <jcholast@redhat.com>
+Date: Tue, 12 Jan 2016 15:41:43 +0100
+Subject: [PATCH] ipalib: assume version 2.0 when skip_version_check is enabled
+
+https://fedorahosted.org/freeipa/ticket/5601
+
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipalib/frontend.py | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/ipalib/frontend.py b/ipalib/frontend.py
+index 2ca3aaea82ea63702052eedbd7e4081f239cbaed..8adcee925a24fd546d7000e9239353da273e0bc9 100644
+--- a/ipalib/frontend.py
++++ b/ipalib/frontend.py
+@@ -26,7 +26,6 @@ from distutils import version
+ 
+ from ipapython.version import API_VERSION
+ from ipapython.ipa_log_manager import root_logger
+-from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES
+ from base import NameSpace
+ from plugable import Plugin
+ from parameters import create_param, Param, Str, Flag, Password
+@@ -425,7 +424,7 @@ class Command(HasParam):
+         if version_provided:
+             self.verify_client_version(unicode(options['version']))
+         elif self.api.env.skip_version_check and not self.api.env.in_server:
+-            options['version'] = VERSION_WITHOUT_CAPABILITIES
++            options['version'] = u'2.0'
+         else:
+             options['version'] = API_VERSION
+         params = self.args_options_2_params(*args, **options)
+-- 
+2.4.3
+
diff --git a/SOURCES/0180-always-start-certmonger-during-IPA-server-configurat.patch b/SOURCES/0180-always-start-certmonger-during-IPA-server-configurat.patch
new file mode 100644
index 0000000..b53e599
--- /dev/null
+++ b/SOURCES/0180-always-start-certmonger-during-IPA-server-configurat.patch
@@ -0,0 +1,87 @@
+From 80115a38d78db0c2a31dea06786af41eafb234f0 Mon Sep 17 00:00:00 2001
+From: Martin Babinsky <mbabinsk@redhat.com>
+Date: Mon, 1 Feb 2016 12:59:04 +0100
+Subject: [PATCH] always start certmonger during IPA server configuration
+ upgrade
+
+This patch fixes a regression introduced by commit
+bef0f4c5c38e7ff6415e8f8c96dc306ef7f0ce56. Instead of checking whether
+there is CA installed in the topology, we should always start certmonger
+service during upgrade regardless when CA was configured.
+
+https://fedorahosted.org/freeipa/ticket/5655
+
+Reviewed-By: Jan Cholasta <jcholast@redhat.com>
+Reviewed-By: Martin Basti <mbasti@redhat.com>
+---
+ ipaserver/install/server/upgrade.py | 33 +++++----------------------------
+ 1 file changed, 5 insertions(+), 28 deletions(-)
+
+diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
+index 616fba5c1a5b3737481aecbb09ab5344641a3b04..1f1cfeb672809c0298c69c121ac38d6c7a482d11 100644
+--- a/ipaserver/install/server/upgrade.py
++++ b/ipaserver/install/server/upgrade.py
+@@ -292,24 +292,6 @@ def setup_firefox_extension(fstore):
+     http.setup_firefox_extension(realm, domain)
+ 
+ 
+-def is_ca_enabled():
+-    """
+-    check whether there is an active CA master
+-    :return: True if there is an active CA in topology, False otherwise
+-    """
+-    ldap2 = api.Backend.ldap2
+-    was_connected = ldap2.isconnected()
+-
+-    if not was_connected:
+-        ldap2.connect()
+-
+-    try:
+-        return api.Command.ca_is_enabled()['result']
+-    finally:
+-        if not was_connected:
+-            ldap2.disconnect()
+-
+-
+ def ca_configure_profiles_acl(ca):
+     root_logger.info('[Authorizing RA Agent to modify profiles]')
+ 
+@@ -1420,6 +1402,10 @@ def upgrade_configuration():
+             )
+         upgrade_pki(ca, fstore)
+ 
++    certmonger_service = services.knownservices.certmonger
++    if ca.is_configured() and not certmonger_service.is_running():
++        certmonger_service.start()
++
+     ca.configure_certmonger_renewal_guard()
+ 
+     update_dbmodules(api.env.realm)
+@@ -1435,8 +1421,7 @@ def upgrade_configuration():
+     http.configure_selinux_for_httpd()
+     http.change_mod_nss_port_from_http()
+ 
+-    if is_ca_enabled():
+-        http.configure_certmonger_renewal_guard()
++    http.configure_certmonger_renewal_guard()
+ 
+     ds.configure_dirsrv_ccache()
+ 
+@@ -1582,14 +1567,6 @@ def upgrade_check(options):
+         print unicode(e)
+         sys.exit(1)
+ 
+-    try:
+-        ca_is_enabled = is_ca_enabled()
+-    except Exception as e:
+-        raise RuntimeError("Cannot connect to LDAP server: {0}".format(e))
+-
+-    if not services.knownservices.certmonger.is_running() and ca_is_enabled:
+-        raise RuntimeError('Certmonger is not running. Start certmonger and run upgrade again.')
+-
+     if not options.skip_version_check:
+         # check IPA version and data version
+         try:
+-- 
+2.5.0
+
diff --git a/SOURCES/ipa-centos-branding.patch b/SOURCES/ipa-centos-branding.patch
deleted file mode 100644
index 673cd2f..0000000
--- a/SOURCES/ipa-centos-branding.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 99efecaf87dc1fc9517efaff441a6a7ce46444eb Mon Sep 17 00:00:00 2001
-From: Jim Perrin <jperrin@centos.org>
-Date: Wed, 11 Mar 2015 10:37:03 -0500
-Subject: [PATCH] update for new ntp server method
-
----
- ipaplatform/base/paths.py        | 1 +
- ipaserver/install/ntpinstance.py | 2 ++
- 2 files changed, 3 insertions(+)
-
-diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
-index af50262..5090062 100644
---- a/ipaplatform/base/paths.py
-+++ b/ipaplatform/base/paths.py
-@@ -99,6 +99,7 @@ class BasePathNamespace(object):
-     PKI_TOMCAT_ALIAS_DIR = "/etc/pki/pki-tomcat/alias/"
-     PKI_TOMCAT_PASSWORD_CONF = "/etc/pki/pki-tomcat/password.conf"
-     ETC_REDHAT_RELEASE = "/etc/redhat-release"
-+    ETC_CENTOS_RELEASE = "/etc/centos-release"
-     RESOLV_CONF = "/etc/resolv.conf"
-     SAMBA_KEYTAB = "/etc/samba/samba.keytab"
-     SMB_CONF = "/etc/samba/smb.conf"
-diff --git a/ipaserver/install/ntpinstance.py b/ipaserver/install/ntpinstance.py
-index c653525..4b0578b 100644
---- a/ipaserver/install/ntpinstance.py
-+++ b/ipaserver/install/ntpinstance.py
-@@ -44,6 +44,8 @@ class NTPInstance(service.Service):
-         os = ""
-         if ipautil.file_exists(paths.ETC_FEDORA_RELEASE):
-             os = "fedora"
-+        elif ipautil.file_exists(paths.ETC_CENTOS_RELEASE):
-+            os = "centos"
-         elif ipautil.file_exists(paths.ETC_REDHAT_RELEASE):
-             os = "rhel"
- 
--- 
-1.8.3.1
-
diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec
index 13775be..50d5e2f 100644
--- a/SPECS/ipa.spec
+++ b/SPECS/ipa.spec
@@ -35,7 +35,7 @@
 
 Name:           ipa
 Version:        4.2.0
-Release:        15%{?dist}.3
+Release:        15%{?dist}.6
 Summary:        The Identity, Policy and Audit system
 
 Group:          System Environment/Base
@@ -43,10 +43,10 @@ License:        GPLv3+
 URL:            http://www.freeipa.org/
 Source0:        http://www.freeipa.org/downloads/src/freeipa-%{VERSION}.tar.gz
 # RHEL spec file only: START: Change branding to IPA and Identity-Management
-#Source1:        header-logo.png
-#Source2:        login-screen-background.jpg
-#Source3:        login-screen-logo.png
-#Source4:        product-name.png
+Source1:        header-logo.png
+Source2:        login-screen-background.jpg
+Source3:        login-screen-logo.png
+Source4:        product-name.png
 # RHEL spec file only: END: Change branding to IPA and Identity-Management
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -210,6 +210,27 @@ Patch0156:      0156-Add-profiles-and-default-CA-ACL-on-migration.patch
 Patch0157:      0157-disconnect-ldap2-backend-after-adding-default-CA-ACL.patch
 Patch0158:      0158-do-not-disconnect-when-using-existing-connection-to-.patch
 Patch0159:      0159-Fix-upgrade-of-forwardzones-when-zone-is-in-realmdom.patch
+Patch0160:      0160-Fix-version-comparison.patch
+Patch0161:      0161-DNS-fix-file-permissions.patch
+Patch0162:      0162-Explicitly-call-chmod-on-newly-created-directories.patch
+Patch0163:      0163-Fix-replace-mkdir-with-chmod.patch
+Patch0164:      0164-DNSSEC-Improve-error-reporting-from-ipa-ods-exporter.patch
+Patch0165:      0165-DNSSEC-Make-sure-that-current-state-in-OpenDNSSEC-ma.patch
+Patch0166:      0166-DNSSEC-Make-sure-that-current-key-state-in-LDAP-matc.patch
+Patch0167:      0167-DNSSEC-remove-obsolete-TODO-note.patch
+Patch0168:      0168-DNSSEC-add-debug-mode-to-ldapkeydb.py.patch
+Patch0169:      0169-DNSSEC-logging-improvements-in-ipa-ods-exporter.patch
+Patch0170:      0170-DNSSEC-remove-keys-purged-by-OpenDNSSEC-from-master-.patch
+Patch0171:      0171-DNSSEC-ipa-dnskeysyncd-Skip-zones-with-old-DNSSEC-me.patch
+Patch0172:      0172-DNSSEC-ipa-ods-exporter-add-ldap-cleanup-command.patch
+Patch0173:      0173-DNSSEC-ipa-dnskeysyncd-call-ods-signer-ldap-cleanup-.patch
+Patch0174:      0174-DNSSEC-Log-debug-messages-at-log-level-DEBUG.patch
+Patch0175:      0175-Allow-to-used-mixed-case-for-sysrestore.patch
+Patch0176:      0176-prevent-crash-of-CA-less-server-upgrade-due-to-absen.patch
+Patch0177:      0177-Upgrade-Fix-upgrade-of-NIS-Server-configuration.patch
+Patch0178:      0178-use-FFI-call-to-rpmvercmp-function-for-version-compa.patch
+Patch0179:      0179-ipalib-assume-version-2.0-when-skip_version_check-is.patch
+Patch0180:      0180-always-start-certmonger-during-IPA-server-configurat.patch
 
 Patch1001:      1001-Hide-pkinit-functionality-from-production-version.patch
 Patch1002:      1002-Remove-pkinit-plugin.patch
@@ -221,7 +242,6 @@ Patch1007:      1007-Do-not-build-tests.patch
 Patch1008:      1008-RCUE.patch
 Patch1009:      1009-Do-not-allow-installation-in-FIPS-mode.patch
 Patch1010:      1010-WebUI-add-API-browser-is-experimental-warning.patch
-Patch1011:      ipa-centos-branding.patch
 # RHEL spec file only: END
 
 %if ! %{ONLY_CLIENT}
@@ -346,14 +366,17 @@ Requires(pre): certmonger >= 0.78
 Requires(pre): 389-ds-base >= 1.3.4.0
 Requires: fontawesome-fonts
 Requires: open-sans-fonts
-Requires: openssl
+# RHEL spec file only: START
+Requires(pre): openssl >= 1:1.0.1e-42
+# RHEL spec file only: END
+Requires: openssl >= 1:1.0.1e-42
 Requires: softhsm >= 2.0.0rc1-1
 Requires: p11-kit
 Requires: systemd-python
 Requires: %{etc_systemd_dir}
 Requires: gzip
 # RHEL spec file only: START
-# Requires: redhat-access-plugin-ipa
+Requires: redhat-access-plugin-ipa
 # RHEL spec file only: END
 
 Conflicts: %{alt_name}-server
@@ -562,10 +585,10 @@ for p in %patches ; do
 done
 
 # Red Hat's Identity Management branding
-#cp %SOURCE1 install/ui/images/header-logo.png
-#cp %SOURCE2 install/ui/images/login-screen-background.jpg
-#cp %SOURCE3 install/ui/images/login-screen-logo.png
-#cp %SOURCE4 install/ui/images/product-name.png
+cp %SOURCE1 install/ui/images/header-logo.png
+cp %SOURCE2 install/ui/images/login-screen-background.jpg
+cp %SOURCE3 install/ui/images/login-screen-logo.png
+cp %SOURCE4 install/ui/images/product-name.png
 # RHEL spec file only: END
 
 %build
@@ -1162,8 +1185,50 @@ fi
 # RHEL spec file only: DELETED: Do not build tests
 
 %changelog
-* Tue Dec 08 2015 CentOS Sources <bugs@centos.org> - 4.2.0-15.el7.centos.3
-- Roll in CentOS Branding
+* Tue Feb  2 2016 Jan Cholasta <jcholast@redhat.com> - 4.2.0-15.6
+- Resolves: #1298103 ipa-server-upgrade fails if certmonger is not running
+  - always start certmonger during IPA server configuration upgrade
+
+* Wed Jan 27 2016 Jan Cholasta <jcholast@redhat.com> - 4.2.0-15.5
+- Resolves: #1298097 IPA server upgrade fails from RHEL 7.0 to RHEL 7.2 using
+  "yum update ipa* sssd"
+  - Set minimal required version for openssl
+
+* Tue Jan 12 2016 Jan Cholasta <jcholast@redhat.com> - 4.2.0-15.4
+- Resolves: #1298097 IPA server upgrade fails from RHEL 7.0 to RHEL 7.2 using
+  "yum update ipa* sssd"
+  - Set minimal required version for openssl
+- Resolves: #1298098 ipa-nis-manage does not update ldap with all NIS maps
+  - Upgrade: Fix upgrade of NIS Server configuration
+- Resolves: #1298099 umask setting causes named-pkcs11 issue with directory
+  permissions on /var/lib/ipa/dnssec
+  - DNS: fix file permissions
+  - Explicitly call chmod on newly created directories
+  - Fix: replace mkdir with chmod
+- Resolves: #1298100 Broken 7.2.0 to 7.2.z upgrade - flawed version comparison
+  - Fix version comparison
+  - use FFI call to rpmvercmp function for version comparison
+- Resolves: #1298101 Sysrestore did not restore state if a key is specified in
+  mixed case
+  - Allow to used mixed case for sysrestore
+- Resolves: #1298102 DNSSEC key purging is not handled properly
+  - DNSSEC: Improve error reporting from ipa-ods-exporter
+  - DNSSEC: Make sure that current state in OpenDNSSEC matches key state in
+    LDAP
+  - DNSSEC: Make sure that current key state in LDAP matches key state in BIND
+  - DNSSEC: remove obsolete TODO note
+  - DNSSEC: add debug mode to ldapkeydb.py
+  - DNSSEC: logging improvements in ipa-ods-exporter
+  - DNSSEC: remove keys purged by OpenDNSSEC from master HSM from LDAP
+  - DNSSEC: ipa-dnskeysyncd: Skip zones with old DNSSEC metadata in LDAP
+  - DNSSEC: ipa-ods-exporter: add ldap-cleanup command
+  - DNSSEC: ipa-dnskeysyncd: call ods-signer ldap-cleanup on zone removal
+  - DNSSEC: Log debug messages at log level DEBUG
+- Resolves: #1298103 ipa-server-upgrade fails if certmonger is not running
+  - prevent crash of CA-less server upgrade due to absent certmonger
+- Resolves: #1298104 The ipa -e skip_version_check=1 still issues
+  incompatibility error when called against RHEL 6 server
+  - ipalib: assume version 2.0 when skip_version_check is enabled
 
 * Wed Nov 25 2015 Jan Cholasta <jcholast@redhat.com> - 4.2.0-15.3
 - Resolves: #1284052 IPA DNS Zone/DNS Forward Zone details missing after