summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Basti <mbasti@redhat.com>2014-05-22 15:01:27 +0200
committerPetr Vobornik <pvoborni@redhat.com>2014-06-20 13:14:45 +0200
commit49068ade92b3fa4874b3107923bbd5b84e1a04f3 (patch)
treeb5ef2e5081f4b768cbb171de9988c33b801cfb40
parente821576129907d89a812edde45121d365a1f696d (diff)
downloadfreeipa-49068ade92b3fa4874b3107923bbd5b84e1a04f3.tar.gz
freeipa-49068ade92b3fa4874b3107923bbd5b84e1a04f3.tar.xz
freeipa-49068ade92b3fa4874b3107923bbd5b84e1a04f3.zip
Separate master and forward DNS zones
Forward zones are stored in idnsforwadzone objectclasses. design: http://www.freeipa.org/page/V4/Forward_zones Ticket: https://fedorahosted.org/freeipa/ticket/3210 Reviewed-By: Petr Vobornik <pvoborni@redhat.com>
-rw-r--r--API.txt94
-rw-r--r--VERSION4
-rw-r--r--install/share/60ipadns.ldif1
-rw-r--r--ipalib/plugins/dns.py328
4 files changed, 425 insertions, 2 deletions
diff --git a/API.txt b/API.txt
index 30974d92e..858908878 100644
--- a/API.txt
+++ b/API.txt
@@ -704,6 +704,100 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
+command: dnsforwardzone_add
+args: 1,8,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, required=True)
+option: Str('addattr*', cli_name='addattr', exclude='webui')
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('idnsforwarders', attribute=True, cli_name='forwarder', csv=True, multivalue=True, required=False)
+option: StrEnum('idnsforwardpolicy', attribute=True, cli_name='forward_policy', multivalue=False, required=False, values=(u'only', u'first', u'none'))
+option: Str('name_from_ip', attribute=False, cli_name='name_from_ip', multivalue=False, required=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: dnsforwardzone_add_permission
+args: 1,1,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: Output('value', <type 'unicode'>, None)
+command: dnsforwardzone_del
+args: 1,2,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=True, only_absolute=True, primary_key=True, query=True, required=True)
+option: Flag('continue', autofill=True, cli_name='continue', default=False)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'dict'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: ListOfPrimaryKeys('value', None, None)
+command: dnsforwardzone_disable
+args: 1,1,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: dnsforwardzone_enable
+args: 1,1,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: dnsforwardzone_find
+args: 1,11,4
+arg: Str('criteria?', noextrawhitespace=False)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('idnsforwarders', attribute=True, autofill=False, cli_name='forwarder', csv=True, multivalue=True, query=True, required=False)
+option: StrEnum('idnsforwardpolicy', attribute=True, autofill=False, cli_name='forward_policy', multivalue=False, query=True, required=False, values=(u'only', u'first', u'none'))
+option: DNSNameParam('idnsname', attribute=True, autofill=False, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=False)
+option: Bool('idnszoneactive', attribute=True, autofill=False, cli_name='zone_active', multivalue=False, query=True, required=False)
+option: Str('name_from_ip', attribute=False, autofill=False, cli_name='name_from_ip', multivalue=False, query=True, required=False)
+option: Flag('pkey_only?', autofill=True, default=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Int('sizelimit?', autofill=False, minvalue=0)
+option: Int('timelimit?', autofill=False, minvalue=0)
+option: Str('version?', exclude='webui')
+output: Output('count', <type 'int'>, None)
+output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: Output('truncated', <type 'bool'>, None)
+command: dnsforwardzone_mod
+args: 1,10,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
+option: Str('addattr*', cli_name='addattr', exclude='webui')
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Str('delattr*', cli_name='delattr', exclude='webui')
+option: Str('idnsforwarders', attribute=True, autofill=False, cli_name='forwarder', csv=True, multivalue=True, required=False)
+option: StrEnum('idnsforwardpolicy', attribute=True, autofill=False, cli_name='forward_policy', multivalue=False, required=False, values=(u'only', u'first', u'none'))
+option: Str('name_from_ip', attribute=False, autofill=False, cli_name='name_from_ip', multivalue=False, required=False)
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Flag('rights', autofill=True, default=False)
+option: Str('setattr*', cli_name='setattr', exclude='webui')
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
+command: dnsforwardzone_remove_permission
+args: 1,1,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
+option: Str('version?', exclude='webui')
+output: Output('result', <type 'bool'>, None)
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: Output('value', <type 'unicode'>, None)
+command: dnsforwardzone_show
+args: 1,4,3
+arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
+option: Flag('rights', autofill=True, default=False)
+option: Str('version?', exclude='webui')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
+output: PrimaryKey('value', None, None)
command: dnsrecord_add
args: 2,116,3
arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True)
diff --git a/VERSION b/VERSION
index 318b88a15..d2a367353 100644
--- a/VERSION
+++ b/VERSION
@@ -89,5 +89,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=89
-# Last change: npmccallum - Add support for managedBy to tokens
+IPA_API_VERSION_MINOR=90
+# Last change: mbasti - Add dnsforwardzone-* commands
diff --git a/install/share/60ipadns.ldif b/install/share/60ipadns.ldif
index aaa1b3110..724524ea7 100644
--- a/install/share/60ipadns.ldif
+++ b/install/share/60ipadns.ldif
@@ -54,3 +54,4 @@ objectClasses: ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, u
objectClasses: ( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsZoneActive $ idnsSOAmName $ idnsSOArName $ idnsSOAserial $ idnsSOArefresh $ idnsSOAretry $ idnsSOAexpire $ idnsSOAminimum ) MAY ( idnsUpdatePolicy $ idnsAllowQuery $ idnsAllowTransfer $ idnsAllowSyncPTR $ idnsForwardPolicy $ idnsForwarders $ idnsSecInlineSigning ) )
objectClasses: ( 2.16.840.1.113730.3.8.6.2 NAME 'idnsConfigObject' DESC 'DNS global config options' STRUCTURAL MAY ( idnsForwardPolicy $ idnsForwarders $ idnsAllowSyncPTR $ idnsZoneRefresh $ idnsPersistentSearch ) )
objectClasses: ( 2.16.840.1.113730.3.8.12.18 NAME 'ipaDNSZone' SUP top AUXILIARY MUST idnsName MAY managedBy X-ORIGIN 'IPA v3' )
+objectClasses: ( 2.16.840.1.113730.3.8.6.3 NAME 'idnsForwardZone' DESC 'Forward Zone class' SUP top STRUCTURAL MUST ( idnsName $ idnsZoneActive ) MAY ( idnsForwarders $ idnsForwardPolicy ) )
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index b149f1f07..ead77ca9c 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -1843,6 +1843,7 @@ class dnszone(LDAPObject):
doc=_('Allow inline DNSSEC signing of records in the zone'),
),
)
+ # Permissions will be apllied for forwardzones too
managed_permissions = {
'System: Add DNS Entries': {
'non_object': True,
@@ -3591,3 +3592,330 @@ class dnsconfig_show(LDAPRetrieve):
self.obj.postprocess_result(result)
return result
+
+@register()
+class dnsforwardzone(LDAPObject):
+ """
+ DNS Forward zone, container for resource records.
+ """
+ container_dn = api.env.container_dns
+ object_name = _('DNS forward zone')
+ object_name_plural = _('DNS forward zones')
+ object_class = ['top', 'idnsforwardzone']
+ possible_objectclasses = ['ipadnszone']
+ default_attributes = [
+ 'idnsname', 'idnszoneactive', 'idnsforwarders', 'idnsforwardpolicy'
+ ]
+ label = _('DNS Forward Zones')
+ label_singular = _('DNS Forward Zone')
+ default_forward_policy = u'first'
+
+ takes_params = (
+ DNSNameParam('idnsname',
+ only_absolute=True,
+ cli_name='name',
+ label=_('Forward zone name'),
+ doc=_('Forward zone name (FQDN)'),
+ default_from=lambda name_from_ip: _reverse_zone_name(name_from_ip),
+ primary_key=True,
+ ),
+ Str('name_from_ip?', _validate_ipnet,
+ label=_('Reverse zone IP network'),
+ doc=_('IP network to create reverse zone name from'),
+ flags=('virtual_attribute',),
+ ),
+ Bool('idnszoneactive?',
+ cli_name='zone_active',
+ label=_('Active zone'),
+ doc=_('Is zone active?'),
+ flags=['no_create', 'no_update'],
+ attribute=True,
+ ),
+ Str('idnsforwarders*',
+ _validate_bind_forwarder,
+ cli_name='forwarder',
+ label=_('Zone forwarders'),
+ doc=_('Per-zone forwarders. A custom port can be specified '
+ 'for each forwarder using a standard format "IP_ADDRESS port PORT"'),
+ csv=True,
+ ),
+ StrEnum('idnsforwardpolicy?',
+ cli_name='forward_policy',
+ label=_('Forward policy'),
+ doc=_('Per-zone conditional forwarding policy. Set to "none" to '
+ 'disable forwarding.'),
+ values=(u'only', u'first', u'none'),
+ ),
+
+ )
+ # managed_permissions: permissions was apllied in dnszone class, do NOT
+ # add them here, they should not be applied twice.
+
+ def get_dn(self, *keys, **options):
+ zone = keys[-1]
+ assert isinstance(zone, DNSName)
+ assert zone.is_absolute()
+ zone = zone.ToASCII()
+
+ # try first relative name, a new zone has to be added as absolute
+ # otherwise ObjectViolation is raised
+ zone = zone[:-1]
+ dn = super(dnsforwardzone, self).get_dn(zone, **options)
+ try:
+ self.backend.get_entry(dn, [''])
+ except errors.NotFound:
+ zone = u"%s." % zone
+ dn = super(dnsforwardzone, self).get_dn(zone, **options)
+
+ return dn
+
+ def permission_name(self, zone):
+ assert isinstance(zone, DNSName)
+ return u"Manage DNS zone %s" % zone.ToASCII()
+
+
+@register()
+class dnsforwardzone_add(LDAPCreate):
+ __doc__ = _('Create new DNS forward zone.')
+
+ has_output_params = LDAPCreate.has_output_params + dnszone_output_params
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
+ if not dns_container_exists(self.api.Backend.ldap2):
+ raise errors.NotFound(reason=_('DNS is not configured'))
+
+ entry_attrs['idnszoneactive'] = 'TRUE'
+
+ if 'idnsforwardpolicy' not in entry_attrs:
+ entry_attrs['idnsforwardpolicy'] = self.obj.default_forward_policy
+
+ if (not entry_attrs.get('idnsforwarders') and
+ entry_attrs['idnsforwardpolicy'] != u'none'):
+ raise errors.ValidationError(name=u'idnsforwarders',
+ error=_('Please specify forwarders.'))
+
+ return dn
+
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
+ return dn
+
+
+@register()
+class dnsforwardzone_del(LDAPDelete):
+ __doc__ = _('Delete DNS forward zone.')
+
+ msg_summary = _('Deleted DNS forward zone "%(value)s"')
+
+ def post_callback(self, ldap, dn, *keys, **options):
+ try:
+ api.Command['permission_del'](self.obj.permission_name(keys[-1]),
+ force=True)
+ except errors.NotFound:
+ pass
+
+ return True
+
+
+@register()
+class dnsforwardzone_mod(LDAPUpdate):
+ __doc__ = _('Modify DNS forward zone.')
+
+ has_output_params = LDAPUpdate.has_output_params + dnszone_output_params
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ try:
+ entry = ldap.get_entry(dn)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+
+ policy = self.obj.default_forward_policy
+ forwarders = []
+
+ if 'idnsforwarders' in entry_attrs:
+ forwarders = entry_attrs['idnsforwarders']
+ elif 'idnsforwarders' in entry:
+ forwarders = entry['idnsforwarders']
+
+ if 'idnsforwardpolicy' in entry_attrs:
+ policy = entry_attrs['idnsforwardpolicy']
+ elif 'idnsforwardpolicy' in entry:
+ policy = entry['idnsforwardpolicy']
+
+ if not forwarders and policy != u'none':
+ raise errors.ValidationError(name=u'idnsforwarders',
+ error=_('Please specify forwarders.'))
+
+ return dn
+
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ return dn
+
+
+@register()
+class dnsforwardzone_find(LDAPSearch):
+ __doc__ = _('Search for DNS forward zones.')
+
+ has_output_params = LDAPSearch.has_output_params + dnszone_output_params
+
+ def args_options_2_params(self, *args, **options):
+ # FIXME: Check that name_from_ip is valid. This is necessary because
+ # custom validation rules, including _validate_ipnet, are not
+ # used when doing a search. Once we have a parameter type for
+ # IP network objects, this will no longer be necessary, as the
+ # parameter type will handle the validation itself (see
+ # <https://fedorahosted.org/freeipa/ticket/2266>).
+ if 'name_from_ip' in options:
+ self.obj.params['name_from_ip'](unicode(options['name_from_ip']))
+ return super(dnsforwardzone_find, self).args_options_2_params(*args, **options)
+
+ def args_options_2_entry(self, *args, **options):
+ if 'name_from_ip' in options:
+ if 'idnsname' not in options:
+ options['idnsname'] = self.obj.params['idnsname'].get_default(**options)
+ del options['name_from_ip']
+ search_kw = super(dnsforwardzone_find, self).args_options_2_entry(*args,
+ **options)
+ name = search_kw.get('idnsname')
+ if name:
+ search_kw['idnsname'] = [name, name.relativize(DNSName.root)]
+ return search_kw
+
+ def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
+
+ filter = _create_idn_filter(self, ldap, *args, **options)
+
+ return (filter, base_dn, scope)
+
+ def post_callback(self, ldap, entries, truncated, *args, **options):
+ return truncated
+
+
+@register()
+class dnsforwardzone_show(LDAPRetrieve):
+ __doc__ = _('Display information about a DNS forward zone.')
+
+ has_output_params = LDAPRetrieve.has_output_params + dnszone_output_params
+
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
+ return dn
+
+
+@register()
+class dnsforwardzone_disable(LDAPQuery):
+ __doc__ = _('Disable DNS Forward Zone.')
+
+ has_output = output.standard_value
+ msg_summary = _('Disabled DNS forward zone "%(value)s"')
+
+ def execute(self, *keys, **options):
+ ldap = self.obj.backend
+
+ dn = self.obj.get_dn(*keys, **options)
+ entry = ldap.get_entry(dn, ['idnszoneactive'])
+
+ entry['idnszoneactive'] = ['FALSE']
+
+ try:
+ ldap.update_entry(entry)
+ except errors.EmptyModlist:
+ pass
+
+ return dict(result=True, value=pkey_to_value(keys[-1], options))
+
+
+@register()
+class dnsforwardzone_enable(LDAPQuery):
+ __doc__ = _('Enable DNS Forward Zone.')
+
+ has_output = output.standard_value
+ msg_summary = _('Enabled DNS forward zone "%(value)s"')
+
+ def execute(self, *keys, **options):
+ ldap = self.obj.backend
+
+ dn = self.obj.get_dn(*keys, **options)
+ entry = ldap.get_entry(dn, ['idnszoneactive'])
+
+ entry['idnszoneactive'] = ['TRUE']
+
+ try:
+ ldap.update_entry(entry)
+ except errors.EmptyModlist:
+ pass
+
+ return dict(result=True, value=pkey_to_value(keys[-1], options))
+
+
+@register()
+class dnsforwardzone_add_permission(LDAPQuery):
+ __doc__ = _('Add a permission for per-zone access delegation.')
+
+ has_output = _output_permissions
+ msg_summary = _('Added system permission "%(value)s"')
+
+ def execute(self, *keys, **options):
+ ldap = self.obj.backend
+ dn = self.obj.get_dn(*keys, **options)
+
+ try:
+ entry_attrs = ldap.get_entry(dn, ['objectclass'])
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+
+ permission_name = self.obj.permission_name(keys[-1])
+ permission = api.Command['permission_add_noaci'](permission_name,
+ ipapermissiontype=u'SYSTEM'
+ )['result']
+
+ dnszone_ocs = entry_attrs.get('objectclass')
+ if dnszone_ocs:
+ for oc in dnszone_ocs:
+ if oc.lower() == 'ipadnszone':
+ break
+ else:
+ dnszone_ocs.append('ipadnszone')
+
+ entry_attrs['managedby'] = [permission['dn']]
+ ldap.update_entry(entry_attrs)
+
+ return dict(
+ result=True,
+ value=pkey_to_value(permission_name, options),
+ )
+
+
+@register()
+class dnsforwardzone_remove_permission(LDAPQuery):
+ __doc__ = _('Remove a permission for per-zone access delegation.')
+
+ has_output = _output_permissions
+ msg_summary = _('Removed system permission "%(value)s"')
+
+ def execute(self, *keys, **options):
+ ldap = self.obj.backend
+ dn = self.obj.get_dn(*keys, **options)
+ try:
+ entry = ldap.get_entry(dn, ['managedby'])
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+
+ entry['managedby'] = None
+
+ try:
+ ldap.update_entry(entry)
+ except errors.EmptyModlist:
+ # managedBy attribute is clean, lets make sure there is also no
+ # dangling DNS zone permission
+ pass
+
+ permission_name = self.obj.permission_name(keys[-1])
+ api.Command['permission_del'](permission_name, force=True)
+
+ return dict(
+ result=True,
+ value=pkey_to_value(permission_name, options),
+ )