There are 2 patches improving our zone zonemgr: 1) ipa-server-install --zonemgr option validation and normalization + the same thing in ipa dnszone-add/mod --admin-email. They now allow and correctly process '.' in a local-part of the zonemgr e-mail (it is encoded as '\.'.
How to test: ipa-server-install -p secret123 -a secret123 --setup-dns [email protected] OR if e-mail is passed in SOA format: ipa-server-install -p secret123 -a secret123 --setup-dns --zonemgr='foo\.bar.example.com' In both cases, the zonemgr e-mail will be set to correct format: 'foo \.bar.example.com'. 2) Our default zonemgr is changed to follow RFC 2142 recommendation - hostmaster@<domain> hostmaster is an alias to root anyway (see /etc/aliases). Martin
>From 4201ceab5149ad7fefe4224181b014b8d73b93f5 Mon Sep 17 00:00:00 2001 From: Martin Kosek <[email protected]> Date: Fri, 11 Nov 2011 14:36:54 +0100 Subject: [PATCH 1/2] Improve zonemgr validator and normalizer The validator has been improved to support better both SOA format (e-mail address in a domain name format, without '@') and standard e-mail format. Allow '\.' character in a SOA format encoding the standard '.' in the local-part of an e-mail. Normalization code has been moved to one common function. https://fedorahosted.org/freeipa/ticket/2053 --- API.txt | 6 ++-- ipalib/plugins/dns.py | 11 +------- ipalib/util.py | 47 +++++++++++++++++++++++++++++-------- ipaserver/install/bindinstance.py | 12 +++------ 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/API.txt b/API.txt index 8a8efa0cddb3f0493b7ba8f622d30cacc10398be..4d220817b647a52b46c599ebe38b263cc2bbc99f 100644 --- a/API.txt +++ b/API.txt @@ -858,7 +858,7 @@ args: 1,19,3 arg: Str('idnsname', attribute=True, cli_name='name', default_from=DefaultFrom(<lambda>, 'name_from_ip'), label=Gettext('Zone name', domain='ipa', localedir=None), multivalue=False, normalizer=<lambda>, primary_key=True, required=True) option: Str('name_from_ip', _validate_ipnet, attribute=True, cli_name='name_from_ip', label=Gettext('Reverse zone IP network', domain='ipa', localedir=None), multivalue=False, required=False) option: Str('idnssoamname', attribute=True, cli_name='name_server', label=Gettext('Authoritative nameserver', domain='ipa', localedir=None), multivalue=False, required=True) -option: Str('idnssoarname', _rname_validator, attribute=True, cli_name='admin_email', default_from=DefaultFrom(<lambda>, 'idnsname'), label=Gettext('Administrator e-mail address', domain='ipa', localedir=None), multivalue=False, normalizer=_rname_normalizer, required=True) +option: Str('idnssoarname', _rname_validator, attribute=True, cli_name='admin_email', default_from=DefaultFrom(<lambda>, 'idnsname'), label=Gettext('Administrator e-mail address', domain='ipa', localedir=None), multivalue=False, normalizer=normalize_zonemgr, required=True) option: Int('idnssoaserial', attribute=True, autofill=True, cli_name='serial', create_default=_create_zone_serial, label=Gettext('SOA serial', domain='ipa', localedir=None), minvalue=1, multivalue=False, required=False) option: Int('idnssoarefresh', attribute=True, autofill=True, cli_name='refresh', default=3600, label=Gettext('SOA refresh', domain='ipa', localedir=None), minvalue=0, multivalue=False, required=False) option: Int('idnssoaretry', attribute=True, autofill=True, cli_name='retry', default=900, label=Gettext('SOA retry', domain='ipa', localedir=None), minvalue=0, multivalue=False, required=False) @@ -903,7 +903,7 @@ arg: Str('criteria?', noextrawhitespace=False) option: Str('idnsname', attribute=True, autofill=False, cli_name='name', default_from=DefaultFrom(<lambda>, 'name_from_ip'), label=Gettext('Zone name', domain='ipa', localedir=None), multivalue=False, normalizer=<lambda>, primary_key=True, query=True, required=False) option: Str('name_from_ip', _validate_ipnet, attribute=True, autofill=False, cli_name='name_from_ip', label=Gettext('Reverse zone IP network', domain='ipa', localedir=None), multivalue=False, query=True, required=False) option: Str('idnssoamname', attribute=True, autofill=False, cli_name='name_server', label=Gettext('Authoritative nameserver', domain='ipa', localedir=None), multivalue=False, query=True, required=False) -option: Str('idnssoarname', _rname_validator, attribute=True, autofill=False, cli_name='admin_email', default_from=DefaultFrom(<lambda>, 'idnsname'), label=Gettext('Administrator e-mail address', domain='ipa', localedir=None), multivalue=False, normalizer=_rname_normalizer, query=True, required=False) +option: Str('idnssoarname', _rname_validator, attribute=True, autofill=False, cli_name='admin_email', default_from=DefaultFrom(<lambda>, 'idnsname'), label=Gettext('Administrator e-mail address', domain='ipa', localedir=None), multivalue=False, normalizer=normalize_zonemgr, query=True, required=False) option: Int('idnssoaserial', attribute=True, autofill=False, cli_name='serial', create_default=_create_zone_serial, label=Gettext('SOA serial', domain='ipa', localedir=None), minvalue=1, multivalue=False, query=True, required=False) option: Int('idnssoarefresh', attribute=True, autofill=False, cli_name='refresh', default=3600, label=Gettext('SOA refresh', domain='ipa', localedir=None), minvalue=0, multivalue=False, query=True, required=False) option: Int('idnssoaretry', attribute=True, autofill=False, cli_name='retry', default=900, label=Gettext('SOA retry', domain='ipa', localedir=None), minvalue=0, multivalue=False, query=True, required=False) @@ -930,7 +930,7 @@ args: 1,18,3 arg: Str('idnsname', attribute=True, cli_name='name', default_from=DefaultFrom(<lambda>, 'name_from_ip'), label=Gettext('Zone name', domain='ipa', localedir=None), multivalue=False, normalizer=<lambda>, primary_key=True, query=True, required=True) option: Str('name_from_ip', _validate_ipnet, attribute=True, autofill=False, cli_name='name_from_ip', label=Gettext('Reverse zone IP network', domain='ipa', localedir=None), multivalue=False, required=False) option: Str('idnssoamname', attribute=True, autofill=False, cli_name='name_server', label=Gettext('Authoritative nameserver', domain='ipa', localedir=None), multivalue=False, required=False) -option: Str('idnssoarname', _rname_validator, attribute=True, autofill=False, cli_name='admin_email', default_from=DefaultFrom(<lambda>, 'idnsname'), label=Gettext('Administrator e-mail address', domain='ipa', localedir=None), multivalue=False, normalizer=_rname_normalizer, required=False) +option: Str('idnssoarname', _rname_validator, attribute=True, autofill=False, cli_name='admin_email', default_from=DefaultFrom(<lambda>, 'idnsname'), label=Gettext('Administrator e-mail address', domain='ipa', localedir=None), multivalue=False, normalizer=normalize_zonemgr, required=False) option: Int('idnssoaserial', attribute=True, autofill=False, cli_name='serial', create_default=_create_zone_serial, label=Gettext('SOA serial', domain='ipa', localedir=None), minvalue=1, multivalue=False, required=False) option: Int('idnssoarefresh', attribute=True, autofill=False, cli_name='refresh', default=3600, label=Gettext('SOA refresh', domain='ipa', localedir=None), minvalue=0, multivalue=False, required=False) option: Int('idnssoaretry', attribute=True, autofill=False, cli_name='retry', default=900, label=Gettext('SOA retry', domain='ipa', localedir=None), minvalue=0, multivalue=False, required=False) diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py index 912fd36f0fc1bc79bb3c31f19a94715cfea403e4..3054899faa0852824ae917f61476f466dcd4f653 100644 --- a/ipalib/plugins/dns.py +++ b/ipalib/plugins/dns.py @@ -26,7 +26,7 @@ from ipalib import Command from ipalib import Flag, Bool, Int, List, Str, StrEnum from ipalib.plugins.baseldap import * from ipalib import _, ngettext -from ipalib.util import validate_zonemgr +from ipalib.util import validate_zonemgr, normalize_zonemgr from ipapython import dnsclient from ipapython.ipautil import valid_ip from ldap import explode_dn @@ -148,13 +148,6 @@ def _rname_validator(ugettext, zonemgr): return unicode(e) return None -# normalizer for admin email -def _rname_normalizer(value): - value = value.replace('@', '.') - if not value.endswith('.'): - value += '.' - return value - def _create_zone_serial(**kwargs): """Generate serial number for zones.""" return int('%s01' % time.strftime('%Y%d%m')) @@ -340,7 +333,7 @@ class dnszone(LDAPObject): label=_('Administrator e-mail address'), doc=_('Administrator e-mail address'), default_from=lambda idnsname: 'root.%s' % idnsname, - normalizer=_rname_normalizer, + normalizer=normalize_zonemgr, ), Int('idnssoaserial?', cli_name='serial', diff --git a/ipalib/util.py b/ipalib/util.py index fa93cc75058997104b3f452b63e83b309da1260a..e2c3ddd0dc760b77b099425bd8c646191b7796b1 100644 --- a/ipalib/util.py +++ b/ipalib/util.py @@ -204,32 +204,59 @@ def check_writable_file(filename): except (IOError, OSError), e: raise errors.FileError(reason=str(e)) +def normalize_zonemgr(zonemgr): + if '@' in zonemgr: + # local-part needs to be normalized + name, at, domain = zonemgr.partition('@') + name = name.replace('.', '\\.') + zonemgr = u''.join((name, u'.', domain)) + + if not zonemgr.endswith('.'): + zonemgr = zonemgr + u'.' + + return zonemgr def validate_zonemgr(zonemgr): """ See RFC 1033, 1035 """ - regex_domain = re.compile(r'^[a-z0-9][a-z0-9-]*$', re.IGNORECASE) - regex_name = re.compile(r'^[a-z0-9][a-z0-9-_]*$', re.IGNORECASE) + regex_domain = re.compile(r'^[a-z0-9]([a-z0-9-]?[a-z0-9])*$', re.IGNORECASE) + regex_local_part = re.compile(r'^[a-z0-9]([a-z0-9-_\.]?[a-z0-9])*$', + re.IGNORECASE) + + local_part_errmsg = _('mail account may only include letters, numbers, -, _ and a dot. There may not be consecutive -, _ and . characters') if len(zonemgr) > 255: raise ValueError(_('cannot be longer that 255 characters')) + if zonemgr.endswith('.'): + zonemgr = zonemgr[:-1] + if zonemgr.count('@') == 1: - name, dot, domain = zonemgr.partition('@') + local_part, dot, domain = zonemgr.partition('@') + if not regex_local_part.match(local_part): + raise ValueError(local_part_errmsg) elif zonemgr.count('@') > 1: raise ValueError(_('too many \'@\' characters')) else: - # address in SOA format already (without @) - name, dot, domain = zonemgr.partition('.') + last_fake_sep = zonemgr.rfind('\\.') + if last_fake_sep != -1: # there is a 'fake' local-part/domain separator + sep = zonemgr.find('.', last_fake_sep+2) + if sep == -1: + raise ValueError(_('address domain is not fully qualified ' \ + '("example.com" instead of just "example")')) + local_part = zonemgr[:sep] + domain = zonemgr[sep+1:] - if domain.endswith('.'): - domain = domain[:-1] + if not all(regex_local_part.match(part) for part in local_part.split('\\.')): + raise ValueError(local_part_errmsg) + else: + local_part, dot, domain = zonemgr.partition('.') + + if not regex_local_part.match(local_part): + raise ValueError(local_part_errmsg) if '.' not in domain: raise ValueError(_('address domain is not fully qualified ' \ '("example.com" instead of just "example")')) - if not regex_name.match(name): - raise ValueError(_('mail account may only include letters, numbers, -, and _')) - if not all(regex_domain.match(part) for part in domain.split(".")): raise ValueError(_('domain name may only include letters, numbers, and -')) diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index 7330264fe69f0bd5aaa63ebf58a8391f85384986..95d62f490a632f2949bd6d08f5f7ac402ce3cf79 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -33,7 +33,7 @@ from ipapython import sysrestore from ipapython import ipautil from ipalib.constants import DNS_ZONE_REFRESH from ipalib.parameters import IA5Str -from ipalib.util import validate_zonemgr +from ipalib.util import validate_zonemgr, normalize_zonemgr import ipalib from ipalib import api, util, errors @@ -298,10 +298,6 @@ def zonemgr_callback(option, opt_str, value, parser): except ValueError, e: parser.error("invalid zonemgr: " + unicode(e)) - name = opt_str.replace('--','') - v = unicode(value, 'utf-8') - ia = IA5Str(name) - ia._convert_scalar(v) parser.values.zonemgr = value class DnsBackup(object): @@ -387,10 +383,10 @@ class BindInstance(service.Service): self.zone_refresh = zone_refresh self.zone_notif = zone_notif - if zonemgr: - self.zonemgr = zonemgr.replace('@','.') - else: + if not zonemgr: self.zonemgr = 'root.%s.%s' % (self.host, self.domain) + else: + self.zonemgr = normalize_zonemgr(zonemgr) self.__setup_sub_dict() -- 1.7.7
>From 6665d99fa97b673dd95deaa78cbbbcdb9780f49f Mon Sep 17 00:00:00 2001 From: Martin Kosek <[email protected]> Date: Fri, 11 Nov 2011 14:59:47 +0100 Subject: [PATCH 2/2] Change default DNS zone manager to hostmaster Change our default zone manager to hostmaster@<domain> (as per RFC 2142 recommendation). https://fedorahosted.org/freeipa/ticket/1981 --- ipalib/plugins/dns.py | 2 +- ipaserver/install/bindinstance.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py index 3054899faa0852824ae917f61476f466dcd4f653..d3ee35bee9153cabb17bbcb8a2bffa0b61677009 100644 --- a/ipalib/plugins/dns.py +++ b/ipalib/plugins/dns.py @@ -332,7 +332,7 @@ class dnszone(LDAPObject): cli_name='admin_email', label=_('Administrator e-mail address'), doc=_('Administrator e-mail address'), - default_from=lambda idnsname: 'root.%s' % idnsname, + default_from=lambda idnsname: 'hostmaster.%s' % idnsname, normalizer=normalize_zonemgr, ), Int('idnssoaserial?', diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py index 95d62f490a632f2949bd6d08f5f7ac402ce3cf79..489830dfff441efbf91d041f62ab44e787901e2c 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -384,7 +384,7 @@ class BindInstance(service.Service): self.zone_notif = zone_notif if not zonemgr: - self.zonemgr = 'root.%s.%s' % (self.host, self.domain) + self.zonemgr = 'hostmaster.%s' % self.domain else: self.zonemgr = normalize_zonemgr(zonemgr) -- 1.7.7
_______________________________________________ Freeipa-devel mailing list [email protected] https://www.redhat.com/mailman/listinfo/freeipa-devel
