summaryrefslogtreecommitdiffstats
path: root/ipapython/dnssec/odsmgr.py
diff options
context:
space:
mode:
Diffstat (limited to 'ipapython/dnssec/odsmgr.py')
-rw-r--r--ipapython/dnssec/odsmgr.py210
1 files changed, 0 insertions, 210 deletions
diff --git a/ipapython/dnssec/odsmgr.py b/ipapython/dnssec/odsmgr.py
deleted file mode 100644
index 0308408e0..000000000
--- a/ipapython/dnssec/odsmgr.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#!/usr/bin/python2
-#
-# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
-#
-
-import dns.name
-try:
- from xml.etree import cElementTree as etree
-except ImportError:
- from xml.etree import ElementTree as etree
-
-from ipapython import ipa_log_manager, ipautil
-
-# hack: zone object UUID is stored as path to imaginary zone file
-ENTRYUUID_PREFIX = "/var/lib/ipa/dns/zone/entryUUID/"
-ENTRYUUID_PREFIX_LEN = len(ENTRYUUID_PREFIX)
-
-
-class ZoneListReader(object):
- def __init__(self):
- self.names = set() # dns.name
- self.uuids = set() # UUID strings
- self.mapping = dict() # {UUID: dns.name}
- self.log = ipa_log_manager.log_mgr.get_logger(self)
-
- def _add_zone(self, name, zid):
- """Add zone & UUID to internal structures.
-
- Zone with given name and UUID must not exist."""
- # detect duplicate zone names
- name = dns.name.from_text(name)
- assert name not in self.names, \
- 'duplicate name (%s, %s) vs. %s' % (name, zid, self.mapping)
- # duplicate non-None zid is not allowed
- assert not zid or zid not in self.uuids, \
- 'duplicate UUID (%s, %s) vs. %s' % (name, zid, self.mapping)
-
- self.names.add(name)
- self.uuids.add(zid)
- self.mapping[zid] = name
-
- def _del_zone(self, name, zid):
- """Remove zone & UUID from internal structures.
-
- Zone with given name and UUID must exist.
- """
- name = dns.name.from_text(name)
- assert zid is not None
- assert name in self.names, \
- 'name (%s, %s) does not exist in %s' % (name, zid, self.mapping)
- assert zid in self.uuids, \
- 'UUID (%s, %s) does not exist in %s' % (name, zid, self.mapping)
- assert zid in self.mapping and name == self.mapping[zid], \
- 'pair {%s: %s} does not exist in %s' % (zid, name, self.mapping)
-
- self.names.remove(name)
- self.uuids.remove(zid)
- del self.mapping[zid]
-
-
-class ODSZoneListReader(ZoneListReader):
- """One-shot parser for ODS zonelist.xml."""
- def __init__(self, zonelist_text):
- super(ODSZoneListReader, self).__init__()
- root = etree.fromstring(zonelist_text)
- self._parse_zonelist(root)
-
- def _parse_zonelist(self, root):
- """iterate over Zone elements with attribute 'name' and
- add IPA zones to self.zones"""
- if not root.tag == 'ZoneList':
- raise ValueError(root.tag)
- for zone_xml in root.findall('./Zone[@name]'):
- name, zid = self._parse_ipa_zone(zone_xml)
- self._add_zone(name, zid)
-
- def _parse_ipa_zone(self, zone_xml):
- """Extract zone name, input adapter and detect IPA zones.
-
- IPA zones have contains Adapters/Input/Adapter element with
- attribute type = "File" and with value prefixed with ENTRYUUID_PREFIX.
-
- Returns:
- tuple (zone name, ID)
- """
- name = zone_xml.get('name')
- zids = []
- for in_adapter in zone_xml.findall(
- './Adapters/Input/Adapter[@type="File"]'):
- path = in_adapter.text
- if path.startswith(ENTRYUUID_PREFIX):
- # strip prefix from path
- zids.append(path[ENTRYUUID_PREFIX_LEN:])
-
- if len(zids) != 1:
- raise ValueError('only IPA zones are supported: {}'.format(
- etree.tostring(zone_xml)))
-
- return name, zids[0]
-
-
-class LDAPZoneListReader(ZoneListReader):
- def __init__(self):
- super(LDAPZoneListReader, self).__init__()
-
- def process_ipa_zone(self, op, uuid, zone_ldap):
- assert (op == 'add' or op == 'del'), 'unsupported op %s' % op
- assert uuid is not None
- assert 'idnsname' in zone_ldap, \
- 'LDAP zone UUID %s without idnsName' % uuid
- assert len(zone_ldap['idnsname']) == 1, \
- 'LDAP zone UUID %s with len(idnsname) != 1' % uuid
-
- if op == 'add':
- self._add_zone(zone_ldap['idnsname'][0], uuid)
- elif op == 'del':
- self._del_zone(zone_ldap['idnsname'][0], uuid)
-
-
-class ODSMgr(object):
- """OpenDNSSEC zone manager. It does LDAP->ODS synchronization.
-
- Zones with idnsSecInlineSigning attribute = TRUE in LDAP are added
- or deleted from ODS as necessary. ODS->LDAP key synchronization
- has to be solved seperatelly.
- """
- def __init__(self):
- self.log = ipa_log_manager.log_mgr.get_logger(self)
- self.zl_ldap = LDAPZoneListReader()
-
- def ksmutil(self, params):
- """Call ods-ksmutil with given parameters and return stdout.
-
- Raises CalledProcessError if returncode != 0.
- """
- cmd = ['ods-ksmutil'] + params
- result = ipautil.run(cmd, capture_output=True)
- return result.output
-
- def get_ods_zonelist(self):
- stdout = self.ksmutil(['zonelist', 'export'])
- reader = ODSZoneListReader(stdout)
- return reader
-
- def add_ods_zone(self, uuid, name):
- zone_path = '%s%s' % (ENTRYUUID_PREFIX, uuid)
- cmd = ['zone', 'add', '--zone', str(name), '--input', zone_path]
- output = self.ksmutil(cmd)
- self.log.info(output)
- self.notify_enforcer()
-
- def del_ods_zone(self, name):
- # ods-ksmutil blows up if zone name has period at the end
- name = name.relativize(dns.name.root)
- # detect if name is root zone
- if name == dns.name.empty:
- name = dns.name.root
- cmd = ['zone', 'delete', '--zone', str(name)]
- 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.
-
- Change is only recorded to memory.
- self.sync() have to be called to synchronize change to ODS."""
- assert op == 'add' or op == 'del'
- self.zl_ldap.process_ipa_zone(op, uuid, attrs)
- self.log.debug("LDAP zones: %s", self.zl_ldap.mapping)
-
- def sync(self):
- """Synchronize list of zones in LDAP with ODS."""
- zl_ods = self.get_ods_zonelist()
- self.log.debug("ODS zones: %s", zl_ods.mapping)
- removed = self.diff_zl(zl_ods, self.zl_ldap)
- self.log.info("Zones removed from LDAP: %s", removed)
- added = self.diff_zl(self.zl_ldap, zl_ods)
- self.log.info("Zones added to LDAP: %s", added)
- for (uuid, name) in removed:
- self.del_ods_zone(name)
- for (uuid, name) in added:
- self.add_ods_zone(uuid, name)
-
- def diff_zl(self, s1, s2):
- """Compute zones present in s1 but not present in s2.
-
- Returns: List of (uuid, name) tuples with zones present only in s1."""
- s1_extra = s1.uuids - s2.uuids
- removed = [(uuid, name) for (uuid, name) in s1.mapping.items()
- if uuid in s1_extra]
- return removed
-
-
-if __name__ == '__main__':
- ipa_log_manager.standard_logging_setup(debug=True)
- ods = ODSMgr()
- reader = ods.get_ods_zonelist()
- ipa_log_manager.root_logger.info('ODS zones: %s', reader.mapping)