On 21.6.2016 10:00, Petr Spacek wrote:
> On 20.6.2016 19:15, Martin Basti wrote:
>>
>>
>> On 20.06.2016 18:32, Petr Spacek wrote:
>>> On 20.6.2016 18:05, Martin Basti wrote:
>>>>
>>>> On 20.06.2016 16:57, Petr Spacek wrote:
>>>>> Hello,
>>>>>
>>>>> DNS: Warn about restart when default TTL setting DNS is changed
>>>>>
>>>>> bind-dyndb-ldap 10.0 has to be restarted after each change to default
>>>>> TTL.
>>>>>
>>>>> https://fedorahosted.org/freeipa/ticket/2956
>>>>>
>>>>> DNS: Support default TTL setting for master DNS zones
>>>>>
>>>>> https://fedorahosted.org/freeipa/ticket/2956
>>>>>
>>>>>
>>>>>
>>>> Thank you for patches, but I have a few comments
>>>>
>>>> TTL patch:
>>>> 1)
>>>> VERSION - please put short note why API was incremented
>>>>
>>>> 2)
>>>> 60ipadns.ldif - please keep ordered attr definitions by OID
>>>>
>>>> 3)
>>>> You missed ACI for updating
>>>>
>>>> Warning patch: LGTM
>>> Thank you very much for review!
>>>
>>> Here is revised version.
>>>
>>
>> I cannot apply patches on current master, even with git am -3
> 
> I do not what could be problem, there was only "standard" conflict on VERSION.
> 
> Anyway, there are patches rebased to current master.

... and now with results from makeaci :-)

-- 
Petr^2 Spacek
From a033905194f9f355e6be1f4aecc5affe6174a603 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 20 Jun 2016 14:38:56 +0200
Subject: [PATCH] DNS: Support default TTL setting for master DNS zones

https://fedorahosted.org/freeipa/ticket/2956
---
 ACI.txt                     |  4 ++--
 API.txt                     |  9 ++++++---
 VERSION                     |  4 ++--
 install/share/60ipadns.ldif |  3 ++-
 ipaserver/plugins/dns.py    | 15 +++++++++++----
 5 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/ACI.txt b/ACI.txt
index 0646d0d24d0e8a427eabf5aca04566f269e96cd2..98566de35e6ce79633dc4968b3063f6fd1336378 100644
--- a/ACI.txt
+++ b/ACI.txt
@@ -73,13 +73,13 @@ aci: (targetattr = "ipaprivatekey || ipapublickey || ipasecretkey || ipasecretke
 dn: dc=ipa,dc=example
 aci: (targetattr = "cn || idnssecalgorithm || idnsseckeyactivate || idnsseckeycreated || idnsseckeydelete || idnsseckeyinactive || idnsseckeypublish || idnsseckeyref || idnsseckeyrevoke || idnsseckeysep || idnsseckeyzone || objectclass")(target = "ldap:///cn=dns,dc=ipa,dc=example";)(targetfilter = "(objectclass=idnsSecKey)")(version 3.0;acl "permission:System: Manage DNSSEC metadata";allow (all) groupdn = "ldap:///cn=System: Manage DNSSEC metadata,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: dc=ipa,dc=example
-aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || createtimestamp || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || entryusn || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || modifytimestamp || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Read DNS Entries";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || createtimestamp || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsdefaultttl || dnsttl || dsrecord || entryusn || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || modifytimestamp || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Read DNS Entries";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: dc=ipa,dc=example
 aci: (targetattr = "cn || createtimestamp || entryusn || idnssecalgorithm || idnsseckeyactivate || idnsseckeycreated || idnsseckeydelete || idnsseckeyinactive || idnsseckeypublish || idnsseckeyref || idnsseckeyrevoke || idnsseckeysep || idnsseckeyzone || modifytimestamp || objectclass")(target = "ldap:///cn=dns,dc=ipa,dc=example";)(targetfilter = "(objectclass=idnsSecKey)")(version 3.0;acl "permission:System: Read DNSSEC metadata";allow (compare,read,search) groupdn = "ldap:///cn=System: Read DNSSEC metadata,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: dc=ipa,dc=example
 aci: (target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Remove DNS Entries";allow (delete) groupdn = "ldap:///cn=System: Remove DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: dc=ipa,dc=example
-aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Update DNS Entries";allow (write) groupdn = "ldap:///cn=System: Update DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
+aci: (targetattr = "a6record || aaaarecord || afsdbrecord || aplrecord || arecord || certrecord || cn || cnamerecord || dhcidrecord || dlvrecord || dnamerecord || dnsclass || dnsdefaultttl || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnstemplateattribute || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord")(target = "ldap:///idnsname=*,cn=dns,dc=ipa,dc=example";)(version 3.0;acl "permission:System: Update DNS Entries";allow (write) groupdn = "ldap:///cn=System: Update DNS Entries,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=groups,cn=accounts,dc=ipa,dc=example
 aci: (targetfilter = "(|(objectclass=ipausergroup)(objectclass=posixgroup))")(version 3.0;acl "permission:System: Add Groups";allow (add) groupdn = "ldap:///cn=System: Add Groups,cn=permissions,cn=pbac,dc=ipa,dc=example";)
 dn: cn=groups,cn=accounts,dc=ipa,dc=example
diff --git a/API.txt b/API.txt
index 142ffcd40814255ba406e3d5f485d6bfae2159c4..1c8600930511c394fbad05c5f00e6214d8923d39 100644
--- a/API.txt
+++ b/API.txt
@@ -1602,11 +1602,12 @@ output: Entry('result')
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: PrimaryKey('value')
 command: dnszone_add
-args: 1,28,3
+args: 1,29,3
 arg: DNSNameParam('idnsname', cli_name='name')
 option: Str('addattr*', cli_name='addattr')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: StrEnum('dnsclass?', cli_name='class', values=[u'IN', u'CS', u'CH', u'HS'])
+option: Int('dnsdefaultttl?', cli_name='default_ttl')
 option: Int('dnsttl?', cli_name='ttl')
 option: Flag('force', autofill=True, default=False)
 option: Bool('idnsallowdynupdate?', autofill=True, cli_name='dynamic_update', default=False)
@@ -1665,10 +1666,11 @@ output: Output('result', type=[<type 'bool'>])
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: PrimaryKey('value')
 command: dnszone_find
-args: 1,28,4
+args: 1,29,4
 arg: Str('criteria?')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: StrEnum('dnsclass?', autofill=False, cli_name='class', values=[u'IN', u'CS', u'CH', u'HS'])
+option: Int('dnsdefaultttl?', autofill=False, cli_name='default_ttl')
 option: Int('dnsttl?', autofill=False, cli_name='ttl')
 option: Flag('forward_only', autofill=True, cli_name='forward_only', default=False)
 option: Bool('idnsallowdynupdate?', autofill=False, cli_name='dynamic_update', default=False)
@@ -1700,12 +1702,13 @@ output: ListOfEntries('result')
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: Output('truncated', type=[<type 'bool'>])
 command: dnszone_mod
-args: 1,27,3
+args: 1,28,3
 arg: DNSNameParam('idnsname', cli_name='name')
 option: Str('addattr*', cli_name='addattr')
 option: Flag('all', autofill=True, cli_name='all', default=False)
 option: Str('delattr*', cli_name='delattr')
 option: StrEnum('dnsclass?', autofill=False, cli_name='class', values=[u'IN', u'CS', u'CH', u'HS'])
+option: Int('dnsdefaultttl?', autofill=False, cli_name='default_ttl')
 option: Int('dnsttl?', autofill=False, cli_name='ttl')
 option: Flag('force', autofill=True, default=False)
 option: Bool('idnsallowdynupdate?', autofill=False, cli_name='dynamic_update', default=False)
diff --git a/VERSION b/VERSION
index fe7614edd0fbda0a040e1ac79151596aad3fa333..b4c414bbe0df0ca55696ac00cac1373b7f313979 100644
--- a/VERSION
+++ b/VERSION
@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
 #                                                      #
 ########################################################
 IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=196
-# Last change: cert: allow search by certificate
+IPA_API_VERSION_MINOR=197
+# Last change: pspacek - DNS: Support default TTL setting for master DNS zones
diff --git a/install/share/60ipadns.ldif b/install/share/60ipadns.ldif
index b6eff3a2b6bae81dd0865594048ee7d193eef91a..6f6239431d04f40d15c503b2b0c7289d1a7701f5 100644
--- a/install/share/60ipadns.ldif
+++ b/install/share/60ipadns.ldif
@@ -6,6 +6,7 @@
 dn: cn=schema
 attributeTypes: (1.3.6.1.4.1.2428.20.0.0 NAME 'dNSTTL' DESC 'An integer denoting time to live' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
 attributeTypes: (1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass' DESC 'The class of a resource record' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+attributeTypes: (1.3.6.1.4.1.2428.20.0.2 NAME 'dNSdefaultTTL' DESC 'An integer denoting default time to live, RFC 2308' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
 attributeTypes: (1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord' DESC 'domain name pointer, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
 attributeTypes: (1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord' DESC 'host information, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
 attributeTypes: (1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord' DESC 'mailbox or mail list information, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
@@ -77,7 +78,7 @@ attributeTypes: ( 2.16.840.1.113730.3.8.5.31 NAME 'idnsServerId' DESC 'DNS serve
 attributeTypes: ( 2.16.840.1.113730.3.8.5.32 NAME 'ipaLocation' DESC 'Reference to IPA location' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.4' )
 attributeTypes: ( 2.16.840.1.113730.3.8.5.33 NAME 'ipaServiceWeight' DESC 'Weight for the server in IPA location' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v4.4' )
 objectClasses: ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( cn $ idnsAllowDynUpdate $ dNSTTL $ dNSClass $ aRecord $ aAAARecord $ a6Record $ nSRecord $ cNAMERecord $ pTRRecord $ sRVRecord $ tXTRecord $ mXRecord $ mDRecord $ hInfoRecord $ mInfoRecord $ aFSDBRecord $ SigRecord $ KeyRecord $ LocRecord $ nXTRecord $ nAPTRRecord $ kXRecord $ certRecord $ dNameRecord $ dSRecord $ sSHFPRecord $ rRSIGRecord $ nSECRecord $ DLVRecord $ TLSARecord $ UnknownRecord $ RPRecord $ APLRecord $ IPSECKEYRecord $ DHCIDRecord $ HIPRecord $ SPFRecord ) )
-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 $ nSEC3PARAMRecord ) )
+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 $ nSEC3PARAMRecord $ dNSdefaultTTL ) )
 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/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
index 8f4c445b2d59ada1ebe1e9968f4b262d0c37b796..069f564b15c49033d5c0cf61b172dd3063d99dd9 100644
--- a/ipaserver/plugins/dns.py
+++ b/ipaserver/plugins/dns.py
@@ -2414,6 +2414,13 @@ class dnszone(DNSZoneBase):
             minvalue=0,
             maxvalue=2147483647, # see RFC 2181
         ),
+        Int('dnsdefaultttl?',
+            cli_name='default_ttl',
+            label=_('Default time to live'),
+            doc=_('Time to live for records without explicit TTL definition'),
+            minvalue=0,
+            maxvalue=2147483647,  # see RFC 2181
+        ),
         StrEnum('dnsclass?',
             # Deprecated
             cli_name='class',
@@ -2496,8 +2503,8 @@ class dnszone(DNSZoneBase):
                 'objectclass',
                 'a6record', 'aaaarecord', 'afsdbrecord', 'aplrecord', 'arecord',
                 'certrecord', 'cn', 'cnamerecord', 'dhcidrecord', 'dlvrecord',
-                'dnamerecord', 'dnsclass', 'dnsttl', 'dsrecord',
-                'hinforecord', 'hiprecord', 'idnsallowdynupdate',
+                'dnamerecord', 'dnsclass', 'dnsdefaultttl', 'dnsttl',
+                'dsrecord', 'hinforecord', 'hiprecord', 'idnsallowdynupdate',
                 'idnsallowquery', 'idnsallowsyncptr', 'idnsallowtransfer',
                 'idnsforwarders', 'idnsforwardpolicy', 'idnsname',
                 'idnssecinlinesigning', 'idnssoaexpire', 'idnssoaminimum',
@@ -2533,8 +2540,8 @@ class dnszone(DNSZoneBase):
                 'objectclass',  # needed for record templates
                 'a6record', 'aaaarecord', 'afsdbrecord', 'aplrecord', 'arecord',
                 'certrecord', 'cn', 'cnamerecord', 'dhcidrecord', 'dlvrecord',
-                'dnamerecord', 'dnsclass', 'dnsttl', 'dsrecord',
-                'hinforecord', 'hiprecord', 'idnsallowdynupdate',
+                'dnamerecord', 'dnsclass', 'dnsdefaultttl', 'dnsttl',
+                'dsrecord', 'hinforecord', 'hiprecord', 'idnsallowdynupdate',
                 'idnsallowquery', 'idnsallowsyncptr', 'idnsallowtransfer',
                 'idnsforwarders', 'idnsforwardpolicy', 'idnsname',
                 'idnssecinlinesigning', 'idnssoaexpire', 'idnssoaminimum',
-- 
2.5.5

From eea191473b7e24117abb6016d62c95d70bd3fceb Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Mon, 20 Jun 2016 15:16:36 +0200
Subject: [PATCH] DNS: Warn about restart when default TTL setting DNS is
 changed

bind-dyndb-ldap 10.0 has to be restarted after each change to default
TTL.

https://fedorahosted.org/freeipa/ticket/2956
---
 ipaserver/plugins/dns.py | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
index 069f564b15c49033d5c0cf61b172dd3063d99dd9..455101ae22b8af2783d8c1734bba37c08af5b47c 100644
--- a/ipaserver/plugins/dns.py
+++ b/ipaserver/plugins/dns.py
@@ -73,6 +73,7 @@ from ipalib.util import (normalize_zonemgr,
                          verify_host_resolvable,
                          validate_bind_forwarder,
                          ipaddr_validator)
+from ipaplatform import services
 from ipapython.dn import DN
 from ipapython.ipautil import CheckedIPAddress
 from ipapython.dnsutil import check_zone_overlap
@@ -2663,6 +2664,17 @@ class dnszone(DNSZoneBase):
                 messages.DNSSECMasterNotInstalled()
             )
 
+    def _warning_ttl_changed_reload_needed(self, result, **options):
+        if 'dnsdefaultttl' in options:
+            messages.add_message(
+                options['version'],
+                result,
+                messages.ServiceRestartRequired(
+                    service=services.service('named').systemd_name,
+                    server=_('<all IPA DNS servers>'), )
+                )
+
+
 
 @register()
 class dnszone_add(DNSZoneBase_add):
@@ -2833,6 +2845,7 @@ class dnszone_mod(DNSZoneBase_mod):
         self.obj._warning_forwarding(result, **options)
         self.obj._warning_name_server_option(result, context, **options)
         self.obj._warning_dnssec_master_is_not_installed(result, **options)
+        self.obj._warning_ttl_changed_reload_needed(result, **options)
         return result
 
     def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
-- 
2.5.5

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to