Improve FQDN handling in DNS and host plugins

DNS and host plugin does not work well with domain names ending
with dot. host plugin creates a record with two fqdn attributes
when such hostname is created which then has to be manually fixed.
DNS plugin handled zones with and without trailing dot as two
distinct zones, which may lead to issues when both zones are
created.

This patch sanitizes approach to FQDNs in both DNS and host plugin.
Hostnames are now always normalized to the form without trailing
dot as this form did not work before and it would keep hostname
form consistent without changes in our server/client enrollment
process.

As DNS zones always worked in both forms this patch rather makes
sure that the plugin works with both forms of one zone and prevents
creating 2 identical zones with just different format.

https://fedorahosted.org/freeipa/ticket/2420
This commit is contained in:
Martin Kosek 2012-02-28 09:13:13 +01:00
parent 7db1da1d65
commit fab033b949
2 changed files with 40 additions and 31 deletions

View File

@ -401,13 +401,9 @@ def get_reverse_zone(ipaddr, prefixlen=None):
return revzone, revname
def add_records_for_host_validation(option_name, host, domain, ip_addresses, check_forward=True, check_reverse=True):
result = api.Command['dnszone_find']()['result']
match = False
for zone in result:
if domain == zone['idnsname'][0]:
match = True
break
if not match:
try:
api.Command['dnszone_show'](domain)['result']
except errors.NotFound:
raise errors.NotFound(
reason=_('DNS zone %(zone)s not found') % dict(zone=domain)
)
@ -1578,6 +1574,25 @@ class dnszone(LDAPObject):
),
)
def get_dn(self, *keys, **options):
zone = keys[-1]
dn = super(dnszone, self).get_dn(zone, **options)
try:
self.backend.get_entry(dn, [''])
except errors.NotFound:
if zone.endswith(u'.'):
zone = zone[:-1]
else:
zone = zone + u'.'
test_dn = super(dnszone, self).get_dn(zone, **options)
try:
(dn, entry_attrs) = self.backend.get_entry(test_dn, [''])
except errors.NotFound:
pass
return dn
api.register(dnszone)
@ -1601,7 +1616,7 @@ class dnszone_add(LDAPCreate):
self.obj.params['name_from_ip'](unicode(options['name_from_ip']))
return super(dnszone_add, self).args_options_2_params(*args, **options)
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
if not dns_container_exists(self.api.Backend.ldap2):
raise errors.NotFound(reason=_('DNS is not configured'))

View File

@ -176,6 +176,12 @@ def validate_ipaddr(ugettext, ipaddr):
return unicode(e)
return None
def normalize_hostname(hostname):
"""Use common fqdn form without the trailing dot"""
if hostname.endswith(u'.'):
hostname = hostname[:-1]
hostname = hostname.lower()
return hostname
class host(LDAPObject):
"""
@ -223,7 +229,7 @@ class host(LDAPObject):
cli_name='hostname',
label=_('Host name'),
primary_key=True,
normalizer=lambda value: value.lower(),
normalizer=normalize_hostname,
),
Str('description?',
cli_name='desc',
@ -294,8 +300,6 @@ class host(LDAPObject):
def get_dn(self, *keys, **options):
hostname = keys[-1]
if hostname.endswith('.'):
hostname = hostname[:-1]
dn = super(host, self).get_dn(hostname, **options)
try:
self.backend.get_entry(dn, [''])
@ -504,16 +508,11 @@ class host_del(LDAPDelete):
# Remove DNS entries
parts = fqdn.split('.')
domain = unicode('.'.join(parts[1:]))
result = api.Command['dnszone_find']()['result']
match = False
for zone in result:
if domain == zone['idnsname'][0]:
match = True
break
if not match:
raise errors.NotFound(
reason=_('DNS zone %(zone)s not found') % dict(zone=domain)
)
try:
result = api.Command['dnszone_show'](domain)['result']
domain = result['idnsname'][0]
except errors.NotFound:
self.obj.handle_not_found(*keys)
# Get all forward resources for this host
records = api.Command['dnsrecord_find'](domain, idnsname=parts[0])['result']
for record in records:
@ -664,16 +663,11 @@ class host_mod(LDAPUpdate):
if options.get('updatedns', False) and dns_container_exists(ldap):
parts = keys[-1].split('.')
domain = unicode('.'.join(parts[1:]))
result = api.Command['dnszone_find']()['result']
match = False
for zone in result:
if domain == zone['idnsname'][0]:
match = True
break
if not match:
raise errors.NotFound(
reason=_('DNS zone %(zone)s not found') % dict(zone=domain)
)
try:
result = api.Command['dnszone_show'](domain)['result']
domain = result['idnsname'][0]
except errors.NotFound:
self.obj.handle_not_found(*keys)
update_sshfp_record(domain, unicode(parts[0]), entry_attrs)
if 'ipasshpubkey' in entry_attrs: