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 
--zonemgr=foo....@example.com
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 <mko...@redhat.com>
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 <mko...@redhat.com>
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
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to