diff options
author | Martin Kosek <mkosek@redhat.com> | 2011-10-24 18:35:48 +0200 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2011-10-26 08:52:50 +0200 |
commit | b26d0dcc04e821543b8582328e99e630b752768f (patch) | |
tree | a6e2e651260456ab6147f61217561dac9fdbeca0 | |
parent | 9bdbdbc0f32b87d0fcdc2b9faa98e7c674b2464d (diff) | |
download | freeipa-b26d0dcc04e821543b8582328e99e630b752768f.tar.gz freeipa-b26d0dcc04e821543b8582328e99e630b752768f.tar.xz freeipa-b26d0dcc04e821543b8582328e99e630b752768f.zip |
Add --zonemgr/--admin-mail validator
Do at least a basic validation of DNS zone manager mail address.
Do not require '@' to be in the mail address as the SOA record
stores this value without it and people may be used to configure
it that way. '@' is always removed by the installer/dns plugin before
the DNS zone is created.
https://fedorahosted.org/freeipa/ticket/1966
-rw-r--r-- | API.txt | 6 | ||||
-rwxr-xr-x | install/tools/ipa-dns-install | 3 | ||||
-rwxr-xr-x | install/tools/ipa-server-install | 13 | ||||
-rw-r--r-- | ipalib/plugins/dns.py | 9 | ||||
-rw-r--r-- | ipalib/util.py | 30 | ||||
-rw-r--r-- | ipaserver/install/bindinstance.py | 17 |
6 files changed, 62 insertions, 16 deletions
@@ -854,7 +854,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', 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=_rname_normalizer, 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) @@ -899,7 +899,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', 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=_rname_normalizer, 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) @@ -925,7 +925,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', 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=_rname_normalizer, 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/install/tools/ipa-dns-install b/install/tools/ipa-dns-install index d81b6a2e..7841c21d 100755 --- a/install/tools/ipa-dns-install +++ b/install/tools/ipa-dns-install @@ -48,7 +48,8 @@ def parse_options(): parser.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use") parser.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="Do not create reverse DNS zone") - parser.add_option("--zonemgr", dest="zonemgr", + parser.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback, + type="string", help="DNS zone manager e-mail address. Defaults to root") parser.add_option("--zone-notif", dest="zone_notif", action="store_true", default=False, diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install index 76d5f2f5..d29b806d 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install @@ -58,7 +58,6 @@ from ipaserver.plugins.ldap2 import ldap2 from ipapython import sysrestore from ipapython.ipautil import * from ipalib import api, errors, util -from ipalib.parameters import IA5Str from ipapython.config import IPAOptionParser from ipalib.dn import DN from ipalib.x509 import load_certificate_from_file, load_certificate_chain_from_file @@ -76,16 +75,6 @@ VALID_SUBJECT_ATTRS = ['cn', 'st', 'o', 'ou', 'dnqualifier', 'c', 'incorporationlocality', 'incorporationstate', 'incorporationcountry', 'businesscategory'] -def zonemgr_callback(option, opt_str, value, parser): - """ - Make sure the zonemgr is an IA5String. - """ - name = opt_str.replace('--','') - v = unicode(value, 'utf-8') - ia = IA5Str(name) - ia._convert_scalar(v) - parser.values.zonemgr = value - def subject_callback(option, opt_str, value, parser): """ Make sure the certificate subject base is a valid DN @@ -195,7 +184,7 @@ def parse_options(): dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use") dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="Do not create reverse DNS zone") - dns_group.add_option("--zonemgr", action="callback", callback=zonemgr_callback, + dns_group.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback, type="string", help="DNS zone manager e-mail address. Defaults to root") dns_group.add_option("--zone-notif", dest="zone_notif", diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py index f6bbb3c4..97eb6a6d 100644 --- a/ipalib/plugins/dns.py +++ b/ipalib/plugins/dns.py @@ -26,6 +26,7 @@ from ipalib import Command from ipalib import Flag, Int, List, Str, StrEnum from ipalib.plugins.baseldap import * from ipalib import _, ngettext +from ipalib.util import validate_zonemgr from ipapython import dnsclient from ipapython.ipautil import valid_ip from ldap import explode_dn @@ -136,6 +137,13 @@ _record_attributes = [str('%srecord' % t.lower()) for t in _record_types] # supported DNS classes, IN = internet, rest is almost never used _record_classes = (u'IN', u'CS', u'CH', u'HS') +def _rname_validator(ugettext, zonemgr): + try: + validate_zonemgr(zonemgr) + except ValueError, e: + return unicode(e) + return None + # normalizer for admin email def _rname_normalizer(value): value = value.replace('@', '.') @@ -323,6 +331,7 @@ class dnszone(LDAPObject): doc=_('Authoritative nameserver domain name'), ), Str('idnssoarname', + _rname_validator, cli_name='admin_email', label=_('Administrator e-mail address'), doc=_('Administrator e-mail address'), diff --git a/ipalib/util.py b/ipalib/util.py index cc887c34..fa93cc75 100644 --- a/ipalib/util.py +++ b/ipalib/util.py @@ -203,3 +203,33 @@ def check_writable_file(filename): fp.close() except (IOError, OSError), e: raise errors.FileError(reason=str(e)) + + +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) + + if len(zonemgr) > 255: + raise ValueError(_('cannot be longer that 255 characters')) + + if zonemgr.count('@') == 1: + name, dot, domain = zonemgr.partition('@') + elif zonemgr.count('@') > 1: + raise ValueError(_('too many \'@\' characters')) + else: + # address in SOA format already (without @) + name, dot, domain = zonemgr.partition('.') + + if domain.endswith('.'): + domain = domain[:-1] + + 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 ddf54977..7330264f 100644 --- a/ipaserver/install/bindinstance.py +++ b/ipaserver/install/bindinstance.py @@ -32,6 +32,8 @@ from ipaserver.install.installutils import resolve_host 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 import ipalib from ipalib import api, util, errors @@ -286,6 +288,21 @@ def get_rr(zone, name, type): return [] +def zonemgr_callback(option, opt_str, value, parser): + """ + Properly validate and convert --zonemgr Option to IA5String + """ + # validate the value first + try: + validate_zonemgr(value) + 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): def __init__(self, service): |