summaryrefslogtreecommitdiffstats
path: root/ipalib
diff options
context:
space:
mode:
Diffstat (limited to 'ipalib')
-rw-r--r--ipalib/plugins/dns.py39
-rw-r--r--ipalib/plugins/host.py21
-rw-r--r--ipalib/util.py47
3 files changed, 72 insertions, 35 deletions
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index af23e03c..44fced64 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -28,7 +28,8 @@ from ipalib import Command
from ipalib.parameters import Flag, Bool, Int, Decimal, Str, StrEnum, Any
from ipalib.plugins.baseldap import *
from ipalib import _, ngettext
-from ipalib.util import validate_zonemgr, normalize_zonemgr, validate_hostname
+from ipalib.util import (validate_zonemgr, normalize_zonemgr,
+ validate_hostname, validate_dns_label, validate_domain_name)
from ipapython import dnsclient
from ipapython.ipautil import valid_ip, CheckedIPAddress
from ldap import explode_dn
@@ -299,7 +300,7 @@ def _normalize_bind_aci(bind_acis):
acis += u';'
return acis
-def _domain_name_validator(ugettext, value):
+def _bind_hostname_validator(ugettext, value):
try:
# Allow domain name which is not fully qualified. These are supported
# in bind and then translated as <non-fqdn-name>.<domain>.
@@ -310,6 +311,22 @@ def _domain_name_validator(ugettext, value):
return None
+def _dns_record_name_validator(ugettext, value):
+ if value == _dns_zone_record:
+ return
+
+ try:
+ map(lambda label:validate_dns_label(label, allow_underscore=True), \
+ value.split(u'.'))
+ except ValueError, e:
+ return unicode(e)
+
+def _domain_name_validator(ugettext, value):
+ try:
+ validate_domain_name(value)
+ except ValueError, e:
+ return unicode(e)
+
def _hostname_validator(ugettext, value):
try:
validate_hostname(value)
@@ -777,7 +794,7 @@ class AFSDBRecord(DNSRecord):
maxvalue=65535,
),
Str('hostname',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Hostname'),
),
)
@@ -816,7 +833,7 @@ class CNAMERecord(DNSRecord):
rfc = 1035
parts = (
Str('hostname',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Hostname'),
doc=_('A hostname which this alias hostname points to'),
),
@@ -837,7 +854,7 @@ class DNAMERecord(DNSRecord):
rfc = 2672
parts = (
Str('target',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Target'),
),
)
@@ -916,7 +933,7 @@ class KXRecord(DNSRecord):
maxvalue=65535,
),
Str('exchanger',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Exchanger'),
doc=_('A host willing to act as a key exchanger'),
),
@@ -1057,7 +1074,7 @@ class MXRecord(DNSRecord):
maxvalue=65535,
),
Str('exchanger',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Exchanger'),
doc=_('A host willing to act as a mail exchanger'),
),
@@ -1069,7 +1086,7 @@ class NSRecord(DNSRecord):
parts = (
Str('hostname',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Hostname'),
),
)
@@ -1083,7 +1100,7 @@ class NSECRecord(DNSRecord):
parts = (
Str('next',
- _domain_name_validator,
+ _bind_hostname_validator,
label=_('Next Domain Name'),
),
StrEnum('types+',
@@ -1181,7 +1198,7 @@ def _srv_target_validator(ugettext, value):
if value == u'.':
# service not available
return
- return _domain_name_validator(ugettext, value)
+ return _bind_hostname_validator(ugettext, value)
class SRVRecord(DNSRecord):
rrtype = 'SRV'
@@ -1426,6 +1443,7 @@ class dnszone(LDAPObject):
takes_params = (
Str('idnsname',
+ _domain_name_validator,
cli_name='name',
label=_('Zone name'),
doc=_('Zone name (FQDN)'),
@@ -1742,6 +1760,7 @@ class dnsrecord(LDAPObject):
takes_params = (
Str('idnsname',
+ _dns_record_name_validator,
cli_name='name',
label=_('Record name'),
doc=_('Record name'),
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index df9ad737..0ff5237f 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -31,7 +31,9 @@ from ipalib.plugins.baseldap import *
from ipalib.plugins.service import split_principal
from ipalib.plugins.service import validate_certificate
from ipalib.plugins.service import set_certificate_attrs
-from ipalib.plugins.dns import dns_container_exists, _record_types, add_records_for_host_validation, add_records_for_host
+from ipalib.plugins.dns import (dns_container_exists, _record_types,
+ add_records_for_host_validation, add_records_for_host,
+ _hostname_validator, get_reverse_zone)
from ipalib.plugins.dns import get_reverse_zone
from ipalib import _, ngettext
from ipalib import x509
@@ -97,14 +99,6 @@ EXAMPLES:
ipa host-add-managedby --hosts=test2 test
""")
-def validate_host(ugettext, fqdn):
- """
- Require at least one dot in the hostname (to support localhost.localdomain)
- """
- if fqdn.find('.') == -1:
- return _('Fully-qualified hostname required')
- return None
-
def remove_fwd_ptr(ipaddr, host, domain, recordtype):
api.log.debug('deleting ipaddr %s' % ipaddr)
try:
@@ -225,10 +219,7 @@ class host(LDAPObject):
label_singular = _('Host')
takes_params = (
- Str('fqdn', validate_host,
- pattern='^[a-zA-Z0-9][a-zA-Z0-9-\.]{0,254}$',
- pattern_errmsg='may only include letters, numbers, and -',
- maxlength=255,
+ Str('fqdn', _hostname_validator,
cli_name='hostname',
label=_('Host name'),
primary_key=True,
@@ -481,7 +472,7 @@ class host_del(LDAPDelete):
def pre_callback(self, ldap, dn, *keys, **options):
# If we aren't given a fqdn, find it
- if validate_host(None, keys[-1]) is not None:
+ if _hostname_validator(None, keys[-1]) is not None:
hostentry = api.Command['host_show'](keys[-1])['result']
fqdn = hostentry['fqdn'][0]
else:
@@ -856,7 +847,7 @@ class host_disable(LDAPQuery):
ldap = self.obj.backend
# If we aren't given a fqdn, find it
- if validate_host(None, keys[-1]) is not None:
+ if _hostname_validator(None, keys[-1]) is not None:
hostentry = api.Command['host_show'](keys[-1])['result']
fqdn = hostentry['fqdn'][0]
else:
diff --git a/ipalib/util.py b/ipalib/util.py
index 395bf0cf..bbc0fa67 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -213,6 +213,36 @@ def normalize_zonemgr(zonemgr):
return zonemgr
+def validate_dns_label(dns_label, allow_underscore=False):
+ label_chars = r'a-z0-9'
+ underscore_err_msg = ''
+ if allow_underscore:
+ label_chars += "_"
+ underscore_err_msg = u' _,'
+ label_regex = r'^[%(chars)s]([%(chars)s-]?[%(chars)s])*$' % dict(chars=label_chars)
+ regex = re.compile(label_regex, re.IGNORECASE)
+
+ if len(dns_label) > 63:
+ raise ValueError(_('DNS label cannot be longer that 63 characters'))
+
+ if not regex.match(dns_label):
+ raise ValueError(_('only letters, numbers,%(underscore)s and - are allowed. ' \
+ '- must not be the DNS label character') \
+ % dict(underscore=underscore_err_msg))
+
+def validate_domain_name(domain_name):
+ if domain_name.endswith('.'):
+ domain_name = domain_name[:-1]
+
+ domain_name = domain_name.split(".")
+
+ # apply DNS name validator to every name part
+ map(lambda label:validate_dns_label(label), domain_name)
+
+ if not domain_name[-1].isalpha():
+ # see RFC 1123
+ raise ValueError(_('top level domain label must be alphabetic'))
+
def validate_zonemgr(zonemgr):
""" See RFC 1033, 1035 """
regex_domain = re.compile(r'^[a-z0-9]([a-z0-9-]?[a-z0-9])*$', re.IGNORECASE)
@@ -252,8 +282,7 @@ def validate_zonemgr(zonemgr):
if not regex_local_part.match(local_part):
raise ValueError(local_part_errmsg)
- if not all(regex_domain.match(part) for part in domain.split(".")):
- raise ValueError(_('domain name may only include letters, numbers, and -'))
+ validate_domain_name(domain)
def validate_hostname(hostname, check_fqdn=True):
""" See RFC 952, 1123
@@ -261,20 +290,18 @@ def validate_hostname(hostname, check_fqdn=True):
:param hostname Checked value
:param check_fqdn Check if hostname is fully qualified
"""
- regex_name = re.compile(r'^[a-z0-9]([a-z0-9-]?[a-z0-9])*$', re.IGNORECASE)
-
if len(hostname) > 255:
raise ValueError(_('cannot be longer that 255 characters'))
if hostname.endswith('.'):
hostname = hostname[:-1]
- if check_fqdn and '.' not in hostname:
- raise ValueError(_('not fully qualified'))
-
- if not all(regex_name.match(part) for part in hostname.split(".")):
- raise ValueError(_('only letters, numbers, and - are allowed. ' \
- '- must not be the last name character'))
+ if '.' not in hostname:
+ if check_fqdn:
+ raise ValueError(_('not fully qualified'))
+ validate_dns_label(hostname)
+ else:
+ validate_domain_name(hostname)
def validate_sshpubkey(ugettext, pubkey):
try: