diff --git a/.gitignore b/.gitignore index 7ac1e50..bcfe5f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -SOURCES/freeipa-4.1.0.tar.gz +SOURCES/freeipa-4.2.0.tar.gz SOURCES/header-logo.png SOURCES/login-screen-background.jpg SOURCES/login-screen-logo.png diff --git a/.ipa.metadata b/.ipa.metadata index 04fe802..3f16db3 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1,4 +1,4 @@ -40a07c0e64a696dccb5d377c635db136cbc7c2a5 SOURCES/freeipa-4.1.0.tar.gz +40a1587de7d78f4e01bfb3775ab3f4e264c56e4c SOURCES/freeipa-4.2.0.tar.gz 77c318cf1f4fc25cf847de0692a77859a767c0e3 SOURCES/header-logo.png 8727245558422bf966d60677568925f081b8e299 SOURCES/login-screen-background.jpg 24a29d79efbd0906777be4639957abda111fca4b SOURCES/login-screen-logo.png diff --git a/SOURCES/0001-Do-not-check-if-port-8443-is-available-in-step-2-of-.patch b/SOURCES/0001-Do-not-check-if-port-8443-is-available-in-step-2-of-.patch deleted file mode 100644 index ae05dc9..0000000 --- a/SOURCES/0001-Do-not-check-if-port-8443-is-available-in-step-2-of-.patch +++ /dev/null @@ -1,54 +0,0 @@ -From e22cf5bafc4c862a16bd8ac0b950c7547b048ae9 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 22 Oct 2014 11:18:35 +0200 -Subject: [PATCH] Do not check if port 8443 is available in step 2 of external - CA install - -The port is never available in step 2 of external CA install, as Dogtag is -already running. - -https://fedorahosted.org/freeipa/ticket/4660 - -Reviewed-By: David Kupka ---- - install/tools/ipa-ca-install | 3 ++- - install/tools/ipa-server-install | 9 +++++---- - 2 files changed, 7 insertions(+), 5 deletions(-) - -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index cb072e6789401f7041cafe926d7f88b2bb7f479d..1bda22dd66729999176c301af2f9b05843eff75c 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -301,7 +301,8 @@ def install_master(safe_options, options): - domain_name = api.env.domain - host_name = api.env.host - -- check_ca() -+ if external != 2: -+ check_ca() - - dirname = dsinstance.config_dirname( - dsinstance.realm_to_serverid(realm_name)) -diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index 0394314ee99817f221536136ae1432cc8e92220a..67dd21f302db0eba94d048cb064caf8a1f054b83 100755 ---- a/install/tools/ipa-server-install -+++ b/install/tools/ipa-server-install -@@ -869,10 +869,11 @@ def main(): - # Make sure the 389-ds ports are available - check_dirsrv(options.unattended) - -- if setup_ca: -- if not cainstance.check_port(): -- print "IPA requires port 8443 for PKI but it is currently in use." -- sys.exit("Aborting installation") -+ if setup_ca: -+ if not cainstance.check_port(): -+ print ("IPA requires port 8443 for PKI but it is currently in " -+ "use.") -+ sys.exit("Aborting installation") - - if options.conf_ntp: - try: --- -1.9.3 - diff --git a/SOURCES/0001-Start-dirsrv-for-kdcproxy-upgrade.patch b/SOURCES/0001-Start-dirsrv-for-kdcproxy-upgrade.patch new file mode 100644 index 0000000..305ea1a --- /dev/null +++ b/SOURCES/0001-Start-dirsrv-for-kdcproxy-upgrade.patch @@ -0,0 +1,72 @@ +From 5e1ff6ef5fa35715a5b9995388c6d7b16375ac23 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 10 Jul 2015 18:18:29 +0200 +Subject: [PATCH] Start dirsrv for kdcproxy upgrade + +The kdcproxy upgrade step in ipa-server-upgrade needs a running dirsrv +instance. Under some circumstances the dirsrv isn't running. The patch +rearranges some upgrade steps and starts DS before enable_kdcproxy(). + +https://fedorahosted.org/freeipa/ticket/5113 + +Reviewed-By: Martin Basti +--- + ipaserver/install/server/upgrade.py | 35 +++++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 84a5b06accb10663eaa4d995f66796366040e9c8..f295655dc2aa592e0215f15017c9b65af49eef80 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1396,22 +1396,6 @@ def upgrade_configuration(): + http.change_mod_nss_port_from_http() + http.configure_certmonger_renewal_guard() + +- if not http.is_kdcproxy_configured(): +- root_logger.info('[Enabling KDC Proxy]') +- if http.admin_conn is None: +- http.ldapi = True +- http.fqdn = fqdn +- http.realm = api.env.realm +- http.suffix = ipautil.realm_to_suffix(api.env.realm) +- http.ldap_connect() +- http.create_kdcproxy_conf() +- http.enable_kdcproxy() +- +- http.stop() +- update_mod_nss_protocol(http) +- fix_trust_flags() +- http.start() +- + ds = dsinstance.DsInstance() + ds.configure_dirsrv_ccache() + +@@ -1433,6 +1417,25 @@ def upgrade_configuration(): + ds.suffix = ipautil.realm_to_suffix(api.env.realm) + ds_enable_sidgen_extdom_plugins(ds) + ++ # Now 389-ds is available, run the remaining http tasks ++ if not http.is_kdcproxy_configured(): ++ root_logger.info('[Enabling KDC Proxy]') ++ if http.admin_conn is None: ++ # 389-ds needs to be running ++ ds.start() ++ http.ldapi = True ++ http.fqdn = fqdn ++ http.realm = api.env.realm ++ http.suffix = ipautil.realm_to_suffix(api.env.realm) ++ http.ldap_connect() ++ http.create_kdcproxy_conf() ++ http.enable_kdcproxy() ++ ++ http.stop() ++ update_mod_nss_protocol(http) ++ fix_trust_flags() ++ http.start() ++ + uninstall_selfsign(ds, http) + + simple_service_list = ( +-- +2.1.0 + diff --git a/SOURCES/0002-Add-ipaSshPubkey-and-gidNumber-to-the-ACI-to-read-ID.patch b/SOURCES/0002-Add-ipaSshPubkey-and-gidNumber-to-the-ACI-to-read-ID.patch deleted file mode 100644 index cf1764e..0000000 --- a/SOURCES/0002-Add-ipaSshPubkey-and-gidNumber-to-the-ACI-to-read-ID.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 8e4181b467d4135dccb23400f8afad6141f44b3a Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 24 Oct 2014 15:01:27 +0300 -Subject: [PATCH] Add ipaSshPubkey and gidNumber to the ACI to read ID user - overrides - -https://fedorahosted.org/freeipa/ticket/4664 - -Reviewed-By: Martin Kosek ---- - ACI.txt | 2 +- - ipalib/plugins/idviews.py | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ACI.txt b/ACI.txt -index 27a5d2f3458ab313437060a9daea470a8f4e5203..6680f658ee1aa0f961b2681f700557ce6b9238f8 100644 ---- a/ACI.txt -+++ b/ACI.txt -@@ -131,7 +131,7 @@ aci: (targetfilter = "(objectclass=ipahostgroup)")(version 3.0;acl "permission:S - dn: cn=views,cn=accounts,dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || description || entryusn || gidnumber || ipaanchoruuid || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaGroupOverride)")(version 3.0;acl "permission:System: Read Group ID Overrides";allow (compare,read,search) userdn = "ldap:///all";) - dn: cn=views,cn=accounts,dc=ipa,dc=example --aci: (targetattr = "createtimestamp || description || entryusn || gecos || homedirectory || ipaanchoruuid || ipaoriginaluid || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=ipaUserOverride)")(version 3.0;acl "permission:System: Read User ID Overrides";allow (compare,read,search) userdn = "ldap:///all";) -+aci: (targetattr = "createtimestamp || description || entryusn || gecos || gidnumber || homedirectory || ipaanchoruuid || ipaoriginaluid || ipasshpubkey || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=ipaUserOverride)")(version 3.0;acl "permission:System: Read User ID Overrides";allow (compare,read,search) userdn = "ldap:///all";) - dn: cn=ranges,cn=etc,dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || entryusn || ipabaseid || ipabaserid || ipaidrangesize || ipanttrusteddomainsid || iparangetype || ipasecondarybaserid || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipaidrange)")(version 3.0;acl "permission:System: Read ID Ranges";allow (compare,read,search) userdn = "ldap:///all";) - dn: cn=views,cn=accounts,dc=ipa,dc=example -diff --git a/ipalib/plugins/idviews.py b/ipalib/plugins/idviews.py -index bfa8675fb84a1d1e13f44b31e9384c9c783f4c4e..9c8721018325f56e681f168b55c31055bfd07345 100644 ---- a/ipalib/plugins/idviews.py -+++ b/ipalib/plugins/idviews.py -@@ -659,6 +659,7 @@ class idoverrideuser(baseidoverride): - 'ipapermdefaultattr': { - 'objectClass', 'ipaAnchorUUID', 'uidNumber', 'description', - 'homeDirectory', 'uid', 'ipaOriginalUid', 'loginShell', 'gecos', -+ 'gidNumber', 'ipaSshPubkey', - }, - }, - } --- -2.1.0 - diff --git a/SOURCES/0002-Fix-DNS-records-installation-for-replicas.patch b/SOURCES/0002-Fix-DNS-records-installation-for-replicas.patch new file mode 100644 index 0000000..1fa91fa --- /dev/null +++ b/SOURCES/0002-Fix-DNS-records-installation-for-replicas.patch @@ -0,0 +1,33 @@ +From 8610ddbee7025286881c1b470e13f0a5ff6a4452 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Fri, 10 Jul 2015 12:58:19 -0400 +Subject: [PATCH] Fix DNS records installation for replicas + +Ticket: https:/fedorahosted.org/freeipa/ticket/5116 + +Signed-off-by: Simo Sorce +Reviewed-By: Martin Basti +--- + ipaserver/install/server/replicainstall.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index a78eeb331c1f3f4f2233abb9e65bdde79eee4000..1ad291a1eada080361031a5723a0ea61679fc72e 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -503,9 +503,9 @@ def install_check(installer): + if options.setup_dns: + dns.install_check(False, True, options, config.host_name) + else: +- installutils.get_server_ip_address(config.host_name, fstore, +- not installer.interactive, False, +- options.ip_addresses) ++ config.ips = installutils.get_server_ip_address( ++ config.host_name, fstore, not installer.interactive, False, ++ options.ip_addresses) + + # check connection + if not options.skip_conncheck: +-- +2.1.0 + diff --git a/SOURCES/0003-Fix-dns-zonemgr-validation-regression.patch b/SOURCES/0003-Fix-dns-zonemgr-validation-regression.patch deleted file mode 100644 index 1698d87..0000000 --- a/SOURCES/0003-Fix-dns-zonemgr-validation-regression.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 142a1ee40666a08006ac084eb182908d8def94af Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 24 Oct 2014 12:15:17 +0200 -Subject: [PATCH] Fix dns zonemgr validation regression - -https://fedorahosted.org/freeipa/ticket/4663 - -Reviewed-By: David Kupka ---- - ipalib/util.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipalib/util.py b/ipalib/util.py -index fcb2bab96bcf5669de444846d8dea572eefce793..7a283106d70ba6a3e25cc7129d57b44b80876882 100644 ---- a/ipalib/util.py -+++ b/ipalib/util.py -@@ -277,6 +277,7 @@ def validate_zonemgr(zonemgr): - - def validate_zonemgr_str(zonemgr): - zonemgr = normalize_zonemgr(zonemgr) -+ zonemgr = DNSName(zonemgr) - return validate_zonemgr(zonemgr) - - def validate_hostname(hostname, check_fqdn=True, allow_underscore=False, allow_slash=False): --- -2.1.0 - diff --git a/SOURCES/0003-Prevent-to-rename-certprofile-profile-id.patch b/SOURCES/0003-Prevent-to-rename-certprofile-profile-id.patch new file mode 100644 index 0000000..5127951 --- /dev/null +++ b/SOURCES/0003-Prevent-to-rename-certprofile-profile-id.patch @@ -0,0 +1,29 @@ +From 51f03f45f6cdab9da0479f48093951ccdd7cdab0 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 9 Jul 2015 17:17:21 +0200 +Subject: [PATCH] Prevent to rename certprofile profile id + +https://fedorahosted.org/freeipa/ticket/5074 + +Reviewed-By: Jan Cholasta +--- + ipalib/plugins/certprofile.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index 6f9a41875b2a276b521219156e630817a9c41fdc..5550ed942521dbab2e783fba1570520268f9b378 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -291,6 +291,9 @@ class certprofile_mod(LDAPUpdate): + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + ca_enabled_check() ++ # Once a profile id is set it cannot be changed ++ if 'cn' in entry_attrs: ++ raise errors.ACIError(info=_('cn is immutable')) + if 'file' in options: + with self.api.Backend.ra_certprofile as profile_api: + profile_api.disable_profile(keys[0]) +-- +2.1.0 + diff --git a/SOURCES/0004-Handle-profile-changes-in-dogtag-ipa-ca-renew-agent.patch b/SOURCES/0004-Handle-profile-changes-in-dogtag-ipa-ca-renew-agent.patch deleted file mode 100644 index 6def83a..0000000 --- a/SOURCES/0004-Handle-profile-changes-in-dogtag-ipa-ca-renew-agent.patch +++ /dev/null @@ -1,181 +0,0 @@ -From b82f0b1bc483fe265f3e2d2089b65185cafffd74 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 14 Oct 2014 10:30:07 +0200 -Subject: [PATCH] Handle profile changes in dogtag-ipa-ca-renew-agent - -To update the CA certificate in the Dogtag NSS database, the -"ipa-cacert-manage renew" and "ipa-certupdate" commands temporarily change -the profile of the CA certificate certmonger request, resubmit it and -change the profile back to the original one. - -When something goes wrong while resubmitting the request, it needs to be -modified and resubmitted again manually. This might fail with invalid -cookie error, because changing the profile does not change the internal -state of the request. - -Detect this in dogtag-ipa-ca-renew-agent and reset the internal state when -profile is changed. - -https://fedorahosted.org/freeipa/ticket/4627 - -Reviewed-By: David Kupka ---- - .../certmonger/dogtag-ipa-ca-renew-agent-submit | 87 ++++++++++++++++++++-- - 1 file changed, 80 insertions(+), 7 deletions(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index 4f0b78accac6840471f8b2e9f17288b3b4e82105..ca4380c331cc417c0a89eca17e987920118337d7 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -31,6 +31,7 @@ import tempfile - import shutil - import base64 - import contextlib -+import json - - from ipapython import ipautil - from ipapython.dn import DN -@@ -64,6 +65,78 @@ def ldap_connect(): - if conn is not None and conn.isconnected(): - conn.disconnect() - -+def call_handler(_handler, *args, **kwargs): -+ """ -+ Request handler call wrapper -+ -+ Before calling the handler, get the original profile name and cookie from -+ the provided cookie, if there is one. If the profile name does not match -+ the requested profile name, drop the cookie and restart the request. -+ -+ After calling the handler, put the requested profile name and cookie -+ returned by the handler in a new cookie and return it. -+ """ -+ operation = os.environ['CERTMONGER_OPERATION'] -+ if operation == 'POLL': -+ cookie = os.environ.pop('CERTMONGER_CA_COOKIE', None) -+ if cookie is not None: -+ try: -+ context = json.loads(cookie) -+ if not isinstance(context, dict): -+ raise TypeError -+ except (TypeError, ValueError): -+ return (UNCONFIGURED, "Invalid cookie: %r" % cookie) -+ else: -+ return (UNCONFIGURED, "Cookie not provided") -+ -+ if 'profile' in context: -+ profile = context.pop('profile') -+ try: -+ if profile is not None: -+ if not isinstance(profile, unicode): -+ raise TypeError -+ profile = profile.encode('raw_unicode_escape') -+ except (TypeError, UnicodeEncodeError): -+ return (UNCONFIGURED, -+ "Invalid 'profile' in cookie: %r" % profile) -+ else: -+ return (UNCONFIGURED, "No 'profile' in cookie") -+ -+ # If profile has changed between SUBMIT and POLL, restart request -+ if os.environ.get('CERTMONGER_CA_PROFILE') != profile: -+ os.environ['CERTMONGER_OPERATION'] = 'SUBMIT' -+ context = {} -+ -+ if 'cookie' in context: -+ cookie = context.pop('cookie') -+ try: -+ if not isinstance(cookie, unicode): -+ raise TypeError -+ cookie = cookie.encode('raw_unicode_escape') -+ except (TypeError, UnicodeEncodeError): -+ return (UNCONFIGURED, -+ "Invalid 'cookie' in cookie: %r" % cookie) -+ os.environ['CERTMONGER_CA_COOKIE'] = cookie -+ else: -+ context = {} -+ -+ result = _handler(*args, **kwargs) -+ -+ if result[0] in (WAIT, WAIT_WITH_DELAY): -+ context['cookie'] = result[-1].decode('raw_unicode_escape') -+ -+ profile = os.environ.get('CERTMONGER_CA_PROFILE') -+ if profile is not None: -+ profile = profile.decode('raw_unicode_escape') -+ context['profile'] = profile -+ -+ cookie = json.dumps(context) -+ os.environ['CERTMONGER_CA_COOKIE'] = cookie -+ if result[0] in (WAIT, WAIT_WITH_DELAY): -+ result = result[:-1] + (cookie,) -+ -+ return result -+ - def request_cert(): - """ - Request certificate from IPA CA. -@@ -144,7 +217,7 @@ def store_cert(): - syslog.syslog( - syslog.LOG_ERR, - "Updating renewal certificate failed: %s. Sleeping 30s" % e) -- return (WAIT_WITH_DELAY, 30, attempts) -+ return (WAIT_WITH_DELAY, 30, str(attempts)) - else: - syslog.syslog( - syslog.LOG_ERR, -@@ -179,7 +252,7 @@ def request_and_store_cert(): - else: - os.environ['CERTMONGER_CA_COOKIE'] = cookie - -- result = request_cert() -+ result = call_handler(request_cert) - if result[0] == WAIT: - return (result[0], 'request:%s' % result[1]) - elif result[0] == WAIT_WITH_DELAY: -@@ -198,7 +271,7 @@ def request_and_store_cert(): - os.environ['CERTMONGER_CA_COOKIE'] = cookie - os.environ['CERTMONGER_CERTIFICATE'] = cert - -- result = store_cert() -+ result = call_handler(store_cert) - if result[0] == WAIT: - return (result[0], 'store:%s:%s' % (cert, result[1])) - elif result[0] == WAIT_WITH_DELAY: -@@ -258,7 +331,7 @@ def retrieve_cert(): - syslog.LOG_INFO, - "Updated certificate for %s not available" % nickname) - # No cert available yet, tell certmonger to wait another 8 hours -- return (WAIT_WITH_DELAY, 8 * 60 * 60, attempts) -+ return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts)) - - cert = base64.b64encode(cert) - cert = x509.make_pem(cert) -@@ -323,14 +396,14 @@ def renew_ca_cert(): - return (OPERATION_NOT_SUPPORTED_BY_HELPER,) - - if state == 'retrieve': -- result = retrieve_cert() -+ result = call_handler(retrieve_cert) - if result[0] == WAIT_WITH_DELAY and not is_self_signed: - syslog.syslog(syslog.LOG_ALERT, - "IPA CA certificate is about to expire, " - "use ipa-cacert-manage to renew it") - elif state == 'request': - os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert' -- result = request_and_store_cert() -+ result = call_handler(request_and_store_cert) - - if result[0] == WAIT: - return (result[0], '%s:%s' % (state, result[1])) -@@ -369,7 +442,7 @@ def main(): - else: - handler = retrieve_cert - -- res = handler() -+ res = call_handler(handler) - for item in res[1:]: - print item - return res[0] --- -2.1.0 - diff --git a/SOURCES/0004-Stageusedr-activate-show-username-instead-of-DN.patch b/SOURCES/0004-Stageusedr-activate-show-username-instead-of-DN.patch new file mode 100644 index 0000000..4d29df8 --- /dev/null +++ b/SOURCES/0004-Stageusedr-activate-show-username-instead-of-DN.patch @@ -0,0 +1,36 @@ +From 5fb2c0f8c7237214f870d341cc10a2ccda48d117 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Fri, 10 Jul 2015 14:47:59 +0200 +Subject: [PATCH] Stageusedr-activate: show username instead of DN + +If activate user already exists, show name of this user in error message +instead of user DN. +Error message reworder to keep the same format as stageuser-add, +user-add. + +https://fedorahosted.org/freeipa/ticket/5038 + +Reviewed-By: David Kupka +--- + ipalib/plugins/stageuser.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/ipalib/plugins/stageuser.py b/ipalib/plugins/stageuser.py +index 35e636ded4474b00ad635c60340aaf66e6b41752..6cbc8f4ab07f2c1172f2b2c45bfe8f30a74938b3 100644 +--- a/ipalib/plugins/stageuser.py ++++ b/ipalib/plugins/stageuser.py +@@ -682,8 +682,9 @@ class stageuser_activate(LDAPQuery): + active_dn, ['dn'] + ) + assert isinstance(staging_dn, DN) +- raise errors.DuplicateEntry(message=_('Active user %(user)s already exists') % dict( +- user=test_entry_attrs.dn)) ++ raise errors.DuplicateEntry( ++ message=_('active user with name "%(user)s" already exists') % ++ dict(user=args[-1])) + except errors.NotFound: + pass + +-- +2.1.0 + diff --git a/SOURCES/0005-Do-not-wait-for-new-CA-certificate-to-appear-in-LDAP.patch b/SOURCES/0005-Do-not-wait-for-new-CA-certificate-to-appear-in-LDAP.patch deleted file mode 100644 index 07ade9e..0000000 --- a/SOURCES/0005-Do-not-wait-for-new-CA-certificate-to-appear-in-LDAP.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 5fa2b9d411c7c35266fa1c9726d91243ba2b02d6 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 14 Oct 2014 11:12:55 +0200 -Subject: [PATCH] Do not wait for new CA certificate to appear in LDAP in - ipa-certupdate - -If new certificate is not available, reuse the old one, instead of waiting -indefinitely for the new certificate to appear. - -https://fedorahosted.org/freeipa/ticket/4628 - -Reviewed-By: David Kupka ---- - .../certmonger/dogtag-ipa-ca-renew-agent-submit | 87 ++++++++++++---------- - ipa-client/ipaclient/ipa_certupdate.py | 6 +- - 2 files changed, 53 insertions(+), 40 deletions(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index ca4380c331cc417c0a89eca17e987920118337d7..9a01eb3a08900a5c8d04953b41f4493f30c2b56f 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -279,25 +279,11 @@ def request_and_store_cert(): - else: - return result - --def retrieve_cert(): -+def retrieve_or_reuse_cert(): - """ -- Retrieve new certificate from LDAP. -+ Retrieve certificate from LDAP. If the certificate is not available, reuse -+ the old certificate. - """ -- operation = os.environ.get('CERTMONGER_OPERATION') -- if operation == 'SUBMIT': -- attempts = 0 -- elif operation == 'POLL': -- cookie = os.environ.get('CERTMONGER_CA_COOKIE') -- if not cookie: -- return (UNCONFIGURED, "Cookie not provided") -- -- try: -- attempts = int(cookie) -- except ValueError: -- return (UNCONFIGURED, "Invalid cookie: %r" % cookie) -- else: -- return (OPERATION_NOT_SUPPORTED_BY_HELPER,) -- - csr = os.environ.get('CERTMONGER_CSR') - if not csr: - return (UNCONFIGURED, "Certificate request not provided") -@@ -306,12 +292,9 @@ def retrieve_cert(): - if not nickname: - return (REJECTED, "No friendly name in the certificate request") - -- old_cert = os.environ.get('CERTMONGER_CERTIFICATE') -- if not old_cert: -+ cert = os.environ.get('CERTMONGER_CERTIFICATE') -+ if not cert: - return (REJECTED, "New certificate requests not supported") -- old_cert = x509.normalize_certificate(old_cert) -- -- syslog.syslog(syslog.LOG_NOTICE, "Updating certificate for %s" % nickname) - - with ldap_connect() as conn: - try: -@@ -320,23 +303,50 @@ def retrieve_cert(): - ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn), - ['usercertificate']) - except errors.NotFound: -- cert = old_cert -+ pass - else: - cert = entry.single_value['usercertificate'] -+ cert = base64.b64encode(cert) -+ cert = x509.make_pem(cert) -+ -+ return (ISSUED, cert) -+ -+def retrieve_cert(): -+ """ -+ Retrieve new certificate from LDAP. -+ """ -+ operation = os.environ.get('CERTMONGER_OPERATION') -+ if operation == 'SUBMIT': -+ attempts = 0 -+ elif operation == 'POLL': -+ cookie = os.environ.get('CERTMONGER_CA_COOKIE') -+ if not cookie: -+ return (UNCONFIGURED, "Cookie not provided") -+ -+ try: -+ attempts = int(cookie) -+ except ValueError: -+ return (UNCONFIGURED, "Invalid cookie: %r" % cookie) -+ else: -+ return (OPERATION_NOT_SUPPORTED_BY_HELPER,) - -- if cert == old_cert: -- attempts += 1 -- if attempts < 4: -- syslog.syslog( -- syslog.LOG_INFO, -- "Updated certificate for %s not available" % nickname) -- # No cert available yet, tell certmonger to wait another 8 hours -- return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts)) -+ old_cert = os.environ.get('CERTMONGER_CERTIFICATE') -+ if old_cert: -+ old_cert = x509.normalize_certificate(old_cert) - -- cert = base64.b64encode(cert) -- cert = x509.make_pem(cert) -+ result = call_handler(retrieve_or_reuse_cert) -+ if result[0] != ISSUED: -+ return result - -- return (ISSUED, cert) -+ new_cert = x509.normalize_certificate(result[1]) -+ if new_cert == old_cert: -+ attempts += 1 -+ if attempts < 4: -+ syslog.syslog(syslog.LOG_INFO, "Updated certificate not available") -+ # No cert available yet, tell certmonger to wait another 8 hours -+ return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts)) -+ -+ return result - - def export_csr(): - """ -@@ -414,10 +424,11 @@ def renew_ca_cert(): - - def main(): - handlers = { -- 'ipaStorage': store_cert, -- 'ipaRetrieval': retrieve_cert, -- 'ipaCSRExport': export_csr, -- 'ipaCACertRenewal': renew_ca_cert, -+ 'ipaStorage': store_cert, -+ 'ipaRetrievalOrReuse': retrieve_or_reuse_cert, -+ 'ipaRetrieval': retrieve_cert, -+ 'ipaCSRExport': export_csr, -+ 'ipaCACertRenewal': renew_ca_cert, - } - - api.bootstrap(context='renew') -diff --git a/ipa-client/ipaclient/ipa_certupdate.py b/ipa-client/ipaclient/ipa_certupdate.py -index 7ef11d058eeeb47dc47d46aa7cbe73578c42d131..031a34c3a54a02d43978eedcb794678a1550702b 100644 ---- a/ipa-client/ipaclient/ipa_certupdate.py -+++ b/ipa-client/ipaclient/ipa_certupdate.py -@@ -143,14 +143,16 @@ class CertUpdate(admintool.AdminTool): - timeout = api.env.startup_timeout + 60 - - self.log.debug("resubmitting certmonger request '%s'", request_id) -- certmonger.resubmit_request(request_id, profile='ipaRetrieval') -+ certmonger.resubmit_request( -+ request_id, profile='ipaRetrievalOrReuse') - try: - state = certmonger.wait_for_request(request_id, timeout) - except RuntimeError: - raise admintool.ScriptError( - "Resubmitting certmonger request '%s' timed out, " - "please check the request manually" % request_id) -- if state != 'MONITORING': -+ ca_error = certmonger.get_request_value(request_id, 'ca-error') -+ if state != 'MONITORING' or ca_error: - raise admintool.ScriptError( - "Error resubmitting certmonger request '%s', " - "please check the request manually" % request_id) --- -2.1.0 - diff --git a/SOURCES/0005-copy-schema-to-ca-allow-to-overwrite-schema-files.patch b/SOURCES/0005-copy-schema-to-ca-allow-to-overwrite-schema-files.patch new file mode 100644 index 0000000..2181d76 --- /dev/null +++ b/SOURCES/0005-copy-schema-to-ca-allow-to-overwrite-schema-files.patch @@ -0,0 +1,72 @@ +From 7919e3c6b245adb0f6d6743edaf03da704259b5d Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Fri, 10 Jul 2015 14:17:02 +0200 +Subject: [PATCH] copy-schema-to-ca: allow to overwrite schema files + +If content of source and target file differs, the script will ask user +for permission to overwrite target file. + +https://fedorahosted.org/freeipa/ticket/5034 + +Reviewed-By: David Kupka +--- + install/share/copy-schema-to-ca.py | 29 ++++++++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/install/share/copy-schema-to-ca.py b/install/share/copy-schema-to-ca.py +index 1614e11636c2f52e231ea2ff40d882209194c60a..ff6c3568586f9f4b3fac7f848869e74d0db0df34 100755 +--- a/install/share/copy-schema-to-ca.py ++++ b/install/share/copy-schema-to-ca.py +@@ -15,6 +15,8 @@ import sys + import pwd + import shutil + ++from hashlib import sha1 ++ + from ipapython import ipautil, dogtag + from ipapython.ipa_log_manager import root_logger, standard_logging_setup + from ipaserver.install.dsinstance import DS_USER, schema_dirname +@@ -42,6 +44,11 @@ SCHEMA_FILENAMES = ( + ) + + ++def _sha1_file(filename): ++ with open(filename, 'rb') as f: ++ return sha1(f.read()).hexdigest() ++ ++ + def add_ca_schema(): + """Copy IPA schema files into the CA DS instance + """ +@@ -54,9 +61,25 @@ def add_ca_schema(): + root_logger.debug('File does not exist: %s', source_fname) + continue + if os.path.exists(target_fname): +- root_logger.info( +- 'Target exists, not overwriting: %s', target_fname) +- continue ++ target_sha1 = _sha1_file(target_fname) ++ source_sha1 = _sha1_file(source_fname) ++ if target_sha1 != source_sha1: ++ target_size = os.stat(target_fname).st_size ++ source_size = os.stat(source_fname).st_size ++ root_logger.info('Target file %s exists but the content is ' ++ 'different', target_fname) ++ root_logger.info('\tTarget file: sha1: %s, size: %s B', ++ target_sha1, target_size) ++ root_logger.info('\tSource file: sha1: %s, size: %s B', ++ source_sha1, source_size) ++ if not ipautil.user_input("Do you want replace %s file?" % ++ target_fname, True): ++ continue ++ ++ else: ++ root_logger.info( ++ 'Target exists, not overwriting: %s', target_fname) ++ continue + try: + shutil.copyfile(source_fname, target_fname) + except IOError, e: +-- +2.1.0 + diff --git a/SOURCES/0006-Fail-if-certmonger-can-t-see-new-CA-certificate-in-L.patch b/SOURCES/0006-Fail-if-certmonger-can-t-see-new-CA-certificate-in-L.patch deleted file mode 100644 index cd83510..0000000 --- a/SOURCES/0006-Fail-if-certmonger-can-t-see-new-CA-certificate-in-L.patch +++ /dev/null @@ -1,101 +0,0 @@ -From ccaacaaf054e9d597159e14714ab41069173da10 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 14 Oct 2014 11:26:15 +0200 -Subject: [PATCH] Fail if certmonger can't see new CA certificate in LDAP in - ipa-cacert-manage - -This should not normally happen, but if it does, report an error instead of -waiting idefinitely for the certificate to appear. - -https://fedorahosted.org/freeipa/ticket/4629 - -Reviewed-By: David Kupka ---- - .../certmonger/dogtag-ipa-ca-renew-agent-submit | 40 +++++++++------------- - ipaserver/install/ipa_cacert_manage.py | 3 +- - 2 files changed, 19 insertions(+), 24 deletions(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index 9a01eb3a08900a5c8d04953b41f4493f30c2b56f..e5ad9639b03b95e6e265214067a985f6c3ca0b2a 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -311,25 +311,11 @@ def retrieve_or_reuse_cert(): - - return (ISSUED, cert) - --def retrieve_cert(): -+def retrieve_cert_continuous(): - """ -- Retrieve new certificate from LDAP. -+ Retrieve new certificate from LDAP. Repeat every eight hours until the -+ certificate is available. - """ -- operation = os.environ.get('CERTMONGER_OPERATION') -- if operation == 'SUBMIT': -- attempts = 0 -- elif operation == 'POLL': -- cookie = os.environ.get('CERTMONGER_CA_COOKIE') -- if not cookie: -- return (UNCONFIGURED, "Cookie not provided") -- -- try: -- attempts = int(cookie) -- except ValueError: -- return (UNCONFIGURED, "Invalid cookie: %r" % cookie) -- else: -- return (OPERATION_NOT_SUPPORTED_BY_HELPER,) -- - old_cert = os.environ.get('CERTMONGER_CERTIFICATE') - if old_cert: - old_cert = x509.normalize_certificate(old_cert) -@@ -340,11 +326,19 @@ def retrieve_cert(): - - new_cert = x509.normalize_certificate(result[1]) - if new_cert == old_cert: -- attempts += 1 -- if attempts < 4: -- syslog.syslog(syslog.LOG_INFO, "Updated certificate not available") -- # No cert available yet, tell certmonger to wait another 8 hours -- return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts)) -+ syslog.syslog(syslog.LOG_INFO, "Updated certificate not available") -+ # No cert available yet, tell certmonger to wait another 8 hours -+ return (WAIT_WITH_DELAY, 8 * 60 * 60, '') -+ -+ return result -+ -+def retrieve_cert(): -+ """ -+ Retrieve new certificate from LDAP. -+ """ -+ result = call_handler(retrieve_cert_continuous) -+ if result[0] == WAIT_WITH_DELAY: -+ return (REJECTED, "Updated certificate not available") - - return result - -@@ -451,7 +445,7 @@ def main(): - if ca.is_renewal_master(): - handler = request_and_store_cert - else: -- handler = retrieve_cert -+ handler = retrieve_cert_continuous - - res = call_handler(handler) - for item in res[1:]: -diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py -index a521e3965321d3345075d7fc4a55fb9c6904a652..2a8d95fdbebecf543a05afd47275c32684cad970 100644 ---- a/ipaserver/install/ipa_cacert_manage.py -+++ b/ipaserver/install/ipa_cacert_manage.py -@@ -297,7 +297,8 @@ class CACertManage(admintool.AdminTool): - raise admintool.ScriptError( - "Resubmitting certmonger request '%s' timed out, " - "please check the request manually" % self.request_id) -- if state != 'MONITORING': -+ ca_error = certmonger.get_request_value(self.request_id, 'ca-error') -+ if state != 'MONITORING' or ca_error: - raise admintool.ScriptError( - "Error resubmitting certmonger request '%s', " - "please check the request manually" % self.request_id) --- -2.1.0 - diff --git a/SOURCES/0006-spec-file-Update-minimum-required-version-of-krb5.patch b/SOURCES/0006-spec-file-Update-minimum-required-version-of-krb5.patch new file mode 100644 index 0000000..8bf286e --- /dev/null +++ b/SOURCES/0006-spec-file-Update-minimum-required-version-of-krb5.patch @@ -0,0 +1,48 @@ +From 6bc5c6e1d7af6229e8c6f547951b0b3314ca5f12 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 15 Jul 2015 08:45:53 +0000 +Subject: [PATCH] spec file: Update minimum required version of krb5 + +Automatically require the krb5 version used at build time. + +https://fedorahosted.org/freeipa/ticket/5132 + +Reviewed-By: Alexander Bokovoy +--- + freeipa.spec.in | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index e78ad1a0851186c7fdb5ab0a4649b64b2b1e010f..a819710b2bad16a5c17b77670cdb29cb4b09ad8f 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -11,6 +11,8 @@ + %global selinux_policy_version 3.12.1-179 + %endif + ++%define krb5_base_version %(LC_ALL=C rpm -q --qf '%%{VERSION}' krb5-devel | grep -Eo '^[^.]+\.[^.]+') ++ + %global plugin_dir %{_libdir}/dirsrv/plugins + %global etc_systemd_dir %{_sysconfdir}/systemd/system + %global gettext_domain ipa +@@ -52,7 +54,7 @@ BuildRequires: nspr-devel + BuildRequires: nss-devel + BuildRequires: openssl-devel + BuildRequires: openldap-devel +-BuildRequires: krb5-devel >= 1.11 ++BuildRequires: krb5-devel >= 1.13 + BuildRequires: krb5-workstation + BuildRequires: libuuid-devel + BuildRequires: libcurl-devel >= 7.21.7-2 +@@ -119,7 +121,7 @@ Requires: 389-ds-base >= 1.3.4.0 + Requires: openldap-clients > 2.4.35-4 + Requires: nss >= 3.14.3-12.0 + Requires: nss-tools >= 3.14.3-12.0 +-Requires: krb5-server >= 1.11.5-5 ++Requires(post): krb5-server >= %{krb5_base_version}, krb5-server < %{krb5_base_version}.100 + Requires: krb5-pkinit-openssl + Requires: cyrus-sasl-gssapi%{?_isa} + Requires: ntp +-- +2.1.0 + diff --git a/SOURCES/0007-Fix-possible-NULL-dereference-in-ipa-kdb.patch b/SOURCES/0007-Fix-possible-NULL-dereference-in-ipa-kdb.patch deleted file mode 100644 index 01e8b44..0000000 --- a/SOURCES/0007-Fix-possible-NULL-dereference-in-ipa-kdb.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 73aa4b8a8b7352679a9c1e5ef900824be7b8f37c Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 5 Nov 2014 08:44:05 +0000 -Subject: [PATCH] Fix possible NULL dereference in ipa-kdb - -https://fedorahosted.org/freeipa/ticket/4651 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 084b689d459f27e72d679d37e24650149973df61..c8f6c76fb5b3bc7d47ec8a1551579d53d226027e 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -1888,9 +1888,11 @@ void get_authz_data_types(krb5_context context, krb5_db_entry *entry, - } - - ipactx = ipadb_get_context(context); -- gcfg = ipadb_get_global_config(ipactx); -- if (gcfg != NULL) -- tmp = gcfg->authz_data; -+ if (ipactx != NULL) { -+ gcfg = ipadb_get_global_config(ipactx); -+ if (gcfg != NULL) -+ tmp = gcfg->authz_data; -+ } - if (ipactx == NULL || tmp == NULL) { - krb5_klog_syslog(LOG_ERR, "No default authorization data types " \ - "available, no authorization data will " \ --- -2.1.0 - diff --git a/SOURCES/0007-do-not-import-memcache-on-client.patch b/SOURCES/0007-do-not-import-memcache-on-client.patch new file mode 100644 index 0000000..cbdcfb0 --- /dev/null +++ b/SOURCES/0007-do-not-import-memcache-on-client.patch @@ -0,0 +1,41 @@ +From 0def5f5e160f6ebdf766d956721b70c26372a0b6 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Thu, 16 Jul 2015 10:17:26 +0200 +Subject: [PATCH] do not import memcache on client + +Fixes regression caused by cd3ca94ff2ef738cb3a9eae502193413058f976d. + +Which caused: +* client installation failure (missing memcache) +* invalid warning in CLI on server + +https://fedorahosted.org/freeipa/ticket/5133 + +Reviewed-By: Tomas Babej +--- + ipalib/plugins/session.py | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/ipalib/plugins/session.py b/ipalib/plugins/session.py +index 3fd566d3224a13b5fbaa4450f02855329a13bc4c..b03b6b41032ab7f00ff9b75e23b5f998353a7ea5 100644 +--- a/ipalib/plugins/session.py ++++ b/ipalib/plugins/session.py +@@ -2,11 +2,13 @@ + # Copyright (C) 2015 FreeIPA Contributors see COPYING for license + # + +-from ipalib import Command ++from ipalib import api, Command + from ipalib.request import context +-from ipalib.session import session_mgr + from ipalib.plugable import Registry + ++if api.env.in_server: ++ from ipalib.session import session_mgr ++ + register = Registry() + + +-- +2.4.3 + diff --git a/SOURCES/0008-Fix-memory-leaks-in-ipa-extdom-extop.patch b/SOURCES/0008-Fix-memory-leaks-in-ipa-extdom-extop.patch deleted file mode 100644 index 39a260e..0000000 --- a/SOURCES/0008-Fix-memory-leaks-in-ipa-extdom-extop.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 57ce6c99123854da69ce07fb8305d102b8e9d271 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 5 Nov 2014 08:46:19 +0000 -Subject: [PATCH] Fix memory leaks in ipa-extdom-extop - -https://fedorahosted.org/freeipa/ticket/4651 - -Reviewed-By: Alexander Bokovoy ---- - .../ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -index df04347e3d36b33ca0a4ea2391f60d97b75a97bf..20fdd62b20f28f5384cf83b8be5819f721c6c3db 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -@@ -340,7 +340,8 @@ static int pack_ber_user(enum response_types response_type, - - ber = ber_alloc_t( LBER_USE_DER ); - if (ber == NULL) { -- return LDAP_OPERATIONS_ERROR; -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; - } - - ret = ber_printf(ber,"{e{ssii", response_type, domain_name, short_user_name, -@@ -449,14 +450,15 @@ static int pack_ber_group(enum response_types response_type, - - ber = ber_alloc_t( LBER_USE_DER ); - if (ber == NULL) { -- return LDAP_OPERATIONS_ERROR; -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; - } - - ret = ber_printf(ber,"{e{ssi", response_type, domain_name, short_group_name, - gid); - if (ret == -1) { -- ber_free(ber, 1); -- return LDAP_OPERATIONS_ERROR; -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; - } - - if (response_type == RESP_GROUP_MEMBERS) { -@@ -716,7 +718,7 @@ static int handle_sid_request(enum request_types request_type, const char *sid, - - ret = get_buffer(&buf_len, &buf); - if (ret != LDAP_SUCCESS) { -- return ret; -+ goto done; - } - - switch(id_type) { --- -2.1.0 - diff --git a/SOURCES/0008-selinux-enable-httpd_run_ipa-to-allow-communicating-.patch b/SOURCES/0008-selinux-enable-httpd_run_ipa-to-allow-communicating-.patch new file mode 100644 index 0000000..c36d10a --- /dev/null +++ b/SOURCES/0008-selinux-enable-httpd_run_ipa-to-allow-communicating-.patch @@ -0,0 +1,49 @@ +From aad359de280a0c28e9a9305fd93b48cd40ddddd8 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 14 Jul 2015 11:11:36 +0000 +Subject: [PATCH] selinux: enable httpd_run_ipa to allow communicating with + oddjobd services + +A new SELinux policy allows communication between IPA framework running +under Apache with oddjobd-based services via DBus. + +This communication is crucial for one-way trust support and also is required +for any out of band tools which may be executed by IPA framework. + +Details of out of band communication and SELinux policy can be found in a bug +https://bugzilla.redhat.com/show_bug.cgi?id=1238165 + +Reviewed-By: Tomas Babej +--- + freeipa.spec.in | 2 +- + ipaserver/install/httpinstance.py | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index a819710b2bad16a5c17b77670cdb29cb4b09ad8f..5790f7941d2117ed95d3c99556f1579c27917270 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -8,7 +8,7 @@ + %global selinux_policy_version 3.12.1-153 + %else + %global samba_version 2:4.0.5-1 +-%global selinux_policy_version 3.12.1-179 ++%global selinux_policy_version 3.13.1-128.6 + %endif + + %define krb5_base_version %(LC_ALL=C rpm -q --qf '%%{VERSION}' krb5-devel | grep -Eo '^[^.]+\.[^.]+') +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index f5f2a86fca3a1ff3e9123d08052a7e57b50a94fe..792825621f68844a2b0b1265eeeb37e4247d66f8 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -46,6 +46,7 @@ from ipaplatform import services + SELINUX_BOOLEAN_SETTINGS = dict( + httpd_can_network_connect='on', + httpd_manage_ipa='on', ++ httpd_run_ipa='on', + ) + + +-- +2.4.3 + diff --git a/SOURCES/0009-Fix-various-bugs-in-ipa-opt-counter-and-ipa-otp-last.patch b/SOURCES/0009-Fix-various-bugs-in-ipa-opt-counter-and-ipa-otp-last.patch deleted file mode 100644 index a9dd4a4..0000000 --- a/SOURCES/0009-Fix-various-bugs-in-ipa-opt-counter-and-ipa-otp-last.patch +++ /dev/null @@ -1,102 +0,0 @@ -From f4574e1764e56a3a281bfc0e5aba886c46cadf95 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 5 Nov 2014 08:50:26 +0000 -Subject: [PATCH] Fix various bugs in ipa-opt-counter and ipa-otp-lasttoken - -Fixes a wrong sizeof argument and unchecked return values. - -https://fedorahosted.org/freeipa/ticket/4651 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-slapi-plugins/ipa-otp-counter/berval.c | 2 +- - .../ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c | 14 +++++++++++--- - .../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 6 +++++- - 3 files changed, 17 insertions(+), 5 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-counter/berval.c b/daemons/ipa-slapi-plugins/ipa-otp-counter/berval.c -index 884e1a21004c5440f3bbad9da57d43bba8649d5f..a2fe592f07746423b12d9a531d7860615b729afa 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-counter/berval.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-counter/berval.c -@@ -48,7 +48,7 @@ berval_new_longlong(long long value) - { - struct berval *bv; - -- bv = (struct berval*) slapi_ch_malloc(sizeof(struct berval*)); -+ bv = (struct berval*) slapi_ch_malloc(sizeof(struct berval)); - bv->bv_val = slapi_ch_smprintf("%lld", value); - bv->bv_len = strlen(bv->bv_val); - -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c b/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c -index 24ef9e2401d62d7d63b55afb9aa3ba2f41642839..da047d7dc58e27b37ad29c39bde44e33602ab4c5 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-counter/ipa_otp_counter.c -@@ -50,6 +50,7 @@ - - #include "berval.h" - #include "ldapmod.h" -+#include "util.h" - - #include - -@@ -140,6 +141,7 @@ normalize_input(LDAPMod ***mods, const char *attr, long long ctr) - case LDAP_MOD_REPLACE: - case LDAP_MOD_INCREMENT: - e++; -+ /* fall through */ - default: - c++; - } -@@ -284,8 +286,12 @@ preop_mod(Slapi_PBlock *pb) - cpre = get_counter(epre, attr); - - if (repl == 0) { -- if (normalize_input(&mods, attr, cpre) != 0) -- slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods); -+ if (normalize_input(&mods, attr, cpre) != 0) { -+ if (slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods)) { -+ LOG_FATAL("slapi_pblock_set failed!\n"); -+ goto error; -+ } -+ } - } - - if (!simulate(mods, attr, cpre, &cpost) && repl == 0) { -@@ -316,7 +322,9 @@ preop_mod(Slapi_PBlock *pb) - error: - rc = LDAP_UNWILLING_TO_PERFORM; - slapi_send_ldap_result(pb, rc, NULL, msg, 0, NULL); -- slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc); -+ if (slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc)) { -+ LOG_FATAL("slapi_pblock_set failed!\n"); -+ } - - slapi_ch_free_string(&msg); - return rc; -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -index 94d24ae0f0383c090e1207c6f4552ea29601f26e..d20fca1e705f7406362a3ba2def9ba102bd1622d 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -@@ -44,6 +44,8 @@ - #include - #include - -+#include "util.h" -+ - #define PLUGIN_NAME "ipa-otp-lasttoken" - #define LOG(sev, ...) \ - slapi_log_error(SLAPI_LOG_ ## sev, PLUGIN_NAME, \ -@@ -100,7 +102,9 @@ static inline int - send_error(Slapi_PBlock *pb, int rc, char *errstr) - { - slapi_send_ldap_result(pb, rc, NULL, errstr, 0, NULL); -- slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc); -+ if (slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc)) { -+ LOG_FATAL("slapi_pblock_set failed!\n"); -+ } - return rc; - } - --- -2.1.0 - diff --git a/SOURCES/0009-oddjob-avoid-chown-keytab-to-sssd-if-sssd-user-does-.patch b/SOURCES/0009-oddjob-avoid-chown-keytab-to-sssd-if-sssd-user-does-.patch new file mode 100644 index 0000000..34ece69 --- /dev/null +++ b/SOURCES/0009-oddjob-avoid-chown-keytab-to-sssd-if-sssd-user-does-.patch @@ -0,0 +1,50 @@ +From cc4f00b7fcbd01dcdfd920feda39cdd0344e7cd7 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 16 Jul 2015 14:11:26 +0300 +Subject: [PATCH] oddjob: avoid chown keytab to sssd if sssd user does not + exist + +If sssd user does not exist, it means SSSD does not run as sssd user. + +Currently SSSD has too tight check for keytab permissions and ownership. +It assumes the keytab has to be owned by the same user it runs under +and has to have 0600 permissions. ipa-getkeytab creates the file with +right permissions and 'root:root' ownership. + +Jakub Hrozek promised to enhance SSSD keytab permissions check so that +both sssd:sssd and root:root ownership is possible and then when SSSD +switches to 'sssd' user, the former becomes the default. Since right now +SSSD 1.13 is capable to run as 'sssd' user but doesn't create 'sssd' +user in Fedora 22 / RHEL 7 environments, we can use its presence as a +version trigger. + +https://fedorahosted.org/freeipa/ticket/5136 + +Reviewed-By: Tomas Babej +--- + install/oddjob/com.redhat.idm.trust-fetch-domains | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains +index 85e3cc993b28f983f7e7ae068d9f9f135bab876e..e50c81e50e73b258bf08737c2d9a13a8832eb69f 100755 +--- a/install/oddjob/com.redhat.idm.trust-fetch-domains ++++ b/install/oddjob/com.redhat.idm.trust-fetch-domains +@@ -45,8 +45,13 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): + env={'KRB5CCNAME': ccache_name, 'LANG': 'C'}, + raiseonerr=False) + # Make sure SSSD is able to read the keytab +- sssd = pwd.getpwnam('sssd') +- os.chown(oneway_keytab_name, sssd[2], sssd[3]) ++ try: ++ sssd = pwd.getpwnam('sssd') ++ os.chown(oneway_keytab_name, sssd[2], sssd[3]) ++ except KeyError as e: ++ # If user 'sssd' does not exist, we don't need to chown from root to sssd ++ # because it means SSSD does not run as sssd user ++ pass + + + def parse_options(): +-- +2.4.3 + diff --git a/SOURCES/0010-Fix-memory-leak-in-ipa-pwd-extop.patch b/SOURCES/0010-Fix-memory-leak-in-ipa-pwd-extop.patch deleted file mode 100644 index a98caa9..0000000 --- a/SOURCES/0010-Fix-memory-leak-in-ipa-pwd-extop.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 8ab479e0fdaa509775255005400b214736c3308c Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 5 Nov 2014 08:53:41 +0000 -Subject: [PATCH] Fix memory leak in ipa-pwd-extop - -Also remove dead code and explicitly mark an ignored return value to prevent -false positives in static code analysis. - -https://fedorahosted.org/freeipa/ticket/4651 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c | 3 +-- - daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c | 2 +- - 2 files changed, 2 insertions(+), 3 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -index ca021cac71da690a498fe3003fae1babb30456c1..f0346a343188930dfc90e19d2e5d38cb30741b90 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -@@ -1393,6 +1393,7 @@ done: - if (rc != LDAP_SUCCESS) { - free(password); - free(svcname); -+ free(enctypes); - *_err_msg = err_msg; - } else { - *_password = password; -@@ -1639,7 +1640,6 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) - krb5_context krbctx = NULL; - krb5_error_code krberr; - struct berval *extop_value = NULL; -- BerElement *ber = NULL; - char *service_name = NULL; - char *svcname; - Slapi_Entry *target_entry = NULL; -@@ -1827,7 +1827,6 @@ free_and_return: - } - free(svals); - } -- if (ber) ber_free(ber, 1); - if (bvp) ber_bvfree(bvp); - - return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -index 2bfcf10a271a497741f08bb519020cd159eb4aeb..cbb4536e7d119f4550e4b523eb02e34d058ae7a1 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -@@ -86,7 +86,7 @@ bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, - } - - /* Decode the optional token DN. */ -- ber_scanf(ber, "a", &token_dn); -+ (void)ber_scanf(ber, "a", &token_dn); - - /* Process the synchronization. */ - success = false; --- -2.1.0 - diff --git a/SOURCES/0010-webui-fix-user-reset-password-dialog.patch b/SOURCES/0010-webui-fix-user-reset-password-dialog.patch new file mode 100644 index 0000000..a94134f --- /dev/null +++ b/SOURCES/0010-webui-fix-user-reset-password-dialog.patch @@ -0,0 +1,61 @@ +From 29bc4045aebbe06c9c4dc6985749b809b12d785e Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 14 Jul 2015 17:55:48 +0200 +Subject: [PATCH] webui: fix user reset password dialog + +Could not open user password dialog. + +regression introduced in ed78dcfa3acde7aeb1f381f49988c6911c5277ee + +https://fedorahosted.org/freeipa/ticket/5131 + +Reviewed-By: Martin Basti +--- + install/ui/src/freeipa/dialogs/password.js | 1 - + install/ui/src/freeipa/user.js | 5 +++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/install/ui/src/freeipa/dialogs/password.js b/install/ui/src/freeipa/dialogs/password.js +index f25f7ac60477b1c85b5a6ede23cd93724a89e642..aa9bf44fc49b890fb5393119335b13c622f48879 100644 +--- a/install/ui/src/freeipa/dialogs/password.js ++++ b/install/ui/src/freeipa/dialogs/password.js +@@ -48,7 +48,6 @@ dialogs.password.default_fields_pre_op = function(spec) { + + spec.title = spec.title || '@i18n:password.reset_password'; + spec.width = spec.width || 400; +- spec.method = spec.method || 'mod'; + spec.success_message = spec.success_message || '@i18n:password.password_change_complete'; + spec.confirm_button_label = spec.confirm_button_label || '@i18n:password.reset_password'; + spec.sections = spec.sections || [ +diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js +index e30311bbf0763d9efbc38fdb19e80e114e7636c9..0e828c16b999ffd58504bc4e53d2748bcd16b042 100644 +--- a/install/ui/src/freeipa/user.js ++++ b/install/ui/src/freeipa/user.js +@@ -29,13 +29,14 @@ define([ + './reg', + './rpc', + './text', ++ './dialog', + './dialogs/password', + './details', + './search', + './association', + './entity', + './certificate'], +- function(builder, IPA, $, phases, reg, rpc, text, password_dialog) { ++ function(builder, IPA, $, phases, reg, rpc, text, dialogs) { + + /** + * User module +@@ -638,7 +639,7 @@ IPA.user.password_dialog_pre_op = function(spec) { + + IPA.user.password_dialog = function(spec) { + +- var that = password_dialog.dialog(spec); ++ var that = dialogs.command_dialog(spec); + + that.is_self_service = function() { + var self_service = that.args[0] === IPA.whoami.uid[0]; +-- +2.4.3 + diff --git a/SOURCES/0011-Fix-memory-leaks-in-ipa-join.patch b/SOURCES/0011-Fix-memory-leaks-in-ipa-join.patch deleted file mode 100644 index 274c2d7..0000000 --- a/SOURCES/0011-Fix-memory-leaks-in-ipa-join.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 211bc475034488f20bfe74fe158bb8b7720fd534 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 5 Nov 2014 08:59:08 +0000 -Subject: [PATCH] Fix memory leaks in ipa-join - -Also remove dead code in ipa-join and add initializer to a variable in -ipa-getkeytab to prevent false positives in static code analysis. - -https://fedorahosted.org/freeipa/ticket/4651 - -Reviewed-By: Alexander Bokovoy ---- - ipa-client/ipa-getkeytab.c | 2 +- - ipa-client/ipa-join.c | 18 ++++++++---------- - 2 files changed, 9 insertions(+), 11 deletions(-) - -diff --git a/ipa-client/ipa-getkeytab.c b/ipa-client/ipa-getkeytab.c -index 7861e4e508ce956a92d80d2e91294215854a2a32..bb43c333dca6560807a120103a1cb535fa87b76a 100644 ---- a/ipa-client/ipa-getkeytab.c -+++ b/ipa-client/ipa-getkeytab.c -@@ -794,7 +794,7 @@ int main(int argc, const char *argv[]) - char *password = NULL; - krb5_context krbctx; - krb5_ccache ccache; -- krb5_principal uprinc; -+ krb5_principal uprinc = NULL; - krb5_principal sprinc; - krb5_error_code krberr; - struct keys_container keys = { 0 }; -diff --git a/ipa-client/ipa-join.c b/ipa-client/ipa-join.c -index df33d3b08cf69a37ae9de76266a071825a95871f..46f64572dcaeb3be61dadf87a07520ad21fb4f47 100644 ---- a/ipa-client/ipa-join.c -+++ b/ipa-client/ipa-join.c -@@ -463,14 +463,12 @@ static int - join_ldap(const char *ipaserver, char *hostname, char ** binddn, const char *bindpw, const char *basedn, const char **princ, const char **subject, int quiet) - { - LDAP *ld; -- char *filter = NULL; - int rval = 0; - char *oidresult = NULL; - struct berval valrequest; - struct berval *valresult = NULL; - int rc, ret; - char *ldap_base = NULL; -- char *search_base = NULL; - - *binddn = NULL; - *princ = NULL; -@@ -542,16 +540,12 @@ join_ldap(const char *ipaserver, char *hostname, char ** binddn, const char *bin - *princ = strdup(valresult->bv_val); - - ldap_done: -- -- free(filter); -- free(search_base); -- free(ldap_base); -- - if (ld != NULL) { - ldap_unbind_ext(ld, NULL, NULL); - } - - done: -+ free(ldap_base); - if (valresult) ber_bvfree(valresult); - if (oidresult) free(oidresult); - return rval; -@@ -815,7 +809,8 @@ unenroll_host(const char *server, const char *hostname, const char *ktname, int - if (!quiet) - fprintf(stderr, _("Error parsing \"%1$s\": %2$s.\n"), - principal, error_message(krberr)); -- return krberr; -+ rval = 4; -+ goto cleanup; - } - strcpy(tgs, KRB5_TGS_NAME); - snprintf(tgs + strlen(tgs), sizeof(tgs) - strlen(tgs), "/%.*s", -@@ -833,7 +828,8 @@ unenroll_host(const char *server, const char *hostname, const char *ktname, int - if (!quiet) - fprintf(stderr, _("Error obtaining initial credentials: %s.\n"), - error_message(krberr)); -- return krberr; -+ rval = 19; -+ goto cleanup; - } - - krberr = krb5_cc_resolve(krbctx, "MEMORY:ipa-join", &ccache); -@@ -852,7 +848,8 @@ unenroll_host(const char *server, const char *hostname, const char *ktname, int - fprintf(stderr, - _("Error storing creds in credential cache: %s.\n"), - error_message(krberr)); -- return krberr; -+ rval = 19; -+ goto cleanup; - } - krb5_cc_close(krbctx, ccache); - ccache = NULL; -@@ -914,6 +911,7 @@ cleanup: - - free(user_agent); - if (keytab) krb5_kt_close(krbctx, keytab); -+ free(host); - free((char *)principal); - free((char *)ipaserver); - if (princ) krb5_free_principal(krbctx, princ); --- -2.1.0 - diff --git a/SOURCES/0011-fix-hbac-rule-search-for-non-admin-users.patch b/SOURCES/0011-fix-hbac-rule-search-for-non-admin-users.patch new file mode 100644 index 0000000..a71a9ae --- /dev/null +++ b/SOURCES/0011-fix-hbac-rule-search-for-non-admin-users.patch @@ -0,0 +1,35 @@ +From f8a4727b7e77e377e4c63c0ebd98a67f4f84bdb4 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 14 Jul 2015 18:04:33 +0200 +Subject: [PATCH] fix hbac rule search for non-admin users + +hbacrule has it default attributes (which are used in search) attribute +'memberhostgroup'. This attr is not in ACI nor in schema. If the search +contains an attribute which can't be read then the search won't return +anything. + +Therefore all searches with filter set fail. + +https://fedorahosted.org/freeipa/ticket/5130 + +Reviewed-By: Martin Basti +--- + ipalib/plugins/hbacrule.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py +index 34bdc9bdfe03f01662851bd5aea9daf9e28823d0..82a52bd80f58ede43249264db69acd193233448d 100644 +--- a/ipalib/plugins/hbacrule.py ++++ b/ipalib/plugins/hbacrule.py +@@ -124,7 +124,7 @@ class hbacrule(LDAPObject): + 'description', 'usercategory', 'hostcategory', + 'servicecategory', 'ipaenabledflag', + 'memberuser', 'sourcehost', 'memberhost', 'memberservice', +- 'memberhostgroup', 'externalhost', ++ 'externalhost', + ] + uuid_attribute = 'ipauniqueid' + rdn_attribute = 'ipauniqueid' +-- +2.4.3 + diff --git a/SOURCES/0012-Fix-various-bugs-in-ipap11helper.patch b/SOURCES/0012-Fix-various-bugs-in-ipap11helper.patch deleted file mode 100644 index 5e570e3..0000000 --- a/SOURCES/0012-Fix-various-bugs-in-ipap11helper.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 39b02dae37106eba8e3204048ca5dc3c9040c11f Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 5 Nov 2014 08:59:57 +0000 -Subject: [PATCH] Fix various bugs in ipap11helper - -Fixes a memory leak, a library handle leak and a double free. - -Also remove some redundant NULL checks before free to prevent false positives -in static code analysis. - -https://fedorahosted.org/freeipa/ticket/4651 - -Reviewed-By: Alexander Bokovoy ---- - ipapython/ipap11helper/p11helper.c | 25 ++++++++++--------------- - 1 file changed, 10 insertions(+), 15 deletions(-) - -diff --git a/ipapython/ipap11helper/p11helper.c b/ipapython/ipap11helper/p11helper.c -index df5302a7f867a38596d8fbb3001a8796659fb706..038c26c4520cc8f71edbee15b0ccd9bf292d7588 100644 ---- a/ipapython/ipap11helper/p11helper.c -+++ b/ipapython/ipap11helper/p11helper.c -@@ -334,8 +334,7 @@ int _find_key(P11_Helper* self, CK_ATTRIBUTE_PTR template, - if (tmp_objects_ptr == NULL) { - *objects_count = 0; - PyErr_SetString(ipap11helperError, "_find_key realloc failed"); -- if (result_objects != NULL) -- free(result_objects); -+ free(result_objects); - return 0; - } else { - result_objects = tmp_objects_ptr; -@@ -346,16 +345,14 @@ int _find_key(P11_Helper* self, CK_ATTRIBUTE_PTR template, - rv = self->p11->C_FindObjects(self->session, &result_object, 1, - &objectCount); - if (!check_return_value(rv, "Check for duplicated key")) { -- if (result_objects != NULL) -- free(result_objects); -+ free(result_objects); - return 0; - } - } - - rv = self->p11->C_FindObjectsFinal(self->session); - if (!check_return_value(rv, "Find objects final")) { -- if (result_objects != NULL) -- free(result_objects); -+ free(result_objects); - return 0; - } - -@@ -499,6 +496,8 @@ static int P11_Helper_init(P11_Helper *self, PyObject *args, PyObject *kwds) { - CK_C_GetFunctionList pGetFunctionList = loadLibrary(library_path, - &module_handle); - if (!pGetFunctionList) { -+ if (module_handle != NULL) -+ unloadLibrary(module_handle); - PyErr_SetString(ipap11helperError, "Could not load the library."); - return -1; - } -@@ -933,9 +932,7 @@ P11_Helper_find_keys(P11_Helper* self, PyObject *args, PyObject *kwds) { - if (result_list == NULL) { - PyErr_SetString(ipap11helperError, - "Unable to create list with results"); -- if (objects != NULL) { -- free(objects); -- } -+ free(objects); - return NULL; - } - Py_INCREF(result_list); -@@ -944,13 +941,12 @@ P11_Helper_find_keys(P11_Helper* self, PyObject *args, PyObject *kwds) { - == -1) { - PyErr_SetString(ipap11helperError, - "Unable to add to value to result list"); -- if (objects != NULL) { -- free(objects); -- } -+ free(objects); - return NULL; - } - } - -+ free(objects); - return result_list; - } - -@@ -1193,7 +1189,6 @@ P11_Helper_import_RSA_public_key(P11_Helper* self, CK_UTF8CHAR *label, - if (rsa == NULL) { - PyErr_SetString(ipap11helperError, - "import_RSA_public_key: EVP_PKEY_get1_RSA error"); -- free(pkey); - return NULL; - } - -@@ -1379,8 +1374,8 @@ P11_Helper_export_wrapped_key(P11_Helper* self, PyObject *args, PyObject *kwds) - wrapped_key = malloc(wrapped_key_len); - if (wrapped_key == NULL) { - rv = CKR_HOST_MEMORY; -- check_return_value(rv, "key wrapping: buffer allocation"); -- return 0; -+ if (!check_return_value(rv, "key wrapping: buffer allocation")) -+ return 0; - } - rv = self->p11->C_WrapKey(self->session, &wrapping_mech, - object_wrapping_key, object_key, wrapped_key, &wrapped_key_len); --- -2.1.0 - diff --git a/SOURCES/0012-fix-selinuxusermap-search-for-non-admin-users.patch b/SOURCES/0012-fix-selinuxusermap-search-for-non-admin-users.patch new file mode 100644 index 0000000..e108873 --- /dev/null +++ b/SOURCES/0012-fix-selinuxusermap-search-for-non-admin-users.patch @@ -0,0 +1,30 @@ +From d234274f7e99a7eeff89e4039cf176a4b15147ec Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 16 Jul 2015 15:07:05 +0200 +Subject: [PATCH] fix selinuxusermap search for non-admin users + +Remove nonexistent attribute 'hostmembergroup' that is not in ACI nor schema. + +Related to https://fedorahosted.org/freeipa/ticket/5130 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/selinuxusermap.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/selinuxusermap.py b/ipalib/plugins/selinuxusermap.py +index 76668b4692d4374fd09a83d6c28cb6cb2b20c958..e1a16af5004a5f4fd01166230ddd586068b6b556 100644 +--- a/ipalib/plugins/selinuxusermap.py ++++ b/ipalib/plugins/selinuxusermap.py +@@ -143,7 +143,7 @@ class selinuxusermap(LDAPObject): + 'cn', 'ipaenabledflag', + 'description', 'usercategory', 'hostcategory', + 'ipaenabledflag', 'memberuser', 'memberhost', +- 'memberhostgroup', 'seealso', 'ipaselinuxuser', ++ 'seealso', 'ipaselinuxuser', + ] + uuid_attribute = 'ipauniqueid' + rdn_attribute = 'ipauniqueid' +-- +2.4.3 + diff --git a/SOURCES/0013-Deadlock-in-schema-compat-plugin-between-automember_.patch b/SOURCES/0013-Deadlock-in-schema-compat-plugin-between-automember_.patch deleted file mode 100644 index 63ccb08..0000000 --- a/SOURCES/0013-Deadlock-in-schema-compat-plugin-between-automember_.patch +++ /dev/null @@ -1,83 +0,0 @@ -From f91b6dd2ac7ee2d3444929e0d8649c9f355bdcd2 Mon Sep 17 00:00:00 2001 -From: "Thierry bordaz (tbordaz)" -Date: Wed, 29 Oct 2014 16:23:03 +0100 -Subject: [PATCH] Deadlock in schema compat plugin (between - automember_update_membership task and dse update) - - Defining schema-compat-ignore-subtree values for schema compat plugin config entries removes the - default value (ignore: cn=tasks,cn=config). This default value prevented deadlocks. - Schema plugin needs to scope the $SUFFIX and also any updates to its configuration. - This change restrict the schema compat to those subtrees. It replaces the definition of ignored subtrees - that would be too long for cn=config (tasks, mapping tree, replication, snmp..) - -https://fedorahosted.org/freeipa/ticket/4635 - -Reviewed-By: Martin Basti -Reviewed-By: Alexander Bokovoy ---- - install/updates/10-schema_compat.update | 30 ++++++++++++++++++++---------- - 1 file changed, 20 insertions(+), 10 deletions(-) - -diff --git a/install/updates/10-schema_compat.update b/install/updates/10-schema_compat.update -index 7b75ba532612bbdaf9c85f8c88b0c8b8454e5969..b8c79012d121116f9cf53908fbe4eeeebe9d3d82 100644 ---- a/install/updates/10-schema_compat.update -+++ b/install/updates/10-schema_compat.update -@@ -18,15 +18,19 @@ add: schema-compat-entry-attribute: 'sudoRunAsUser=%ifeq("ipaSudoRunAsUserCatego - add: schema-compat-entry-attribute: 'sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%deref_f(\"ipaSudoRunAs\",\"(objectclass=posixAccount)\",\"uid\")")' - add: schema-compat-entry-attribute: 'sudoRunAsGroup=%ifeq("ipaSudoRunAsGroupCategory","all","ALL","%{ipaSudoRunAsExtGroup}")' - add: schema-compat-entry-attribute: 'sudoRunAsGroup=%ifeq("ipaSudoRunAsGroupCategory","all","ALL","%deref_f(\"ipaSudoRunAsGroup\",\"(objectclass=posixGroup)\",\"cn\")")' --add: schema-compat-ignore-subtree: cn=changelog --add: schema-compat-ignore-subtree: o=ipaca -+remove: schema-compat-ignore-subtree: cn=changelog -+remove: schema-compat-ignore-subtree: o=ipaca -+add: schema-compat-restrict-subtree: '$SUFFIX' -+add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' - - # Change padding for host and userCategory so the pad returns the same value - # as the original, '' or -. - dn: cn=ng,cn=Schema Compatibility,cn=plugins,cn=config - replace: schema-compat-entry-attribute:'nisNetgroupTriple=(%link("%ifeq(\"hostCategory\",\"all\",\"\",\"%collect(\\\"%{externalHost}\\\",\\\"%deref(\\\\\\\"memberHost\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberHost\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\")\")","-",",","%ifeq(\"userCategory\",\"all\",\"\",\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\")","-"),%{nisDomainName:-})::nisNetgroupTriple=(%link("%ifeq(\"hostCategory\",\"all\",\"\",\"%collect(\\\"%{externalHost}\\\",\\\"%deref(\\\\\\\"memberHost\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberHost\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\")\")","%ifeq(\"hostCategory\",\"all\",\"\",\"-\")",",","%ifeq(\"userCategory\",\"all\",\"\",\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\")","%ifeq(\"userCategory\",\"all\",\"\",\"-\")"),%{nisDomainName:-})' --add: schema-compat-ignore-subtree: cn=changelog --add: schema-compat-ignore-subtree: o=ipaca -+remove: schema-compat-ignore-subtree: cn=changelog -+remove: schema-compat-ignore-subtree: o=ipaca -+add: schema-compat-restrict-subtree: '$SUFFIX' -+add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' - - dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config - default:objectClass: top -@@ -41,19 +45,25 @@ default:schema-compat-entry-attribute: objectclass=device - default:schema-compat-entry-attribute: objectclass=ieee802Device - default:schema-compat-entry-attribute: cn=%{fqdn} - default:schema-compat-entry-attribute: macAddress=%{macAddress} --add: schema-compat-ignore-subtree: cn=changelog --add: schema-compat-ignore-subtree: o=ipaca -+remove: schema-compat-ignore-subtree: cn=changelog -+remove: schema-compat-ignore-subtree: o=ipaca -+add: schema-compat-restrict-subtree: '$SUFFIX' -+add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' - - dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config - add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} - - dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config --add: schema-compat-ignore-subtree: cn=changelog --add: schema-compat-ignore-subtree: o=ipaca -+remove: schema-compat-ignore-subtree: cn=changelog -+remove: schema-compat-ignore-subtree: o=ipaca -+add: schema-compat-restrict-subtree: '$SUFFIX' -+add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' - - dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config --add: schema-compat-ignore-subtree: cn=changelog --add: schema-compat-ignore-subtree: o=ipaca -+remove: schema-compat-ignore-subtree: cn=changelog -+remove: schema-compat-ignore-subtree: o=ipaca -+add: schema-compat-restrict-subtree: '$SUFFIX' -+add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' - - dn: cn=Schema Compatibility,cn=plugins,cn=config - # We need to run schema-compat pre-bind callback before --- -2.1.0 - diff --git a/SOURCES/0013-Validate-adding-privilege-to-a-permission.patch b/SOURCES/0013-Validate-adding-privilege-to-a-permission.patch new file mode 100644 index 0000000..69f0992 --- /dev/null +++ b/SOURCES/0013-Validate-adding-privilege-to-a-permission.patch @@ -0,0 +1,113 @@ +From 8ad2b5d6b81986235d0da6aa9349cfefaec06fcb Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 9 Jul 2015 16:48:36 +0200 +Subject: [PATCH] Validate adding privilege to a permission + +Adding priviledge to a permission via webUI allowed to avoid check and to add permission +with improper type. + +https://fedorahosted.org/freeipa/ticket/5075 + +Reviewed-By: Jan Cholasta +--- + ipalib/plugins/permission.py | 7 ++++++ + ipalib/plugins/privilege.py | 51 ++++++++++++++++++++++---------------------- + 2 files changed, 33 insertions(+), 25 deletions(-) + +diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py +index f2e896935cc777801ec3a70262372f296b1ea2b8..7d2a4dd156693d9d9b7d6f042488856274fb3f64 100644 +--- a/ipalib/plugins/permission.py ++++ b/ipalib/plugins/permission.py +@@ -21,6 +21,7 @@ import re + import traceback + + from ipalib.plugins import baseldap ++from ipalib.plugins.privilege import validate_permission_to_privilege + from ipalib import errors + from ipalib.parameters import Str, StrEnum, DNParam, Flag + from ipalib import api, _, ngettext +@@ -1377,6 +1378,12 @@ class permission_add_member(baseldap.LDAPAddMember): + """Add members to a permission.""" + NO_CLI = True + ++ def pre_callback(self, ldap, dn, member_dns, failed, *keys, **options): ++ # We can only add permissions with bind rule type set to ++ # "permission" (or old-style permissions) ++ validate_permission_to_privilege(self.api, keys[-1]) ++ return dn ++ + + @register() + class permission_remove_member(baseldap.LDAPRemoveMember): +diff --git a/ipalib/plugins/privilege.py b/ipalib/plugins/privilege.py +index 867544359f76fdcb44cd3015f7466a46ba492bec..ffb903e03dbfaafbe2bb7135038494ae49a7d8a8 100644 +--- a/ipalib/plugins/privilege.py ++++ b/ipalib/plugins/privilege.py +@@ -45,6 +45,31 @@ See role and permission for additional information. + register = Registry() + + ++def validate_permission_to_privilege(api, permission): ++ ldap = api.Backend.ldap2 ++ ldapfilter = ldap.combine_filters(rules='&', filters=[ ++ '(objectClass=ipaPermissionV2)', '(!(ipaPermBindRuleType=permission))', ++ ldap.make_filter_from_attr('cn', permission, rules='|')]) ++ try: ++ entries, truncated = ldap.find_entries( ++ filter=ldapfilter, ++ attrs_list=['cn', 'ipapermbindruletype'], ++ base_dn=DN(api.env.container_permission, api.env.basedn), ++ size_limit=1) ++ except errors.NotFound: ++ pass ++ else: ++ entry = entries[0] ++ message = _('cannot add permission "%(perm)s" with bindtype ' ++ '"%(bindtype)s" to a privilege') ++ raise errors.ValidationError( ++ name='permission', ++ error=message % { ++ 'perm': entry.single_value['cn'], ++ 'bindtype': entry.single_value.get( ++ 'ipapermbindruletype', 'permission')}) ++ ++ + @register() + class privilege(LDAPObject): + """ +@@ -185,31 +210,7 @@ class privilege_add_permission(LDAPAddReverseMember): + if options.get('permission'): + # We can only add permissions with bind rule type set to + # "permission" (or old-style permissions) +- ldapfilter = ldap.combine_filters(rules='&', filters=[ +- '(objectClass=ipaPermissionV2)', +- '(!(ipaPermBindRuleType=permission))', +- ldap.make_filter_from_attr('cn', options['permission'], +- rules='|'), +- ]) +- try: +- entries, truncated = ldap.find_entries( +- filter=ldapfilter, +- attrs_list=['cn', 'ipapermbindruletype'], +- base_dn=DN(self.api.env.container_permission, +- self.api.env.basedn), +- size_limit=1) +- except errors.NotFound: +- pass +- else: +- entry = entries[0] +- message = _('cannot add permission "%(perm)s" with bindtype ' +- '"%(bindtype)s" to a privilege') +- raise errors.ValidationError( +- name='permission', +- error=message % { +- 'perm': entry.single_value['cn'], +- 'bindtype': entry.single_value.get( +- 'ipapermbindruletype', 'permission')}) ++ validate_permission_to_privilege(self.api, options['permission']) + return dn + + +-- +2.4.3 + diff --git a/SOURCES/0014-Stop-dirsrv-last-in-ipactl-stop.patch b/SOURCES/0014-Stop-dirsrv-last-in-ipactl-stop.patch deleted file mode 100644 index b6b9e1f..0000000 --- a/SOURCES/0014-Stop-dirsrv-last-in-ipactl-stop.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 788b0ac5d9ae805f46321d50531ed5baf80eee1e Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 4 Nov 2014 03:22:59 -0500 -Subject: [PATCH] Stop dirsrv last in ipactl stop. - -Other services may depend on directory server. - -https://fedorahosted.org/freeipa/ticket/4632 - -Reviewed-By: Jan Cholasta ---- - install/tools/ipactl | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/install/tools/ipactl b/install/tools/ipactl -index 7a1e41b01a80eeea85c417399dcf4666f70d4b26..b1b0b6e26fa97cdc953c86eee22e160782b57379 100755 ---- a/install/tools/ipactl -+++ b/install/tools/ipactl -@@ -291,12 +291,6 @@ def ipa_stop(options): - finally: - raise IpactlError() - -- try: -- print "Stopping Directory Service" -- dirsrv.stop(capture_output=False) -- except: -- raise IpactlError("Failed to stop Directory Service") -- - for svc in reversed(svc_list): - svchandle = services.service(svc) - try: -@@ -305,6 +299,12 @@ def ipa_stop(options): - except: - emit_err("Failed to stop %s Service" % svc) - -+ try: -+ print "Stopping Directory Service" -+ dirsrv.stop(capture_output=False) -+ except: -+ raise IpactlError("Failed to stop Directory Service") -+ - # remove file with list of started services - try: - os.unlink(paths.SVC_LIST_FILE) --- -2.1.0 - diff --git a/SOURCES/0014-migration-Use-api.env-variables.patch b/SOURCES/0014-migration-Use-api.env-variables.patch new file mode 100644 index 0000000..420edaa --- /dev/null +++ b/SOURCES/0014-migration-Use-api.env-variables.patch @@ -0,0 +1,85 @@ +From c626fcb564404d41cd06db83a299e97959fa3c4e Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Thu, 16 Jul 2015 10:15:36 +0200 +Subject: [PATCH] migration: Use api.env variables. + +Use api.env.basedn instead of anonymously accessing LDAP to get base DN. +Use api.env.basedn instead of searching filesystem for ldapi socket. + +https://fedorahosted.org/freeipa/ticket/4953 + +Reviewed-By: Jan Cholasta +Reviewed-By: Petr Vobornik +Reviewed-By: Alexander Bokovoy +--- + install/migration/migration.py | 33 +++++---------------------------- + 1 file changed, 5 insertions(+), 28 deletions(-) + +diff --git a/install/migration/migration.py b/install/migration/migration.py +index b629b1c9ff7bd58f1ea64e4c2b2433428a939f28..8c440175a0358b01acba227ea3179318af50fa32 100644 +--- a/install/migration/migration.py ++++ b/install/migration/migration.py +@@ -22,14 +22,13 @@ Password migration script + + import cgi + import errno +-import glob + from wsgiref.util import request_uri + + from ipapython.ipa_log_manager import root_logger + from ipapython.ipautil import get_ipa_basedn + from ipapython.dn import DN + from ipapython.ipaldap import IPAdmin +-from ipalib import errors ++from ipalib import errors, create_api + from ipaplatform.paths import paths + + +@@ -45,23 +44,6 @@ def get_ui_url(environ): + return full_url[:index] + "/ipa/ui" + + +-def get_base_dn(ldap_uri): +- """ +- Retrieve LDAP server base DN. +- """ +- try: +- conn = IPAdmin(ldap_uri=ldap_uri) +- conn.do_simple_bind(DN(), '') +- base_dn = get_ipa_basedn(conn) +- except Exception, e: +- root_logger.error('migration context search failed: %s' % e) +- return '' +- finally: +- conn.unbind() +- +- return base_dn +- +- + def bind(ldap_uri, base_dn, username, password): + if not base_dn: + root_logger.error('migration unable to get base dn') +@@ -90,16 +72,11 @@ def application(environ, start_response): + if not form_data.has_key('username') or not form_data.has_key('password'): + return wsgi_redirect(start_response, 'invalid.html') + +- slapd_sockets = glob.glob(paths.ALL_SLAPD_INSTANCE_SOCKETS) +- if slapd_sockets: +- ldap_uri = 'ldapi://%s' % slapd_sockets[0].replace('/', '%2f') +- else: +- ldap_uri = 'ldaps://localhost:636' +- +- base_dn = get_base_dn(ldap_uri) +- ++ # API object only for configuration, finalize() not needed ++ api = create_api(mode=None) ++ api.bootstrap(context='server', in_server=True) + try: +- bind(ldap_uri, base_dn, ++ bind(api.env.ldap_uri, api.env.basedn, + form_data['username'].value, form_data['password'].value) + except IOError as err: + if err.errno == errno.EPERM: +-- +2.4.3 + diff --git a/SOURCES/0015-Fix-upgrade-do-not-use-invalid-ldap-connection.patch b/SOURCES/0015-Fix-upgrade-do-not-use-invalid-ldap-connection.patch deleted file mode 100644 index 334f889..0000000 --- a/SOURCES/0015-Fix-upgrade-do-not-use-invalid-ldap-connection.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 925904b8724c50b6336c0cd17f5dbb2eb85be8a4 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Tue, 4 Nov 2014 15:59:50 +0100 -Subject: [PATCH] Fix upgrade: do not use invalid ldap connection - -Ticket: https://fedorahosted.org/freeipa/ticket/4670 -Reviewed-By: Jan Cholasta ---- - ipaserver/install/ldapupdate.py | 6 ++++++ - ipaserver/install/plugins/updateclient.py | 3 +++ - 2 files changed, 9 insertions(+) - -diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py -index 6bed046d2661f48218b66c11e6f6a43c6dc0f6bf..47f0399b928b3b0da3954592d56750450454aac7 100644 ---- a/ipaserver/install/ldapupdate.py -+++ b/ipaserver/install/ldapupdate.py -@@ -889,3 +889,9 @@ class LDAPUpdate: - self._run_updates(updates) - - return self.modified -+ -+ def close_connection(self): -+ """Close ldap connection""" -+ if self.conn: -+ self.conn.unbind() -+ self.conn = None -diff --git a/ipaserver/install/plugins/updateclient.py b/ipaserver/install/plugins/updateclient.py -index 7566b6cd807dafc3af5e7b51a1dfa68847ca91c2..8f5c5b5fdbc2b7bfec8be342ee267425c93b47cf 100644 ---- a/ipaserver/install/plugins/updateclient.py -+++ b/ipaserver/install/plugins/updateclient.py -@@ -122,6 +122,9 @@ class updateclient(backend.Executioner): - for update in self.order(updatetype): - (restart, apply_now, res) = self.run(update.name, **kw) - if restart: -+ # connection has to be closed before restart, otherwise -+ # ld instance will try to reuse old non-valid connection -+ ld.close_connection() - self.restart(dm_password, live_run) - - if apply_now: --- -2.1.0 - diff --git a/SOURCES/0015-sysrestore-copy-files-instead-of-moving-them-to-avoi.patch b/SOURCES/0015-sysrestore-copy-files-instead-of-moving-them-to-avoi.patch new file mode 100644 index 0000000..330d314 --- /dev/null +++ b/SOURCES/0015-sysrestore-copy-files-instead-of-moving-them-to-avoi.patch @@ -0,0 +1,44 @@ +From 630a9b60995e2d6eb02281a3dd176f0252f632db Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 15 Jul 2015 16:20:59 +0200 +Subject: [PATCH] sysrestore: copy files instead of moving them to avoind + SELinux issues + +Copying files restores SELinux context. + +https://fedorahosted.org/freeipa/ticket/4923 + +Reviewed-By: Alexander Bokovoy +--- + ipapython/sysrestore.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/ipapython/sysrestore.py b/ipapython/sysrestore.py +index 580df9a4fd6d0fae35602dad1f81d498fa8f0173..1a111258bc0f6dd503673028d3a990821f077fef 100644 +--- a/ipapython/sysrestore.py ++++ b/ipapython/sysrestore.py +@@ -187,7 +187,9 @@ class FileStore: + if new_path is not None: + path = new_path + +- shutil.move(backup_path, path) ++ shutil.copy(backup_path, path) # SELinux needs copy ++ os.remove(backup_path) ++ + os.chown(path, int(uid), int(gid)) + os.chmod(path, int(mode)) + +@@ -218,7 +220,9 @@ class FileStore: + root_logger.debug(" -> Not restoring - '%s' doesn't exist", backup_path) + continue + +- shutil.move(backup_path, path) ++ shutil.copy(backup_path, path) # SELinux needs copy ++ os.remove(backup_path) ++ + os.chown(path, int(uid), int(gid)) + os.chmod(path, int(mode)) + +-- +2.4.3 + diff --git a/SOURCES/0016-Allow-value-no-for-replica-certify-all-attr-in-abort.patch b/SOURCES/0016-Allow-value-no-for-replica-certify-all-attr-in-abort.patch new file mode 100644 index 0000000..f241c55 --- /dev/null +++ b/SOURCES/0016-Allow-value-no-for-replica-certify-all-attr-in-abort.patch @@ -0,0 +1,68 @@ +From c2b5f7b164268ec8d15916031260c87dc6c9ffd5 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 16 Jul 2015 16:26:55 +0200 +Subject: [PATCH] Allow value 'no' for replica-certify-all attr in + abort-clean-ruv subcommand + +--force option set replica-certify-all to 'no' during abort-clean-ruv +subcommand + +https://fedorahosted.org/freeipa/ticket/4988 + +Reviewed-By: Petr Vobornik +--- + install/tools/ipa-replica-manage | 2 +- + install/tools/man/ipa-replica-manage.1 | 2 +- + ipaserver/install/replication.py | 3 ++- + 3 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage +index e525a02f4c60350b7a943abab4b4aedd957e984a..50a57f70ec452c0df5bf2ea55d2a136e8149aa41 100755 +--- a/install/tools/ipa-replica-manage ++++ b/install/tools/ipa-replica-manage +@@ -470,7 +470,7 @@ def abort_clean_ruv(realm, ruv, options): + print + thisrepl = replication.ReplicationManager(realm, options.host, + options.dirman_passwd) +- thisrepl.abortcleanallruv(ruv) ++ thisrepl.abortcleanallruv(ruv, options.force) + + print "Cleanup task stopped" + +diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1 +index 8a7c78f39eeb6c7902ed99e7bed37e32eb0e92dc..c09ed362f3143e6e38716e1b3a96e90001a64674 100644 +--- a/install/tools/man/ipa-replica-manage.1 ++++ b/install/tools/man/ipa-replica-manage.1 +@@ -49,7 +49,7 @@ Manages the replication agreements of an IPA server. The available commands are: + \- Run the CLEANALLRUV task to remove a replication ID. + .TP + \fBabort\-clean\-ruv\fR [REPLICATION_ID] +-\- Abort a running CLEANALLRUV task. ++\- Abort a running CLEANALLRUV task. With \-\-force option the task does not wait for all the replica servers to have been sent the abort task, or be online, before completing. + .TP + \fBlist\-clean\-ruv\fR + \- List all running CLEANALLRUV and abort CLEANALLRUV tasks. +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index 0f420106e093e8a7a277016857d27aaa48daa4dc..e9af88dc4356d4fd5495f4fea399ab09c75db953 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -1451,7 +1451,7 @@ class ReplicationManager(object): + + wait_for_task(self.conn, dn) + +- def abortcleanallruv(self, replicaId): ++ def abortcleanallruv(self, replicaId, force=False): + """ + Create a task to abort a CLEANALLRUV operation. + """ +@@ -1465,6 +1465,7 @@ class ReplicationManager(object): + 'replica-id': [replicaId], + 'objectclass': ['top', 'extensibleObject'], + 'cn': ['abort %d' % replicaId], ++ 'replica-certify-all': ['no'] if force else ['yes'], + } + ) + try: +-- +2.4.3 + diff --git a/SOURCES/0016-Ensure-that-a-password-exists-after-OTP-validation.patch b/SOURCES/0016-Ensure-that-a-password-exists-after-OTP-validation.patch deleted file mode 100644 index f74ac1e..0000000 --- a/SOURCES/0016-Ensure-that-a-password-exists-after-OTP-validation.patch +++ /dev/null @@ -1,73 +0,0 @@ -From a4505caea4e4905e1756f31779c315de979f8f2c Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Wed, 5 Nov 2014 13:50:41 -0500 -Subject: [PATCH] Ensure that a password exists after OTP validation - -Before this patch users could log in using only the OTP value. This -arose because ipapwd_authentication() successfully determined that -an empty password was invalid, but 389 itself would see this as an -anonymous bind. An anonymous bind would never even get this far in -this code, so we simply deny requests with empty passwords. - -This patch resolves CVE-2014-7828. - -https://fedorahosted.org/freeipa/ticket/4690 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 26 ++++++++++++----------- - 1 file changed, 14 insertions(+), 12 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -index 60ceaaa7ab0cd282efb45f1a89de9dbd240a452c..1f595d01d986ca2950672d796d62f5f78b05c212 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -@@ -1446,12 +1446,12 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) - - /* Try to do OTP first. */ - syncreq = sync_request_present(pb); -- if (!syncreq && !ipapwd_pre_bind_otp(dn, entry, credentials)) { -- slapi_entry_free(entry); -- slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, -- NULL, NULL, 0, NULL); -- return 1; -- } -+ if (!syncreq && !ipapwd_pre_bind_otp(dn, entry, credentials)) -+ goto invalid_creds; -+ -+ /* Ensure that there is a password. */ -+ if (credentials->bv_len == 0) -+ goto invalid_creds; - - /* Authenticate the user. */ - ret = ipapwd_authenticate(dn, entry, credentials); -@@ -1461,18 +1461,20 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) - } - - /* Attempt to handle a token synchronization request. */ -- if (syncreq && !sync_request_handle(ipapwd_get_plugin_id(), pb, dn)) { -- slapi_entry_free(entry); -- slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, -- NULL, NULL, 0, NULL); -- return 1; -- } -+ if (syncreq && !sync_request_handle(ipapwd_get_plugin_id(), pb, dn)) -+ goto invalid_creds; - - /* Attempt to write out kerberos keys for the user. */ - ipapwd_write_krb_keys(pb, dn, entry, credentials); - - slapi_entry_free(entry); - return 0; -+ -+invalid_creds: -+ slapi_entry_free(entry); -+ slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, -+ NULL, NULL, 0, NULL); -+ return 1; - } - - /* Init pre ops */ --- -2.1.0 - diff --git a/SOURCES/0017-ipa-restore-Don-t-crash-if-AD-trust-is-not-installed.patch b/SOURCES/0017-ipa-restore-Don-t-crash-if-AD-trust-is-not-installed.patch deleted file mode 100644 index 022c014..0000000 --- a/SOURCES/0017-ipa-restore-Don-t-crash-if-AD-trust-is-not-installed.patch +++ /dev/null @@ -1,53 +0,0 @@ -From d693ffd819a2016c6cc871107d5f66353c999888 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 10 Nov 2014 13:29:58 +0100 -Subject: [PATCH] ipa-restore: Don't crash if AD trust is not installed - -https://fedorahosted.org/freeipa/ticket/4668 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/ipa_restore.py | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 239de99c462639854e8e25c6b9278cb94b6fc6b8..352a1ca2bf283c0beb8c95925c6eb9c9984b3338 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -37,7 +37,6 @@ from ipaserver.install.replication import (wait_for_task, ReplicationManager, - get_cs_replication_manager) - from ipaserver.install import installutils - from ipaserver.install import httpinstance --from ipaserver.install import adtrustinstance - from ipapython import ipaldap - import ipapython.errors - from ipaplatform.tasks import tasks -@@ -45,6 +44,11 @@ from ipaserver.install.ipa_backup import BACKUP_DIR - from ipaplatform import services - from ipaplatform.paths import paths - -+try: -+ from ipaserver.install import adtrustinstance -+except ImportError: -+ adtrustinstance = None -+ - - def recursive_chown(path, uid, gid): - ''' -@@ -646,7 +650,12 @@ class Restore(admintool.AdminTool): - def restore_selinux_booleans(self): - bools = dict(httpinstance.SELINUX_BOOLEAN_SETTINGS) - if 'ADTRUST' in self.backup_services: -- bools.update(adtrustinstance.SELINUX_BOOLEAN_SETTINGS) -+ if adtrustinstance: -+ bools.update(adtrustinstance.SELINUX_BOOLEAN_SETTINGS) -+ else: -+ self.log.error( -+ 'The AD trust package was not found, ' -+ 'not setting SELinux booleans.') - try: - tasks.set_selinux_booleans(bools) - except ipapython.errors.SetseboolError as e: --- -2.1.0 - diff --git a/SOURCES/0017-trusts-Check-for-AD-root-domain-among-our-trusted-do.patch b/SOURCES/0017-trusts-Check-for-AD-root-domain-among-our-trusted-do.patch new file mode 100644 index 0000000..b0593e2 --- /dev/null +++ b/SOURCES/0017-trusts-Check-for-AD-root-domain-among-our-trusted-do.patch @@ -0,0 +1,68 @@ +From eb8651626099df8df14e12b905aace0be5c37ded Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 15 Jul 2015 14:22:48 +0200 +Subject: [PATCH] trusts: Check for AD root domain among our trusted domains + +Check for the presence of the forest root DNS domain of the AD realm +among the IPA realm domains prior to esablishing the trust. + +This prevents creation of a failing setup, as trusts would not work +properly in this case. + +https://fedorahosted.org/freeipa/ticket/4799 + +Reviewed-By: Petr Vobornik +Reviewed-By: Alexander Bokovoy +--- + ipalib/plugins/trust.py | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py +index 196df5926e7965dc1f0165f301bd5ac11528d1cd..6232e4fe9d3d5e957d22a3557cdcf4bb12cec0ea 100644 +--- a/ipalib/plugins/trust.py ++++ b/ipalib/plugins/trust.py +@@ -640,6 +640,8 @@ sides. + self.params['realm_passwd'].label, confirm=False) + + def validate_options(self, *keys, **options): ++ trusted_realm_domain = keys[-1] ++ + if not _bindings_installed: + raise errors.NotFound( + name=_('AD Trust setup'), +@@ -692,6 +694,23 @@ sides. + ) + ) + ++ # Obtain a list of IPA realm domains ++ result = self.api.Command.realmdomains_show()['result'] ++ realm_domains = result['associateddomain'] ++ ++ # Do not allow the AD's trusted realm domain in the list ++ # of our realm domains ++ if trusted_realm_domain.lower() in realm_domains: ++ raise errors.ValidationError( ++ name=_('AD Trust setup'), ++ error=_( ++ 'Trusted domain %(domain)s is included among ' ++ 'IPA realm domains. It needs to be removed ' ++ 'prior to establishing the trust. See the ' ++ '"ipa realmdomains-mod --del-domain" command.' ++ ) % dict(domain=trusted_realm_domain) ++ ) ++ + self.realm_server = options.get('realm_server') + self.realm_admin = options.get('realm_admin') + self.realm_passwd = options.get('realm_passwd') +@@ -702,7 +721,7 @@ sides. + if len(names) > 1: + # realm admin name is in UPN format, user@realm, check that + # realm is the same as the one that we are attempting to trust +- if keys[-1].lower() != names[-1].lower(): ++ if trusted_realm_domain.lower() != names[-1].lower(): + raise errors.ValidationError( + name=_('AD Trust setup'), + error=_( +-- +2.4.3 + diff --git a/SOURCES/0018-enable-debugging-of-ntpd-during-client-installation.patch b/SOURCES/0018-enable-debugging-of-ntpd-during-client-installation.patch new file mode 100644 index 0000000..5dce4b2 --- /dev/null +++ b/SOURCES/0018-enable-debugging-of-ntpd-during-client-installation.patch @@ -0,0 +1,71 @@ +From 941941733a9a2af27ae4fd73714a87a08931e76a Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Mon, 30 Mar 2015 12:29:04 +0200 +Subject: [PATCH] enable debugging of ntpd during client installation + +When installing IPA client in debug mode, the ntpd command spawned during +initial time-sync with master KDC will also run in debug mode. + +https://fedorahosted.org/freeipa/ticket/4931 + +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +--- + ipa-client/ipa-install/ipa-client-install | 5 +++-- + ipa-client/ipaclient/ntpconf.py | 7 +++++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install +index a1564583ca2d461413da7ea5929b91851cd3f3e1..96b30b486585bc60b0882263cff58292a3538df9 100755 +--- a/ipa-client/ipa-install/ipa-client-install ++++ b/ipa-client/ipa-install/ipa-client-install +@@ -2388,12 +2388,13 @@ def install(options, env, fstore, statestore): + ntp_servers = options.ntp_servers + + for s in ntp_servers: +- synced_ntp = ipaclient.ntpconf.synconce_ntp(s) ++ synced_ntp = ipaclient.ntpconf.synconce_ntp(s, options.debug) + if synced_ntp: + break + + if not synced_ntp and not options.ntp_servers: +- synced_ntp = ipaclient.ntpconf.synconce_ntp(cli_server[0]) ++ synced_ntp = ipaclient.ntpconf.synconce_ntp(cli_server[0], ++ options.debug) + if not synced_ntp: + root_logger.warning("Unable to sync time with NTP " + + "server, assuming the time is in sync. Please check " + +diff --git a/ipa-client/ipaclient/ntpconf.py b/ipa-client/ipaclient/ntpconf.py +index c22fba401d33009b3b95d1418dc7c8a03328d569..9a7db6544b54288569dc7699e67ddc865bb88db4 100644 +--- a/ipa-client/ipaclient/ntpconf.py ++++ b/ipa-client/ipaclient/ntpconf.py +@@ -137,7 +137,7 @@ def config_ntp(ntp_servers, fstore = None, sysstore = None): + services.knownservices.ntpd.restart() + + +-def synconce_ntp(server_fqdn): ++def synconce_ntp(server_fqdn, debug=False): + """ + Syncs time with specified server using ntpd. + Primarily designed to be used before Kerberos setup +@@ -150,13 +150,16 @@ def synconce_ntp(server_fqdn): + return False + + tmp_ntp_conf = ipautil.write_tmp_file('server %s' % server_fqdn) ++ args = [ntpd, '-qgc', tmp_ntp_conf.name] ++ if debug: ++ args.append('-d') + try: + # The ntpd command will never exit if it is unable to reach the + # server, so timeout after 15 seconds. + timeout = 15 + root_logger.info('Attempting to sync time using ntpd. ' + 'Will timeout after %d seconds' % timeout) +- ipautil.run([ntpd, '-qgc', tmp_ntp_conf.name], timeout=timeout) ++ ipautil.run(args, timeout=timeout) + return True + except ipautil.CalledProcessError: + return False +-- +2.4.3 + diff --git a/SOURCES/0018-ranges-prohibit-setting-rid-base-with-ipa-trust-ad-p.patch b/SOURCES/0018-ranges-prohibit-setting-rid-base-with-ipa-trust-ad-p.patch deleted file mode 100644 index c37297e..0000000 --- a/SOURCES/0018-ranges-prohibit-setting-rid-base-with-ipa-trust-ad-p.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 77af6877a855c6dd738d03376464197ac3a938f8 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 13 Oct 2014 14:57:45 +0200 -Subject: [PATCH] ranges: prohibit setting --rid-base with ipa-trust-ad-posix - type - -We should not allow setting --rid-base for ranges of ipa-trust-ad-posix since we do not perform any RID -> UID/GID mappings for these ranges (objects have UID/GID set in AD). Thus, setting RID base makes no sense. - -Since ipaBaseRID is a MUST in ipaTrustedADDomainRange object class, value '0' is allowed and used internally for 'ipa-trust-ad-posix' range type. - -No schema change is done. - -https://fedorahosted.org/freeipa/ticket/4221 - -Reviewed-By: Tomas Babej ---- - ipalib/plugins/idrange.py | 61 ++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 47 insertions(+), 14 deletions(-) - -diff --git a/ipalib/plugins/idrange.py b/ipalib/plugins/idrange.py -index 9e0481e94048c465f9a86112378a47390de0d494..6c3be6e69595127e346969e41703dc98e783282e 100644 ---- a/ipalib/plugins/idrange.py -+++ b/ipalib/plugins/idrange.py -@@ -248,6 +248,12 @@ class idrange(LDAPObject): - if not options.get('all', False) or options.get('pkey_only', False): - entry_attrs.pop('objectclass', None) - -+ def handle_ipabaserid(self, entry_attrs, options): -+ if any((options.get('pkey_only', False), options.get('raw', False))): -+ return -+ if entry_attrs['iparangetype'][0] == u'ipa-ad-trust-posix': -+ entry_attrs.pop('ipabaserid', None) -+ - def check_ids_in_modified_range(self, old_base, old_size, new_base, - new_size): - if new_base is None and new_size is None: -@@ -414,6 +420,7 @@ class idrange_add(LDAPCreate): - - rid_base = kw.get('ipabaserid', None) - secondary_rid_base = kw.get('ipasecondarybaserid', None) -+ range_type = kw.get('iparangetype', None) - - def set_from_prompt(param): - value = self.prompt_param(self.params[param]) -@@ -424,7 +431,7 @@ class idrange_add(LDAPCreate): - # This is a trusted range - - # Prompt for RID base if domain SID / name was given -- if rid_base is None: -+ if rid_base is None and range_type != u'ipa-ad-trust-posix': - set_from_prompt('ipabaserid') - - else: -@@ -486,23 +493,33 @@ class idrange_add(LDAPCreate): - if not is_set('iparangetype'): - entry_attrs['iparangetype'] = u'ipa-ad-trust' - -- if entry_attrs['iparangetype'] not in (u'ipa-ad-trust', -- u'ipa-ad-trust-posix'): -+ if entry_attrs['iparangetype'] == u'ipa-ad-trust': -+ if not is_set('ipabaserid'): -+ raise errors.ValidationError( -+ name='ID Range setup', -+ error=_('Options dom-sid/dom-name and rid-base must ' -+ 'be used together') -+ ) -+ elif entry_attrs['iparangetype'] == u'ipa-ad-trust-posix': -+ if is_set('ipabaserid') and entry_attrs['ipabaserid'] != 0: -+ raise errors.ValidationError( -+ name='ID Range setup', -+ error=_('Option rid-base must not be used when IPA ' -+ 'range type is ipa-ad-trust-posix') -+ ) -+ else: -+ entry_attrs['ipabaserid'] = 0 -+ else: - raise errors.ValidationError(name='ID Range setup', - error=_('IPA Range type must be one of ipa-ad-trust ' - 'or ipa-ad-trust-posix when SID of the trusted ' -- 'domain is specified.')) -+ 'domain is specified')) - - if is_set('ipasecondarybaserid'): - raise errors.ValidationError(name='ID Range setup', - error=_('Options dom-sid/dom-name and secondary-rid-base ' - 'cannot be used together')) - -- if not is_set('ipabaserid'): -- raise errors.ValidationError(name='ID Range setup', -- error=_('Options dom-sid/dom-name and rid-base must ' -- 'be used together')) -- - # Validate SID as the one of trusted domains - self.obj.validate_trusted_domain_sid( - entry_attrs['ipanttrusteddomainsid']) -@@ -557,6 +574,7 @@ class idrange_add(LDAPCreate): - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) -+ self.obj.handle_ipabaserid(entry_attrs, options) - self.obj.handle_iparangetype(entry_attrs, options, - keep_objectclass=True) - return dn -@@ -628,6 +646,7 @@ class idrange_find(LDAPSearch): - - def post_callback(self, ldap, entries, truncated, *args, **options): - for entry in entries: -+ self.obj.handle_ipabaserid(entry, options) - self.obj.handle_iparangetype(entry, options) - return truncated - -@@ -643,6 +662,7 @@ class idrange_show(LDAPRetrieve): - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) -+ self.obj.handle_ipabaserid(entry_attrs, options) - self.obj.handle_iparangetype(entry_attrs, options) - return dn - -@@ -699,11 +719,23 @@ class idrange_mod(LDAPUpdate): - raise errors.ValidationError(name='ID Range setup', - error=_('Options dom-sid and secondary-rid-base cannot ' - 'be used together')) -- -- if not in_updated_attrs('ipabaserid'): -- raise errors.ValidationError(name='ID Range setup', -- error=_('Options dom-sid and rid-base must ' -- 'be used together')) -+ range_type = old_attrs['iparangetype'][0] -+ if range_type == u'ipa-ad-trust': -+ if not in_updated_attrs('ipabaserid'): -+ raise errors.ValidationError( -+ name='ID Range setup', -+ error=_('Options dom-sid and rid-base must ' -+ 'be used together')) -+ elif (range_type == u'ipa-ad-trust-posix' and -+ 'ipabaserid' in entry_attrs): -+ if entry_attrs['ipabaserid'] is None: -+ entry_attrs['ipabaserid'] = 0 -+ elif entry_attrs['ipabaserid'] != 0: -+ raise errors.ValidationError( -+ name='ID Range setup', -+ error=_('Option rid-base must not be used when IPA ' -+ 'range type is ipa-ad-trust-posix') -+ ) - - if is_set('ipanttrusteddomainsid'): - # Validate SID as the one of trusted domains -@@ -766,6 +798,7 @@ class idrange_mod(LDAPUpdate): - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) -+ self.obj.handle_ipabaserid(entry_attrs, options) - self.obj.handle_iparangetype(entry_attrs, options) - return dn - --- -2.1.0 - diff --git a/SOURCES/0019-cermonger-Use-private-unix-socket-when-DBus-SystemBu.patch b/SOURCES/0019-cermonger-Use-private-unix-socket-when-DBus-SystemBu.patch new file mode 100644 index 0000000..364e464 --- /dev/null +++ b/SOURCES/0019-cermonger-Use-private-unix-socket-when-DBus-SystemBu.patch @@ -0,0 +1,288 @@ +From 3cec31570b04fa9ece1f3d02768a676c6c2f35ff Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Tue, 7 Jul 2015 15:49:27 +0200 +Subject: [PATCH] cermonger: Use private unix socket when DBus SystemBus is not + available. + +https://fedorahosted.org/freeipa/ticket/5095 + +Reviewed-By: Jan Cholasta +--- + ipaplatform/base/paths.py | 4 ++ + ipapython/certmonger.py | 137 +++++++++++++++++++++++++++++++--------------- + 2 files changed, 98 insertions(+), 43 deletions(-) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 9fef3e7a1351dd42895fe560bb3c1bc5a1c852b4..5756040172126438d42275b734f4d766d53048fe 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -348,3 +348,7 @@ class BasePathNamespace(object): + BAK2DB = '/usr/sbin/bak2db' + DB2BAK = '/usr/sbin/db2bak' + KDCPROXY_CONFIG = '/etc/ipa/kdcproxy/kdcproxy.conf' ++ CERTMONGER = '/usr/sbin/certmonger' ++ ++ ++path_namespace = BasePathNamespace +diff --git a/ipapython/certmonger.py b/ipapython/certmonger.py +index 4baaaa85da08bb943d6b9f0091a1d2acc36b18d6..b37676872a8b983636c7b2dc5590e83c8b08ea98 100644 +--- a/ipapython/certmonger.py ++++ b/ipapython/certmonger.py +@@ -27,6 +27,8 @@ import sys + import time + import dbus + import shlex ++import subprocess ++import tempfile + from ipapython import ipautil + from ipapython import dogtag + from ipapython.ipa_log_manager import * +@@ -35,6 +37,7 @@ from ipaplatform import services + + DBUS_CM_PATH = '/org/fedorahosted/certmonger' + DBUS_CM_IF = 'org.fedorahosted.certmonger' ++DBUS_CM_NAME = 'org.fedorahosted.certmonger' + DBUS_CM_REQUEST_IF = 'org.fedorahosted.certmonger.request' + DBUS_CM_CA_IF = 'org.fedorahosted.certmonger.ca' + DBUS_PROPERTY_IF = 'org.freedesktop.DBus.Properties' +@@ -44,7 +47,7 @@ class _cm_dbus_object(object): + """ + Auxiliary class for convenient DBus object handling. + """ +- def __init__(self, bus, object_path, object_dbus_interface, ++ def __init__(self, bus, parent, object_path, object_dbus_interface, + parent_dbus_interface=None, property_interface=False): + """ + bus - DBus bus object, result of dbus.SystemBus() or dbus.SessionBus() +@@ -60,6 +63,7 @@ class _cm_dbus_object(object): + if parent_dbus_interface is None: + parent_dbus_interface = object_dbus_interface + self.bus = bus ++ self.parent = parent + self.path = object_path + self.obj_dbus_if = object_dbus_interface + self.parent_dbus_if = parent_dbus_interface +@@ -69,36 +73,83 @@ class _cm_dbus_object(object): + self.prop_if = dbus.Interface(self.obj, DBUS_PROPERTY_IF) + + +-def _start_certmonger(): +- """ +- Start certmonger daemon. If it's already running systemctl just ignores +- the command. +- """ +- if not services.knownservices.certmonger.is_running(): ++class _certmonger(_cm_dbus_object): ++ """ ++ Create a connection to certmonger. ++ By default use SystemBus. When not available use private connection ++ over Unix socket. ++ This solution is really ugly and should be removed as soon as DBus ++ SystemBus is available at system install time. ++ """ ++ timeout = 300 ++ ++ def _start_private_conn(self): ++ sock_filename = os.path.join(tempfile.mkdtemp(), 'certmonger') ++ self._proc = subprocess.Popen([paths.CERTMONGER, '-n', '-L', '-P', ++ sock_filename]) ++ for t in range(0, self.timeout, 5): ++ if os.path.exists(sock_filename): ++ return "unix:path=%s" % sock_filename ++ time.sleep(5) ++ self._stop_private_conn() ++ raise RuntimeError("Failed to start certmonger: Timed out") ++ ++ def _stop_private_conn(self): ++ if self._proc: ++ retcode = self._proc.poll() ++ if retcode is not None: ++ return ++ self._proc.terminate() ++ for t in range(0, self.timeout, 5): ++ retcode = self._proc.poll() ++ if retcode is not None: ++ return ++ time.sleep(5) ++ root_logger.error("Failed to stop certmonger.") ++ ++ def __del__(self): ++ self._stop_private_conn() ++ ++ def __init__(self): ++ self._proc = None ++ self._bus = None + try: +- services.knownservices.certmonger.start() +- except Exception, e: +- root_logger.error('Failed to start certmonger: %s' % e) +- raise +- +- +-def _connect_to_certmonger(): +- """ +- Start certmonger daemon and connect to it via DBus. +- """ +- try: +- _start_certmonger() +- except (KeyboardInterrupt, OSError), e: +- root_logger.error('Failed to start certmonger: %s' % e) +- raise +- +- try: +- bus = dbus.SystemBus() +- cm = _cm_dbus_object(bus, DBUS_CM_PATH, DBUS_CM_IF) +- except dbus.DBusException, e: +- root_logger.error("Failed to access certmonger over DBus: %s", e) +- raise +- return cm ++ self._bus = dbus.SystemBus() ++ except dbus.DBusException as e: ++ err_name = e.get_dbus_name() ++ if err_name not in ['org.freedesktop.DBus.Error.NoServer', ++ 'org.freedesktop.DBus.Error.FileNotFound']: ++ root_logger.error("Failed to connect to certmonger over " ++ "SystemBus: %s" % e) ++ raise ++ try: ++ self._private_sock = self._start_private_conn() ++ self._bus = dbus.connection.Connection(self._private_sock) ++ except dbus.DBusException as e: ++ root_logger.error("Failed to connect to certmonger over " ++ "private socket: %s" % e) ++ raise ++ else: ++ try: ++ self._bus.get_name_owner(DBUS_CM_NAME) ++ except dbus.DBusException: ++ try: ++ services.knownservices.certmonger.start() ++ except Exception as e: ++ root_logger.error("Failed to start certmonger: %s" % e) ++ raise ++ ++ for t in range(0, self.timeout, 5): ++ try: ++ self._bus.get_name_owner(DBUS_CM_NAME) ++ break ++ except dbus.DBusException: ++ pass ++ time.sleep(5) ++ raise RuntimeError('Failed to start certmonger') ++ ++ super(_certmonger, self).__init__(self._bus, None, DBUS_CM_PATH, ++ DBUS_CM_IF) + + + def _get_requests(criteria=dict()): +@@ -108,7 +159,7 @@ def _get_requests(criteria=dict()): + if not isinstance(criteria, dict): + raise TypeError('"criteria" must be dict.') + +- cm = _connect_to_certmonger() ++ cm = _certmonger() + requests = [] + requests_paths = [] + if 'nickname' in criteria: +@@ -119,12 +170,12 @@ def _get_requests(criteria=dict()): + requests_paths = cm.obj_if.get_requests() + + for request_path in requests_paths: +- request = _cm_dbus_object(cm.bus, request_path, DBUS_CM_REQUEST_IF, ++ request = _cm_dbus_object(cm.bus, cm, request_path, DBUS_CM_REQUEST_IF, + DBUS_CM_IF, True) + for criterion in criteria: + if criterion == 'ca-name': + ca_path = request.obj_if.get_ca() +- ca = _cm_dbus_object(cm.bus, ca_path, DBUS_CM_CA_IF, ++ ca = _cm_dbus_object(cm.bus, cm, ca_path, DBUS_CM_CA_IF, + DBUS_CM_IF) + value = ca.obj_if.get_nickname() + else: +@@ -133,6 +184,7 @@ def _get_requests(criteria=dict()): + break + else: + requests.append(request) ++ + return requests + + +@@ -166,7 +218,7 @@ def get_request_value(request_id, directive): + if request: + if directive == 'ca-name': + ca_path = request.obj_if.get_ca() +- ca = _cm_dbus_object(request.bus, ca_path, DBUS_CM_CA_IF, ++ ca = _cm_dbus_object(request.bus, request, ca_path, DBUS_CM_CA_IF, + DBUS_CM_IF) + return ca.obj_if.get_nickname() + else: +@@ -250,7 +302,7 @@ def request_cert(nssdb, nickname, subject, principal, passwd_fname=None): + """ + Execute certmonger to request a server certificate. + """ +- cm = _connect_to_certmonger() ++ cm = _certmonger() + ca_path = cm.obj_if.find_ca_by_nickname('IPA') + if not ca_path: + raise RuntimeError('IPA CA not found') +@@ -264,7 +316,7 @@ def request_cert(nssdb, nickname, subject, principal, passwd_fname=None): + result = cm.obj_if.add_request(request_parameters) + try: + if result[0]: +- request = _cm_dbus_object(cm.bus, result[1], DBUS_CM_REQUEST_IF, ++ request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF, + DBUS_CM_IF, True) + except TypeError: + root_logger.error('Failed to get create new request.') +@@ -283,7 +335,7 @@ def start_tracking(nickname, secdir, password_file=None, command=None): + + Returns certificate nickname. + """ +- cm = _connect_to_certmonger() ++ cm = _certmonger() + params = {'TRACK': True} + params['cert-nickname'] = nickname + params['cert-database'] = os.path.abspath(secdir) +@@ -302,7 +354,7 @@ def start_tracking(nickname, secdir, password_file=None, command=None): + result = cm.obj_if.add_request(params) + try: + if result[0]: +- request = _cm_dbus_object(cm.bus, result[1], DBUS_CM_REQUEST_IF, ++ request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF, + DBUS_CM_IF, True) + except TypeError, e: + root_logger.error('Failed to add new request.') +@@ -330,8 +382,7 @@ def stop_tracking(secdir, request_id=None, nickname=None): + root_logger.error('Failed to get request: %s' % e) + raise + if request: +- cm = _connect_to_certmonger() +- cm.obj_if.remove_request(request.path) ++ request.parent.obj_if.remove_request(request.path) + + + def modify(request_id, profile=None): +@@ -357,9 +408,9 @@ def _find_IPA_ca(): + We can use find_request_value because the ca files have the + same file format. + """ +- cm = _connect_to_certmonger() ++ cm = _certmonger() + ca_path = cm.obj_if.find_ca_by_nickname('IPA') +- return _cm_dbus_object(cm.bus, ca_path, DBUS_CM_CA_IF, DBUS_CM_IF, True) ++ return _cm_dbus_object(cm.bus, cm, ca_path, DBUS_CM_CA_IF, DBUS_CM_IF, True) + + + def add_principal_to_cas(principal): +@@ -423,7 +474,7 @@ def dogtag_start_tracking(ca, nickname, pin, pinfile, secdir, pre_command, + Both commands can be None. + """ + +- cm = _connect_to_certmonger() ++ cm = _certmonger() + certmonger_cmd_template = paths.CERTMONGER_COMMAND_TEMPLATE + + params = {'TRACK': True} +-- +2.4.3 + diff --git a/SOURCES/0019-ldapupdater-set-baserid-to-0-for-ipa-ad-trust-posix-.patch b/SOURCES/0019-ldapupdater-set-baserid-to-0-for-ipa-ad-trust-posix-.patch deleted file mode 100644 index 47342c5..0000000 --- a/SOURCES/0019-ldapupdater-set-baserid-to-0-for-ipa-ad-trust-posix-.patch +++ /dev/null @@ -1,102 +0,0 @@ -From aa5a5fa8349444c2817feb21dd8c6f8ba6b38fd0 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 13 Oct 2014 14:59:24 +0200 -Subject: [PATCH] ldapupdater: set baserid to 0 for ipa-ad-trust-posix ranges - -New updater plugin which sets baserid to 0 for ranges with type ipa-ad-trust-posix - -https://fedorahosted.org/freeipa/ticket/4221 - -Reviewed-By: Tomas Babej ---- - ipaserver/install/plugins/update_idranges.py | 69 +++++++++++++++++++++++++++- - 1 file changed, 68 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/plugins/update_idranges.py b/ipaserver/install/plugins/update_idranges.py -index 9e97c9f74570484a8bae82e99a7561350163a1b1..1aa5fa7631fd35a7aaf4a23a5eee44e4e0a2e904 100644 ---- a/ipaserver/install/plugins/update_idranges.py -+++ b/ipaserver/install/plugins/update_idranges.py -@@ -17,7 +17,7 @@ - # You should have received a copy of the GNU General Public License - # along with this program. If not, see . - --from ipaserver.install.plugins import MIDDLE -+from ipaserver.install.plugins import MIDDLE, LAST - from ipaserver.install.plugins.baseupdate import PostUpdate - from ipalib import api, errors - from ipapython.dn import DN -@@ -111,4 +111,71 @@ class update_idrange_type(PostUpdate): - - return (False, False, []) - -+ -+class update_idrange_baserid(PostUpdate): -+ """ -+ Update ipa-ad-trust-posix ranges' base RID to 0. This applies to AD trust -+ posix ranges prior to IPA 4.1. -+ """ -+ -+ order = LAST -+ -+ def execute(self, **options): -+ ldap = self.obj.backend -+ -+ base_dn = DN(api.env.container_ranges, api.env.basedn) -+ search_filter = ("(&(objectClass=ipaTrustedADDomainRange)" -+ "(ipaRangeType=ipa-ad-trust-posix)" -+ "(!(ipaBaseRID=0)))") -+ root_logger.debug( -+ "update_idrange_baserid: search for ipa-ad-trust-posix ID ranges " -+ "with ipaBaseRID != 0" -+ ) -+ -+ try: -+ (entries, truncated) = ldap.find_entries( -+ search_filter, ['ipabaserid'], base_dn, -+ paged_search=True, time_limit=0, size_limit=0) -+ -+ except errors.NotFound: -+ root_logger.debug("update_idrange_baserid: no AD domain " -+ "range with posix attributes found") -+ return (False, False, []) -+ -+ except errors.ExecutionError, e: -+ root_logger.error("update_idrange_baserid: cannot retrieve " -+ "list of affected ranges: %s", e) -+ return (False, False, []) -+ -+ root_logger.debug("update_idrange_baserid: found %d " -+ "idranges possible to update", -+ len(entries)) -+ -+ error = False -+ -+ # Set the range type -+ for entry in entries: -+ entry['ipabaserid'] = 0 -+ try: -+ root_logger.info("Updating existing idrange: %s" % (entry.dn)) -+ ldap.update_entry(entry) -+ root_logger.info("Done") -+ except (errors.EmptyModlist, errors.NotFound): -+ pass -+ except errors.ExecutionError, e: -+ root_logger.debug("update_idrange_type: cannot " -+ "update idrange: %s", e) -+ error = True -+ -+ if error: -+ root_logger.error("update_idrange_baserid: error(s) " -+ "detected during idrange baserid update") -+ else: -+ # All affected entries updated, exit the loop -+ root_logger.debug("update_idrange_baserid: all affected " -+ "idranges updated") -+ -+ return (False, False, []) -+ - api.register(update_idrange_type) -+api.register(update_idrange_baserid) --- -2.1.0 - diff --git a/SOURCES/0020-idrange-include-raw-range-type-in-output.patch b/SOURCES/0020-idrange-include-raw-range-type-in-output.patch deleted file mode 100644 index 03e655f..0000000 --- a/SOURCES/0020-idrange-include-raw-range-type-in-output.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 83e12a6e7266ab1324f259eaed809f8db1118d7a Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Wed, 15 Oct 2014 13:42:30 +0200 -Subject: [PATCH] idrange: include raw range type in output - -iparangetype output is a localized human-readable value which is not suitable for machine-based API consumers - -Solved by new iparangetyperaw output attribute which contains iparangetype's raw value - -Reviewed-By: Tomas Babej ---- - ipalib/plugins/idrange.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipalib/plugins/idrange.py b/ipalib/plugins/idrange.py -index 6c3be6e69595127e346969e41703dc98e783282e..fb198d79d4c14ffd5f7dc633c9f01a1465ff01d7 100644 ---- a/ipalib/plugins/idrange.py -+++ b/ipalib/plugins/idrange.py -@@ -241,6 +241,7 @@ class idrange(LDAPObject): - if not any((options.get('pkey_only', False), - options.get('raw', False))): - range_type = entry_attrs['iparangetype'][0] -+ entry_attrs['iparangetyperaw'] = [range_type] - entry_attrs['iparangetype'] = [self.range_types.get(range_type, None)] - - # Remove the objectclass --- -2.1.0 - diff --git a/SOURCES/0020-ipa-client-install-Do-not-re-start-certmonger-and-DB.patch b/SOURCES/0020-ipa-client-install-Do-not-re-start-certmonger-and-DB.patch new file mode 100644 index 0000000..5e5ef43 --- /dev/null +++ b/SOURCES/0020-ipa-client-install-Do-not-re-start-certmonger-and-DB.patch @@ -0,0 +1,138 @@ +From 42353682a3d9e92f4053877d66f54e44f516bb53 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Tue, 7 Jul 2015 15:49:51 +0200 +Subject: [PATCH] ipa-client-install: Do not (re)start certmonger and DBus + daemons. + +When DBus is present in the system it is always running. + +Starting of certmomger is handled in ipapython/certmonger.py module if +necessary. Restarting is no longer needed since freeipa is not changing +certmonger's files. + +https://fedorahosted.org/freeipa/ticket/5095 + +Reviewed-By: Jan Cholasta +--- + ipa-client/ipa-install/ipa-client-install | 71 +++++++------------------------ + 1 file changed, 15 insertions(+), 56 deletions(-) + +diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install +index 96b30b486585bc60b0882263cff58292a3538df9..91323ae115a27d221bcbc43fee887c56d99c8635 100755 +--- a/ipa-client/ipa-install/ipa-client-install ++++ b/ipa-client/ipa-install/ipa-client-install +@@ -522,20 +522,7 @@ def uninstall(options, env): + ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) + sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR) + +- # Always start certmonger. We can't untrack something if it isn't +- # running +- messagebus = services.knownservices.messagebus +- try: +- messagebus.start() +- except Exception, e: +- log_service_error(messagebus.service_name, 'start', e) +- + cmonger = services.knownservices.certmonger +- try: +- cmonger.start() +- except Exception, e: +- log_service_error(cmonger.service_name, 'start', e) +- + if ipa_db.has_nickname('Local IPA host'): + try: + certmonger.stop_tracking(paths.IPA_NSSDB_DIR, +@@ -576,14 +563,14 @@ def uninstall(options, env): + nickname, sys_db.secdir, e) + break + ++ # Remove any special principal names we added to the IPA CA helper ++ certmonger.remove_principal_from_cas() ++ + try: + cmonger.stop() + except Exception, e: + log_service_error(cmonger.service_name, 'stop', e) + +- # Remove any special principal names we added to the IPA CA helper +- certmonger.remove_principal_from_cas() +- + try: + cmonger.disable() + except Exception, e: +@@ -1138,41 +1125,14 @@ def configure_certmonger(fstore, subject_base, cli_realm, hostname, options, + "Not requesting host certificate.") + return + +- started = True + principal = 'host/%s@%s' % (hostname, cli_realm) + +- messagebus = services.knownservices.messagebus +- try: +- messagebus.start() +- except Exception, e: +- log_service_error(messagebus.service_name, 'start', e) +- +- # Ensure that certmonger has been started at least once to generate the +- # cas files in /var/lib/certmonger/cas. +- cmonger = services.knownservices.certmonger +- try: +- cmonger.restart() +- except Exception, e: +- log_service_error(cmonger.service_name, 'restart', e) +- + if options.hostname: +- # It needs to be stopped if we touch them +- try: +- cmonger.stop() +- except Exception, e: +- log_service_error(cmonger.service_name, 'stop', e) + # If the hostname is explicitly set then we need to tell certmonger + # which principal name to use when requesting certs. + certmonger.add_principal_to_cas(principal) + +- try: +- cmonger.restart() +- except Exception, e: +- log_service_error(cmonger.service_name, 'restart', e) +- root_logger.warning( +- "Automatic certificate management will not be available") +- started = False +- ++ cmonger = services.knownservices.certmonger + try: + cmonger.enable() + except Exception, e: +@@ -1183,18 +1143,17 @@ def configure_certmonger(fstore, subject_base, cli_realm, hostname, options, + "Automatic certificate management will not be available") + + # Request our host cert +- if started: +- subject = str(DN(('CN', hostname), subject_base)) +- passwd_fname = os.path.join(paths.IPA_NSSDB_DIR, 'pwdfile.txt') +- try: +- certmonger.request_cert(nssdb=paths.IPA_NSSDB_DIR, +- nickname='Local IPA host', +- subject=subject, +- principal=principal, +- passwd_fname=passwd_fname) +- except Exception: +- root_logger.error("%s request for host certificate failed", +- cmonger.service_name) ++ subject = str(DN(('CN', hostname), subject_base)) ++ passwd_fname = os.path.join(paths.IPA_NSSDB_DIR, 'pwdfile.txt') ++ try: ++ certmonger.request_cert(nssdb=paths.IPA_NSSDB_DIR, ++ nickname='Local IPA host', ++ subject=subject, ++ principal=principal, ++ passwd_fname=passwd_fname) ++ except Exception: ++ root_logger.error("%s request for host certificate failed", ++ cmonger.service_name) + + def configure_sssd_conf(fstore, cli_realm, cli_domain, cli_server, options, client_domain, client_hostname): + try: +-- +2.4.3 + diff --git a/SOURCES/0021-DNS-Consolidate-DNS-RR-types-in-API-and-schema.patch b/SOURCES/0021-DNS-Consolidate-DNS-RR-types-in-API-and-schema.patch new file mode 100644 index 0000000..5aa37bd --- /dev/null +++ b/SOURCES/0021-DNS-Consolidate-DNS-RR-types-in-API-and-schema.patch @@ -0,0 +1,503 @@ +From eeec6dd88ea1e6f2c24ee87d70a8d6aa98cbd0e4 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 15 Jul 2015 09:44:07 +0200 +Subject: [PATCH] DNS: Consolidate DNS RR types in API and schema + +* Remove NSEC3, DNSKEY, TSIG, TKEY, TA records from API: + These records never worked, they dont have attributes in schema. + TSIG and TKEY are meta-RR should not be in LDAP + TA is not supported by BIND + NSEC3, DNSKEY are DNSSEC records generated by BIND, should not be + in LDAP. + *! SIG, NSEC are already defined in schema, must stay in API. + +* Add HINFO, MINFO, MD, NXT records to API as unsupported records + These records are already defined in LDAP schema + +* Add schema for RP, APL, IPSEC, DHCID, HIP, SPF records + These records were defined in IPA API as unsupported, but schema definition was + missing. This causes that ACI cannot be created for these records + and dnszone-find failed. (#5055) + +https://fedorahosted.org/freeipa/ticket/4934 +https://fedorahosted.org/freeipa/ticket/5055 + +Reviewed-By: Martin Babinsky +Reviewed-By: Petr Spacek +--- + ACI.txt | 4 +- + API.txt | 28 ++---------- + VERSION | 4 +- + install/share/60ipadns.ldif | 8 +++- + install/share/dns.ldif | 2 +- + install/updates/40-dns.update | 4 +- + ipalib/plugins/dns.py | 101 ++++++++++++++++++++++-------------------- + 7 files changed, 71 insertions(+), 80 deletions(-) + +diff --git a/ACI.txt b/ACI.txt +index 76a7ff70e27c032bdd8fa26e076271e02b23d3b3..60607b98deb74d0b7f45d24ee9359b0cf8162b0d 100644 +--- a/ACI.txt ++++ b/ACI.txt +@@ -61,13 +61,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 || arecord || certrecord || cn || cnamerecord || createtimestamp || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || entryusn || hinforecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || modifytimestamp || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || objectclass || ptrrecord || rrsigrecord || sigrecord || 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 || dnsttl || dsrecord || entryusn || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || 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 || arecord || certrecord || cn || cnamerecord || dlvrecord || dnamerecord || dnsclass || dnsttl || dsrecord || hinforecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || ptrrecord || rrsigrecord || sigrecord || 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 || dnsttl || dsrecord || hinforecord || hiprecord || idnsallowdynupdate || idnsallowquery || idnsallowsyncptr || idnsallowtransfer || idnsforwarders || idnsforwardpolicy || idnsname || idnssecinlinesigning || idnssoaexpire || idnssoaminimum || idnssoamname || idnssoarefresh || idnssoaretry || idnssoarname || idnssoaserial || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || managedby || mdrecord || minforecord || mxrecord || naptrrecord || nsec3paramrecord || nsecrecord || nsrecord || nxtrecord || 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 c68bee94e3a9ed6182f6bd2152070222e32c7532..6ab30ddab41715fdbccb4f37aa1852621bca62b4 100644 +--- a/API.txt ++++ b/API.txt +@@ -1054,7 +1054,7 @@ output: Entry('result', , Gettext('A dictionary representing an LDA + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) + command: dnsrecord_add +-args: 2,100,3 ++args: 2,95,3 + arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True) + arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, primary_key=True, required=True) + option: Str('a6_part_data', attribute=False, cli_name='a6_data', multivalue=False, option_group=u'A6 Record', required=False) +@@ -1087,7 +1087,6 @@ option: DLVRecord('dlvrecord', attribute=True, cli_name='dlv_rec', csv=True, mul + option: DNSNameParam('dname_part_target', attribute=False, cli_name='dname_target', multivalue=False, option_group=u'DNAME Record', required=False) + option: DNAMERecord('dnamerecord', attribute=True, cli_name='dname_rec', csv=True, multivalue=True, option_group=u'DNAME Record', required=False) + option: StrEnum('dnsclass', attribute=True, cli_name='class', multivalue=False, required=False, values=(u'IN', u'CS', u'CH', u'HS')) +-option: DNSKEYRecord('dnskeyrecord', attribute=True, cli_name='dnskey_rec', csv=True, multivalue=True, option_group=u'DNSKEY Record', required=False) + option: Int('dnsttl', attribute=True, cli_name='ttl', multivalue=False, required=False) + option: Int('ds_part_algorithm', attribute=False, cli_name='ds_algorithm', maxvalue=255, minvalue=0, multivalue=False, option_group=u'DS Record', required=False) + option: Str('ds_part_digest', attribute=False, cli_name='ds_digest', multivalue=False, option_group=u'DS Record', pattern='^[0-9a-fA-F]+$', required=False) +@@ -1125,7 +1124,6 @@ option: Str('naptr_part_replacement', attribute=False, cli_name='naptr_replaceme + option: Str('naptr_part_service', attribute=False, cli_name='naptr_service', multivalue=False, option_group=u'NAPTR Record', required=False) + option: NAPTRRecord('naptrrecord', attribute=True, cli_name='naptr_rec', csv=True, multivalue=True, option_group=u'NAPTR Record', required=False) + option: DNSNameParam('ns_part_hostname', attribute=False, cli_name='ns_hostname', multivalue=False, option_group=u'NS Record', required=False) +-option: NSEC3Record('nsec3record', attribute=True, cli_name='nsec3_rec', csv=True, multivalue=True, option_group=u'NSEC3 Record', required=False) + option: NSECRecord('nsecrecord', attribute=True, cli_name='nsec_rec', csv=True, multivalue=True, option_group=u'NSEC Record', required=False) + option: NSRecord('nsrecord', attribute=True, cli_name='ns_rec', csv=True, multivalue=True, option_group=u'NS Record', required=False) + option: DNSNameParam('ptr_part_hostname', attribute=False, cli_name='ptr_hostname', multivalue=False, option_group=u'PTR Record', required=False) +@@ -1146,14 +1144,11 @@ option: Str('sshfp_part_fingerprint', attribute=False, cli_name='sshfp_fingerpri + option: Int('sshfp_part_fp_type', attribute=False, cli_name='sshfp_fp_type', maxvalue=255, minvalue=0, multivalue=False, option_group=u'SSHFP Record', required=False) + option: SSHFPRecord('sshfprecord', attribute=True, cli_name='sshfp_rec', csv=True, multivalue=True, option_group=u'SSHFP Record', required=False) + option: Flag('structured', autofill=True, default=False) +-option: TARecord('tarecord', attribute=True, cli_name='ta_rec', csv=True, multivalue=True, option_group=u'TA Record', required=False) +-option: TKEYRecord('tkeyrecord', attribute=True, cli_name='tkey_rec', csv=True, multivalue=True, option_group=u'TKEY Record', required=False) + option: Str('tlsa_part_cert_association_data', attribute=False, cli_name='tlsa_cert_association_data', multivalue=False, option_group=u'TLSA Record', required=False) + option: Int('tlsa_part_cert_usage', attribute=False, cli_name='tlsa_cert_usage', maxvalue=255, minvalue=0, multivalue=False, option_group=u'TLSA Record', required=False) + option: Int('tlsa_part_matching_type', attribute=False, cli_name='tlsa_matching_type', maxvalue=255, minvalue=0, multivalue=False, option_group=u'TLSA Record', required=False) + option: Int('tlsa_part_selector', attribute=False, cli_name='tlsa_selector', maxvalue=255, minvalue=0, multivalue=False, option_group=u'TLSA Record', required=False) + option: TLSARecord('tlsarecord', attribute=True, cli_name='tlsa_rec', csv=True, multivalue=True, option_group=u'TLSA Record', required=False) +-option: TSIGRecord('tsigrecord', attribute=True, cli_name='tsig_rec', csv=True, multivalue=True, option_group=u'TSIG Record', required=False) + option: Str('txt_part_data', attribute=False, cli_name='txt_data', multivalue=False, option_group=u'TXT Record', required=False) + option: TXTRecord('txtrecord', attribute=True, cli_name='txt_rec', csv=True, multivalue=True, option_group=u'TXT Record', required=False) + option: Str('version?', exclude='webui') +@@ -1161,7 +1156,7 @@ output: Entry('result', , Gettext('A dictionary representing an LDA + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) + command: dnsrecord_del +-args: 2,39,3 ++args: 2,34,3 + arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True) + arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True) + option: A6Record('a6record', attribute=True, autofill=False, cli_name='a6_rec', csv=True, multivalue=True, option_group=None, required=False) +@@ -1176,7 +1171,6 @@ option: DHCIDRecord('dhcidrecord', attribute=True, autofill=False, cli_name='dhc + option: DLVRecord('dlvrecord', attribute=True, autofill=False, cli_name='dlv_rec', csv=True, multivalue=True, option_group=None, required=False) + option: DNAMERecord('dnamerecord', attribute=True, autofill=False, cli_name='dname_rec', csv=True, multivalue=True, option_group=None, required=False) + option: StrEnum('dnsclass', attribute=True, autofill=False, cli_name='class', multivalue=False, required=False, values=(u'IN', u'CS', u'CH', u'HS')) +-option: DNSKEYRecord('dnskeyrecord', attribute=True, autofill=False, cli_name='dnskey_rec', csv=True, multivalue=True, option_group=None, required=False) + option: Int('dnsttl', attribute=True, autofill=False, cli_name='ttl', multivalue=False, required=False) + option: DSRecord('dsrecord', attribute=True, autofill=False, cli_name='ds_rec', csv=True, multivalue=True, option_group=None, required=False) + option: HIPRecord('hiprecord', attribute=True, autofill=False, cli_name='hip_rec', csv=True, multivalue=True, option_group=None, required=False) +@@ -1186,7 +1180,6 @@ option: KXRecord('kxrecord', attribute=True, autofill=False, cli_name='kx_rec', + option: LOCRecord('locrecord', attribute=True, autofill=False, cli_name='loc_rec', csv=True, multivalue=True, option_group=None, required=False) + option: MXRecord('mxrecord', attribute=True, autofill=False, cli_name='mx_rec', csv=True, multivalue=True, option_group=None, required=False) + option: NAPTRRecord('naptrrecord', attribute=True, autofill=False, cli_name='naptr_rec', csv=True, multivalue=True, option_group=None, required=False) +-option: NSEC3Record('nsec3record', attribute=True, autofill=False, cli_name='nsec3_rec', csv=True, multivalue=True, option_group=None, required=False) + option: NSECRecord('nsecrecord', attribute=True, autofill=False, cli_name='nsec_rec', csv=True, multivalue=True, option_group=None, required=False) + option: NSRecord('nsrecord', attribute=True, autofill=False, cli_name='ns_rec', csv=True, multivalue=True, option_group=None, required=False) + option: PTRRecord('ptrrecord', attribute=True, autofill=False, cli_name='ptr_rec', csv=True, multivalue=True, option_group=None, required=False) +@@ -1197,10 +1190,7 @@ option: SPFRecord('spfrecord', attribute=True, autofill=False, cli_name='spf_rec + option: SRVRecord('srvrecord', attribute=True, autofill=False, cli_name='srv_rec', csv=True, multivalue=True, option_group=None, required=False) + option: SSHFPRecord('sshfprecord', attribute=True, autofill=False, cli_name='sshfp_rec', csv=True, multivalue=True, option_group=None, required=False) + option: Flag('structured', autofill=True, default=False) +-option: TARecord('tarecord', attribute=True, autofill=False, cli_name='ta_rec', csv=True, multivalue=True, option_group=None, required=False) +-option: TKEYRecord('tkeyrecord', attribute=True, autofill=False, cli_name='tkey_rec', csv=True, multivalue=True, option_group=None, required=False) + option: TLSARecord('tlsarecord', attribute=True, autofill=False, cli_name='tlsa_rec', csv=True, multivalue=True, option_group=None, required=False) +-option: TSIGRecord('tsigrecord', attribute=True, autofill=False, cli_name='tsig_rec', csv=True, multivalue=True, option_group=None, required=False) + option: TXTRecord('txtrecord', attribute=True, autofill=False, cli_name='txt_rec', csv=True, multivalue=True, option_group=None, required=False) + option: Str('version?', exclude='webui') + output: Output('result', , None) +@@ -1216,7 +1206,7 @@ output: Output('result', , None) + output: Output('summary', (, ), None) + output: ListOfPrimaryKeys('value', None, None) + command: dnsrecord_find +-args: 2,44,4 ++args: 2,39,4 + arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True) + arg: Str('criteria?', noextrawhitespace=False) + option: A6Record('a6record', attribute=True, autofill=False, cli_name='a6_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) +@@ -1231,7 +1221,6 @@ option: DHCIDRecord('dhcidrecord', attribute=True, autofill=False, cli_name='dhc + option: DLVRecord('dlvrecord', attribute=True, autofill=False, cli_name='dlv_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: DNAMERecord('dnamerecord', attribute=True, autofill=False, cli_name='dname_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: StrEnum('dnsclass', attribute=True, autofill=False, cli_name='class', multivalue=False, query=True, required=False, values=(u'IN', u'CS', u'CH', u'HS')) +-option: DNSKEYRecord('dnskeyrecord', attribute=True, autofill=False, cli_name='dnskey_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: Int('dnsttl', attribute=True, autofill=False, cli_name='ttl', multivalue=False, query=True, required=False) + option: DSRecord('dsrecord', attribute=True, autofill=False, cli_name='ds_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: HIPRecord('hiprecord', attribute=True, autofill=False, cli_name='hip_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) +@@ -1242,7 +1231,6 @@ option: KXRecord('kxrecord', attribute=True, autofill=False, cli_name='kx_rec', + option: LOCRecord('locrecord', attribute=True, autofill=False, cli_name='loc_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: MXRecord('mxrecord', attribute=True, autofill=False, cli_name='mx_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: NAPTRRecord('naptrrecord', attribute=True, autofill=False, cli_name='naptr_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) +-option: NSEC3Record('nsec3record', attribute=True, autofill=False, cli_name='nsec3_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: NSECRecord('nsecrecord', attribute=True, autofill=False, cli_name='nsec_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: NSRecord('nsrecord', attribute=True, autofill=False, cli_name='ns_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: Flag('pkey_only?', autofill=True, default=False) +@@ -1256,11 +1244,8 @@ option: SPFRecord('spfrecord', attribute=True, autofill=False, cli_name='spf_rec + option: SRVRecord('srvrecord', attribute=True, autofill=False, cli_name='srv_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: SSHFPRecord('sshfprecord', attribute=True, autofill=False, cli_name='sshfp_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: Flag('structured', autofill=True, default=False) +-option: TARecord('tarecord', attribute=True, autofill=False, cli_name='ta_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: Int('timelimit?', autofill=False, minvalue=0) +-option: TKEYRecord('tkeyrecord', attribute=True, autofill=False, cli_name='tkey_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: TLSARecord('tlsarecord', attribute=True, autofill=False, cli_name='tlsa_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) +-option: TSIGRecord('tsigrecord', attribute=True, autofill=False, cli_name='tsig_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: TXTRecord('txtrecord', attribute=True, autofill=False, cli_name='txt_rec', csv=True, multivalue=True, option_group=None, query=True, required=False) + option: Str('version?', exclude='webui') + output: Output('count', , None) +@@ -1268,7 +1253,7 @@ output: ListOfEntries('result', (, ), Gettext('A list + output: Output('summary', (, ), None) + output: Output('truncated', , None) + command: dnsrecord_mod +-args: 2,100,3 ++args: 2,95,3 + arg: DNSNameParam('dnszoneidnsname', cli_name='dnszone', multivalue=False, only_absolute=True, primary_key=True, query=True, required=True) + arg: DNSNameParam('idnsname', attribute=True, cli_name='name', multivalue=False, primary_key=True, query=True, required=True) + option: Str('a6_part_data', attribute=False, autofill=False, cli_name='a6_data', multivalue=False, option_group=u'A6 Record', required=False) +@@ -1300,7 +1285,6 @@ option: DLVRecord('dlvrecord', attribute=True, autofill=False, cli_name='dlv_rec + option: DNSNameParam('dname_part_target', attribute=False, autofill=False, cli_name='dname_target', multivalue=False, option_group=u'DNAME Record', required=False) + option: DNAMERecord('dnamerecord', attribute=True, autofill=False, cli_name='dname_rec', csv=True, multivalue=True, option_group=u'DNAME Record', required=False) + option: StrEnum('dnsclass', attribute=True, autofill=False, cli_name='class', multivalue=False, required=False, values=(u'IN', u'CS', u'CH', u'HS')) +-option: DNSKEYRecord('dnskeyrecord', attribute=True, autofill=False, cli_name='dnskey_rec', csv=True, multivalue=True, option_group=u'DNSKEY Record', required=False) + option: Int('dnsttl', attribute=True, autofill=False, cli_name='ttl', multivalue=False, required=False) + option: Int('ds_part_algorithm', attribute=False, autofill=False, cli_name='ds_algorithm', maxvalue=255, minvalue=0, multivalue=False, option_group=u'DS Record', required=False) + option: Str('ds_part_digest', attribute=False, autofill=False, cli_name='ds_digest', multivalue=False, option_group=u'DS Record', pattern='^[0-9a-fA-F]+$', required=False) +@@ -1337,7 +1321,6 @@ option: Str('naptr_part_replacement', attribute=False, autofill=False, cli_name= + option: Str('naptr_part_service', attribute=False, autofill=False, cli_name='naptr_service', multivalue=False, option_group=u'NAPTR Record', required=False) + option: NAPTRRecord('naptrrecord', attribute=True, autofill=False, cli_name='naptr_rec', csv=True, multivalue=True, option_group=u'NAPTR Record', required=False) + option: DNSNameParam('ns_part_hostname', attribute=False, autofill=False, cli_name='ns_hostname', multivalue=False, option_group=u'NS Record', required=False) +-option: NSEC3Record('nsec3record', attribute=True, autofill=False, cli_name='nsec3_rec', csv=True, multivalue=True, option_group=u'NSEC3 Record', required=False) + option: NSECRecord('nsecrecord', attribute=True, autofill=False, cli_name='nsec_rec', csv=True, multivalue=True, option_group=u'NSEC Record', required=False) + option: NSRecord('nsrecord', attribute=True, autofill=False, cli_name='ns_rec', csv=True, multivalue=True, option_group=u'NS Record', required=False) + option: DNSNameParam('ptr_part_hostname', attribute=False, autofill=False, cli_name='ptr_hostname', multivalue=False, option_group=u'PTR Record', required=False) +@@ -1360,14 +1343,11 @@ option: Str('sshfp_part_fingerprint', attribute=False, autofill=False, cli_name= + option: Int('sshfp_part_fp_type', attribute=False, autofill=False, cli_name='sshfp_fp_type', maxvalue=255, minvalue=0, multivalue=False, option_group=u'SSHFP Record', required=False) + option: SSHFPRecord('sshfprecord', attribute=True, autofill=False, cli_name='sshfp_rec', csv=True, multivalue=True, option_group=u'SSHFP Record', required=False) + option: Flag('structured', autofill=True, default=False) +-option: TARecord('tarecord', attribute=True, autofill=False, cli_name='ta_rec', csv=True, multivalue=True, option_group=u'TA Record', required=False) +-option: TKEYRecord('tkeyrecord', attribute=True, autofill=False, cli_name='tkey_rec', csv=True, multivalue=True, option_group=u'TKEY Record', required=False) + option: Str('tlsa_part_cert_association_data', attribute=False, autofill=False, cli_name='tlsa_cert_association_data', multivalue=False, option_group=u'TLSA Record', required=False) + option: Int('tlsa_part_cert_usage', attribute=False, autofill=False, cli_name='tlsa_cert_usage', maxvalue=255, minvalue=0, multivalue=False, option_group=u'TLSA Record', required=False) + option: Int('tlsa_part_matching_type', attribute=False, autofill=False, cli_name='tlsa_matching_type', maxvalue=255, minvalue=0, multivalue=False, option_group=u'TLSA Record', required=False) + option: Int('tlsa_part_selector', attribute=False, autofill=False, cli_name='tlsa_selector', maxvalue=255, minvalue=0, multivalue=False, option_group=u'TLSA Record', required=False) + option: TLSARecord('tlsarecord', attribute=True, autofill=False, cli_name='tlsa_rec', csv=True, multivalue=True, option_group=u'TLSA Record', required=False) +-option: TSIGRecord('tsigrecord', attribute=True, autofill=False, cli_name='tsig_rec', csv=True, multivalue=True, option_group=u'TSIG Record', required=False) + option: Str('txt_part_data', attribute=False, autofill=False, cli_name='txt_data', multivalue=False, option_group=u'TXT Record', required=False) + option: TXTRecord('txtrecord', attribute=True, autofill=False, cli_name='txt_rec', csv=True, multivalue=True, option_group=u'TXT Record', required=False) + option: Str('version?', exclude='webui') +diff --git a/VERSION b/VERSION +index b2f7a9a3e73b5f38741f7266054e3429803d7036..678d1f8a7e588d480b16441e12e4d527d9c1cd98 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=146 +-# Last change: pvoborni - move session_logout to ipalib/plugins ++IPA_API_VERSION_MINOR=147 ++# Last change: mbasti - Consolidate DNS RR in API and schema +diff --git a/install/share/60ipadns.ldif b/install/share/60ipadns.ldif +index 9e5b7feb2ee1809fb67b23cb2017a536d1bacb0a..e0ed0ab869cea0478d9640bb509c6267abed1a01 100644 +--- a/install/share/60ipadns.ldif ++++ b/install/share/60ipadns.ldif +@@ -10,6 +10,7 @@ attributeTypes: (1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord' DESC 'domain name poi + 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 ) + attributeTypes: (1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord' DESC 'text string, 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.17 NAME 'RPRecord' DESC 'Responsible Person, RFC 1183' 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.18 NAME 'aFSDBRecord' DESC 'for AFS Data Base location, RFC 1183' 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.24 NAME 'SigRecord' DESC 'Signature, RFC 2535' 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.25 NAME 'KeyRecord' DESC 'Key, RFC 2535' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +@@ -22,12 +23,17 @@ attributeTypes: (1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord' DESC 'Key Exchange Del + attributeTypes: (1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord' DESC 'certificate, RFC 2538' 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.38 NAME 'a6Record' DESC 'A6 Record Type, RFC 2874' 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.39 NAME 'dNameRecord' DESC 'Non-Terminal DNS Name Redirection, RFC 2672' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) ++attributeTypes: (1.3.6.1.4.1.2428.20.1.42 NAME 'APLRecord' DESC 'Lists of Address Prefixes, RFC 3132' 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.43 NAME 'dSRecord' DESC 'Delegation Signer, RFC 3658' 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.44 NAME 'sSHFPRecord' DESC 'SSH Key Fingerprint, draft-ietf-secsh-dns-05.txt' 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.45 NAME 'IPSECKEYRecord' DESC 'IPSECKEY, RFC 4025' 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.46 NAME 'rRSIGRecord' DESC 'RRSIG, RFC 3755' 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.47 NAME 'nSECRecord' DESC 'NSEC, RFC 3755' 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.49 NAME 'DHCIDRecord' DESC 'Dynamic Host Configuration Protocol (DHCP) Information, RFC 4701' 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.51 NAME 'nSEC3PARAMRecord' DESC 'RFC 5155' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) + attributeTypes: (1.3.6.1.4.1.2428.20.1.52 NAME 'TLSARecord' DESC 'DNS-Based Authentication of Named Entities - Transport Layer Security Protocol, RFC 6698' 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.55 NAME 'HIPRecord' DESC 'Host Identity Protocol (HIP) Domain Name System (DNS) Extension, RFC 5205' 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.99 NAME 'SPFRecord' DESC 'Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, RFC 7208' 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.32769 NAME 'DLVRecord' DESC 'DNSSEC Lookaside Validation, RFC 4431' 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.4 NAME 'UnknownRecord' DESC 'unknown DNS record, RFC 3597' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch ) + attributeTypes: (0.9.2342.19200300.100.1.26 NAME 'aRecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +@@ -64,7 +70,7 @@ attributeTypes: ( 2.16.840.1.113730.3.8.5.25 NAME 'idnsSecKeyRevoke' DESC 'DNSKE + attributeTypes: ( 2.16.840.1.113730.3.8.5.26 NAME 'idnsSecKeySep' DESC 'DNSKEY SEP flag (equivalent to bit 15): RFC 4035' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4.1' ) + attributeTypes: ( 2.16.840.1.113730.3.8.5.27 NAME 'idnsSecAlgorithm' DESC 'DNSKEY algorithm: string used as mnemonic' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v4.1' ) + attributeTypes: ( 2.16.840.1.113730.3.8.5.28 NAME 'idnsSecKeyRef' DESC 'PKCS#11 URI of the key' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.1' ) +-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 ) ) ++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.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' ) +diff --git a/install/share/dns.ldif b/install/share/dns.ldif +index c9e368677006b55d0e748f54d297d83bdd69e205..42b41a8d706a8a3fd826320aff6c9333264128fc 100644 +--- a/install/share/dns.ldif ++++ b/install/share/dns.ldif +@@ -9,7 +9,7 @@ ipaConfigString: DNSVersion 1 + aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX" or userattr = "parent[0,1].managedby#GROUPDN";) + aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";) + aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";) +-aci: (targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) ++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 || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) + + dn: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX + changetype: add +diff --git a/install/updates/40-dns.update b/install/updates/40-dns.update +index c06d8158d85fd811be0253ac0f1146a623fae2b2..9f64a2f707db5cb0e3503259a0e64d9831ae92f2 100644 +--- a/install/updates/40-dns.update ++++ b/install/updates/40-dns.update +@@ -5,7 +5,8 @@ addifexist: objectClass: idnsConfigObject + addifexist: objectClass: ipaConfigObject + addifexist: aci:(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";) + addifexist: aci:(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";) +-addifexist: aci:(targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) ++addifexist: 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 || idnsupdatepolicy || idnszoneactive || ipseckeyrecord || keyrecord || kxrecord || locrecord || mdrecord || minforecord || mxrecord || naptrrecord || nsecrecord || nsec3paramrecord || nsrecord || nxtrecord || ptrrecord || rprecord || rrsigrecord || sigrecord || spfrecord || srvrecord || sshfprecord || tlsarecord || txtrecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) ++ + + # replace DNS tree deny rule with managedBy enhanced allow rule + dn: cn=dns, $SUFFIX +@@ -16,6 +17,7 @@ replace:aci:(targetattr = "*")(version 3.0; acl "Allow read access"; allow (read + dn: cn=dns, $SUFFIX + remove:aci:(targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) + remove:aci:(targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) ++remove:aci:(targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord || unknownrecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) + + # add DNS plugin + dn: cn=IPA DNS,cn=plugins,cn=config +diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py +index a7a4100db6de1956b8d0468e03214abc227386d5..512a653c3cc8ee641debec0d20f58e17eff08266 100644 +--- a/ipalib/plugins/dns.py ++++ b/ipalib/plugins/dns.py +@@ -281,10 +281,9 @@ register = Registry() + # supported resource record types + _record_types = ( + u'A', u'AAAA', u'A6', u'AFSDB', u'APL', u'CERT', u'CNAME', u'DHCID', u'DLV', +- u'DNAME', u'DNSKEY', u'DS', u'HIP', u'IPSECKEY', u'KEY', u'KX', u'LOC', +- u'MX', u'NAPTR', u'NS', u'NSEC', u'NSEC3', u'PTR', +- u'RRSIG', u'RP', u'SIG', u'SPF', u'SRV', u'SSHFP', u'TA', u'TKEY', +- u'TLSA', u'TSIG', u'TXT', ++ u'DNAME', u'DS', u'HIP', u'HINFO', u'IPSECKEY', u'KEY', u'KX', u'LOC', ++ u'MD', u'MINFO', u'MX', u'NAPTR', u'NS', u'NSEC', u'NXT', u'PTR', u'RRSIG', ++ u'RP', u'SIG', u'SPF', u'SRV', u'SSHFP', u'TLSA', u'TXT', + ) + + # DNS zone record identificator +@@ -1092,9 +1091,6 @@ class DNAMERecord(DNSRecord): + ), + ) + +-class DNSKEYRecord(UnsupportedDNSRecord): +- rrtype = 'DNSKEY' +- rfc = 4034 + + class DSRecord(DNSRecord): + rrtype = 'DS' +@@ -1129,6 +1125,11 @@ class DLVRecord(DSRecord): + rfc = 4431 + + ++class HINFORecord(UnsupportedDNSRecord): ++ rrtype = 'HINFO' ++ rfc = 1035 ++ ++ + class HIPRecord(UnsupportedDNSRecord): + rrtype = 'HIP' + rfc = 5205 +@@ -1287,6 +1288,18 @@ class LOCRecord(DNSRecord): + name=target_cli_name) + raise errors.ValidationError(name=self.name, error=error) + ++ ++class MDRecord(UnsupportedDNSRecord): ++ # obsoleted, use MX instead ++ rrtype = 'MD' ++ rfc = 1035 ++ ++ ++class MINFORecord(UnsupportedDNSRecord): ++ rrtype = 'MINFO' ++ rfc = 1035 ++ ++ + class MXRecord(DNSRecord): + rrtype = 'MX' + rfc = 1035 +@@ -1318,9 +1331,6 @@ class NSECRecord(UnsupportedDNSRecord): + rrtype = 'NSEC' + rfc = 4034 + +-class NSEC3Record(UnsupportedDNSRecord): +- rrtype = 'NSEC3' +- rfc = 5155 + + def _validate_naptr_flags(ugettext, flags): + allowed_flags = u'SAUP' +@@ -1361,6 +1371,12 @@ class NAPTRRecord(DNSRecord): + ), + ) + ++ ++class NXTRecord(UnsupportedDNSRecord): ++ rrtype = 'NXT' ++ rfc = 2535 ++ ++ + class PTRRecord(DNSRecord): + rrtype = 'PTR' + rfc = 1035 +@@ -1450,10 +1466,6 @@ class SSHFPRecord(DNSRecord): + return tuple(values) + + +-class TARecord(UnsupportedDNSRecord): +- rrtype = 'TA' +- +- + class TLSARecord(DNSRecord): + rrtype = 'TLSA' + rfc = 6698 +@@ -1479,12 +1491,6 @@ class TLSARecord(DNSRecord): + ) + + +-class TKEYRecord(UnsupportedDNSRecord): +- rrtype = 'TKEY' +- +-class TSIGRecord(UnsupportedDNSRecord): +- rrtype = 'TSIG' +- + class TXTRecord(DNSRecord): + rrtype = 'TXT' + rfc = 1035 +@@ -1509,7 +1515,6 @@ _dns_records = ( + DHCIDRecord(), + DLVRecord(), + DNAMERecord(), +- DNSKEYRecord(), + DSRecord(), + HIPRecord(), + IPSECKEYRecord(), +@@ -1520,7 +1525,6 @@ _dns_records = ( + NAPTRRecord(), + NSRecord(), + NSECRecord(), +- NSEC3Record(), + PTRRecord(), + RRSIGRecord(), + RPRecord(), +@@ -1528,10 +1532,7 @@ _dns_records = ( + SPFRecord(), + SRVRecord(), + SSHFPRecord(), +- TARecord(), + TLSARecord(), +- TKEYRecord(), +- TSIGRecord(), + TXTRecord(), + ) + +@@ -2500,20 +2501,21 @@ class dnszone(DNSZoneBase): + 'ipapermtarget': DN('idnsname=*', 'cn=dns', api.env.basedn), + 'ipapermdefaultattr': { + 'objectclass', +- 'a6record', 'aaaarecord', 'afsdbrecord', 'arecord', +- 'certrecord', 'cn', 'cnamerecord', 'dlvrecord', 'dnamerecord', +- 'dnsclass', 'dnsttl', 'dsrecord', 'hinforecord', +- 'idnsallowdynupdate', 'idnsallowquery', 'idnsallowsyncptr', +- 'idnsallowtransfer', 'idnsforwarders', 'idnsforwardpolicy', +- 'idnsname', 'idnssecinlinesigning', 'idnssoaexpire', +- 'idnssoaminimum', 'idnssoamname', 'idnssoarefresh', +- 'idnssoaretry', 'idnssoarname', 'idnssoaserial', +- 'idnsupdatepolicy', 'idnszoneactive', 'keyrecord', 'kxrecord', ++ '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', 'idnsupdatepolicy', ++ 'idnszoneactive', 'ipseckeyrecord','keyrecord', 'kxrecord', + 'locrecord', 'managedby', 'mdrecord', 'minforecord', + 'mxrecord', 'naptrrecord', 'nsecrecord', 'nsec3paramrecord', +- 'nsrecord', 'nxtrecord', 'ptrrecord', 'rrsigrecord', +- 'sigrecord', 'srvrecord', 'sshfprecord', 'tlsarecord', +- 'txtrecord', 'unknownrecord', ++ 'nsrecord', 'nxtrecord', 'ptrrecord', 'rprecord', 'rrsigrecord', ++ 'sigrecord', 'spfrecord', 'srvrecord', 'sshfprecord', ++ 'tlsarecord', 'txtrecord', 'unknownrecord', + }, + 'replaces_system': ['Read DNS Entries'], + 'default_privileges': {'DNS Administrators', 'DNS Servers'}, +@@ -2534,20 +2536,21 @@ class dnszone(DNSZoneBase): + 'ipapermlocation': api.env.basedn, + 'ipapermtarget': DN('idnsname=*', 'cn=dns', api.env.basedn), + 'ipapermdefaultattr': { +- 'a6record', 'aaaarecord', 'afsdbrecord', 'arecord', +- 'certrecord', 'cn', 'cnamerecord', 'dlvrecord', 'dnamerecord', +- 'dnsclass', 'dnsttl', 'dsrecord', 'hinforecord', +- 'idnsallowdynupdate', 'idnsallowquery', 'idnsallowsyncptr', +- 'idnsallowtransfer', 'idnsforwarders', 'idnsforwardpolicy', +- 'idnsname', 'idnssecinlinesigning', 'idnssoaexpire', +- 'idnssoaminimum', 'idnssoamname', 'idnssoarefresh', +- 'idnssoaretry', 'idnssoarname', 'idnssoaserial', +- 'idnsupdatepolicy', 'idnszoneactive', 'keyrecord', 'kxrecord', ++ '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', 'idnsupdatepolicy', ++ 'idnszoneactive', 'ipseckeyrecord','keyrecord', 'kxrecord', + 'locrecord', 'managedby', 'mdrecord', 'minforecord', + 'mxrecord', 'naptrrecord', 'nsecrecord', 'nsec3paramrecord', +- 'nsrecord', 'nxtrecord', 'ptrrecord', 'rrsigrecord', +- 'sigrecord', 'srvrecord', 'sshfprecord', 'tlsarecord', +- 'txtrecord', 'unknownrecord', ++ 'nsrecord', 'nxtrecord', 'ptrrecord', 'rprecord', 'rrsigrecord', ++ 'sigrecord', 'spfrecord', 'srvrecord', 'sshfprecord', ++ 'tlsarecord', 'txtrecord', 'unknownrecord', + }, + 'replaces': [ + '(targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)', +-- +2.4.3 + diff --git a/SOURCES/0021-webui-prohibit-setting-rid-base-with-ipa-trust-ad-po.patch b/SOURCES/0021-webui-prohibit-setting-rid-base-with-ipa-trust-ad-po.patch deleted file mode 100644 index ebcb9ab..0000000 --- a/SOURCES/0021-webui-prohibit-setting-rid-base-with-ipa-trust-ad-po.patch +++ /dev/null @@ -1,153 +0,0 @@ -From da57475f30f086b2420652b1aeab9e2902fb8664 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Wed, 3 Sep 2014 17:23:33 +0200 -Subject: [PATCH] webui: prohibit setting rid base with ipa-trust-ad-posix type - -Base RID is no longer editable for ipa-trust-ad-posix range type - -Adder dialog: -- Range type selector was moved up because it affects a field above it - -Details page: -- Only fields relevant to range's type are visible - -https://fedorahosted.org/freeipa/ticket/4221 - -Reviewed-By: Tomas Babej ---- - install/ui/src/freeipa/idrange.js | 77 ++++++++++++++++++++++++++++++--------- - 1 file changed, 60 insertions(+), 17 deletions(-) - -diff --git a/install/ui/src/freeipa/idrange.js b/install/ui/src/freeipa/idrange.js -index 12c0b288b766c059db6b844f445fb88b5821a1db..4e5dbfa00dcf80495d8a96f7fc961b9c6676691f 100644 ---- a/install/ui/src/freeipa/idrange.js -+++ b/install/ui/src/freeipa/idrange.js -@@ -54,6 +54,11 @@ return { - 'cn', - 'iparangetype', - { -+ name: 'iparangetyperaw', -+ read_only: true, -+ visible: false -+ }, -+ { - name: 'ipabaseid', - label: '@i18n:objects.idrange.ipabaseid', - title: '@mo-param:idrange:ipabaseid:label' -@@ -80,6 +85,9 @@ return { - } - ] - } -+ ], -+ policies: [ -+ exp.idrange_policy - ] - } - ], -@@ -89,21 +97,6 @@ return { - name: 'cn' - }, - { -- name: 'ipabaseid', -- label: '@i18n:objects.idrange.ipabaseid', -- title: '@mo-param:idrange:ipabaseid:label' -- }, -- { -- name: 'ipaidrangesize', -- label: '@i18n:objects.idrange.ipaidrangesize', -- title: '@mo-param:idrange:ipaidrangesize:label' -- }, -- { -- name: 'ipabaserid', -- label: '@i18n:objects.idrange.ipabaserid', -- title: '@mo-param:idrange:ipabaserid:label' -- }, -- { - name: 'iparangetype', - $type: 'radio', - label: '@i18n:objects.idrange.type', -@@ -125,6 +118,21 @@ return { - ] - }, - { -+ name: 'ipabaseid', -+ label: '@i18n:objects.idrange.ipabaseid', -+ title: '@mo-param:idrange:ipabaseid:label' -+ }, -+ { -+ name: 'ipaidrangesize', -+ label: '@i18n:objects.idrange.ipaidrangesize', -+ title: '@mo-param:idrange:ipaidrangesize:label' -+ }, -+ { -+ name: 'ipabaserid', -+ label: '@i18n:objects.idrange.ipabaserid', -+ title: '@mo-param:idrange:ipabaserid:label' -+ }, -+ { - name: 'ipasecondarybaserid', - label: '@i18n:objects.idrange.ipasecondarybaserid', - title: '@mo-param:idrange:ipasecondarybaserid:label' -@@ -147,7 +155,9 @@ IPA.idrange_adder_policy = function(spec) { - The logic for enabling/requiring ipabaserid, ipasecondarybaserid and - ipanttrusteddomainsid is as follows: - 1) for AD ranges (range type is ipa-ad-trust or ipa-ad-trust-posix): -- * ipabaserid and ipanttrusteddomainsid are requred -+ * ipanttrusteddomainsid is required -+ * ipabaserid is required for ipa-ad-trust but disabled for -+ ipa-ad-trust-posix - * ipasecondarybaserid is disabled - 2) for local ranges - * ipanttrusteddomainsid is disabled -@@ -206,7 +216,11 @@ IPA.idrange_adder_policy = function(spec) { - var is_ad_range = (type_v === 'ipa-ad-trust' || type_v === 'ipa-ad-trust-posix'); - - if (is_ad_range) { -- require(baserid_f); -+ if (type_v === 'ipa-ad-trust') { -+ require(baserid_f); -+ } else { -+ disable(baserid_f); -+ } - require(trusteddomainsid_f); - disable(secondarybaserid_f); - } else { -@@ -230,6 +244,35 @@ IPA.idrange_adder_policy = function(spec) { - return that; - }; - -+exp.idrange_policy = function(spec) { -+ -+ spec = spec || {}; -+ var that = IPA.facet_policy(spec); -+ -+ that.post_load = function() { -+ var type_f = that.container.fields.get_field('iparangetyperaw'); -+ var widgets = that.container.widgets; -+ var type_v = type_f.get_value()[0]; -+ -+ var baserid = true; -+ var secrid = true; -+ var sid = true; -+ -+ if (type_v === 'ipa-local') { -+ sid = false; -+ } else if (type_v === 'ipa-ad-trust-posix') { -+ baserid = secrid = false; -+ } else if (type_v === 'ipa-ad-trust') { -+ secrid = false; -+ } -+ -+ widgets.get_widget('details.ipabaserid').set_visible(baserid); -+ widgets.get_widget('details.ipasecondarybaserid').set_visible(secrid); -+ widgets.get_widget('details.ipanttrusteddomainsid').set_visible(sid); -+ }; -+ return that; -+}; -+ - exp.entity_spec = make_spec(); - exp.register = function() { - var e = reg.entity; --- -2.1.0 - diff --git a/SOURCES/0022-Fix-CA-certificate-backup-and-restore.patch b/SOURCES/0022-Fix-CA-certificate-backup-and-restore.patch deleted file mode 100644 index c41a1f3..0000000 --- a/SOURCES/0022-Fix-CA-certificate-backup-and-restore.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 9037c4d84bcf9cde48beb83d69f05c3733106c2d Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 16:24:22 +0000 -Subject: [PATCH] Fix CA certificate backup and restore - -Backup and restore /etc/pki/ca-trust/source/ipa.p11-kit. - -Create /etc/ipa/nssdb after restore if necessary. - -https://fedorahosted.org/freeipa/ticket/4711 - -Reviewed-By: Petr Viktorin ---- - ipaplatform/base/paths.py | 2 +- - ipaplatform/base/tasks.py | 9 +++++++++ - ipaplatform/redhat/tasks.py | 43 ++++++++++++++++++++-------------------- - ipaserver/install/ipa_backup.py | 2 ++ - ipaserver/install/ipa_restore.py | 35 +++++++++++++++++++++++++++++++- - 5 files changed, 67 insertions(+), 24 deletions(-) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index af502628e493ad7b4d8d30ed1acb98bba8cb39e4..e28147ab4aa1faa3859c38665a83f57fb67e96b2 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -92,7 +92,7 @@ class BasePathNamespace(object): - PAM_LDAP_CONF = "/etc/pam_ldap.conf" - PASSWD = "/etc/passwd" - ETC_PKI_CA_DIR = "/etc/pki-ca" -- SYSTEMWIDE_CA_STORE = "/etc/pki/ca-trust/source/anchors/" -+ SYSTEMWIDE_IPA_CA_CRT = "/etc/pki/ca-trust/source/anchors/ipa-ca.crt" - IPA_P11_KIT = "/etc/pki/ca-trust/source/ipa.p11-kit" - NSS_DB_DIR = "/etc/pki/nssdb" - PKI_TOMCAT = "/etc/pki/pki-tomcat" -diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py -index 408447e43cd36d0cdf11a1877b3bc9880c4785de..a6684d7653d6de8202a489edb1f7a38f4b344bbc 100644 ---- a/ipaplatform/base/tasks.py -+++ b/ipaplatform/base/tasks.py -@@ -49,6 +49,15 @@ class BaseTaskNamespace(object): - - return - -+ def reload_systemwide_ca_store(self): -+ """ -+ Reloads the systemwide CA store. -+ -+ Returns True if the operation succeeded, False otherwise. -+ """ -+ -+ return True -+ - def insert_ca_certs_into_systemwide_ca_store(self, ca_certs): - """ - Adds CA certificates from 'ca_certs' to the systemwide CA store -diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py -index 555516d90a6d1a7d3d9aced5de82a5c1efe6b8c2..4977e1c7c496e36d56110bcdf040ab5c932d31a2 100644 ---- a/ipaplatform/redhat/tasks.py -+++ b/ipaplatform/redhat/tasks.py -@@ -158,8 +158,19 @@ class RedHatTaskNamespace(BaseTaskNamespace): - auth_config.add_option("nostart") - auth_config.execute() - -+ def reload_systemwide_ca_store(self): -+ try: -+ ipautil.run([paths.UPDATE_CA_TRUST]) -+ except CalledProcessError, e: -+ root_logger.error( -+ "Could not update systemwide CA trust database: %s", e) -+ return False -+ else: -+ root_logger.info("Systemwide CA database updated.") -+ return True -+ - def insert_ca_certs_into_systemwide_ca_store(self, ca_certs): -- new_cacert_path = os.path.join(paths.SYSTEMWIDE_CA_STORE, 'ipa-ca.crt') -+ new_cacert_path = paths.SYSTEMWIDE_IPA_CA_CRT - - if os.path.exists(new_cacert_path): - try: -@@ -248,24 +259,18 @@ class RedHatTaskNamespace(BaseTaskNamespace): - f.close() - - # Add the CA to the systemwide CA trust database -- try: -- ipautil.run([paths.UPDATE_CA_TRUST]) -- except CalledProcessError, e: -- root_logger.info("Failed to add CA to the systemwide " -- "CA trust database: %s" % str(e)) -- else: -- root_logger.info('Added the CA to the systemwide CA trust ' -- 'database.') -- return True -+ if not self.reload_systemwide_ca_store(): -+ return False - -- return False -+ return True - - def remove_ca_certs_from_systemwide_ca_store(self): -- ipa_ca_crt = os.path.join(paths.SYSTEMWIDE_CA_STORE, 'ipa-ca.crt') -+ result = True - update = False - - # Remove CA cert from systemwide store -- for new_cacert_path in (paths.IPA_P11_KIT, ipa_ca_crt): -+ for new_cacert_path in (paths.IPA_P11_KIT, -+ paths.SYSTEMWIDE_IPA_CA_CRT): - if not os.path.exists(new_cacert_path): - continue - try: -@@ -273,21 +278,15 @@ class RedHatTaskNamespace(BaseTaskNamespace): - except OSError, e: - root_logger.error( - "Could not remove %s: %s", new_cacert_path, e) -+ result = False - else: - update = True - - if update: -- try: -- ipautil.run([paths.UPDATE_CA_TRUST]) -- except CalledProcessError, e: -- root_logger.error( -- "Could not update systemwide CA trust database: %s", e) -+ if not self.reload_systemwide_ca_store(): - return False -- else: -- root_logger.info("Systemwide CA database updated.") -- return True - -- return False -+ return result - - def backup_and_replace_hostname(self, fstore, statestore, hostname): - old_hostname = socket.gethostname() -diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py -index 75ee243d1c8deb6f8452744df4c040fd0794250c..5d583f7e9186f20ebe8187ba70db28de0c255ae7 100644 ---- a/ipaserver/install/ipa_backup.py -+++ b/ipaserver/install/ipa_backup.py -@@ -138,6 +138,8 @@ class Backup(admintool.AdminTool): - paths.SYSCONFIG_ODS, - paths.ETC_SYSCONFIG_AUTHCONFIG, - paths.IPA_NSSDB_PWDFILE_TXT, -+ paths.IPA_P11_KIT, -+ paths.SYSTEMWIDE_IPA_CA_CRT, - paths.NSSWITCH_CONF, - paths.KRB5_KEYTAB, - paths.SSSD_CONF, -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 352a1ca2bf283c0beb8c95925c6eb9c9984b3338..8b1e80f5ed5e140ccb17ea0b63d92b6049507b74 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -26,7 +26,7 @@ import pwd - from ConfigParser import SafeConfigParser - - from ipalib import api, errors --from ipapython import version -+from ipapython import version, ipautil, certdb - from ipapython.ipautil import run, user_input - from ipapython import admintool - from ipapython.dn import DN -@@ -278,7 +278,9 @@ class Restore(admintool.AdminTool): - create_ca_user() - if options.online: - raise admintool.ScriptError('File restoration cannot be done online.') -+ self.cert_restore_prepare() - self.file_restore(options.no_logs) -+ self.cert_restore() - if 'CA' in self.backup_services: - self.__create_dogtag_log_dirs() - -@@ -660,3 +662,34 @@ class Restore(admintool.AdminTool): - tasks.set_selinux_booleans(bools) - except ipapython.errors.SetseboolError as e: - self.log.error('%s', e) -+ -+ def cert_restore_prepare(self): -+ for basename in ('cert8.db', 'key3.db', 'secmod.db', 'pwdfile.txt'): -+ filename = os.path.join(paths.IPA_NSSDB_DIR, basename) -+ try: -+ ipautil.backup_file(filename) -+ except OSError as e: -+ self.log.error("Failed to backup %s: %s" % (filename, e)) -+ -+ tasks.remove_ca_certs_from_systemwide_ca_store() -+ -+ def cert_restore(self): -+ if not os.path.exists(os.path.join(paths.IPA_NSSDB_DIR, 'cert8.db')): -+ certdb.create_ipa_nssdb() -+ ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) -+ sys_db = certdb.NSSDatabase(paths.NSS_DB_DIR) -+ for nickname, trust_flags in (('IPA CA', 'CT,C,C'), -+ ('External CA cert', 'C,,')): -+ try: -+ cert = sys_db.get_cert(nickname) -+ except RuntimeError: -+ pass -+ else: -+ try: -+ ipa_db.add_cert(cert, nickname, trust_flags) -+ except ipautil.CalledProcessError as e: -+ self.log.error( -+ "Failed to add %s to %s: %s" % -+ (nickname, paths.IPA_NSSDB_DIR, e)) -+ -+ tasks.reload_systemwide_ca_store() --- -2.1.0 - diff --git a/SOURCES/0022-ipaplatform-Add-constants-submodule.patch b/SOURCES/0022-ipaplatform-Add-constants-submodule.patch new file mode 100644 index 0000000..418c4f2 --- /dev/null +++ b/SOURCES/0022-ipaplatform-Add-constants-submodule.patch @@ -0,0 +1,147 @@ +From 9e5c97ffdc7a42f6f76affbc9a791496ba245557 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Thu, 2 Jul 2015 12:38:43 +0200 +Subject: [PATCH] ipaplatform: Add constants submodule + +Introduce a ipaplatform/constants.py file to store platform related +constants, which are not paths. + +Reviewed-By: Martin Basti +Reviewed-By: Petr Spacek +--- + Makefile | 3 ++- + freeipa.spec.in | 2 ++ + ipaplatform/base/constants.py | 11 +++++++++++ + ipaplatform/fedora/constants.py | 16 ++++++++++++++++ + ipaplatform/redhat/constants.py | 17 +++++++++++++++++ + ipaplatform/rhel/constants.py | 16 ++++++++++++++++ + 6 files changed, 64 insertions(+), 1 deletion(-) + create mode 100644 ipaplatform/base/constants.py + create mode 100644 ipaplatform/fedora/constants.py + create mode 100644 ipaplatform/redhat/constants.py + create mode 100644 ipaplatform/rhel/constants.py + +diff --git a/Makefile b/Makefile +index abf58382960099a54b8920dd0e741b9fda17682f..3c81466d3728022c1d9cf5bb216990f14a59b7e5 100644 +--- a/Makefile ++++ b/Makefile +@@ -159,10 +159,11 @@ version-update: release-update + if [ "$(SUPPORTED_PLATFORM)" != "" ]; then \ + sed -e s/__PLATFORM__/$(SUPPORTED_PLATFORM)/ \ + ipaplatform/__init__.py.in > ipaplatform/__init__.py; \ +- rm -f ipaplatform/paths.py ipaplatform/services.py ipaplatform/tasks.py; \ ++ rm -f ipaplatform/paths.py ipaplatform/services.py ipaplatform/tasks.py ipaplatform/constants.py; \ + ln -s $(SUPPORTED_PLATFORM)/paths.py ipaplatform/paths.py; \ + ln -s $(SUPPORTED_PLATFORM)/services.py ipaplatform/services.py; \ + ln -s $(SUPPORTED_PLATFORM)/tasks.py ipaplatform/tasks.py; \ ++ ln -s $(SUPPORTED_PLATFORM)/constants.py ipaplatform/constants.py; \ + fi + + if [ "$(SKIP_API_VERSION_CHECK)" != "yes" ]; then \ +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 5790f7941d2117ed95d3c99556f1579c27917270..e9ba596fec1f8d179d4f834485e35a4814db898d 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -363,6 +363,7 @@ rm -f ipapython/version.py + rm -f ipaplatform/services.py + rm -f ipaplatform/tasks.py + rm -f ipaplatform/paths.py ++rm -f ipaplatform/constants.py + make version-update + cd ipa-client; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd .. + %if ! %{ONLY_CLIENT} +@@ -385,6 +386,7 @@ rm -f ipapython/version.py + rm -f ipaplatform/services.py + rm -f ipaplatform/tasks.py + rm -f ipaplatform/paths.py ++rm -f ipaplatform/constants.py + make version-update + %if ! %{ONLY_CLIENT} + make install DESTDIR=%{buildroot} +diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py +new file mode 100644 +index 0000000000000000000000000000000000000000..70485055fa5a12fac878ace3dea11ea442ebe6be +--- /dev/null ++++ b/ipaplatform/base/constants.py +@@ -0,0 +1,11 @@ ++# ++# Copyright (C) 2015 FreeIPA Contributors see COPYING for license ++# ++ ++''' ++This base platform module exports platform dependant constants. ++''' ++ ++ ++class BaseConstantsNamespace(object): ++ pass +diff --git a/ipaplatform/fedora/constants.py b/ipaplatform/fedora/constants.py +new file mode 100644 +index 0000000000000000000000000000000000000000..ce03f58cf95be1a72a9ce3da65e6d21ef193cefe +--- /dev/null ++++ b/ipaplatform/fedora/constants.py +@@ -0,0 +1,16 @@ ++# ++# Copyright (C) 2015 FreeIPA Contributors see COPYING for license ++# ++ ++''' ++This Fedora base platform module exports platform related constants. ++''' ++ ++# Fallback to default constant definitions ++from ipaplatform.redhat.constants import RedHatConstantsNamespace ++ ++ ++class FedoraConstantsNamespace(RedHatConstantsNamespace): ++ pass ++ ++constants = FedoraConstantsNamespace() +diff --git a/ipaplatform/redhat/constants.py b/ipaplatform/redhat/constants.py +new file mode 100644 +index 0000000000000000000000000000000000000000..7209947f8afbd688b02c8b134d33185e497befe0 +--- /dev/null ++++ b/ipaplatform/redhat/constants.py +@@ -0,0 +1,17 @@ ++# ++# Copyright (C) 2015 FreeIPA Contributors see COPYING for license ++# ++ ++''' ++This Red Hat OS family base platform module exports default platform ++related constants for the Red Hat OS family-based systems. ++''' ++ ++# Fallback to default path definitions ++from ipaplatform.base.constants import BaseConstantsNamespace ++ ++ ++class RedHatConstantsNamespace(BaseConstantsNamespace): ++ pass ++ ++constants = RedHatConstantsNamespace() +diff --git a/ipaplatform/rhel/constants.py b/ipaplatform/rhel/constants.py +new file mode 100644 +index 0000000000000000000000000000000000000000..eaca48030fa28804c70c161b07228646a95fc1a3 +--- /dev/null ++++ b/ipaplatform/rhel/constants.py +@@ -0,0 +1,16 @@ ++# ++# Copyright (C) 2015 FreeIPA Contributors see COPYING for license ++# ++ ++''' ++This RHEL base platform module exports platform related constants. ++''' ++ ++# Fallback to default constant definitions ++from ipaplatform.redhat.constants import RedHatConstantsNamespace ++ ++ ++class RHELConstantsNamespace(RedHatConstantsNamespace): ++ pass ++ ++constants = RHELConstantsNamespace() +-- +2.4.3 + diff --git a/SOURCES/0023-DNS-check-if-DNS-package-is-installed.patch b/SOURCES/0023-DNS-check-if-DNS-package-is-installed.patch new file mode 100644 index 0000000..cd483f2 --- /dev/null +++ b/SOURCES/0023-DNS-check-if-DNS-package-is-installed.patch @@ -0,0 +1,170 @@ +From 9bf3e3efe51ccda418afd2340a113f39144851c3 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 1 Jul 2015 15:05:45 +0200 +Subject: [PATCH] DNS: check if DNS package is installed + +Instead of separate checking of DNS required packages, we need just +check if IPA DNS package is installed. + +https://fedorahosted.org/freeipa/ticket/4058 + +Reviewed-By: Martin Babinsky +Reviewed-By: Petr Spacek +Reviewed-By: Tomas Babej +--- + ipaplatform/base/constants.py | 2 +- + ipaplatform/base/paths.py | 1 + + ipaplatform/rhel/constants.py | 2 +- + ipaserver/install/bindinstance.py | 19 +------------------ + ipaserver/install/dns.py | 11 ++++++----- + ipaserver/install/dnskeysyncinstance.py | 6 ------ + ipaserver/install/opendnssecinstance.py | 8 -------- + 7 files changed, 10 insertions(+), 39 deletions(-) + +diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py +index 70485055fa5a12fac878ace3dea11ea442ebe6be..cef829e2d3886db00ae6d0299ddcf325d1add80e 100644 +--- a/ipaplatform/base/constants.py ++++ b/ipaplatform/base/constants.py +@@ -8,4 +8,4 @@ This base platform module exports platform dependant constants. + + + class BaseConstantsNamespace(object): +- pass ++ IPA_DNS_PACKAGE_NAME = "freeipa-server-dns" +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 5756040172126438d42275b734f4d766d53048fe..4c93c1f7162b0aeb4f798ef84e1ac8db4573518b 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -218,6 +218,7 @@ class BasePathNamespace(object): + GROUPADD = "/usr/sbin/groupadd" + HTTPD = "/usr/sbin/httpd" + IPA_CLIENT_INSTALL = "/usr/sbin/ipa-client-install" ++ IPA_DNS_INSTALL = "/usr/sbin/ipa-dns-install" + SBIN_IPA_JOIN = "/usr/sbin/ipa-join" + IPA_REPLICA_CONNCHECK = "/usr/sbin/ipa-replica-conncheck" + IPA_RMKEYTAB = "/usr/sbin/ipa-rmkeytab" +diff --git a/ipaplatform/rhel/constants.py b/ipaplatform/rhel/constants.py +index eaca48030fa28804c70c161b07228646a95fc1a3..17abde1f861778bec83067cb01e9a1faae325527 100644 +--- a/ipaplatform/rhel/constants.py ++++ b/ipaplatform/rhel/constants.py +@@ -11,6 +11,6 @@ from ipaplatform.redhat.constants import RedHatConstantsNamespace + + + class RHELConstantsNamespace(RedHatConstantsNamespace): +- pass ++ IPA_DNS_PACKAGE_NAME = "ipa-server-dns" + + constants = RHELConstantsNamespace() +diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py +index 2228342dc40ee415d1adf2687a7ae91a5963d3c7..9705e845a76191a252bfa963b54d9c31d83ad18e 100644 +--- a/ipaserver/install/bindinstance.py ++++ b/ipaserver/install/bindinstance.py +@@ -62,25 +62,8 @@ named_conf_arg_options_template_nonstr = "%(indent)s%(name)s %(value)s;\n" + named_conf_include_re = re.compile(r'\s*include\s+"(?P)"\s*;') + named_conf_include_template = "include \"%(path)s\";\n" + +-def check_inst(unattended): +- has_bind = True +- named = services.knownservices.named +- if not os.path.exists(named.get_binary_path()): +- print "BIND was not found on this system" +- print ("Please install the '%s' package and start the installation again" +- % named.get_package_name()) +- has_bind = False +- +- # Also check for the LDAP BIND plug-in +- if not os.path.exists(paths.BIND_LDAP_SO) and \ +- not os.path.exists(paths.BIND_LDAP_SO_64): +- print "The BIND LDAP plug-in was not found on this system" +- print "Please install the 'bind-dyndb-ldap' package and start the installation again" +- has_bind = False +- +- if not has_bind: +- return False + ++def check_inst(unattended): + if not unattended and os.path.exists(NAMED_CONF): + msg = "Existing BIND configuration detected, overwrite?" + return ipautil.user_input(msg, False) +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index d22bce7a7cd2e0e8a7ffe0ab4aa496634465903b..9430d189978b0984b0b71d7d754516a4135053fb 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -9,6 +9,7 @@ from subprocess import CalledProcessError + from ipalib import api + from ipalib import errors + from ipaplatform.paths import paths ++from ipaplatform.constants import constants + from ipaplatform import services + from ipapython import ipautil + from ipapython import sysrestore +@@ -96,6 +97,10 @@ def install_check(standalone, replica, options, hostname): + global reverse_zones + fstore = sysrestore.FileStore(paths.SYSRESTORE) + ++ if not ipautil.file_exists(paths.IPA_DNS_INSTALL): ++ raise RuntimeError("Integrated DNS requires '%s' package" % ++ constants.IPA_DNS_PACKAGE_NAME) ++ + if standalone: + print "==============================================================================" + print "This program will setup DNS for the FreeIPA Server." +@@ -141,8 +146,7 @@ def install_check(standalone, replica, options, hostname): + sys.exit("Aborted") + + # Check bind packages are installed +- if not (bindinstance.check_inst(options.unattended) and +- dnskeysyncinstance.check_inst()): ++ if not bindinstance.check_inst(options.unattended): + sys.exit("Aborting installation.") + + if options.disable_dnssec_master: +@@ -177,9 +181,6 @@ def install_check(standalone, replica, options, hostname): + sys.exit("Only one DNSSEC key master is supported in current " + "version.") + +- # check opendnssec packages are installed +- if not opendnssecinstance.check_inst(): +- sys.exit("Aborting installation") + if options.kasp_db_file: + dnskeysyncd = services.service('ipa-dnskeysyncd') + +diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py +index eb6d07f014bce296a5b094f499194286c31c2489..7d1351ccc57a5dbd7d537741545ad44d0dcd5eb1 100644 +--- a/ipaserver/install/dnskeysyncinstance.py ++++ b/ipaserver/install/dnskeysyncinstance.py +@@ -30,12 +30,6 @@ softhsm_token_label = u'ipaDNSSEC' + softhsm_slot = 0 + replica_keylabel_template = u"dnssec-replica:%s" + +-def check_inst(): +- if not os.path.exists(paths.DNSSEC_KEYFROMLABEL): +- print ("Please install the 'bind-pkcs11-utils' package and start " +- "the installation again") +- return False +- return True + + def dnssec_container_exists(fqdn, suffix, dm_password=None, ldapi=False, + realm=None, autobind=ipaldap.AUTOBIND_DISABLED): +diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py +index d68691fa32f135c7527ce28ed771757eadab4831..0f1af828ea245046330fdfab77db130ca14faba3 100644 +--- a/ipaserver/install/opendnssecinstance.py ++++ b/ipaserver/install/opendnssecinstance.py +@@ -55,14 +55,6 @@ def get_dnssec_key_masters(conn): + return keymasters_list + + +-def check_inst(): +- if not os.path.exists(paths.ODS_KSMUTIL): +- print ("Please install the 'opendnssec' package and start " +- "the installation again") +- return False +- return True +- +- + class OpenDNSSECInstance(service.Service): + def __init__(self, fstore=None, dm_password=None, ldapi=False, + start_tls=False, autobind=ipaldap.AUTOBIND_ENABLED): +-- +2.4.3 + diff --git a/SOURCES/0023-Fix-DNS-installer-adds-invalid-zonemgr-email.patch b/SOURCES/0023-Fix-DNS-installer-adds-invalid-zonemgr-email.patch deleted file mode 100644 index 0de6d63..0000000 --- a/SOURCES/0023-Fix-DNS-installer-adds-invalid-zonemgr-email.patch +++ /dev/null @@ -1,43 +0,0 @@ -From cb9593d1571ed8704ebe33084463b2462a30cab9 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 7 Nov 2014 12:45:43 +0100 -Subject: [PATCH] Fix: DNS installer adds invalid zonemgr email - -Installer adds zonemgr as relative (and invalid) address. -This fix force installer to use absolute email. - -Ticket: https://fedorahosted.org/freeipa/ticket/4707 -Reviewed-By: David Kupka ---- - install/share/bind.zone.db.template | 2 +- - ipaserver/install/bindinstance.py | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/install/share/bind.zone.db.template b/install/share/bind.zone.db.template -index 6795bb01a7d8003a26dcc8a1cbc337550b3c296c..ec175c60825869ea9b86f7d1351a96189028b5d4 100644 ---- a/install/share/bind.zone.db.template -+++ b/install/share/bind.zone.db.template -@@ -1,6 +1,6 @@ - $$ORIGIN $DOMAIN. - $$TTL 86400 --@ IN SOA $DOMAIN. $ZONEMGR. ( -+@ IN SOA $DOMAIN. $ZONEMGR ( - 01 ; serial - 3H ; refresh - 15M ; retry -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 6cf018e9cda3734a99a8ac5ac1df134e9e4c2293..16894de0a009aacb123cf76072f2556aebc5722f 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -563,7 +563,7 @@ class BindInstance(service.Service): - self.no_dnssec_validation=no_dnssec_validation - - if not zonemgr: -- self.zonemgr = 'hostmaster.%s' % self.domain -+ self.zonemgr = 'hostmaster.%s' % normalize_zone(self.domain) - else: - self.zonemgr = normalize_zonemgr(zonemgr) - --- -2.1.0 - diff --git a/SOURCES/0024-dcerpc-Expand-explanation-for-WERR_ACCESS_DENIED.patch b/SOURCES/0024-dcerpc-Expand-explanation-for-WERR_ACCESS_DENIED.patch new file mode 100644 index 0000000..b400a03 --- /dev/null +++ b/SOURCES/0024-dcerpc-Expand-explanation-for-WERR_ACCESS_DENIED.patch @@ -0,0 +1,76 @@ +From c4859813a5fd89082c9c05a3808f9b6cb97ca5d0 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 15 Jul 2015 15:38:50 +0200 +Subject: [PATCH] dcerpc: Expand explanation for WERR_ACCESS_DENIED + +It's possible for AD to contact a wrong IPA server in case the DNS +SRV records on the AD sides are not properly configured. + +Mention this case in the error message as well. + +https://fedorahosted.org/freeipa/ticket/5013 + +Reviewed-By: Petr Vobornik +--- + ipaserver/dcerpc.py | 36 +++++++++++++++++++++++++++++------- + 1 file changed, 29 insertions(+), 7 deletions(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index a1da0a641064f59a79639d97489ff73181787a4a..97f6c1694c20f26af0861b86a1ae1adf7a970a59 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -1084,22 +1084,44 @@ class TrustDomainInstance(object): + result = retrieve_netlogon_info_2(None, self, + netlogon.NETLOGON_CONTROL_TC_VERIFY, + another_domain.info['dns_domain']) +- if (result and (result.flags and netlogon.NETLOGON_VERIFY_STATUS_RETURNED)): +- if (result.pdc_connection_status[0] != 0) and (result.tc_connection_status[0] != 0): ++ ++ if result and result.flags and netlogon.NETLOGON_VERIFY_STATUS_RETURNED: ++ if result.pdc_connection_status[0] != 0 and result.tc_connection_status[0] != 0: + if result.pdc_connection_status[1] == "WERR_ACCESS_DENIED": + # Most likely AD DC hit another IPA replica which yet has no trust secret replicated ++ + # Sleep and repeat again + self.validation_attempts += 1 + if self.validation_attempts < 10: + sleep(5) + return self.verify_trust(another_domain) +- raise errors.ACIError( +- info=_('IPA master denied trust validation requests from AD DC ' +- '%(count)d times. Most likely AD DC contacted a replica ' +- 'that has no trust information replicated yet.') +- % dict(count=self.validation_attempts)) ++ ++ # If we get here, we already failed 10 times ++ srv_record_templates = ( ++ '_ldap._tcp.%s', ++ '_ldap._tcp.Default-First-Site-Name._sites.dc._msdcs.%s' ++ ) ++ ++ srv_records = ', '.join( ++ [srv_record % api.env.domain ++ for srv_record in srv_record_templates] ++ ) ++ ++ error_message = _( ++ 'IPA master denied trust validation requests from AD ' ++ 'DC %(count)d times. Most likely AD DC contacted a ' ++ 'replica that has no trust information replicated ' ++ 'yet. Additionally, please check that AD DNS is able ' ++ 'to resolve %(records)s SRV records to the correct ' ++ 'IPA server.') % dict(count=self.validation_attempts, ++ records=srv_records) ++ ++ raise errors.ACIError(info=error_message) ++ + raise assess_dcerpc_exception(*result.pdc_connection_status) ++ + return True ++ + return False + + +-- +2.4.3 + diff --git a/SOURCES/0024-ipaplatform-Use-the-dirsrv-service-not-target.patch b/SOURCES/0024-ipaplatform-Use-the-dirsrv-service-not-target.patch deleted file mode 100644 index fc46b34..0000000 --- a/SOURCES/0024-ipaplatform-Use-the-dirsrv-service-not-target.patch +++ /dev/null @@ -1,37 +0,0 @@ -From f16e7b3a95d48afc0e798055e8ff4ac9efd9ce28 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Tue, 11 Nov 2014 16:07:37 +0100 -Subject: [PATCH] ipaplatform: Use the dirsrv service, not target - -IPA only uses one instance of the directory server. When an instance -is not specified to a call to service.start/stop/restart/..., -use IPA's instance. - -Stopping a systemd service is synchronous (bby default), but stopping -a target is not. This will change ensures that the directory server -is actually down when stop() finishes. - -https://fedorahosted.org/freeipa/ticket/4709 - -Reviewed-By: Jan Cholasta ---- - ipaplatform/base/services.py | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py -index 961c368e6b4d81d337cf0a8601075f052352ecbf..370b628c78a65591dec09db25f9f7545f920d795 100644 ---- a/ipaplatform/base/services.py -+++ b/ipaplatform/base/services.py -@@ -187,8 +187,7 @@ class SystemdService(PlatformService): - elements = self.systemd_name.split("@") - - # Make sure the correct DS instance is returned -- if (elements[0] == 'dirsrv' and not instance_name and -- operation == 'is-active'): -+ if elements[0] == 'dirsrv' and not instance_name: - - return ('dirsrv@%s.service' - % str(self.api.env.realm.replace('.', '-'))) --- -2.1.0 - diff --git a/SOURCES/0025-Fix-DNS-policy-upgrade-raises-asertion-error.patch b/SOURCES/0025-Fix-DNS-policy-upgrade-raises-asertion-error.patch deleted file mode 100644 index a56a044..0000000 --- a/SOURCES/0025-Fix-DNS-policy-upgrade-raises-asertion-error.patch +++ /dev/null @@ -1,29 +0,0 @@ -From a7fdb85235909e8498f0b8b257bbab5825c3c338 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 7 Nov 2014 15:09:29 +0100 -Subject: [PATCH] Fix: DNS policy upgrade raises asertion error - -Ticket: https://fedorahosted.org/freeipa/ticket/4708 -Reviewed-By: Jan Cholasta ---- - ipaserver/install/plugins/dns.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py -index 1aef837f63176cd307868c726460485fd4a004ed..62cf588d27155acb03026f69ea09ff15582d26dc 100644 ---- a/ipaserver/install/plugins/dns.py -+++ b/ipaserver/install/plugins/dns.py -@@ -86,7 +86,9 @@ class update_dnszones(PostUpdate): - api.env.realm) - - if update: -- api.Command.dnszone_mod(zone[u'idnsname'][0], **update) -+ # FIXME: https://fedorahosted.org/freeipa/ticket/4722 -+ api.Command.dnszone_mod(zone[u'idnsname'][0].make_absolute(), -+ **update) - - return (False, False, []) - --- -2.1.0 - diff --git a/SOURCES/0025-dcerpc-Fix-UnboundLocalError-for-ccache_name.patch b/SOURCES/0025-dcerpc-Fix-UnboundLocalError-for-ccache_name.patch new file mode 100644 index 0000000..27e23ca --- /dev/null +++ b/SOURCES/0025-dcerpc-Fix-UnboundLocalError-for-ccache_name.patch @@ -0,0 +1,26 @@ +From 45cbe4b94e59bcfa3d8968595a780bdb9f3af2f2 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 22 Jul 2015 14:29:35 +0200 +Subject: [PATCH] dcerpc: Fix UnboundLocalError for ccache_name + +Reviewed-By: Alexander Bokovoy +--- + ipaserver/dcerpc.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index 97f6c1694c20f26af0861b86a1ae1adf7a970a59..c0aa322c5d59e7d17a4ceb90448b397613284e38 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -644,6 +644,8 @@ class DomainValidator(object): + Returns LDAP result or None. + """ + ++ ccache_name = None ++ + if self._admin_creds: + (ccache_name, principal) = self.kinit_as_administrator(info['dns_domain']) + +-- +2.4.3 + diff --git a/SOURCES/0026-Fix-upgrade-referint-plugin.patch b/SOURCES/0026-Fix-upgrade-referint-plugin.patch deleted file mode 100644 index d72fba0..0000000 --- a/SOURCES/0026-Fix-upgrade-referint-plugin.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 822910bb85c4dedff39faff142e645c5f2922984 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 7 Nov 2014 13:28:01 +0100 -Subject: [PATCH] Fix upgrade referint plugin - -Mixing 'Old' and 'New' attr style for referential integrity plugin causes errors. -Now old setting are migrated to new style setting before upgrade - -Ticket: https://fedorahosted.org/freeipa/ticket/4622 -Reviewed-By: David Kupka ---- - install/updates/25-referint.update | 13 +--- - ipaserver/install/plugins/Makefile.am | 1 + - ipaserver/install/plugins/update_referint.py | 90 ++++++++++++++++++++++++++++ - 3 files changed, 92 insertions(+), 12 deletions(-) - create mode 100644 ipaserver/install/plugins/update_referint.py - -diff --git a/install/updates/25-referint.update b/install/updates/25-referint.update -index a43d21ad5152358cb939c3545f0eef9d251e7fe0..609eaba74f0fcde6ce875093587315681fbd4584 100644 ---- a/install/updates/25-referint.update -+++ b/install/updates/25-referint.update -@@ -1,19 +1,8 @@ - # Expand attributes checked by Referential Integrity plugin - # pres and eq indexes defined in 20-indices.update must be set for all these - # attributes -+# NOTE: migration to new style is done in update_referint.py - dn: cn=referential integrity postoperation,cn=plugins,cn=config --remove: nsslapd-pluginArg7: manager --remove: nsslapd-pluginArg8: secretary --remove: nsslapd-pluginArg9: memberuser --remove: nsslapd-pluginArg10: memberhost --remove: nsslapd-pluginArg11: sourcehost --remove: nsslapd-pluginArg12: memberservice --remove: nsslapd-pluginArg13: managedby --remove: nsslapd-pluginArg14: memberallowcmd --remove: nsslapd-pluginArg15: memberdenycmd --remove: nsslapd-pluginArg16: ipasudorunas --remove: nsslapd-pluginArg17: ipasudorunasgroup --remove: nsslapd-pluginArg18: ipatokenradiusconfiglink - add: referint-membership-attr: manager - add: referint-membership-attr: secretary - add: referint-membership-attr: memberuser -diff --git a/ipaserver/install/plugins/Makefile.am b/ipaserver/install/plugins/Makefile.am -index 635877d8c2160a91208276498cdb4cd9bc82d56b..d651297ac141b0f05831e7fabbb9b561cdd239c7 100644 ---- a/ipaserver/install/plugins/Makefile.am -+++ b/ipaserver/install/plugins/Makefile.am -@@ -11,6 +11,7 @@ app_PYTHON = \ - update_services.py \ - update_anonymous_aci.py \ - update_pacs.py \ -+ update_referint.py \ - ca_renewal_master.py \ - update_uniqueness.py \ - $(NULL) -diff --git a/ipaserver/install/plugins/update_referint.py b/ipaserver/install/plugins/update_referint.py -new file mode 100644 -index 0000000000000000000000000000000000000000..1b7411035b27ebba04246a7ee6f220d470b46688 ---- /dev/null -+++ b/ipaserver/install/plugins/update_referint.py -@@ -0,0 +1,90 @@ -+# -+# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -+# -+ -+from ipaserver.install.plugins import MIDDLE -+from ipaserver.install.plugins.baseupdate import PreUpdate -+from ipalib import api, errors -+from ipapython.dn import DN -+from ipapython.ipa_log_manager import root_logger -+ -+class update_referint(PreUpdate): -+ """ -+ Update referential integrity configuration to new style -+ http://directory.fedoraproject.org/docs/389ds/design/ri-plugin-configuration.html -+ -+ old attr -> new attr -+ nsslapd-pluginArg0 -> referint-update-delay -+ nsslapd-pluginArg1 -> referint-logfile -+ nsslapd-pluginArg2 -> referint-logchanges -+ nsslapd-pluginArg3..N -> referint-membership-attr [3..N] -+ -+ Old and new style cannot be mixed, all nslapd-pluginArg* attrs have to be removed -+ """ -+ -+ order = MIDDLE -+ -+ referint_dn = DN(('cn', 'referential integrity postoperation'), -+ ('cn', 'plugins'), ('cn', 'config')) -+ -+ def execute(self, **options): -+ -+ root_logger.debug("Upgrading referential integrity plugin configuration") -+ ldap = self.obj.backend -+ try: -+ entry = ldap.get_entry(self.referint_dn) -+ except errors.NotFound: -+ root_logger.error("Referential integrity configuration not found") -+ return False, False, [] -+ -+ referint_membership_attrs = [] -+ -+ root_logger.debug("Initial value: %s", repr(entry)) -+ -+ # nsslapd-pluginArg0 -> referint-update-delay -+ update_delay = entry.get('nsslapd-pluginArg0') -+ if update_delay: -+ root_logger.debug("add: referint-update-delay: %s", update_delay) -+ entry['referint-update-delay'] = update_delay -+ entry['nsslapd-pluginArg0'] = None -+ else: -+ root_logger.info("Plugin already uses new style, skipping") -+ return False, False, [] -+ -+ # nsslapd-pluginArg1 -> referint-logfile -+ logfile = entry.get('nsslapd-pluginArg1') -+ if logfile: -+ root_logger.debug("add: referint-logfile: %s", logfile) -+ entry['referint-logfile'] = logfile -+ entry['nsslapd-pluginArg1'] = None -+ -+ # nsslapd-pluginArg2 -> referint-logchanges -+ logchanges = entry.get('nsslapd-pluginArg2') -+ if logchanges: -+ root_logger.debug("add: referint-logchanges: %s", logchanges) -+ entry['referint-logchanges'] = logchanges -+ entry['nsslapd-pluginArg2'] = None -+ -+ # nsslapd-pluginArg3..N -> referint-membership-attr [3..N] -+ for key in entry.keys(): -+ if key.lower().startswith('nsslapd-pluginarg'): -+ arg_val = entry.single_value[key] -+ if arg_val: -+ referint_membership_attrs.append(arg_val) -+ entry[key] = None -+ -+ if referint_membership_attrs: -+ # entry['referint-membership-attr'] is None, plugin doesn't allow -+ # mixing old and new style -+ entry['referint-membership-attr'] = referint_membership_attrs -+ -+ root_logger.debug("Final value: %s", repr(entry)) -+ try: -+ ldap.update_entry(entry) -+ except errors.EmptyModlist: -+ root_logger.debug("No modifications required") -+ return False, False, [] -+ -+ return False, True, [] -+ -+api.register(update_referint) --- -2.1.0 - diff --git a/SOURCES/0026-fix-broken-search-for-users-by-their-manager.patch b/SOURCES/0026-fix-broken-search-for-users-by-their-manager.patch new file mode 100644 index 0000000..be8fffb --- /dev/null +++ b/SOURCES/0026-fix-broken-search-for-users-by-their-manager.patch @@ -0,0 +1,72 @@ +From 29d63aa08fc648c3dfbc9ae4cc74991eba2fb7a0 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 23 Jul 2015 10:44:08 +0200 +Subject: [PATCH] fix broken search for users by their manager + +The patch fixes incorrect construction of search filter when using `ipa +user-find` with '--manager' option. + +https://fedorahosted.org/freeipa/ticket/5146 + +Reviewed-By: Tomas Babej +--- + ipalib/plugins/baseuser.py | 8 ++++++++ + ipalib/plugins/stageuser.py | 7 ------- + ipalib/plugins/user.py | 4 ---- + 3 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/ipalib/plugins/baseuser.py b/ipalib/plugins/baseuser.py +index 9068ef0fd266a4460697ee45f29c80b74662fab2..bd66cf5a3e3a4e6c18d1a54408f969668c834fab 100644 +--- a/ipalib/plugins/baseuser.py ++++ b/ipalib/plugins/baseuser.py +@@ -561,6 +561,14 @@ class baseuser_find(LDAPSearch): + """ + Prototype command plugin to be implemented by real plugin + """ ++ def args_options_2_entry(self, *args, **options): ++ newoptions = {} ++ self.common_enhance_options(newoptions, **options) ++ options.update(newoptions) ++ ++ return super(baseuser_find, self).args_options_2_entry( ++ *args, **options) ++ + def common_enhance_options(self, newoptions, **options): + # assure the manager attr is a dn, not just a bare uid + manager = options.get('manager') +diff --git a/ipalib/plugins/stageuser.py b/ipalib/plugins/stageuser.py +index 6cbc8f4ab07f2c1172f2b2c45bfe8f30a74938b3..49a762a922b21bd6d0824787d9305417f5e47ee6 100644 +--- a/ipalib/plugins/stageuser.py ++++ b/ipalib/plugins/stageuser.py +@@ -449,13 +449,6 @@ class stageuser_find(baseuser_find): + member_attributes = ['memberof'] + has_output_params = baseuser_find.has_output_params + stageuser_output_params + +- def execute(self, *args, **options): +- newoptions = {} +- self.common_enhance_options(newoptions, **options) +- options.update(newoptions) +- +- return super(stageuser_find, self).execute(self, *args, **options) +- + def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options): + assert isinstance(base_dn, DN) + +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 9bd7bf7e5242234ead4c39a6346e57865b2e2124..206b380efb6472fb040dde33ac80e3f66c00c138 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -730,10 +730,6 @@ class user_find(baseuser_find): + return ("(&(objectclass=posixaccount)(krbprincipalname=%s))"%\ + getattr(context, 'principal'), base_dn, scope) + +- newoptions = {} +- self.common_enhance_options(newoptions, **options) +- options.update(newoptions) +- + preserved = options.get('preserved', False) + if preserved is None: + base_dn = self.api.env.basedn +-- +2.4.3 + diff --git a/SOURCES/0027-Upgrade-fix-trusts-objectclass-violationi.patch b/SOURCES/0027-Upgrade-fix-trusts-objectclass-violationi.patch deleted file mode 100644 index e107203..0000000 --- a/SOURCES/0027-Upgrade-fix-trusts-objectclass-violationi.patch +++ /dev/null @@ -1,63 +0,0 @@ -From faa47e835213aaeff8ad4fa73b2bc20735615b37 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Mon, 10 Nov 2014 14:13:07 +0100 -Subject: [PATCH] Upgrade: fix trusts objectclass violationi - -Execute updates in proper ordering. -Curently ldap-updater implementation doesnt allow better fix. - -Ticket: https://fedorahosted.org/freeipa/ticket/4680 -Reviewed-By: David Kupka ---- - install/updates/59-trusts-sysacount.update | 8 ++++++++ - install/updates/60-trusts.update | 6 ------ - install/updates/Makefile.am | 1 + - 3 files changed, 9 insertions(+), 6 deletions(-) - create mode 100644 install/updates/59-trusts-sysacount.update - -diff --git a/install/updates/59-trusts-sysacount.update b/install/updates/59-trusts-sysacount.update -new file mode 100644 -index 0000000000000000000000000000000000000000..b90de80d27b36c9a7bfd3b358338a0a79d969813 ---- /dev/null -+++ b/install/updates/59-trusts-sysacount.update -@@ -0,0 +1,8 @@ -+# this update must be applied before 60-trusts.update, because current -+# implementation of ipa-ldap-updater doesn't keep the order of updates in -+# filesets -+dn: cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX -+add: objectClass: nestedgroup -+default: objectClass: GroupOfNames -+default: objectClass: top -+default: cn: adtrust agents -diff --git a/install/updates/60-trusts.update b/install/updates/60-trusts.update -index 9dabc806e2f747c47ab809cd2ed2150b2a13c2a6..79caa837a55eae0e05e1a94f3eabdda7b2b9cc38 100644 ---- a/install/updates/60-trusts.update -+++ b/install/updates/60-trusts.update -@@ -10,12 +10,6 @@ default: member: uid=admin,cn=users,cn=accounts,$SUFFIX - default: nsAccountLock: FALSE - default: ipaUniqueID: autogenerate - --dn: cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX --add: objectClass: nestedgroup --default: objectClass: GroupOfNames --default: objectClass: top --default: cn: adtrust agents -- - dn: cn=ADTrust Agents,cn=privileges,cn=pbac,$SUFFIX - default: objectClass: top - default: objectClass: groupofnames -diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am -index e62a64cea925aaeae9d013ab01a89371c727a6fd..255586c6de1cab52a526c1ca82b4720adf998eee 100644 ---- a/install/updates/Makefile.am -+++ b/install/updates/Makefile.am -@@ -41,6 +41,7 @@ app_DATA = \ - 50-nis.update \ - 50-ipaconfig.update \ - 55-pbacmemberof.update \ -+ 59-trusts-sysacount.update \ - 60-trusts.update \ - 61-trusts-s4u2proxy.update \ - 62-ranges.update \ --- -2.1.0 - diff --git a/SOURCES/0027-dcerpc-Add-get_trusted_domain_object_type-method.patch b/SOURCES/0027-dcerpc-Add-get_trusted_domain_object_type-method.patch new file mode 100644 index 0000000..d9aaad1 --- /dev/null +++ b/SOURCES/0027-dcerpc-Add-get_trusted_domain_object_type-method.patch @@ -0,0 +1,62 @@ +From c21bb52f339a38aaf7d5b4285447e5a166fb4fcf Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 22 Jul 2015 14:00:37 +0200 +Subject: [PATCH] dcerpc: Add get_trusted_domain_object_type method + +https://fedorahosted.org/freeipa/ticket/5029 + +Reviewed-By: Alexander Bokovoy +--- + ipaserver/dcerpc.py | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index c0aa322c5d59e7d17a4ceb90448b397613284e38..c604fa3eae4cf94d719190a5a3e3de15d3841d24 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -107,6 +107,14 @@ dcerpc_error_messages = { + errors.RequirementError(name=_('At least the domain or IP address should be specified')), + } + ++pysss_type_key_translation_dict = { ++ pysss_nss_idmap.ID_USER: 'user', ++ pysss_nss_idmap.ID_GROUP: 'group', ++ # Used for users with magic private groups ++ pysss_nss_idmap.ID_BOTH: 'both', ++} ++ ++ + def assess_dcerpc_exception(num=None,message=None): + """ + Takes error returned by Samba bindings and converts it into +@@ -368,6 +376,27 @@ class DomainValidator(object): + raise errors.ValidationError(name=_('trusted domain object'), + error= _('Trusted domain did not return a valid SID for the object')) + ++ def get_trusted_domain_object_type(self, name_or_sid): ++ """ ++ Return the type of the object corresponding to the given name in ++ the trusted domain, which is either 'user', 'group' or 'both'. ++ The 'both' types is used for users with magic private groups. ++ """ ++ ++ object_type = None ++ ++ if is_sid_valid(name_or_sid): ++ result = pysss_nss_idmap.getnamebysid(name_or_sid) ++ else: ++ result = pysss_nss_idmap.getsidbyname(name_or_sid) ++ ++ if name_or_sid in result: ++ object_type = result[name_or_sid].get(pysss_nss_idmap.TYPE_KEY) ++ ++ # Do the translation to hide pysss_nss_idmap constants ++ # from higher-level code ++ return pysss_type_key_translation_dict.get(object_type) ++ + def get_trusted_domain_object_from_sid(self, sid): + root_logger.debug("Converting SID to object name: %s" % sid) + +-- +2.4.3 + diff --git a/SOURCES/0028-Produce-better-error-in-group-add-command.patch b/SOURCES/0028-Produce-better-error-in-group-add-command.patch deleted file mode 100644 index 9cbe930..0000000 --- a/SOURCES/0028-Produce-better-error-in-group-add-command.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 2ed0fd652cce1cef6035856ff16bf090c844646e Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 5 Nov 2014 02:40:10 -0500 -Subject: [PATCH] Produce better error in group-add command. - -https://fedorahosted.org/freeipa/ticket/4611 - -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/group.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py -index 03e6893e3c7604268b503b28ea39ed3f610aec47..d25ed9a1958119a5872db85e958323fdb8205366 100644 ---- a/ipalib/plugins/group.py -+++ b/ipalib/plugins/group.py -@@ -287,7 +287,7 @@ class group_add(LDAPCreate): - if options['external']: - entry_attrs['objectclass'].append('ipaexternalgroup') - if 'gidnumber' in options: -- raise errors.RequirementError(name='gid') -+ raise errors.MutuallyExclusiveError(reason=_('gid cannot be set for external group')) - elif not options['nonposix']: - entry_attrs['objectclass'].append('posixgroup') - if not 'gidnumber' in options: --- -2.1.0 - diff --git a/SOURCES/0028-idviews-Restrict-anchor-to-name-and-name-to-anchor-c.patch b/SOURCES/0028-idviews-Restrict-anchor-to-name-and-name-to-anchor-c.patch new file mode 100644 index 0000000..21dea02 --- /dev/null +++ b/SOURCES/0028-idviews-Restrict-anchor-to-name-and-name-to-anchor-c.patch @@ -0,0 +1,98 @@ +From 964bce5fd60bbb52be1dcc67e628a6c1ab62e356 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Thu, 23 Jul 2015 12:36:53 +0200 +Subject: [PATCH] idviews: Restrict anchor to name and name to anchor + conversions + +When converting the ID override anchor from AD SID representation to +the object name, we need to properly restrict the type of the object +that is being resolved. + +The same restriction applies for the opposite direction, when +converting the object name to it's SID. + +https://fedorahosted.org/freeipa/ticket/5029 + +Reviewed-By: Alexander Bokovoy +--- + ipalib/plugins/idviews.py | 50 +++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 46 insertions(+), 4 deletions(-) + +diff --git a/ipalib/plugins/idviews.py b/ipalib/plugins/idviews.py +index 67f52f886f0e19288a829616603c7aef6768f8db..c4f748132642f8702dcd12d38367dc36f4bc4a3c 100644 +--- a/ipalib/plugins/idviews.py ++++ b/ipalib/plugins/idviews.py +@@ -432,6 +432,36 @@ class idview_unapply(baseidview_apply): + + + # ID overrides helper methods ++def verify_trusted_domain_object_type(validator, desired_type, name_or_sid): ++ ++ object_type = validator.get_trusted_domain_object_type(name_or_sid) ++ ++ if object_type == desired_type: ++ # In case SSSD returns the same type as the type being ++ # searched, no problems here. ++ return True ++ ++ elif desired_type == 'user' and object_type == 'both': ++ # Type both denotes users with magic private groups. ++ # Overriding attributes for such users is OK. ++ return True ++ ++ elif desired_type == 'group' and object_type == 'both': ++ # However, overriding attributes for magic private groups ++ # does not make sense. One should override the GID of ++ # the user itself. ++ ++ raise errors.ConversionError( ++ name='identifier', ++ error=_('You are trying to reference a magic private group ' ++ 'which is not allowed to be overriden. ' ++ 'Try overriding the GID attribute of the ' ++ 'corresponding user instead.') ++ ) ++ ++ return False ++ ++ + def resolve_object_to_anchor(ldap, obj_type, obj, fallback_to_ldap): + """ + Resolves the user/group name to the anchor uuid: +@@ -482,9 +512,15 @@ def resolve_object_to_anchor(ldap, obj_type, obj, fallback_to_ldap): + sid = domain_validator.get_trusted_domain_object_sid(obj, + fallback_to_ldap=fallback_to_ldap) + +- # There is no domain prefix since SID contains information +- # about the domain +- return SID_ANCHOR_PREFIX + sid ++ # We need to verify that the object type is correct ++ type_correct = verify_trusted_domain_object_type( ++ domain_validator, obj_type, sid) ++ ++ if type_correct: ++ # There is no domain prefix since SID contains information ++ # about the domain ++ return SID_ANCHOR_PREFIX + sid ++ + except errors.ValidationError: + # Domain validator raises Validation Error if object name does not + # contain domain part (either NETBIOS\ prefix or @domain.name suffix) +@@ -539,7 +575,13 @@ def resolve_anchor_to_object_name(ldap, obj_type, anchor): + domain_validator = ipaserver.dcerpc.DomainValidator(api) + if domain_validator.is_configured(): + name = domain_validator.get_trusted_domain_object_from_sid(sid) +- return name ++ ++ # We need to verify that the object type is correct ++ type_correct = verify_trusted_domain_object_type( ++ domain_validator, obj_type, name) ++ ++ if type_correct: ++ return name + + # No acceptable object was found + raise errors.NotFound( +-- +2.4.3 + diff --git a/SOURCES/0029-Search-using-proper-scope-when-connecting-CA-instanc.patch b/SOURCES/0029-Search-using-proper-scope-when-connecting-CA-instanc.patch deleted file mode 100644 index 0a02cd2..0000000 --- a/SOURCES/0029-Search-using-proper-scope-when-connecting-CA-instanc.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 6aa3004870321dc5f34b2a6a9e6d6cdf2459d7ee Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Thu, 6 Nov 2014 16:10:01 -0500 -Subject: [PATCH] Search using proper scope when connecting CA instances - -The wrong search scope was being used when trying to determine if -a given master had a CA installed when trying to create a new -connection. - -https://fedorahosted.org/freeipa/ticket/4704 - -Reviewed-By: Nathaniel McCallum ---- - install/tools/ipa-csreplica-manage | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage -index c534446d7b0daf0ce0709edf952a8795ba85e937..6f6c6c75a122274eeb221f6e0eb15959dec56786 100755 ---- a/install/tools/ipa-csreplica-manage -+++ b/install/tools/ipa-csreplica-manage -@@ -303,7 +303,7 @@ def add_link(realm, replica1, replica2, dirman_passwd, options): - - dn = DN(('cn', 'CA'), ('cn', replica2), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), - ipautil.realm_to_suffix(realm)) -- conn.get_entries(dn, conn.SCOPE_ONELEVEL) -+ conn.get_entries(dn, conn.SCOPE_BASE) - conn.unbind() - except errors.NotFound: - sys.exit('%s does not have a CA configured.' % replica2) --- -2.1.0 - diff --git a/SOURCES/0029-idviews-Enforce-objectclass-check-in-idoverride-del.patch b/SOURCES/0029-idviews-Enforce-objectclass-check-in-idoverride-del.patch new file mode 100644 index 0000000..be14df0 --- /dev/null +++ b/SOURCES/0029-idviews-Enforce-objectclass-check-in-idoverride-del.patch @@ -0,0 +1,52 @@ +From 9fedf58eb1282560957edc1f36356602b55a736d Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Thu, 23 Jul 2015 14:00:06 +0200 +Subject: [PATCH] idviews: Enforce objectclass check in idoverride*-del + +Even with anchor to sid type checking, it would be still +possible to delete a user ID override by specifying a group +raw anchor and vice versa. + +This patch introduces a objectclass check in idoverride*-del +commands to prevent that. + +https://fedorahosted.org/freeipa/ticket/5029 + +Reviewed-By: Alexander Bokovoy +--- + ipalib/plugins/idviews.py | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/ipalib/plugins/idviews.py b/ipalib/plugins/idviews.py +index c4f748132642f8702dcd12d38367dc36f4bc4a3c..2e6e84510d3caa3636d3f0c08c56403866ff54f9 100644 +--- a/ipalib/plugins/idviews.py ++++ b/ipalib/plugins/idviews.py +@@ -716,6 +716,25 @@ class baseidoverride_del(LDAPDelete): + + takes_options = LDAPDelete.takes_options + (fallback_to_ldap_option,) + ++ def pre_callback(self, ldap, dn, *keys, **options): ++ assert isinstance(dn, DN) ++ ++ # Make sure the entry we're deleting has all the objectclasses ++ # this object requires ++ try: ++ entry = ldap.get_entry(dn, ['objectclass']) ++ except errors.NotFound: ++ self.obj.handle_not_found(*keys) ++ ++ required_object_classes = set(self.obj.object_class) ++ actual_object_classes = set(entry['objectclass']) ++ ++ # If not, treat it as a failed search ++ if not required_object_classes.issubset(actual_object_classes): ++ self.obj.handle_not_found(*keys) ++ ++ return dn ++ + + class baseidoverride_mod(LDAPUpdate): + __doc__ = _('Modify an ID override.') +-- +2.4.3 + diff --git a/SOURCES/0030-Fix-zonemgr-must-be-unicode-value.patch b/SOURCES/0030-Fix-zonemgr-must-be-unicode-value.patch deleted file mode 100644 index adbf8bb..0000000 --- a/SOURCES/0030-Fix-zonemgr-must-be-unicode-value.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 969021984125c94b1058bf94681f295071849a22 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 13 Nov 2014 18:22:22 +0100 -Subject: [PATCH] Fix: zonemgr must be unicode value - -To support IDNA --zonemgr option must be unicode not ascii - -https://fedorahosted.org/freeipa/ticket/4724 - -Reviewed-By: David Kupka ---- - ipaserver/install/bindinstance.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 16894de0a009aacb123cf76072f2556aebc5722f..5bf784e62aec7c323a84fc5130e53c3deb86e6fd 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -403,6 +403,8 @@ def zonemgr_callback(option, opt_str, value, parser): - """ - # validate the value first - try: -+ # IDNA support requires unicode -+ value = value.decode(sys.stdin.encoding) - validate_zonemgr_str(value) - except ValueError, e: - parser.error("invalid zonemgr: " + unicode(e)) --- -2.1.0 - diff --git a/SOURCES/0030-idviews-Check-for-the-Default-Trust-View-only-if-app.patch b/SOURCES/0030-idviews-Check-for-the-Default-Trust-View-only-if-app.patch new file mode 100644 index 0000000..2f74590 --- /dev/null +++ b/SOURCES/0030-idviews-Check-for-the-Default-Trust-View-only-if-app.patch @@ -0,0 +1,50 @@ +From f12e0e81f1cc6af2034c535866c3bfeddce8321d Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Tue, 21 Jul 2015 12:44:37 +0200 +Subject: [PATCH] idviews: Check for the Default Trust View only if applying + the view + +Currently, the code wrongly validates the idview-unapply command. Move +check for the forbidden application of the Default Trust View into +the correct logical branch. + +https://fedorahosted.org/freeipa/ticket/4969 + +Reviewed-By: Martin Basti +--- + ipalib/plugins/idviews.py | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/ipalib/plugins/idviews.py b/ipalib/plugins/idviews.py +index 2e6e84510d3caa3636d3f0c08c56403866ff54f9..ceb277020d1325bfd1607bcd4b05f4069ae9508d 100644 +--- a/ipalib/plugins/idviews.py ++++ b/ipalib/plugins/idviews.py +@@ -256,17 +256,19 @@ class baseidview_apply(LDAPQuery): + if not options.get('clear_view', False): + view_dn = self.api.Object['idview'].get_dn_if_exists(view) + assert isinstance(view_dn, DN) ++ ++ # Check that we're not applying the Default Trust View ++ if view.lower() == DEFAULT_TRUST_VIEW_NAME: ++ raise errors.ValidationError( ++ name=_('ID View'), ++ error=_('Default Trust View cannot be applied on hosts') ++ ) ++ + else: + # In case we are removing assigned view, we modify the host setting + # the ipaAssignedIDView to None + view_dn = None + +- if view.lower() == DEFAULT_TRUST_VIEW_NAME: +- raise errors.ValidationError( +- name=_('ID View'), +- error=_('Default Trust View cannot be applied on hosts') +- ) +- + completed = 0 + succeeded = {'host': []} + failed = { +-- +2.4.3 + diff --git a/SOURCES/0031-Fix-warning-message-should-not-contain-CLI-commands.patch b/SOURCES/0031-Fix-warning-message-should-not-contain-CLI-commands.patch deleted file mode 100644 index 38f504e..0000000 --- a/SOURCES/0031-Fix-warning-message-should-not-contain-CLI-commands.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 22f830576d7d9f6585842818ea33379fd1674091 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 13 Nov 2014 14:02:02 +0100 -Subject: [PATCH] Fix warning message should not contain CLI commands - -Message is now universal for both CLI and WebUI - -Ticket: https://fedorahosted.org/freeipa/ticket/4647 -Reviewed-By: Petr Vobornik ---- - ipalib/messages.py | 4 ++-- - ipalib/plugins/dns.py | 9 ++++----- - ipatests/test_xmlrpc/test_dns_plugin.py | 9 ++++++--- - 3 files changed, 12 insertions(+), 10 deletions(-) - -diff --git a/ipalib/messages.py b/ipalib/messages.py -index 5eeab3c54caf3a7318d89a4aeaee1357fceb787f..102e35275dbe37328c84ecb3cd5b2a8d8578056f 100644 ---- a/ipalib/messages.py -+++ b/ipalib/messages.py -@@ -175,8 +175,8 @@ class OptionSemanticChangedWarning(PublicMessage): - - errno = 13005 - type = "warning" -- format = _(u"semantic of '%(option)s' option was changed: " -- u"%(current_behavior)s.\n%(hint)s") -+ format = _(u"Semantic of %(label)s was changed. %(current_behavior)s\n" -+ u"%(hint)s") - - - class DNSServerNotRespondingWarning(PublicMessage): -diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py -index dd1e640f4062a32921bf1edf316e122b81a6d485..c5d96a8c4fcdf101254ecefb60cb83d63bee6310 100644 ---- a/ipalib/plugins/dns.py -+++ b/ipalib/plugins/dns.py -@@ -2369,11 +2369,10 @@ class dnszone(DNSZoneBase): - messages.add_message( - options['version'], - result, messages.OptionSemanticChangedWarning( -- option=u"--name-server", -- current_behavior=_(u"the option is used only for " -- u"setting up the SOA MNAME attribute"), -- hint=_(u"To edit NS record(s) in zone apex, use command " -- u"'dnsrecord-mod [zone] @ --ns-rec=nameserver'.") -+ label=_(u"setting Authoritative nameserver"), -+ current_behavior=_(u"It is used only for setting the " -+ u"SOA MNAME attribute."), -+ hint=_(u"NS record(s) can be edited in zone apex - '@'. ") - ) - ) - -diff --git a/ipatests/test_xmlrpc/test_dns_plugin.py b/ipatests/test_xmlrpc/test_dns_plugin.py -index a34d11a3278c67a3d00ca8f59bb8d8d19cf8a46e..fb53853147ecf663cf7015867131445f32364cfb 100644 ---- a/ipatests/test_xmlrpc/test_dns_plugin.py -+++ b/ipatests/test_xmlrpc/test_dns_plugin.py -@@ -497,9 +497,12 @@ class test_dns(Declarative): - 'objectclass': objectclasses.dnszone, - }, - 'messages': ( -- {'message': u"semantic of '--name-server' option was changed: the option is used only for setting up" -- u" the SOA MNAME attribute.\nTo edit NS record(s) in zone apex, use command " -- u"'dnsrecord-mod [zone] @ --ns-rec=nameserver'.", -+ {'message': u"Semantic of setting Authoritative nameserver " -+ u"was changed. " -+ u"It is used only for setting the SOA MNAME " -+ u"attribute.\n" -+ u"NS record(s) can be edited in zone " -+ u"apex - '@'. ", - 'code': 13005, - 'type': u'warning', - 'name': u'OptionSemanticChangedWarning'}, --- -2.1.0 - diff --git a/SOURCES/0031-replication-Fix-incorrect-exception-invocation.patch b/SOURCES/0031-replication-Fix-incorrect-exception-invocation.patch new file mode 100644 index 0000000..8ae1032 --- /dev/null +++ b/SOURCES/0031-replication-Fix-incorrect-exception-invocation.patch @@ -0,0 +1,26 @@ +From e3925cac13a3daca4880e789a139bad265c21798 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Fri, 24 Jul 2015 11:26:33 +0200 +Subject: [PATCH] replication: Fix incorrect exception invocation + +Reviewed-By: Tomas Babej +--- + ipaserver/install/replication.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index e9af88dc4356d4fd5495f4fea399ab09c75db953..2b36a5eb9287bf1789009a3198e540e333869e98 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -1171,7 +1171,7 @@ class ReplicationManager(object): + entry = self.get_replication_agreement(hostname) + if not entry: + raise errors.NotFound( +- "Replication agreement for %s not found" % hostname) ++ reason="Replication agreement for %s not found" % hostname) + objectclass = entry.get("objectclass") + + for o in objectclass: +-- +2.4.3 + diff --git a/SOURCES/0032-Fix-wrong-expiration-date-on-renewed-IPA-CA-certific.patch b/SOURCES/0032-Fix-wrong-expiration-date-on-renewed-IPA-CA-certific.patch deleted file mode 100644 index c7805e0..0000000 --- a/SOURCES/0032-Fix-wrong-expiration-date-on-renewed-IPA-CA-certific.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 6c7f71caf333363f8b4c18b3229de1533c1ad6fc Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 18 Nov 2014 14:01:59 +0000 -Subject: [PATCH] Fix wrong expiration date on renewed IPA CA certificates - -The expiration date was always set to the expiration date of the original -certificate. - -https://fedorahosted.org/freeipa/ticket/4717 - -Reviewed-By: David Kupka ---- - freeipa.spec.in | 4 ++-- - install/certmonger/dogtag-ipa-ca-renew-agent-submit | 2 ++ - 2 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index be13e69255e7612f84aeca22105645b544cc50b5..e29f77de0db89035d15008c6be2da0ae7e96158a 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -140,7 +140,7 @@ Requires: python-dns >= 1.11.1 - Requires: zip - Requires: policycoreutils >= 2.1.12-5 - Requires: tar --Requires(pre): certmonger >= 0.75.13 -+Requires(pre): certmonger >= 0.76.8 - Requires(pre): 389-ds-base >= 1.3.3.5 - Requires: fontawesome-fonts - Requires: open-sans-fonts -@@ -221,7 +221,7 @@ Requires: wget - Requires: libcurl >= 7.21.7-2 - Requires: xmlrpc-c >= 1.27.4 - Requires: sssd >= 1.12.2 --Requires: certmonger >= 0.75.6 -+Requires: certmonger >= 0.76.8 - Requires: nss-tools - Requires: bind-utils - Requires: oddjob-mkhomedir -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index e5ad9639b03b95e6e265214067a985f6c3ca0b2a..0a2cff148810e4800c02121afc68911c221d34d7 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -146,6 +146,8 @@ def request_cert(): - - path = paths.DOGTAG_IPA_RENEW_AGENT_SUBMIT - args = [path] + sys.argv[1:] -+ if os.environ.get('CERTMONGER_CA_PROFILE') == 'caCACert': -+ args += ['-O', 'bypassCAnotafter=true'] - stdout, stderr, rc = ipautil.run(args, raiseonerr=False, env=os.environ) - sys.stderr.write(stderr) - sys.stderr.flush() --- -2.1.0 - diff --git a/SOURCES/0032-webui-add-Kerberos-configuration-instructions-for-Ch.patch b/SOURCES/0032-webui-add-Kerberos-configuration-instructions-for-Ch.patch new file mode 100644 index 0000000..4693fb7 --- /dev/null +++ b/SOURCES/0032-webui-add-Kerberos-configuration-instructions-for-Ch.patch @@ -0,0 +1,149 @@ +From dc0d09f6e6a5681fa4c4146e6df6872dccc40b68 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Fri, 17 Jul 2015 15:57:30 +0200 +Subject: [PATCH] webui: add Kerberos configuration instructions for Chrome + +* IE section moved at the end +* Chrome section added +* FF and IE icons removed + +https://fedorahosted.org/freeipa/ticket/823 + +Reviewed-By: Martin Basti +--- + install/html/ssbrowser.html | 111 +++++++++++++++++++++++++++++++------------- + 1 file changed, 80 insertions(+), 31 deletions(-) + +diff --git a/install/html/ssbrowser.html b/install/html/ssbrowser.html +index d90103228150a60bd49e91ea8c64891d53d75d7b..685800e16e6e77c70adf905acfca2996513d1e1d 100644 +--- a/install/html/ssbrowser.html ++++ b/install/html/ssbrowser.html +@@ -54,38 +54,8 @@ +
+
+

Browser Kerberos Setup

+-

Internet ExplorerInternet Explorer Configuration

+-

+- Once you are able to log into the workstation with your kerberos key you are now able to use that ticket in Internet Explorer. +-

+-

+- Login to the Windows machine using an account of your Kerberos realm (administrative domain) +-

+-

+- In Internet Explorer, click Tools, and then click Internet Options. +-

+-
+-
    +-
  1. Click the Security tab
  2. +-
  3. Click Local intranet
  4. +-
  5. Click Sites
  6. +-
  7. Click Advanced
  8. +-
  9. Add your domain to the list
  10. +-
+-
    +-
  1. Click the Security tab
  2. +-
  3. Click Local intranet
  4. +-
  5. Click Custom Level
  6. +-
  7. Select Automatic logon only in Intranet zone
  8. +-
+- +-
    +-
  1. Visit a kerberized web site using IE (You must use the fully-qualified Domain Name in the URL)
  2. +-
  3. You are all set.
  4. +-
+-
+ +-

FirefoxFirefox Configuration

++

Firefox

+ +

+ You can configure Firefox to use Kerberos for Single Sign-on. The following instructions will guide you in configuring your web browser to send your Kerberos credentials to the appropriate Key Distribution Center which enables Single Sign-on. +@@ -117,6 +87,85 @@ + + + ++

Chrome

++ ++

++ You can configure Chrome to use Kerberos for Single Sign-on. The following instructions will guide you in configuring your web browser to send your Kerberos credentials to the appropriate Key Distribution Center which enables Single Sign-on. ++

++ ++

Import CA Certificate

++
    ++
  1. ++ Download the CA certificate. Alternatively, if the host is also an IdM client, you can find the certificate in /etc/ipa/ca.crt. ++
  2. ++
  3. ++ Click the menu button with the Customize and control Google Chrome tooltip, which is by default in the top right-hand corner of Chrome, and click Settings. ++
  4. ++
  5. ++ Click Show advanced settings to display more options, and then click the Manage certificates button located under the HTTPS/SSL heading. ++
  6. ++
  7. ++ In the Authorities tab, click the Import button at the bottom. ++
  8. ++
  9. Select the CA certificate file that you downloaded in the first step.
  10. ++
++ ++

++ Enable SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) to Use Kerberos Authentication ++ in Chrome ++

++
    ++
  1. ++ Make sure you have the necessary directory created by running: ++
    ++ [root@client]# mkdir -p /etc/opt/chrome/policies/managed/ ++
    ++
  2. ++
  3. ++ Create a new /etc/opt/chrome/policies/managed/mydomain.json file with write privileges limited to the system administrator or root, and include the following line: ++
    ++ { "AuthServerWhitelist": "*.example.com." } ++
    ++
    ++ You can do this by running: ++
    ++
    ++ [root@server]# echo '{ "AuthServerWhitelist": "*.example.com." }' > /etc/opt/chrome/policies/managed/mydomain.json ++
    ++
  4. ++
++ ++

Internet Explorer

++

++ Once you are able to log into the workstation with your kerberos key you are now able to use that ticket in Internet Explorer. ++

++

++ Login to the Windows machine using an account of your Kerberos realm (administrative domain) ++

++

++ In Internet Explorer, click Tools, and then click Internet Options. ++

++
++
    ++
  1. Click the Security tab
  2. ++
  3. Click Local intranet
  4. ++
  5. Click Sites
  6. ++
  7. Click Advanced
  8. ++
  9. Add your domain to the list
  10. ++
++
    ++
  1. Click the Security tab
  2. ++
  3. Click Local intranet
  4. ++
  5. Click Custom Level
  6. ++
  7. Select Automatic logon only in Intranet zone
  8. ++
++ ++
    ++
  1. Visit a kerberized web site using IE (You must use the fully-qualified Domain Name in the URL)
  2. ++
  3. You are all set.
  4. ++
++
++ +
+
+ +-- +2.4.3 + diff --git a/SOURCES/0033-Do-not-restore-SELinux-settings-that-were-not-backed.patch b/SOURCES/0033-Do-not-restore-SELinux-settings-that-were-not-backed.patch deleted file mode 100644 index 108f221..0000000 --- a/SOURCES/0033-Do-not-restore-SELinux-settings-that-were-not-backed.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 449e333dbf4c803bb179e7d27f08666fd6e333af Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Tue, 18 Nov 2014 10:40:31 +0100 -Subject: [PATCH] Do not restore SELinux settings that were not backed up - -https://fedorahosted.org/freeipa/ticket/4678 - -Reviewed-By: Petr Vobornik ---- - ipaplatform/base/tasks.py | 3 ++- - ipaplatform/redhat/tasks.py | 2 ++ - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py -index a6684d7653d6de8202a489edb1f7a38f4b344bbc..ab2c50332bce9f6eb95e2cb76aa6f7904b542765 100644 ---- a/ipaplatform/base/tasks.py -+++ b/ipaplatform/base/tasks.py -@@ -146,7 +146,8 @@ class BaseTaskNamespace(object): - - :param required_settings: A dictionary mapping the boolean names - to desired_values. -- The desired value can be 'on' or 'off'. -+ The desired value can be 'on' or 'off', -+ or None to leave the setting unchanged. - - :param backup_func: A function called for each boolean with two - arguments: the name and the previous value -diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py -index 4977e1c7c496e36d56110bcdf040ab5c932d31a2..c01d8cf8b65b3d93ba204b3453f5c65d556723cf 100644 ---- a/ipaplatform/redhat/tasks.py -+++ b/ipaplatform/redhat/tasks.py -@@ -366,6 +366,8 @@ class RedHatTaskNamespace(BaseTaskNamespace): - updated_vars = {} - failed_vars = {} - for setting, state in required_settings.iteritems(): -+ if state is None: -+ continue - try: - (stdout, stderr, rc) = ipautil.run([paths.GETSEBOOL, setting]) - original_state = stdout.split()[2] --- -2.1.0 - diff --git a/SOURCES/0033-Remove-ico-files-from-Makefile.patch b/SOURCES/0033-Remove-ico-files-from-Makefile.patch new file mode 100644 index 0000000..620acff --- /dev/null +++ b/SOURCES/0033-Remove-ico-files-from-Makefile.patch @@ -0,0 +1,32 @@ +From 56cdac487c35623b89881df4dd39713fdd36cb7c Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Mon, 27 Jul 2015 16:06:39 +0200 +Subject: [PATCH] Remove ico files from Makefile + +Icons were removed in a4be844809179ff0a05286606df1487d81a70022 but still +persist in Makefile. This patch fixes Makefile. + +https://fedorahosted.org/freeipa/ticket/823 + +Reviewed-By: Martin Babinsky +--- + install/ui/images/Makefile.am | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/install/ui/images/Makefile.am b/install/ui/images/Makefile.am +index e74d747b79ad14ef2f5b9e539c348670796fec8a..7d85d7e8203ca54f5b8fddeb55d86e106f077140 100644 +--- a/install/ui/images/Makefile.am ++++ b/install/ui/images/Makefile.am +@@ -4,9 +4,7 @@ appdir = $(IPA_DATA_DIR)/ui/images + app_DATA = \ + facet-tab-off.png \ + facet-tab-on.png \ +- firefox-icon.png \ + header-logo.png \ +- ie-icon.png \ + login-screen-background.jpg \ + login-screen-logo.png \ + product-name.png \ +-- +2.4.3 + diff --git a/SOURCES/0034-ACI-plugin-correctly-parse-bind-rules-enclosed-in-pa.patch b/SOURCES/0034-ACI-plugin-correctly-parse-bind-rules-enclosed-in-pa.patch new file mode 100644 index 0000000..2268504 --- /dev/null +++ b/SOURCES/0034-ACI-plugin-correctly-parse-bind-rules-enclosed-in-pa.patch @@ -0,0 +1,47 @@ +From c00b3fac15439828ce0ecffa181d1b263ad505a7 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 23 Jul 2015 15:45:35 +0200 +Subject: [PATCH] ACI plugin: correctly parse bind rules enclosed in + parentheses + +Since bind rule such as `(userdn = "ldap:///anyone")` is also a valid +statement, the ipalib ACI parser was updated to handle this case. + +https://fedorahosted.org/freeipa/ticket/5037 + +Reviewed-By: Martin Basti +--- + ipalib/aci.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/ipalib/aci.py b/ipalib/aci.py +index a55732bf19e58d8a4b36fa18bee2725d5b6584da..f78c5327dbe659240f046ae15622e798c8552829 100755 +--- a/ipalib/aci.py ++++ b/ipalib/aci.py +@@ -26,10 +26,11 @@ import re + ACIPat = re.compile(r'\(version\s+3.0\s*;\s*ac[li]\s+\"([^\"]*)\"\s*;\s*([^;]*);\s*\)', re.UNICODE) + + # Break the permissions/bind_rules out +-PermPat = re.compile(r'(\w+)\s*\((.*)\)\s+(.*)', re.UNICODE) ++PermPat = re.compile(r'(\w+)\s*\(([^()]*)\)\s*(.*)', re.UNICODE) + + # Break the bind rule out +-BindPat = re.compile(r'([a-zA-Z0-9;\.]+)\s*(\!?=)\s*(.*)', re.UNICODE) ++BindPat = re.compile(r'\(?([a-zA-Z0-9;\.]+)\s*(\!?=)\s*\"(.*)\"\)?', ++ re.UNICODE) + + ACTIONS = ["allow", "deny"] + +@@ -193,6 +194,9 @@ class ACI: + self.target['target']['operator'] = operator + + def set_bindrule(self, bindrule): ++ if bindrule.startswith('(') != bindrule.endswith(')'): ++ raise SyntaxError("non-matching parentheses in bindrule") ++ + match = BindPat.match(bindrule) + if not match or len(match.groups()) < 3: + raise SyntaxError, "malformed bind rule" +-- +2.4.3 + diff --git a/SOURCES/0034-Improve-otptoken-help-messages.patch b/SOURCES/0034-Improve-otptoken-help-messages.patch deleted file mode 100644 index 3a6ca29..0000000 --- a/SOURCES/0034-Improve-otptoken-help-messages.patch +++ /dev/null @@ -1,121 +0,0 @@ -From 0d1c2e1039758c1c11fb60299f571013f3572842 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Thu, 6 Nov 2014 15:19:01 -0500 -Subject: [PATCH] Improve otptoken help messages - -https://fedorahosted.org/freeipa/ticket/4689 - -Reviewed-By: Petr Vobornik ---- - ipalib/plugins/otptoken.py | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py -index 2b5f1c5fb83341d392e165a3507f5076820f1d3a..77366bafe7a102f5d2c048ac3d5f7d9948ed7fe4 100644 ---- a/ipalib/plugins/otptoken.py -+++ b/ipalib/plugins/otptoken.py -@@ -153,6 +153,7 @@ class otptoken(LDAPObject): - ), - StrEnum('type?', - label=_('Type'), -+ doc=_('Type of the token'), - default=u'totp', - autofill=True, - values=tuple(TOKEN_TYPES.keys() + [x.upper() for x in TOKEN_TYPES]), -@@ -161,42 +162,52 @@ class otptoken(LDAPObject): - Str('description?', - cli_name='desc', - label=_('Description'), -+ doc=_('Token description (informational only)'), - ), - Str('ipatokenowner?', - cli_name='owner', - label=_('Owner'), -+ doc=_('Assigned user of the token (default: self)'), - ), - Str('managedby_user?', - label=_('Manager'), -+ doc=_('Assigned manager of the token (default: self)'), - flags=['no_create', 'no_update', 'no_search'], - ), - Bool('ipatokendisabled?', - cli_name='disabled', -- label=_('Disabled state') -+ label=_('Disabled'), -+ doc=_('Mark the token as disabled (default: false)') - ), - DateTime('ipatokennotbefore?', - cli_name='not_before', - label=_('Validity start'), -+ doc=_('First date/time the token can be used'), - ), - DateTime('ipatokennotafter?', - cli_name='not_after', - label=_('Validity end'), -+ doc=_('Last date/time the token can be used'), - ), - Str('ipatokenvendor?', - cli_name='vendor', - label=_('Vendor'), -+ doc=_('Token vendor name (informational only)'), - ), - Str('ipatokenmodel?', - cli_name='model', - label=_('Model'), -+ doc=_('Token model (informational only)'), - ), - Str('ipatokenserial?', - cli_name='serial', - label=_('Serial'), -+ doc=_('Token serial (informational only)'), - ), - OTPTokenKey('ipatokenotpkey?', - cli_name='key', - label=_('Key'), -+ doc=_('Token secret (Base32; default: random)'), - default_from=lambda: os.urandom(KEY_LENGTH), - autofill=True, - flags=('no_display', 'no_update', 'no_search'), -@@ -204,6 +215,7 @@ class otptoken(LDAPObject): - StrEnum('ipatokenotpalgorithm?', - cli_name='algo', - label=_('Algorithm'), -+ doc=_('Token hash algorithm'), - default=u'sha1', - autofill=True, - flags=('no_update'), -@@ -212,6 +224,7 @@ class otptoken(LDAPObject): - IntEnum('ipatokenotpdigits?', - cli_name='digits', - label=_('Digits'), -+ doc=_('Number of digits each token code will have'), - values=(6, 8), - default=6, - autofill=True, -@@ -220,6 +233,7 @@ class otptoken(LDAPObject): - Int('ipatokentotpclockoffset?', - cli_name='offset', - label=_('Clock offset'), -+ doc=_('TOTP token / FreeIPA server time difference'), - default=0, - autofill=True, - flags=('no_update'), -@@ -227,6 +241,7 @@ class otptoken(LDAPObject): - Int('ipatokentotptimestep?', - cli_name='interval', - label=_('Clock interval'), -+ doc=_('Length of TOTP token code validity'), - default=30, - autofill=True, - minvalue=5, -@@ -235,6 +250,7 @@ class otptoken(LDAPObject): - Int('ipatokenhotpcounter?', - cli_name='counter', - label=_('Counter'), -+ doc=_('Initial counter for the HOTP token'), - default=0, - autofill=True, - minvalue=0, --- -2.1.0 - diff --git a/SOURCES/0035-Ensure-users-exist-when-assigning-tokens-to-them.patch b/SOURCES/0035-Ensure-users-exist-when-assigning-tokens-to-them.patch deleted file mode 100644 index a19c17a..0000000 --- a/SOURCES/0035-Ensure-users-exist-when-assigning-tokens-to-them.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 6e7474a1db6d49a4b07cd01663ec7f55df5225c4 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Fri, 24 Oct 2014 16:16:50 -0400 -Subject: [PATCH] Ensure users exist when assigning tokens to them - -https://fedorahosted.org/freeipa/ticket/4642 - -Reviewed-By: Petr Vobornik -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/otptoken.py | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py -index 77366bafe7a102f5d2c048ac3d5f7d9948ed7fe4..f48feeee0502992f1b5fed4f342cace1c404624b 100644 ---- a/ipalib/plugins/otptoken.py -+++ b/ipalib/plugins/otptoken.py -@@ -100,8 +100,11 @@ def _convert_owner(userobj, entry_attrs, options): - - def _normalize_owner(userobj, entry_attrs): - owner = entry_attrs.get('ipatokenowner', None) -- if owner is not None: -- entry_attrs['ipatokenowner'] = userobj.get_dn(owner) -+ if owner: -+ try: -+ entry_attrs['ipatokenowner'] = userobj._normalize_manager(owner)[0] -+ except NotFound: -+ userobj.handle_not_found(owner) - - def _check_interval(not_before, not_after): - if not_before and not_after: --- -2.1.0 - diff --git a/SOURCES/0035-ULC-Fix-stageused-add-from-delete-command.patch b/SOURCES/0035-ULC-Fix-stageused-add-from-delete-command.patch new file mode 100644 index 0000000..5927ccb --- /dev/null +++ b/SOURCES/0035-ULC-Fix-stageused-add-from-delete-command.patch @@ -0,0 +1,46 @@ +From c899fa3f5b404e9e28a149cc55684591482344f9 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 23 Jul 2015 10:52:54 +0200 +Subject: [PATCH] ULC: Fix stageused-add --from-delete command + +Nonexistent method was used to move deleted user to staged area. +Minor fixes added: + * handle not found error + * return new DN + +https://fedorahosted.org/freeipa/ticket/5145 + +Reviewed-By: David Kupka +--- + ipalib/plugins/stageuser.py | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/ipalib/plugins/stageuser.py b/ipalib/plugins/stageuser.py +index 49a762a922b21bd6d0824787d9305417f5e47ee6..41844712042c4456fc515afd316af60b612f164f 100644 +--- a/ipalib/plugins/stageuser.py ++++ b/ipalib/plugins/stageuser.py +@@ -377,16 +377,17 @@ class stageuser_add(baseuser_add): + + staging_dn = self.obj.get_dn(*keys, **options) + delete_dn = DN(staging_dn[0], self.obj.delete_container_dn, api.env.basedn) +- ++ new_dn = DN(staging_dn[0], self.obj.stage_container_dn, api.env.basedn) + # Check that this value is a Active user + try: + entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn, ['dn']) + except errors.NotFound: +- raise +- self._exc_wrapper(keys, options, ldap.move_entry_newsuperior)(delete_dn, str(DN(self.obj.stage_container_dn, api.env.basedn))) ++ self.obj.handle_not_found(*keys) + ++ self._exc_wrapper(keys, options, ldap.move_entry)( ++ delete_dn, new_dn) + entry_attrs = entry_to_dict(entry_attrs, **options) +- entry_attrs['dn'] = delete_dn ++ entry_attrs['dn'] = new_dn + + if self.obj.primary_key and keys[-1] is not None: + return dict(result=entry_attrs, value=keys[-1]) +-- +2.4.3 + diff --git a/SOURCES/0036-Enable-QR-code-display-by-default-in-otptoken-add.patch b/SOURCES/0036-Enable-QR-code-display-by-default-in-otptoken-add.patch deleted file mode 100644 index 7a89d30..0000000 --- a/SOURCES/0036-Enable-QR-code-display-by-default-in-otptoken-add.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 9adf96c47f37ee027cef03dc5bed49c2567ae75d Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Thu, 6 Nov 2014 15:30:13 -0500 -Subject: [PATCH] Enable QR code display by default in otptoken-add - -This is possible because python-qrcode's output now fits in a standard -terminal. Also, update ipa-otp-import and otptoken-add-yubikey to -disable QR code output as it doesn't make sense in these contexts. - -https://fedorahosted.org/freeipa/ticket/4703 - -Reviewed-By: Petr Vobornik ---- - API.txt | 3 ++- - VERSION | 4 ++-- - ipalib/plugins/otptoken.py | 5 +++-- - ipalib/plugins/otptoken_yubikey.py | 1 + - ipaserver/install/ipa_otptoken_import.py | 2 +- - 5 files changed, 9 insertions(+), 6 deletions(-) - -diff --git a/API.txt b/API.txt -index 0000491d7a76fd1d2d50208d314d1600839ce295..2a63f1e2349f0df69433fa7cb742e269cd42d79f 100644 ---- a/API.txt -+++ b/API.txt -@@ -2592,7 +2592,7 @@ output: Entry('result', , Gettext('A dictionary representing an LDA - output: Output('summary', (, ), None) - output: PrimaryKey('value', None, None) - command: otptoken_add --args: 1,22,3 -+args: 1,23,3 - arg: Str('ipatokenuniqueid', attribute=True, cli_name='id', multivalue=False, primary_key=True, required=False) - option: Str('addattr*', cli_name='addattr', exclude='webui') - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') -@@ -2611,6 +2611,7 @@ option: Int('ipatokentotpclockoffset', attribute=True, autofill=True, cli_name=' - option: Int('ipatokentotptimestep', attribute=True, autofill=True, cli_name='interval', default=30, minvalue=5, multivalue=False, required=False) - option: Str('ipatokenvendor', attribute=True, cli_name='vendor', multivalue=False, required=False) - option: Flag('no_members', autofill=True, default=False, exclude='webui') -+option: Flag('no_qrcode', autofill=True, default=False) - option: Flag('qrcode?', autofill=True, default=False) - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('setattr*', cli_name='setattr', exclude='webui') -diff --git a/VERSION b/VERSION -index 138648545c3cbe395303fa3cfa9dc99623b7e6c2..750b5058867ca5f073a083009c4aadeeb0240c35 100644 ---- a/VERSION -+++ b/VERSION -@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 - # # - ######################################################## - IPA_API_VERSION_MAJOR=2 --IPA_API_VERSION_MINOR=108 --# Last change: pvoborni - manage authorization of keytab operations -+IPA_API_VERSION_MINOR=109 -+# Last change: npmccallum - display qrcode by default -diff --git a/ipalib/plugins/otptoken.py b/ipalib/plugins/otptoken.py -index f48feeee0502992f1b5fed4f342cace1c404624b..f0850854f98e84e44acdcef311225220ac0129a3 100644 ---- a/ipalib/plugins/otptoken.py -+++ b/ipalib/plugins/otptoken.py -@@ -268,7 +268,8 @@ class otptoken_add(LDAPCreate): - msg_summary = _('Added OTP token "%(value)s"') - - takes_options = LDAPCreate.takes_options + ( -- Flag('qrcode?', label=_('Display QR code')), -+ Flag('qrcode?', label=_('(deprecated)'), flags=('no_option')), -+ Flag('no_qrcode', label=_('Do not display QR code'), default=False), - ) - - has_output_params = LDAPCreate.has_output_params + ( -@@ -348,7 +349,7 @@ class otptoken_add(LDAPCreate): - rv = super(otptoken_add, self).output_for_cli(textui, output, *args, **options) - - # Print QR code to terminal if specified -- if uri and options.get('qrcode', False): -+ if uri and not options.get('no_qrcode', False): - print "\n" - qr = qrcode.QRCode() - qr.add_data(uri) -diff --git a/ipalib/plugins/otptoken_yubikey.py b/ipalib/plugins/otptoken_yubikey.py -index e70ddb6e42b5ea34d7ebecb252d6bbd73ac64d03..7095887ac7cdf5d4b7d0d30edc6cab0222246664 100644 ---- a/ipalib/plugins/otptoken_yubikey.py -+++ b/ipalib/plugins/otptoken_yubikey.py -@@ -124,6 +124,7 @@ class otptoken_add_yubikey(Command): - ipatokenotpalgorithm=u'sha1', - ipatokenhotpcounter=0, - ipatokenotpkey=key, -+ no_qrcode=True, - **options) - - # Suppress values we don't want to return. -diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py -index 31a6902014b8e3b2aafb3ba98a4190dc2059a3e7..b78aba93a2edc987450d921c87ea4f61b014b419 100644 ---- a/ipaserver/install/ipa_otptoken_import.py -+++ b/ipaserver/install/ipa_otptoken_import.py -@@ -517,7 +517,7 @@ class OTPTokenImport(admintool.AdminTool): - # Parse tokens - for keypkg in self.doc.getKeyPackages(): - try: -- api.Command.otptoken_add(keypkg.id, **keypkg.options) -+ api.Command.otptoken_add(keypkg.id, no_qrcode=True, **keypkg.options) - except Exception as e: - self.log.warn("Error adding token: %s", e) - else: --- -2.1.0 - diff --git a/SOURCES/0036-webui-fix-regressions-failed-auth-messages.patch b/SOURCES/0036-webui-fix-regressions-failed-auth-messages.patch new file mode 100644 index 0000000..ea69c48 --- /dev/null +++ b/SOURCES/0036-webui-fix-regressions-failed-auth-messages.patch @@ -0,0 +1,79 @@ +From 4c1b511fbcdca211c913a4db409c66469cdc3a4f Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 28 Jul 2015 14:01:34 +0200 +Subject: [PATCH] webui: fix regressions failed auth messages + +1. after logout, krb auth no longer shows "session expired" but correct +"Authentication with Kerberos failed". + +2. "The password or username you entered is incorrect." is showed on +failed forms-based auth. + +https://fedorahosted.org/freeipa/ticket/5163 + +Reviewed-By: Martin Basti +--- + install/ui/src/freeipa/ipa.js | 8 ++++---- + install/ui/src/freeipa/widgets/LoginScreen.js | 2 +- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js +index 75dd73c379815a0e0e1dc2c4d786fdcf3be7c1b0..eaaaaf7fcfaee873d97d96630b72365ecffe6b08 100644 +--- a/install/ui/src/freeipa/ipa.js ++++ b/install/ui/src/freeipa/ipa.js +@@ -32,6 +32,7 @@ define([ + './json2', + './_base/i18n', + './auth', ++ './config', + './datetime', + './metadata', + './builder', +@@ -41,7 +42,8 @@ define([ + './util', + 'exports' + ], function(declare, Deferred, Evented, keys, topic, $, JSON, i18n, auth, +- datetime, metadata_provider, builder, reg, rpc, text, util, exports) { ++ config, datetime, metadata_provider, builder, reg, rpc, text, ++ util, exports) { + + /** + * @class +@@ -127,11 +129,9 @@ var IPA = function () { + // if current path matches live server path, use live data + if (that.url && window.location.pathname.substring(0, that.url.length) === that.url) { + that.json_url = params.url || '/ipa/session/json'; +- that.login_url = params.url || '/ipa/session/login_kerberos'; + + } else { // otherwise use fixtures + that.json_path = params.url || "test/data"; +- // that.login_url is not needed for fixtures + } + + $.ajaxSetup(that.ajax_options); +@@ -377,7 +377,7 @@ IPA.get_credentials = function() { + } + + var request = { +- url: IPA.login_url, ++ url: config.krb_login_url, + cache: false, + type: "GET", + success: success_handler, +diff --git a/install/ui/src/freeipa/widgets/LoginScreen.js b/install/ui/src/freeipa/widgets/LoginScreen.js +index fb7ccccc6c34d9c1c7115dd95809f3a39de488eb..eb95b9161f05eeac1ec9aed286c9730dada85d59 100644 +--- a/install/ui/src/freeipa/widgets/LoginScreen.js ++++ b/install/ui/src/freeipa/widgets/LoginScreen.js +@@ -232,8 +232,8 @@ define(['dojo/_base/declare', + this.set('view', 'reset'); + val_summary.add_info('login', this.password_expired); + } else { +- val_summary.add_error('login', this.form_auth_failed); + password_f.set_value(''); ++ val_summary.add_error('login', this.form_auth_failed); + } + })); + }, +-- +2.4.3 + diff --git a/SOURCES/0037-Show-warning-instead-of-error-if-CA-did-not-start.patch b/SOURCES/0037-Show-warning-instead-of-error-if-CA-did-not-start.patch deleted file mode 100644 index d70a544..0000000 --- a/SOURCES/0037-Show-warning-instead-of-error-if-CA-did-not-start.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 2e974ebf99737504f01feb2cbb85d3acbc2a15d6 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Tue, 18 Nov 2014 18:30:59 +0100 -Subject: [PATCH] Show warning instead of error if CA did not start - -This is just workaround, checking if CA is working raises false positive -exception during upgrade - -Ticket: https://fedorahosted.org/freeipa/ticket/4676 -Reviewed-By: Simo Sorce ---- - install/tools/ipa-upgradeconfig | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig -index 6556d8f313d3a9efeb32d4cba97cb82796459652..3484f8e8768fe05dddb08e9a40e58d8ad9c2e1e7 100644 ---- a/install/tools/ipa-upgradeconfig -+++ b/install/tools/ipa-upgradeconfig -@@ -1457,6 +1457,10 @@ def main(): - ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) - except ipautil.CalledProcessError, e: - root_logger.error("Failed to restart %s: %s", ca.service_name, e) -+ # FIXME https://fedorahosted.org/freeipa/ticket/4676 -+ # workaround -+ except RuntimeError as e: -+ root_logger.warning(str(e)) - - set_sssd_domain_option('ipa_server_mode', 'True') - --- -2.1.0 - diff --git a/SOURCES/0037-Validate-vault-s-file-parameters.patch b/SOURCES/0037-Validate-vault-s-file-parameters.patch new file mode 100644 index 0000000..c6b18d3 --- /dev/null +++ b/SOURCES/0037-Validate-vault-s-file-parameters.patch @@ -0,0 +1,139 @@ +From f5cf88337d6f775df4a311469b869921bbc90f05 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 30 Jul 2015 15:48:40 +0200 +Subject: [PATCH] Validate vault's file parameters + +A user can pass file names for password, public and private key files to +the vault plugin. The plugin attempts to read from these files. If any +file can't be, an internal error was raised. The patch wraps all reads +and turns any IOError and UnicodeError into a ValidationError. + +https://fedorahosted.org/freeipa/ticket/5155 + +Reviewed-By: Martin Basti +--- + ipalib/plugins/vault.py | 59 +++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 47 insertions(+), 12 deletions(-) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 37a32282e7a4e87889eea90d987b737f98fd82c3..fe4eec325dde4a9ecd8a7ce5af1a124fc5c6a9ae 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -19,6 +19,7 @@ + + import base64 + import getpass ++import io + import json + import os + import sys +@@ -210,6 +211,33 @@ EXAMPLES: + ipa vault-remove-member --users + """) + ++ ++def validated_read(argname, filename, mode='r', encoding=None): ++ """Read file and catch errors ++ ++ IOError and UnicodeError (for text files) are turned into a ++ ValidationError ++ """ ++ try: ++ with io.open(filename, mode=mode, encoding=encoding) as f: ++ data = f.read() ++ except IOError as exc: ++ raise errors.ValidationError( ++ name=argname, ++ error=_("Cannot read file '%(filename)s': %(exc)s") % { ++ 'filename': filename, 'exc': exc[1] ++ } ++ ) ++ except UnicodeError as exc: ++ raise errors.ValidationError( ++ name=argname, ++ error=_("Cannot decode file '%(filename)s': %(exc)s") % { ++ 'filename': filename, 'exc': exc ++ } ++ ) ++ return data ++ ++ + register = Registry() + + +@@ -591,8 +619,10 @@ class vault_add(PKQuery, Local): + pass + + elif password_file: +- with open(password_file, 'rb') as f: +- password = f.read().rstrip('\n').decode('utf-8') ++ password = validated_read('password-file', ++ password_file, ++ encoding='utf-8') ++ password = password.rstrip('\n') + + else: + password = self.obj.get_new_password() +@@ -611,8 +641,9 @@ class vault_add(PKQuery, Local): + pass + + elif public_key_file: +- with open(public_key_file, 'rb') as f: +- public_key = f.read() ++ public_key = validated_read('public-key-file', ++ public_key_file, ++ mode='rb') + + # store vault public key + options['ipavaultpublickey'] = public_key +@@ -904,8 +935,7 @@ class vault_archive(PKQuery, Local): + reason=_('Input data specified multiple times')) + + elif input_file: +- with open(input_file, 'rb') as f: +- data = f.read() ++ data = validated_read('in', input_file, mode='rb') + + elif not data: + data = '' +@@ -937,8 +967,10 @@ class vault_archive(PKQuery, Local): + pass + + elif password_file: +- with open(password_file) as f: +- password = f.read().rstrip('\n').decode('utf-8') ++ password = validated_read('password-file', ++ password_file, ++ encoding='utf-8') ++ password = password.rstrip('\n') + + else: + password = self.obj.get_existing_password() +@@ -1254,8 +1286,10 @@ class vault_retrieve(PKQuery, Local): + pass + + elif password_file: +- with open(password_file) as f: +- password = f.read().rstrip('\n').decode('utf-8') ++ password = validated_read('password-file', ++ password_file, ++ encoding='utf-8') ++ password = password.rstrip('\n') + + else: + password = self.obj.get_existing_password() +@@ -1277,8 +1311,9 @@ class vault_retrieve(PKQuery, Local): + pass + + elif private_key_file: +- with open(private_key_file, 'rb') as f: +- private_key = f.read() ++ private_key = validated_read('private-key-file', ++ private_key_file, ++ mode='rb') + + else: + raise errors.ValidationError( +-- +2.4.3 + diff --git a/SOURCES/0038-certprofile-import-do-not-require-profileId-in-profi.patch b/SOURCES/0038-certprofile-import-do-not-require-profileId-in-profi.patch new file mode 100644 index 0000000..57f8aa1 --- /dev/null +++ b/SOURCES/0038-certprofile-import-do-not-require-profileId-in-profi.patch @@ -0,0 +1,58 @@ +From ae5939600d367172a1e830c87254d2fc1bb56fe8 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 23 Jul 2015 17:48:56 +0200 +Subject: [PATCH] certprofile-import: do not require profileId in profile data + +certprofile-import no longer requires profileId in profile data. Instead +the profile ID from the command line is taken and added to the profile +data internally. + +If profileId is set in the profile, then it still has to match the CLI +option. + +https://fedorahosted.org/freeipa/ticket/5090 + +Reviewed-By: Martin Basti +--- + ipalib/plugins/certprofile.py | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index 5550ed942521dbab2e783fba1570520268f9b378..b0b76ca8e78f2482b5c08dad21d9161fd4c2c2d0 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -11,6 +11,7 @@ from ipalib.plugins.virtual import VirtualCommand + from ipalib.plugins.baseldap import ( + LDAPObject, LDAPSearch, LDAPCreate, + LDAPDelete, LDAPUpdate, LDAPRetrieve) ++from ipalib.request import context + from ipalib import ngettext + from ipalib.text import _ + from ipapython.version import API_VERSION +@@ -230,11 +231,12 @@ class certprofile_import(LDAPCreate): + + def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options): + ca_enabled_check() ++ context.profile = options['file'] + + match = self.PROFILE_ID_PATTERN.search(options['file']) + if match is None: +- raise errors.ValidationError(name='file', +- error=_("Profile ID is not present in profile data")) ++ # no profileId found, use CLI value as profileId. ++ context.profile = u'profileId=%s\n%s' % (keys[0], context.profile) + elif keys[0] != match.group(1): + raise errors.ValidationError(name='file', + error=_("Profile ID '%(cli_value)s' does not match profile data '%(file_value)s'") +@@ -250,7 +252,7 @@ class certprofile_import(LDAPCreate): + """ + try: + with self.api.Backend.ra_certprofile as profile_api: +- profile_api.create_profile(options['file']) ++ profile_api.create_profile(context.profile) + profile_api.enable_profile(keys[0]) + except: + # something went wrong ; delete entry +-- +2.4.3 + diff --git a/SOURCES/0038-webui-fix-potential-XSS-vulnerabilities.patch b/SOURCES/0038-webui-fix-potential-XSS-vulnerabilities.patch deleted file mode 100644 index f6c78d2..0000000 --- a/SOURCES/0038-webui-fix-potential-XSS-vulnerabilities.patch +++ /dev/null @@ -1,131 +0,0 @@ -From a1d4f412181423cb3883650e033b9fb5b415bd83 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 10 Nov 2014 16:24:15 +0100 -Subject: [PATCH] webui: fix potential XSS vulnerabilities - -Escape user defined text to prevent XSS attacks. Extra precaution was taken -to escape also parts which are unlikely to contain user-defined text. - -fixes CVE-2014-7850 - -https://fedorahosted.org/freeipa/ticket/4742 - -Reviewed-By: Tomas Babej ---- - install/ui/src/freeipa/Application_controller.js | 4 ++-- - install/ui/src/freeipa/facet.js | 12 +++++++----- - install/ui/src/freeipa/ipa.js | 1 + - install/ui/src/freeipa/rule.js | 2 +- - install/ui/src/freeipa/widget.js | 4 ++-- - 5 files changed, 13 insertions(+), 10 deletions(-) - -diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js -index 094bd3da7c4806a316ebe2589b98a523410f4a5f..4bf76f8f56a8e34e330c35956b8922cc3c8f79e3 100644 ---- a/install/ui/src/freeipa/Application_controller.js -+++ b/install/ui/src/freeipa/Application_controller.js -@@ -252,12 +252,12 @@ define([ - var error_container = $('
', { - 'class': 'container facet-content facet-error' - }).appendTo($('.app-container .content').empty()); -- error_container.append('

'+name+'

'); -+ error_container.append($('

', { text: name })); - var details = $('
', { - 'class': 'error-details' - }).appendTo(error_container); - -- details.append('

Web UI got in unrecoverable state during "'+error.phase+'" phase.

'); -+ details.append($('

', { text: 'Web UI got in unrecoverable state during "' + error.phase + '" phase' })); - if (error.name) window.console.error(error.name); - if (error.results) { - var msg = error.results.message; -diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js -index 43627d9d531ed700ff780a0773451eaf17b1cbdd..b0121c75fd584988883a3b5f7d1665a985a321fd 100644 ---- a/install/ui/src/freeipa/facet.js -+++ b/install/ui/src/freeipa/facet.js -@@ -895,12 +895,12 @@ exp.facet = IPA.facet = function(spec, no_init) { - title = title.replace('${error}', error_thrown.name); - - that.error_container.empty(); -- that.error_container.append('

'+title+'

'); -+ that.error_container.append($('

', { text: title })); - - var details = $('
', { - 'class': 'error-details' - }).appendTo(that.error_container); -- details.append('

'+error_thrown.message+'

'); -+ details.append($('

', { text: error_thrown.message })); - - $('

', { - text: text.get('@i18n:error_report.options') -@@ -932,7 +932,9 @@ exp.facet = IPA.facet = function(spec, no_init) { - } - ); - -- that.error_container.append('

'+text.get('@i18n:error_report.problem_persists')+'

'); -+ that.error_container.append($('

', { -+ text: text.get('@i18n:error_report.problem_persists') -+ })); - - that.show_error(); - }; -@@ -1214,7 +1216,7 @@ exp.facet_header = IPA.facet_header = function(spec) { - click: item.handler - }).appendTo(bc_item); - } else { -- bc_item.append(item.text); -+ bc_item.text(item.text); - } - return bc_item; - }; -@@ -1823,7 +1825,7 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) { - function(xhr, text_status, error_thrown) { - that.load_records([]); - var summary = that.table.summary.empty(); -- summary.append(error_thrown.name+': '+error_thrown.message); -+ summary.text(error_thrown.name+': '+error_thrown.message); - } - ); - }; -diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js -index 6d3aeaaaaca11dfdaf20935e5c9084c9ed106e6c..137f11e832ff8d0b6dd1b50060f8537c7b117616 100644 ---- a/install/ui/src/freeipa/ipa.js -+++ b/install/ui/src/freeipa/ipa.js -@@ -1133,6 +1133,7 @@ IPA.notify = function(message, type, timeout) { - - if (typeof message === 'string') { - message = text.get(message); -+ message = document.createTextNode(message); - } - - var notification_area = $('#notification .notification-area'); -diff --git a/install/ui/src/freeipa/rule.js b/install/ui/src/freeipa/rule.js -index 8a2b01963b74e1892ac15127ae0050b35fe6ac27..706827190261efda136f6d1489bdb13543c00f7a 100644 ---- a/install/ui/src/freeipa/rule.js -+++ b/install/ui/src/freeipa/rule.js -@@ -91,7 +91,7 @@ IPA.rule_radio_widget = function(spec) { - var param_info = IPA.get_entity_param(that.entity.name, that.name); - var title = param_info ? param_info.doc : that.name; - -- container.append(title + ': '); -+ container.append(document.createTextNode(title + ': ')); - that.widget_create(container); - that.owb_create(container); - if (that.undo) { -diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js -index 9240df8ef5402310ec9ceafd0b766def10c8cb48..1ef1a2bf22b735edcfcca44cfc1e69bc8d36a740 100644 ---- a/install/ui/src/freeipa/widget.js -+++ b/install/ui/src/freeipa/widget.js -@@ -4166,8 +4166,8 @@ IPA.link_widget = function(spec) { - - that.values = util.normalize_value(values); - that.value = that.values.slice(-1)[0] || ''; -- that.link.html(that.value); -- that.nonlink.html(that.value); -+ that.link.text(that.value); -+ that.nonlink.text(that.value); - that.update_link(); - that.check_entity_link(); - that.on_value_changed(values); --- -2.1.0 - diff --git a/SOURCES/0039-Raise-right-exception-if-domain-name-is-not-valid.patch b/SOURCES/0039-Raise-right-exception-if-domain-name-is-not-valid.patch deleted file mode 100644 index 2714868..0000000 --- a/SOURCES/0039-Raise-right-exception-if-domain-name-is-not-valid.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e2f285e7c63a8ff9f2c049ee3a058b6e281352a8 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Wed, 19 Nov 2014 14:51:20 +0100 -Subject: [PATCH] Raise right exception if domain name is not valid - -Because of dnspython implementation, in some cases UnicodeError is -raised instead of DNS SyntaxError - -Ticket: https://fedorahosted.org/freeipa/ticket/4734 -Reviewed-By: Jan Cholasta ---- - ipapython/dnsutil.py | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - -diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py -index d7841fe2548dd100d51e60ea11bc6e468f3475cf..f08cddad959658a11623a31cb591655f1a5fdabf 100644 ---- a/ipapython/dnsutil.py -+++ b/ipapython/dnsutil.py -@@ -26,15 +26,16 @@ class DNSName(dns.name.Name): - labels = None # make pylint happy - - def __init__(self, labels, origin=None): -- if isinstance(labels, str): -- #pylint: disable=E1101 -- labels = dns.name.from_text(labels, origin).labels -- elif isinstance(labels, unicode): -- #pylint: disable=E1101 -- labels = dns.name.from_unicode(labels, origin).labels -- elif isinstance(labels, dns.name.Name): -- labels = labels.labels - try: -+ if isinstance(labels, str): -+ #pylint: disable=E1101 -+ labels = dns.name.from_text(labels, origin).labels -+ elif isinstance(labels, unicode): -+ #pylint: disable=E1101 -+ labels = dns.name.from_unicode(labels, origin).labels -+ elif isinstance(labels, dns.name.Name): -+ labels = labels.labels -+ - super(DNSName, self).__init__(labels) - except UnicodeError, e: - # dnspython bug, an invalid domain name returns the UnicodeError --- -2.1.0 - diff --git a/SOURCES/0039-user-show-add-out-option-to-save-certificates-to-fil.patch b/SOURCES/0039-user-show-add-out-option-to-save-certificates-to-fil.patch new file mode 100644 index 0000000..94d2fb8 --- /dev/null +++ b/SOURCES/0039-user-show-add-out-option-to-save-certificates-to-fil.patch @@ -0,0 +1,109 @@ +From 52ddaafcac7ace012535ac7044b301ad3a7d7b9a Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Fri, 24 Jul 2015 09:31:26 -0400 +Subject: [PATCH] user-show: add --out option to save certificates to file + +Add the --out option to user-show, bringing it into line with +host-show and service-show with the ability to save the user's +certificate(s) to a file. + +https://fedorahosted.org/freeipa/ticket/5171 + +Reviewed-By: Martin Basti +--- + API.txt | 3 ++- + VERSION | 4 ++-- + ipalib/plugins/user.py | 27 ++++++++++++++++++++++++++- + 3 files changed, 30 insertions(+), 4 deletions(-) + +diff --git a/API.txt b/API.txt +index 6ab30ddab41715fdbccb4f37aa1852621bca62b4..2e19d6b2f1e16cc1c89d71ed7d443145426a28e3 100644 +--- a/API.txt ++++ b/API.txt +@@ -5360,10 +5360,11 @@ output: Entry('result', , Gettext('A dictionary representing an LDA + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) + command: user_show +-args: 1,5,3 ++args: 1,6,3 + arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Flag('no_members', autofill=True, default=False, exclude='webui') ++option: Str('out?') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Flag('rights', autofill=True, default=False) + option: Str('version?', exclude='webui') +diff --git a/VERSION b/VERSION +index 678d1f8a7e588d480b16441e12e4d527d9c1cd98..ca43f3e0c06880d355c068514134187c5edda175 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=147 +-# Last change: mbasti - Consolidate DNS RR in API and schema ++IPA_API_VERSION_MINOR=148 ++# Last change: ftweedal - add --out option to user-show +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 206b380efb6472fb040dde33ac80e3f66c00c138..0209b29b130f2377c04f497f95c8ad39e98f2587 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -23,7 +23,7 @@ import string + import posixpath + import os + +-from ipalib import api, errors ++from ipalib import api, errors, util + from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime + from ipalib.plugins.baseuser import baseuser, baseuser_add, baseuser_del, \ + baseuser_mod, baseuser_find, baseuser_show, \ +@@ -38,6 +38,7 @@ from ipalib.plugins import baseldap + from ipalib.request import context + from ipalib import _, ngettext + from ipalib import output ++from ipalib import x509 + from ipaplatform.paths import paths + from ipapython.ipautil import ipa_generate_password + from ipapython.ipavalidate import Email +@@ -765,6 +766,11 @@ class user_show(baseuser_show): + __doc__ = _('Display information about a user.') + + has_output_params = baseuser_show.has_output_params + user_output_params ++ takes_options = baseuser_show.takes_options + ( ++ Str('out?', ++ doc=_('file to store certificate in'), ++ ), ++ ) + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + convert_nsaccountlock(entry_attrs) +@@ -772,6 +778,25 @@ class user_show(baseuser_show): + self.obj.get_preserved_attribute(entry_attrs, options) + return dn + ++ def forward(self, *keys, **options): ++ if 'out' in options: ++ util.check_writable_file(options['out']) ++ result = super(user_show, self).forward(*keys, **options) ++ if 'usercertificate' in result['result']: ++ x509.write_certificate_list( ++ result['result']['usercertificate'], ++ options['out'] ++ ) ++ result['summary'] = ( ++ _('Certificate(s) stored in file \'%(file)s\'') ++ % dict(file=options['out']) ++ ) ++ return result ++ else: ++ raise errors.NoCertificateError(entry=keys[-1]) ++ else: ++ return super(user_show, self).forward(*keys, **options) ++ + @register() + class user_undel(LDAPQuery): + __doc__ = _('Undelete a delete user account.') +-- +2.4.3 + diff --git a/SOURCES/0040-Restore-file-extended-attributes-and-SELinux-context.patch b/SOURCES/0040-Restore-file-extended-attributes-and-SELinux-context.patch deleted file mode 100644 index 5d920ee..0000000 --- a/SOURCES/0040-Restore-file-extended-attributes-and-SELinux-context.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 387a4fb2430639f3d87ee1d310997576ddfd9246 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 20 Nov 2014 12:45:40 +0000 -Subject: [PATCH] Restore file extended attributes and SELinux context in - ipa-restore - -https://fedorahosted.org/freeipa/ticket/4712 - -Reviewed-By: Petr Viktorin ---- - ipaserver/install/ipa_restore.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 8b1e80f5ed5e140ccb17ea0b63d92b6049507b74..7b92ab5d490a7a254b1ea307d5031da002b9f653 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -523,6 +523,8 @@ class Restore(admintool.AdminTool): - cwd = os.getcwd() - os.chdir('/') - args = ['tar', -+ '--xattrs', -+ '--selinux', - '-xzf', - os.path.join(self.dir, 'files.tar') - ] -@@ -581,6 +583,8 @@ class Restore(admintool.AdminTool): - os.chdir(self.dir) - - args = ['tar', -+ '--xattrs', -+ '--selinux', - '-xzf', - filename, - '.' --- -2.1.0 - diff --git a/SOURCES/0040-store-certificates-issued-for-user-entries-as-userCe.patch b/SOURCES/0040-store-certificates-issued-for-user-entries-as-userCe.patch new file mode 100644 index 0000000..c284618 --- /dev/null +++ b/SOURCES/0040-store-certificates-issued-for-user-entries-as-userCe.patch @@ -0,0 +1,158 @@ +From 180f571e60aaedaacdaa272d2a34719ce0ce0565 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Mon, 3 Aug 2015 13:36:29 +0200 +Subject: [PATCH] store certificates issued for user entries as + userCertificate;binary + +This patch forces the user management CLI command to store certificates as +userCertificate;binary attribute. The code to retrieve of user information was +modified to enable outputting of userCertificate;binary attribute to the +command line. + +The modification also fixes https://fedorahosted.org/freeipa/ticket/5173 + +Reviewed-By: Jan Cholasta +--- + ipalib/plugins/baseuser.py | 23 ++++++++++++++++++++++- + ipalib/plugins/user.py | 21 +++++++++------------ + 2 files changed, 31 insertions(+), 13 deletions(-) + +diff --git a/ipalib/plugins/baseuser.py b/ipalib/plugins/baseuser.py +index bd66cf5a3e3a4e6c18d1a54408f969668c834fab..5eede7a98e7e6d9bf31a6d553b0ce60c7cf3527c 100644 +--- a/ipalib/plugins/baseuser.py ++++ b/ipalib/plugins/baseuser.py +@@ -187,7 +187,7 @@ class baseuser(LDAPObject): + 'telephonenumber', 'title', 'memberof', 'nsaccountlock', + 'memberofindirect', 'ipauserauthtype', 'userclass', + 'ipatokenradiusconfiglink', 'ipatokenradiususername', +- 'krbprincipalexpiration', 'usercertificate', ++ 'krbprincipalexpiration', 'usercertificate;binary', + ] + search_display_attributes = [ + 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', +@@ -465,10 +465,27 @@ class baseuser(LDAPObject): + assert isinstance(user, DN) + return self._user_status(user, DN(self.delete_container_dn, api.env.basedn)) + ++ def convert_usercertificate_pre(self, entry_attrs): ++ if 'usercertificate' in entry_attrs: ++ entry_attrs['usercertificate;binary'] = entry_attrs.pop( ++ 'usercertificate') ++ ++ def convert_usercertificate_post(self, entry_attrs, **options): ++ if 'usercertificate;binary' in entry_attrs: ++ entry_attrs['usercertificate'] = entry_attrs.pop( ++ 'usercertificate;binary') ++ + class baseuser_add(LDAPCreate): + """ + Prototype command plugin to be implemented by real plugin + """ ++ def pre_common_callback(self, ldap, dn, entry_attrs, **options): ++ assert isinstance(dn, DN) ++ self.obj.convert_usercertificate_pre(entry_attrs) ++ ++ def post_common_callback(self, ldap, dn, entry_attrs, **options): ++ assert isinstance(dn, DN) ++ self.obj.convert_usercertificate_post(entry_attrs, **options) + + class baseuser_del(LDAPDelete): + """ +@@ -542,6 +559,7 @@ class baseuser_mod(LDAPUpdate): + self.check_userpassword(entry_attrs, **options) + + self.check_objectclass(ldap, dn, entry_attrs) ++ self.obj.convert_usercertificate_pre(entry_attrs) + + def post_common_callback(self, ldap, dn, entry_attrs, **options): + assert isinstance(dn, DN) +@@ -554,6 +572,7 @@ class baseuser_mod(LDAPUpdate): + convert_nsaccountlock(entry_attrs) + self.obj.convert_manager(entry_attrs, **options) + self.obj.get_password_attributes(ldap, dn, entry_attrs) ++ self.obj.convert_usercertificate_post(entry_attrs, **options) + convert_sshpubkey_post(ldap, dn, entry_attrs) + radius_dn2pk(self.api, entry_attrs) + +@@ -584,6 +603,7 @@ class baseuser_find(LDAPSearch): + for attrs in entries: + self.obj.convert_manager(attrs, **options) + self.obj.get_password_attributes(ldap, attrs.dn, attrs) ++ self.obj.convert_usercertificate_post(attrs, **options) + if (lockout): + attrs['nsaccountlock'] = True + else: +@@ -598,5 +618,6 @@ class baseuser_show(LDAPRetrieve): + assert isinstance(dn, DN) + self.obj.convert_manager(entry_attrs, **options) + self.obj.get_password_attributes(ldap, dn, entry_attrs) ++ self.obj.convert_usercertificate_post(entry_attrs, **options) + convert_sshpubkey_post(ldap, dn, entry_attrs) + radius_dn2pk(self.api, entry_attrs) +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 0209b29b130f2377c04f497f95c8ad39e98f2587..859939205f903fa4832524c8d2601141f3674bb5 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -510,6 +510,8 @@ class user_add(baseuser_add): + answer = self.api.Object['radiusproxy'].get_dn_if_exists(rcl) + entry_attrs['ipatokenradiusconfiglink'] = answer + ++ self.pre_common_callback(ldap, dn, entry_attrs, **options) ++ + return dn + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): +@@ -557,6 +559,9 @@ class user_add(baseuser_add): + convert_sshpubkey_post(ldap, dn, entry_attrs) + radius_dn2pk(self.api, entry_attrs) + self.obj.get_preserved_attribute(entry_attrs, options) ++ ++ self.post_common_callback(ldap, dn, entry_attrs, **options) ++ + return dn + + +@@ -1034,18 +1039,14 @@ class user_add_cert(LDAPAddAttribute): + **options): + assert isinstance(dn, DN) + +- new_attr_name = '%s;binary' % self.attribute +- if self.attribute in entry_attrs: +- entry_attrs[new_attr_name] = entry_attrs.pop(self.attribute) ++ self.obj.convert_usercertificate_pre(entry_attrs) + + return dn + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + assert isinstance(dn, DN) + +- old_attr_name = '%s;binary' % self.attribute +- if old_attr_name in entry_attrs: +- entry_attrs[self.attribute] = entry_attrs.pop(old_attr_name) ++ self.obj.convert_usercertificate_post(entry_attrs, **options) + + return dn + +@@ -1060,17 +1061,13 @@ class user_remove_cert(LDAPRemoveAttribute): + **options): + assert isinstance(dn, DN) + +- new_attr_name = '%s;binary' % self.attribute +- if self.attribute in entry_attrs: +- entry_attrs[new_attr_name] = entry_attrs.pop(self.attribute) ++ self.obj.convert_usercertificate_pre(entry_attrs) + + return dn + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + assert isinstance(dn, DN) + +- old_attr_name = '%s;binary' % self.attribute +- if old_attr_name in entry_attrs: +- entry_attrs[self.attribute] = entry_attrs.pop(old_attr_name) ++ self.obj.convert_usercertificate_post(entry_attrs, **options) + + return dn +-- +2.4.3 + diff --git a/SOURCES/0041-Fix-incorrect-type-comparison-in-trust-fetch-domains.patch b/SOURCES/0041-Fix-incorrect-type-comparison-in-trust-fetch-domains.patch new file mode 100644 index 0000000..3e06394 --- /dev/null +++ b/SOURCES/0041-Fix-incorrect-type-comparison-in-trust-fetch-domains.patch @@ -0,0 +1,30 @@ +From 8233849dd703e964f6abb70d2a4f37377d5bb7f0 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 5 Aug 2015 17:31:47 +0200 +Subject: [PATCH] Fix incorrect type comparison in trust-fetch-domains + +Value needs to be unpacked from the list and converted before comparison. + +https://fedorahosted.org/freeipa/ticket/5182 + +Reviewed-By: Alexander Bokovoy +--- + ipalib/plugins/trust.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py +index 6232e4fe9d3d5e957d22a3557cdcf4bb12cec0ea..0bb5e6558b680ac1acad44461d78a571098c7b25 100644 +--- a/ipalib/plugins/trust.py ++++ b/ipalib/plugins/trust.py +@@ -1487,7 +1487,7 @@ class trust_fetch_domains(LDAPRetrieve): + result['truncated'] = False + + # For one-way trust fetch over DBus. we don't get the list in this case. +- if trust['ipanttrustdirection'] & TRUST_BIDIRECTIONAL != TRUST_BIDIRECTIONAL: ++ if int(trust['ipanttrustdirection'][0]) != TRUST_BIDIRECTIONAL: + fetch_trusted_domains_over_dbus(self.api, self.log, keys[0]) + result['summary'] = unicode(_('List of trust domains successfully refreshed. Use trustdomain-find command to list them.')) + return result +-- +2.4.3 + diff --git a/SOURCES/0041-restore-clear-httpd-ccache-after-restore.patch b/SOURCES/0041-restore-clear-httpd-ccache-after-restore.patch deleted file mode 100644 index ed2eb27..0000000 --- a/SOURCES/0041-restore-clear-httpd-ccache-after-restore.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 8fb9a4a82c6ab1026e3d414d39b86d0467735a37 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Thu, 20 Nov 2014 15:11:02 +0100 -Subject: [PATCH] restore: clear httpd ccache after restore - -so that httpd ccache won't contain old credentials which would make ipa CLI fail with error: - - Insufficient access: SASL(-1): generic failure: GSSAPI Error: Unspecified GSS failure. Minor code may provide more information (Decrypt integrity check failed) - -https://fedorahosted.org/freeipa/ticket/4726 - -Reviewed-By: Petr Viktorin ---- - ipaserver/install/ipa_restore.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 7b92ab5d490a7a254b1ea307d5031da002b9f653..93f176d302a49319940555a0be3037620143e1f3 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -315,6 +315,8 @@ class Restore(admintool.AdminTool): - self.log.info('Restarting SSSD') - sssd = services.service('sssd') - sssd.restart() -+ http = httpinstance.HTTPInstance() -+ http.remove_httpd_ccache() - finally: - try: - os.chdir(cwd) --- -2.1.0 - diff --git a/SOURCES/0042-Fix-selector-of-protocol-for-LSA-RPC-binding-string.patch b/SOURCES/0042-Fix-selector-of-protocol-for-LSA-RPC-binding-string.patch new file mode 100644 index 0000000..42548b9 --- /dev/null +++ b/SOURCES/0042-Fix-selector-of-protocol-for-LSA-RPC-binding-string.patch @@ -0,0 +1,37 @@ +From 2585d6d6455d7c9257a8bbc65cc489d4a424a08e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 5 Aug 2015 21:33:45 +0300 +Subject: [PATCH] Fix selector of protocol for LSA RPC binding string + +For Windows Server 2012R2 and others which force SMB2 protocol use +we have to specify right DCE RPC binding options. + +For using SMB1 protocol we have to omit specifying SMB2 protocol and +anything else or otherwise SMB1 would be considered a pipe to connect +to. This is by design of a binding string format. + +https://fedorahosted.org/freeipa/ticket/5183 + +Reviewed-By: Tomas Babej +--- + ipaserver/dcerpc.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index c604fa3eae4cf94d719190a5a3e3de15d3841d24..74b4743d4bfb9c4950f441f1aa3561fc7a81391c 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -854,8 +854,8 @@ class TrustDomainInstance(object): + We try NCACN_NP before NCACN_IP_TCP and use SMB2 before SMB1 or defaults. + """ + transports = (u'ncacn_np', u'ncacn_ip_tcp') +- options = ( u'smb2', u'smb1', u'') +- binding_template=lambda x,y,z: u'%s:%s[%s,print]' % (x, y, z) ++ options = ( u'smb2,print', u'print') ++ binding_template=lambda x,y,z: u'%s:%s[%s]' % (x, y, z) + return [binding_template(t, remote_host, o) for t in transports for o in options] + + def retrieve_anonymously(self, remote_host, discover_srv=False, search_pdc=False): +-- +2.4.3 + diff --git a/SOURCES/0042-Fix-user-group-ignore-attribute-in-migration-plugin.patch b/SOURCES/0042-Fix-user-group-ignore-attribute-in-migration-plugin.patch deleted file mode 100644 index 0b0939a..0000000 --- a/SOURCES/0042-Fix-user-group-ignore-attribute-in-migration-plugin.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 7f2021b3fc501d3ee70976f4dba06629c71ae417 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 19 Nov 2014 09:57:59 -0500 -Subject: [PATCH] Fix --{user,group}-ignore-attribute in migration plugin. - -Ignore case in attribute names. - -https://fedorahosted.org/freeipa/ticket/4620 - -Reviewed-By: Martin Basti ---- - ipalib/plugins/migration.py | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py -index 6b630a464f0be163e82de95afe3a74b22889574b..fa3d512bf1434c7d349713f78c292b481021303a 100644 ---- a/ipalib/plugins/migration.py -+++ b/ipalib/plugins/migration.py -@@ -196,9 +196,8 @@ def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs - entry_attrs.setdefault('loginshell', default_shell) - - # do not migrate all attributes -- for attr in entry_attrs.keys(): -- if attr in attr_blacklist: -- del entry_attrs[attr] -+ for attr in attr_blacklist: -+ entry_attrs.pop(attr, None) - - # do not migrate all object classes - if 'objectclass' in entry_attrs: -@@ -393,9 +392,8 @@ def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwarg - raise ValueError('Schema %s not supported' % schema) - - # do not migrate all attributes -- for attr in entry_attrs.keys(): -- if attr in attr_blacklist: -- del entry_attrs[attr] -+ for attr in attr_blacklist: -+ entry_attrs.pop(attr, None) - - # do not migrate all object classes - if 'objectclass' in entry_attrs: --- -2.1.0 - diff --git a/SOURCES/0043-Fix-filtering-of-enctypes-in-server-code.patch b/SOURCES/0043-Fix-filtering-of-enctypes-in-server-code.patch deleted file mode 100644 index 27024cf..0000000 --- a/SOURCES/0043-Fix-filtering-of-enctypes-in-server-code.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 6a6389fefdc055b5a920e6e4412ff0b7e37ef33a Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Mon, 17 Nov 2014 21:05:56 -0500 -Subject: [PATCH] Fix filtering of enctypes in server code. - -The filtering was incorrect and would result in always discarding all values. -Also make sure there are no duplicates in the list. - -Partial fix for: -https://fedorahosted.org/freeipa/ticket/4718 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Nathaniel McCallum ---- - .../ipa-pwd-extop/ipa_pwd_extop.c | 60 ++++++++++++++++------ - 1 file changed, 43 insertions(+), 17 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -index f0346a343188930dfc90e19d2e5d38cb30741b90..b87ae0dc7a180008228f31293b49212df80584e8 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -@@ -125,6 +125,48 @@ static void filter_keys(struct ipapwd_krbcfg *krbcfg, - } - } - -+static void filter_enctypes(struct ipapwd_krbcfg *krbcfg, -+ krb5_key_salt_tuple *kenctypes, -+ int *num_kenctypes) -+{ -+ /* first filter for duplicates */ -+ for (int i = 0; i + 1 < *num_kenctypes; i++) { -+ for (int j = i + 1; j < *num_kenctypes; j++) { -+ if (kenctypes[i].ks_enctype == kenctypes[j].ks_enctype) { -+ /* duplicate, filter out */ -+ for (int k = j; k + 1 < *num_kenctypes; k++) { -+ kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype; -+ kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype; -+ } -+ (*num_kenctypes)--; -+ j--; -+ } -+ } -+ } -+ -+ /* then filter for supported */ -+ for (int i = 0; i < *num_kenctypes; i++) { -+ int j; -+ -+ /* Check if supported */ -+ for (j = 0; j < krbcfg->num_supp_encsalts; j++) { -+ if (kenctypes[i].ks_enctype == -+ krbcfg->supp_encsalts[j].ks_enctype) { -+ break; -+ } -+ } -+ if (j == krbcfg->num_supp_encsalts) { -+ /* Unsupported, filter out */ -+ for (int k = i; k + 1 < *num_kenctypes; k++) { -+ kenctypes[k].ks_enctype = kenctypes[k + 1].ks_enctype; -+ kenctypes[k].ks_salttype = kenctypes[k + 1].ks_salttype; -+ } -+ (*num_kenctypes)--; -+ i--; -+ } -+ } -+} -+ - static int ipapwd_to_ldap_pwpolicy_error(int ipapwderr) - { - switch (ipapwderr) { -@@ -1740,23 +1782,7 @@ static int ipapwd_getkeytab(Slapi_PBlock *pb, struct ipapwd_krbcfg *krbcfg) - goto free_and_return; - } - -- for (int i = 0; i < num_kenctypes; i++) { -- -- /* Check if supported */ -- for (int j = 0; j < krbcfg->num_supp_encsalts; j++) { -- if (kenctypes[i].ks_enctype == -- krbcfg->supp_encsalts[j].ks_enctype) { -- continue; -- } -- } -- /* Unsupported, filter out */ -- for (int j = i; j + 1 < num_kenctypes; j++) { -- kenctypes[j].ks_enctype = kenctypes[j + 1].ks_enctype; -- kenctypes[j].ks_salttype = kenctypes[j + 1].ks_salttype; -- } -- num_kenctypes--; -- i--; -- } -+ filter_enctypes(krbcfg, kenctypes, &num_kenctypes); - - /* check if we have any left */ - if (num_kenctypes == 0 && kenctypes != NULL) { --- -2.1.0 - diff --git a/SOURCES/0043-dcerpc-Simplify-generation-of-LSA-RPC-binding-string.patch b/SOURCES/0043-dcerpc-Simplify-generation-of-LSA-RPC-binding-string.patch new file mode 100644 index 0000000..1edd83d --- /dev/null +++ b/SOURCES/0043-dcerpc-Simplify-generation-of-LSA-RPC-binding-string.patch @@ -0,0 +1,29 @@ +From 47e9c9cacdc189ac87983ed1596db3d48f45e089 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Fri, 7 Aug 2015 18:03:48 +0200 +Subject: [PATCH] dcerpc: Simplify generation of LSA-RPC binding strings + +https://fedorahosted.org/freeipa/ticket/5183 + +Reviewed-By: Tomas Babej +--- + ipaserver/dcerpc.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index 74b4743d4bfb9c4950f441f1aa3561fc7a81391c..71106b6a804b8445e5c266a92a30ac7557dcf853 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -855,8 +855,7 @@ class TrustDomainInstance(object): + """ + transports = (u'ncacn_np', u'ncacn_ip_tcp') + options = ( u'smb2,print', u'print') +- binding_template=lambda x,y,z: u'%s:%s[%s]' % (x, y, z) +- return [binding_template(t, remote_host, o) for t in transports for o in options] ++ return [u'%s:%s[%s]' % (t, remote_host, o) for t in transports for o in options] + + def retrieve_anonymously(self, remote_host, discover_srv=False, search_pdc=False): + """ +-- +2.4.3 + diff --git a/SOURCES/0044-Add-asn1c-generated-code-for-keytab-controls.patch b/SOURCES/0044-Add-asn1c-generated-code-for-keytab-controls.patch deleted file mode 100644 index 31aba71..0000000 --- a/SOURCES/0044-Add-asn1c-generated-code-for-keytab-controls.patch +++ /dev/null @@ -1,13109 +0,0 @@ -From eaad64ae7202fd46c85cc20fc9a09891efb3c937 Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Thu, 13 Nov 2014 11:31:09 -0500 -Subject: [PATCH] Add asn1c generated code for keytab controls - -Instead of manually encoding controls, use an actual asn1 compiler. -The file asn1/asn1c/ipa.asn1 will contain ipa modules. The generated code -is committed to the tree and built into a static library that is linked -to the code that uses it. - -The first module implements the GetKeytabControl control. - -Related: -https://fedorahosted.org/freeipa/ticket/4718 -https://fedorahosted.org/freeipa/ticket/4728 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Nathaniel McCallum ---- - .gitignore | 1 + - Makefile | 5 +- - asn1/Makefile.am | 8 + - asn1/README | 17 + - asn1/asn1c/BIT_STRING.c | 188 +++++ - asn1/asn1c/BIT_STRING.h | 33 + - asn1/asn1c/GKCurrentKeys.c | 61 ++ - asn1/asn1c/GKCurrentKeys.h | 37 + - asn1/asn1c/GKNewKeys.c | 126 ++++ - asn1/asn1c/GKNewKeys.h | 47 ++ - asn1/asn1c/GKReply.c | 115 +++ - asn1/asn1c/GKReply.h | 51 ++ - asn1/asn1c/GetKeytabControl.c | 77 ++ - asn1/asn1c/GetKeytabControl.h | 52 ++ - asn1/asn1c/INTEGER.c | 835 +++++++++++++++++++++ - asn1/asn1c/INTEGER.h | 65 ++ - asn1/asn1c/Int32.c | 127 ++++ - asn1/asn1c/Int32.h | 38 + - asn1/asn1c/KrbKey.c | 81 ++ - asn1/asn1c/KrbKey.h | 46 ++ - asn1/asn1c/Makefile.am | 93 +++ - asn1/asn1c/NativeEnumerated.c | 204 ++++++ - asn1/asn1c/NativeEnumerated.h | 32 + - asn1/asn1c/NativeInteger.c | 314 ++++++++ - asn1/asn1c/NativeInteger.h | 37 + - asn1/asn1c/OCTET_STRING.c | 1550 +++++++++++++++++++++++++++++++++++++++ - asn1/asn1c/OCTET_STRING.h | 80 ++ - asn1/asn1c/TypeValuePair.c | 71 ++ - asn1/asn1c/TypeValuePair.h | 39 + - asn1/asn1c/asn_SEQUENCE_OF.c | 41 ++ - asn1/asn1c/asn_SEQUENCE_OF.h | 52 ++ - asn1/asn1c/asn_SET_OF.c | 88 +++ - asn1/asn1c/asn_SET_OF.h | 62 ++ - asn1/asn1c/asn_application.h | 47 ++ - asn1/asn1c/asn_codecs.h | 109 +++ - asn1/asn1c/asn_codecs_prim.c | 295 ++++++++ - asn1/asn1c/asn_codecs_prim.h | 53 ++ - asn1/asn1c/asn_internal.h | 111 +++ - asn1/asn1c/asn_system.h | 104 +++ - asn1/asn1c/ber_decoder.c | 283 +++++++ - asn1/asn1c/ber_decoder.h | 63 ++ - asn1/asn1c/ber_tlv_length.c | 178 +++++ - asn1/asn1c/ber_tlv_length.h | 50 ++ - asn1/asn1c/ber_tlv_tag.c | 144 ++++ - asn1/asn1c/ber_tlv_tag.h | 60 ++ - asn1/asn1c/constr_CHOICE.c | 1101 +++++++++++++++++++++++++++ - asn1/asn1c/constr_CHOICE.h | 57 ++ - asn1/asn1c/constr_SEQUENCE.c | 1251 +++++++++++++++++++++++++++++++ - asn1/asn1c/constr_SEQUENCE.h | 60 ++ - asn1/asn1c/constr_SEQUENCE_OF.c | 208 ++++++ - asn1/asn1c/constr_SEQUENCE_OF.h | 33 + - asn1/asn1c/constr_SET_OF.c | 942 ++++++++++++++++++++++++ - asn1/asn1c/constr_SET_OF.h | 42 ++ - asn1/asn1c/constr_TYPE.c | 77 ++ - asn1/asn1c/constr_TYPE.h | 180 +++++ - asn1/asn1c/constraints.c | 93 +++ - asn1/asn1c/constraints.h | 63 ++ - asn1/asn1c/der_encoder.c | 199 +++++ - asn1/asn1c/der_encoder.h | 67 ++ - asn1/asn1c/ipa.asn1 | 37 + - asn1/asn1c/per_decoder.c | 55 ++ - asn1/asn1c/per_decoder.h | 44 ++ - asn1/asn1c/per_encoder.c | 95 +++ - asn1/asn1c/per_encoder.h | 49 ++ - asn1/asn1c/per_support.c | 318 ++++++++ - asn1/asn1c/per_support.h | 105 +++ - asn1/asn1c/xer_decoder.c | 363 +++++++++ - asn1/asn1c/xer_decoder.h | 106 +++ - asn1/asn1c/xer_encoder.c | 67 ++ - asn1/asn1c/xer_encoder.h | 59 ++ - asn1/asn1c/xer_support.c | 233 ++++++ - asn1/asn1c/xer_support.h | 55 ++ - asn1/configure.ac | 24 + - asn1/ipa_asn1.c | 229 ++++++ - asn1/ipa_asn1.h | 76 ++ - util/ipa_krb5.h | 1 + - 76 files changed, 12457 insertions(+), 2 deletions(-) - create mode 100644 asn1/Makefile.am - create mode 100644 asn1/README - create mode 100644 asn1/asn1c/BIT_STRING.c - create mode 100644 asn1/asn1c/BIT_STRING.h - create mode 100644 asn1/asn1c/GKCurrentKeys.c - create mode 100644 asn1/asn1c/GKCurrentKeys.h - create mode 100644 asn1/asn1c/GKNewKeys.c - create mode 100644 asn1/asn1c/GKNewKeys.h - create mode 100644 asn1/asn1c/GKReply.c - create mode 100644 asn1/asn1c/GKReply.h - create mode 100644 asn1/asn1c/GetKeytabControl.c - create mode 100644 asn1/asn1c/GetKeytabControl.h - create mode 100644 asn1/asn1c/INTEGER.c - create mode 100644 asn1/asn1c/INTEGER.h - create mode 100644 asn1/asn1c/Int32.c - create mode 100644 asn1/asn1c/Int32.h - create mode 100644 asn1/asn1c/KrbKey.c - create mode 100644 asn1/asn1c/KrbKey.h - create mode 100644 asn1/asn1c/Makefile.am - create mode 100644 asn1/asn1c/NativeEnumerated.c - create mode 100644 asn1/asn1c/NativeEnumerated.h - create mode 100644 asn1/asn1c/NativeInteger.c - create mode 100644 asn1/asn1c/NativeInteger.h - create mode 100644 asn1/asn1c/OCTET_STRING.c - create mode 100644 asn1/asn1c/OCTET_STRING.h - create mode 100644 asn1/asn1c/TypeValuePair.c - create mode 100644 asn1/asn1c/TypeValuePair.h - create mode 100644 asn1/asn1c/asn_SEQUENCE_OF.c - create mode 100644 asn1/asn1c/asn_SEQUENCE_OF.h - create mode 100644 asn1/asn1c/asn_SET_OF.c - create mode 100644 asn1/asn1c/asn_SET_OF.h - create mode 100644 asn1/asn1c/asn_application.h - create mode 100644 asn1/asn1c/asn_codecs.h - create mode 100644 asn1/asn1c/asn_codecs_prim.c - create mode 100644 asn1/asn1c/asn_codecs_prim.h - create mode 100644 asn1/asn1c/asn_internal.h - create mode 100644 asn1/asn1c/asn_system.h - create mode 100644 asn1/asn1c/ber_decoder.c - create mode 100644 asn1/asn1c/ber_decoder.h - create mode 100644 asn1/asn1c/ber_tlv_length.c - create mode 100644 asn1/asn1c/ber_tlv_length.h - create mode 100644 asn1/asn1c/ber_tlv_tag.c - create mode 100644 asn1/asn1c/ber_tlv_tag.h - create mode 100644 asn1/asn1c/constr_CHOICE.c - create mode 100644 asn1/asn1c/constr_CHOICE.h - create mode 100644 asn1/asn1c/constr_SEQUENCE.c - create mode 100644 asn1/asn1c/constr_SEQUENCE.h - create mode 100644 asn1/asn1c/constr_SEQUENCE_OF.c - create mode 100644 asn1/asn1c/constr_SEQUENCE_OF.h - create mode 100644 asn1/asn1c/constr_SET_OF.c - create mode 100644 asn1/asn1c/constr_SET_OF.h - create mode 100644 asn1/asn1c/constr_TYPE.c - create mode 100644 asn1/asn1c/constr_TYPE.h - create mode 100644 asn1/asn1c/constraints.c - create mode 100644 asn1/asn1c/constraints.h - create mode 100644 asn1/asn1c/der_encoder.c - create mode 100644 asn1/asn1c/der_encoder.h - create mode 100644 asn1/asn1c/ipa.asn1 - create mode 100644 asn1/asn1c/per_decoder.c - create mode 100644 asn1/asn1c/per_decoder.h - create mode 100644 asn1/asn1c/per_encoder.c - create mode 100644 asn1/asn1c/per_encoder.h - create mode 100644 asn1/asn1c/per_support.c - create mode 100644 asn1/asn1c/per_support.h - create mode 100644 asn1/asn1c/xer_decoder.c - create mode 100644 asn1/asn1c/xer_decoder.h - create mode 100644 asn1/asn1c/xer_encoder.c - create mode 100644 asn1/asn1c/xer_encoder.h - create mode 100644 asn1/asn1c/xer_support.c - create mode 100644 asn1/asn1c/xer_support.h - create mode 100644 asn1/configure.ac - create mode 100644 asn1/ipa_asn1.c - create mode 100644 asn1/ipa_asn1.h - -diff --git a/.gitignore b/.gitignore -index 5b3f401d26c172cf24a08014651e453439a5e9d1..c4c761903d29e1b9f62c7ece04dbaa187fb84de8 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -25,6 +25,7 @@ missing - stamp-h1 - libtool - build/ -+compile - - # Python compilation - *.pyc -diff --git a/Makefile b/Makefile -index eca282a2390002dcefcc7b544b69a47b81418e0d..c1a298f91717246e8dab5e3f0de47d0ac9b2ae35 100644 ---- a/Makefile -+++ b/Makefile -@@ -1,7 +1,7 @@ - include VERSION - --SUBDIRS=daemons install ipapython ipa-client --CLIENTDIRS=ipapython ipa-client -+SUBDIRS=asn1 daemons install ipapython ipa-client -+CLIENTDIRS=ipapython ipa-client asn1 - - PRJ_PREFIX=freeipa - -@@ -79,6 +79,7 @@ bootstrap-autogen: version-update client-autogen - cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - - client-autogen: version-update -+ cd asn1; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - cd ipa-client; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - -diff --git a/asn1/Makefile.am b/asn1/Makefile.am -new file mode 100644 -index 0000000000000000000000000000000000000000..03e92b2d6d73f89625d5613f039361a6e02866b9 ---- /dev/null -+++ b/asn1/Makefile.am -@@ -0,0 +1,8 @@ -+SUBDIRS = asn1c -+ -+AM_CPPFLAGS = -I../util -Iasn1c -+ -+noinst_LTLIBRARIES=libipaasn1.la -+noinst_HEADERS=ipa_asn1.h -+libipaasn1_la_SOURCES=ipa_asn1.c -+libipaasn1_la_LIBADD=asn1c/libasn1c.la -diff --git a/asn1/README b/asn1/README -new file mode 100644 -index 0000000000000000000000000000000000000000..ec9752f566a8b57b45d433bb46316c9aba325fa7 ---- /dev/null -+++ b/asn1/README -@@ -0,0 +1,17 @@ -+libipaasn1.a is a small static convenience library used by other ipa -+binaries and modules. At the moment it is not meant to be a public shared -+library and stable interface, but may become one in future. -+ -+The only files that should be manually modified are: -+* asn1c/ipa.asn1 - when new interfaces are added -+* ipa_asn1.[ch] - to add wrappers around interfaces -+ -+ipa_asn1.[ch] are the public interface and they SHOULD NOT export generated -+structures so that the autogenerated code can change w/o impacting any other -+code except the internal library functions. -+ -+To regenerate the automatically generated files run the following command: -+cd asn1c; -+make regenerate -+ -+Remember to commit and add any new file to asn1c/Makefile.am -diff --git a/asn1/asn1c/BIT_STRING.c b/asn1/asn1c/BIT_STRING.c -new file mode 100644 -index 0000000000000000000000000000000000000000..6469d4fd2c8782048e228c19e67950f3b2dc1305 ---- /dev/null -+++ b/asn1/asn1c/BIT_STRING.c -@@ -0,0 +1,188 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * BIT STRING basic type description. -+ */ -+static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) -+}; -+static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { -+ sizeof(BIT_STRING_t), -+ offsetof(BIT_STRING_t, _asn_ctx), -+ 1, /* Special indicator that this is a BIT STRING type */ -+}; -+asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { -+ "BIT STRING", -+ "BIT_STRING", -+ OCTET_STRING_free, /* Implemented in terms of OCTET STRING */ -+ BIT_STRING_print, -+ BIT_STRING_constraint, -+ OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ -+ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ -+ OCTET_STRING_decode_xer_binary, -+ BIT_STRING_encode_xer, -+ OCTET_STRING_decode_uper, /* Unaligned PER decoder */ -+ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_BIT_STRING_tags, -+ sizeof(asn_DEF_BIT_STRING_tags) -+ / sizeof(asn_DEF_BIT_STRING_tags[0]), -+ asn_DEF_BIT_STRING_tags, /* Same as above */ -+ sizeof(asn_DEF_BIT_STRING_tags) -+ / sizeof(asn_DEF_BIT_STRING_tags[0]), -+ 0, /* No PER visible constraints */ -+ 0, 0, /* No members */ -+ &asn_DEF_BIT_STRING_specs -+}; -+ -+/* -+ * BIT STRING generic constraint. -+ */ -+int -+BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr, -+ asn_app_constraint_failed_f *ctfailcb, void *app_key) { -+ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; -+ -+ if(st && st->buf) { -+ if(st->size == 1 && st->bits_unused) { -+ _ASN_CTFAIL(app_key, td, -+ "%s: invalid padding byte (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+ } else { -+ _ASN_CTFAIL(app_key, td, -+ "%s: value not given (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static char *_bit_pattern[16] = { -+ "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", -+ "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" -+}; -+ -+asn_enc_rval_t -+BIT_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t er; -+ char scratch[128]; -+ char *p = scratch; -+ char *scend = scratch + (sizeof(scratch) - 10); -+ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; -+ int xcan = (flags & XER_F_CANONICAL); -+ uint8_t *buf; -+ uint8_t *end; -+ -+ if(!st || !st->buf) -+ _ASN_ENCODE_FAILED; -+ -+ er.encoded = 0; -+ -+ buf = st->buf; -+ end = buf + st->size - 1; /* Last byte is special */ -+ -+ /* -+ * Binary dump -+ */ -+ for(; buf < end; buf++) { -+ int v = *buf; -+ int nline = xcan?0:(((buf - st->buf) % 8) == 0); -+ if(p >= scend || nline) { -+ er.encoded += p - scratch; -+ _ASN_CALLBACK(scratch, p - scratch); -+ p = scratch; -+ if(nline) _i_ASN_TEXT_INDENT(1, ilevel); -+ } -+ memcpy(p + 0, _bit_pattern[v >> 4], 4); -+ memcpy(p + 4, _bit_pattern[v & 0x0f], 4); -+ p += 8; -+ } -+ -+ if(!xcan && ((buf - st->buf) % 8) == 0) -+ _i_ASN_TEXT_INDENT(1, ilevel); -+ er.encoded += p - scratch; -+ _ASN_CALLBACK(scratch, p - scratch); -+ p = scratch; -+ -+ if(buf == end) { -+ int v = *buf; -+ int ubits = st->bits_unused; -+ int i; -+ for(i = 7; i >= ubits; i--) -+ *p++ = (v & (1 << i)) ? 0x31 : 0x30; -+ er.encoded += p - scratch; -+ _ASN_CALLBACK(scratch, p - scratch); -+ } -+ -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); -+ -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+ -+/* -+ * BIT STRING specific contents printer. -+ */ -+int -+BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ static const char *h2c = "0123456789ABCDEF"; -+ char scratch[64]; -+ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; -+ uint8_t *buf; -+ uint8_t *end; -+ char *p = scratch; -+ -+ (void)td; /* Unused argument */ -+ -+ if(!st || !st->buf) -+ return (cb("", 8, app_key) < 0) ? -1 : 0; -+ -+ ilevel++; -+ buf = st->buf; -+ end = buf + st->size; -+ -+ /* -+ * Hexadecimal dump. -+ */ -+ for(; buf < end; buf++) { -+ if((buf - st->buf) % 16 == 0 && (st->size > 16) -+ && buf != st->buf) { -+ _i_INDENT(1); -+ /* Dump the string */ -+ if(cb(scratch, p - scratch, app_key) < 0) return -1; -+ p = scratch; -+ } -+ *p++ = h2c[*buf >> 4]; -+ *p++ = h2c[*buf & 0x0F]; -+ *p++ = 0x20; -+ } -+ -+ if(p > scratch) { -+ p--; /* Eat the tailing space */ -+ -+ if((st->size > 16)) { -+ _i_INDENT(1); -+ } -+ -+ /* Dump the incomplete 16-bytes row */ -+ if(cb(scratch, p - scratch, app_key) < 0) -+ return -1; -+ } -+ -+ return 0; -+} -+ -diff --git a/asn1/asn1c/BIT_STRING.h b/asn1/asn1c/BIT_STRING.h -new file mode 100644 -index 0000000000000000000000000000000000000000..732e878bcad1694e685153934afd8ce91f869e83 ---- /dev/null -+++ b/asn1/asn1c/BIT_STRING.h -@@ -0,0 +1,33 @@ -+/*- -+ * Copyright (c) 2003 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _BIT_STRING_H_ -+#define _BIT_STRING_H_ -+ -+#include /* Some help from OCTET STRING */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct BIT_STRING_s { -+ uint8_t *buf; /* BIT STRING body */ -+ int size; /* Size of the above buffer */ -+ -+ int bits_unused;/* Unused trailing bits in the last octet (0..7) */ -+ -+ asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ -+} BIT_STRING_t; -+ -+extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; -+ -+asn_struct_print_f BIT_STRING_print; /* Human-readable output */ -+asn_constr_check_f BIT_STRING_constraint; -+xer_type_encoder_f BIT_STRING_encode_xer; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _BIT_STRING_H_ */ -diff --git a/asn1/asn1c/GKCurrentKeys.c b/asn1/asn1c/GKCurrentKeys.c -new file mode 100644 -index 0000000000000000000000000000000000000000..abcc53130d64259d0f2947b04412b4b769bb4360 ---- /dev/null -+++ b/asn1/asn1c/GKCurrentKeys.c -@@ -0,0 +1,61 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "GKCurrentKeys.h" -+ -+static asn_TYPE_member_t asn_MBR_GKCurrentKeys_1[] = { -+ { ATF_NOFLAGS, 0, offsetof(struct GKCurrentKeys, serviceIdentity), -+ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_OCTET_STRING, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "serviceIdentity" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_GKCurrentKeys_tags_1[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_TYPE_tag2member_t asn_MAP_GKCurrentKeys_tag2el_1[] = { -+ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* serviceIdentity at 19 */ -+}; -+static asn_SEQUENCE_specifics_t asn_SPC_GKCurrentKeys_specs_1 = { -+ sizeof(struct GKCurrentKeys), -+ offsetof(struct GKCurrentKeys, _asn_ctx), -+ asn_MAP_GKCurrentKeys_tag2el_1, -+ 1, /* Count of tags in the map */ -+ 0, 0, 0, /* Optional elements (not needed) */ -+ -1, /* Start extensions */ -+ -1 /* Stop extensions */ -+}; -+asn_TYPE_descriptor_t asn_DEF_GKCurrentKeys = { -+ "GKCurrentKeys", -+ "GKCurrentKeys", -+ SEQUENCE_free, -+ SEQUENCE_print, -+ SEQUENCE_constraint, -+ SEQUENCE_decode_ber, -+ SEQUENCE_encode_der, -+ SEQUENCE_decode_xer, -+ SEQUENCE_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_GKCurrentKeys_tags_1, -+ sizeof(asn_DEF_GKCurrentKeys_tags_1) -+ /sizeof(asn_DEF_GKCurrentKeys_tags_1[0]), /* 1 */ -+ asn_DEF_GKCurrentKeys_tags_1, /* Same as above */ -+ sizeof(asn_DEF_GKCurrentKeys_tags_1) -+ /sizeof(asn_DEF_GKCurrentKeys_tags_1[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_GKCurrentKeys_1, -+ 1, /* Elements count */ -+ &asn_SPC_GKCurrentKeys_specs_1 /* Additional specs */ -+}; -+ -diff --git a/asn1/asn1c/GKCurrentKeys.h b/asn1/asn1c/GKCurrentKeys.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7ec4e4c60dd5c605bec311f713e33630dedaca58 ---- /dev/null -+++ b/asn1/asn1c/GKCurrentKeys.h -@@ -0,0 +1,37 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _GKCurrentKeys_H_ -+#define _GKCurrentKeys_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* GKCurrentKeys */ -+typedef struct GKCurrentKeys { -+ OCTET_STRING_t serviceIdentity; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+} GKCurrentKeys_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_GKCurrentKeys; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _GKCurrentKeys_H_ */ -diff --git a/asn1/asn1c/GKNewKeys.c b/asn1/asn1c/GKNewKeys.c -new file mode 100644 -index 0000000000000000000000000000000000000000..35ebcf245c25c02572377381ba3418f3f8488fd7 ---- /dev/null -+++ b/asn1/asn1c/GKNewKeys.c -@@ -0,0 +1,126 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "GKNewKeys.h" -+ -+static asn_TYPE_member_t asn_MBR_enctypes_3[] = { -+ { ATF_POINTER, 0, 0, -+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), -+ 0, -+ &asn_DEF_Int32, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_enctypes_tags_3[] = { -+ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_SET_OF_specifics_t asn_SPC_enctypes_specs_3 = { -+ sizeof(struct enctypes), -+ offsetof(struct enctypes, _asn_ctx), -+ 0, /* XER encoding is XMLDelimitedItemList */ -+}; -+static /* Use -fall-defs-global to expose */ -+asn_TYPE_descriptor_t asn_DEF_enctypes_3 = { -+ "enctypes", -+ "enctypes", -+ SEQUENCE_OF_free, -+ SEQUENCE_OF_print, -+ SEQUENCE_OF_constraint, -+ SEQUENCE_OF_decode_ber, -+ SEQUENCE_OF_encode_der, -+ SEQUENCE_OF_decode_xer, -+ SEQUENCE_OF_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_enctypes_tags_3, -+ sizeof(asn_DEF_enctypes_tags_3) -+ /sizeof(asn_DEF_enctypes_tags_3[0]), /* 2 */ -+ asn_DEF_enctypes_tags_3, /* Same as above */ -+ sizeof(asn_DEF_enctypes_tags_3) -+ /sizeof(asn_DEF_enctypes_tags_3[0]), /* 2 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_enctypes_3, -+ 1, /* Single element */ -+ &asn_SPC_enctypes_specs_3 /* Additional specs */ -+}; -+ -+static asn_TYPE_member_t asn_MBR_GKNewKeys_1[] = { -+ { ATF_NOFLAGS, 0, offsetof(struct GKNewKeys, serviceIdentity), -+ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_OCTET_STRING, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "serviceIdentity" -+ }, -+ { ATF_NOFLAGS, 0, offsetof(struct GKNewKeys, enctypes), -+ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_enctypes_3, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "enctypes" -+ }, -+ { ATF_POINTER, 1, offsetof(struct GKNewKeys, password), -+ (ASN_TAG_CLASS_CONTEXT | (2 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_OCTET_STRING, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "password" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_GKNewKeys_tags_1[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_TYPE_tag2member_t asn_MAP_GKNewKeys_tag2el_1[] = { -+ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* serviceIdentity at 13 */ -+ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* enctypes at 14 */ -+ { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* password at 15 */ -+}; -+static asn_SEQUENCE_specifics_t asn_SPC_GKNewKeys_specs_1 = { -+ sizeof(struct GKNewKeys), -+ offsetof(struct GKNewKeys, _asn_ctx), -+ asn_MAP_GKNewKeys_tag2el_1, -+ 3, /* Count of tags in the map */ -+ 0, 0, 0, /* Optional elements (not needed) */ -+ -1, /* Start extensions */ -+ -1 /* Stop extensions */ -+}; -+asn_TYPE_descriptor_t asn_DEF_GKNewKeys = { -+ "GKNewKeys", -+ "GKNewKeys", -+ SEQUENCE_free, -+ SEQUENCE_print, -+ SEQUENCE_constraint, -+ SEQUENCE_decode_ber, -+ SEQUENCE_encode_der, -+ SEQUENCE_decode_xer, -+ SEQUENCE_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_GKNewKeys_tags_1, -+ sizeof(asn_DEF_GKNewKeys_tags_1) -+ /sizeof(asn_DEF_GKNewKeys_tags_1[0]), /* 1 */ -+ asn_DEF_GKNewKeys_tags_1, /* Same as above */ -+ sizeof(asn_DEF_GKNewKeys_tags_1) -+ /sizeof(asn_DEF_GKNewKeys_tags_1[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_GKNewKeys_1, -+ 3, /* Elements count */ -+ &asn_SPC_GKNewKeys_specs_1 /* Additional specs */ -+}; -+ -diff --git a/asn1/asn1c/GKNewKeys.h b/asn1/asn1c/GKNewKeys.h -new file mode 100644 -index 0000000000000000000000000000000000000000..2cd158dff9c36cd6f632448235e889f3c8ab937f ---- /dev/null -+++ b/asn1/asn1c/GKNewKeys.h -@@ -0,0 +1,47 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _GKNewKeys_H_ -+#define _GKNewKeys_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include -+#include "Int32.h" -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* GKNewKeys */ -+typedef struct GKNewKeys { -+ OCTET_STRING_t serviceIdentity; -+ struct enctypes { -+ A_SEQUENCE_OF(Int32_t) list; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+ } enctypes; -+ OCTET_STRING_t *password /* OPTIONAL */; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+} GKNewKeys_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_GKNewKeys; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _GKNewKeys_H_ */ -diff --git a/asn1/asn1c/GKReply.c b/asn1/asn1c/GKReply.c -new file mode 100644 -index 0000000000000000000000000000000000000000..220c791e2d84b2ea9d889307403bc2b64781f3ce ---- /dev/null -+++ b/asn1/asn1c/GKReply.c -@@ -0,0 +1,115 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "GKReply.h" -+ -+static asn_TYPE_member_t asn_MBR_keys_3[] = { -+ { ATF_POINTER, 0, 0, -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), -+ 0, -+ &asn_DEF_KrbKey, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_keys_tags_3[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_SET_OF_specifics_t asn_SPC_keys_specs_3 = { -+ sizeof(struct keys), -+ offsetof(struct keys, _asn_ctx), -+ 0, /* XER encoding is XMLDelimitedItemList */ -+}; -+static /* Use -fall-defs-global to expose */ -+asn_TYPE_descriptor_t asn_DEF_keys_3 = { -+ "keys", -+ "keys", -+ SEQUENCE_OF_free, -+ SEQUENCE_OF_print, -+ SEQUENCE_OF_constraint, -+ SEQUENCE_OF_decode_ber, -+ SEQUENCE_OF_encode_der, -+ SEQUENCE_OF_decode_xer, -+ SEQUENCE_OF_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_keys_tags_3, -+ sizeof(asn_DEF_keys_tags_3) -+ /sizeof(asn_DEF_keys_tags_3[0]), /* 1 */ -+ asn_DEF_keys_tags_3, /* Same as above */ -+ sizeof(asn_DEF_keys_tags_3) -+ /sizeof(asn_DEF_keys_tags_3[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_keys_3, -+ 1, /* Single element */ -+ &asn_SPC_keys_specs_3 /* Additional specs */ -+}; -+ -+static asn_TYPE_member_t asn_MBR_GKReply_1[] = { -+ { ATF_NOFLAGS, 0, offsetof(struct GKReply, newkvno), -+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), -+ 0, -+ &asn_DEF_Int32, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "newkvno" -+ }, -+ { ATF_NOFLAGS, 0, offsetof(struct GKReply, keys), -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), -+ 0, -+ &asn_DEF_keys_3, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "keys" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_GKReply_tags_1[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_TYPE_tag2member_t asn_MAP_GKReply_tag2el_1[] = { -+ { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 0, 0, 0 }, /* newkvno at 23 */ -+ { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 1, 0, 0 } /* keys at 25 */ -+}; -+static asn_SEQUENCE_specifics_t asn_SPC_GKReply_specs_1 = { -+ sizeof(struct GKReply), -+ offsetof(struct GKReply, _asn_ctx), -+ asn_MAP_GKReply_tag2el_1, -+ 2, /* Count of tags in the map */ -+ 0, 0, 0, /* Optional elements (not needed) */ -+ -1, /* Start extensions */ -+ -1 /* Stop extensions */ -+}; -+asn_TYPE_descriptor_t asn_DEF_GKReply = { -+ "GKReply", -+ "GKReply", -+ SEQUENCE_free, -+ SEQUENCE_print, -+ SEQUENCE_constraint, -+ SEQUENCE_decode_ber, -+ SEQUENCE_encode_der, -+ SEQUENCE_decode_xer, -+ SEQUENCE_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_GKReply_tags_1, -+ sizeof(asn_DEF_GKReply_tags_1) -+ /sizeof(asn_DEF_GKReply_tags_1[0]), /* 1 */ -+ asn_DEF_GKReply_tags_1, /* Same as above */ -+ sizeof(asn_DEF_GKReply_tags_1) -+ /sizeof(asn_DEF_GKReply_tags_1[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_GKReply_1, -+ 2, /* Elements count */ -+ &asn_SPC_GKReply_specs_1 /* Additional specs */ -+}; -+ -diff --git a/asn1/asn1c/GKReply.h b/asn1/asn1c/GKReply.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7f058f6bf481ee2e570138f06fdef3d913949e9f ---- /dev/null -+++ b/asn1/asn1c/GKReply.h -@@ -0,0 +1,51 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _GKReply_H_ -+#define _GKReply_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include "Int32.h" -+#include -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Forward declarations */ -+struct KrbKey; -+ -+/* GKReply */ -+typedef struct GKReply { -+ Int32_t newkvno; -+ struct keys { -+ A_SEQUENCE_OF(struct KrbKey) list; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+ } keys; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+} GKReply_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_GKReply; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+/* Referred external types */ -+#include "KrbKey.h" -+ -+#endif /* _GKReply_H_ */ -diff --git a/asn1/asn1c/GetKeytabControl.c b/asn1/asn1c/GetKeytabControl.c -new file mode 100644 -index 0000000000000000000000000000000000000000..65b55d1ef34e31b81ef7b751608da4cc6c12020c ---- /dev/null -+++ b/asn1/asn1c/GetKeytabControl.c -@@ -0,0 +1,77 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "GetKeytabControl.h" -+ -+static asn_TYPE_member_t asn_MBR_GetKeytabControl_1[] = { -+ { ATF_NOFLAGS, 0, offsetof(struct GetKeytabControl, choice.newkeys), -+ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_GKNewKeys, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "newkeys" -+ }, -+ { ATF_NOFLAGS, 0, offsetof(struct GetKeytabControl, choice.curkeys), -+ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_GKCurrentKeys, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "curkeys" -+ }, -+ { ATF_NOFLAGS, 0, offsetof(struct GetKeytabControl, choice.reply), -+ (ASN_TAG_CLASS_CONTEXT | (2 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_GKReply, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "reply" -+ }, -+}; -+static asn_TYPE_tag2member_t asn_MAP_GetKeytabControl_tag2el_1[] = { -+ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* newkeys at 7 */ -+ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* curkeys at 8 */ -+ { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* reply at 10 */ -+}; -+static asn_CHOICE_specifics_t asn_SPC_GetKeytabControl_specs_1 = { -+ sizeof(struct GetKeytabControl), -+ offsetof(struct GetKeytabControl, _asn_ctx), -+ offsetof(struct GetKeytabControl, present), -+ sizeof(((struct GetKeytabControl *)0)->present), -+ asn_MAP_GetKeytabControl_tag2el_1, -+ 3, /* Count of tags in the map */ -+ 0, -+ -1 /* Extensions start */ -+}; -+asn_TYPE_descriptor_t asn_DEF_GetKeytabControl = { -+ "GetKeytabControl", -+ "GetKeytabControl", -+ CHOICE_free, -+ CHOICE_print, -+ CHOICE_constraint, -+ CHOICE_decode_ber, -+ CHOICE_encode_der, -+ CHOICE_decode_xer, -+ CHOICE_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ CHOICE_outmost_tag, -+ 0, /* No effective tags (pointer) */ -+ 0, /* No effective tags (count) */ -+ 0, /* No tags (pointer) */ -+ 0, /* No tags (count) */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_GetKeytabControl_1, -+ 3, /* Elements count */ -+ &asn_SPC_GetKeytabControl_specs_1 /* Additional specs */ -+}; -+ -diff --git a/asn1/asn1c/GetKeytabControl.h b/asn1/asn1c/GetKeytabControl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5f5fcd22e74f65e9356be886520b8ddd3cac348c ---- /dev/null -+++ b/asn1/asn1c/GetKeytabControl.h -@@ -0,0 +1,52 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _GetKeytabControl_H_ -+#define _GetKeytabControl_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include "GKNewKeys.h" -+#include "GKCurrentKeys.h" -+#include "GKReply.h" -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Dependencies */ -+typedef enum GetKeytabControl_PR { -+ GetKeytabControl_PR_NOTHING, /* No components present */ -+ GetKeytabControl_PR_newkeys, -+ GetKeytabControl_PR_curkeys, -+ GetKeytabControl_PR_reply -+} GetKeytabControl_PR; -+ -+/* GetKeytabControl */ -+typedef struct GetKeytabControl { -+ GetKeytabControl_PR present; -+ union GetKeytabControl_u { -+ GKNewKeys_t newkeys; -+ GKCurrentKeys_t curkeys; -+ GKReply_t reply; -+ } choice; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+} GetKeytabControl_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_GetKeytabControl; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _GetKeytabControl_H_ */ -diff --git a/asn1/asn1c/INTEGER.c b/asn1/asn1c/INTEGER.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9c8b9ed3a5d778c30185842ca04cc5d8f9ca058b ---- /dev/null -+++ b/asn1/asn1c/INTEGER.c -@@ -0,0 +1,835 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include /* Encoder and decoder of a primitive type */ -+#include -+ -+/* -+ * INTEGER basic type description. -+ */ -+static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) -+}; -+asn_TYPE_descriptor_t asn_DEF_INTEGER = { -+ "INTEGER", -+ "INTEGER", -+ ASN__PRIMITIVE_TYPE_free, -+ INTEGER_print, -+ asn_generic_no_constraint, -+ ber_decode_primitive, -+ INTEGER_encode_der, -+ INTEGER_decode_xer, -+ INTEGER_encode_xer, -+ INTEGER_decode_uper, /* Unaligned PER decoder */ -+ INTEGER_encode_uper, /* Unaligned PER encoder */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_INTEGER_tags, -+ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), -+ asn_DEF_INTEGER_tags, /* Same as above */ -+ sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), -+ 0, /* No PER visible constraints */ -+ 0, 0, /* No members */ -+ 0 /* No specifics */ -+}; -+ -+/* -+ * Encode INTEGER type using DER. -+ */ -+asn_enc_rval_t -+INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ INTEGER_t *st = (INTEGER_t *)sptr; -+ -+ ASN_DEBUG("%s %s as INTEGER (tm=%d)", -+ cb?"Encoding":"Estimating", td->name, tag_mode); -+ -+ /* -+ * Canonicalize integer in the buffer. -+ * (Remove too long sign extension, remove some first 0x00 bytes) -+ */ -+ if(st->buf) { -+ uint8_t *buf = st->buf; -+ uint8_t *end1 = buf + st->size - 1; -+ int shift; -+ -+ /* Compute the number of superfluous leading bytes */ -+ for(; buf < end1; buf++) { -+ /* -+ * If the contents octets of an integer value encoding -+ * consist of more than one octet, then the bits of the -+ * first octet and bit 8 of the second octet: -+ * a) shall not all be ones; and -+ * b) shall not all be zero. -+ */ -+ switch(*buf) { -+ case 0x00: if((buf[1] & 0x80) == 0) -+ continue; -+ break; -+ case 0xff: if((buf[1] & 0x80)) -+ continue; -+ break; -+ } -+ break; -+ } -+ -+ /* Remove leading superfluous bytes from the integer */ -+ shift = buf - st->buf; -+ if(shift) { -+ uint8_t *nb = st->buf; -+ uint8_t *end; -+ -+ st->size -= shift; /* New size, minus bad bytes */ -+ end = nb + st->size; -+ -+ for(; nb < end; nb++, buf++) -+ *nb = *buf; -+ } -+ -+ } /* if(1) */ -+ -+ return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key); -+} -+ -+static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop); -+ -+/* -+ * INTEGER specific human-readable output. -+ */ -+static ssize_t -+INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { -+ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; -+ char scratch[32]; /* Enough for 64-bit integer */ -+ uint8_t *buf = st->buf; -+ uint8_t *buf_end = st->buf + st->size; -+ signed long accum; -+ ssize_t wrote = 0; -+ char *p; -+ int ret; -+ -+ /* -+ * Advance buf pointer until the start of the value's body. -+ * This will make us able to process large integers using simple case, -+ * when the actual value is small -+ * (0x0000000000abcdef would yield a fine 0x00abcdef) -+ */ -+ /* Skip the insignificant leading bytes */ -+ for(; buf < buf_end-1; buf++) { -+ switch(*buf) { -+ case 0x00: if((buf[1] & 0x80) == 0) continue; break; -+ case 0xff: if((buf[1] & 0x80) != 0) continue; break; -+ } -+ break; -+ } -+ -+ /* Simple case: the integer size is small */ -+ if((size_t)(buf_end - buf) <= sizeof(accum)) { -+ const asn_INTEGER_enum_map_t *el; -+ size_t scrsize; -+ char *scr; -+ -+ if(buf == buf_end) { -+ accum = 0; -+ } else { -+ accum = (*buf & 0x80) ? -1 : 0; -+ for(; buf < buf_end; buf++) -+ accum = (accum << 8) | *buf; -+ } -+ -+ el = INTEGER_map_value2enum(specs, accum); -+ if(el) { -+ scrsize = el->enum_len + 32; -+ scr = (char *)alloca(scrsize); -+ if(plainOrXER == 0) -+ ret = snprintf(scr, scrsize, -+ "%ld (%s)", accum, el->enum_name); -+ else -+ ret = snprintf(scr, scrsize, -+ "<%s/>", el->enum_name); -+ } else if(plainOrXER && specs && specs->strict_enumeration) { -+ ASN_DEBUG("ASN.1 forbids dealing with " -+ "unknown value of ENUMERATED type"); -+ errno = EPERM; -+ return -1; -+ } else { -+ scrsize = sizeof(scratch); -+ scr = scratch; -+ ret = snprintf(scr, scrsize, "%ld", accum); -+ } -+ assert(ret > 0 && (size_t)ret < scrsize); -+ return (cb(scr, ret, app_key) < 0) ? -1 : ret; -+ } else if(plainOrXER && specs && specs->strict_enumeration) { -+ /* -+ * Here and earlier, we cannot encode the ENUMERATED values -+ * if there is no corresponding identifier. -+ */ -+ ASN_DEBUG("ASN.1 forbids dealing with " -+ "unknown value of ENUMERATED type"); -+ errno = EPERM; -+ return -1; -+ } -+ -+ /* Output in the long xx:yy:zz... format */ -+ /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ -+ for(p = scratch; buf < buf_end; buf++) { -+ static const char *h2c = "0123456789ABCDEF"; -+ if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { -+ /* Flush buffer */ -+ if(cb(scratch, p - scratch, app_key) < 0) -+ return -1; -+ wrote += p - scratch; -+ p = scratch; -+ } -+ *p++ = h2c[*buf >> 4]; -+ *p++ = h2c[*buf & 0x0F]; -+ *p++ = 0x3a; /* ":" */ -+ } -+ if(p != scratch) -+ p--; /* Remove the last ":" */ -+ -+ wrote += p - scratch; -+ return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote; -+} -+ -+/* -+ * INTEGER specific human-readable output. -+ */ -+int -+INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ const INTEGER_t *st = (const INTEGER_t *)sptr; -+ ssize_t ret; -+ -+ (void)td; -+ (void)ilevel; -+ -+ if(!st || !st->buf) -+ ret = cb("", 8, app_key); -+ else -+ ret = INTEGER__dump(td, st, cb, app_key, 0); -+ -+ return (ret < 0) ? -1 : 0; -+} -+ -+struct e2v_key { -+ const char *start; -+ const char *stop; -+ asn_INTEGER_enum_map_t *vemap; -+ unsigned int *evmap; -+}; -+static int -+INTEGER__compar_enum2value(const void *kp, const void *am) { -+ const struct e2v_key *key = (const struct e2v_key *)kp; -+ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; -+ const char *ptr, *end, *name; -+ -+ /* Remap the element (sort by different criterion) */ -+ el = key->vemap + key->evmap[el - key->vemap]; -+ -+ /* Compare strings */ -+ for(ptr = key->start, end = key->stop, name = el->enum_name; -+ ptr < end; ptr++, name++) { -+ if(*ptr != *name) -+ return *(const unsigned char *)ptr -+ - *(const unsigned char *)name; -+ } -+ return name[0] ? -1 : 0; -+} -+ -+static const asn_INTEGER_enum_map_t * -+INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { -+ asn_INTEGER_enum_map_t *el_found; -+ int count = specs ? specs->map_count : 0; -+ struct e2v_key key; -+ const char *lp; -+ -+ if(!count) return NULL; -+ -+ /* Guaranteed: assert(lstart < lstop); */ -+ /* Figure out the tag name */ -+ for(lstart++, lp = lstart; lp < lstop; lp++) { -+ switch(*lp) { -+ case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */ -+ case 0x2f: /* '/' */ case 0x3e: /* '>' */ -+ break; -+ default: -+ continue; -+ } -+ break; -+ } -+ if(lp == lstop) return NULL; /* No tag found */ -+ lstop = lp; -+ -+ key.start = lstart; -+ key.stop = lstop; -+ key.vemap = specs->value2enum; -+ key.evmap = specs->enum2value; -+ el_found = (asn_INTEGER_enum_map_t *)bsearch(&key, -+ specs->value2enum, count, sizeof(specs->value2enum[0]), -+ INTEGER__compar_enum2value); -+ if(el_found) { -+ /* Remap enum2value into value2enum */ -+ el_found = key.vemap + key.evmap[el_found - key.vemap]; -+ } -+ return el_found; -+} -+ -+static int -+INTEGER__compar_value2enum(const void *kp, const void *am) { -+ long a = *(const long *)kp; -+ const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; -+ long b = el->nat_value; -+ if(a < b) return -1; -+ else if(a == b) return 0; -+ else return 1; -+} -+ -+const asn_INTEGER_enum_map_t * -+INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { -+ int count = specs ? specs->map_count : 0; -+ if(!count) return 0; -+ return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum, -+ count, sizeof(specs->value2enum[0]), -+ INTEGER__compar_value2enum); -+} -+ -+static int -+INTEGER_st_prealloc(INTEGER_t *st, int min_size) { -+ void *p = MALLOC(min_size + 1); -+ if(p) { -+ void *b = st->buf; -+ st->size = 0; -+ st->buf = p; -+ FREEMEM(b); -+ return 0; -+ } else { -+ return -1; -+ } -+} -+ -+/* -+ * Decode the chunk of XML text encoding INTEGER. -+ */ -+static enum xer_pbd_rval -+INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { -+ INTEGER_t *st = (INTEGER_t *)sptr; -+ long sign = 1; -+ long value; -+ const char *lp; -+ const char *lstart = (const char *)chunk_buf; -+ const char *lstop = lstart + chunk_size; -+ enum { -+ ST_SKIPSPACE, -+ ST_SKIPSPHEX, -+ ST_WAITDIGITS, -+ ST_DIGITS, -+ ST_HEXDIGIT1, -+ ST_HEXDIGIT2, -+ ST_HEXCOLON, -+ ST_EXTRASTUFF -+ } state = ST_SKIPSPACE; -+ -+ if(chunk_size) -+ ASN_DEBUG("INTEGER body %d 0x%2x..0x%2x", -+ chunk_size, *lstart, lstop[-1]); -+ -+ /* -+ * We may have received a tag here. It will be processed inline. -+ * Use strtoul()-like code and serialize the result. -+ */ -+ for(value = 0, lp = lstart; lp < lstop; lp++) { -+ int lv = *lp; -+ switch(lv) { -+ case 0x09: case 0x0a: case 0x0d: case 0x20: -+ switch(state) { -+ case ST_SKIPSPACE: -+ case ST_SKIPSPHEX: -+ continue; -+ case ST_HEXCOLON: -+ if(xer_is_whitespace(lp, lstop - lp)) { -+ lp = lstop - 1; -+ continue; -+ } -+ break; -+ default: -+ break; -+ } -+ break; -+ case 0x2d: /* '-' */ -+ if(state == ST_SKIPSPACE) { -+ sign = -1; -+ state = ST_WAITDIGITS; -+ continue; -+ } -+ break; -+ case 0x2b: /* '+' */ -+ if(state == ST_SKIPSPACE) { -+ state = ST_WAITDIGITS; -+ continue; -+ } -+ break; -+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: -+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: -+ switch(state) { -+ case ST_DIGITS: break; -+ case ST_SKIPSPHEX: /* Fall through */ -+ case ST_HEXDIGIT1: -+ value = (lv - 0x30) << 4; -+ state = ST_HEXDIGIT2; -+ continue; -+ case ST_HEXDIGIT2: -+ value += (lv - 0x30); -+ state = ST_HEXCOLON; -+ st->buf[st->size++] = value; -+ continue; -+ case ST_HEXCOLON: -+ return XPBD_BROKEN_ENCODING; -+ default: -+ state = ST_DIGITS; -+ break; -+ } -+ -+ { -+ long new_value = value * 10; -+ -+ if(new_value / 10 != value) -+ /* Overflow */ -+ return XPBD_DECODER_LIMIT; -+ -+ value = new_value + (lv - 0x30); -+ /* Check for two's complement overflow */ -+ if(value < 0) { -+ /* Check whether it is a LONG_MIN */ -+ if(sign == -1 -+ && (unsigned long)value -+ == ~((unsigned long)-1 >> 1)) { -+ sign = 1; -+ } else { -+ /* Overflow */ -+ return XPBD_DECODER_LIMIT; -+ } -+ } -+ } -+ continue; -+ case 0x3c: /* '<' */ -+ if(state == ST_SKIPSPACE) { -+ const asn_INTEGER_enum_map_t *el; -+ el = INTEGER_map_enum2value( -+ (asn_INTEGER_specifics_t *) -+ td->specifics, lstart, lstop); -+ if(el) { -+ ASN_DEBUG("Found \"%s\" => %ld", -+ el->enum_name, el->nat_value); -+ state = ST_DIGITS; -+ value = el->nat_value; -+ lp = lstop - 1; -+ continue; -+ } -+ ASN_DEBUG("Unknown identifier for INTEGER"); -+ } -+ return XPBD_BROKEN_ENCODING; -+ case 0x3a: /* ':' */ -+ if(state == ST_HEXCOLON) { -+ /* This colon is expected */ -+ state = ST_HEXDIGIT1; -+ continue; -+ } else if(state == ST_DIGITS) { -+ /* The colon here means that we have -+ * decoded the first two hexadecimal -+ * places as a decimal value. -+ * Switch decoding mode. */ -+ ASN_DEBUG("INTEGER re-evaluate as hex form"); -+ if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) -+ return XPBD_SYSTEM_FAILURE; -+ state = ST_SKIPSPHEX; -+ lp = lstart - 1; -+ continue; -+ } else { -+ ASN_DEBUG("state %d at %d", state, lp - lstart); -+ break; -+ } -+ /* [A-Fa-f] */ -+ case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: -+ case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: -+ switch(state) { -+ case ST_SKIPSPHEX: -+ case ST_SKIPSPACE: /* Fall through */ -+ case ST_HEXDIGIT1: -+ value = lv - ((lv < 0x61) ? 0x41 : 0x61); -+ value += 10; -+ value <<= 4; -+ state = ST_HEXDIGIT2; -+ continue; -+ case ST_HEXDIGIT2: -+ value += lv - ((lv < 0x61) ? 0x41 : 0x61); -+ value += 10; -+ st->buf[st->size++] = value; -+ state = ST_HEXCOLON; -+ continue; -+ case ST_DIGITS: -+ ASN_DEBUG("INTEGER re-evaluate as hex form"); -+ if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) -+ return XPBD_SYSTEM_FAILURE; -+ state = ST_SKIPSPHEX; -+ lp = lstart - 1; -+ continue; -+ default: -+ break; -+ } -+ break; -+ } -+ -+ /* Found extra non-numeric stuff */ -+ ASN_DEBUG("Found non-numeric 0x%2x at %d", -+ lv, lp - lstart); -+ state = ST_EXTRASTUFF; -+ break; -+ } -+ -+ switch(state) { -+ case ST_DIGITS: -+ /* Everything is cool */ -+ break; -+ case ST_HEXCOLON: -+ st->buf[st->size] = 0; /* Just in case termination */ -+ return XPBD_BODY_CONSUMED; -+ case ST_HEXDIGIT1: -+ case ST_HEXDIGIT2: -+ case ST_SKIPSPHEX: -+ return XPBD_BROKEN_ENCODING; -+ default: -+ if(xer_is_whitespace(lp, lstop - lp)) { -+ if(state != ST_EXTRASTUFF) -+ return XPBD_NOT_BODY_IGNORE; -+ break; -+ } else { -+ ASN_DEBUG("INTEGER: No useful digits (state %d)", -+ state); -+ return XPBD_BROKEN_ENCODING; /* No digits */ -+ } -+ break; -+ } -+ -+ value *= sign; /* Change sign, if needed */ -+ -+ if(asn_long2INTEGER(st, value)) -+ return XPBD_SYSTEM_FAILURE; -+ -+ return XPBD_BODY_CONSUMED; -+} -+ -+asn_dec_rval_t -+INTEGER_decode_xer(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, -+ const void *buf_ptr, size_t size) { -+ -+ return xer_decode_primitive(opt_codec_ctx, td, -+ sptr, sizeof(INTEGER_t), opt_mname, -+ buf_ptr, size, INTEGER__xer_body_decode); -+} -+ -+asn_enc_rval_t -+INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ const INTEGER_t *st = (const INTEGER_t *)sptr; -+ asn_enc_rval_t er; -+ -+ (void)ilevel; -+ (void)flags; -+ -+ if(!st || !st->buf) -+ _ASN_ENCODE_FAILED; -+ -+ er.encoded = INTEGER__dump(td, st, cb, app_key, 1); -+ if(er.encoded < 0) _ASN_ENCODE_FAILED; -+ -+ _ASN_ENCODED_OK(er); -+} -+ -+asn_dec_rval_t -+INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { -+ asn_dec_rval_t rval = { RC_OK, 0 }; -+ INTEGER_t *st = (INTEGER_t *)*sptr; -+ asn_per_constraint_t *ct; -+ int repeat; -+ -+ (void)opt_codec_ctx; -+ -+ if(!st) { -+ st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); -+ if(!st) _ASN_DECODE_FAILED; -+ } -+ -+ if(!constraints) constraints = td->per_constraints; -+ ct = constraints ? &constraints->value : 0; -+ -+ if(ct && ct->flags & APC_EXTENSIBLE) { -+ int inext = per_get_few_bits(pd, 1); -+ if(inext < 0) _ASN_DECODE_STARVED; -+ if(inext) ct = 0; -+ } -+ -+ FREEMEM(st->buf); -+ if(ct) { -+ if(ct->flags & APC_SEMI_CONSTRAINED) { -+ st->buf = (uint8_t *)CALLOC(1, 2); -+ if(!st->buf) _ASN_DECODE_FAILED; -+ st->size = 1; -+ } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { -+ size_t size = (ct->range_bits + 7) >> 3; -+ st->buf = (uint8_t *)MALLOC(1 + size + 1); -+ if(!st->buf) _ASN_DECODE_FAILED; -+ st->size = size; -+ } else { -+ st->size = 0; -+ } -+ } else { -+ st->size = 0; -+ } -+ -+ /* X.691, #12.2.2 */ -+ if(ct && ct->flags != APC_UNCONSTRAINED) { -+ /* #10.5.6 */ -+ ASN_DEBUG("Integer with range %d bits", ct->range_bits); -+ if(ct->range_bits >= 0) { -+ long value = per_get_few_bits(pd, ct->range_bits); -+ if(value < 0) _ASN_DECODE_STARVED; -+ ASN_DEBUG("Got value %ld + low %ld", -+ value, ct->lower_bound); -+ value += ct->lower_bound; -+ if(asn_long2INTEGER(st, value)) -+ _ASN_DECODE_FAILED; -+ return rval; -+ } -+ } else { -+ ASN_DEBUG("Decoding unconstrained integer %s", td->name); -+ } -+ -+ /* X.691, #12.2.3, #12.2.4 */ -+ do { -+ ssize_t len; -+ void *p; -+ int ret; -+ -+ /* Get the PER length */ -+ len = uper_get_length(pd, -1, &repeat); -+ if(len < 0) _ASN_DECODE_STARVED; -+ -+ p = REALLOC(st->buf, st->size + len + 1); -+ if(!p) _ASN_DECODE_FAILED; -+ st->buf = (uint8_t *)p; -+ -+ ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); -+ if(ret < 0) _ASN_DECODE_STARVED; -+ st->size += len; -+ } while(repeat); -+ st->buf[st->size] = 0; /* JIC */ -+ -+ /* #12.2.3 */ -+ if(ct && ct->lower_bound) { -+ /* -+ * TODO: replace by in-place arithmetics. -+ */ -+ long value; -+ if(asn_INTEGER2long(st, &value)) -+ _ASN_DECODE_FAILED; -+ if(asn_long2INTEGER(st, value + ct->lower_bound)) -+ _ASN_DECODE_FAILED; -+ } -+ -+ return rval; -+} -+ -+asn_enc_rval_t -+INTEGER_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ asn_enc_rval_t er; -+ INTEGER_t *st = (INTEGER_t *)sptr; -+ const uint8_t *buf; -+ const uint8_t *end; -+ asn_per_constraint_t *ct; -+ long value = 0; -+ -+ if(!st || st->size == 0) _ASN_ENCODE_FAILED; -+ -+ if(!constraints) constraints = td->per_constraints; -+ ct = constraints ? &constraints->value : 0; -+ -+ er.encoded = 0; -+ -+ if(ct) { -+ int inext = 0; -+ if(asn_INTEGER2long(st, &value)) -+ _ASN_ENCODE_FAILED; -+ /* Check proper range */ -+ if(ct->flags & APC_SEMI_CONSTRAINED) { -+ if(value < ct->lower_bound) -+ inext = 1; -+ } else if(ct->range_bits >= 0) { -+ if(value < ct->lower_bound -+ || value > ct->upper_bound) -+ inext = 1; -+ } -+ ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", -+ value, st->buf[0], st->size, -+ ct->lower_bound, ct->upper_bound, -+ inext ? "ext" : "fix"); -+ if(ct->flags & APC_EXTENSIBLE) { -+ if(per_put_few_bits(po, inext, 1)) -+ _ASN_ENCODE_FAILED; -+ if(inext) ct = 0; -+ } else if(inext) { -+ _ASN_ENCODE_FAILED; -+ } -+ } -+ -+ -+ /* X.691, #12.2.2 */ -+ if(ct && ct->range_bits >= 0) { -+ /* #10.5.6 */ -+ ASN_DEBUG("Encoding integer with range %d bits", -+ ct->range_bits); -+ if(per_put_few_bits(po, value - ct->lower_bound, -+ ct->range_bits)) -+ _ASN_ENCODE_FAILED; -+ _ASN_ENCODED_OK(er); -+ } -+ -+ if(ct && ct->lower_bound) { -+ ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); -+ /* TODO: adjust lower bound */ -+ _ASN_ENCODE_FAILED; -+ } -+ -+ for(buf = st->buf, end = st->buf + st->size; buf < end;) { -+ ssize_t mayEncode = uper_put_length(po, end - buf); -+ if(mayEncode < 0) -+ _ASN_ENCODE_FAILED; -+ if(per_put_many_bits(po, buf, 8 * mayEncode)) -+ _ASN_ENCODE_FAILED; -+ buf += mayEncode; -+ } -+ -+ _ASN_ENCODED_OK(er); -+} -+ -+int -+asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { -+ uint8_t *b, *end; -+ size_t size; -+ long l; -+ -+ /* Sanity checking */ -+ if(!iptr || !iptr->buf || !lptr) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ /* Cache the begin/end of the buffer */ -+ b = iptr->buf; /* Start of the INTEGER buffer */ -+ size = iptr->size; -+ end = b + size; /* Where to stop */ -+ -+ if(size > sizeof(long)) { -+ uint8_t *end1 = end - 1; -+ /* -+ * Slightly more advanced processing, -+ * able to >sizeof(long) bytes, -+ * when the actual value is small -+ * (0x0000000000abcdef would yield a fine 0x00abcdef) -+ */ -+ /* Skip out the insignificant leading bytes */ -+ for(; b < end1; b++) { -+ switch(*b) { -+ case 0x00: if((b[1] & 0x80) == 0) continue; break; -+ case 0xff: if((b[1] & 0x80) != 0) continue; break; -+ } -+ break; -+ } -+ -+ size = end - b; -+ if(size > sizeof(long)) { -+ /* Still cannot fit the long */ -+ errno = ERANGE; -+ return -1; -+ } -+ } -+ -+ /* Shortcut processing of a corner case */ -+ if(end == b) { -+ *lptr = 0; -+ return 0; -+ } -+ -+ /* Perform the sign initialization */ -+ /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ -+ if((*b >> 7)) l = -1; else l = 0; -+ -+ /* Conversion engine */ -+ for(; b < end; b++) -+ l = (l << 8) | *b; -+ -+ *lptr = l; -+ return 0; -+} -+ -+int -+asn_long2INTEGER(INTEGER_t *st, long value) { -+ uint8_t *buf, *bp; -+ uint8_t *p; -+ uint8_t *pstart; -+ uint8_t *pend1; -+ int littleEndian = 1; /* Run-time detection */ -+ int add; -+ -+ if(!st) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ buf = (uint8_t *)MALLOC(sizeof(value)); -+ if(!buf) return -1; -+ -+ if(*(char *)&littleEndian) { -+ pstart = (uint8_t *)&value + sizeof(value) - 1; -+ pend1 = (uint8_t *)&value; -+ add = -1; -+ } else { -+ pstart = (uint8_t *)&value; -+ pend1 = pstart + sizeof(value) - 1; -+ add = 1; -+ } -+ -+ /* -+ * If the contents octet consists of more than one octet, -+ * then bits of the first octet and bit 8 of the second octet: -+ * a) shall not all be ones; and -+ * b) shall not all be zero. -+ */ -+ for(p = pstart; p != pend1; p += add) { -+ switch(*p) { -+ case 0x00: if((*(p+add) & 0x80) == 0) -+ continue; -+ break; -+ case 0xff: if((*(p+add) & 0x80)) -+ continue; -+ break; -+ } -+ break; -+ } -+ /* Copy the integer body */ -+ for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) -+ *bp++ = *p; -+ -+ if(st->buf) FREEMEM(st->buf); -+ st->buf = buf; -+ st->size = bp - buf; -+ -+ return 0; -+} -diff --git a/asn1/asn1c/INTEGER.h b/asn1/asn1c/INTEGER.h -new file mode 100644 -index 0000000000000000000000000000000000000000..62832b12e1271e1f27a5edd5b4a0f82986ff2fc3 ---- /dev/null -+++ b/asn1/asn1c/INTEGER.h -@@ -0,0 +1,65 @@ -+/*- -+ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _INTEGER_H_ -+#define _INTEGER_H_ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; -+ -+extern asn_TYPE_descriptor_t asn_DEF_INTEGER; -+ -+/* Map with to integer value association */ -+typedef struct asn_INTEGER_enum_map_s { -+ long nat_value; /* associated native integer value */ -+ size_t enum_len; /* strlen("tag") */ -+ const char *enum_name; /* "tag" */ -+} asn_INTEGER_enum_map_t; -+ -+/* This type describes an enumeration for INTEGER and ENUMERATED types */ -+typedef struct asn_INTEGER_specifics_s { -+ asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ -+ unsigned int *enum2value; /* "tag" => N; sorted by tag */ -+ int map_count; /* Elements in either map */ -+ int extension; /* This map is extensible */ -+ int strict_enumeration; /* Enumeration set is fixed */ -+} asn_INTEGER_specifics_t; -+ -+asn_struct_print_f INTEGER_print; -+ber_type_decoder_f INTEGER_decode_ber; -+der_type_encoder_f INTEGER_encode_der; -+xer_type_decoder_f INTEGER_decode_xer; -+xer_type_encoder_f INTEGER_encode_xer; -+per_type_decoder_f INTEGER_decode_uper; -+per_type_encoder_f INTEGER_encode_uper; -+ -+/*********************************** -+ * Some handy conversion routines. * -+ ***********************************/ -+ -+/* -+ * Returns 0 if it was possible to convert, -1 otherwise. -+ * -1/EINVAL: Mandatory argument missing -+ * -1/ERANGE: Value encoded is out of range for long representation -+ * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). -+ */ -+int asn_INTEGER2long(const INTEGER_t *i, long *l); -+int asn_long2INTEGER(INTEGER_t *i, long l); -+ -+/* -+ * Convert the integer value into the corresponding enumeration map entry. -+ */ -+const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _INTEGER_H_ */ -diff --git a/asn1/asn1c/Int32.c b/asn1/asn1c/Int32.c -new file mode 100644 -index 0000000000000000000000000000000000000000..600934beed3fcff4527de4969c1d3effd272355e ---- /dev/null -+++ b/asn1/asn1c/Int32.c -@@ -0,0 +1,127 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "Int32.h" -+ -+int -+Int32_constraint(asn_TYPE_descriptor_t *td, const void *sptr, -+ asn_app_constraint_failed_f *ctfailcb, void *app_key) { -+ long value; -+ -+ if(!sptr) { -+ _ASN_CTFAIL(app_key, td, sptr, -+ "%s: value not given (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+ -+ value = *(const long *)sptr; -+ -+ if((value >= -2147483648 && value <= 2147483647)) { -+ /* Constraint check succeeded */ -+ return 0; -+ } else { -+ _ASN_CTFAIL(app_key, td, sptr, -+ "%s: constraint failed (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+} -+ -+/* -+ * This type is implemented using NativeInteger, -+ * so here we adjust the DEF accordingly. -+ */ -+static void -+Int32_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { -+ td->free_struct = asn_DEF_NativeInteger.free_struct; -+ td->print_struct = asn_DEF_NativeInteger.print_struct; -+ td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; -+ td->der_encoder = asn_DEF_NativeInteger.der_encoder; -+ td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; -+ td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; -+ td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; -+ td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; -+ if(!td->per_constraints) -+ td->per_constraints = asn_DEF_NativeInteger.per_constraints; -+ td->elements = asn_DEF_NativeInteger.elements; -+ td->elements_count = asn_DEF_NativeInteger.elements_count; -+ td->specifics = asn_DEF_NativeInteger.specifics; -+} -+ -+void -+Int32_free(asn_TYPE_descriptor_t *td, -+ void *struct_ptr, int contents_only) { -+ Int32_1_inherit_TYPE_descriptor(td); -+ td->free_struct(td, struct_ptr, contents_only); -+} -+ -+int -+Int32_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, -+ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { -+ Int32_1_inherit_TYPE_descriptor(td); -+ return td->print_struct(td, struct_ptr, ilevel, cb, app_key); -+} -+ -+asn_dec_rval_t -+Int32_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **structure, const void *bufptr, size_t size, int tag_mode) { -+ Int32_1_inherit_TYPE_descriptor(td); -+ return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); -+} -+ -+asn_enc_rval_t -+Int32_encode_der(asn_TYPE_descriptor_t *td, -+ void *structure, int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ Int32_1_inherit_TYPE_descriptor(td); -+ return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); -+} -+ -+asn_dec_rval_t -+Int32_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **structure, const char *opt_mname, const void *bufptr, size_t size) { -+ Int32_1_inherit_TYPE_descriptor(td); -+ return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); -+} -+ -+asn_enc_rval_t -+Int32_encode_xer(asn_TYPE_descriptor_t *td, void *structure, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ Int32_1_inherit_TYPE_descriptor(td); -+ return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); -+} -+ -+static ber_tlv_tag_t asn_DEF_Int32_tags_1[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) -+}; -+asn_TYPE_descriptor_t asn_DEF_Int32 = { -+ "Int32", -+ "Int32", -+ Int32_free, -+ Int32_print, -+ Int32_constraint, -+ Int32_decode_ber, -+ Int32_encode_der, -+ Int32_decode_xer, -+ Int32_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_Int32_tags_1, -+ sizeof(asn_DEF_Int32_tags_1) -+ /sizeof(asn_DEF_Int32_tags_1[0]), /* 1 */ -+ asn_DEF_Int32_tags_1, /* Same as above */ -+ sizeof(asn_DEF_Int32_tags_1) -+ /sizeof(asn_DEF_Int32_tags_1[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ 0, 0, /* No members */ -+ 0 /* No specifics */ -+}; -+ -diff --git a/asn1/asn1c/Int32.h b/asn1/asn1c/Int32.h -new file mode 100644 -index 0000000000000000000000000000000000000000..9ee672ec9b5d49cfaddd2bf0bfb5ab2c5015d498 ---- /dev/null -+++ b/asn1/asn1c/Int32.h -@@ -0,0 +1,38 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _Int32_H_ -+#define _Int32_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Int32 */ -+typedef long Int32_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_Int32; -+asn_struct_free_f Int32_free; -+asn_struct_print_f Int32_print; -+asn_constr_check_f Int32_constraint; -+ber_type_decoder_f Int32_decode_ber; -+der_type_encoder_f Int32_encode_der; -+xer_type_decoder_f Int32_decode_xer; -+xer_type_encoder_f Int32_encode_xer; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _Int32_H_ */ -diff --git a/asn1/asn1c/KrbKey.c b/asn1/asn1c/KrbKey.c -new file mode 100644 -index 0000000000000000000000000000000000000000..3abbdf1b6e42ee759c149b6cbfa4b53695a2f0a3 ---- /dev/null -+++ b/asn1/asn1c/KrbKey.c -@@ -0,0 +1,81 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "KrbKey.h" -+ -+static asn_TYPE_member_t asn_MBR_KrbKey_1[] = { -+ { ATF_NOFLAGS, 0, offsetof(struct KrbKey, key), -+ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_TypeValuePair, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "key" -+ }, -+ { ATF_POINTER, 2, offsetof(struct KrbKey, salt), -+ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_TypeValuePair, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "salt" -+ }, -+ { ATF_POINTER, 1, offsetof(struct KrbKey, s2kparams), -+ (ASN_TAG_CLASS_CONTEXT | (2 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_OCTET_STRING, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "s2kparams" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_KrbKey_tags_1[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_TYPE_tag2member_t asn_MAP_KrbKey_tag2el_1[] = { -+ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* key at 28 */ -+ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* salt at 29 */ -+ { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* s2kparams at 30 */ -+}; -+static asn_SEQUENCE_specifics_t asn_SPC_KrbKey_specs_1 = { -+ sizeof(struct KrbKey), -+ offsetof(struct KrbKey, _asn_ctx), -+ asn_MAP_KrbKey_tag2el_1, -+ 3, /* Count of tags in the map */ -+ 0, 0, 0, /* Optional elements (not needed) */ -+ -1, /* Start extensions */ -+ -1 /* Stop extensions */ -+}; -+asn_TYPE_descriptor_t asn_DEF_KrbKey = { -+ "KrbKey", -+ "KrbKey", -+ SEQUENCE_free, -+ SEQUENCE_print, -+ SEQUENCE_constraint, -+ SEQUENCE_decode_ber, -+ SEQUENCE_encode_der, -+ SEQUENCE_decode_xer, -+ SEQUENCE_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_KrbKey_tags_1, -+ sizeof(asn_DEF_KrbKey_tags_1) -+ /sizeof(asn_DEF_KrbKey_tags_1[0]), /* 1 */ -+ asn_DEF_KrbKey_tags_1, /* Same as above */ -+ sizeof(asn_DEF_KrbKey_tags_1) -+ /sizeof(asn_DEF_KrbKey_tags_1[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_KrbKey_1, -+ 3, /* Elements count */ -+ &asn_SPC_KrbKey_specs_1 /* Additional specs */ -+}; -+ -diff --git a/asn1/asn1c/KrbKey.h b/asn1/asn1c/KrbKey.h -new file mode 100644 -index 0000000000000000000000000000000000000000..3134be528d1b9848b17d5eaee941aeef6fbd91b6 ---- /dev/null -+++ b/asn1/asn1c/KrbKey.h -@@ -0,0 +1,46 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _KrbKey_H_ -+#define _KrbKey_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include "TypeValuePair.h" -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Forward declarations */ -+struct TypeValuePair; -+ -+/* KrbKey */ -+typedef struct KrbKey { -+ TypeValuePair_t key; -+ struct TypeValuePair *salt /* OPTIONAL */; -+ OCTET_STRING_t *s2kparams /* OPTIONAL */; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+} KrbKey_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_KrbKey; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+/* Referred external types */ -+#include "TypeValuePair.h" -+ -+#endif /* _KrbKey_H_ */ -diff --git a/asn1/asn1c/Makefile.am b/asn1/asn1c/Makefile.am -new file mode 100644 -index 0000000000000000000000000000000000000000..e4ed6ab79fa776131b5baaaf7b5d254850c966c2 ---- /dev/null -+++ b/asn1/asn1c/Makefile.am -@@ -0,0 +1,93 @@ -+NULL = -+ -+ASN1C_SOURCES = \ -+ INTEGER.c \ -+ NativeEnumerated.c \ -+ NativeInteger.c \ -+ asn_SEQUENCE_OF.c \ -+ asn_SET_OF.c \ -+ constr_CHOICE.c \ -+ constr_SEQUENCE.c \ -+ constr_SEQUENCE_OF.c \ -+ constr_SET_OF.c \ -+ OCTET_STRING.c \ -+ BIT_STRING.c \ -+ asn_codecs_prim.c \ -+ ber_tlv_length.c \ -+ ber_tlv_tag.c \ -+ ber_decoder.c \ -+ der_encoder.c \ -+ constr_TYPE.c \ -+ constraints.c \ -+ xer_support.c \ -+ xer_decoder.c \ -+ xer_encoder.c \ -+ per_support.c \ -+ per_decoder.c \ -+ per_encoder.c \ -+ $(NULL) -+ -+ASN1C_HEADERS = -+ INTEGER.h \ -+ NativeEnumerated.h \ -+ NativeInteger.h \ -+ asn_SEQUENCE_OF.h \ -+ asn_SET_OF.h \ -+ constr_CHOICE.h \ -+ constr_SEQUENCE.h \ -+ constr_SEQUENCE_OF.h \ -+ constr_SET_OF.h \ -+ asn_application.h \ -+ asn_system.h \ -+ asn_codecs.h \ -+ asn_internal.h \ -+ OCTET_STRING.h \ -+ BIT_STRING.h \ -+ asn_codecs_prim.h \ -+ ber_tlv_length.h \ -+ ber_tlv_tag.h \ -+ ber_decoder.h \ -+ der_encoder.h \ -+ constr_TYPE.h \ -+ constraints.h \ -+ xer_support.h \ -+ xer_decoder.h \ -+ xer_encoder.h \ -+ per_support.h \ -+ per_decoder.h \ -+ per_encoder.h \ -+ $(NULL) -+ -+ASN1Cdir = . -+ -+IPAASN1_SOURCES= \ -+ Int32.c \ -+ GetKeytabControl.c \ -+ GKNewKeys.c \ -+ GKCurrentKeys.c \ -+ GKReply.c \ -+ KrbKey.c \ -+ TypeValuePair.c \ -+ $(NULL) -+ -+IPAASN1_HEADERS= \ -+ Int32.h \ -+ GetKeytabControl.h \ -+ GKNewKeys.h \ -+ GKCurrentKeys.h \ -+ GKReply.h \ -+ KrbKey.h \ -+ TypeValuePair.h \ -+ $(NULL) -+ -+IPAASN1dir = . -+ -+AM_CPPFLAGS = -I../../util -+ -+noinst_LTLIBRARIES=libasn1c.la -+noinst_HEADERS=$(ASN1C_HEADERS) $(IPAASN1_HEADERS) -+libasn1c_la_SOURCES=$(ASN1C_SOURCES) $(IPAASN1_SOURCES) -+ -+regenerate: -+ asn1c -fskeletons-copy -fnative-types ipa.asn1 -+ rm -f converter-sample.c Makefile.am.sample -diff --git a/asn1/asn1c/NativeEnumerated.c b/asn1/asn1c/NativeEnumerated.c -new file mode 100644 -index 0000000000000000000000000000000000000000..e3af1ca49b2c722513876e70219bb0ac8e74cbd9 ---- /dev/null -+++ b/asn1/asn1c/NativeEnumerated.c -@@ -0,0 +1,204 @@ -+/*- -+ * Copyright (c) 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * Read the NativeInteger.h for the explanation wrt. differences between -+ * INTEGER and NativeInteger. -+ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this -+ * implementation deals with the standard (machine-specific) representation -+ * of them instead of using the platform-independent buffer. -+ */ -+#include -+#include -+ -+/* -+ * NativeEnumerated basic type description. -+ */ -+static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) -+}; -+asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { -+ "ENUMERATED", /* The ASN.1 type is still ENUMERATED */ -+ "ENUMERATED", -+ NativeInteger_free, -+ NativeInteger_print, -+ asn_generic_no_constraint, -+ NativeInteger_decode_ber, -+ NativeInteger_encode_der, -+ NativeInteger_decode_xer, -+ NativeEnumerated_encode_xer, -+ NativeEnumerated_decode_uper, -+ NativeEnumerated_encode_uper, -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_NativeEnumerated_tags, -+ sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), -+ asn_DEF_NativeEnumerated_tags, /* Same as above */ -+ sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), -+ 0, /* No PER visible constraints */ -+ 0, 0, /* No members */ -+ 0 /* No specifics */ -+}; -+ -+asn_enc_rval_t -+NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; -+ asn_enc_rval_t er; -+ const long *native = (const long *)sptr; -+ const asn_INTEGER_enum_map_t *el; -+ -+ (void)ilevel; -+ (void)flags; -+ -+ if(!native) _ASN_ENCODE_FAILED; -+ -+ el = INTEGER_map_value2enum(specs, *native); -+ if(el) { -+ size_t srcsize = el->enum_len + 5; -+ char *src = (char *)alloca(srcsize); -+ -+ er.encoded = snprintf(src, srcsize, "<%s/>", el->enum_name); -+ assert(er.encoded > 0 && (size_t)er.encoded < srcsize); -+ if(cb(src, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED; -+ _ASN_ENCODED_OK(er); -+ } else { -+ ASN_DEBUG("ASN.1 forbids dealing with " -+ "unknown value of ENUMERATED type"); -+ _ASN_ENCODE_FAILED; -+ } -+} -+ -+asn_dec_rval_t -+NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, -+ void **sptr, asn_per_data_t *pd) { -+ asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; -+ asn_dec_rval_t rval = { RC_OK, 0 }; -+ long *native = (long *)*sptr; -+ asn_per_constraint_t *ct; -+ long value; -+ -+ (void)opt_codec_ctx; -+ -+ if(constraints) ct = &constraints->value; -+ else if(td->per_constraints) ct = &td->per_constraints->value; -+ else _ASN_DECODE_FAILED; /* Mandatory! */ -+ if(!specs) _ASN_DECODE_FAILED; -+ -+ if(!native) { -+ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); -+ if(!native) _ASN_DECODE_FAILED; -+ } -+ -+ ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); -+ -+ if(ct->flags & APC_EXTENSIBLE) { -+ int inext = per_get_few_bits(pd, 1); -+ if(inext < 0) _ASN_DECODE_STARVED; -+ if(inext) ct = 0; -+ } -+ -+ if(ct && ct->range_bits >= 0) { -+ value = per_get_few_bits(pd, ct->range_bits); -+ if(value < 0) _ASN_DECODE_STARVED; -+ if(value >= (specs->extension -+ ? specs->extension - 1 : specs->map_count)) -+ _ASN_DECODE_FAILED; -+ } else { -+ if(!specs->extension) -+ _ASN_DECODE_FAILED; -+ /* -+ * X.691, #10.6: normally small non-negative whole number; -+ */ -+ value = uper_get_nsnnwn(pd); -+ if(value < 0) _ASN_DECODE_STARVED; -+ value += specs->extension - 1; -+ if(value >= specs->map_count) -+ _ASN_DECODE_FAILED; -+ } -+ -+ *native = specs->value2enum[value].nat_value; -+ ASN_DEBUG("Decoded %s = %ld", td->name, *native); -+ -+ return rval; -+} -+ -+static int -+NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { -+ const asn_INTEGER_enum_map_t *a = ap; -+ const asn_INTEGER_enum_map_t *b = bp; -+ if(a->nat_value == b->nat_value) -+ return 0; -+ if(a->nat_value < b->nat_value) -+ return -1; -+ return 1; -+} -+ -+asn_enc_rval_t -+NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; -+ asn_enc_rval_t er; -+ long native, value; -+ asn_per_constraint_t *ct; -+ int inext = 0; -+ asn_INTEGER_enum_map_t key; -+ asn_INTEGER_enum_map_t *kf; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ if(!specs) _ASN_ENCODE_FAILED; -+ -+ if(constraints) ct = &constraints->value; -+ else if(td->per_constraints) ct = &td->per_constraints->value; -+ else _ASN_ENCODE_FAILED; /* Mandatory! */ -+ -+ ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); -+ -+ er.encoded = 0; -+ -+ native = *(long *)sptr; -+ if(native < 0) _ASN_ENCODE_FAILED; -+ -+ key.nat_value = native; -+ kf = bsearch(&key, specs->value2enum, specs->map_count, -+ sizeof(key), NativeEnumerated__compar_value2enum); -+ if(!kf) { -+ ASN_DEBUG("No element corresponds to %ld", native); -+ _ASN_ENCODE_FAILED; -+ } -+ value = kf - specs->value2enum; -+ -+ if(ct->range_bits >= 0) { -+ int cmpWith = specs->extension -+ ? specs->extension - 1 : specs->map_count; -+ if(value >= cmpWith) -+ inext = 1; -+ } -+ if(ct->flags & APC_EXTENSIBLE) { -+ if(per_put_few_bits(po, inext, 0)) -+ _ASN_ENCODE_FAILED; -+ ct = 0; -+ } else if(inext) { -+ _ASN_ENCODE_FAILED; -+ } -+ -+ if(ct && ct->range_bits >= 0) { -+ if(per_put_few_bits(po, value, ct->range_bits)) -+ _ASN_ENCODE_FAILED; -+ _ASN_ENCODED_OK(er); -+ } -+ -+ if(!specs->extension) -+ _ASN_ENCODE_FAILED; -+ -+ /* -+ * X.691, #10.6: normally small non-negative whole number; -+ */ -+ if(uper_put_nsnnwn(po, value - (specs->extension - 1))) -+ _ASN_ENCODE_FAILED; -+ -+ _ASN_ENCODED_OK(er); -+} -+ -diff --git a/asn1/asn1c/NativeEnumerated.h b/asn1/asn1c/NativeEnumerated.h -new file mode 100644 -index 0000000000000000000000000000000000000000..c59bb1ba9438f85d3c42c99bba3a02aa917f0837 ---- /dev/null -+++ b/asn1/asn1c/NativeEnumerated.h -@@ -0,0 +1,32 @@ -+/*- -+ * Copyright (c) 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * This type differs from the standard ENUMERATED in that it is modelled using -+ * the fixed machine type (long, int, short), so it can hold only values of -+ * limited length. There is no type (i.e., NativeEnumerated_t, any integer type -+ * will do). -+ * This type may be used when integer range is limited by subtype constraints. -+ */ -+#ifndef _NativeEnumerated_H_ -+#define _NativeEnumerated_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; -+ -+xer_type_encoder_f NativeEnumerated_encode_xer; -+per_type_decoder_f NativeEnumerated_decode_uper; -+per_type_encoder_f NativeEnumerated_encode_uper; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _NativeEnumerated_H_ */ -diff --git a/asn1/asn1c/NativeInteger.c b/asn1/asn1c/NativeInteger.c -new file mode 100644 -index 0000000000000000000000000000000000000000..34599f6186cd77d38106e171ec3b24cb29638afa ---- /dev/null -+++ b/asn1/asn1c/NativeInteger.c -@@ -0,0 +1,314 @@ -+/*- -+ * Copyright (c) 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * Read the NativeInteger.h for the explanation wrt. differences between -+ * INTEGER and NativeInteger. -+ * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this -+ * implementation deals with the standard (machine-specific) representation -+ * of them instead of using the platform-independent buffer. -+ */ -+#include -+#include -+ -+/* -+ * NativeInteger basic type description. -+ */ -+static ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) -+}; -+asn_TYPE_descriptor_t asn_DEF_NativeInteger = { -+ "INTEGER", /* The ASN.1 type is still INTEGER */ -+ "INTEGER", -+ NativeInteger_free, -+ NativeInteger_print, -+ asn_generic_no_constraint, -+ NativeInteger_decode_ber, -+ NativeInteger_encode_der, -+ NativeInteger_decode_xer, -+ NativeInteger_encode_xer, -+ NativeInteger_decode_uper, /* Unaligned PER decoder */ -+ NativeInteger_encode_uper, /* Unaligned PER encoder */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_NativeInteger_tags, -+ sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), -+ asn_DEF_NativeInteger_tags, /* Same as above */ -+ sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), -+ 0, /* No PER visible constraints */ -+ 0, 0, /* No members */ -+ 0 /* No specifics */ -+}; -+ -+/* -+ * Decode INTEGER type. -+ */ -+asn_dec_rval_t -+NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, -+ void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) { -+ long *native = (long *)*nint_ptr; -+ asn_dec_rval_t rval; -+ ber_tlv_len_t length; -+ -+ /* -+ * If the structure is not there, allocate it. -+ */ -+ if(native == NULL) { -+ native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); -+ if(native == NULL) { -+ rval.code = RC_FAIL; -+ rval.consumed = 0; -+ return rval; -+ } -+ } -+ -+ ASN_DEBUG("Decoding %s as INTEGER (tm=%d)", -+ td->name, tag_mode); -+ -+ /* -+ * Check tags. -+ */ -+ rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, -+ tag_mode, 0, &length, 0); -+ if(rval.code != RC_OK) -+ return rval; -+ -+ ASN_DEBUG("%s length is %d bytes", td->name, (int)length); -+ -+ /* -+ * Make sure we have this length. -+ */ -+ buf_ptr = ((const char *)buf_ptr) + rval.consumed; -+ size -= rval.consumed; -+ if(length > (ber_tlv_len_t)size) { -+ rval.code = RC_WMORE; -+ rval.consumed = 0; -+ return rval; -+ } -+ -+ /* -+ * ASN.1 encoded INTEGER: buf_ptr, length -+ * Fill the native, at the same time checking for overflow. -+ * If overflow occured, return with RC_FAIL. -+ */ -+ { -+ INTEGER_t tmp; -+ union { -+ const void *constbuf; -+ void *nonconstbuf; -+ } unconst_buf; -+ long l; -+ -+ unconst_buf.constbuf = buf_ptr; -+ tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; -+ tmp.size = length; -+ -+ if(asn_INTEGER2long(&tmp, &l)) { -+ rval.code = RC_FAIL; -+ rval.consumed = 0; -+ return rval; -+ } -+ -+ *native = l; -+ } -+ -+ rval.code = RC_OK; -+ rval.consumed += length; -+ -+ ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)", -+ (long)rval.consumed, (long)length, td->name, (long)*native); -+ -+ return rval; -+} -+ -+/* -+ * Encode the NativeInteger using the standard INTEGER type DER encoder. -+ */ -+asn_enc_rval_t -+NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ unsigned long native = *(unsigned long *)ptr; /* Disable sign ext. */ -+ asn_enc_rval_t erval; -+ INTEGER_t tmp; -+ -+#ifdef WORDS_BIGENDIAN /* Opportunistic optimization */ -+ -+ tmp.buf = (uint8_t *)&native; -+ tmp.size = sizeof(native); -+ -+#else /* Works even if WORDS_BIGENDIAN is not set where should've been */ -+ uint8_t buf[sizeof(native)]; -+ uint8_t *p; -+ -+ /* Prepare a fake INTEGER */ -+ for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) -+ *p = native; -+ -+ tmp.buf = buf; -+ tmp.size = sizeof(buf); -+#endif /* WORDS_BIGENDIAN */ -+ -+ /* Encode fake INTEGER */ -+ erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key); -+ if(erval.encoded == -1) { -+ assert(erval.structure_ptr == &tmp); -+ erval.structure_ptr = ptr; -+ } -+ return erval; -+} -+ -+/* -+ * Decode the chunk of XML text encoding INTEGER. -+ */ -+asn_dec_rval_t -+NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, -+ const void *buf_ptr, size_t size) { -+ asn_dec_rval_t rval; -+ INTEGER_t st; -+ void *st_ptr = (void *)&st; -+ long *native = (long *)*sptr; -+ -+ if(!native) { -+ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); -+ if(!native) _ASN_DECODE_FAILED; -+ } -+ -+ memset(&st, 0, sizeof(st)); -+ rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, -+ opt_mname, buf_ptr, size); -+ if(rval.code == RC_OK) { -+ long l; -+ if(asn_INTEGER2long(&st, &l)) { -+ rval.code = RC_FAIL; -+ rval.consumed = 0; -+ } else { -+ *native = l; -+ } -+ } else { -+ /* -+ * Cannot restart from the middle; -+ * there is no place to save state in the native type. -+ * Request a continuation from the very beginning. -+ */ -+ rval.consumed = 0; -+ } -+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st); -+ return rval; -+} -+ -+ -+asn_enc_rval_t -+NativeInteger_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ char scratch[32]; /* Enough for 64-bit int */ -+ asn_enc_rval_t er; -+ const long *native = (const long *)sptr; -+ -+ (void)ilevel; -+ (void)flags; -+ -+ if(!native) _ASN_ENCODE_FAILED; -+ -+ er.encoded = snprintf(scratch, sizeof(scratch), "%ld", *native); -+ if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch) -+ || cb(scratch, er.encoded, app_key) < 0) -+ _ASN_ENCODE_FAILED; -+ -+ _ASN_ENCODED_OK(er); -+} -+ -+asn_dec_rval_t -+NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { -+ -+ asn_dec_rval_t rval; -+ long *native = (long *)*sptr; -+ INTEGER_t tmpint; -+ void *tmpintptr = &tmpint; -+ -+ (void)opt_codec_ctx; -+ ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name); -+ -+ if(!native) { -+ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); -+ if(!native) _ASN_DECODE_FAILED; -+ } -+ -+ memset(&tmpint, 0, sizeof tmpint); -+ rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, -+ &tmpintptr, pd); -+ if(rval.code == RC_OK) { -+ if(asn_INTEGER2long(&tmpint, native)) -+ rval.code = RC_FAIL; -+ else -+ ASN_DEBUG("NativeInteger %s got value %ld", -+ td->name, *native); -+ } -+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); -+ -+ return rval; -+} -+ -+asn_enc_rval_t -+NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ asn_enc_rval_t er; -+ long native; -+ INTEGER_t tmpint; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ -+ native = *(long *)sptr; -+ -+ ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); -+ -+ memset(&tmpint, 0, sizeof(tmpint)); -+ if(asn_long2INTEGER(&tmpint, native)) -+ _ASN_ENCODE_FAILED; -+ er = INTEGER_encode_uper(td, constraints, &tmpint, po); -+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); -+ return er; -+} -+ -+/* -+ * INTEGER specific human-readable output. -+ */ -+int -+NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ const long *native = (const long *)sptr; -+ char scratch[32]; /* Enough for 64-bit int */ -+ int ret; -+ -+ (void)td; /* Unused argument */ -+ (void)ilevel; /* Unused argument */ -+ -+ if(native) { -+ ret = snprintf(scratch, sizeof(scratch), "%ld", *native); -+ assert(ret > 0 && (size_t)ret < sizeof(scratch)); -+ return (cb(scratch, ret, app_key) < 0) ? -1 : 0; -+ } else { -+ return (cb("", 8, app_key) < 0) ? -1 : 0; -+ } -+} -+ -+void -+NativeInteger_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { -+ -+ if(!td || !ptr) -+ return; -+ -+ ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)", -+ td->name, contents_only, ptr); -+ -+ if(!contents_only) { -+ FREEMEM(ptr); -+ } -+} -+ -diff --git a/asn1/asn1c/NativeInteger.h b/asn1/asn1c/NativeInteger.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4e63a8355d12b7c90ce53a23a43cb5583f811257 ---- /dev/null -+++ b/asn1/asn1c/NativeInteger.h -@@ -0,0 +1,37 @@ -+/*- -+ * Copyright (c) 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * This type differs from the standard INTEGER in that it is modelled using -+ * the fixed machine type (long, int, short), so it can hold only values of -+ * limited length. There is no type (i.e., NativeInteger_t, any integer type -+ * will do). -+ * This type may be used when integer range is limited by subtype constraints. -+ */ -+#ifndef _NativeInteger_H_ -+#define _NativeInteger_H_ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; -+ -+asn_struct_free_f NativeInteger_free; -+asn_struct_print_f NativeInteger_print; -+ber_type_decoder_f NativeInteger_decode_ber; -+der_type_encoder_f NativeInteger_encode_der; -+xer_type_decoder_f NativeInteger_decode_xer; -+xer_type_encoder_f NativeInteger_encode_xer; -+per_type_decoder_f NativeInteger_decode_uper; -+per_type_encoder_f NativeInteger_encode_uper; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _NativeInteger_H_ */ -diff --git a/asn1/asn1c/OCTET_STRING.c b/asn1/asn1c/OCTET_STRING.c -new file mode 100644 -index 0000000000000000000000000000000000000000..3a83bd98c5b30a10b5fb12b78bd4f317e8abb27a ---- /dev/null -+++ b/asn1/asn1c/OCTET_STRING.c -@@ -0,0 +1,1550 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include /* for .bits_unused member */ -+#include -+ -+/* -+ * OCTET STRING basic type description. -+ */ -+static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) -+}; -+static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { -+ sizeof(OCTET_STRING_t), -+ offsetof(OCTET_STRING_t, _asn_ctx), -+ 0 -+}; -+static asn_per_constraint_t asn_DEF_OCTET_STRING_constraint = { -+ APC_SEMI_CONSTRAINED, -1, -1, 0, 0 -+}; -+asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { -+ "OCTET STRING", /* Canonical name */ -+ "OCTET_STRING", /* XML tag name */ -+ OCTET_STRING_free, -+ OCTET_STRING_print, /* non-ascii stuff, generally */ -+ asn_generic_no_constraint, -+ OCTET_STRING_decode_ber, -+ OCTET_STRING_encode_der, -+ OCTET_STRING_decode_xer_hex, -+ OCTET_STRING_encode_xer, -+ OCTET_STRING_decode_uper, /* Unaligned PER decoder */ -+ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_OCTET_STRING_tags, -+ sizeof(asn_DEF_OCTET_STRING_tags) -+ / sizeof(asn_DEF_OCTET_STRING_tags[0]), -+ asn_DEF_OCTET_STRING_tags, /* Same as above */ -+ sizeof(asn_DEF_OCTET_STRING_tags) -+ / sizeof(asn_DEF_OCTET_STRING_tags[0]), -+ 0, /* No PER visible constraints */ -+ 0, 0, /* No members */ -+ &asn_DEF_OCTET_STRING_specs -+}; -+ -+#undef _CH_PHASE -+#undef NEXT_PHASE -+#undef PREV_PHASE -+#define _CH_PHASE(ctx, inc) do { \ -+ if(ctx->phase == 0) \ -+ ctx->context = 0; \ -+ ctx->phase += inc; \ -+ } while(0) -+#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) -+#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) -+ -+#undef ADVANCE -+#define ADVANCE(num_bytes) do { \ -+ size_t num = (num_bytes); \ -+ buf_ptr = ((const char *)buf_ptr) + num; \ -+ size -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+#undef RETURN -+#define RETURN(_code) do { \ -+ asn_dec_rval_t tmprval; \ -+ tmprval.code = _code; \ -+ tmprval.consumed = consumed_myself; \ -+ return tmprval; \ -+ } while(0) -+ -+#undef APPEND -+#define APPEND(bufptr, bufsize) do { \ -+ size_t _bs = (bufsize); /* Append size */ \ -+ size_t _ns = ctx->context; /* Allocated now */ \ -+ size_t _es = st->size + _bs; /* Expected size */ \ -+ /* int is really a typeof(st->size): */ \ -+ if((int)_es < 0) RETURN(RC_FAIL); \ -+ if(_ns <= _es) { \ -+ void *ptr; \ -+ /* Be nice and round to the memory allocator */ \ -+ do { _ns = _ns ? _ns << 1 : 16; } \ -+ while(_ns <= _es); \ -+ /* int is really a typeof(st->size): */ \ -+ if((int)_ns < 0) RETURN(RC_FAIL); \ -+ ptr = REALLOC(st->buf, _ns); \ -+ if(ptr) { \ -+ st->buf = (uint8_t *)ptr; \ -+ ctx->context = _ns; \ -+ } else { \ -+ RETURN(RC_FAIL); \ -+ } \ -+ ASN_DEBUG("Reallocating into %ld", (long)_ns); \ -+ } \ -+ memcpy(st->buf + st->size, bufptr, _bs); \ -+ /* Convenient nul-termination */ \ -+ st->buf[_es] = '\0'; \ -+ st->size = _es; \ -+ } while(0) -+ -+/* -+ * Internal variant of the OCTET STRING. -+ */ -+typedef enum OS_type { -+ _TT_GENERIC = 0, /* Just a random OCTET STRING */ -+ _TT_BIT_STRING = 1, /* BIT STRING type, a special case */ -+ _TT_ANY = 2 /* ANY type, a special case too */ -+} OS_type_e; -+ -+/* -+ * The main reason why ASN.1 is still alive is that too much time and effort -+ * is necessary for learning it more or less adequately, thus creating a gut -+ * necessity to demonstrate that aquired skill everywhere afterwards. -+ * No, I am not going to explain what the following stuff is. -+ */ -+struct _stack_el { -+ ber_tlv_len_t left; /* What's left to read (or -1) */ -+ ber_tlv_len_t got; /* What was actually processed */ -+ int cont_level; /* Depth of subcontainment */ -+ int want_nulls; /* Want null "end of content" octets? */ -+ int bits_chopped; /* Flag in BIT STRING mode */ -+ ber_tlv_tag_t tag; /* For debugging purposes */ -+ struct _stack_el *prev; -+ struct _stack_el *next; -+}; -+struct _stack { -+ struct _stack_el *tail; -+ struct _stack_el *cur_ptr; -+}; -+ -+static struct _stack_el * -+OS__add_stack_el(struct _stack *st) { -+ struct _stack_el *nel; -+ -+ /* -+ * Reuse the old stack frame or allocate a new one. -+ */ -+ if(st->cur_ptr && st->cur_ptr->next) { -+ nel = st->cur_ptr->next; -+ nel->bits_chopped = 0; -+ nel->got = 0; -+ /* Retain the nel->cont_level, it's correct. */ -+ } else { -+ nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el)); -+ if(nel == NULL) -+ return NULL; -+ -+ if(st->tail) { -+ /* Increase a subcontainment depth */ -+ nel->cont_level = st->tail->cont_level + 1; -+ st->tail->next = nel; -+ } -+ nel->prev = st->tail; -+ st->tail = nel; -+ } -+ -+ st->cur_ptr = nel; -+ -+ return nel; -+} -+ -+static struct _stack * -+_new_stack() { -+ return (struct _stack *)CALLOC(1, sizeof(struct _stack)); -+} -+ -+/* -+ * Decode OCTET STRING type. -+ */ -+asn_dec_rval_t -+OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, -+ void **sptr, const void *buf_ptr, size_t size, int tag_mode) { -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ BIT_STRING_t *st = (BIT_STRING_t *)*sptr; -+ asn_dec_rval_t rval; -+ asn_struct_ctx_t *ctx; -+ ssize_t consumed_myself = 0; -+ struct _stack *stck; /* Expectations stack structure */ -+ struct _stack_el *sel = 0; /* Stack element */ -+ int tlv_constr; -+ OS_type_e type_variant = (OS_type_e)specs->subvariant; -+ -+ ASN_DEBUG("Decoding %s as %s (frame %ld)", -+ td->name, -+ (type_variant == _TT_GENERIC) ? -+ "OCTET STRING" : "OS-SpecialCase", -+ (long)size); -+ -+ /* -+ * Create the string if does not exist. -+ */ -+ if(st == NULL) { -+ st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); -+ if(st == NULL) RETURN(RC_FAIL); -+ } -+ -+ /* Restore parsing context */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ -+ switch(ctx->phase) { -+ case 0: -+ /* -+ * Check tags. -+ */ -+ rval = ber_check_tags(opt_codec_ctx, td, ctx, -+ buf_ptr, size, tag_mode, -1, -+ &ctx->left, &tlv_constr); -+ if(rval.code != RC_OK) -+ return rval; -+ -+ if(tlv_constr) { -+ /* -+ * Complex operation, requires stack of expectations. -+ */ -+ ctx->ptr = _new_stack(); -+ if(ctx->ptr) { -+ stck = (struct _stack *)ctx->ptr; -+ } else { -+ RETURN(RC_FAIL); -+ } -+ } else { -+ /* -+ * Jump into stackless primitive decoding. -+ */ -+ _CH_PHASE(ctx, 3); -+ if(type_variant == _TT_ANY && tag_mode != 1) -+ APPEND(buf_ptr, rval.consumed); -+ ADVANCE(rval.consumed); -+ goto phase3; -+ } -+ -+ NEXT_PHASE(ctx); -+ /* Fall through */ -+ case 1: -+ phase1: -+ /* -+ * Fill the stack with expectations. -+ */ -+ stck = (struct _stack *)ctx->ptr; -+ sel = stck->cur_ptr; -+ do { -+ ber_tlv_tag_t tlv_tag; -+ ber_tlv_len_t tlv_len; -+ ber_tlv_tag_t expected_tag; -+ ssize_t tl, ll, tlvl; -+ /* This one works even if (sel->left == -1) */ -+ ssize_t Left = ((!sel||(size_t)sel->left >= size) -+ ?(ssize_t)size:sel->left); -+ -+ -+ ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel, -+ (long)(sel?sel->left:0), -+ (long)(sel?sel->want_nulls:0), -+ (long)(sel?sel->got:0) -+ ); -+ if(sel && sel->left <= 0 && sel->want_nulls == 0) { -+ if(sel->prev) { -+ struct _stack_el *prev = sel->prev; -+ if(prev->left != -1) { -+ if(prev->left < sel->got) -+ RETURN(RC_FAIL); -+ prev->left -= sel->got; -+ } -+ prev->got += sel->got; -+ sel = stck->cur_ptr = prev; -+ if(!sel) break; -+ tlv_constr = 1; -+ continue; -+ } else { -+ sel = stck->cur_ptr = 0; -+ break; /* Nothing to wait */ -+ } -+ } -+ -+ tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); -+ ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld", -+ (long)size, (long)Left, sel?"":"!", -+ (long)(sel?sel->left:0), -+ (long)(sel?sel->want_nulls:0), -+ (long)tl); -+ switch(tl) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ } -+ -+ tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr); -+ -+ ll = ber_fetch_length(tlv_constr, -+ (const char *)buf_ptr + tl,Left - tl,&tlv_len); -+ ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld", -+ ber_tlv_tag_string(tlv_tag), tlv_constr, -+ (long)Left, (long)tl, (long)tlv_len, (long)ll); -+ switch(ll) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ } -+ -+ if(sel && sel->want_nulls -+ && ((const uint8_t *)buf_ptr)[0] == 0 -+ && ((const uint8_t *)buf_ptr)[1] == 0) -+ { -+ -+ ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); -+ -+ if(type_variant == _TT_ANY -+ && (tag_mode != 1 || sel->cont_level)) -+ APPEND("\0\0", 2); -+ -+ ADVANCE(2); -+ sel->got += 2; -+ if(sel->left != -1) { -+ sel->left -= 2; /* assert(sel->left >= 2) */ -+ } -+ -+ sel->want_nulls--; -+ if(sel->want_nulls == 0) { -+ /* Move to the next expectation */ -+ sel->left = 0; -+ tlv_constr = 1; -+ } -+ -+ continue; -+ } -+ -+ /* -+ * Set up expected tags, -+ * depending on ASN.1 type being decoded. -+ */ -+ switch(type_variant) { -+ case _TT_BIT_STRING: -+ /* X.690: 8.6.4.1, NOTE 2 */ -+ /* Fall through */ -+ case _TT_GENERIC: -+ default: -+ if(sel) { -+ int level = sel->cont_level; -+ if(level < td->all_tags_count) { -+ expected_tag = td->all_tags[level]; -+ break; -+ } else if(td->all_tags_count) { -+ expected_tag = td->all_tags -+ [td->all_tags_count - 1]; -+ break; -+ } -+ /* else, Fall through */ -+ } -+ /* Fall through */ -+ case _TT_ANY: -+ expected_tag = tlv_tag; -+ break; -+ } -+ -+ -+ if(tlv_tag != expected_tag) { -+ char buf[2][32]; -+ ber_tlv_tag_snprint(tlv_tag, -+ buf[0], sizeof(buf[0])); -+ ber_tlv_tag_snprint(td->tags[td->tags_count-1], -+ buf[1], sizeof(buf[1])); -+ ASN_DEBUG("Tag does not match expectation: %s != %s", -+ buf[0], buf[1]); -+ RETURN(RC_FAIL); -+ } -+ -+ tlvl = tl + ll; /* Combined length of T and L encoding */ -+ if((tlv_len + tlvl) < 0) { -+ /* tlv_len value is too big */ -+ ASN_DEBUG("TLV encoding + length (%ld) is too big", -+ (long)tlv_len); -+ RETURN(RC_FAIL); -+ } -+ -+ /* -+ * Append a new expectation. -+ */ -+ sel = OS__add_stack_el(stck); -+ if(!sel) RETURN(RC_FAIL); -+ -+ sel->tag = tlv_tag; -+ -+ sel->want_nulls = (tlv_len==-1); -+ if(sel->prev && sel->prev->left != -1) { -+ /* Check that the parent frame is big enough */ -+ if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len)) -+ RETURN(RC_FAIL); -+ if(tlv_len == -1) -+ sel->left = sel->prev->left - tlvl; -+ else -+ sel->left = tlv_len; -+ } else { -+ sel->left = tlv_len; -+ } -+ if(type_variant == _TT_ANY -+ && (tag_mode != 1 || sel->cont_level)) -+ APPEND(buf_ptr, tlvl); -+ sel->got += tlvl; -+ ADVANCE(tlvl); -+ -+ ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d", -+ (long)sel->got, (long)sel->left, -+ sel->want_nulls, sel->cont_level); -+ -+ } while(tlv_constr); -+ if(sel == NULL) { -+ /* Finished operation, "phase out" */ -+ ASN_DEBUG("Phase out"); -+ _CH_PHASE(ctx, +3); -+ break; -+ } -+ -+ NEXT_PHASE(ctx); -+ /* Fall through */ -+ case 2: -+ stck = (struct _stack *)ctx->ptr; -+ sel = stck->cur_ptr; -+ ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", -+ (long)sel->left, (long)size, (long)sel->got, -+ sel->want_nulls); -+ { -+ ber_tlv_len_t len; -+ -+ assert(sel->left >= 0); -+ -+ len = ((ber_tlv_len_t)size < sel->left) -+ ? (ber_tlv_len_t)size : sel->left; -+ if(len > 0) { -+ if(type_variant == _TT_BIT_STRING -+ && sel->bits_chopped == 0) { -+ /* Put the unused-bits-octet away */ -+ st->bits_unused = *(const uint8_t *)buf_ptr; -+ APPEND(((const char *)buf_ptr+1), (len - 1)); -+ sel->bits_chopped = 1; -+ } else { -+ APPEND(buf_ptr, len); -+ } -+ ADVANCE(len); -+ sel->left -= len; -+ sel->got += len; -+ } -+ -+ if(sel->left) { -+ ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n", -+ (long)sel->left, (long)size, sel->want_nulls); -+ RETURN(RC_WMORE); -+ } -+ -+ PREV_PHASE(ctx); -+ goto phase1; -+ } -+ break; -+ case 3: -+ phase3: -+ /* -+ * Primitive form, no stack required. -+ */ -+ assert(ctx->left >= 0); -+ -+ if(size < (size_t)ctx->left) { -+ if(!size) RETURN(RC_WMORE); -+ if(type_variant == _TT_BIT_STRING && !ctx->context) { -+ st->bits_unused = *(const uint8_t *)buf_ptr; -+ ctx->left--; -+ ADVANCE(1); -+ } -+ APPEND(buf_ptr, size); -+ assert(ctx->context > 0); -+ ctx->left -= size; -+ ADVANCE(size); -+ RETURN(RC_WMORE); -+ } else { -+ if(type_variant == _TT_BIT_STRING -+ && !ctx->context && ctx->left) { -+ st->bits_unused = *(const uint8_t *)buf_ptr; -+ ctx->left--; -+ ADVANCE(1); -+ } -+ APPEND(buf_ptr, ctx->left); -+ ADVANCE(ctx->left); -+ ctx->left = 0; -+ -+ NEXT_PHASE(ctx); -+ } -+ break; -+ } -+ -+ if(sel) { -+ ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", -+ sel->prev, sel->want_nulls, -+ (long)sel->left, (long)sel->got, (long)size); -+ if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { -+ RETURN(RC_WMORE); -+ } -+ } -+ -+ /* -+ * BIT STRING-specific processing. -+ */ -+ if(type_variant == _TT_BIT_STRING && st->size) { -+ /* Finalize BIT STRING: zero out unused bits. */ -+ st->buf[st->size-1] &= 0xff << st->bits_unused; -+ } -+ -+ ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", -+ (long)consumed_myself, td->name, -+ (type_variant == _TT_GENERIC) ? (char *)st->buf : "", -+ (long)st->size); -+ -+ -+ RETURN(RC_OK); -+} -+ -+/* -+ * Encode OCTET STRING type using DER. -+ */ -+asn_enc_rval_t -+OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t er; -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ BIT_STRING_t *st = (BIT_STRING_t *)sptr; -+ OS_type_e type_variant = (OS_type_e)specs->subvariant; -+ int fix_last_byte = 0; -+ -+ ASN_DEBUG("%s %s as OCTET STRING", -+ cb?"Estimating":"Encoding", td->name); -+ -+ /* -+ * Write tags. -+ */ -+ if(type_variant != _TT_ANY || tag_mode == 1) { -+ er.encoded = der_write_tags(td, -+ (type_variant == _TT_BIT_STRING) + st->size, -+ tag_mode, type_variant == _TT_ANY, tag, cb, app_key); -+ if(er.encoded == -1) { -+ er.failed_type = td; -+ er.structure_ptr = sptr; -+ return er; -+ } -+ } else { -+ /* Disallow: [] IMPLICIT ANY */ -+ assert(type_variant != _TT_ANY || tag_mode != -1); -+ er.encoded = 0; -+ } -+ -+ if(!cb) { -+ er.encoded += (type_variant == _TT_BIT_STRING) + st->size; -+ _ASN_ENCODED_OK(er); -+ } -+ -+ /* -+ * Prepare to deal with the last octet of BIT STRING. -+ */ -+ if(type_variant == _TT_BIT_STRING) { -+ uint8_t b = st->bits_unused & 0x07; -+ if(b && st->size) fix_last_byte = 1; -+ _ASN_CALLBACK(&b, 1); -+ er.encoded++; -+ } -+ -+ /* Invoke callback for the main part of the buffer */ -+ _ASN_CALLBACK(st->buf, st->size - fix_last_byte); -+ -+ /* The last octet should be stripped off the unused bits */ -+ if(fix_last_byte) { -+ uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); -+ _ASN_CALLBACK(&b, 1); -+ } -+ -+ er.encoded += st->size; -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+asn_enc_rval_t -+OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ static const char *h2c = "0123456789ABCDEF"; -+ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; -+ asn_enc_rval_t er; -+ char scratch[16 * 3 + 4]; -+ char *p = scratch; -+ uint8_t *buf; -+ uint8_t *end; -+ size_t i; -+ -+ if(!st || !st->buf) -+ _ASN_ENCODE_FAILED; -+ -+ er.encoded = 0; -+ -+ /* -+ * Dump the contents of the buffer in hexadecimal. -+ */ -+ buf = st->buf; -+ end = buf + st->size; -+ if(flags & XER_F_CANONICAL) { -+ char *scend = scratch + (sizeof(scratch) - 2); -+ for(; buf < end; buf++) { -+ if(p >= scend) { -+ _ASN_CALLBACK(scratch, p - scratch); -+ er.encoded += p - scratch; -+ p = scratch; -+ } -+ *p++ = h2c[(*buf >> 4) & 0x0F]; -+ *p++ = h2c[*buf & 0x0F]; -+ } -+ -+ _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ -+ er.encoded += p - scratch; -+ } else { -+ for(i = 0; buf < end; buf++, i++) { -+ if(!(i % 16) && (i || st->size > 16)) { -+ _ASN_CALLBACK(scratch, p-scratch); -+ er.encoded += (p-scratch); -+ p = scratch; -+ _i_ASN_TEXT_INDENT(1, ilevel); -+ } -+ *p++ = h2c[(*buf >> 4) & 0x0F]; -+ *p++ = h2c[*buf & 0x0F]; -+ *p++ = 0x20; -+ } -+ if(p - scratch) { -+ p--; /* Remove the tail space */ -+ _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */ -+ er.encoded += p - scratch; -+ if(st->size > 16) -+ _i_ASN_TEXT_INDENT(1, ilevel-1); -+ } -+ } -+ -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+static struct OCTET_STRING__xer_escape_table_s { -+ char *string; -+ int size; -+} OCTET_STRING__xer_escape_table[] = { -+#define OSXET(s) { s, sizeof(s) - 1 } -+ OSXET("\074\156\165\154\057\076"), /* */ -+ OSXET("\074\163\157\150\057\076"), /* */ -+ OSXET("\074\163\164\170\057\076"), /* */ -+ OSXET("\074\145\164\170\057\076"), /* */ -+ OSXET("\074\145\157\164\057\076"), /* */ -+ OSXET("\074\145\156\161\057\076"), /* */ -+ OSXET("\074\141\143\153\057\076"), /* */ -+ OSXET("\074\142\145\154\057\076"), /* */ -+ OSXET("\074\142\163\057\076"), /* */ -+ OSXET("\011"), /* \t */ -+ OSXET("\012"), /* \n */ -+ OSXET("\074\166\164\057\076"), /* */ -+ OSXET("\074\146\146\057\076"), /* */ -+ OSXET("\015"), /* \r */ -+ OSXET("\074\163\157\057\076"), /* */ -+ OSXET("\074\163\151\057\076"), /* */ -+ OSXET("\074\144\154\145\057\076"), /* */ -+ OSXET("\074\144\143\061\057\076"), /* */ -+ OSXET("\074\144\143\062\057\076"), /* */ -+ OSXET("\074\144\143\063\057\076"), /* */ -+ OSXET("\074\144\143\064\057\076"), /* */ -+ OSXET("\074\156\141\153\057\076"), /* */ -+ OSXET("\074\163\171\156\057\076"), /* */ -+ OSXET("\074\145\164\142\057\076"), /* */ -+ OSXET("\074\143\141\156\057\076"), /* */ -+ OSXET("\074\145\155\057\076"), /* */ -+ OSXET("\074\163\165\142\057\076"), /* */ -+ OSXET("\074\145\163\143\057\076"), /* */ -+ OSXET("\074\151\163\064\057\076"), /* */ -+ OSXET("\074\151\163\063\057\076"), /* */ -+ OSXET("\074\151\163\062\057\076"), /* */ -+ OSXET("\074\151\163\061\057\076"), /* */ -+ { 0, 0 }, /* " " */ -+ { 0, 0 }, /* ! */ -+ { 0, 0 }, /* \" */ -+ { 0, 0 }, /* # */ -+ { 0, 0 }, /* $ */ -+ { 0, 0 }, /* % */ -+ OSXET("\046\141\155\160\073"), /* & */ -+ { 0, 0 }, /* ' */ -+ {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */ -+ {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */ -+ {0,0},{0,0},{0,0},{0,0}, /* 89:; */ -+ OSXET("\046\154\164\073"), /* < */ -+ { 0, 0 }, /* = */ -+ OSXET("\046\147\164\073"), /* > */ -+}; -+ -+static int -+OS__check_escaped_control_char(const void *buf, int size) { -+ size_t i; -+ /* -+ * Inefficient algorithm which translates the escape sequences -+ * defined above into characters. Returns -1 if not found. -+ * TODO: replace by a faster algorithm (bsearch(), hash or -+ * nested table lookups). -+ */ -+ for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { -+ struct OCTET_STRING__xer_escape_table_s *el; -+ el = &OCTET_STRING__xer_escape_table[i]; -+ if(el->size == size && memcmp(buf, el->string, size) == 0) -+ return i; -+ } -+ return -1; -+} -+ -+static int -+OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) { -+ /* -+ * This might be one of the escape sequences -+ * for control characters. Check it out. -+ * #11.15.5 -+ */ -+ int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size); -+ if(control_char >= 0) { -+ OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr; -+ void *p = REALLOC(st->buf, st->size + 2); -+ if(p) { -+ st->buf = (uint8_t *)p; -+ st->buf[st->size++] = control_char; -+ st->buf[st->size] = '\0'; /* nul-termination */ -+ return 0; -+ } -+ } -+ -+ return -1; /* No, it's not */ -+} -+ -+asn_enc_rval_t -+OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; -+ asn_enc_rval_t er; -+ uint8_t *buf, *end; -+ uint8_t *ss; /* Sequence start */ -+ ssize_t encoded_len = 0; -+ -+ (void)ilevel; /* Unused argument */ -+ (void)flags; /* Unused argument */ -+ -+ if(!st || !st->buf) -+ _ASN_ENCODE_FAILED; -+ -+ buf = st->buf; -+ end = buf + st->size; -+ for(ss = buf; buf < end; buf++) { -+ unsigned int ch = *buf; -+ int s_len; /* Special encoding sequence length */ -+ -+ /* -+ * Escape certain characters: X.680/11.15 -+ */ -+ if(ch < sizeof(OCTET_STRING__xer_escape_table) -+ /sizeof(OCTET_STRING__xer_escape_table[0]) -+ && (s_len = OCTET_STRING__xer_escape_table[ch].size)) { -+ if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) -+ || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, -+ app_key) < 0) -+ _ASN_ENCODE_FAILED; -+ encoded_len += (buf - ss) + s_len; -+ ss = buf + 1; -+ } -+ } -+ -+ encoded_len += (buf - ss); -+ if((buf - ss) && cb(ss, buf - ss, app_key) < 0) -+ _ASN_ENCODE_FAILED; -+ -+ er.encoded = encoded_len; -+ _ASN_ENCODED_OK(er); -+} -+ -+/* -+ * Convert from hexadecimal format (cstring): "AB CD EF" -+ */ -+static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { -+ OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; -+ const char *chunk_stop = (const char *)chunk_buf; -+ const char *p = chunk_stop; -+ const char *pend = p + chunk_size; -+ unsigned int clv = 0; -+ int half = 0; /* Half bit */ -+ uint8_t *buf; -+ -+ /* Reallocate buffer according to high cap estimation */ -+ ssize_t _ns = st->size + (chunk_size + 1) / 2; -+ void *nptr = REALLOC(st->buf, _ns + 1); -+ if(!nptr) return -1; -+ st->buf = (uint8_t *)nptr; -+ buf = st->buf + st->size; -+ -+ /* -+ * If something like " a b c " appears here, the " a b":3 will be -+ * converted, and the rest skipped. That is, unless buf_size is greater -+ * than chunk_size, then it'll be equivalent to "ABC0". -+ */ -+ for(; p < pend; p++) { -+ int ch = *(const unsigned char *)p; -+ switch(ch) { -+ case 0x09: case 0x0a: case 0x0c: case 0x0d: -+ case 0x20: -+ /* Ignore whitespace */ -+ continue; -+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ -+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ -+ clv = (clv << 4) + (ch - 0x30); -+ break; -+ case 0x41: case 0x42: case 0x43: /* ABC */ -+ case 0x44: case 0x45: case 0x46: /* DEF */ -+ clv = (clv << 4) + (ch - 0x41 + 10); -+ break; -+ case 0x61: case 0x62: case 0x63: /* abc */ -+ case 0x64: case 0x65: case 0x66: /* def */ -+ clv = (clv << 4) + (ch - 0x61 + 10); -+ break; -+ default: -+ *buf = 0; /* JIC */ -+ return -1; -+ } -+ if(half++) { -+ half = 0; -+ *buf++ = clv; -+ chunk_stop = p + 1; -+ } -+ } -+ -+ /* -+ * Check partial decoding. -+ */ -+ if(half) { -+ if(have_more) { -+ /* -+ * Partial specification is fine, -+ * because no more more PXER_TEXT data is available. -+ */ -+ *buf++ = clv << 4; -+ chunk_stop = p; -+ } -+ } else { -+ chunk_stop = p; -+ } -+ -+ st->size = buf - st->buf; /* Adjust the buffer size */ -+ assert(st->size <= _ns); -+ st->buf[st->size] = 0; /* Courtesy termination */ -+ -+ return (chunk_stop - (const char *)chunk_buf); /* Converted size */ -+} -+ -+/* -+ * Convert from binary format: "00101011101" -+ */ -+static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { -+ BIT_STRING_t *st = (BIT_STRING_t *)sptr; -+ const char *p = (const char *)chunk_buf; -+ const char *pend = p + chunk_size; -+ int bits_unused = st->bits_unused & 0x7; -+ uint8_t *buf; -+ -+ /* Reallocate buffer according to high cap estimation */ -+ ssize_t _ns = st->size + (chunk_size + 7) / 8; -+ void *nptr = REALLOC(st->buf, _ns + 1); -+ if(!nptr) return -1; -+ st->buf = (uint8_t *)nptr; -+ buf = st->buf + st->size; -+ -+ (void)have_more; -+ -+ if(bits_unused == 0) -+ bits_unused = 8; -+ else if(st->size) -+ buf--; -+ -+ /* -+ * Convert series of 0 and 1 into the octet string. -+ */ -+ for(; p < pend; p++) { -+ int ch = *(const unsigned char *)p; -+ switch(ch) { -+ case 0x09: case 0x0a: case 0x0c: case 0x0d: -+ case 0x20: -+ /* Ignore whitespace */ -+ break; -+ case 0x30: -+ case 0x31: -+ if(bits_unused-- <= 0) { -+ *++buf = 0; /* Clean the cell */ -+ bits_unused = 7; -+ } -+ *buf |= (ch&1) << bits_unused; -+ break; -+ default: -+ st->bits_unused = bits_unused; -+ return -1; -+ } -+ } -+ -+ if(bits_unused == 8) { -+ st->size = buf - st->buf; -+ st->bits_unused = 0; -+ } else { -+ st->size = buf - st->buf + 1; -+ st->bits_unused = bits_unused; -+ } -+ -+ assert(st->size <= _ns); -+ st->buf[st->size] = 0; /* Courtesy termination */ -+ -+ return chunk_size; /* Converted in full */ -+} -+ -+/* -+ * Something like strtod(), but with stricter rules. -+ */ -+static int -+OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { -+ int32_t val = 0; -+ const char *p; -+ -+ for(p = buf; p < end; p++) { -+ int ch = *p; -+ -+ /* Strange huge value */ -+ if((val * base + base) < 0) -+ return -1; -+ -+ switch(ch) { -+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ -+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ -+ val = val * base + (ch - 0x30); -+ break; -+ case 0x41: case 0x42: case 0x43: /* ABC */ -+ case 0x44: case 0x45: case 0x46: /* DEF */ -+ val = val * base + (ch - 0x41 + 10); -+ break; -+ case 0x61: case 0x62: case 0x63: /* abc */ -+ case 0x64: case 0x65: case 0x66: /* def */ -+ val = val * base + (ch - 0x61 + 10); -+ break; -+ case 0x3b: /* ';' */ -+ *ret_value = val; -+ return (p - buf) + 1; -+ default: -+ return -1; /* Character set error */ -+ } -+ } -+ -+ *ret_value = -1; -+ return (p - buf); -+} -+ -+/* -+ * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" -+ */ -+static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { -+ OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; -+ const char *p = (const char *)chunk_buf; -+ const char *pend = p + chunk_size; -+ uint8_t *buf; -+ -+ /* Reallocate buffer */ -+ ssize_t _ns = st->size + chunk_size; -+ void *nptr = REALLOC(st->buf, _ns + 1); -+ if(!nptr) return -1; -+ st->buf = (uint8_t *)nptr; -+ buf = st->buf + st->size; -+ -+ /* -+ * Convert series of 0 and 1 into the octet string. -+ */ -+ for(; p < pend; p++) { -+ int ch = *(const unsigned char *)p; -+ int len; /* Length of the rest of the chunk */ -+ -+ if(ch != 0x26 /* '&' */) { -+ *buf++ = ch; -+ continue; /* That was easy... */ -+ } -+ -+ /* -+ * Process entity reference. -+ */ -+ len = chunk_size - (p - (const char *)chunk_buf); -+ if(len == 1 /* "&" */) goto want_more; -+ if(p[1] == 0x23 /* '#' */) { -+ const char *pval; /* Pointer to start of digits */ -+ int32_t val = 0; /* Entity reference value */ -+ int base; -+ -+ if(len == 2 /* "&#" */) goto want_more; -+ if(p[2] == 0x78 /* 'x' */) -+ pval = p + 3, base = 16; -+ else -+ pval = p + 2, base = 10; -+ len = OS__strtoent(base, pval, p + len, &val); -+ if(len == -1) { -+ /* Invalid charset. Just copy verbatim. */ -+ *buf++ = ch; -+ continue; -+ } -+ if(!len || pval[len-1] != 0x3b) goto want_more; -+ assert(val > 0); -+ p += (pval - p) + len - 1; /* Advance past entref */ -+ -+ if(val < 0x80) { -+ *buf++ = (char)val; -+ } else if(val < 0x800) { -+ *buf++ = 0xc0 | ((val >> 6)); -+ *buf++ = 0x80 | ((val & 0x3f)); -+ } else if(val < 0x10000) { -+ *buf++ = 0xe0 | ((val >> 12)); -+ *buf++ = 0x80 | ((val >> 6) & 0x3f); -+ *buf++ = 0x80 | ((val & 0x3f)); -+ } else if(val < 0x200000) { -+ *buf++ = 0xf0 | ((val >> 18)); -+ *buf++ = 0x80 | ((val >> 12) & 0x3f); -+ *buf++ = 0x80 | ((val >> 6) & 0x3f); -+ *buf++ = 0x80 | ((val & 0x3f)); -+ } else if(val < 0x4000000) { -+ *buf++ = 0xf8 | ((val >> 24)); -+ *buf++ = 0x80 | ((val >> 18) & 0x3f); -+ *buf++ = 0x80 | ((val >> 12) & 0x3f); -+ *buf++ = 0x80 | ((val >> 6) & 0x3f); -+ *buf++ = 0x80 | ((val & 0x3f)); -+ } else { -+ *buf++ = 0xfc | ((val >> 30) & 0x1); -+ *buf++ = 0x80 | ((val >> 24) & 0x3f); -+ *buf++ = 0x80 | ((val >> 18) & 0x3f); -+ *buf++ = 0x80 | ((val >> 12) & 0x3f); -+ *buf++ = 0x80 | ((val >> 6) & 0x3f); -+ *buf++ = 0x80 | ((val & 0x3f)); -+ } -+ } else { -+ /* -+ * Ugly, limited parsing of & > < -+ */ -+ char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len); -+ if(!sc) goto want_more; -+ if((sc - p) == 4 -+ && p[1] == 0x61 /* 'a' */ -+ && p[2] == 0x6d /* 'm' */ -+ && p[3] == 0x70 /* 'p' */) { -+ *buf++ = 0x26; -+ p = sc; -+ continue; -+ } -+ if((sc - p) == 3) { -+ if(p[1] == 0x6c) { -+ *buf = 0x3c; /* '<' */ -+ } else if(p[1] == 0x67) { -+ *buf = 0x3e; /* '>' */ -+ } else { -+ /* Unsupported entity reference */ -+ *buf++ = ch; -+ continue; -+ } -+ if(p[2] != 0x74) { -+ /* Unsupported entity reference */ -+ *buf++ = ch; -+ continue; -+ } -+ buf++; -+ p = sc; -+ continue; -+ } -+ /* Unsupported entity reference */ -+ *buf++ = ch; -+ } -+ -+ continue; -+ want_more: -+ if(have_more) { -+ /* -+ * We know that no more data (of the same type) -+ * is coming. Copy the rest verbatim. -+ */ -+ *buf++ = ch; -+ continue; -+ } -+ chunk_size = (p - (const char *)chunk_buf); -+ /* Processing stalled: need more data */ -+ break; -+ } -+ -+ st->size = buf - st->buf; -+ assert(st->size <= _ns); -+ st->buf[st->size] = 0; /* Courtesy termination */ -+ -+ return chunk_size; /* Converted in full */ -+} -+ -+/* -+ * Decode OCTET STRING from the XML element's body. -+ */ -+static asn_dec_rval_t -+OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, void **sptr, -+ const char *opt_mname, const void *buf_ptr, size_t size, -+ int (*opt_unexpected_tag_decoder) -+ (void *struct_ptr, const void *chunk_buf, size_t chunk_size), -+ ssize_t (*body_receiver) -+ (void *struct_ptr, const void *chunk_buf, size_t chunk_size, -+ int have_more) -+) { -+ OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; -+ asn_struct_ctx_t *ctx; /* Per-structure parser context */ -+ asn_dec_rval_t rval; /* Return value from the decoder */ -+ int st_allocated; -+ -+ /* -+ * Create the string if does not exist. -+ */ -+ if(!st) { -+ st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); -+ *sptr = (void *)st; -+ if(!st) goto sta_failed; -+ st_allocated = 1; -+ } else { -+ st_allocated = 0; -+ } -+ if(!st->buf) { -+ /* This is separate from above section */ -+ st->buf = (uint8_t *)CALLOC(1, 1); -+ if(!st->buf) { -+ if(st_allocated) { -+ *sptr = 0; -+ goto stb_failed; -+ } else { -+ goto sta_failed; -+ } -+ } -+ } -+ -+ /* Restore parsing context */ -+ ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset); -+ -+ return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag, -+ buf_ptr, size, opt_unexpected_tag_decoder, body_receiver); -+ -+stb_failed: -+ FREEMEM(st); -+sta_failed: -+ rval.code = RC_FAIL; -+ rval.consumed = 0; -+ return rval; -+} -+ -+/* -+ * Decode OCTET STRING from the hexadecimal data. -+ */ -+asn_dec_rval_t -+OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, void **sptr, -+ const char *opt_mname, const void *buf_ptr, size_t size) { -+ return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, -+ buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); -+} -+ -+/* -+ * Decode OCTET STRING from the binary (0/1) data. -+ */ -+asn_dec_rval_t -+OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, void **sptr, -+ const char *opt_mname, const void *buf_ptr, size_t size) { -+ return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, -+ buf_ptr, size, 0, OCTET_STRING__convert_binary); -+} -+ -+/* -+ * Decode OCTET STRING from the string (ASCII/UTF-8) data. -+ */ -+asn_dec_rval_t -+OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, void **sptr, -+ const char *opt_mname, const void *buf_ptr, size_t size) { -+ return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, -+ buf_ptr, size, -+ OCTET_STRING__handle_control_chars, -+ OCTET_STRING__convert_entrefs); -+} -+ -+asn_dec_rval_t -+OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, -+ void **sptr, asn_per_data_t *pd) { -+ -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ asn_per_constraint_t *ct = constraints ? &constraints->size -+ : (td->per_constraints -+ ? &td->per_constraints->size -+ : &asn_DEF_OCTET_STRING_constraint); -+ asn_dec_rval_t rval = { RC_OK, 0 }; -+ BIT_STRING_t *st = (BIT_STRING_t *)*sptr; -+ ssize_t consumed_myself = 0; -+ int repeat; -+ int unit_bits = (specs->subvariant != 1) * 7 + 1; -+ -+ (void)opt_codec_ctx; -+ -+ /* -+ * Allocate the string. -+ */ -+ if(!st) { -+ st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); -+ if(!st) RETURN(RC_FAIL); -+ } -+ -+ ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d", -+ ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed", -+ ct->lower_bound, ct->upper_bound, ct->effective_bits); -+ -+ if(ct->flags & APC_EXTENSIBLE) { -+ int inext = per_get_few_bits(pd, 1); -+ if(inext < 0) RETURN(RC_WMORE); -+ if(inext) ct = &asn_DEF_OCTET_STRING_constraint; -+ consumed_myself = 0; -+ } -+ -+ if(ct->effective_bits >= 0 -+ && (!st->buf || st->size < ct->upper_bound)) { -+ FREEMEM(st->buf); -+ if(unit_bits == 1) { -+ st->size = (ct->upper_bound + 7) >> 3; -+ } else { -+ st->size = ct->upper_bound; -+ } -+ st->buf = (uint8_t *)MALLOC(st->size + 1); -+ if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } -+ } -+ -+ /* X.691, #16.5: zero-length encoding */ -+ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ -+ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ -+ if(ct->effective_bits == 0) { -+ int ret = per_get_many_bits(pd, st->buf, 0, -+ unit_bits * ct->upper_bound); -+ if(ret < 0) RETURN(RC_WMORE); -+ consumed_myself += unit_bits * ct->upper_bound; -+ st->buf[st->size] = 0; -+ if(unit_bits == 1 && (ct->upper_bound & 0x7)) -+ st->bits_unused = 8 - (ct->upper_bound & 0x7); -+ RETURN(RC_OK); -+ } -+ -+ st->size = 0; -+ do { -+ ssize_t len_bytes; -+ ssize_t len_bits; -+ void *p; -+ int ret; -+ -+ /* Get the PER length */ -+ len_bits = uper_get_length(pd, ct->effective_bits, &repeat); -+ if(len_bits < 0) RETURN(RC_WMORE); -+ len_bits += ct->lower_bound; -+ -+ ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", -+ (long)ct->effective_bits, (long)len_bits, -+ repeat ? "repeat" : "once", td->name); -+ if(unit_bits == 1) { -+ len_bytes = (len_bits + 7) >> 3; -+ if(len_bits & 0x7) -+ st->bits_unused = 8 - (len_bits & 0x7); -+ /* len_bits be multiple of 16K if repeat is set */ -+ } else { -+ len_bytes = len_bits; -+ len_bits = len_bytes << 3; -+ } -+ p = REALLOC(st->buf, st->size + len_bytes + 1); -+ if(!p) RETURN(RC_FAIL); -+ st->buf = (uint8_t *)p; -+ -+ ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); -+ if(ret < 0) RETURN(RC_WMORE); -+ st->size += len_bytes; -+ } while(repeat); -+ st->buf[st->size] = 0; /* nul-terminate */ -+ -+ return rval; -+} -+ -+asn_enc_rval_t -+OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ asn_per_constraint_t *ct = constraints ? &constraints->size -+ : (td->per_constraints -+ ? &td->per_constraints->size -+ : &asn_DEF_OCTET_STRING_constraint); -+ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; -+ int unit_bits = (specs->subvariant != 1) * 7 + 1; -+ asn_enc_rval_t er; -+ int ct_extensible = ct->flags & APC_EXTENSIBLE; -+ int inext = 0; /* Lies not within extension root */ -+ int sizeinunits = st->size; -+ const uint8_t *buf; -+ int ret; -+ -+ if(!st || !st->buf) -+ _ASN_ENCODE_FAILED; -+ -+ if(unit_bits == 1) { -+ ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", -+ sizeinunits, st->bits_unused); -+ sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07); -+ } -+ -+ ASN_DEBUG("Encoding %s into %d units of %d bits" -+ " (%d..%d, effective %d)%s", -+ td->name, sizeinunits, unit_bits, -+ ct->lower_bound, ct->upper_bound, -+ ct->effective_bits, ct_extensible ? " EXT" : ""); -+ -+ /* Figure out wheter size lies within PER visible consrtaint */ -+ -+ if(ct->effective_bits >= 0) { -+ if(sizeinunits < ct->lower_bound -+ || sizeinunits > ct->upper_bound) { -+ if(ct_extensible) { -+ ct = &asn_DEF_OCTET_STRING_constraint; -+ inext = 1; -+ } else -+ _ASN_ENCODE_FAILED; -+ } -+ } else { -+ inext = 0; -+ } -+ -+ if(ct_extensible) { -+ /* Declare whether length is [not] within extension root */ -+ if(per_put_few_bits(po, inext, 1)) -+ _ASN_ENCODE_FAILED; -+ } -+ -+ /* X.691, #16.5: zero-length encoding */ -+ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ -+ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ -+ if(ct->effective_bits >= 0) { -+ ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", -+ st->size, sizeinunits - ct->lower_bound, -+ ct->effective_bits); -+ ret = per_put_few_bits(po, sizeinunits - ct->lower_bound, -+ ct->effective_bits); -+ if(ret) _ASN_ENCODE_FAILED; -+ ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits); -+ if(ret) _ASN_ENCODE_FAILED; -+ _ASN_ENCODED_OK(er); -+ } -+ -+ ASN_DEBUG("Encoding %d bytes", st->size); -+ -+ if(sizeinunits == 0) { -+ if(uper_put_length(po, 0)) -+ _ASN_ENCODE_FAILED; -+ _ASN_ENCODED_OK(er); -+ } -+ -+ buf = st->buf; -+ while(sizeinunits) { -+ ssize_t maySave = uper_put_length(po, sizeinunits); -+ if(maySave < 0) _ASN_ENCODE_FAILED; -+ -+ ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits); -+ -+ ret = per_put_many_bits(po, buf, maySave * unit_bits); -+ if(ret) _ASN_ENCODE_FAILED; -+ -+ if(unit_bits == 1) -+ buf += maySave >> 3; -+ else -+ buf += maySave; -+ sizeinunits -= maySave; -+ assert(!(maySave & 0x07) || !sizeinunits); -+ } -+ -+ _ASN_ENCODED_OK(er); -+} -+ -+int -+OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ static const char *h2c = "0123456789ABCDEF"; -+ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; -+ char scratch[16 * 3 + 4]; -+ char *p = scratch; -+ uint8_t *buf; -+ uint8_t *end; -+ size_t i; -+ -+ (void)td; /* Unused argument */ -+ -+ if(!st || !st->buf) return (cb("", 8, app_key) < 0) ? -1 : 0; -+ -+ /* -+ * Dump the contents of the buffer in hexadecimal. -+ */ -+ buf = st->buf; -+ end = buf + st->size; -+ for(i = 0; buf < end; buf++, i++) { -+ if(!(i % 16) && (i || st->size > 16)) { -+ if(cb(scratch, p - scratch, app_key) < 0) -+ return -1; -+ _i_INDENT(1); -+ p = scratch; -+ } -+ *p++ = h2c[(*buf >> 4) & 0x0F]; -+ *p++ = h2c[*buf & 0x0F]; -+ *p++ = 0x20; -+ } -+ -+ if(p > scratch) { -+ p--; /* Remove the tail space */ -+ if(cb(scratch, p - scratch, app_key) < 0) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+int -+OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, -+ int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { -+ const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; -+ -+ (void)td; /* Unused argument */ -+ (void)ilevel; /* Unused argument */ -+ -+ if(st && st->buf) { -+ return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; -+ } else { -+ return (cb("", 8, app_key) < 0) ? -1 : 0; -+ } -+} -+ -+void -+OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { -+ OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ asn_struct_ctx_t *ctx = (asn_struct_ctx_t *) -+ ((char *)st + specs->ctx_offset); -+ struct _stack *stck; -+ -+ if(!td || !st) -+ return; -+ -+ ASN_DEBUG("Freeing %s as OCTET STRING", td->name); -+ -+ if(st->buf) { -+ FREEMEM(st->buf); -+ } -+ -+ /* -+ * Remove decode-time stack. -+ */ -+ stck = (struct _stack *)ctx->ptr; -+ if(stck) { -+ while(stck->tail) { -+ struct _stack_el *sel = stck->tail; -+ stck->tail = sel->prev; -+ FREEMEM(sel); -+ } -+ FREEMEM(stck); -+ } -+ -+ if(!contents_only) { -+ FREEMEM(st); -+ } -+} -+ -+/* -+ * Conversion routines. -+ */ -+int -+OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { -+ void *buf; -+ -+ if(st == 0 || (str == 0 && len)) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ /* -+ * Clear the OCTET STRING. -+ */ -+ if(str == NULL) { -+ FREEMEM(st->buf); -+ st->buf = 0; -+ st->size = 0; -+ return 0; -+ } -+ -+ /* Determine the original string size, if not explicitly given */ -+ if(len < 0) -+ len = strlen(str); -+ -+ /* Allocate and fill the memory */ -+ buf = MALLOC(len + 1); -+ if(buf == NULL) -+ return -1; -+ -+ memcpy(buf, str, len); -+ ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ -+ FREEMEM(st->buf); -+ st->buf = (uint8_t *)buf; -+ st->size = len; -+ -+ return 0; -+} -+ -+OCTET_STRING_t * -+OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { -+ asn_OCTET_STRING_specifics_t *specs = td->specifics -+ ? (asn_OCTET_STRING_specifics_t *)td->specifics -+ : &asn_DEF_OCTET_STRING_specs; -+ OCTET_STRING_t *st; -+ -+ st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); -+ if(st && str && OCTET_STRING_fromBuf(st, str, len)) { -+ FREEMEM(st); -+ st = NULL; -+ } -+ -+ return st; -+} -+ -diff --git a/asn1/asn1c/OCTET_STRING.h b/asn1/asn1c/OCTET_STRING.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5150161a7a1a19e8e7c123776684e66c1cd429cf ---- /dev/null -+++ b/asn1/asn1c/OCTET_STRING.h -@@ -0,0 +1,80 @@ -+/*- -+ * Copyright (c) 2003 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _OCTET_STRING_H_ -+#define _OCTET_STRING_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct OCTET_STRING { -+ uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ -+ int size; /* Size of the buffer */ -+ -+ asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ -+} OCTET_STRING_t; -+ -+extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; -+ -+asn_struct_free_f OCTET_STRING_free; -+asn_struct_print_f OCTET_STRING_print; -+asn_struct_print_f OCTET_STRING_print_utf8; -+ber_type_decoder_f OCTET_STRING_decode_ber; -+der_type_encoder_f OCTET_STRING_encode_der; -+xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ -+xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ -+xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ -+xer_type_encoder_f OCTET_STRING_encode_xer; -+xer_type_encoder_f OCTET_STRING_encode_xer_utf8; -+per_type_decoder_f OCTET_STRING_decode_uper; -+per_type_encoder_f OCTET_STRING_encode_uper; -+ -+/****************************** -+ * Handy conversion routines. * -+ ******************************/ -+ -+/* -+ * This function clears the previous value of the OCTET STRING (if any) -+ * and then allocates a new memory with the specified content (str/size). -+ * If size = -1, the size of the original string will be determined -+ * using strlen(str). -+ * If str equals to NULL, the function will silently clear the -+ * current contents of the OCTET STRING. -+ * Returns 0 if it was possible to perform operation, -1 otherwise. -+ */ -+int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); -+ -+/* Handy conversion from the C string into the OCTET STRING. */ -+#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) -+ -+/* -+ * Allocate and fill the new OCTET STRING and return a pointer to the newly -+ * allocated object. NULL is permitted in str: the function will just allocate -+ * empty OCTET STRING. -+ */ -+OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, -+ const char *str, int size); -+ -+/**************************** -+ * Internally useful stuff. * -+ ****************************/ -+ -+typedef struct asn_OCTET_STRING_specifics_s { -+ /* -+ * Target structure description. -+ */ -+ int struct_size; /* Size of the structure */ -+ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ -+ -+ int subvariant; /* {0,1,2} for O-S, BIT STRING or ANY */ -+} asn_OCTET_STRING_specifics_t; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _OCTET_STRING_H_ */ -diff --git a/asn1/asn1c/TypeValuePair.c b/asn1/asn1c/TypeValuePair.c -new file mode 100644 -index 0000000000000000000000000000000000000000..707eef3f65c4bf0a64b4864391e64865cc19d7ca ---- /dev/null -+++ b/asn1/asn1c/TypeValuePair.c -@@ -0,0 +1,71 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#include -+ -+#include "TypeValuePair.h" -+ -+static asn_TYPE_member_t asn_MBR_TypeValuePair_1[] = { -+ { ATF_NOFLAGS, 0, offsetof(struct TypeValuePair, type), -+ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_Int32, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "type" -+ }, -+ { ATF_NOFLAGS, 0, offsetof(struct TypeValuePair, value), -+ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), -+ +1, /* EXPLICIT tag at current level */ -+ &asn_DEF_OCTET_STRING, -+ 0, /* Defer constraints checking to the member type */ -+ 0, /* PER is not compiled, use -gen-PER */ -+ 0, -+ "value" -+ }, -+}; -+static ber_tlv_tag_t asn_DEF_TypeValuePair_tags_1[] = { -+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -+}; -+static asn_TYPE_tag2member_t asn_MAP_TypeValuePair_tag2el_1[] = { -+ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* type at 34 */ -+ { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* value at 35 */ -+}; -+static asn_SEQUENCE_specifics_t asn_SPC_TypeValuePair_specs_1 = { -+ sizeof(struct TypeValuePair), -+ offsetof(struct TypeValuePair, _asn_ctx), -+ asn_MAP_TypeValuePair_tag2el_1, -+ 2, /* Count of tags in the map */ -+ 0, 0, 0, /* Optional elements (not needed) */ -+ -1, /* Start extensions */ -+ -1 /* Stop extensions */ -+}; -+asn_TYPE_descriptor_t asn_DEF_TypeValuePair = { -+ "TypeValuePair", -+ "TypeValuePair", -+ SEQUENCE_free, -+ SEQUENCE_print, -+ SEQUENCE_constraint, -+ SEQUENCE_decode_ber, -+ SEQUENCE_encode_der, -+ SEQUENCE_decode_xer, -+ SEQUENCE_encode_xer, -+ 0, 0, /* No PER support, use "-gen-PER" to enable */ -+ 0, /* Use generic outmost tag fetcher */ -+ asn_DEF_TypeValuePair_tags_1, -+ sizeof(asn_DEF_TypeValuePair_tags_1) -+ /sizeof(asn_DEF_TypeValuePair_tags_1[0]), /* 1 */ -+ asn_DEF_TypeValuePair_tags_1, /* Same as above */ -+ sizeof(asn_DEF_TypeValuePair_tags_1) -+ /sizeof(asn_DEF_TypeValuePair_tags_1[0]), /* 1 */ -+ 0, /* No PER visible constraints */ -+ asn_MBR_TypeValuePair_1, -+ 2, /* Elements count */ -+ &asn_SPC_TypeValuePair_specs_1 /* Additional specs */ -+}; -+ -diff --git a/asn1/asn1c/TypeValuePair.h b/asn1/asn1c/TypeValuePair.h -new file mode 100644 -index 0000000000000000000000000000000000000000..538b4609c5f0fe051988885c84c3caf6d8b85452 ---- /dev/null -+++ b/asn1/asn1c/TypeValuePair.h -@@ -0,0 +1,39 @@ -+/* -+ * Generated by asn1c-0.9.21 (http://lionet.info/asn1c) -+ * From ASN.1 module "KeytabModule" -+ * found in "ipa.asn1" -+ * `asn1c -fskeletons-copy` -+ */ -+ -+#ifndef _TypeValuePair_H_ -+#define _TypeValuePair_H_ -+ -+ -+#include -+ -+/* Including external dependencies */ -+#include "Int32.h" -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* TypeValuePair */ -+typedef struct TypeValuePair { -+ Int32_t type; -+ OCTET_STRING_t value; -+ -+ /* Context for parsing across buffer boundaries */ -+ asn_struct_ctx_t _asn_ctx; -+} TypeValuePair_t; -+ -+/* Implementation */ -+extern asn_TYPE_descriptor_t asn_DEF_TypeValuePair; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _TypeValuePair_H_ */ -diff --git a/asn1/asn1c/asn_SEQUENCE_OF.c b/asn1/asn1c/asn_SEQUENCE_OF.c -new file mode 100644 -index 0000000000000000000000000000000000000000..ec952fc99936ab1464d76ac75821fc19e47995cb ---- /dev/null -+++ b/asn1/asn1c/asn_SEQUENCE_OF.c -@@ -0,0 +1,41 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+ -+typedef A_SEQUENCE_OF(void) asn_sequence; -+ -+void -+asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free) { -+ asn_sequence *as = (asn_sequence *)asn_sequence_of_x; -+ -+ if(as) { -+ void *ptr; -+ int n; -+ -+ if(number < 0 || number >= as->count) -+ return; /* Nothing to delete */ -+ -+ if(_do_free && as->free) { -+ ptr = as->array[number]; -+ } else { -+ ptr = 0; -+ } -+ -+ /* -+ * Shift all elements to the left to hide the gap. -+ */ -+ --as->count; -+ for(n = number; n < as->count; n++) -+ as->array[n] = as->array[n+1]; -+ -+ /* -+ * Invoke the third-party function only when the state -+ * of the parent structure is consistent. -+ */ -+ if(ptr) as->free(ptr); -+ } -+} -+ -diff --git a/asn1/asn1c/asn_SEQUENCE_OF.h b/asn1/asn1c/asn_SEQUENCE_OF.h -new file mode 100644 -index 0000000000000000000000000000000000000000..e678f0347221f96698668bf6d8461655f8e40d82 ---- /dev/null -+++ b/asn1/asn1c/asn_SEQUENCE_OF.h -@@ -0,0 +1,52 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef ASN_SEQUENCE_OF_H -+#define ASN_SEQUENCE_OF_H -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * SEQUENCE OF is the same as SET OF with a tiny difference: -+ * the delete operation preserves the initial order of elements -+ * and thus MAY operate in non-constant time. -+ */ -+#define A_SEQUENCE_OF(type) A_SET_OF(type) -+ -+#define ASN_SEQUENCE_ADD(headptr, ptr) \ -+ asn_sequence_add((headptr), (ptr)) -+ -+/*********************************************** -+ * Implementation of the SEQUENCE OF structure. -+ */ -+ -+#define asn_sequence_add asn_set_add -+#define asn_sequence_empty asn_set_empty -+ -+/* -+ * Delete the element from the set by its number (base 0). -+ * This is NOT a constant-time operation. -+ * The order of elements is preserved. -+ * If _do_free is given AND the (*free) is initialized, the element -+ * will be freed using the custom (*free) function as well. -+ */ -+void asn_sequence_del(void *asn_sequence_of_x, int number, int _do_free); -+ -+/* -+ * Cope with different conversions requirements to/from void in C and C++. -+ * This is mostly useful for support library. -+ */ -+typedef A_SEQUENCE_OF(void) asn_anonymous_sequence_; -+#define _A_SEQUENCE_FROM_VOID(ptr) ((asn_anonymous_sequence_ *)(ptr)) -+#define _A_CSEQUENCE_FROM_VOID(ptr) ((const asn_anonymous_sequence_ *)(ptr)) -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* ASN_SEQUENCE_OF_H */ -diff --git a/asn1/asn1c/asn_SET_OF.c b/asn1/asn1c/asn_SET_OF.c -new file mode 100644 -index 0000000000000000000000000000000000000000..944f2cb8ad70a166e65dbb3536ef62fc34a8e74c ---- /dev/null -+++ b/asn1/asn1c/asn_SET_OF.c -@@ -0,0 +1,88 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * Add another element into the set. -+ */ -+int -+asn_set_add(void *asn_set_of_x, void *ptr) { -+ asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); -+ -+ if(as == 0 || ptr == 0) { -+ errno = EINVAL; /* Invalid arguments */ -+ return -1; -+ } -+ -+ /* -+ * Make sure there's enough space to insert an element. -+ */ -+ if(as->count == as->size) { -+ int _newsize = as->size ? (as->size << 1) : 4; -+ void *_new_arr; -+ _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0])); -+ if(_new_arr) { -+ as->array = (void **)_new_arr; -+ as->size = _newsize; -+ } else { -+ /* ENOMEM */ -+ return -1; -+ } -+ } -+ -+ as->array[as->count++] = ptr; -+ -+ return 0; -+} -+ -+void -+asn_set_del(void *asn_set_of_x, int number, int _do_free) { -+ asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); -+ -+ if(as) { -+ void *ptr; -+ if(number < 0 || number >= as->count) -+ return; -+ -+ if(_do_free && as->free) { -+ ptr = as->array[number]; -+ } else { -+ ptr = 0; -+ } -+ -+ as->array[number] = as->array[--as->count]; -+ -+ /* -+ * Invoke the third-party function only when the state -+ * of the parent structure is consistent. -+ */ -+ if(ptr) as->free(ptr); -+ } -+} -+ -+/* -+ * Free the contents of the set, do not free the set itself. -+ */ -+void -+asn_set_empty(void *asn_set_of_x) { -+ asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); -+ -+ if(as) { -+ if(as->array) { -+ if(as->free) { -+ while(as->count--) -+ as->free(as->array[as->count]); -+ } -+ FREEMEM(as->array); -+ as->array = 0; -+ } -+ as->count = 0; -+ as->size = 0; -+ } -+ -+} -+ -diff --git a/asn1/asn1c/asn_SET_OF.h b/asn1/asn1c/asn_SET_OF.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7edf14b51b984d545b818fcf3a93204935d46a80 ---- /dev/null -+++ b/asn1/asn1c/asn_SET_OF.h -@@ -0,0 +1,62 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef ASN_SET_OF_H -+#define ASN_SET_OF_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define A_SET_OF(type) \ -+ struct { \ -+ type **array; \ -+ int count; /* Meaningful size */ \ -+ int size; /* Allocated size */ \ -+ void (*free)(type *); \ -+ } -+ -+#define ASN_SET_ADD(headptr, ptr) \ -+ asn_set_add((headptr), (ptr)) -+ -+/******************************************* -+ * Implementation of the SET OF structure. -+ */ -+ -+/* -+ * Add another structure into the set by its pointer. -+ * RETURN VALUES: -+ * 0 for success and -1/errno for failure. -+ */ -+int asn_set_add(void *asn_set_of_x, void *ptr); -+ -+/* -+ * Delete the element from the set by its number (base 0). -+ * This is a constant-time operation. The order of elements before the -+ * deleted ones is guaranteed, the order of elements after the deleted -+ * one is NOT guaranteed. -+ * If _do_free is given AND the (*free) is initialized, the element -+ * will be freed using the custom (*free) function as well. -+ */ -+void asn_set_del(void *asn_set_of_x, int number, int _do_free); -+ -+/* -+ * Empty the contents of the set. Will free the elements, if (*free) is given. -+ * Will NOT free the set itself. -+ */ -+void asn_set_empty(void *asn_set_of_x); -+ -+/* -+ * Cope with different conversions requirements to/from void in C and C++. -+ * This is mostly useful for support library. -+ */ -+typedef A_SET_OF(void) asn_anonymous_set_; -+#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) -+#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* ASN_SET_OF_H */ -diff --git a/asn1/asn1c/asn_application.h b/asn1/asn1c/asn_application.h -new file mode 100644 -index 0000000000000000000000000000000000000000..f40cd86ad3c63a7a0a07214addecb57d087abe25 ---- /dev/null -+++ b/asn1/asn1c/asn_application.h -@@ -0,0 +1,47 @@ -+/*- -+ * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * Application-level ASN.1 callbacks. -+ */ -+#ifndef _ASN_APPLICATION_H_ -+#define _ASN_APPLICATION_H_ -+ -+#include "asn_system.h" /* for platform-dependent types */ -+#include "asn_codecs.h" /* for ASN.1 codecs specifics */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * Generic type of an application-defined callback to return various -+ * types of data to the application. -+ * EXPECTED RETURN VALUES: -+ * -1: Failed to consume bytes. Abort the mission. -+ * Non-negative return values indicate success, and ignored. -+ */ -+typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, -+ void *application_specific_key); -+ -+/* -+ * A callback of this type is called whenever constraint validation fails -+ * on some ASN.1 type. See "constraints.h" for more details on constraint -+ * validation. -+ * This callback specifies a descriptor of the ASN.1 type which failed -+ * the constraint check, as well as human readable message on what -+ * particular constraint has failed. -+ */ -+typedef void (asn_app_constraint_failed_f)(void *application_specific_key, -+ struct asn_TYPE_descriptor_s *type_descriptor_which_failed, -+ const void *structure_which_failed_ptr, -+ const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ -+ -+#endif /* _ASN_APPLICATION_H_ */ -diff --git a/asn1/asn1c/asn_codecs.h b/asn1/asn1c/asn_codecs.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4a251d940880a03b24dc9f3fe41f2febb9b49211 ---- /dev/null -+++ b/asn1/asn1c/asn_codecs.h -@@ -0,0 +1,109 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _ASN_CODECS_H_ -+#define _ASN_CODECS_H_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* -+ * This structure defines a set of parameters that may be passed -+ * to every ASN.1 encoder or decoder function. -+ * WARNING: if max_stack_size member is set, and you are calling the -+ * function pointers of the asn_TYPE_descriptor_t directly, -+ * this structure must be ALLOCATED ON THE STACK! -+ * If you can't always satisfy this requirement, use ber_decode(), -+ * xer_decode() and uper_decode() functions instead. -+ */ -+typedef struct asn_codec_ctx_s { -+ /* -+ * Limit the decoder routines to use no (much) more stack than a given -+ * number of bytes. Most of decoders are stack-based, and this -+ * would protect against stack overflows if the number of nested -+ * encodings is high. -+ * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based, -+ * and are safe from this kind of overflow. -+ * A value from getrlimit(RLIMIT_STACK) may be used to initialize -+ * this variable. Be careful in multithreaded environments, as the -+ * stack size is rather limited. -+ */ -+ size_t max_stack_size; /* 0 disables stack bounds checking */ -+} asn_codec_ctx_t; -+ -+/* -+ * Type of the return value of the encoding functions (der_encode, xer_encode). -+ */ -+typedef struct asn_enc_rval_s { -+ /* -+ * Number of bytes encoded. -+ * -1 indicates failure to encode the structure. -+ * In this case, the members below this one are meaningful. -+ */ -+ ssize_t encoded; -+ -+ /* -+ * Members meaningful when (encoded == -1), for post mortem analysis. -+ */ -+ -+ /* Type which cannot be encoded */ -+ struct asn_TYPE_descriptor_s *failed_type; -+ -+ /* Pointer to the structure of that type */ -+ void *structure_ptr; -+} asn_enc_rval_t; -+#define _ASN_ENCODE_FAILED do { \ -+ asn_enc_rval_t tmp_error; \ -+ tmp_error.encoded = -1; \ -+ tmp_error.failed_type = td; \ -+ tmp_error.structure_ptr = sptr; \ -+ ASN_DEBUG("Failed to encode element %s", td->name); \ -+ return tmp_error; \ -+} while(0) -+#define _ASN_ENCODED_OK(rval) do { \ -+ rval.structure_ptr = 0; \ -+ rval.failed_type = 0; \ -+ return rval; \ -+} while(0) -+ -+/* -+ * Type of the return value of the decoding functions (ber_decode, xer_decode) -+ * -+ * Please note that the number of consumed bytes is ALWAYS meaningful, -+ * even if code==RC_FAIL. This is to indicate the number of successfully -+ * decoded bytes, hence providing a possibility to fail with more diagnostics -+ * (i.e., print the offending remainder of the buffer). -+ */ -+enum asn_dec_rval_code_e { -+ RC_OK, /* Decoded successfully */ -+ RC_WMORE, /* More data expected, call again */ -+ RC_FAIL /* Failure to decode data */ -+}; -+typedef struct asn_dec_rval_s { -+ enum asn_dec_rval_code_e code; /* Result code */ -+ size_t consumed; /* Number of bytes consumed */ -+} asn_dec_rval_t; -+#define _ASN_DECODE_FAILED do { \ -+ asn_dec_rval_t tmp_error; \ -+ tmp_error.code = RC_FAIL; \ -+ tmp_error.consumed = 0; \ -+ ASN_DEBUG("Failed to decode element %s", td->name); \ -+ return tmp_error; \ -+} while(0) -+#define _ASN_DECODE_STARVED do { \ -+ asn_dec_rval_t tmp_error; \ -+ tmp_error.code = RC_WMORE; \ -+ tmp_error.consumed = 0; \ -+ return tmp_error; \ -+} while(0) -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _ASN_CODECS_H_ */ -diff --git a/asn1/asn1c/asn_codecs_prim.c b/asn1/asn1c/asn_codecs_prim.c -new file mode 100644 -index 0000000000000000000000000000000000000000..4e5c63937adafc40a56b67fe5b3d9482220907d5 ---- /dev/null -+++ b/asn1/asn1c/asn_codecs_prim.c -@@ -0,0 +1,295 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * Decode an always-primitive type. -+ */ -+asn_dec_rval_t -+ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, -+ void **sptr, const void *buf_ptr, size_t size, int tag_mode) { -+ ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; -+ asn_dec_rval_t rval; -+ ber_tlv_len_t length; -+ -+ /* -+ * If the structure is not there, allocate it. -+ */ -+ if(st == NULL) { -+ st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st)); -+ if(st == NULL) _ASN_DECODE_FAILED; -+ *sptr = (void *)st; -+ } -+ -+ ASN_DEBUG("Decoding %s as plain primitive (tm=%d)", -+ td->name, tag_mode); -+ -+ /* -+ * Check tags and extract value length. -+ */ -+ rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, -+ tag_mode, 0, &length, 0); -+ if(rval.code != RC_OK) -+ return rval; -+ -+ ASN_DEBUG("%s length is %d bytes", td->name, (int)length); -+ -+ /* -+ * Make sure we have this length. -+ */ -+ buf_ptr = ((const char *)buf_ptr) + rval.consumed; -+ size -= rval.consumed; -+ if(length > (ber_tlv_len_t)size) { -+ rval.code = RC_WMORE; -+ rval.consumed = 0; -+ return rval; -+ } -+ -+ st->size = (int)length; -+ /* The following better be optimized away. */ -+ if(sizeof(st->size) != sizeof(length) -+ && (ber_tlv_len_t)st->size != length) { -+ st->size = 0; -+ _ASN_DECODE_FAILED; -+ } -+ -+ st->buf = (uint8_t *)MALLOC(length + 1); -+ if(!st->buf) { -+ st->size = 0; -+ _ASN_DECODE_FAILED; -+ } -+ -+ memcpy(st->buf, buf_ptr, length); -+ st->buf[length] = '\0'; /* Just in case */ -+ -+ rval.code = RC_OK; -+ rval.consumed += length; -+ -+ ASN_DEBUG("Took %ld/%ld bytes to encode %s", -+ (long)rval.consumed, -+ (long)length, td->name); -+ -+ return rval; -+} -+ -+/* -+ * Encode an always-primitive type using DER. -+ */ -+asn_enc_rval_t -+der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t erval; -+ ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; -+ -+ ASN_DEBUG("%s %s as a primitive type (tm=%d)", -+ cb?"Encoding":"Estimating", td->name, tag_mode); -+ -+ erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag, -+ cb, app_key); -+ ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded); -+ if(erval.encoded == -1) { -+ erval.failed_type = td; -+ erval.structure_ptr = sptr; -+ return erval; -+ } -+ -+ if(cb && st->buf) { -+ if(cb(st->buf, st->size, app_key) < 0) { -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = sptr; -+ return erval; -+ } -+ } else { -+ assert(st->buf || st->size == 0); -+ } -+ -+ erval.encoded += st->size; -+ _ASN_ENCODED_OK(erval); -+} -+ -+void -+ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr, -+ int contents_only) { -+ ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; -+ -+ if(!td || !sptr) -+ return; -+ -+ ASN_DEBUG("Freeing %s as a primitive type", td->name); -+ -+ if(st->buf) -+ FREEMEM(st->buf); -+ -+ if(!contents_only) -+ FREEMEM(st); -+} -+ -+ -+/* -+ * Local internal type passed around as an argument. -+ */ -+struct xdp_arg_s { -+ asn_TYPE_descriptor_t *type_descriptor; -+ void *struct_key; -+ xer_primitive_body_decoder_f *prim_body_decoder; -+ int decoded_something; -+ int want_more; -+}; -+ -+ -+static int -+xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { -+ struct xdp_arg_s *arg = (struct xdp_arg_s *)key; -+ enum xer_pbd_rval bret; -+ -+ if(arg->decoded_something) { -+ if(xer_is_whitespace(chunk_buf, chunk_size)) -+ return 0; /* Skip it. */ -+ /* -+ * Decoding was done once already. Prohibit doing it again. -+ */ -+ return -1; -+ } -+ -+ bret = arg->prim_body_decoder(arg->type_descriptor, -+ arg->struct_key, chunk_buf, chunk_size); -+ switch(bret) { -+ case XPBD_SYSTEM_FAILURE: -+ case XPBD_DECODER_LIMIT: -+ case XPBD_BROKEN_ENCODING: -+ break; -+ case XPBD_BODY_CONSUMED: -+ /* Tag decoded successfully */ -+ arg->decoded_something = 1; -+ /* Fall through */ -+ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ -+ return 0; -+ } -+ -+ return -1; -+} -+ -+static ssize_t -+xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { -+ struct xdp_arg_s *arg = (struct xdp_arg_s *)key; -+ enum xer_pbd_rval bret; -+ -+ if(arg->decoded_something) { -+ if(xer_is_whitespace(chunk_buf, chunk_size)) -+ return chunk_size; -+ /* -+ * Decoding was done once already. Prohibit doing it again. -+ */ -+ return -1; -+ } -+ -+ if(!have_more) { -+ /* -+ * If we've received something like "1", we can't really -+ * tell whether it is really `1` or `123`, until we know -+ * that there is no more data coming. -+ * The have_more argument will be set to 1 once something -+ * like this is available to the caller of this callback: -+ * "1want_more = 1; -+ return -1; -+ } -+ -+ bret = arg->prim_body_decoder(arg->type_descriptor, -+ arg->struct_key, chunk_buf, chunk_size); -+ switch(bret) { -+ case XPBD_SYSTEM_FAILURE: -+ case XPBD_DECODER_LIMIT: -+ case XPBD_BROKEN_ENCODING: -+ break; -+ case XPBD_BODY_CONSUMED: -+ /* Tag decoded successfully */ -+ arg->decoded_something = 1; -+ /* Fall through */ -+ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ -+ return chunk_size; -+ } -+ -+ return -1; -+} -+ -+ -+asn_dec_rval_t -+xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, -+ void **sptr, -+ size_t struct_size, -+ const char *opt_mname, -+ const void *buf_ptr, size_t size, -+ xer_primitive_body_decoder_f *prim_body_decoder -+) { -+ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; -+ asn_struct_ctx_t s_ctx; -+ struct xdp_arg_s s_arg; -+ asn_dec_rval_t rc; -+ -+ /* -+ * Create the structure if does not exist. -+ */ -+ if(!*sptr) { -+ *sptr = CALLOC(1, struct_size); -+ if(!*sptr) _ASN_DECODE_FAILED; -+ } -+ -+ memset(&s_ctx, 0, sizeof(s_ctx)); -+ s_arg.type_descriptor = td; -+ s_arg.struct_key = *sptr; -+ s_arg.prim_body_decoder = prim_body_decoder; -+ s_arg.decoded_something = 0; -+ s_arg.want_more = 0; -+ -+ rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, -+ xml_tag, buf_ptr, size, -+ xer_decode__unexpected_tag, xer_decode__body); -+ switch(rc.code) { -+ case RC_OK: -+ if(!s_arg.decoded_something) { -+ char ch; -+ ASN_DEBUG("Primitive body is not recognized, " -+ "supplying empty one"); -+ /* -+ * Decoding opportunity has come and gone. -+ * Where's the result? -+ * Try to feed with empty body, see if it eats it. -+ */ -+ if(prim_body_decoder(s_arg.type_descriptor, -+ s_arg.struct_key, &ch, 0) -+ != XPBD_BODY_CONSUMED) { -+ /* -+ * This decoder does not like empty stuff. -+ */ -+ _ASN_DECODE_FAILED; -+ } -+ } -+ break; -+ case RC_WMORE: -+ /* -+ * Redo the whole thing later. -+ * We don't have a context to save intermediate parsing state. -+ */ -+ rc.consumed = 0; -+ break; -+ case RC_FAIL: -+ rc.consumed = 0; -+ if(s_arg.want_more) -+ rc.code = RC_WMORE; -+ else -+ _ASN_DECODE_FAILED; -+ break; -+ } -+ return rc; -+} -+ -diff --git a/asn1/asn1c/asn_codecs_prim.h b/asn1/asn1c/asn_codecs_prim.h -new file mode 100644 -index 0000000000000000000000000000000000000000..0f683fdd0ac7d5be56c55b1363fa4fddb0d48198 ---- /dev/null -+++ b/asn1/asn1c/asn_codecs_prim.h -@@ -0,0 +1,53 @@ -+/*- -+ * Copyright (c) 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef ASN_CODECS_PRIM_H -+#define ASN_CODECS_PRIM_H -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct ASN__PRIMITIVE_TYPE_s { -+ uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ -+ int size; /* Size of the buffer */ -+} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ -+ -+asn_struct_free_f ASN__PRIMITIVE_TYPE_free; -+ber_type_decoder_f ber_decode_primitive; -+der_type_encoder_f der_encode_primitive; -+ -+/* -+ * A callback specification for the xer_decode_primitive() function below. -+ */ -+enum xer_pbd_rval { -+ XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ -+ XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ -+ XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ -+ XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ -+ XPBD_BODY_CONSUMED /* Body is recognized and consumed */ -+}; -+typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) -+ (asn_TYPE_descriptor_t *td, void *struct_ptr, -+ const void *chunk_buf, size_t chunk_size); -+ -+/* -+ * Specific function to decode simple primitive types. -+ * Also see xer_decode_general() in xer_decoder.h -+ */ -+asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *type_descriptor, -+ void **struct_ptr, size_t struct_size, -+ const char *opt_mname, -+ const void *buf_ptr, size_t size, -+ xer_primitive_body_decoder_f *prim_body_decoder -+); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* ASN_CODECS_PRIM_H */ -diff --git a/asn1/asn1c/asn_internal.h b/asn1/asn1c/asn_internal.h -new file mode 100644 -index 0000000000000000000000000000000000000000..67f055a62fbf74c397d2c108469549291ef9e6af ---- /dev/null -+++ b/asn1/asn1c/asn_internal.h -@@ -0,0 +1,111 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * Declarations internally useful for the ASN.1 support code. -+ */ -+#ifndef _ASN_INTERNAL_H_ -+#define _ASN_INTERNAL_H_ -+ -+#include "asn_application.h" /* Application-visible API */ -+ -+#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ -+#include /* for assert() macro */ -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* Environment version might be used to avoid running with the old library */ -+#define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */ -+int get_asn1c_environment_version(void); /* Run-time version */ -+ -+#define CALLOC(nmemb, size) calloc(nmemb, size) -+#define MALLOC(size) malloc(size) -+#define REALLOC(oldptr, size) realloc(oldptr, size) -+#define FREEMEM(ptr) free(ptr) -+ -+/* -+ * A macro for debugging the ASN.1 internals. -+ * You may enable or override it. -+ */ -+#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ -+#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ -+#ifdef __GNUC__ -+#define ASN_DEBUG(fmt, args...) do { \ -+ fprintf(stderr, fmt, ##args); \ -+ fprintf(stderr, " (%s:%d)\n", \ -+ __FILE__, __LINE__); \ -+ } while(0) -+#else /* !__GNUC__ */ -+void ASN_DEBUG_f(const char *fmt, ...); -+#define ASN_DEBUG ASN_DEBUG_f -+#endif /* __GNUC__ */ -+#else /* EMIT_ASN_DEBUG != 1 */ -+static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } -+#endif /* EMIT_ASN_DEBUG */ -+#endif /* ASN_DEBUG */ -+ -+/* -+ * Invoke the application-supplied callback and fail, if something is wrong. -+ */ -+#define __ASN_E_cbc(buf, size) (cb((buf), (size), app_key) < 0) -+#define _ASN_E_CALLBACK(foo) do { \ -+ if(foo) goto cb_failed; \ -+ } while(0) -+#define _ASN_CALLBACK(buf, size) \ -+ _ASN_E_CALLBACK(__ASN_E_cbc(buf, size)) -+#define _ASN_CALLBACK2(buf1, size1, buf2, size2) \ -+ _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) || __ASN_E_cbc(buf2, size2)) -+#define _ASN_CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ -+ _ASN_E_CALLBACK(__ASN_E_cbc(buf1, size1) \ -+ || __ASN_E_cbc(buf2, size2) \ -+ || __ASN_E_cbc(buf3, size3)) -+ -+#define _i_ASN_TEXT_INDENT(nl, level) do { \ -+ int __level = (level); \ -+ int __nl = ((nl) != 0); \ -+ int __i; \ -+ if(__nl) _ASN_CALLBACK("\n", 1); \ -+ for(__i = 0; __i < __level; __i++) \ -+ _ASN_CALLBACK(" ", 4); \ -+ er.encoded += __nl + 4 * __level; \ -+} while(0) -+ -+#define _i_INDENT(nl) do { \ -+ int __i; \ -+ if((nl) && cb("\n", 1, app_key) < 0) return -1; \ -+ for(__i = 0; __i < ilevel; __i++) \ -+ if(cb(" ", 4, app_key) < 0) return -1; \ -+} while(0) -+ -+/* -+ * Check stack against overflow, if limit is set. -+ */ -+#define _ASN_DEFAULT_STACK_MAX (30000) -+static inline int -+_ASN_STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { -+ if(ctx && ctx->max_stack_size) { -+ -+ /* ctx MUST be allocated on the stack */ -+ ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); -+ if(usedstack > 0) usedstack = -usedstack; /* grows up! */ -+ -+ /* double negative required to avoid int wrap-around */ -+ if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { -+ ASN_DEBUG("Stack limit %ld reached", -+ (long)ctx->max_stack_size); -+ return -1; -+ } -+ } -+ return 0; -+} -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _ASN_INTERNAL_H_ */ -diff --git a/asn1/asn1c/asn_system.h b/asn1/asn1c/asn_system.h -new file mode 100644 -index 0000000000000000000000000000000000000000..d7ebdaa4e16a2636184db6ba4fe34fda5860a6bc ---- /dev/null -+++ b/asn1/asn1c/asn_system.h -@@ -0,0 +1,104 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * Miscellaneous system-dependent types. -+ */ -+#ifndef _ASN_SYSTEM_H_ -+#define _ASN_SYSTEM_H_ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include /* For snprintf(3) */ -+#include /* For *alloc(3) */ -+#include /* For memcpy(3) */ -+#include /* For size_t */ -+#include /* For va_start */ -+#include /* for offsetof and ptrdiff_t */ -+ -+#ifdef WIN32 -+ -+#include -+#include -+#define snprintf _snprintf -+#define vsnprintf _vsnprintf -+ -+#ifdef _MSC_VER /* MSVS.Net */ -+#ifndef __cplusplus -+#define inline __inline -+#endif -+#define ssize_t SSIZE_T -+typedef char int8_t; -+typedef short int16_t; -+typedef int int32_t; -+typedef unsigned char uint8_t; -+typedef unsigned short uint16_t; -+typedef unsigned int uint32_t; -+#define WIN32_LEAN_AND_MEAN -+#include -+#include -+#define isnan _isnan -+#define finite _finite -+#define copysign _copysign -+#define ilogb _logb -+#endif /* _MSC_VER */ -+ -+#else /* !WIN32 */ -+ -+#if defined(__vxworks) -+#include -+#else /* !defined(__vxworks) */ -+ -+#include /* C99 specifies this file */ -+/* -+ * 1. Earlier FreeBSD version didn't have , -+ * but was present. -+ * 2. Sun Solaris requires for alloca(3), -+ * but does not have . -+ */ -+#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) -+#if defined(sun) -+#include /* For alloca(3) */ -+#include /* for finite(3) */ -+#elif defined(__hpux) -+#ifdef __GNUC__ -+#include /* For alloca(3) */ -+#else /* !__GNUC__ */ -+#define inline -+#endif /* __GNUC__ */ -+#else -+#include /* SUSv2+ and C99 specify this file, for uintXX_t */ -+#endif /* defined(sun) */ -+#endif -+ -+#endif /* defined(__vxworks) */ -+ -+#endif /* WIN32 */ -+ -+#if __GNUC__ >= 3 -+#ifndef GCC_PRINTFLIKE -+#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) -+#endif -+#else -+#ifndef GCC_PRINTFLIKE -+#define GCC_PRINTFLIKE(fmt,var) /* nothing */ -+#endif -+#endif -+ -+#ifndef offsetof /* If not defined by */ -+#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) -+#endif /* offsetof */ -+ -+#ifndef MIN /* Suitable for comparing primitive types (integers) */ -+#if defined(__GNUC__) -+#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ -+ ((_a)<(_b)?(_a):(_b)); }) -+#else /* !__GNUC__ */ -+#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ -+#endif /* __GNUC__ */ -+#endif /* MIN */ -+ -+#endif /* _ASN_SYSTEM_H_ */ -diff --git a/asn1/asn1c/ber_decoder.c b/asn1/asn1c/ber_decoder.c -new file mode 100644 -index 0000000000000000000000000000000000000000..601f66c0b0274b74dcb56e7eca469ded9b076b2c ---- /dev/null -+++ b/asn1/asn1c/ber_decoder.c -@@ -0,0 +1,283 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+ -+#undef ADVANCE -+#define ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ ptr = ((const char *)ptr) + num; \ -+ size -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+#undef RETURN -+#define RETURN(_code) do { \ -+ asn_dec_rval_t rval; \ -+ rval.code = _code; \ -+ if(opt_ctx) opt_ctx->step = step; /* Save context */ \ -+ if(_code == RC_OK || opt_ctx) \ -+ rval.consumed = consumed_myself; \ -+ else \ -+ rval.consumed = 0; /* Context-free */ \ -+ return rval; \ -+ } while(0) -+ -+/* -+ * The BER decoder of any type. -+ */ -+asn_dec_rval_t -+ber_decode(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *type_descriptor, -+ void **struct_ptr, const void *ptr, size_t size) { -+ asn_codec_ctx_t s_codec_ctx; -+ -+ /* -+ * Stack checker requires that the codec context -+ * must be allocated on the stack. -+ */ -+ if(opt_codec_ctx) { -+ if(opt_codec_ctx->max_stack_size) { -+ s_codec_ctx = *opt_codec_ctx; -+ opt_codec_ctx = &s_codec_ctx; -+ } -+ } else { -+ /* If context is not given, be security-conscious anyway */ -+ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); -+ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; -+ opt_codec_ctx = &s_codec_ctx; -+ } -+ -+ /* -+ * Invoke type-specific decoder. -+ */ -+ return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor, -+ struct_ptr, /* Pointer to the destination structure */ -+ ptr, size, /* Buffer and its size */ -+ 0 /* Default tag mode is 0 */ -+ ); -+} -+ -+/* -+ * Check the set of >> tags matches the definition. -+ */ -+asn_dec_rval_t -+ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, -+ asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, -+ const void *ptr, size_t size, int tag_mode, int last_tag_form, -+ ber_tlv_len_t *last_length, int *opt_tlv_form) { -+ ssize_t consumed_myself = 0; -+ ssize_t tag_len; -+ ssize_t len_len; -+ ber_tlv_tag_t tlv_tag; -+ ber_tlv_len_t tlv_len; -+ ber_tlv_len_t limit_len = -1; -+ int expect_00_terminators = 0; -+ int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ -+ int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ -+ int tagno; -+ -+ /* -+ * Make sure we didn't exceed the maximum stack size. -+ */ -+ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) -+ RETURN(RC_FAIL); -+ -+ /* -+ * So what does all this implicit skip stuff mean? -+ * Imagine two types, -+ * A ::= [5] IMPLICIT T -+ * B ::= [2] EXPLICIT T -+ * Where T is defined as -+ * T ::= [4] IMPLICIT SEQUENCE { ... } -+ * -+ * Let's say, we are starting to decode type A, given the -+ * following TLV stream: <5> <0>. What does this mean? -+ * It means that the type A contains type T which is, -+ * in turn, empty. -+ * Remember though, that we are still in A. We cannot -+ * just pass control to the type T decoder. Why? Because -+ * the type T decoder expects <4> <0>, not <5> <0>. -+ * So, we must make sure we are going to receive <5> while -+ * still in A, then pass control to the T decoder, indicating -+ * that the tag <4> was implicitly skipped. The decoder of T -+ * hence will be prepared to treat <4> as valid tag, and decode -+ * it appropriately. -+ */ -+ -+ tagno = step /* Continuing where left previously */ -+ + (tag_mode==1?-1:0) -+ ; -+ ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)", -+ td->name, (long)size, tag_mode, step, tagno); -+ /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ -+ -+ if(tag_mode == 0 && tagno == td->tags_count) { -+ /* -+ * This must be the _untagged_ ANY type, -+ * which outermost tag isn't known in advance. -+ * Fetch the tag and length separately. -+ */ -+ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); -+ switch(tag_len) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ } -+ tlv_constr = BER_TLV_CONSTRUCTED(ptr); -+ len_len = ber_fetch_length(tlv_constr, -+ (const char *)ptr + tag_len, size - tag_len, &tlv_len); -+ switch(len_len) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ } -+ ASN_DEBUG("Advancing %ld in ANY case", -+ (long)(tag_len + len_len)); -+ ADVANCE(tag_len + len_len); -+ } else { -+ assert(tagno < td->tags_count); /* At least one loop */ -+ } -+ for((void)tagno; tagno < td->tags_count; tagno++, step++) { -+ -+ /* -+ * Fetch and process T from TLV. -+ */ -+ tag_len = ber_fetch_tag(ptr, size, &tlv_tag); -+ ASN_DEBUG("Fetching tag from {%p,%ld}: " -+ "len %ld, step %d, tagno %d got %s", -+ ptr, (long)size, -+ (long)tag_len, step, tagno, -+ ber_tlv_tag_string(tlv_tag)); -+ switch(tag_len) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ } -+ -+ tlv_constr = BER_TLV_CONSTRUCTED(ptr); -+ -+ /* -+ * If {I}, don't check anything. -+ * If {I,B,C}, check B and C unless we're at I. -+ */ -+ if(tag_mode != 0 && step == 0) { -+ /* -+ * We don't expect tag to match here. -+ * It's just because we don't know how the tag -+ * is supposed to look like. -+ */ -+ } else { -+ assert(tagno >= 0); /* Guaranteed by the code above */ -+ if(tlv_tag != td->tags[tagno]) { -+ /* -+ * Unexpected tag. Too bad. -+ */ -+ ASN_DEBUG("Expected: %s, " -+ "expectation failed (tn=%d, tm=%d)", -+ ber_tlv_tag_string(td->tags[tagno]), -+ tagno, tag_mode -+ ); -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * Attention: if there are more tags expected, -+ * ensure that the current tag is presented -+ * in constructed form (it contains other tags!). -+ * If this one is the last one, check that the tag form -+ * matches the one given in descriptor. -+ */ -+ if(tagno < (td->tags_count - 1)) { -+ if(tlv_constr == 0) { -+ ASN_DEBUG("tlv_constr = %d, expfail", -+ tlv_constr); -+ RETURN(RC_FAIL); -+ } -+ } else { -+ if(last_tag_form != tlv_constr -+ && last_tag_form != -1) { -+ ASN_DEBUG("last_tag_form %d != %d", -+ last_tag_form, tlv_constr); -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * Fetch and process L from TLV. -+ */ -+ len_len = ber_fetch_length(tlv_constr, -+ (const char *)ptr + tag_len, size - tag_len, &tlv_len); -+ ASN_DEBUG("Fetchinig len = %ld", (long)len_len); -+ switch(len_len) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ } -+ -+ /* -+ * FIXME -+ * As of today, the chain of tags -+ * must either contain several indefinite length TLVs, -+ * or several definite length ones. -+ * No mixing is allowed. -+ */ -+ if(tlv_len == -1) { -+ /* -+ * Indefinite length. -+ */ -+ if(limit_len == -1) { -+ expect_00_terminators++; -+ } else { -+ ASN_DEBUG("Unexpected indefinite length " -+ "in a chain of definite lengths"); -+ RETURN(RC_FAIL); -+ } -+ ADVANCE(tag_len + len_len); -+ continue; -+ } else { -+ if(expect_00_terminators) { -+ ASN_DEBUG("Unexpected definite length " -+ "in a chain of indefinite lengths"); -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * Check that multiple TLVs specify ever decreasing length, -+ * which is consistent. -+ */ -+ if(limit_len == -1) { -+ limit_len = tlv_len + tag_len + len_len; -+ if(limit_len < 0) { -+ /* Too great tlv_len value? */ -+ RETURN(RC_FAIL); -+ } -+ } else if(limit_len != tlv_len + tag_len + len_len) { -+ /* -+ * Inner TLV specifies length which is inconsistent -+ * with the outer TLV's length value. -+ */ -+ ASN_DEBUG("Outer TLV is %ld and inner is %ld", -+ (long)limit_len, (long)tlv_len); -+ RETURN(RC_FAIL); -+ } -+ -+ ADVANCE(tag_len + len_len); -+ -+ limit_len -= (tag_len + len_len); -+ if((ssize_t)size > limit_len) { -+ /* -+ * Make sure that we won't consume more bytes -+ * from the parent frame than the inferred limit. -+ */ -+ size = limit_len; -+ } -+ } -+ -+ if(opt_tlv_form) -+ *opt_tlv_form = tlv_constr; -+ if(expect_00_terminators) -+ *last_length = -expect_00_terminators; -+ else -+ *last_length = tlv_len; -+ -+ RETURN(RC_OK); -+} -diff --git a/asn1/asn1c/ber_decoder.h b/asn1/asn1c/ber_decoder.h -new file mode 100644 -index 0000000000000000000000000000000000000000..768133b67e75b4eb18e523e1943245e17ce9b3aa ---- /dev/null -+++ b/asn1/asn1c/ber_decoder.h -@@ -0,0 +1,63 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _BER_DECODER_H_ -+#define _BER_DECODER_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+struct asn_codec_ctx_s; /* Forward declaration */ -+ -+/* -+ * The BER decoder of any type. -+ * This function may be invoked directly from the application. -+ */ -+asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void **struct_ptr, /* Pointer to a target structure's pointer */ -+ const void *buffer, /* Data to be decoded */ -+ size_t size /* Size of that buffer */ -+ ); -+ -+/* -+ * Type of generic function which decodes the byte stream into the structure. -+ */ -+typedef asn_dec_rval_t (ber_type_decoder_f)( -+ struct asn_codec_ctx_s *opt_codec_ctx, -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void **struct_ptr, const void *buf_ptr, size_t size, -+ int tag_mode); -+ -+/******************************* -+ * INTERNALLY USEFUL FUNCTIONS * -+ *******************************/ -+ -+/* -+ * Check that all tags correspond to the type definition (as given in head). -+ * On return, last_length would contain either a non-negative length of the -+ * value part of the last TLV, or the negative number of expected -+ * "end of content" sequences. The number may only be negative if the -+ * head->last_tag_form is non-zero. -+ */ -+asn_dec_rval_t ber_check_tags( -+ struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ asn_struct_ctx_t *opt_ctx, /* saved decoding context */ -+ const void *ptr, size_t size, -+ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ -+ int last_tag_form, /* {-1,0:1}: any, primitive, constr */ -+ ber_tlv_len_t *last_length, -+ int *opt_tlv_form /* optional tag form */ -+ ); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _BER_DECODER_H_ */ -diff --git a/asn1/asn1c/ber_tlv_length.c b/asn1/asn1c/ber_tlv_length.c -new file mode 100644 -index 0000000000000000000000000000000000000000..b87e75e0469887ee7d06bfb5f83b99b8120a5374 ---- /dev/null -+++ b/asn1/asn1c/ber_tlv_length.c -@@ -0,0 +1,178 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+ssize_t -+ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, -+ ber_tlv_len_t *len_r) { -+ const uint8_t *buf = (const uint8_t *)bufptr; -+ unsigned oct; -+ -+ if(size == 0) -+ return 0; /* Want more */ -+ -+ oct = *(const uint8_t *)buf; -+ if((oct & 0x80) == 0) { -+ /* -+ * Short definite length. -+ */ -+ *len_r = oct; /* & 0x7F */ -+ return 1; -+ } else { -+ ber_tlv_len_t len; -+ size_t skipped; -+ -+ if(_is_constructed && oct == 0x80) { -+ *len_r = -1; /* Indefinite length */ -+ return 1; -+ } -+ -+ if(oct == 0xff) { -+ /* Reserved in standard for future use. */ -+ return -1; -+ } -+ -+ oct &= 0x7F; /* Leave only the 7 LS bits */ -+ for(len = 0, buf++, skipped = 1; -+ oct && (++skipped <= size); buf++, oct--) { -+ -+ len = (len << 8) | *buf; -+ if(len < 0 -+ || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) { -+ /* -+ * Too large length value. -+ */ -+ return -1; -+ } -+ } -+ -+ if(oct == 0) { -+ ber_tlv_len_t lenplusepsilon = (size_t)len + 1024; -+ /* -+ * Here length may be very close or equal to 2G. -+ * However, the arithmetics used in some decoders -+ * may add some (small) quantities to the length, -+ * to check the resulting value against some limits. -+ * This may result in integer wrap-around, which -+ * we try to avoid by checking it earlier here. -+ */ -+ if(lenplusepsilon < 0) { -+ /* Too large length value */ -+ return -1; -+ } -+ -+ *len_r = len; -+ return skipped; -+ } -+ -+ return 0; /* Want more */ -+ } -+ -+} -+ -+ssize_t -+ber_skip_length(asn_codec_ctx_t *opt_codec_ctx, -+ int _is_constructed, const void *ptr, size_t size) { -+ ber_tlv_len_t vlen; /* Length of V in TLV */ -+ ssize_t tl; /* Length of L in TLV */ -+ ssize_t ll; /* Length of L in TLV */ -+ size_t skip; -+ -+ /* -+ * Make sure we didn't exceed the maximum stack size. -+ */ -+ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) -+ return -1; -+ -+ /* -+ * Determine the size of L in TLV. -+ */ -+ ll = ber_fetch_length(_is_constructed, ptr, size, &vlen); -+ if(ll <= 0) return ll; -+ -+ /* -+ * Definite length. -+ */ -+ if(vlen >= 0) { -+ skip = ll + vlen; -+ if(skip > size) -+ return 0; /* Want more */ -+ return skip; -+ } -+ -+ /* -+ * Indefinite length! -+ */ -+ ASN_DEBUG("Skipping indefinite length"); -+ for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) { -+ ber_tlv_tag_t tag; -+ -+ /* Fetch the tag */ -+ tl = ber_fetch_tag(ptr, size, &tag); -+ if(tl <= 0) return tl; -+ -+ ll = ber_skip_length(opt_codec_ctx, -+ BER_TLV_CONSTRUCTED(ptr), -+ ((const char *)ptr) + tl, size - tl); -+ if(ll <= 0) return ll; -+ -+ skip += tl + ll; -+ -+ /* -+ * This may be the end of the indefinite length structure, -+ * two consecutive 0 octets. -+ * Check if it is true. -+ */ -+ if(((const uint8_t *)ptr)[0] == 0 -+ && ((const uint8_t *)ptr)[1] == 0) -+ return skip; -+ -+ ptr = ((const char *)ptr) + tl + ll; -+ size -= tl + ll; -+ } -+ -+ /* UNREACHABLE */ -+} -+ -+size_t -+der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) { -+ size_t required_size; /* Size of len encoding */ -+ uint8_t *buf = (uint8_t *)bufp; -+ uint8_t *end; -+ size_t i; -+ -+ if(len <= 127) { -+ /* Encoded in 1 octet */ -+ if(size) *buf = (uint8_t)len; -+ return 1; -+ } -+ -+ /* -+ * Compute the size of the subsequent bytes. -+ */ -+ for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) { -+ if(len >> i) -+ required_size++; -+ else -+ break; -+ } -+ -+ if(size <= required_size) -+ return required_size + 1; -+ -+ *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */ -+ -+ /* -+ * Produce the len encoding, space permitting. -+ */ -+ end = buf + required_size; -+ for(i -= 8; buf < end; i -= 8, buf++) -+ *buf = (uint8_t)(len >> i); -+ -+ return required_size + 1; -+} -+ -diff --git a/asn1/asn1c/ber_tlv_length.h b/asn1/asn1c/ber_tlv_length.h -new file mode 100644 -index 0000000000000000000000000000000000000000..3496802244013c6c3652d5d067bccdf022e719cf ---- /dev/null -+++ b/asn1/asn1c/ber_tlv_length.h -@@ -0,0 +1,50 @@ -+/*- -+ * Copyright (c) 2003 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _BER_TLV_LENGTH_H_ -+#define _BER_TLV_LENGTH_H_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef ssize_t ber_tlv_len_t; -+ -+/* -+ * This function tries to fetch the length of the BER TLV value and place it -+ * in *len_r. -+ * RETURN VALUES: -+ * 0: More data expected than bufptr contains. -+ * -1: Fatal error deciphering length. -+ * >0: Number of bytes used from bufptr. -+ * On return with >0, len_r is constrained as -1..MAX, where -1 mean -+ * that the value is of indefinite length. -+ */ -+ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, -+ ber_tlv_len_t *len_r); -+ -+/* -+ * This function expects bufptr to be positioned over L in TLV. -+ * It returns number of bytes occupied by L and V together, suitable -+ * for skipping. The function properly handles indefinite length. -+ * RETURN VALUES: -+ * Standard {-1,0,>0} convention. -+ */ -+ssize_t ber_skip_length( -+ struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ -+ int _is_constructed, const void *bufptr, size_t size); -+ -+/* -+ * This function serializes the length (L from TLV) in DER format. -+ * It always returns number of bytes necessary to represent the length, -+ * it is a caller's responsibility to check the return value -+ * against the supplied buffer's size. -+ */ -+size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _BER_TLV_LENGTH_H_ */ -diff --git a/asn1/asn1c/ber_tlv_tag.c b/asn1/asn1c/ber_tlv_tag.c -new file mode 100644 -index 0000000000000000000000000000000000000000..42708760e089948b405743678efbc56ddd836c87 ---- /dev/null -+++ b/asn1/asn1c/ber_tlv_tag.c -@@ -0,0 +1,144 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+ssize_t -+ber_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { -+ ber_tlv_tag_t val; -+ ber_tlv_tag_t tclass; -+ size_t skipped; -+ -+ if(size == 0) -+ return 0; -+ -+ val = *(const uint8_t *)ptr; -+ tclass = (val >> 6); -+ if((val &= 0x1F) != 0x1F) { -+ /* -+ * Simple form: everything encoded in a single octet. -+ * Tag Class is encoded using two least significant bits. -+ */ -+ *tag_r = (val << 2) | tclass; -+ return 1; -+ } -+ -+ /* -+ * Each octet contains 7 bits of useful information. -+ * The MSB is 0 if it is the last octet of the tag. -+ */ -+ for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; -+ skipped <= size; -+ ptr = ((const char *)ptr) + 1, skipped++) { -+ unsigned int oct = *(const uint8_t *)ptr; -+ if(oct & 0x80) { -+ val = (val << 7) | (oct & 0x7F); -+ /* -+ * Make sure there are at least 9 bits spare -+ * at the MS side of a value. -+ */ -+ if(val >> ((8 * sizeof(val)) - 9)) { -+ /* -+ * We would not be able to accomodate -+ * any more tag bits. -+ */ -+ return -1; -+ } -+ } else { -+ val = (val << 7) | oct; -+ *tag_r = (val << 2) | tclass; -+ return skipped; -+ } -+ } -+ -+ return 0; /* Want more */ -+} -+ -+ -+ssize_t -+ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) { -+ char buf[sizeof("[APPLICATION ]") + 32]; -+ ssize_t ret; -+ -+ ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf)); -+ if(ret >= (ssize_t)sizeof(buf) || ret < 2) { -+ errno = EPERM; -+ return -1; -+ } -+ -+ return fwrite(buf, 1, ret, f); -+} -+ -+ssize_t -+ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) { -+ char *type = 0; -+ int ret; -+ -+ switch(tag & 0x3) { -+ case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break; -+ case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break; -+ case ASN_TAG_CLASS_CONTEXT: type = ""; break; -+ case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break; -+ } -+ -+ ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2); -+ if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */ -+ -+ return ret; -+} -+ -+char * -+ber_tlv_tag_string(ber_tlv_tag_t tag) { -+ static char buf[sizeof("[APPLICATION ]") + 32]; -+ -+ (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf)); -+ -+ return buf; -+} -+ -+ -+size_t -+ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) { -+ int tclass = BER_TAG_CLASS(tag); -+ ber_tlv_tag_t tval = BER_TAG_VALUE(tag); -+ uint8_t *buf = (uint8_t *)bufp; -+ uint8_t *end; -+ size_t required_size; -+ size_t i; -+ -+ if(tval <= 30) { -+ /* Encoded in 1 octet */ -+ if(size) buf[0] = (tclass << 6) | tval; -+ return 1; -+ } else if(size) { -+ *buf++ = (tclass << 6) | 0x1F; -+ size--; -+ } -+ -+ /* -+ * Compute the size of the subsequent bytes. -+ */ -+ for(required_size = 1, i = 7; i < 8 * sizeof(tval); i += 7) { -+ if(tval >> i) -+ required_size++; -+ else -+ break; -+ } -+ -+ if(size < required_size) -+ return required_size + 1; -+ -+ /* -+ * Fill in the buffer, space permitting. -+ */ -+ end = buf + required_size - 1; -+ for(i -= 7; buf < end; i -= 7, buf++) -+ *buf = 0x80 | ((tval >> i) & 0x7F); -+ *buf = (tval & 0x7F); /* Last octet without high bit */ -+ -+ return required_size + 1; -+} -+ -diff --git a/asn1/asn1c/ber_tlv_tag.h b/asn1/asn1c/ber_tlv_tag.h -new file mode 100644 -index 0000000000000000000000000000000000000000..60e866861b28b3861f1e482452dcde1c844e5253 ---- /dev/null -+++ b/asn1/asn1c/ber_tlv_tag.h -@@ -0,0 +1,60 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _BER_TLV_TAG_H_ -+#define _BER_TLV_TAG_H_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+enum asn_tag_class { -+ ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ -+ ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ -+ ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ -+ ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ -+}; -+typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ -+ -+/* -+ * Tag class is encoded together with tag value for optimization purposes. -+ */ -+#define BER_TAG_CLASS(tag) ((tag) & 0x3) -+#define BER_TAG_VALUE(tag) ((tag) >> 2) -+#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) -+ -+#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) -+ -+/* -+ * Several functions for printing the TAG in the canonical form -+ * (i.e. "[PRIVATE 0]"). -+ * Return values correspond to their libc counterparts (if any). -+ */ -+ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); -+ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); -+char *ber_tlv_tag_string(ber_tlv_tag_t tag); -+ -+ -+/* -+ * This function tries to fetch the tag from the input stream. -+ * RETURN VALUES: -+ * 0: More data expected than bufptr contains. -+ * -1: Fatal error deciphering tag. -+ * >0: Number of bytes used from bufptr. tag_r will contain the tag. -+ */ -+ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); -+ -+/* -+ * This function serializes the tag (T from TLV) in BER format. -+ * It always returns number of bytes necessary to represent the tag, -+ * it is a caller's responsibility to check the return value -+ * against the supplied buffer's size. -+ */ -+size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _BER_TLV_TAG_H_ */ -diff --git a/asn1/asn1c/constr_CHOICE.c b/asn1/asn1c/constr_CHOICE.c -new file mode 100644 -index 0000000000000000000000000000000000000000..b8d6fa9a7f210585e851f8f1ab3cadf1d8fe4923 ---- /dev/null -+++ b/asn1/asn1c/constr_CHOICE.c -@@ -0,0 +1,1101 @@ -+/* -+ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+ -+/* -+ * Number of bytes left for this structure. -+ * (ctx->left) indicates the number of bytes _transferred_ for the structure. -+ * (size) contains the number of bytes in the buffer passed. -+ */ -+#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) -+ -+/* -+ * If the subprocessor function returns with an indication that it wants -+ * more data, it may well be a fatal decoding problem, because the -+ * size is constrained by the 's L, even if the buffer size allows -+ * reading more data. -+ * For example, consider the buffer containing the following TLVs: -+ * ... -+ * The TLV length clearly indicates that one byte is expected in V, but -+ * if the V processor returns with "want more data" even if the buffer -+ * contains way more data than the V processor have seen. -+ */ -+#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) -+ -+/* -+ * This macro "eats" the part of the buffer which is definitely "consumed", -+ * i.e. was correctly converted into local representation or rightfully skipped. -+ */ -+#undef ADVANCE -+#define ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ ptr = ((const char *)ptr) + num;\ -+ size -= num; \ -+ if(ctx->left >= 0) \ -+ ctx->left -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+/* -+ * Switch to the next phase of parsing. -+ */ -+#undef NEXT_PHASE -+#define NEXT_PHASE(ctx) do { \ -+ ctx->phase++; \ -+ ctx->step = 0; \ -+ } while(0) -+ -+/* -+ * Return a standardized complex structure. -+ */ -+#undef RETURN -+#define RETURN(_code) do { \ -+ rval.code = _code; \ -+ rval.consumed = consumed_myself;\ -+ return rval; \ -+ } while(0) -+ -+/* -+ * See the definitions. -+ */ -+static int _fetch_present_idx(const void *struct_ptr, int off, int size); -+static void _set_present_idx(void *sptr, int offset, int size, int pres); -+ -+/* -+ * Tags are canonically sorted in the tag to member table. -+ */ -+static int -+_search4tag(const void *ap, const void *bp) { -+ const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; -+ const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; -+ -+ int a_class = BER_TAG_CLASS(a->el_tag); -+ int b_class = BER_TAG_CLASS(b->el_tag); -+ -+ if(a_class == b_class) { -+ ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); -+ ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); -+ -+ if(a_value == b_value) -+ return 0; -+ else if(a_value < b_value) -+ return -1; -+ else -+ return 1; -+ } else if(a_class < b_class) { -+ return -1; -+ } else { -+ return 1; -+ } -+} -+ -+/* -+ * The decoder of the CHOICE type. -+ */ -+asn_dec_rval_t -+CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const void *ptr, size_t size, int tag_mode) { -+ /* -+ * Bring closer parts of structure description. -+ */ -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elements = td->elements; -+ -+ /* -+ * Parts of the structure being constructed. -+ */ -+ void *st = *struct_ptr; /* Target structure. */ -+ asn_struct_ctx_t *ctx; /* Decoder context */ -+ -+ ber_tlv_tag_t tlv_tag; /* T from TLV */ -+ ssize_t tag_len; /* Length of TLV's T */ -+ asn_dec_rval_t rval; /* Return code from subparsers */ -+ -+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ -+ -+ ASN_DEBUG("Decoding %s as CHOICE", td->name); -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(st == 0) { -+ st = *struct_ptr = CALLOC(1, specs->struct_size); -+ if(st == 0) { -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * Restore parsing context. -+ */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ -+ /* -+ * Start to parse where left previously -+ */ -+ switch(ctx->phase) { -+ case 0: -+ /* -+ * PHASE 0. -+ * Check that the set of tags associated with given structure -+ * perfectly fits our expectations. -+ */ -+ -+ if(tag_mode || td->tags_count) { -+ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, -+ tag_mode, -1, &ctx->left, 0); -+ if(rval.code != RC_OK) { -+ ASN_DEBUG("%s tagging check failed: %d", -+ td->name, rval.code); -+ return rval; -+ } -+ -+ if(ctx->left >= 0) { -+ /* ?Substracted below! */ -+ ctx->left += rval.consumed; -+ } -+ ADVANCE(rval.consumed); -+ } else { -+ ctx->left = -1; -+ } -+ -+ NEXT_PHASE(ctx); -+ -+ ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", -+ (long)ctx->left, (long)size); -+ -+ /* Fall through */ -+ case 1: -+ /* -+ * Fetch the T from TLV. -+ */ -+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); -+ ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len); -+ switch(tag_len) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ do { -+ asn_TYPE_tag2member_t *t2m; -+ asn_TYPE_tag2member_t key; -+ -+ key.el_tag = tlv_tag; -+ t2m = (asn_TYPE_tag2member_t *)bsearch(&key, -+ specs->tag2el, specs->tag2el_count, -+ sizeof(specs->tag2el[0]), _search4tag); -+ if(t2m) { -+ /* -+ * Found the element corresponding to the tag. -+ */ -+ NEXT_PHASE(ctx); -+ ctx->step = t2m->el_no; -+ break; -+ } else if(specs->ext_start == -1) { -+ ASN_DEBUG("Unexpected tag %s " -+ "in non-extensible CHOICE %s", -+ ber_tlv_tag_string(tlv_tag), td->name); -+ RETURN(RC_FAIL); -+ } else { -+ /* Skip this tag */ -+ ssize_t skip; -+ -+ ASN_DEBUG("Skipping unknown tag %s", -+ ber_tlv_tag_string(tlv_tag)); -+ -+ skip = ber_skip_length(opt_codec_ctx, -+ BER_TLV_CONSTRUCTED(ptr), -+ (const char *)ptr + tag_len, -+ LEFT - tag_len); -+ -+ switch(skip) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ ADVANCE(skip + tag_len); -+ RETURN(RC_OK); -+ } -+ } while(0); -+ -+ case 2: -+ /* -+ * PHASE 2. -+ * Read in the element. -+ */ -+ do { -+ asn_TYPE_member_t *elm;/* CHOICE's element */ -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ -+ elm = &elements[ctx->step]; -+ -+ /* -+ * Compute the position of the member inside a structure, -+ * and also a type of containment (it may be contained -+ * as pointer or using inline inclusion). -+ */ -+ if(elm->flags & ATF_POINTER) { -+ /* Member is a pointer to another structure */ -+ memb_ptr2 = (void **)((char *)st + elm->memb_offset); -+ } else { -+ /* -+ * A pointer to a pointer -+ * holding the start of the structure -+ */ -+ memb_ptr = (char *)st + elm->memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ /* Set presence to be able to free it properly at any time */ -+ _set_present_idx(st, specs->pres_offset, -+ specs->pres_size, ctx->step + 1); -+ /* -+ * Invoke the member fetch routine according to member's type -+ */ -+ rval = elm->type->ber_decoder(opt_codec_ctx, elm->type, -+ memb_ptr2, ptr, LEFT, elm->tag_mode); -+ switch(rval.code) { -+ case RC_OK: -+ break; -+ case RC_WMORE: /* More data expected */ -+ if(!SIZE_VIOLATION) { -+ ADVANCE(rval.consumed); -+ RETURN(RC_WMORE); -+ } -+ RETURN(RC_FAIL); -+ case RC_FAIL: /* Fatal error */ -+ RETURN(rval.code); -+ } /* switch(rval) */ -+ -+ ADVANCE(rval.consumed); -+ } while(0); -+ -+ NEXT_PHASE(ctx); -+ -+ /* Fall through */ -+ case 3: -+ ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d", -+ td->name, (long)ctx->left, (long)size, -+ tag_mode, td->tags_count); -+ -+ if(ctx->left > 0) { -+ /* -+ * The type must be fully decoded -+ * by the CHOICE member-specific decoder. -+ */ -+ RETURN(RC_FAIL); -+ } -+ -+ if(ctx->left == -1 -+ && !(tag_mode || td->tags_count)) { -+ /* -+ * This is an untagged CHOICE. -+ * It doesn't contain nothing -+ * except for the member itself, including all its tags. -+ * The decoding is completed. -+ */ -+ NEXT_PHASE(ctx); -+ break; -+ } -+ -+ /* -+ * Read in the "end of data chunks"'s. -+ */ -+ while(ctx->left < 0) { -+ ssize_t tl; -+ -+ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); -+ switch(tl) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ /* -+ * Expected <0><0>... -+ */ -+ if(((const uint8_t *)ptr)[0] == 0) { -+ if(LEFT < 2) { -+ if(SIZE_VIOLATION) -+ RETURN(RC_FAIL); -+ else -+ RETURN(RC_WMORE); -+ } else if(((const uint8_t *)ptr)[1] == 0) { -+ /* -+ * Correctly finished with <0><0>. -+ */ -+ ADVANCE(2); -+ ctx->left++; -+ continue; -+ } -+ } else { -+ ASN_DEBUG("Unexpected continuation in %s", -+ td->name); -+ RETURN(RC_FAIL); -+ } -+ -+ /* UNREACHABLE */ -+ } -+ -+ NEXT_PHASE(ctx); -+ case 4: -+ /* No meaningful work here */ -+ break; -+ } -+ -+ RETURN(RC_OK); -+} -+ -+asn_enc_rval_t -+CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elm; /* CHOICE element */ -+ asn_enc_rval_t erval; -+ void *memb_ptr; -+ size_t computed_size = 0; -+ int present; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ -+ ASN_DEBUG("%s %s as CHOICE", -+ cb?"Encoding":"Estimating", td->name); -+ -+ present = _fetch_present_idx(sptr, -+ specs->pres_offset, specs->pres_size); -+ -+ /* -+ * If the structure was not initialized, it cannot be encoded: -+ * can't deduce what to encode in the choice type. -+ */ -+ if(present <= 0 || present > td->elements_count) { -+ if(present == 0 && td->elements_count == 0) { -+ /* The CHOICE is empty?! */ -+ erval.encoded = 0; -+ _ASN_ENCODED_OK(erval); -+ } -+ _ASN_ENCODE_FAILED; -+ } -+ -+ /* -+ * Seek over the present member of the structure. -+ */ -+ elm = &td->elements[present-1]; -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(memb_ptr == 0) { -+ if(elm->optional) { -+ erval.encoded = 0; -+ _ASN_ENCODED_OK(erval); -+ } -+ /* Mandatory element absent */ -+ _ASN_ENCODE_FAILED; -+ } -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ } -+ -+ /* -+ * If the CHOICE itself is tagged EXPLICIT: -+ * T ::= [2] EXPLICIT CHOICE { ... } -+ * Then emit the appropriate tags. -+ */ -+ if(tag_mode == 1 || td->tags_count) { -+ /* -+ * For this, we need to pre-compute the member. -+ */ -+ ssize_t ret; -+ -+ /* Encode member with its tag */ -+ erval = elm->type->der_encoder(elm->type, memb_ptr, -+ elm->tag_mode, elm->tag, 0, 0); -+ if(erval.encoded == -1) -+ return erval; -+ -+ /* Encode CHOICE with parent or my own tag */ -+ ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag, -+ cb, app_key); -+ if(ret == -1) -+ _ASN_ENCODE_FAILED; -+ computed_size += ret; -+ } -+ -+ /* -+ * Encode the single underlying member. -+ */ -+ erval = elm->type->der_encoder(elm->type, memb_ptr, -+ elm->tag_mode, elm->tag, cb, app_key); -+ if(erval.encoded == -1) -+ return erval; -+ -+ ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)", -+ (long)erval.encoded, (long)computed_size); -+ -+ erval.encoded += computed_size; -+ -+ return erval; -+} -+ -+ber_tlv_tag_t -+CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ int present; -+ -+ assert(tag_mode == 0); (void)tag_mode; -+ assert(tag == 0); (void)tag; -+ -+ /* -+ * Figure out which CHOICE element is encoded. -+ */ -+ present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); -+ -+ if(present > 0 || present <= td->elements_count) { -+ asn_TYPE_member_t *elm = &td->elements[present-1]; -+ const void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(const void * const *) -+ ((const char *)ptr + elm->memb_offset); -+ } else { -+ memb_ptr = (const void *) -+ ((const char *)ptr + elm->memb_offset); -+ } -+ -+ return asn_TYPE_outmost_tag(elm->type, memb_ptr, -+ elm->tag_mode, elm->tag); -+ } else { -+ return (ber_tlv_tag_t)-1; -+ } -+} -+ -+int -+CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, -+ asn_app_constraint_failed_f *ctfailcb, void *app_key) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ int present; -+ -+ if(!sptr) { -+ _ASN_CTFAIL(app_key, td, -+ "%s: value not given (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+ -+ /* -+ * Figure out which CHOICE element is encoded. -+ */ -+ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); -+ if(present > 0 && present <= td->elements_count) { -+ asn_TYPE_member_t *elm = &td->elements[present-1]; -+ const void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); -+ if(!memb_ptr) { -+ if(elm->optional) -+ return 0; -+ _ASN_CTFAIL(app_key, td, -+ "%s: mandatory CHOICE element %s absent (%s:%d)", -+ td->name, elm->name, __FILE__, __LINE__); -+ return -1; -+ } -+ } else { -+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); -+ } -+ -+ if(elm->memb_constraints) { -+ return elm->memb_constraints(elm->type, memb_ptr, -+ ctfailcb, app_key); -+ } else { -+ int ret = elm->type->check_constraints(elm->type, -+ memb_ptr, ctfailcb, app_key); -+ /* -+ * Cannot inherit it eralier: -+ * need to make sure we get the updated version. -+ */ -+ elm->memb_constraints = elm->type->check_constraints; -+ return ret; -+ } -+ } else { -+ _ASN_CTFAIL(app_key, td, -+ "%s: no CHOICE element given (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+} -+ -+#undef XER_ADVANCE -+#define XER_ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ buf_ptr = ((const char *)buf_ptr) + num;\ -+ size -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+/* -+ * Decode the XER (XML) data. -+ */ -+asn_dec_rval_t -+CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const char *opt_mname, -+ const void *buf_ptr, size_t size) { -+ /* -+ * Bring closer parts of structure description. -+ */ -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; -+ -+ /* -+ * Parts of the structure being constructed. -+ */ -+ void *st = *struct_ptr; /* Target structure. */ -+ asn_struct_ctx_t *ctx; /* Decoder context */ -+ -+ asn_dec_rval_t rval; /* Return value of a decoder */ -+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ -+ int edx; /* Element index */ -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(st == 0) { -+ st = *struct_ptr = CALLOC(1, specs->struct_size); -+ if(st == 0) RETURN(RC_FAIL); -+ } -+ -+ /* -+ * Restore parsing context. -+ */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ if(ctx->phase == 0 && !*xml_tag) -+ ctx->phase = 1; /* Skip the outer tag checking phase */ -+ -+ /* -+ * Phases of XER/XML processing: -+ * Phase 0: Check that the opening tag matches our expectations. -+ * Phase 1: Processing body and reacting on closing tag. -+ * Phase 2: Processing inner type. -+ * Phase 3: Only waiting for closing tag. -+ * Phase 4: Skipping unknown extensions. -+ * Phase 5: PHASED OUT -+ */ -+ for(edx = ctx->step; ctx->phase <= 4;) { -+ pxer_chunk_type_e ch_type; /* XER chunk type */ -+ ssize_t ch_size; /* Chunk size */ -+ xer_check_tag_e tcv; /* Tag check value */ -+ asn_TYPE_member_t *elm; -+ -+ /* -+ * Go inside the member. -+ */ -+ if(ctx->phase == 2) { -+ asn_dec_rval_t tmprval; -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ -+ elm = &td->elements[edx]; -+ -+ if(elm->flags & ATF_POINTER) { -+ /* Member is a pointer to another structure */ -+ memb_ptr2 = (void **)((char *)st -+ + elm->memb_offset); -+ } else { -+ memb_ptr = (char *)st + elm->memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ -+ /* Start/Continue decoding the inner member */ -+ tmprval = elm->type->xer_decoder(opt_codec_ctx, -+ elm->type, memb_ptr2, elm->name, -+ buf_ptr, size); -+ XER_ADVANCE(tmprval.consumed); -+ ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d", -+ elm->type->name, tmprval.code); -+ if(tmprval.code != RC_OK) -+ RETURN(tmprval.code); -+ assert(_fetch_present_idx(st, -+ specs->pres_offset, specs->pres_size) == 0); -+ /* Record what we've got */ -+ _set_present_idx(st, -+ specs->pres_offset, specs->pres_size, edx + 1); -+ ctx->phase = 3; -+ /* Fall through */ -+ } -+ -+ /* No need to wait for closing tag; special mode. */ -+ if(ctx->phase == 3 && !*xml_tag) { -+ ctx->phase = 5; /* Phase out */ -+ RETURN(RC_OK); -+ } -+ -+ /* -+ * Get the next part of the XML stream. -+ */ -+ ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); -+ switch(ch_size) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ default: -+ switch(ch_type) { -+ case PXER_COMMENT: /* Got XML comment */ -+ case PXER_TEXT: /* Ignore free-standing text */ -+ XER_ADVANCE(ch_size); /* Skip silently */ -+ continue; -+ case PXER_TAG: -+ break; /* Check the rest down there */ -+ } -+ } -+ -+ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); -+ ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d", -+ ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', -+ ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', -+ ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', -+ ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', -+ xml_tag, tcv); -+ -+ /* Skip the extensions section */ -+ if(ctx->phase == 4) { -+ ASN_DEBUG("skip_unknown(%d, %ld)", -+ tcv, (long)ctx->left); -+ switch(xer_skip_unknown(tcv, &ctx->left)) { -+ case -1: -+ ctx->phase = 5; -+ RETURN(RC_FAIL); -+ continue; -+ case 1: -+ ctx->phase = 3; -+ /* Fall through */ -+ case 0: -+ XER_ADVANCE(ch_size); -+ continue; -+ case 2: -+ ctx->phase = 3; -+ break; -+ } -+ } -+ -+ switch(tcv) { -+ case XCT_BOTH: -+ break; /* No CHOICE? */ -+ case XCT_CLOSING: -+ if(ctx->phase != 3) -+ break; -+ XER_ADVANCE(ch_size); -+ ctx->phase = 5; /* Phase out */ -+ RETURN(RC_OK); -+ case XCT_OPENING: -+ if(ctx->phase == 0) { -+ XER_ADVANCE(ch_size); -+ ctx->phase = 1; /* Processing body phase */ -+ continue; -+ } -+ /* Fall through */ -+ case XCT_UNKNOWN_OP: -+ case XCT_UNKNOWN_BO: -+ -+ if(ctx->phase != 1) -+ break; /* Really unexpected */ -+ -+ /* -+ * Search which inner member corresponds to this tag. -+ */ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ elm = &td->elements[edx]; -+ tcv = xer_check_tag(buf_ptr,ch_size,elm->name); -+ switch(tcv) { -+ case XCT_BOTH: -+ case XCT_OPENING: -+ /* -+ * Process this member. -+ */ -+ ctx->step = edx; -+ ctx->phase = 2; -+ break; -+ case XCT_UNKNOWN_OP: -+ case XCT_UNKNOWN_BO: -+ continue; -+ default: -+ edx = td->elements_count; -+ break; /* Phase out */ -+ } -+ break; -+ } -+ if(edx != td->elements_count) -+ continue; -+ -+ /* It is expected extension */ -+ if(specs->ext_start != -1) { -+ ASN_DEBUG("Got anticipated extension"); -+ /* -+ * Check for (XCT_BOTH or XCT_UNKNOWN_BO) -+ * By using a mask. Only record a pure -+ * tags. -+ */ -+ if(tcv & XCT_CLOSING) { -+ /* Found without body */ -+ ctx->phase = 3; /* Terminating */ -+ } else { -+ ctx->left = 1; -+ ctx->phase = 4; /* Skip ...'s */ -+ } -+ XER_ADVANCE(ch_size); -+ continue; -+ } -+ -+ /* Fall through */ -+ default: -+ break; -+ } -+ -+ ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]" -+ " (ph=%d, tag=%s)", -+ ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', -+ ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', -+ ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', -+ ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', -+ td->name, ctx->phase, xml_tag); -+ break; -+ } -+ -+ ctx->phase = 5; /* Phase out, just in case */ -+ RETURN(RC_FAIL); -+} -+ -+ -+asn_enc_rval_t -+CHOICE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_CHOICE_specifics_t *specs=(asn_CHOICE_specifics_t *)td->specifics; -+ asn_enc_rval_t er; -+ int present; -+ -+ if(!sptr) -+ _ASN_ENCODE_FAILED; -+ -+ /* -+ * Figure out which CHOICE element is encoded. -+ */ -+ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); -+ -+ if(present <= 0 || present > td->elements_count) { -+ _ASN_ENCODE_FAILED; -+ } else { -+ asn_enc_rval_t tmper; -+ asn_TYPE_member_t *elm = &td->elements[present-1]; -+ void *memb_ptr; -+ const char *mname = elm->name; -+ unsigned int mlen = strlen(mname); -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(!memb_ptr) _ASN_ENCODE_FAILED; -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ } -+ -+ er.encoded = 0; -+ -+ if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel); -+ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); -+ -+ tmper = elm->type->xer_encoder(elm->type, memb_ptr, -+ ilevel + 1, flags, cb, app_key); -+ if(tmper.encoded == -1) return tmper; -+ -+ _ASN_CALLBACK3("", 1); -+ -+ er.encoded += 5 + (2 * mlen) + tmper.encoded; -+ } -+ -+ if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel - 1); -+ -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+asn_dec_rval_t -+CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ asn_dec_rval_t rv; -+ asn_per_constraint_t *ct; -+ asn_TYPE_member_t *elm; /* CHOICE's element */ -+ void *memb_ptr; -+ void **memb_ptr2; -+ void *st = *sptr; -+ int value; -+ -+ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) -+ _ASN_DECODE_FAILED; -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(!st) { -+ st = *sptr = CALLOC(1, specs->struct_size); -+ if(!st) _ASN_DECODE_FAILED; -+ } -+ -+ if(constraints) ct = &constraints->value; -+ else if(td->per_constraints) ct = &td->per_constraints->value; -+ else ct = 0; -+ -+ if(ct && ct->flags & APC_EXTENSIBLE) { -+ value = per_get_few_bits(pd, 1); -+ if(value < 0) _ASN_DECODE_STARVED; -+ if(value) ct = 0; /* Not restricted */ -+ } -+ -+ if(ct && ct->range_bits >= 0) { -+ value = per_get_few_bits(pd, ct->range_bits); -+ if(value < 0) _ASN_DECODE_STARVED; -+ ASN_DEBUG("CHOICE %s got index %d in range %d", -+ td->name, value, ct->range_bits); -+ if(value > ct->upper_bound) -+ _ASN_DECODE_FAILED; -+ } else { -+ if(specs->ext_start == -1) -+ _ASN_DECODE_FAILED; -+ value = uper_get_nsnnwn(pd); -+ if(value < 0) _ASN_DECODE_STARVED; -+ value += specs->ext_start; -+ if(value >= td->elements_count) -+ _ASN_DECODE_FAILED; -+ ASN_DEBUG("NOT IMPLEMENTED YET"); -+ _ASN_DECODE_FAILED; -+ } -+ -+ /* Adjust if canonical order is different from natural order */ -+ if(specs->canonical_order) -+ value = specs->canonical_order[value]; -+ -+ /* Set presence to be able to free it later */ -+ _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); -+ -+ elm = &td->elements[value]; -+ if(elm->flags & ATF_POINTER) { -+ /* Member is a pointer to another structure */ -+ memb_ptr2 = (void **)((char *)st + elm->memb_offset); -+ } else { -+ memb_ptr = (char *)st + elm->memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); -+ -+ rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, -+ elm->per_constraints, memb_ptr2, pd); -+ if(rv.code != RC_OK) -+ ASN_DEBUG("Failed to decode %s in %s (CHOICE)", -+ elm->name, td->name); -+ return rv; -+} -+ -+asn_enc_rval_t -+CHOICE_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elm; /* CHOICE's element */ -+ asn_per_constraint_t *ct; -+ void *memb_ptr; -+ int present; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ -+ ASN_DEBUG("Encoding %s as CHOICE", td->name); -+ -+ if(constraints) ct = &constraints->value; -+ else if(td->per_constraints) ct = &td->per_constraints->value; -+ else ct = 0; -+ -+ present = _fetch_present_idx(sptr, -+ specs->pres_offset, specs->pres_size); -+ -+ /* -+ * If the structure was not initialized properly, it cannot be encoded: -+ * can't deduce what to encode in the choice type. -+ */ -+ if(present <= 0 || present > td->elements_count) -+ _ASN_ENCODE_FAILED; -+ else -+ present--; -+ -+ /* Adjust if canonical order is different from natural order */ -+ if(specs->canonical_order) -+ present = specs->canonical_order[present]; -+ -+ ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); -+ -+ if(ct && ct->range_bits >= 0) { -+ if(present < ct->lower_bound -+ || present > ct->upper_bound) { -+ if(ct->flags & APC_EXTENSIBLE) { -+ if(per_put_few_bits(po, 1, 1)) -+ _ASN_ENCODE_FAILED; -+ } else { -+ _ASN_ENCODE_FAILED; -+ } -+ ct = 0; -+ } -+ } -+ if(ct && ct->flags & APC_EXTENSIBLE) -+ if(per_put_few_bits(po, 0, 1)) -+ _ASN_ENCODE_FAILED; -+ -+ if(ct && ct->range_bits >= 0) { -+ if(per_put_few_bits(po, present, ct->range_bits)) -+ _ASN_ENCODE_FAILED; -+ } else { -+ if(specs->ext_start == -1) -+ _ASN_ENCODE_FAILED; -+ if(uper_put_nsnnwn(po, present - specs->ext_start)) -+ _ASN_ENCODE_FAILED; -+ ASN_DEBUG("NOT IMPLEMENTED YET"); -+ _ASN_ENCODE_FAILED; -+ } -+ -+ elm = &td->elements[present]; -+ if(elm->flags & ATF_POINTER) { -+ /* Member is a pointer to another structure */ -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(!memb_ptr) _ASN_ENCODE_FAILED; -+ } else { -+ memb_ptr = (char *)sptr + elm->memb_offset; -+ } -+ -+ return elm->type->uper_encoder(elm->type, elm->per_constraints, -+ memb_ptr, po); -+} -+ -+ -+int -+CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ int present; -+ -+ if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; -+ -+ /* -+ * Figure out which CHOICE element is encoded. -+ */ -+ present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); -+ -+ /* -+ * Print that element. -+ */ -+ if(present > 0 && present <= td->elements_count) { -+ asn_TYPE_member_t *elm = &td->elements[present-1]; -+ const void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); -+ if(!memb_ptr) return (cb("", 8, app_key) < 0) ? -1 : 0; -+ } else { -+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); -+ } -+ -+ /* Print member's name and stuff */ -+ if(0) { -+ if(cb(elm->name, strlen(elm->name), app_key) < 0 -+ || cb(": ", 2, app_key) < 0) -+ return -1; -+ } -+ -+ return elm->type->print_struct(elm->type, memb_ptr, ilevel, -+ cb, app_key); -+ } else { -+ return (cb("", 8, app_key) < 0) ? -1 : 0; -+ } -+} -+ -+void -+CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { -+ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; -+ int present; -+ -+ if(!td || !ptr) -+ return; -+ -+ ASN_DEBUG("Freeing %s as CHOICE", td->name); -+ -+ /* -+ * Figure out which CHOICE element is encoded. -+ */ -+ present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); -+ -+ /* -+ * Free that element. -+ */ -+ if(present > 0 && present <= td->elements_count) { -+ asn_TYPE_member_t *elm = &td->elements[present-1]; -+ void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)ptr + elm->memb_offset); -+ if(memb_ptr) -+ ASN_STRUCT_FREE(*elm->type, memb_ptr); -+ } else { -+ memb_ptr = (void *)((char *)ptr + elm->memb_offset); -+ ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); -+ } -+ } -+ -+ if(!contents_only) { -+ FREEMEM(ptr); -+ } -+} -+ -+ -+/* -+ * The following functions functions offer protection against -fshort-enums, -+ * compatible with little- and big-endian machines. -+ * If assertion is triggered, either disable -fshort-enums, or add an entry -+ * here with the ->pres_size of your target stracture. -+ * Unless the target structure is packed, the ".present" member -+ * is guaranteed to be aligned properly. ASN.1 compiler itself does not -+ * produce packed code. -+ */ -+static int -+_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) { -+ const void *present_ptr; -+ int present; -+ -+ present_ptr = ((const char *)struct_ptr) + pres_offset; -+ -+ switch(pres_size) { -+ case sizeof(int): present = *(const int *)present_ptr; break; -+ case sizeof(short): present = *(const short *)present_ptr; break; -+ case sizeof(char): present = *(const char *)present_ptr; break; -+ default: -+ /* ANSI C mandates enum to be equivalent to integer */ -+ assert(pres_size != sizeof(int)); -+ return 0; /* If not aborted, pass back safe value */ -+ } -+ -+ return present; -+} -+ -+static void -+_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) { -+ void *present_ptr; -+ present_ptr = ((char *)struct_ptr) + pres_offset; -+ -+ switch(pres_size) { -+ case sizeof(int): *(int *)present_ptr = present; break; -+ case sizeof(short): *(short *)present_ptr = present; break; -+ case sizeof(char): *(char *)present_ptr = present; break; -+ default: -+ /* ANSI C mandates enum to be equivalent to integer */ -+ assert(pres_size != sizeof(int)); -+ } -+} -diff --git a/asn1/asn1c/constr_CHOICE.h b/asn1/asn1c/constr_CHOICE.h -new file mode 100644 -index 0000000000000000000000000000000000000000..83404e6d43573c9903888fb5c49853e852a7848e ---- /dev/null -+++ b/asn1/asn1c/constr_CHOICE.h -@@ -0,0 +1,57 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _CONSTR_CHOICE_H_ -+#define _CONSTR_CHOICE_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct asn_CHOICE_specifics_s { -+ /* -+ * Target structure description. -+ */ -+ int struct_size; /* Size of the target structure. */ -+ int ctx_offset; /* Offset of the asn_codec_ctx_t member */ -+ int pres_offset; /* Identifier of the present member */ -+ int pres_size; /* Size of the identifier (enum) */ -+ -+ /* -+ * Tags to members mapping table. -+ */ -+ asn_TYPE_tag2member_t *tag2el; -+ int tag2el_count; -+ -+ /* Canonical ordering of CHOICE elements, for PER */ -+ int *canonical_order; -+ -+ /* -+ * Extensions-related stuff. -+ */ -+ int ext_start; /* First member of extensions, or -1 */ -+} asn_CHOICE_specifics_t; -+ -+/* -+ * A set specialized functions dealing with the CHOICE type. -+ */ -+asn_struct_free_f CHOICE_free; -+asn_struct_print_f CHOICE_print; -+asn_constr_check_f CHOICE_constraint; -+ber_type_decoder_f CHOICE_decode_ber; -+der_type_encoder_f CHOICE_encode_der; -+xer_type_decoder_f CHOICE_decode_xer; -+xer_type_encoder_f CHOICE_encode_xer; -+per_type_decoder_f CHOICE_decode_uper; -+per_type_encoder_f CHOICE_encode_uper; -+asn_outmost_tag_f CHOICE_outmost_tag; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _CONSTR_CHOICE_H_ */ -diff --git a/asn1/asn1c/constr_SEQUENCE.c b/asn1/asn1c/constr_SEQUENCE.c -new file mode 100644 -index 0000000000000000000000000000000000000000..b769434345763a454777a89458155f5debea73c8 ---- /dev/null -+++ b/asn1/asn1c/constr_SEQUENCE.c -@@ -0,0 +1,1251 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+ -+/* -+ * Number of bytes left for this structure. -+ * (ctx->left) indicates the number of bytes _transferred_ for the structure. -+ * (size) contains the number of bytes in the buffer passed. -+ */ -+#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) -+ -+/* -+ * If the subprocessor function returns with an indication that it wants -+ * more data, it may well be a fatal decoding problem, because the -+ * size is constrained by the 's L, even if the buffer size allows -+ * reading more data. -+ * For example, consider the buffer containing the following TLVs: -+ * ... -+ * The TLV length clearly indicates that one byte is expected in V, but -+ * if the V processor returns with "want more data" even if the buffer -+ * contains way more data than the V processor have seen. -+ */ -+#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) -+ -+/* -+ * This macro "eats" the part of the buffer which is definitely "consumed", -+ * i.e. was correctly converted into local representation or rightfully skipped. -+ */ -+#undef ADVANCE -+#define ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ ptr = ((const char *)ptr) + num;\ -+ size -= num; \ -+ if(ctx->left >= 0) \ -+ ctx->left -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+/* -+ * Switch to the next phase of parsing. -+ */ -+#undef NEXT_PHASE -+#undef PHASE_OUT -+#define NEXT_PHASE(ctx) do { \ -+ ctx->phase++; \ -+ ctx->step = 0; \ -+ } while(0) -+#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) -+ -+/* -+ * Return a standardized complex structure. -+ */ -+#undef RETURN -+#define RETURN(_code) do { \ -+ rval.code = _code; \ -+ rval.consumed = consumed_myself;\ -+ return rval; \ -+ } while(0) -+ -+/* -+ * Check whether we are inside the extensions group. -+ */ -+#define IN_EXTENSION_GROUP(specs, memb_idx) \ -+ ( ((memb_idx) > (specs)->ext_after) \ -+ &&((memb_idx) < (specs)->ext_before)) -+ -+ -+/* -+ * Tags are canonically sorted in the tag2element map. -+ */ -+static int -+_t2e_cmp(const void *ap, const void *bp) { -+ const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; -+ const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; -+ -+ int a_class = BER_TAG_CLASS(a->el_tag); -+ int b_class = BER_TAG_CLASS(b->el_tag); -+ -+ if(a_class == b_class) { -+ ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); -+ ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); -+ -+ if(a_value == b_value) { -+ if(a->el_no > b->el_no) -+ return 1; -+ /* -+ * Important: we do not check -+ * for a->el_no <= b->el_no! -+ */ -+ return 0; -+ } else if(a_value < b_value) -+ return -1; -+ else -+ return 1; -+ } else if(a_class < b_class) { -+ return -1; -+ } else { -+ return 1; -+ } -+} -+ -+ -+/* -+ * The decoder of the SEQUENCE type. -+ */ -+asn_dec_rval_t -+SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const void *ptr, size_t size, int tag_mode) { -+ /* -+ * Bring closer parts of structure description. -+ */ -+ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elements = td->elements; -+ -+ /* -+ * Parts of the structure being constructed. -+ */ -+ void *st = *struct_ptr; /* Target structure. */ -+ asn_struct_ctx_t *ctx; /* Decoder context */ -+ -+ ber_tlv_tag_t tlv_tag; /* T from TLV */ -+ asn_dec_rval_t rval; /* Return code from subparsers */ -+ -+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ -+ int edx; /* SEQUENCE element's index */ -+ -+ ASN_DEBUG("Decoding %s as SEQUENCE", td->name); -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(st == 0) { -+ st = *struct_ptr = CALLOC(1, specs->struct_size); -+ if(st == 0) { -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * Restore parsing context. -+ */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ -+ /* -+ * Start to parse where left previously -+ */ -+ switch(ctx->phase) { -+ case 0: -+ /* -+ * PHASE 0. -+ * Check that the set of tags associated with given structure -+ * perfectly fits our expectations. -+ */ -+ -+ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, -+ tag_mode, 1, &ctx->left, 0); -+ if(rval.code != RC_OK) { -+ ASN_DEBUG("%s tagging check failed: %d", -+ td->name, rval.code); -+ return rval; -+ } -+ -+ if(ctx->left >= 0) -+ ctx->left += rval.consumed; /* ?Substracted below! */ -+ ADVANCE(rval.consumed); -+ -+ NEXT_PHASE(ctx); -+ -+ ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", -+ (long)ctx->left, (long)size); -+ -+ /* Fall through */ -+ case 1: -+ /* -+ * PHASE 1. -+ * From the place where we've left it previously, -+ * try to decode the next member from the list of -+ * this structure's elements. -+ * (ctx->step) stores the member being processed -+ * between invocations and the microphase {0,1} of parsing -+ * that member: -+ * step = ( * 2 + ). -+ */ -+ for(edx = (ctx->step >> 1); edx < td->elements_count; -+ edx++, ctx->step = (ctx->step & ~1) + 2) { -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ ssize_t tag_len; /* Length of TLV's T */ -+ int opt_edx_end; /* Next non-optional element */ -+ int use_bsearch; -+ int n; -+ -+ if(ctx->step & 1) -+ goto microphase2; -+ -+ /* -+ * MICROPHASE 1: Synchronize decoding. -+ */ -+ ASN_DEBUG("In %s SEQUENCE left %d, edx=%d flags=%d" -+ " opt=%d ec=%d", -+ td->name, (int)ctx->left, edx, -+ elements[edx].flags, elements[edx].optional, -+ td->elements_count); -+ -+ if(ctx->left == 0 /* No more stuff is expected */ -+ && ( -+ /* Explicit OPTIONAL specification reaches the end */ -+ (edx + elements[edx].optional -+ == td->elements_count) -+ || -+ /* All extensions are optional */ -+ (IN_EXTENSION_GROUP(specs, edx) -+ && specs->ext_before > td->elements_count) -+ ) -+ ) { -+ ASN_DEBUG("End of SEQUENCE %s", td->name); -+ /* -+ * Found the legitimate end of the structure. -+ */ -+ PHASE_OUT(ctx); -+ RETURN(RC_OK); -+ } -+ -+ /* -+ * Fetch the T from TLV. -+ */ -+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); -+ ASN_DEBUG("Current tag in %s SEQUENCE for element %d " -+ "(%s) is %s encoded in %d bytes, of frame %ld", -+ td->name, edx, elements[edx].name, -+ ber_tlv_tag_string(tlv_tag), (int)tag_len, (long)LEFT); -+ switch(tag_len) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { -+ if(LEFT < 2) { -+ if(SIZE_VIOLATION) -+ RETURN(RC_FAIL); -+ else -+ RETURN(RC_WMORE); -+ } else if(((const uint8_t *)ptr)[1] == 0) { -+ ASN_DEBUG("edx = %d, opt = %d, ec=%d", -+ edx, elements[edx].optional, -+ td->elements_count); -+ if((edx + elements[edx].optional -+ == td->elements_count) -+ || (IN_EXTENSION_GROUP(specs, edx) -+ && specs->ext_before -+ > td->elements_count)) { -+ /* -+ * Yeah, baby! Found the terminator -+ * of the indefinite length structure. -+ */ -+ /* -+ * Proceed to the canonical -+ * finalization function. -+ * No advancing is necessary. -+ */ -+ goto phase3; -+ } -+ } -+ } -+ -+ /* -+ * Find the next available type with this tag. -+ */ -+ use_bsearch = 0; -+ opt_edx_end = edx + elements[edx].optional + 1; -+ if(opt_edx_end > td->elements_count) -+ opt_edx_end = td->elements_count; /* Cap */ -+ else if(opt_edx_end - edx > 8) { -+ /* Limit the scope of linear search... */ -+ opt_edx_end = edx + 8; -+ use_bsearch = 1; -+ /* ... and resort to bsearch() */ -+ } -+ for(n = edx; n < opt_edx_end; n++) { -+ if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { -+ /* -+ * Found element corresponding to the tag -+ * being looked at. -+ * Reposition over the right element. -+ */ -+ edx = n; -+ ctx->step = 1 + 2 * edx; /* Remember! */ -+ goto microphase2; -+ } else if(elements[n].flags & ATF_OPEN_TYPE) { -+ /* -+ * This is the ANY type, which may bear -+ * any flag whatsoever. -+ */ -+ edx = n; -+ ctx->step = 1 + 2 * edx; /* Remember! */ -+ goto microphase2; -+ } else if(elements[n].tag == (ber_tlv_tag_t)-1) { -+ use_bsearch = 1; -+ break; -+ } -+ } -+ if(use_bsearch) { -+ /* -+ * Resort to a binary search over -+ * sorted array of tags. -+ */ -+ asn_TYPE_tag2member_t *t2m; -+ asn_TYPE_tag2member_t key; -+ key.el_tag = tlv_tag; -+ key.el_no = edx; -+ t2m = (asn_TYPE_tag2member_t *)bsearch(&key, -+ specs->tag2el, specs->tag2el_count, -+ sizeof(specs->tag2el[0]), _t2e_cmp); -+ if(t2m) { -+ asn_TYPE_tag2member_t *best = 0; -+ asn_TYPE_tag2member_t *t2m_f, *t2m_l; -+ int edx_max = edx + elements[edx].optional; -+ /* -+ * Rewind to the first element with that tag, -+ * `cause bsearch() does not guarantee order. -+ */ -+ t2m_f = t2m + t2m->toff_first; -+ t2m_l = t2m + t2m->toff_last; -+ for(t2m = t2m_f; t2m <= t2m_l; t2m++) { -+ if(t2m->el_no > edx_max) break; -+ if(t2m->el_no < edx) continue; -+ best = t2m; -+ } -+ if(best) { -+ edx = best->el_no; -+ ctx->step = 1 + 2 * edx; -+ goto microphase2; -+ } -+ } -+ n = opt_edx_end; -+ } -+ if(n == opt_edx_end) { -+ /* -+ * If tag is unknown, it may be either -+ * an unknown (thus, incorrect) tag, -+ * or an extension (...), -+ * or an end of the indefinite-length structure. -+ */ -+ if(!IN_EXTENSION_GROUP(specs, edx)) { -+ ASN_DEBUG("Unexpected tag %s (at %d)", -+ ber_tlv_tag_string(tlv_tag), edx); -+ ASN_DEBUG("Expected tag %s (%s)%s", -+ ber_tlv_tag_string(elements[edx].tag), -+ elements[edx].name, -+ elements[edx].optional -+ ?" or alternatives":""); -+ RETURN(RC_FAIL); -+ } else { -+ /* Skip this tag */ -+ ssize_t skip; -+ -+ skip = ber_skip_length(opt_codec_ctx, -+ BER_TLV_CONSTRUCTED(ptr), -+ (const char *)ptr + tag_len, -+ LEFT - tag_len); -+ ASN_DEBUG("Skip length %d in %s", -+ (int)skip, td->name); -+ switch(skip) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ ADVANCE(skip + tag_len); -+ ctx->step -= 2; -+ edx--; -+ continue; /* Try again with the next tag */ -+ } -+ } -+ -+ /* -+ * MICROPHASE 2: Invoke the member-specific decoder. -+ */ -+ ctx->step |= 1; /* Confirm entering next microphase */ -+ microphase2: -+ ASN_DEBUG("Inside SEQUENCE %s MF2", td->name); -+ -+ /* -+ * Compute the position of the member inside a structure, -+ * and also a type of containment (it may be contained -+ * as pointer or using inline inclusion). -+ */ -+ if(elements[edx].flags & ATF_POINTER) { -+ /* Member is a pointer to another structure */ -+ memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); -+ } else { -+ /* -+ * A pointer to a pointer -+ * holding the start of the structure -+ */ -+ memb_ptr = (char *)st + elements[edx].memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ /* -+ * Invoke the member fetch routine according to member's type -+ */ -+ rval = elements[edx].type->ber_decoder(opt_codec_ctx, -+ elements[edx].type, -+ memb_ptr2, ptr, LEFT, -+ elements[edx].tag_mode); -+ ASN_DEBUG("In %s SEQUENCE decoded %d %s of %d " -+ "in %d bytes rval.code %d, size=%d", -+ td->name, edx, elements[edx].type->name, -+ (int)LEFT, (int)rval.consumed, rval.code, (int)size); -+ switch(rval.code) { -+ case RC_OK: -+ break; -+ case RC_WMORE: /* More data expected */ -+ if(!SIZE_VIOLATION) { -+ ADVANCE(rval.consumed); -+ RETURN(RC_WMORE); -+ } -+ ASN_DEBUG("Size violation (c->l=%ld <= s=%ld)", -+ (long)ctx->left, (long)size); -+ /* Fall through */ -+ case RC_FAIL: /* Fatal error */ -+ RETURN(RC_FAIL); -+ } /* switch(rval) */ -+ -+ ADVANCE(rval.consumed); -+ } /* for(all structure members) */ -+ -+ phase3: -+ ctx->phase = 3; -+ case 3: /* 00 and other tags expected */ -+ case 4: /* only 00's expected */ -+ -+ ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld", -+ td->name, (long)ctx->left, (long)size); -+ -+ /* -+ * Skip everything until the end of the SEQUENCE. -+ */ -+ while(ctx->left) { -+ ssize_t tl, ll; -+ -+ tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); -+ switch(tl) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ /* -+ * If expected <0><0>... -+ */ -+ if(ctx->left < 0 -+ && ((const uint8_t *)ptr)[0] == 0) { -+ if(LEFT < 2) { -+ if(SIZE_VIOLATION) -+ RETURN(RC_FAIL); -+ else -+ RETURN(RC_WMORE); -+ } else if(((const uint8_t *)ptr)[1] == 0) { -+ /* -+ * Correctly finished with <0><0>. -+ */ -+ ADVANCE(2); -+ ctx->left++; -+ ctx->phase = 4; -+ continue; -+ } -+ } -+ -+ if(!IN_EXTENSION_GROUP(specs, td->elements_count) -+ || ctx->phase == 4) { -+ ASN_DEBUG("Unexpected continuation " -+ "of a non-extensible type " -+ "%s (SEQUENCE): %s", -+ td->name, -+ ber_tlv_tag_string(tlv_tag)); -+ RETURN(RC_FAIL); -+ } -+ -+ ll = ber_skip_length(opt_codec_ctx, -+ BER_TLV_CONSTRUCTED(ptr), -+ (const char *)ptr + tl, LEFT - tl); -+ switch(ll) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ ADVANCE(tl + ll); -+ } -+ -+ PHASE_OUT(ctx); -+ } -+ -+ RETURN(RC_OK); -+} -+ -+ -+/* -+ * The DER encoder of the SEQUENCE type. -+ */ -+asn_enc_rval_t -+SEQUENCE_encode_der(asn_TYPE_descriptor_t *td, -+ void *sptr, int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ size_t computed_size = 0; -+ asn_enc_rval_t erval; -+ ssize_t ret; -+ int edx; -+ -+ ASN_DEBUG("%s %s as SEQUENCE", -+ cb?"Encoding":"Estimating", td->name); -+ -+ /* -+ * Gather the length of the underlying members sequence. -+ */ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ void *memb_ptr; -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(!memb_ptr) { -+ if(elm->optional) continue; -+ /* Mandatory element is missing */ -+ _ASN_ENCODE_FAILED; -+ } -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ } -+ erval = elm->type->der_encoder(elm->type, memb_ptr, -+ elm->tag_mode, elm->tag, -+ 0, 0); -+ if(erval.encoded == -1) -+ return erval; -+ computed_size += erval.encoded; -+ ASN_DEBUG("Member %d %s estimated %ld bytes", -+ edx, elm->name, (long)erval.encoded); -+ } -+ -+ /* -+ * Encode the TLV for the sequence itself. -+ */ -+ ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); -+ ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size); -+ if(ret == -1) -+ _ASN_ENCODE_FAILED; -+ erval.encoded = computed_size + ret; -+ -+ if(!cb) _ASN_ENCODED_OK(erval); -+ -+ /* -+ * Encode all members. -+ */ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ asn_enc_rval_t tmperval; -+ void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(!memb_ptr) continue; -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ } -+ tmperval = elm->type->der_encoder(elm->type, memb_ptr, -+ elm->tag_mode, elm->tag, -+ cb, app_key); -+ if(tmperval.encoded == -1) -+ return tmperval; -+ computed_size -= tmperval.encoded; -+ ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %ld bytes", -+ edx, elm->name, td->name, (long)tmperval.encoded); -+ } -+ -+ if(computed_size != 0) -+ /* -+ * Encoded size is not equal to the computed size. -+ */ -+ _ASN_ENCODE_FAILED; -+ -+ _ASN_ENCODED_OK(erval); -+} -+ -+ -+#undef XER_ADVANCE -+#define XER_ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ buf_ptr = ((const char *)buf_ptr) + num;\ -+ size -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+/* -+ * Decode the XER (XML) data. -+ */ -+asn_dec_rval_t -+SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const char *opt_mname, -+ const void *buf_ptr, size_t size) { -+ /* -+ * Bring closer parts of structure description. -+ */ -+ asn_SEQUENCE_specifics_t *specs -+ = (asn_SEQUENCE_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elements = td->elements; -+ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; -+ -+ /* -+ * ... and parts of the structure being constructed. -+ */ -+ void *st = *struct_ptr; /* Target structure. */ -+ asn_struct_ctx_t *ctx; /* Decoder context */ -+ -+ asn_dec_rval_t rval; /* Return value from a decoder */ -+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ -+ int edx; /* Element index */ -+ int edx_end; -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(st == 0) { -+ st = *struct_ptr = CALLOC(1, specs->struct_size); -+ if(st == 0) RETURN(RC_FAIL); -+ } -+ -+ /* -+ * Restore parsing context. -+ */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ -+ -+ /* -+ * Phases of XER/XML processing: -+ * Phase 0: Check that the opening tag matches our expectations. -+ * Phase 1: Processing body and reacting on closing tag. -+ * Phase 2: Processing inner type. -+ * Phase 3: Skipping unknown extensions. -+ * Phase 4: PHASED OUT -+ */ -+ for(edx = ctx->step; ctx->phase <= 3;) { -+ pxer_chunk_type_e ch_type; /* XER chunk type */ -+ ssize_t ch_size; /* Chunk size */ -+ xer_check_tag_e tcv; /* Tag check value */ -+ asn_TYPE_member_t *elm; -+ int n; -+ -+ /* -+ * Go inside the inner member of a sequence. -+ */ -+ if(ctx->phase == 2) { -+ asn_dec_rval_t tmprval; -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ -+ elm = &td->elements[edx]; -+ -+ if(elm->flags & ATF_POINTER) { -+ /* Member is a pointer to another structure */ -+ memb_ptr2 = (void **)((char *)st -+ + elm->memb_offset); -+ } else { -+ memb_ptr = (char *)st + elm->memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ -+ /* Invoke the inner type decoder, m.b. multiple times */ -+ tmprval = elm->type->xer_decoder(opt_codec_ctx, -+ elm->type, memb_ptr2, elm->name, -+ buf_ptr, size); -+ XER_ADVANCE(tmprval.consumed); -+ if(tmprval.code != RC_OK) -+ RETURN(tmprval.code); -+ ctx->phase = 1; /* Back to body processing */ -+ ctx->step = ++edx; -+ ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d", -+ ctx->phase, ctx->step); -+ /* Fall through */ -+ } -+ -+ /* -+ * Get the next part of the XML stream. -+ */ -+ ch_size = xer_next_token(&ctx->context, buf_ptr, size, -+ &ch_type); -+ switch(ch_size) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ default: -+ switch(ch_type) { -+ case PXER_COMMENT: /* Got XML comment */ -+ case PXER_TEXT: /* Ignore free-standing text */ -+ XER_ADVANCE(ch_size); /* Skip silently */ -+ continue; -+ case PXER_TAG: -+ break; /* Check the rest down there */ -+ } -+ } -+ -+ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); -+ ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]", -+ tcv, ctx->phase, xml_tag); -+ -+ /* Skip the extensions section */ -+ if(ctx->phase == 3) { -+ switch(xer_skip_unknown(tcv, &ctx->left)) { -+ case -1: -+ ctx->phase = 4; -+ RETURN(RC_FAIL); -+ case 0: -+ XER_ADVANCE(ch_size); -+ continue; -+ case 1: -+ XER_ADVANCE(ch_size); -+ ctx->phase = 1; -+ continue; -+ case 2: -+ ctx->phase = 1; -+ break; -+ } -+ } -+ -+ switch(tcv) { -+ case XCT_CLOSING: -+ if(ctx->phase == 0) break; -+ ctx->phase = 0; -+ /* Fall through */ -+ case XCT_BOTH: -+ if(ctx->phase == 0) { -+ if(edx >= td->elements_count -+ || -+ /* Explicit OPTIONAL specs reaches the end */ -+ (edx + elements[edx].optional -+ == td->elements_count) -+ || -+ /* All extensions are optional */ -+ (IN_EXTENSION_GROUP(specs, edx) -+ && specs->ext_before -+ > td->elements_count) -+ ) { -+ XER_ADVANCE(ch_size); -+ ctx->phase = 4; /* Phase out */ -+ RETURN(RC_OK); -+ } else { -+ ASN_DEBUG("Premature end of XER SEQUENCE"); -+ RETURN(RC_FAIL); -+ } -+ } -+ /* Fall through */ -+ case XCT_OPENING: -+ if(ctx->phase == 0) { -+ XER_ADVANCE(ch_size); -+ ctx->phase = 1; /* Processing body phase */ -+ continue; -+ } -+ /* Fall through */ -+ case XCT_UNKNOWN_OP: -+ case XCT_UNKNOWN_BO: -+ -+ ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%d", -+ tcv, ctx->phase, edx); -+ if(ctx->phase != 1) { -+ break; /* Really unexpected */ -+ } -+ -+ if(edx < td->elements_count) { -+ /* -+ * Search which member corresponds to this tag. -+ */ -+ edx_end = edx + elements[edx].optional + 1; -+ if(edx_end > td->elements_count) -+ edx_end = td->elements_count; -+ for(n = edx; n < edx_end; n++) { -+ elm = &td->elements[n]; -+ tcv = xer_check_tag(buf_ptr, -+ ch_size, elm->name); -+ switch(tcv) { -+ case XCT_BOTH: -+ case XCT_OPENING: -+ /* -+ * Process this member. -+ */ -+ ctx->step = edx = n; -+ ctx->phase = 2; -+ break; -+ case XCT_UNKNOWN_OP: -+ case XCT_UNKNOWN_BO: -+ continue; -+ default: -+ n = edx_end; -+ break; /* Phase out */ -+ } -+ break; -+ } -+ if(n != edx_end) -+ continue; -+ } else { -+ ASN_DEBUG("Out of defined members: %d/%d", -+ edx, td->elements_count); -+ } -+ -+ /* It is expected extension */ -+ if(IN_EXTENSION_GROUP(specs, -+ edx + (edx < td->elements_count -+ ? elements[edx].optional : 0))) { -+ ASN_DEBUG("Got anticipated extension at %d", -+ edx); -+ /* -+ * Check for (XCT_BOTH or XCT_UNKNOWN_BO) -+ * By using a mask. Only record a pure -+ * tags. -+ */ -+ if(tcv & XCT_CLOSING) { -+ /* Found without body */ -+ } else { -+ ctx->left = 1; -+ ctx->phase = 3; /* Skip ...'s */ -+ } -+ XER_ADVANCE(ch_size); -+ continue; -+ } -+ -+ /* Fall through */ -+ default: -+ break; -+ } -+ -+ ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]", -+ size>0?((const char *)buf_ptr)[0]:'.', -+ size>1?((const char *)buf_ptr)[1]:'.', -+ size>2?((const char *)buf_ptr)[2]:'.', -+ size>3?((const char *)buf_ptr)[3]:'.', -+ size>4?((const char *)buf_ptr)[4]:'.', -+ size>5?((const char *)buf_ptr)[5]:'.'); -+ break; -+ } -+ -+ ctx->phase = 4; /* "Phase out" on hard failure */ -+ RETURN(RC_FAIL); -+} -+ -+asn_enc_rval_t -+SEQUENCE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t er; -+ int xcan = (flags & XER_F_CANONICAL); -+ int edx; -+ -+ if(!sptr) -+ _ASN_ENCODE_FAILED; -+ -+ er.encoded = 0; -+ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ asn_enc_rval_t tmper; -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ void *memb_ptr; -+ const char *mname = elm->name; -+ unsigned int mlen = strlen(mname); -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(!memb_ptr) { -+ if(elm->optional) -+ continue; -+ /* Mandatory element is missing */ -+ _ASN_ENCODE_FAILED; -+ } -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ } -+ -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); -+ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); -+ -+ /* Print the member itself */ -+ tmper = elm->type->xer_encoder(elm->type, memb_ptr, -+ ilevel + 1, flags, cb, app_key); -+ if(tmper.encoded == -1) return tmper; -+ -+ _ASN_CALLBACK3("", 1); -+ er.encoded += 5 + (2 * mlen) + tmper.encoded; -+ } -+ -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); -+ -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+int -+SEQUENCE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ int edx; -+ int ret; -+ -+ if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; -+ -+ /* Dump preamble */ -+ if(cb(td->name, strlen(td->name), app_key) < 0 -+ || cb(" ::= {", 6, app_key) < 0) -+ return -1; -+ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ const void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); -+ if(!memb_ptr) { -+ if(elm->optional) continue; -+ /* Print line */ -+ /* Fall through */ -+ } -+ } else { -+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); -+ } -+ -+ /* Indentation */ -+ _i_INDENT(1); -+ -+ /* Print the member's name and stuff */ -+ if(cb(elm->name, strlen(elm->name), app_key) < 0 -+ || cb(": ", 2, app_key) < 0) -+ return -1; -+ -+ /* Print the member itself */ -+ ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 1, -+ cb, app_key); -+ if(ret) return ret; -+ } -+ -+ ilevel--; -+ _i_INDENT(1); -+ -+ return (cb("}", 1, app_key) < 0) ? -1 : 0; -+} -+ -+void -+SEQUENCE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { -+ int edx; -+ -+ if(!td || !sptr) -+ return; -+ -+ ASN_DEBUG("Freeing %s as SEQUENCE", td->name); -+ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ void *memb_ptr; -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); -+ if(memb_ptr) -+ ASN_STRUCT_FREE(*elm->type, memb_ptr); -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); -+ } -+ } -+ -+ if(!contents_only) { -+ FREEMEM(sptr); -+ } -+} -+ -+int -+SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, -+ asn_app_constraint_failed_f *ctfailcb, void *app_key) { -+ int edx; -+ -+ if(!sptr) { -+ _ASN_CTFAIL(app_key, td, -+ "%s: value not given (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+ -+ /* -+ * Iterate over structure members and check their validity. -+ */ -+ for(edx = 0; edx < td->elements_count; edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ const void *memb_ptr; -+ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); -+ if(!memb_ptr) { -+ if(elm->optional) -+ continue; -+ _ASN_CTFAIL(app_key, td, -+ "%s: mandatory element %s absent (%s:%d)", -+ td->name, elm->name, __FILE__, __LINE__); -+ return -1; -+ } -+ } else { -+ memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); -+ } -+ -+ if(elm->memb_constraints) { -+ int ret = elm->memb_constraints(elm->type, memb_ptr, -+ ctfailcb, app_key); -+ if(ret) return ret; -+ } else { -+ int ret = elm->type->check_constraints(elm->type, -+ memb_ptr, ctfailcb, app_key); -+ if(ret) return ret; -+ /* -+ * Cannot inherit it earlier: -+ * need to make sure we get the updated version. -+ */ -+ elm->memb_constraints = elm->type->check_constraints; -+ } -+ } -+ -+ return 0; -+} -+ -+asn_dec_rval_t -+SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { -+ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; -+ void *st = *sptr; /* Target structure. */ -+ int extpresent = 0; /* Extension additions are present */ -+ uint8_t *opres; /* Presence of optional root members */ -+ asn_per_data_t opmd; -+ asn_dec_rval_t rv; -+ int edx; -+ -+ (void)constraints; -+ -+ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) -+ _ASN_DECODE_FAILED; -+ -+ if(!st) { -+ st = *sptr = CALLOC(1, specs->struct_size); -+ if(!st) _ASN_DECODE_FAILED; -+ } -+ -+ ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); -+ -+ /* Handle extensions */ -+ if(specs->ext_before >= 0) { -+ extpresent = per_get_few_bits(pd, 1); -+ if(extpresent < 0) _ASN_DECODE_STARVED; -+ } -+ -+ /* Prepare a place and read-in the presence bitmap */ -+ if(specs->roms_count) { -+ opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); -+ if(!opres) _ASN_DECODE_FAILED; -+ /* Get the presence map */ -+ if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { -+ FREEMEM(opres); -+ _ASN_DECODE_STARVED; -+ } -+ opmd.buffer = opres; -+ opmd.nboff = 0; -+ opmd.nbits = specs->roms_count; -+ ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", -+ td->name, specs->roms_count, *opres); -+ } else { -+ opres = 0; -+ memset(&opmd, 0, sizeof opmd); -+ } -+ -+ /* -+ * Get the sequence ROOT elements. -+ */ -+ for(edx = 0; edx < ((specs->ext_before < 0) -+ ? td->elements_count : specs->ext_before + 1); edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ -+ /* Fetch the pointer to this member */ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr2 = (void **)((char *)st + elm->memb_offset); -+ } else { -+ memb_ptr = (char *)st + elm->memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ -+ /* Deal with optionality */ -+ if(elm->optional) { -+ int present = per_get_few_bits(&opmd, 1); -+ ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", -+ td->name, elm->name, present, -+ (int)opmd.nboff, (int)opmd.nbits); -+ if(present == 0) { -+ /* This element is not present */ -+ if(elm->default_value) { -+ /* Fill-in DEFAULT */ -+ if(elm->default_value(1, memb_ptr2)) { -+ FREEMEM(opres); -+ _ASN_DECODE_FAILED; -+ } -+ } -+ /* The member is just not present */ -+ continue; -+ } -+ /* Fall through */ -+ } -+ -+ /* Fetch the member from the stream */ -+ ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); -+ rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, -+ elm->per_constraints, memb_ptr2, pd); -+ if(rv.code != RC_OK) { -+ ASN_DEBUG("Failed decode %s in %s", -+ elm->name, td->name); -+ FREEMEM(opres); -+ return rv; -+ } -+ } -+ -+ /* -+ * Deal with extensions. -+ */ -+ if(extpresent) { -+ ASN_DEBUG("Extensibility for %s: NOT IMPLEMENTED", td->name); -+ _ASN_DECODE_FAILED; -+ } else { -+ for(edx = specs->roms_count; edx < specs->roms_count -+ + specs->aoms_count; edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ -+ if(!elm->default_value) continue; -+ -+ /* Fetch the pointer to this member */ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr2 = (void **)((char *)st -+ + elm->memb_offset); -+ } else { -+ memb_ptr = (char *)st + elm->memb_offset; -+ memb_ptr2 = &memb_ptr; -+ } -+ -+ /* Set default value */ -+ if(elm->default_value(1, memb_ptr2)) { -+ FREEMEM(opres); -+ _ASN_DECODE_FAILED; -+ } -+ } -+ } -+ -+ rv.consumed = 0; -+ rv.code = RC_OK; -+ FREEMEM(opres); -+ return rv; -+} -+ -+asn_enc_rval_t -+SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ asn_SEQUENCE_specifics_t *specs -+ = (asn_SEQUENCE_specifics_t *)td->specifics; -+ asn_enc_rval_t er; -+ int edx; -+ int i; -+ -+ (void)constraints; -+ -+ if(!sptr) -+ _ASN_ENCODE_FAILED; -+ -+ er.encoded = 0; -+ -+ ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); -+ if(specs->ext_before >= 0) -+ _ASN_ENCODE_FAILED; /* We don't encode extensions yet */ -+ -+ /* Encode a presence bitmap */ -+ for(i = 0; i < specs->roms_count; i++) { -+ asn_TYPE_member_t *elm; -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ int present; -+ -+ edx = specs->oms[i]; -+ elm = &td->elements[edx]; -+ -+ /* Fetch the pointer to this member */ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); -+ present = (*memb_ptr2 != 0); -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ memb_ptr2 = &memb_ptr; -+ present = 1; -+ } -+ -+ /* Eliminate default values */ -+ if(present && elm->default_value -+ && elm->default_value(0, memb_ptr2) == 1) -+ present = 0; -+ -+ ASN_DEBUG("Element %s %s %s->%s is %s", -+ elm->flags & ATF_POINTER ? "ptr" : "inline", -+ elm->default_value ? "def" : "wtv", -+ td->name, elm->name, present ? "present" : "absent"); -+ if(per_put_few_bits(po, present, 1)) -+ _ASN_ENCODE_FAILED; -+ } -+ -+ /* -+ * Get the sequence ROOT elements. -+ */ -+ for(edx = 0; edx < ((specs->ext_before < 0) -+ ? td->elements_count : specs->ext_before + 1); edx++) { -+ asn_TYPE_member_t *elm = &td->elements[edx]; -+ void *memb_ptr; /* Pointer to the member */ -+ void **memb_ptr2; /* Pointer to that pointer */ -+ -+ /* Fetch the pointer to this member */ -+ if(elm->flags & ATF_POINTER) { -+ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); -+ if(!*memb_ptr2) { -+ ASN_DEBUG("Element %s %d not present", -+ elm->name, edx); -+ if(elm->optional) -+ continue; -+ /* Mandatory element is missing */ -+ _ASN_ENCODE_FAILED; -+ } -+ } else { -+ memb_ptr = (void *)((char *)sptr + elm->memb_offset); -+ memb_ptr2 = &memb_ptr; -+ } -+ -+ /* Eliminate default values */ -+ if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) -+ continue; -+ -+ er = elm->type->uper_encoder(elm->type, elm->per_constraints, -+ *memb_ptr2, po); -+ if(er.encoded == -1) -+ return er; -+ } -+ -+ _ASN_ENCODED_OK(er); -+} -+ -diff --git a/asn1/asn1c/constr_SEQUENCE.h b/asn1/asn1c/constr_SEQUENCE.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5f589d5c1c0d1ae1d6e970742fc6467153bea79c ---- /dev/null -+++ b/asn1/asn1c/constr_SEQUENCE.h -@@ -0,0 +1,60 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _CONSTR_SEQUENCE_H_ -+#define _CONSTR_SEQUENCE_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct asn_SEQUENCE_specifics_s { -+ /* -+ * Target structure description. -+ */ -+ int struct_size; /* Size of the target structure. */ -+ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ -+ -+ /* -+ * Tags to members mapping table (sorted). -+ */ -+ asn_TYPE_tag2member_t *tag2el; -+ int tag2el_count; -+ -+ /* -+ * Optional members of the extensions root (roms) or additions (aoms). -+ * Meaningful for PER. -+ */ -+ int *oms; /* Optional MemberS */ -+ int roms_count; /* Root optional members count */ -+ int aoms_count; /* Additions optional members count */ -+ -+ /* -+ * Description of an extensions group. -+ */ -+ int ext_after; /* Extensions start after this member */ -+ int ext_before; /* Extensions stop before this member */ -+} asn_SEQUENCE_specifics_t; -+ -+ -+/* -+ * A set specialized functions dealing with the SEQUENCE type. -+ */ -+asn_struct_free_f SEQUENCE_free; -+asn_struct_print_f SEQUENCE_print; -+asn_constr_check_f SEQUENCE_constraint; -+ber_type_decoder_f SEQUENCE_decode_ber; -+der_type_encoder_f SEQUENCE_encode_der; -+xer_type_decoder_f SEQUENCE_decode_xer; -+xer_type_encoder_f SEQUENCE_encode_xer; -+per_type_decoder_f SEQUENCE_decode_uper; -+per_type_encoder_f SEQUENCE_encode_uper; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _CONSTR_SEQUENCE_H_ */ -diff --git a/asn1/asn1c/constr_SEQUENCE_OF.c b/asn1/asn1c/constr_SEQUENCE_OF.c -new file mode 100644 -index 0000000000000000000000000000000000000000..aa101176d649ee2b26e3616e88197d9488991bb2 ---- /dev/null -+++ b/asn1/asn1c/constr_SEQUENCE_OF.c -@@ -0,0 +1,208 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * The DER encoder of the SEQUENCE OF type. -+ */ -+asn_enc_rval_t -+SEQUENCE_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_TYPE_member_t *elm = td->elements; -+ asn_anonymous_sequence_ *list = _A_SEQUENCE_FROM_VOID(ptr); -+ size_t computed_size = 0; -+ ssize_t encoding_size = 0; -+ asn_enc_rval_t erval; -+ int edx; -+ -+ ASN_DEBUG("Estimating size of SEQUENCE OF %s", td->name); -+ -+ /* -+ * Gather the length of the underlying members sequence. -+ */ -+ for(edx = 0; edx < list->count; edx++) { -+ void *memb_ptr = list->array[edx]; -+ if(!memb_ptr) continue; -+ erval = elm->type->der_encoder(elm->type, memb_ptr, -+ 0, elm->tag, -+ 0, 0); -+ if(erval.encoded == -1) -+ return erval; -+ computed_size += erval.encoded; -+ } -+ -+ /* -+ * Encode the TLV for the sequence itself. -+ */ -+ encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, -+ cb, app_key); -+ if(encoding_size == -1) { -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = ptr; -+ return erval; -+ } -+ -+ computed_size += encoding_size; -+ if(!cb) { -+ erval.encoded = computed_size; -+ _ASN_ENCODED_OK(erval); -+ } -+ -+ ASN_DEBUG("Encoding members of SEQUENCE OF %s", td->name); -+ -+ /* -+ * Encode all members. -+ */ -+ for(edx = 0; edx < list->count; edx++) { -+ void *memb_ptr = list->array[edx]; -+ if(!memb_ptr) continue; -+ erval = elm->type->der_encoder(elm->type, memb_ptr, -+ 0, elm->tag, -+ cb, app_key); -+ if(erval.encoded == -1) -+ return erval; -+ encoding_size += erval.encoded; -+ } -+ -+ if(computed_size != (size_t)encoding_size) { -+ /* -+ * Encoded size is not equal to the computed size. -+ */ -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = ptr; -+ } else { -+ erval.encoded = computed_size; -+ erval.structure_ptr = 0; -+ erval.failed_type = 0; -+ } -+ -+ return erval; -+} -+ -+asn_enc_rval_t -+SEQUENCE_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t er; -+ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elm = td->elements; -+ asn_anonymous_sequence_ *list = _A_SEQUENCE_FROM_VOID(sptr); -+ const char *mname = specs->as_XMLValueList -+ ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); -+ unsigned int mlen = mname ? strlen(mname) : 0; -+ int xcan = (flags & XER_F_CANONICAL); -+ int i; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ -+ er.encoded = 0; -+ -+ for(i = 0; i < list->count; i++) { -+ asn_enc_rval_t tmper; -+ void *memb_ptr = list->array[i]; -+ if(!memb_ptr) continue; -+ -+ if(mname) { -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); -+ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); -+ } -+ -+ tmper = elm->type->xer_encoder(elm->type, memb_ptr, -+ ilevel + 1, flags, cb, app_key); -+ if(tmper.encoded == -1) return tmper; -+ if(tmper.encoded == 0 && specs->as_XMLValueList) { -+ const char *name = elm->type->xml_tag; -+ size_t len = strlen(name); -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel + 1); -+ _ASN_CALLBACK3("<", 1, name, len, "/>", 2); -+ } -+ -+ if(mname) { -+ _ASN_CALLBACK3("", 1); -+ er.encoded += 5; -+ } -+ -+ er.encoded += (2 * mlen) + tmper.encoded; -+ } -+ -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); -+ -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+asn_enc_rval_t -+SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { -+ asn_anonymous_sequence_ *list; -+ asn_per_constraint_t *ct; -+ asn_enc_rval_t er; -+ asn_TYPE_member_t *elm = td->elements; -+ int seq; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ list = _A_SEQUENCE_FROM_VOID(sptr); -+ -+ er.encoded = 0; -+ -+ ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count); -+ -+ if(constraints) ct = &constraints->size; -+ else if(td->per_constraints) ct = &td->per_constraints->size; -+ else ct = 0; -+ -+ /* If extensible constraint, check if size is in root */ -+ if(ct) { -+ int not_in_root = (list->count < ct->lower_bound -+ || list->count > ct->upper_bound); -+ ASN_DEBUG("lb %ld ub %ld %s", -+ ct->lower_bound, ct->upper_bound, -+ ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); -+ if(ct->flags & APC_EXTENSIBLE) { -+ /* Declare whether size is in extension root */ -+ if(per_put_few_bits(po, not_in_root, 1)) -+ _ASN_ENCODE_FAILED; -+ if(not_in_root) ct = 0; -+ } else if(not_in_root && ct->effective_bits >= 0) -+ _ASN_ENCODE_FAILED; -+ } -+ -+ if(ct && ct->effective_bits >= 0) { -+ /* X.691, #19.5: No length determinant */ -+ if(per_put_few_bits(po, list->count - ct->lower_bound, -+ ct->effective_bits)) -+ _ASN_ENCODE_FAILED; -+ } -+ -+ for(seq = -1; seq < list->count;) { -+ ssize_t mayEncode; -+ if(seq < 0) seq = 0; -+ if(ct && ct->effective_bits >= 0) { -+ mayEncode = list->count; -+ } else { -+ mayEncode = uper_put_length(po, list->count - seq); -+ if(mayEncode < 0) _ASN_ENCODE_FAILED; -+ } -+ -+ while(mayEncode--) { -+ void *memb_ptr = list->array[seq++]; -+ if(!memb_ptr) _ASN_ENCODE_FAILED; -+ er = elm->type->uper_encoder(elm->type, -+ elm->per_constraints, memb_ptr, po); -+ if(er.encoded == -1) -+ _ASN_ENCODE_FAILED; -+ } -+ } -+ -+ _ASN_ENCODED_OK(er); -+} -+ -diff --git a/asn1/asn1c/constr_SEQUENCE_OF.h b/asn1/asn1c/constr_SEQUENCE_OF.h -new file mode 100644 -index 0000000000000000000000000000000000000000..e2272f326ba1b961f3f0539c160481f9348b49da ---- /dev/null -+++ b/asn1/asn1c/constr_SEQUENCE_OF.h -@@ -0,0 +1,33 @@ -+/*- -+ * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _CONSTR_SEQUENCE_OF_H_ -+#define _CONSTR_SEQUENCE_OF_H_ -+ -+#include -+#include /* Implemented using SET OF */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * A set specialized functions dealing with the SEQUENCE OF type. -+ * Generally implemented using SET OF. -+ */ -+#define SEQUENCE_OF_free SET_OF_free -+#define SEQUENCE_OF_print SET_OF_print -+#define SEQUENCE_OF_constraint SET_OF_constraint -+#define SEQUENCE_OF_decode_ber SET_OF_decode_ber -+#define SEQUENCE_OF_decode_xer SET_OF_decode_xer -+#define SEQUENCE_OF_decode_uper SET_OF_decode_uper -+der_type_encoder_f SEQUENCE_OF_encode_der; -+xer_type_encoder_f SEQUENCE_OF_encode_xer; -+per_type_encoder_f SEQUENCE_OF_encode_uper; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _CONSTR_SET_OF_H_ */ -diff --git a/asn1/asn1c/constr_SET_OF.c b/asn1/asn1c/constr_SET_OF.c -new file mode 100644 -index 0000000000000000000000000000000000000000..09f27db53dada6869accd8dbb3aba0f56b49e00b ---- /dev/null -+++ b/asn1/asn1c/constr_SET_OF.c -@@ -0,0 +1,942 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * Number of bytes left for this structure. -+ * (ctx->left) indicates the number of bytes _transferred_ for the structure. -+ * (size) contains the number of bytes in the buffer passed. -+ */ -+#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) -+ -+/* -+ * If the subprocessor function returns with an indication that it wants -+ * more data, it may well be a fatal decoding problem, because the -+ * size is constrained by the 's L, even if the buffer size allows -+ * reading more data. -+ * For example, consider the buffer containing the following TLVs: -+ * ... -+ * The TLV length clearly indicates that one byte is expected in V, but -+ * if the V processor returns with "want more data" even if the buffer -+ * contains way more data than the V processor have seen. -+ */ -+#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) -+ -+/* -+ * This macro "eats" the part of the buffer which is definitely "consumed", -+ * i.e. was correctly converted into local representation or rightfully skipped. -+ */ -+#undef ADVANCE -+#define ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ ptr = ((const char *)ptr) + num;\ -+ size -= num; \ -+ if(ctx->left >= 0) \ -+ ctx->left -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+/* -+ * Switch to the next phase of parsing. -+ */ -+#undef NEXT_PHASE -+#undef PHASE_OUT -+#define NEXT_PHASE(ctx) do { \ -+ ctx->phase++; \ -+ ctx->step = 0; \ -+ } while(0) -+#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) -+ -+/* -+ * Return a standardized complex structure. -+ */ -+#undef RETURN -+#define RETURN(_code) do { \ -+ rval.code = _code; \ -+ rval.consumed = consumed_myself;\ -+ return rval; \ -+ } while(0) -+ -+/* -+ * The decoder of the SET OF type. -+ */ -+asn_dec_rval_t -+SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const void *ptr, size_t size, int tag_mode) { -+ /* -+ * Bring closer parts of structure description. -+ */ -+ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elm = td->elements; /* Single one */ -+ -+ /* -+ * Parts of the structure being constructed. -+ */ -+ void *st = *struct_ptr; /* Target structure. */ -+ asn_struct_ctx_t *ctx; /* Decoder context */ -+ -+ ber_tlv_tag_t tlv_tag; /* T from TLV */ -+ asn_dec_rval_t rval; /* Return code from subparsers */ -+ -+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ -+ -+ ASN_DEBUG("Decoding %s as SET OF", td->name); -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(st == 0) { -+ st = *struct_ptr = CALLOC(1, specs->struct_size); -+ if(st == 0) { -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * Restore parsing context. -+ */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ -+ /* -+ * Start to parse where left previously -+ */ -+ switch(ctx->phase) { -+ case 0: -+ /* -+ * PHASE 0. -+ * Check that the set of tags associated with given structure -+ * perfectly fits our expectations. -+ */ -+ -+ rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, -+ tag_mode, 1, &ctx->left, 0); -+ if(rval.code != RC_OK) { -+ ASN_DEBUG("%s tagging check failed: %d", -+ td->name, rval.code); -+ return rval; -+ } -+ -+ if(ctx->left >= 0) -+ ctx->left += rval.consumed; /* ?Substracted below! */ -+ ADVANCE(rval.consumed); -+ -+ ASN_DEBUG("Structure consumes %ld bytes, " -+ "buffer %ld", (long)ctx->left, (long)size); -+ -+ NEXT_PHASE(ctx); -+ /* Fall through */ -+ case 1: -+ /* -+ * PHASE 1. -+ * From the place where we've left it previously, -+ * try to decode the next item. -+ */ -+ for(;; ctx->step = 0) { -+ ssize_t tag_len; /* Length of TLV's T */ -+ -+ if(ctx->step & 1) -+ goto microphase2; -+ -+ /* -+ * MICROPHASE 1: Synchronize decoding. -+ */ -+ -+ if(ctx->left == 0) { -+ ASN_DEBUG("End of SET OF %s", td->name); -+ /* -+ * No more things to decode. -+ * Exit out of here. -+ */ -+ PHASE_OUT(ctx); -+ RETURN(RC_OK); -+ } -+ -+ /* -+ * Fetch the T from TLV. -+ */ -+ tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); -+ switch(tag_len) { -+ case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); -+ /* Fall through */ -+ case -1: RETURN(RC_FAIL); -+ } -+ -+ if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { -+ if(LEFT < 2) { -+ if(SIZE_VIOLATION) -+ RETURN(RC_FAIL); -+ else -+ RETURN(RC_WMORE); -+ } else if(((const uint8_t *)ptr)[1] == 0) { -+ /* -+ * Found the terminator of the -+ * indefinite length structure. -+ */ -+ break; -+ } -+ } -+ -+ /* Outmost tag may be unknown and cannot be fetched/compared */ -+ if(elm->tag != (ber_tlv_tag_t)-1) { -+ if(BER_TAGS_EQUAL(tlv_tag, elm->tag)) { -+ /* -+ * The new list member of expected type has arrived. -+ */ -+ } else { -+ ASN_DEBUG("Unexpected tag %s fixed SET OF %s", -+ ber_tlv_tag_string(tlv_tag), td->name); -+ ASN_DEBUG("%s SET OF has tag %s", -+ td->name, ber_tlv_tag_string(elm->tag)); -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ /* -+ * MICROPHASE 2: Invoke the member-specific decoder. -+ */ -+ ctx->step |= 1; /* Confirm entering next microphase */ -+ microphase2: -+ -+ /* -+ * Invoke the member fetch routine according to member's type -+ */ -+ rval = elm->type->ber_decoder(opt_codec_ctx, -+ elm->type, &ctx->ptr, ptr, LEFT, 0); -+ ASN_DEBUG("In %s SET OF %s code %d consumed %d", -+ td->name, elm->type->name, -+ rval.code, (int)rval.consumed); -+ switch(rval.code) { -+ case RC_OK: -+ { -+ asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); -+ if(ASN_SET_ADD(list, ctx->ptr) != 0) -+ RETURN(RC_FAIL); -+ else -+ ctx->ptr = 0; -+ } -+ break; -+ case RC_WMORE: /* More data expected */ -+ if(!SIZE_VIOLATION) { -+ ADVANCE(rval.consumed); -+ RETURN(RC_WMORE); -+ } -+ /* Fall through */ -+ case RC_FAIL: /* Fatal error */ -+ RETURN(RC_FAIL); -+ } /* switch(rval) */ -+ -+ ADVANCE(rval.consumed); -+ } /* for(all list members) */ -+ -+ NEXT_PHASE(ctx); -+ case 2: -+ /* -+ * Read in all "end of content" TLVs. -+ */ -+ while(ctx->left < 0) { -+ if(LEFT < 2) { -+ if(LEFT > 0 && ((const char *)ptr)[0] != 0) { -+ /* Unexpected tag */ -+ RETURN(RC_FAIL); -+ } else { -+ RETURN(RC_WMORE); -+ } -+ } -+ if(((const char *)ptr)[0] == 0 -+ && ((const char *)ptr)[1] == 0) { -+ ADVANCE(2); -+ ctx->left++; -+ } else { -+ RETURN(RC_FAIL); -+ } -+ } -+ -+ PHASE_OUT(ctx); -+ } -+ -+ RETURN(RC_OK); -+} -+ -+/* -+ * Internally visible buffer holding a single encoded element. -+ */ -+struct _el_buffer { -+ uint8_t *buf; -+ size_t length; -+ size_t size; -+}; -+/* Append bytes to the above structure */ -+static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) { -+ struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; -+ -+ if(el_buf->length + size > el_buf->size) -+ return -1; -+ -+ memcpy(el_buf->buf + el_buf->length, buffer, size); -+ -+ el_buf->length += size; -+ return 0; -+} -+static int _el_buf_cmp(const void *ap, const void *bp) { -+ const struct _el_buffer *a = (const struct _el_buffer *)ap; -+ const struct _el_buffer *b = (const struct _el_buffer *)bp; -+ int ret; -+ size_t common_len; -+ -+ if(a->length < b->length) -+ common_len = a->length; -+ else -+ common_len = b->length; -+ -+ ret = memcmp(a->buf, b->buf, common_len); -+ if(ret == 0) { -+ if(a->length < b->length) -+ ret = -1; -+ else if(a->length > b->length) -+ ret = 1; -+ } -+ -+ return ret; -+} -+ -+/* -+ * The DER encoder of the SET OF type. -+ */ -+asn_enc_rval_t -+SET_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, -+ int tag_mode, ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_TYPE_member_t *elm = td->elements; -+ asn_TYPE_descriptor_t *elm_type = elm->type; -+ der_type_encoder_f *der_encoder = elm_type->der_encoder; -+ asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); -+ size_t computed_size = 0; -+ ssize_t encoding_size = 0; -+ struct _el_buffer *encoded_els; -+ ssize_t eels_count = 0; -+ size_t max_encoded_len = 1; -+ asn_enc_rval_t erval; -+ int ret; -+ int edx; -+ -+ ASN_DEBUG("Estimating size for SET OF %s", td->name); -+ -+ /* -+ * Gather the length of the underlying members sequence. -+ */ -+ for(edx = 0; edx < list->count; edx++) { -+ void *memb_ptr = list->array[edx]; -+ if(!memb_ptr) continue; -+ erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, 0, 0); -+ if(erval.encoded == -1) -+ return erval; -+ computed_size += erval.encoded; -+ -+ /* Compute maximum encoding's size */ -+ if(max_encoded_len < (size_t)erval.encoded) -+ max_encoded_len = erval.encoded; -+ } -+ -+ /* -+ * Encode the TLV for the sequence itself. -+ */ -+ encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, -+ cb, app_key); -+ if(encoding_size == -1) { -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = ptr; -+ return erval; -+ } -+ computed_size += encoding_size; -+ -+ if(!cb || list->count == 0) { -+ erval.encoded = computed_size; -+ _ASN_ENCODED_OK(erval); -+ } -+ -+ /* -+ * DER mandates dynamic sorting of the SET OF elements -+ * according to their encodings. Build an array of the -+ * encoded elements. -+ */ -+ encoded_els = (struct _el_buffer *)MALLOC( -+ list->count * sizeof(encoded_els[0])); -+ if(encoded_els == NULL) { -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = ptr; -+ return erval; -+ } -+ -+ ASN_DEBUG("Encoding members of %s SET OF", td->name); -+ -+ /* -+ * Encode all members. -+ */ -+ for(edx = 0; edx < list->count; edx++) { -+ void *memb_ptr = list->array[edx]; -+ struct _el_buffer *encoded_el = &encoded_els[eels_count]; -+ -+ if(!memb_ptr) continue; -+ -+ /* -+ * Prepare space for encoding. -+ */ -+ encoded_el->buf = (uint8_t *)MALLOC(max_encoded_len); -+ if(encoded_el->buf) { -+ encoded_el->length = 0; -+ encoded_el->size = max_encoded_len; -+ } else { -+ for(edx--; edx >= 0; edx--) -+ FREEMEM(encoded_els[edx].buf); -+ FREEMEM(encoded_els); -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = ptr; -+ return erval; -+ } -+ -+ /* -+ * Encode the member into the prepared space. -+ */ -+ erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, -+ _el_addbytes, encoded_el); -+ if(erval.encoded == -1) { -+ for(; edx >= 0; edx--) -+ FREEMEM(encoded_els[edx].buf); -+ FREEMEM(encoded_els); -+ return erval; -+ } -+ encoding_size += erval.encoded; -+ eels_count++; -+ } -+ -+ /* -+ * Sort the encoded elements according to their encoding. -+ */ -+ qsort(encoded_els, eels_count, sizeof(encoded_els[0]), _el_buf_cmp); -+ -+ /* -+ * Report encoded elements to the application. -+ * Dispose of temporary sorted members table. -+ */ -+ ret = 0; -+ for(edx = 0; edx < eels_count; edx++) { -+ struct _el_buffer *encoded_el = &encoded_els[edx]; -+ /* Report encoded chunks to the application */ -+ if(ret == 0 -+ && cb(encoded_el->buf, encoded_el->length, app_key) < 0) -+ ret = -1; -+ FREEMEM(encoded_el->buf); -+ } -+ FREEMEM(encoded_els); -+ -+ if(ret || computed_size != (size_t)encoding_size) { -+ /* -+ * Standard callback failed, or -+ * encoded size is not equal to the computed size. -+ */ -+ erval.encoded = -1; -+ erval.failed_type = td; -+ erval.structure_ptr = ptr; -+ } else { -+ erval.encoded = computed_size; -+ } -+ -+ _ASN_ENCODED_OK(erval); -+} -+ -+#undef XER_ADVANCE -+#define XER_ADVANCE(num_bytes) do { \ -+ size_t num = num_bytes; \ -+ buf_ptr = ((const char *)buf_ptr) + num;\ -+ size -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+/* -+ * Decode the XER (XML) data. -+ */ -+asn_dec_rval_t -+SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const char *opt_mname, -+ const void *buf_ptr, size_t size) { -+ /* -+ * Bring closer parts of structure description. -+ */ -+ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; -+ asn_TYPE_member_t *element = td->elements; -+ const char *elm_tag; -+ const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; -+ -+ /* -+ * ... and parts of the structure being constructed. -+ */ -+ void *st = *struct_ptr; /* Target structure. */ -+ asn_struct_ctx_t *ctx; /* Decoder context */ -+ -+ asn_dec_rval_t rval; /* Return value from a decoder */ -+ ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(st == 0) { -+ st = *struct_ptr = CALLOC(1, specs->struct_size); -+ if(st == 0) RETURN(RC_FAIL); -+ } -+ -+ /* Which tag is expected for the downstream */ -+ if(specs->as_XMLValueList) { -+ elm_tag = (specs->as_XMLValueList == 1) ? 0 : ""; -+ } else { -+ elm_tag = (*element->name) -+ ? element->name : element->type->xml_tag; -+ } -+ -+ /* -+ * Restore parsing context. -+ */ -+ ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); -+ -+ /* -+ * Phases of XER/XML processing: -+ * Phase 0: Check that the opening tag matches our expectations. -+ * Phase 1: Processing body and reacting on closing tag. -+ * Phase 2: Processing inner type. -+ */ -+ for(; ctx->phase <= 2;) { -+ pxer_chunk_type_e ch_type; /* XER chunk type */ -+ ssize_t ch_size; /* Chunk size */ -+ xer_check_tag_e tcv; /* Tag check value */ -+ -+ /* -+ * Go inside the inner member of a set. -+ */ -+ if(ctx->phase == 2) { -+ asn_dec_rval_t tmprval; -+ -+ /* Invoke the inner type decoder, m.b. multiple times */ -+ ASN_DEBUG("XER/SET OF element [%s]", elm_tag); -+ tmprval = element->type->xer_decoder(opt_codec_ctx, -+ element->type, &ctx->ptr, elm_tag, -+ buf_ptr, size); -+ if(tmprval.code == RC_OK) { -+ asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); -+ if(ASN_SET_ADD(list, ctx->ptr) != 0) -+ RETURN(RC_FAIL); -+ ctx->ptr = 0; -+ XER_ADVANCE(tmprval.consumed); -+ } else { -+ XER_ADVANCE(tmprval.consumed); -+ RETURN(tmprval.code); -+ } -+ ctx->phase = 1; /* Back to body processing */ -+ ASN_DEBUG("XER/SET OF phase => %d", ctx->phase); -+ /* Fall through */ -+ } -+ -+ /* -+ * Get the next part of the XML stream. -+ */ -+ ch_size = xer_next_token(&ctx->context, -+ buf_ptr, size, &ch_type); -+ switch(ch_size) { -+ case -1: RETURN(RC_FAIL); -+ case 0: RETURN(RC_WMORE); -+ default: -+ switch(ch_type) { -+ case PXER_COMMENT: /* Got XML comment */ -+ case PXER_TEXT: /* Ignore free-standing text */ -+ XER_ADVANCE(ch_size); /* Skip silently */ -+ continue; -+ case PXER_TAG: -+ break; /* Check the rest down there */ -+ } -+ } -+ -+ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); -+ ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s", -+ tcv, ctx->phase, xml_tag); -+ switch(tcv) { -+ case XCT_CLOSING: -+ if(ctx->phase == 0) break; -+ ctx->phase = 0; -+ /* Fall through */ -+ case XCT_BOTH: -+ if(ctx->phase == 0) { -+ /* No more things to decode */ -+ XER_ADVANCE(ch_size); -+ ctx->phase = 3; /* Phase out */ -+ RETURN(RC_OK); -+ } -+ /* Fall through */ -+ case XCT_OPENING: -+ if(ctx->phase == 0) { -+ XER_ADVANCE(ch_size); -+ ctx->phase = 1; /* Processing body phase */ -+ continue; -+ } -+ /* Fall through */ -+ case XCT_UNKNOWN_OP: -+ case XCT_UNKNOWN_BO: -+ -+ ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase); -+ if(ctx->phase == 1) { -+ /* -+ * Process a single possible member. -+ */ -+ ctx->phase = 2; -+ continue; -+ } -+ /* Fall through */ -+ default: -+ break; -+ } -+ -+ ASN_DEBUG("Unexpected XML tag in SET OF"); -+ break; -+ } -+ -+ ctx->phase = 3; /* "Phase out" on hard failure */ -+ RETURN(RC_FAIL); -+} -+ -+ -+ -+typedef struct xer_tmp_enc_s { -+ void *buffer; -+ size_t offset; -+ size_t size; -+} xer_tmp_enc_t; -+static int -+SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) { -+ xer_tmp_enc_t *t = (xer_tmp_enc_t *)key; -+ if(t->offset + size >= t->size) { -+ size_t newsize = (t->size << 2) + size; -+ void *p = REALLOC(t->buffer, newsize); -+ if(!p) return -1; -+ t->buffer = p; -+ t->size = newsize; -+ } -+ memcpy((char *)t->buffer + t->offset, buffer, size); -+ t->offset += size; -+ return 0; -+} -+static int -+SET_OF_xer_order(const void *aptr, const void *bptr) { -+ const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr; -+ const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr; -+ size_t minlen = a->offset; -+ int ret; -+ if(b->offset < minlen) minlen = b->offset; -+ /* Well-formed UTF-8 has this nice lexicographical property... */ -+ ret = memcmp(a->buffer, b->buffer, minlen); -+ if(ret != 0) return ret; -+ if(a->offset == b->offset) -+ return 0; -+ if(a->offset == minlen) -+ return -1; -+ return 1; -+} -+ -+ -+asn_enc_rval_t -+SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, -+ int ilevel, enum xer_encoder_flags_e flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t er; -+ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elm = td->elements; -+ asn_anonymous_set_ *list = _A_SET_FROM_VOID(sptr); -+ const char *mname = specs->as_XMLValueList -+ ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); -+ size_t mlen = mname ? strlen(mname) : 0; -+ int xcan = (flags & XER_F_CANONICAL); -+ xer_tmp_enc_t *encs = 0; -+ size_t encs_count = 0; -+ void *original_app_key = app_key; -+ asn_app_consume_bytes_f *original_cb = cb; -+ int i; -+ -+ if(!sptr) _ASN_ENCODE_FAILED; -+ -+ if(xcan) { -+ encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0])); -+ if(!encs) _ASN_ENCODE_FAILED; -+ cb = SET_OF_encode_xer_callback; -+ } -+ -+ er.encoded = 0; -+ -+ for(i = 0; i < list->count; i++) { -+ asn_enc_rval_t tmper; -+ -+ void *memb_ptr = list->array[i]; -+ if(!memb_ptr) continue; -+ -+ if(encs) { -+ memset(&encs[encs_count], 0, sizeof(encs[0])); -+ app_key = &encs[encs_count]; -+ encs_count++; -+ } -+ -+ if(mname) { -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel); -+ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); -+ } -+ -+ if(!xcan && specs->as_XMLValueList == 1) -+ _i_ASN_TEXT_INDENT(1, ilevel + 1); -+ tmper = elm->type->xer_encoder(elm->type, memb_ptr, -+ ilevel + (specs->as_XMLValueList != 2), -+ flags, cb, app_key); -+ if(tmper.encoded == -1) { -+ td = tmper.failed_type; -+ sptr = tmper.structure_ptr; -+ goto cb_failed; -+ } -+ if(tmper.encoded == 0 && specs->as_XMLValueList) { -+ const char *name = elm->type->xml_tag; -+ size_t len = strlen(name); -+ _ASN_CALLBACK3("<", 1, name, len, "/>", 2); -+ } -+ -+ if(mname) { -+ _ASN_CALLBACK3("", 1); -+ er.encoded += 5; -+ } -+ -+ er.encoded += (2 * mlen) + tmper.encoded; -+ } -+ -+ if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1); -+ -+ if(encs) { -+ xer_tmp_enc_t *enc = encs; -+ xer_tmp_enc_t *end = encs + encs_count; -+ ssize_t control_size = 0; -+ -+ cb = original_cb; -+ app_key = original_app_key; -+ qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order); -+ -+ for(; enc < end; enc++) { -+ _ASN_CALLBACK(enc->buffer, enc->offset); -+ FREEMEM(enc->buffer); -+ enc->buffer = 0; -+ control_size += enc->offset; -+ } -+ assert(control_size == er.encoded); -+ } -+ -+ goto cleanup; -+cb_failed: -+ er.encoded = -1; -+ er.failed_type = td; -+ er.structure_ptr = sptr; -+cleanup: -+ if(encs) { -+ while(encs_count-- > 0) { -+ if(encs[encs_count].buffer) -+ FREEMEM(encs[encs_count].buffer); -+ } -+ FREEMEM(encs); -+ } -+ _ASN_ENCODED_OK(er); -+} -+ -+int -+SET_OF_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_TYPE_member_t *elm = td->elements; -+ const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); -+ int ret; -+ int i; -+ -+ if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; -+ -+ /* Dump preamble */ -+ if(cb(td->name, strlen(td->name), app_key) < 0 -+ || cb(" ::= {", 6, app_key) < 0) -+ return -1; -+ -+ for(i = 0; i < list->count; i++) { -+ const void *memb_ptr = list->array[i]; -+ if(!memb_ptr) continue; -+ -+ _i_INDENT(1); -+ -+ ret = elm->type->print_struct(elm->type, memb_ptr, -+ ilevel + 1, cb, app_key); -+ if(ret) return ret; -+ } -+ -+ ilevel--; -+ _i_INDENT(1); -+ -+ return (cb("}", 1, app_key) < 0) ? -1 : 0; -+} -+ -+void -+SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { -+ if(td && ptr) { -+ asn_TYPE_member_t *elm = td->elements; -+ asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); -+ int i; -+ -+ /* -+ * Could not use set_of_empty() because of (*free) -+ * incompatibility. -+ */ -+ for(i = 0; i < list->count; i++) { -+ void *memb_ptr = list->array[i]; -+ if(memb_ptr) -+ ASN_STRUCT_FREE(*elm->type, memb_ptr); -+ } -+ list->count = 0; /* No meaningful elements left */ -+ -+ asn_set_empty(list); /* Remove (list->array) */ -+ -+ if(!contents_only) { -+ FREEMEM(ptr); -+ } -+ } -+} -+ -+int -+SET_OF_constraint(asn_TYPE_descriptor_t *td, const void *sptr, -+ asn_app_constraint_failed_f *ctfailcb, void *app_key) { -+ asn_TYPE_member_t *elm = td->elements; -+ asn_constr_check_f *constr; -+ const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); -+ int i; -+ -+ if(!sptr) { -+ _ASN_CTFAIL(app_key, td, -+ "%s: value not given (%s:%d)", -+ td->name, __FILE__, __LINE__); -+ return -1; -+ } -+ -+ constr = elm->memb_constraints; -+ if(!constr) constr = elm->type->check_constraints; -+ -+ /* -+ * Iterate over the members of an array. -+ * Validate each in turn, until one fails. -+ */ -+ for(i = 0; i < list->count; i++) { -+ const void *memb_ptr = list->array[i]; -+ int ret; -+ -+ if(!memb_ptr) continue; -+ -+ ret = constr(elm->type, memb_ptr, ctfailcb, app_key); -+ if(ret) return ret; -+ } -+ -+ /* -+ * Cannot inherit it eralier: -+ * need to make sure we get the updated version. -+ */ -+ if(!elm->memb_constraints) -+ elm->memb_constraints = elm->type->check_constraints; -+ -+ return 0; -+} -+ -+asn_dec_rval_t -+SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { -+ asn_dec_rval_t rv; -+ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; -+ asn_TYPE_member_t *elm = td->elements; /* Single one */ -+ void *st = *sptr; -+ asn_anonymous_set_ *list; -+ asn_per_constraint_t *ct; -+ int repeat = 0; -+ ssize_t nelems; -+ -+ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) -+ _ASN_DECODE_FAILED; -+ -+ /* -+ * Create the target structure if it is not present already. -+ */ -+ if(!st) { -+ st = *sptr = CALLOC(1, specs->struct_size); -+ if(!st) _ASN_DECODE_FAILED; -+ } -+ list = _A_SET_FROM_VOID(st); -+ -+ /* Figure out which constraints to use */ -+ if(constraints) ct = &constraints->size; -+ else if(td->per_constraints) ct = &td->per_constraints->size; -+ else ct = 0; -+ -+ if(ct && ct->flags & APC_EXTENSIBLE) { -+ int value = per_get_few_bits(pd, 1); -+ if(value < 0) _ASN_DECODE_STARVED; -+ if(value) ct = 0; /* Not restricted! */ -+ } -+ -+ if(ct && ct->effective_bits >= 0) { -+ /* X.691, #19.5: No length determinant */ -+ nelems = per_get_few_bits(pd, ct->effective_bits); -+ ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", -+ (long)nelems, ct->lower_bound, td->name); -+ if(nelems < 0) _ASN_DECODE_STARVED; -+ nelems += ct->lower_bound; -+ } else { -+ nelems = -1; -+ } -+ -+ do { -+ int i; -+ if(nelems < 0) { -+ nelems = uper_get_length(pd, -+ ct ? ct->effective_bits : -1, &repeat); -+ ASN_DEBUG("Got to decode %d elements (eff %d)", -+ (int)nelems, (int)ct ? ct->effective_bits : -1); -+ if(nelems < 0) _ASN_DECODE_STARVED; -+ } -+ -+ for(i = 0; i < nelems; i++) { -+ void *ptr = 0; -+ ASN_DEBUG("SET OF %s decoding", elm->type->name); -+ rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, -+ elm->per_constraints, &ptr, pd); -+ ASN_DEBUG("%s SET OF %s decoded %d, %p", -+ td->name, elm->type->name, rv.code, ptr); -+ if(rv.code == RC_OK) { -+ if(ASN_SET_ADD(list, ptr) == 0) -+ continue; -+ ASN_DEBUG("Failed to add element into %s", -+ td->name); -+ /* Fall through */ -+ rv.code == RC_FAIL; -+ } else { -+ ASN_DEBUG("Failed decoding %s of %s (SET OF)", -+ elm->type->name, td->name); -+ } -+ if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); -+ return rv; -+ } -+ -+ nelems = -1; /* Allow uper_get_length() */ -+ } while(repeat); -+ -+ ASN_DEBUG("Decoded %s as SET OF", td->name); -+ -+ rv.code = RC_OK; -+ rv.consumed = 0; -+ return rv; -+} -+ -diff --git a/asn1/asn1c/constr_SET_OF.h b/asn1/asn1c/constr_SET_OF.h -new file mode 100644 -index 0000000000000000000000000000000000000000..bcd09662906b69e5ac5cfec82c8a47b47ab3f351 ---- /dev/null -+++ b/asn1/asn1c/constr_SET_OF.h -@@ -0,0 +1,42 @@ -+/*- -+ * Copyright (c) 2003 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _CONSTR_SET_OF_H_ -+#define _CONSTR_SET_OF_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef struct asn_SET_OF_specifics_s { -+ /* -+ * Target structure description. -+ */ -+ int struct_size; /* Size of the target structure. */ -+ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ -+ -+ /* XER-specific stuff */ -+ int as_XMLValueList; /* The member type must be encoded like this */ -+} asn_SET_OF_specifics_t; -+ -+/* -+ * A set specialized functions dealing with the SET OF type. -+ */ -+asn_struct_free_f SET_OF_free; -+asn_struct_print_f SET_OF_print; -+asn_constr_check_f SET_OF_constraint; -+ber_type_decoder_f SET_OF_decode_ber; -+der_type_encoder_f SET_OF_encode_der; -+xer_type_decoder_f SET_OF_decode_xer; -+xer_type_encoder_f SET_OF_encode_xer; -+per_type_decoder_f SET_OF_decode_uper; -+per_type_encoder_f SET_OF_encode_uper; -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _CONSTR_SET_OF_H_ */ -diff --git a/asn1/asn1c/constr_TYPE.c b/asn1/asn1c/constr_TYPE.c -new file mode 100644 -index 0000000000000000000000000000000000000000..4bc88d44f3c54131da0696b60050bd26376ce5b4 ---- /dev/null -+++ b/asn1/asn1c/constr_TYPE.c -@@ -0,0 +1,77 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * Version of the ASN.1 infrastructure shipped with compiler. -+ */ -+int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; } -+ -+static asn_app_consume_bytes_f _print2fp; -+ -+/* -+ * Return the outmost tag of the type. -+ */ -+ber_tlv_tag_t -+asn_TYPE_outmost_tag(asn_TYPE_descriptor_t *type_descriptor, -+ const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { -+ -+ if(tag_mode) -+ return tag; -+ -+ if(type_descriptor->tags_count) -+ return type_descriptor->tags[0]; -+ -+ return type_descriptor->outmost_tag(type_descriptor, struct_ptr, 0, 0); -+} -+ -+/* -+ * Print the target language's structure in human readable form. -+ */ -+int -+asn_fprint(FILE *stream, asn_TYPE_descriptor_t *td, const void *struct_ptr) { -+ if(!stream) stream = stdout; -+ if(!td || !struct_ptr) { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ /* Invoke type-specific printer */ -+ if(td->print_struct(td, struct_ptr, 1, _print2fp, stream)) -+ return -1; -+ -+ /* Terminate the output */ -+ if(_print2fp("\n", 1, stream)) -+ return -1; -+ -+ return fflush(stream); -+} -+ -+/* Dump the data into the specified stdio stream */ -+static int -+_print2fp(const void *buffer, size_t size, void *app_key) { -+ FILE *stream = (FILE *)app_key; -+ -+ if(fwrite(buffer, 1, size, stream) != size) -+ return -1; -+ -+ return 0; -+} -+ -+ -+/* -+ * Some compilers do not support variable args macros. -+ * This function is a replacement of ASN_DEBUG() macro. -+ */ -+void ASN_DEBUG_f(const char *fmt, ...); -+void ASN_DEBUG_f(const char *fmt, ...) { -+ va_list ap; -+ va_start(ap, fmt); -+ vfprintf(stderr, fmt, ap); -+ fprintf(stderr, "\n"); -+ va_end(ap); -+} -diff --git a/asn1/asn1c/constr_TYPE.h b/asn1/asn1c/constr_TYPE.h -new file mode 100644 -index 0000000000000000000000000000000000000000..95507c8097b840457eafb95e1bae4abcff6a3e22 ---- /dev/null -+++ b/asn1/asn1c/constr_TYPE.h -@@ -0,0 +1,180 @@ -+/*- -+ * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+/* -+ * This file contains the declaration structure called "ASN.1 Type Definition", -+ * which holds all information necessary for encoding and decoding routines. -+ * This structure even contains pointer to these encoding and decoding routines -+ * for each defined ASN.1 type. -+ */ -+#ifndef _CONSTR_TYPE_H_ -+#define _CONSTR_TYPE_H_ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+struct asn_TYPE_member_s; /* Forward declaration */ -+ -+/* -+ * This type provides the context information for various ASN.1 routines, -+ * primarily ones doing decoding. A member _asn_ctx of this type must be -+ * included into certain target language's structures, such as compound types. -+ */ -+typedef struct asn_struct_ctx_s { -+ short phase; /* Decoding phase */ -+ short step; /* Elementary step of a phase */ -+ int context; /* Other context information */ -+ void *ptr; /* Decoder-specific stuff (stack elements) */ -+ ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ -+} asn_struct_ctx_t; -+ -+#include /* Basic Encoding Rules decoder */ -+#include /* Distinguished Encoding Rules encoder */ -+#include /* Decoder of XER (XML, text) */ -+#include /* Encoder into XER (XML, text) */ -+#include /* Packet Encoding Rules decoder */ -+#include /* Packet Encoding Rules encoder */ -+#include /* Subtype constraints support */ -+ -+/* -+ * Free the structure according to its specification. -+ * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) -+ * will not be freed. (It may be useful in case the structure is allocated -+ * statically or arranged on the stack, yet its elements are allocated -+ * dynamically.) -+ */ -+typedef void (asn_struct_free_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, int free_contents_only); -+#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) -+#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ -+ (asn_DEF).free_struct(&(asn_DEF),ptr,1) -+ -+/* -+ * Print the structure according to its specification. -+ */ -+typedef int (asn_struct_print_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ const void *struct_ptr, -+ int level, /* Indentation level */ -+ asn_app_consume_bytes_f *callback, void *app_key); -+ -+/* -+ * Return the outmost tag of the type. -+ * If the type is untagged CHOICE, the dynamic operation is performed. -+ * NOTE: This function pointer type is only useful internally. -+ * Do not use it in your application. -+ */ -+typedef ber_tlv_tag_t (asn_outmost_tag_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); -+/* The instance of the above function type; used internally. */ -+asn_outmost_tag_f asn_TYPE_outmost_tag; -+ -+ -+/* -+ * The definitive description of the destination language's structure. -+ */ -+typedef struct asn_TYPE_descriptor_s { -+ char *name; /* A name of the ASN.1 type. "" in some cases. */ -+ char *xml_tag; /* Name used in XML tag */ -+ -+ /* -+ * Generalized functions for dealing with the specific type. -+ * May be directly invoked by applications. -+ */ -+ asn_struct_free_f *free_struct; /* Free the structure */ -+ asn_struct_print_f *print_struct; /* Human readable output */ -+ asn_constr_check_f *check_constraints; /* Constraints validator */ -+ ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ -+ der_type_encoder_f *der_encoder; /* Canonical DER encoder */ -+ xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ -+ xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ -+ per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ -+ per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ -+ -+ /*********************************************************************** -+ * Internally useful members. Not to be used by applications directly. * -+ **********************************************************************/ -+ -+ /* -+ * Tags that are expected to occur. -+ */ -+ asn_outmost_tag_f *outmost_tag; /* */ -+ ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ -+ int tags_count; /* Number of tags which are expected */ -+ ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ -+ int all_tags_count; /* Number of tags */ -+ -+ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ -+ -+ /* -+ * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). -+ */ -+ struct asn_TYPE_member_s *elements; -+ int elements_count; -+ -+ /* -+ * Additional information describing the type, used by appropriate -+ * functions above. -+ */ -+ void *specifics; -+} asn_TYPE_descriptor_t; -+ -+/* -+ * This type describes an element of the constructed type, -+ * i.e. SEQUENCE, SET, CHOICE, etc. -+ */ -+ enum asn_TYPE_flags_e { -+ ATF_NOFLAGS, -+ ATF_POINTER = 0x01, /* Represented by the pointer */ -+ ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ -+ }; -+typedef struct asn_TYPE_member_s { -+ enum asn_TYPE_flags_e flags; /* Element's presentation flags */ -+ int optional; /* Following optional members, including current */ -+ int memb_offset; /* Offset of the element */ -+ ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ -+ int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ -+ asn_TYPE_descriptor_t *type; /* Member type descriptor */ -+ asn_constr_check_f *memb_constraints; /* Constraints validator */ -+ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ -+ int (*default_value)(int setval, void **sptr); /* DEFAULT */ -+ char *name; /* ASN.1 identifier of the element */ -+} asn_TYPE_member_t; -+ -+/* -+ * BER tag to element number mapping. -+ */ -+typedef struct asn_TYPE_tag2member_s { -+ ber_tlv_tag_t el_tag; /* Outmost tag of the member */ -+ int el_no; /* Index of the associated member, base 0 */ -+ int toff_first; /* First occurence of the el_tag, relative */ -+ int toff_last; /* Last occurence of the el_tag, relatvie */ -+} asn_TYPE_tag2member_t; -+ -+/* -+ * This function is a wrapper around (td)->print_struct, which prints out -+ * the contents of the target language's structure (struct_ptr) into the -+ * file pointer (stream) in human readable form. -+ * RETURN VALUES: -+ * 0: The structure is printed. -+ * -1: Problem dumping the structure. -+ * (See also xer_fprint() in xer_encoder.h) -+ */ -+int asn_fprint(FILE *stream, /* Destination stream descriptor */ -+ asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ -+ const void *struct_ptr); /* Structure to be printed */ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _CONSTR_TYPE_H_ */ -diff --git a/asn1/asn1c/constraints.c b/asn1/asn1c/constraints.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1bdda73e5d68cba8311e3fda444fd86d20865d2d ---- /dev/null -+++ b/asn1/asn1c/constraints.c -@@ -0,0 +1,93 @@ -+#include "asn_internal.h" -+#include "constraints.h" -+ -+int -+asn_generic_no_constraint(asn_TYPE_descriptor_t *type_descriptor, -+ const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { -+ -+ (void)type_descriptor; /* Unused argument */ -+ (void)struct_ptr; /* Unused argument */ -+ (void)cb; /* Unused argument */ -+ (void)key; /* Unused argument */ -+ -+ /* Nothing to check */ -+ return 0; -+} -+ -+int -+asn_generic_unknown_constraint(asn_TYPE_descriptor_t *type_descriptor, -+ const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { -+ -+ (void)type_descriptor; /* Unused argument */ -+ (void)struct_ptr; /* Unused argument */ -+ (void)cb; /* Unused argument */ -+ (void)key; /* Unused argument */ -+ -+ /* Unknown how to check */ -+ return 0; -+} -+ -+struct errbufDesc { -+ asn_TYPE_descriptor_t *failed_type; -+ const void *failed_struct_ptr; -+ char *errbuf; -+ size_t errlen; -+}; -+ -+static void -+_asn_i_ctfailcb(void *key, asn_TYPE_descriptor_t *td, const void *sptr, const char *fmt, ...) { -+ struct errbufDesc *arg = key; -+ va_list ap; -+ ssize_t vlen; -+ ssize_t maxlen; -+ -+ arg->failed_type = td; -+ arg->failed_struct_ptr = sptr; -+ -+ maxlen = arg->errlen; -+ if(maxlen <= 0) -+ return; -+ -+ va_start(ap, fmt); -+ vlen = vsnprintf(arg->errbuf, maxlen, fmt, ap); -+ va_end(ap); -+ if(vlen >= maxlen) { -+ arg->errbuf[maxlen-1] = '\0'; /* Ensuring libc correctness */ -+ arg->errlen = maxlen - 1; /* Not counting termination */ -+ return; -+ } else if(vlen >= 0) { -+ arg->errbuf[vlen] = '\0'; /* Ensuring libc correctness */ -+ arg->errlen = vlen; /* Not counting termination */ -+ } else { -+ /* -+ * The libc on this system is broken. -+ */ -+ vlen = sizeof("") - 1; -+ maxlen--; -+ arg->errlen = vlen < maxlen ? vlen : maxlen; -+ memcpy(arg->errbuf, "", arg->errlen); -+ arg->errbuf[arg->errlen] = 0; -+ } -+ -+ return; -+} -+ -+int -+asn_check_constraints(asn_TYPE_descriptor_t *type_descriptor, -+ const void *struct_ptr, char *errbuf, size_t *errlen) { -+ struct errbufDesc arg; -+ int ret; -+ -+ arg.failed_type = 0; -+ arg.failed_struct_ptr = 0; -+ arg.errbuf = errbuf; -+ arg.errlen = errlen ? *errlen : 0; -+ -+ ret = type_descriptor->check_constraints(type_descriptor, -+ struct_ptr, _asn_i_ctfailcb, &arg); -+ if(ret == -1 && errlen) -+ *errlen = arg.errlen; -+ -+ return ret; -+} -+ -diff --git a/asn1/asn1c/constraints.h b/asn1/asn1c/constraints.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5032345ee475564eeea0240bf73d76ae41139f6f ---- /dev/null -+++ b/asn1/asn1c/constraints.h -@@ -0,0 +1,63 @@ -+/*- -+ * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _ASN1_CONSTRAINTS_VALIDATOR_H_ -+#define _ASN1_CONSTRAINTS_VALIDATOR_H_ -+ -+#include /* Platform-dependent types */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* -+ * Validate the structure according to the ASN.1 constraints. -+ * If errbuf and errlen are given, they shall be pointing to the appropriate -+ * buffer space and its length before calling this function. Alternatively, -+ * they could be passed as NULL's. If constraints validation fails, -+ * errlen will contain the actual number of bytes taken from the errbuf -+ * to encode an error message (properly 0-terminated). -+ * -+ * RETURN VALUES: -+ * This function returns 0 in case all ASN.1 constraints are met -+ * and -1 if one or more constraints were failed. -+ */ -+int -+asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, -+ const void *struct_ptr, /* Target language's structure */ -+ char *errbuf, /* Returned error description */ -+ size_t *errlen /* Length of the error description */ -+ ); -+ -+ -+/* -+ * Generic type for constraint checking callback, -+ * associated with every type descriptor. -+ */ -+typedef int (asn_constr_check_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ const void *struct_ptr, -+ asn_app_constraint_failed_f *optional_callback, /* Log the error */ -+ void *optional_app_key /* Opaque key passed to a callback */ -+ ); -+ -+/******************************* -+ * INTERNALLY USEFUL FUNCTIONS * -+ *******************************/ -+ -+asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ -+asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ -+ -+/* -+ * Invoke the callback with a complete error message. -+ */ -+#define _ASN_CTFAIL if(ctfailcb) ctfailcb -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _ASN1_CONSTRAINTS_VALIDATOR_H_ */ -diff --git a/asn1/asn1c/der_encoder.c b/asn1/asn1c/der_encoder.c -new file mode 100644 -index 0000000000000000000000000000000000000000..6c859e1b08bba9600c97970df2fceede5716ddc0 ---- /dev/null -+++ b/asn1/asn1c/der_encoder.c -@@ -0,0 +1,199 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+ -+static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, -+ asn_app_consume_bytes_f *cb, void *app_key, int constructed); -+ -+/* -+ * The DER encoder of any type. -+ */ -+asn_enc_rval_t -+der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, -+ asn_app_consume_bytes_f *consume_bytes, void *app_key) { -+ -+ ASN_DEBUG("DER encoder invoked for %s", -+ type_descriptor->name); -+ -+ /* -+ * Invoke type-specific encoder. -+ */ -+ return type_descriptor->der_encoder(type_descriptor, -+ struct_ptr, /* Pointer to the destination structure */ -+ 0, 0, -+ consume_bytes, app_key); -+} -+ -+/* -+ * Argument type and callback necessary for der_encode_to_buffer(). -+ */ -+typedef struct enc_to_buf_arg { -+ void *buffer; -+ size_t left; -+} enc_to_buf_arg; -+static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { -+ enc_to_buf_arg *arg = (enc_to_buf_arg *)key; -+ -+ if(arg->left < size) -+ return -1; /* Data exceeds the available buffer size */ -+ -+ memcpy(arg->buffer, buffer, size); -+ arg->buffer = ((char *)arg->buffer) + size; -+ arg->left -= size; -+ -+ return 0; -+} -+ -+/* -+ * A variant of the der_encode() which encodes the data into the provided buffer -+ */ -+asn_enc_rval_t -+der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, -+ void *buffer, size_t buffer_size) { -+ enc_to_buf_arg arg; -+ asn_enc_rval_t ec; -+ -+ arg.buffer = buffer; -+ arg.left = buffer_size; -+ -+ ec = type_descriptor->der_encoder(type_descriptor, -+ struct_ptr, /* Pointer to the destination structure */ -+ 0, 0, encode_to_buffer_cb, &arg); -+ if(ec.encoded != -1) { -+ assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); -+ /* Return the encoded contents size */ -+ } -+ return ec; -+} -+ -+ -+/* -+ * Write out leading TL[v] sequence according to the type definition. -+ */ -+ssize_t -+der_write_tags(asn_TYPE_descriptor_t *sd, -+ size_t struct_length, -+ int tag_mode, int last_tag_form, -+ ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ -+ asn_app_consume_bytes_f *cb, -+ void *app_key) { -+ ber_tlv_tag_t *tags; /* Copy of tags stream */ -+ int tags_count; /* Number of tags */ -+ size_t overall_length; -+ ssize_t *lens; -+ int i; -+ -+ ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)", -+ sd->name, tag_mode, sd->tags_count, -+ ber_tlv_tag_string(tag), -+ tag_mode -+ ?(sd->tags_count+1 -+ -((tag_mode == -1) && sd->tags_count)) -+ :sd->tags_count -+ ); -+ -+ if(tag_mode) { -+ /* -+ * Instead of doing shaman dance like we do in ber_check_tags(), -+ * allocate a small array on the stack -+ * and initialize it appropriately. -+ */ -+ int stag_offset; -+ tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); -+ if(!tags) { /* Can fail on !x86 */ -+ errno = ENOMEM; -+ return -1; -+ } -+ tags_count = sd->tags_count -+ + 1 /* EXPLICIT or IMPLICIT tag is given */ -+ - ((tag_mode == -1) && sd->tags_count); -+ /* Copy tags over */ -+ tags[0] = tag; -+ stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); -+ for(i = 1; i < tags_count; i++) -+ tags[i] = sd->tags[i + stag_offset]; -+ } else { -+ tags = sd->tags; -+ tags_count = sd->tags_count; -+ } -+ -+ /* No tags to write */ -+ if(tags_count == 0) -+ return 0; -+ -+ lens = (ssize_t *)alloca(tags_count * sizeof(lens[0])); -+ if(!lens) { -+ errno = ENOMEM; -+ return -1; -+ } -+ -+ /* -+ * Array of tags is initialized. -+ * Now, compute the size of the TLV pairs, from right to left. -+ */ -+ overall_length = struct_length; -+ for(i = tags_count - 1; i >= 0; --i) { -+ lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0); -+ if(lens[i] == -1) return -1; -+ overall_length += lens[i]; -+ lens[i] = overall_length - lens[i]; -+ } -+ -+ if(!cb) return overall_length - struct_length; -+ -+ ASN_DEBUG("%s %s TL sequence (%d elements)", -+ cb?"Encoding":"Estimating", sd->name, tags_count); -+ -+ /* -+ * Encode the TL sequence for real. -+ */ -+ for(i = 0; i < tags_count; i++) { -+ ssize_t len; -+ int _constr; -+ -+ /* Check if this tag happens to be constructed */ -+ _constr = (last_tag_form || i < (tags_count - 1)); -+ -+ len = der_write_TL(tags[i], lens[i], cb, app_key, _constr); -+ if(len == -1) return -1; -+ } -+ -+ return overall_length - struct_length; -+} -+ -+static ssize_t -+der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, -+ asn_app_consume_bytes_f *cb, void *app_key, -+ int constructed) { -+ uint8_t buf[32]; -+ size_t size = 0; -+ int buf_size = cb?sizeof(buf):0; -+ ssize_t tmp; -+ -+ /* Serialize tag (T from TLV) into possibly zero-length buffer */ -+ tmp = ber_tlv_tag_serialize(tag, buf, buf_size); -+ if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1; -+ size += tmp; -+ -+ /* Serialize length (L from TLV) into possibly zero-length buffer */ -+ tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0); -+ if(tmp == -1) return -1; -+ size += tmp; -+ -+ if(size > sizeof(buf)) -+ return -1; -+ -+ /* -+ * If callback is specified, invoke it, and check its return value. -+ */ -+ if(cb) { -+ if(constructed) *buf |= 0x20; -+ if(cb(buf, size, app_key) < 0) -+ return -1; -+ } -+ -+ return size; -+} -diff --git a/asn1/asn1c/der_encoder.h b/asn1/asn1c/der_encoder.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4e2fb06c28194510c6434f4829e56b2436d8f092 ---- /dev/null -+++ b/asn1/asn1c/der_encoder.h -@@ -0,0 +1,67 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _DER_ENCODER_H_ -+#define _DER_ENCODER_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* -+ * The DER encoder of any type. May be invoked by the application. -+ */ -+asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ asn_app_consume_bytes_f *consume_bytes_cb, -+ void *app_key /* Arbitrary callback argument */ -+ ); -+ -+/* A variant of der_encode() which encodes data into the pre-allocated buffer */ -+asn_enc_rval_t der_encode_to_buffer( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ void *buffer, /* Pre-allocated buffer */ -+ size_t buffer_size /* Initial buffer size (maximum) */ -+ ); -+ -+/* -+ * Type of the generic DER encoder. -+ */ -+typedef asn_enc_rval_t (der_type_encoder_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ -+ ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ -+ void *app_key /* Arbitrary callback argument */ -+ ); -+ -+ -+/******************************* -+ * INTERNALLY USEFUL FUNCTIONS * -+ *******************************/ -+ -+/* -+ * Write out leading TL[v] sequence according to the type definition. -+ */ -+ssize_t der_write_tags( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ size_t struct_length, -+ int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ -+ int last_tag_form, /* {0,!0}: prim, constructed */ -+ ber_tlv_tag_t tag, -+ asn_app_consume_bytes_f *consume_bytes_cb, -+ void *app_key -+ ); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _DER_ENCODER_H_ */ -diff --git a/asn1/asn1c/ipa.asn1 b/asn1/asn1c/ipa.asn1 -new file mode 100644 -index 0000000000000000000000000000000000000000..a18488ed371de7270afe7a0a9b345217205a2873 ---- /dev/null -+++ b/asn1/asn1c/ipa.asn1 -@@ -0,0 +1,37 @@ -+KeytabModule DEFINITIONS ::= BEGIN -+ -+ Int32 ::= INTEGER (-2147483648..2147483647) -+ -- signed values representable in 32 bits (from RFC4120) -+ -+ GetKeytabControl ::= CHOICE { -+ newkeys [0] GKNewKeys, -+ curkeys [1] GKCurrentKeys, -+ reply [2] GKReply -+ } -+ -+ GKNewKeys ::= SEQUENCE { -+ serviceIdentity [0] OCTET STRING, -+ enctypes [1] SEQUENCE OF Int32, -+ password [2] OCTET STRING OPTIONAL -+ } -+ -+ GKCurrentKeys ::= SEQUENCE { -+ serviceIdentity [0] OCTET STRING -+ } -+ -+ GKReply ::= SEQUENCE { -+ newkvno Int32, -+ keys SEQUENCE OF KrbKey -+ } -+ -+ KrbKey ::= SEQUENCE { -+ key [0] TypeValuePair, -+ salt [1] TypeValuePair OPTIONAL, -+ s2kparams [2] OCTET STRING OPTIONAL -+ } -+ -+ TypeValuePair ::= SEQUENCE { -+ type [0] Int32, -+ value [1] OCTET STRING -+ } -+END -diff --git a/asn1/asn1c/per_decoder.c b/asn1/asn1c/per_decoder.c -new file mode 100644 -index 0000000000000000000000000000000000000000..16dee369624bbf28bb8957e222abe77059980d9f ---- /dev/null -+++ b/asn1/asn1c/per_decoder.c -@@ -0,0 +1,55 @@ -+#include -+#include -+#include -+ -+asn_dec_rval_t -+uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { -+ asn_codec_ctx_t s_codec_ctx; -+ asn_dec_rval_t rval; -+ asn_per_data_t pd; -+ -+ if(skip_bits < 0 || skip_bits > 7 -+ || unused_bits < 0 || unused_bits > 7 -+ || (unused_bits > 0 && !size)) -+ _ASN_DECODE_FAILED; -+ -+ /* -+ * Stack checker requires that the codec context -+ * must be allocated on the stack. -+ */ -+ if(opt_codec_ctx) { -+ if(opt_codec_ctx->max_stack_size) { -+ s_codec_ctx = *opt_codec_ctx; -+ opt_codec_ctx = &s_codec_ctx; -+ } -+ } else { -+ /* If context is not given, be security-conscious anyway */ -+ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); -+ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; -+ opt_codec_ctx = &s_codec_ctx; -+ } -+ -+ /* Fill in the position indicator */ -+ pd.buffer = (const uint8_t *)buffer; -+ pd.nboff = skip_bits; -+ pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ -+ if(pd.nboff > pd.nbits) -+ _ASN_DECODE_FAILED; -+ -+ /* -+ * Invoke type-specific decoder. -+ */ -+ if(!td->uper_decoder) -+ _ASN_DECODE_FAILED; /* PER is not compiled in */ -+ rval = td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd); -+ if(rval.code == RC_OK) { -+ /* Return the number of consumed bits */ -+ rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) -+ + pd.nboff - skip_bits; -+ } else { -+ /* PER codec is not a restartable */ -+ rval.consumed = 0; -+ } -+ return rval; -+} -+ -diff --git a/asn1/asn1c/per_decoder.h b/asn1/asn1c/per_decoder.h -new file mode 100644 -index 0000000000000000000000000000000000000000..26aaf59400445aff62fb007370fc35c0cfa9b1b2 ---- /dev/null -+++ b/asn1/asn1c/per_decoder.h -@@ -0,0 +1,44 @@ -+/*- -+ * Copyright (c) 2005 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _PER_DECODER_H_ -+#define _PER_DECODER_H_ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* -+ * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. -+ */ -+asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, -+ struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ -+ void **struct_ptr, /* Pointer to a target structure's pointer */ -+ const void *buffer, /* Data to be decoded */ -+ size_t size, /* Size of data buffer */ -+ int skip_bits, /* Number of unused leading bits, 0..7 */ -+ int unused_bits /* Number of unused tailing bits, 0..7 */ -+ ); -+ -+ -+/* -+ * Type of the type-specific PER decoder function. -+ */ -+typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ asn_per_constraints_t *constraints, -+ void **struct_ptr, -+ asn_per_data_t *per_data -+ ); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _PER_DECODER_H_ */ -diff --git a/asn1/asn1c/per_encoder.c b/asn1/asn1c/per_encoder.c -new file mode 100644 -index 0000000000000000000000000000000000000000..614dd23331d482a05b973f790449359e7f503768 ---- /dev/null -+++ b/asn1/asn1c/per_encoder.c -@@ -0,0 +1,95 @@ -+#include -+#include -+#include -+ -+/* Flush partially filled buffer */ -+static int _uper_encode_flush_outp(asn_per_outp_t *po); -+ -+asn_enc_rval_t -+uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_per_outp_t po; -+ asn_enc_rval_t er; -+ -+ /* -+ * Invoke type-specific encoder. -+ */ -+ if(!td || !td->uper_encoder) -+ _ASN_ENCODE_FAILED; /* PER is not compiled in */ -+ -+ po.buffer = po.tmpspace; -+ po.nboff = 0; -+ po.nbits = 8 * sizeof(po.tmpspace); -+ po.outper = cb; -+ po.op_key = app_key; -+ po.flushed_bytes = 0; -+ -+ er = td->uper_encoder(td, 0, sptr, &po); -+ if(er.encoded != -1) { -+ size_t bits_to_flush; -+ -+ bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; -+ -+ /* Set number of bits encoded to a firm value */ -+ er.encoded = (po.flushed_bytes << 3) + bits_to_flush; -+ -+ if(_uper_encode_flush_outp(&po)) -+ _ASN_ENCODE_FAILED; -+ } -+ -+ return er; -+} -+ -+/* -+ * Argument type and callback necessary for uper_encode_to_buffer(). -+ */ -+typedef struct enc_to_buf_arg { -+ void *buffer; -+ size_t left; -+} enc_to_buf_arg; -+static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { -+ enc_to_buf_arg *arg = (enc_to_buf_arg *)key; -+ -+ if(arg->left < size) -+ return -1; /* Data exceeds the available buffer size */ -+ -+ memcpy(arg->buffer, buffer, size); -+ arg->buffer = ((char *)arg->buffer) + size; -+ arg->left -= size; -+ -+ return 0; -+} -+ -+asn_enc_rval_t -+uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { -+ enc_to_buf_arg key; -+ -+ /* -+ * Invoke type-specific encoder. -+ */ -+ if(!td || !td->uper_encoder) -+ _ASN_ENCODE_FAILED; /* PER is not compiled in */ -+ -+ key.buffer = buffer; -+ key.left = buffer_size; -+ -+ ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); -+ -+ return uper_encode(td, sptr, encode_to_buffer_cb, &key); -+} -+ -+static int -+_uper_encode_flush_outp(asn_per_outp_t *po) { -+ uint8_t *buf; -+ -+ if(po->nboff == 0 && po->buffer == po->tmpspace) -+ return 0; -+ -+ buf = po->buffer + (po->nboff >> 3); -+ /* Make sure we account for the last, partially filled */ -+ if(po->nboff & 0x07) { -+ buf[0] &= 0xff << (8 - (po->nboff & 0x07)); -+ buf++; -+ } -+ -+ return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); -+} -diff --git a/asn1/asn1c/per_encoder.h b/asn1/asn1c/per_encoder.h -new file mode 100644 -index 0000000000000000000000000000000000000000..9ac130b7373cc354effd24058027ea85ca3a9e59 ---- /dev/null -+++ b/asn1/asn1c/per_encoder.h -@@ -0,0 +1,49 @@ -+/*- -+ * Copyright (c) 2006 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _PER_ENCODER_H_ -+#define _PER_ENCODER_H_ -+ -+#include -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* -+ * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. -+ */ -+asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ -+ void *app_key /* Arbitrary callback argument */ -+); -+ -+/* A variant of uper_encode() which encodes data into the existing buffer */ -+asn_enc_rval_t uper_encode_to_buffer( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ void *buffer, /* Pre-allocated buffer */ -+ size_t buffer_size /* Initial buffer size (max) */ -+); -+ -+ -+/* -+ * Type of the generic PER encoder function. -+ */ -+typedef asn_enc_rval_t (per_type_encoder_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ asn_per_constraints_t *constraints, -+ void *struct_ptr, -+ asn_per_outp_t *per_output -+); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _PER_ENCODER_H_ */ -diff --git a/asn1/asn1c/per_support.c b/asn1/asn1c/per_support.c -new file mode 100644 -index 0000000000000000000000000000000000000000..c83441931caf1fcc3a79c0062014833db3d141b5 ---- /dev/null -+++ b/asn1/asn1c/per_support.c -@@ -0,0 +1,318 @@ -+/* -+ * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * Extract a small number of bits (<= 31) from the specified PER data pointer. -+ */ -+int32_t -+per_get_few_bits(asn_per_data_t *pd, int nbits) { -+ size_t off; /* Next after last bit offset */ -+ uint32_t accum; -+ const uint8_t *buf; -+ -+ if(nbits < 0 || pd->nboff + nbits > pd->nbits) -+ return -1; -+ -+ ASN_DEBUG("[PER get %d bits from %p+%d bits]", -+ nbits, pd->buffer, pd->nboff); -+ -+ /* -+ * Normalize position indicator. -+ */ -+ if(pd->nboff >= 8) { -+ pd->buffer += (pd->nboff >> 3); -+ pd->nbits -= (pd->nboff & ~0x07); -+ pd->nboff &= 0x07; -+ } -+ off = (pd->nboff += nbits); -+ buf = pd->buffer; -+ -+ /* -+ * Extract specified number of bits. -+ */ -+ if(off <= 8) -+ accum = nbits ? (buf[0]) >> (8 - off) : 0; -+ else if(off <= 16) -+ accum = ((buf[0] << 8) + buf[1]) >> (16 - off); -+ else if(off <= 24) -+ accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); -+ else if(off <= 31) -+ accum = ((buf[0] << 24) + (buf[1] << 16) -+ + (buf[2] << 8) + (buf[3])) >> (32 - off); -+ else if(nbits <= 31) { -+ asn_per_data_t tpd = *pd; -+ /* Here are we with our 31-bits limit plus 1..7 bits offset. */ -+ tpd.nboff -= nbits; -+ accum = per_get_few_bits(&tpd, nbits - 24) << 24; -+ accum |= per_get_few_bits(&tpd, 24); -+ } else { -+ pd->nboff -= nbits; /* Oops, revert back */ -+ return -1; -+ } -+ -+ return (accum & (((uint32_t)1 << nbits) - 1)); -+} -+ -+/* -+ * Extract a large number of bits from the specified PER data pointer. -+ */ -+int -+per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { -+ int32_t value; -+ -+ if(alright && (nbits & 7)) { -+ /* Perform right alignment of a first few bits */ -+ value = per_get_few_bits(pd, nbits & 0x07); -+ if(value < 0) return -1; -+ *dst++ = value; /* value is already right-aligned */ -+ nbits &= ~7; -+ } -+ -+ while(nbits) { -+ if(nbits >= 24) { -+ value = per_get_few_bits(pd, 24); -+ if(value < 0) return -1; -+ *(dst++) = value >> 16; -+ *(dst++) = value >> 8; -+ *(dst++) = value; -+ nbits -= 24; -+ } else { -+ value = per_get_few_bits(pd, nbits); -+ if(value < 0) return -1; -+ if(nbits & 7) { /* implies left alignment */ -+ value <<= 8 - (nbits & 7), -+ nbits += 8 - (nbits & 7); -+ if(nbits > 24) -+ *dst++ = value >> 24; -+ } -+ if(nbits > 16) -+ *dst++ = value >> 16; -+ if(nbits > 8) -+ *dst++ = value >> 8; -+ *dst++ = value; -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Get the length "n" from the stream. -+ */ -+ssize_t -+uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { -+ ssize_t value; -+ -+ *repeat = 0; -+ -+ if(ebits >= 0) return per_get_few_bits(pd, ebits); -+ -+ value = per_get_few_bits(pd, 8); -+ if(value < 0) return -1; -+ if((value & 128) == 0) /* #10.9.3.6 */ -+ return (value & 0x7F); -+ if((value & 64) == 0) { /* #10.9.3.7 */ -+ value = ((value & 63) << 8) | per_get_few_bits(pd, 8); -+ if(value < 0) return -1; -+ return value; -+ } -+ value &= 63; /* this is "m" from X.691, #10.9.3.8 */ -+ if(value < 1 || value > 4) -+ return -1; -+ *repeat = 1; -+ return (16384 * value); -+} -+ -+/* -+ * Get the normally small non-negative whole number. -+ * X.691, #10.6 -+ */ -+ssize_t -+uper_get_nsnnwn(asn_per_data_t *pd) { -+ ssize_t value; -+ -+ value = per_get_few_bits(pd, 7); -+ if(value & 64) { /* implicit (value < 0) */ -+ value &= 63; -+ value <<= 2; -+ value |= per_get_few_bits(pd, 2); -+ if(value & 128) /* implicit (value < 0) */ -+ return -1; -+ if(value == 0) -+ return 0; -+ if(value >= 3) -+ return -1; -+ value = per_get_few_bits(pd, 8 * value); -+ return value; -+ } -+ -+ return value; -+} -+ -+/* -+ * Put the normally small non-negative whole number. -+ * X.691, #10.6 -+ */ -+int -+uper_put_nsnnwn(asn_per_outp_t *po, int n) { -+ int bytes; -+ -+ if(n <= 63) { -+ if(n < 0) return -1; -+ return per_put_few_bits(po, n, 7); -+ } -+ if(n < 256) -+ bytes = 1; -+ else if(n < 65536) -+ bytes = 2; -+ else if(n < 256 * 65536) -+ bytes = 3; -+ else -+ return -1; /* This is not a "normally small" value */ -+ if(per_put_few_bits(po, bytes, 8)) -+ return -1; -+ -+ return per_put_few_bits(po, n, 8 * bytes); -+} -+ -+ -+/* -+ * Put a small number of bits (<= 31). -+ */ -+int -+per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { -+ size_t off; /* Next after last bit offset */ -+ size_t omsk; /* Existing last byte meaningful bits mask */ -+ uint8_t *buf; -+ -+ if(obits <= 0 || obits >= 32) return obits ? -1 : 0; -+ -+ ASN_DEBUG("[PER put %d bits to %p+%d bits]", -+ obits, po->buffer, po->nboff); -+ -+ /* -+ * Normalize position indicator. -+ */ -+ if(po->nboff >= 8) { -+ po->buffer += (po->nboff >> 3); -+ po->nbits -= (po->nboff & ~0x07); -+ po->nboff &= 0x07; -+ } -+ -+ /* -+ * Flush whole-bytes output, if necessary. -+ */ -+ if(po->nboff + obits > po->nbits) { -+ int complete_bytes = (po->buffer - po->tmpspace); -+ if(po->outper(po->buffer, complete_bytes, po->op_key) < 0) -+ return -1; -+ if(po->nboff) -+ po->tmpspace[0] = po->buffer[0]; -+ po->buffer = po->tmpspace; -+ po->nbits = 8 * sizeof(po->tmpspace); -+ po->flushed_bytes += complete_bytes; -+ } -+ -+ /* -+ * Now, due to sizeof(tmpspace), we are guaranteed large enough space. -+ */ -+ buf = po->buffer; -+ omsk = ~((1 << (8 - po->nboff)) - 1); -+ off = (po->nboff += obits); -+ -+ /* Clear data of debris before meaningful bits */ -+ bits &= (((uint32_t)1 << obits) - 1); -+ -+ ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, bits, bits, -+ po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); -+ -+ if(off <= 8) /* Completely within 1 byte */ -+ bits <<= (8 - off), -+ buf[0] = (buf[0] & omsk) | bits; -+ else if(off <= 16) -+ bits <<= (16 - off), -+ buf[0] = (buf[0] & omsk) | (bits >> 8), -+ buf[1] = bits; -+ else if(off <= 24) -+ bits <<= (24 - off), -+ buf[0] = (buf[0] & omsk) | (bits >> 16), -+ buf[1] = bits >> 8, -+ buf[2] = bits; -+ else if(off <= 31) -+ bits <<= (32 - off), -+ buf[0] = (buf[0] & omsk) | (bits >> 24), -+ buf[1] = bits >> 16, -+ buf[2] = bits >> 8, -+ buf[3] = bits; -+ else { -+ ASN_DEBUG("->[PER out split %d]", obits); -+ per_put_few_bits(po, bits >> 8, 24); -+ per_put_few_bits(po, bits, obits - 24); -+ ASN_DEBUG("<-[PER out split %d]", obits); -+ } -+ -+ ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", -+ bits, bits, buf[0], po->buffer - po->tmpspace); -+ -+ return 0; -+} -+ -+ -+/* -+ * Output a large number of bits. -+ */ -+int -+per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { -+ -+ while(nbits) { -+ uint32_t value; -+ -+ if(nbits >= 24) { -+ value = (src[0] << 16) | (src[1] << 8) | src[2]; -+ src += 3; -+ nbits -= 24; -+ if(per_put_few_bits(po, value, 24)) -+ return -1; -+ } else { -+ value = src[0]; -+ if(nbits > 8) -+ value = (value << 8) | src[1]; -+ if(nbits > 16) -+ value = (value << 8) | src[2]; -+ if(nbits & 0x07) -+ value >>= (8 - (nbits & 0x07)); -+ if(per_put_few_bits(po, value, nbits)) -+ return -1; -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Put the length "n" (or part of it) into the stream. -+ */ -+ssize_t -+uper_put_length(asn_per_outp_t *po, size_t length) { -+ -+ if(length <= 127) /* #10.9.3.6 */ -+ return per_put_few_bits(po, length, 8) -+ ? -1 : (ssize_t)length; -+ else if(length < 16384) /* #10.9.3.7 */ -+ return per_put_few_bits(po, length|0x8000, 16) -+ ? -1 : (ssize_t)length; -+ -+ length >>= 14; -+ if(length > 4) length = 4; -+ -+ return per_put_few_bits(po, 0xC0 | length, 8) -+ ? -1 : (ssize_t)(length << 14); -+} -+ -diff --git a/asn1/asn1c/per_support.h b/asn1/asn1c/per_support.h -new file mode 100644 -index 0000000000000000000000000000000000000000..420bb83c58d081ba3949951b67709e3200e7192a ---- /dev/null -+++ b/asn1/asn1c/per_support.h -@@ -0,0 +1,105 @@ -+/* -+ * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _PER_SUPPORT_H_ -+#define _PER_SUPPORT_H_ -+ -+#include /* Platform-specific types */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * Pre-computed PER constraints. -+ */ -+typedef struct asn_per_constraint_s { -+ enum asn_per_constraint_flags { -+ APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ -+ APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ -+ APC_CONSTRAINED = 0x2, /* Fully constrained */ -+ APC_EXTENSIBLE = 0x4 /* May have extension */ -+ } flags; -+ int range_bits; /* Full number of bits in the range */ -+ int effective_bits; /* Effective bits */ -+ long lower_bound; /* "lb" value */ -+ long upper_bound; /* "ub" value */ -+} asn_per_constraint_t; -+typedef struct asn_per_constraints_s { -+ asn_per_constraint_t value; -+ asn_per_constraint_t size; -+} asn_per_constraints_t; -+ -+/* -+ * This structure describes a position inside an incoming PER bit stream. -+ */ -+typedef struct asn_per_data_s { -+ const uint8_t *buffer; /* Pointer to the octet stream */ -+ size_t nboff; /* Bit offset to the meaningful bit */ -+ size_t nbits; /* Number of bits in the stream */ -+} asn_per_data_t; -+ -+/* -+ * Extract a small number of bits (<= 31) from the specified PER data pointer. -+ * This function returns -1 if the specified number of bits could not be -+ * extracted due to EOD or other conditions. -+ */ -+int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); -+ -+/* -+ * Extract a large number of bits from the specified PER data pointer. -+ * This function returns -1 if the specified number of bits could not be -+ * extracted due to EOD or other conditions. -+ */ -+int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, -+ int get_nbits); -+ -+/* -+ * Get the length "n" from the Unaligned PER stream. -+ */ -+ssize_t uper_get_length(asn_per_data_t *pd, -+ int effective_bound_bits, -+ int *repeat); -+ -+/* -+ * Get the normally small non-negative whole number. -+ */ -+ssize_t uper_get_nsnnwn(asn_per_data_t *pd); -+ -+/* -+ * This structure supports forming PER output. -+ */ -+typedef struct asn_per_outp_s { -+ uint8_t *buffer; /* Pointer into the (tmpspace) */ -+ size_t nboff; /* Bit offset to the meaningful bit */ -+ size_t nbits; /* Number of bits left in (tmpspace) */ -+ uint8_t tmpspace[32]; /* Preliminary storage to hold data */ -+ int (*outper)(const void *data, size_t size, void *op_key); -+ void *op_key; /* Key for (outper) data callback */ -+ size_t flushed_bytes; /* Bytes already flushed through (outper) */ -+} asn_per_outp_t; -+ -+/* Output a small number of bits (<= 31) */ -+int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); -+ -+/* Output a large number of bits */ -+int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); -+ -+/* -+ * Put the length "n" to the Unaligned PER stream. -+ * This function returns the number of units which may be flushed -+ * in the next units saving iteration. -+ */ -+ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); -+ -+/* -+ * Put the normally small non-negative whole number. -+ */ -+int uper_put_nsnnwn(asn_per_outp_t *po, int n); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _PER_SUPPORT_H_ */ -diff --git a/asn1/asn1c/xer_decoder.c b/asn1/asn1c/xer_decoder.c -new file mode 100644 -index 0000000000000000000000000000000000000000..161dc78ce5320368d07c0cd9b01032d07997e0fb ---- /dev/null -+++ b/asn1/asn1c/xer_decoder.c -@@ -0,0 +1,363 @@ -+/* -+ * Copyright (c) 2004, 2005 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include /* XER/XML parsing support */ -+ -+ -+/* -+ * Decode the XER encoding of a given type. -+ */ -+asn_dec_rval_t -+xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, -+ void **struct_ptr, const void *buffer, size_t size) { -+ asn_codec_ctx_t s_codec_ctx; -+ -+ /* -+ * Stack checker requires that the codec context -+ * must be allocated on the stack. -+ */ -+ if(opt_codec_ctx) { -+ if(opt_codec_ctx->max_stack_size) { -+ s_codec_ctx = *opt_codec_ctx; -+ opt_codec_ctx = &s_codec_ctx; -+ } -+ } else { -+ /* If context is not given, be security-conscious anyway */ -+ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); -+ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; -+ opt_codec_ctx = &s_codec_ctx; -+ } -+ -+ /* -+ * Invoke type-specific decoder. -+ */ -+ return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size); -+} -+ -+ -+ -+struct xer__cb_arg { -+ pxml_chunk_type_e chunk_type; -+ size_t chunk_size; -+ const void *chunk_buf; -+ int callback_not_invoked; -+}; -+ -+static int -+xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) { -+ struct xer__cb_arg *arg = (struct xer__cb_arg *)key; -+ arg->chunk_type = type; -+ arg->chunk_size = _chunk_size; -+ arg->chunk_buf = _chunk_data; -+ arg->callback_not_invoked = 0; -+ return -1; /* Terminate the XML parsing */ -+} -+ -+/* -+ * Fetch the next token from the XER/XML stream. -+ */ -+ssize_t -+xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) { -+ struct xer__cb_arg arg; -+ int new_stateContext = *stateContext; -+ ssize_t ret; -+ -+ arg.callback_not_invoked = 1; -+ ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg); -+ if(ret < 0) return -1; -+ if(arg.callback_not_invoked) { -+ assert(ret == 0); /* No data was consumed */ -+ return 0; /* Try again with more data */ -+ } else { -+ assert(arg.chunk_size); -+ assert(arg.chunk_buf == buffer); -+ } -+ -+ /* -+ * Translate the XML chunk types into more convenient ones. -+ */ -+ switch(arg.chunk_type) { -+ case PXML_TEXT: -+ *ch_type = PXER_TEXT; -+ break; -+ case PXML_TAG: return 0; /* Want more */ -+ case PXML_TAG_END: -+ *ch_type = PXER_TAG; -+ break; -+ case PXML_COMMENT: -+ case PXML_COMMENT_END: -+ *ch_type = PXER_COMMENT; -+ break; -+ } -+ -+ *stateContext = new_stateContext; -+ return arg.chunk_size; -+} -+ -+#define CSLASH 0x2f /* '/' */ -+#define LANGLE 0x3c /* '<' */ -+#define RANGLE 0x3e /* '>' */ -+ -+xer_check_tag_e -+xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { -+ const char *buf = (const char *)buf_ptr; -+ const char *end; -+ xer_check_tag_e ct = XCT_OPENING; -+ -+ if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { -+ if(size >= 2) -+ ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]); -+ return XCT_BROKEN; -+ } -+ -+ /* -+ * Determine the tag class. -+ */ -+ if(buf[1] == CSLASH) { -+ buf += 2; /* advance past "" */ -+ ct = XCT_CLOSING; -+ if(size > 0 && buf[size-1] == CSLASH) -+ return XCT_BROKEN; /* */ -+ } else { -+ buf++; /* advance past "<" */ -+ size -= 2; /* strip "<" and ">" */ -+ if(size > 0 && buf[size-1] == CSLASH) { -+ ct = XCT_BOTH; -+ size--; /* One more, for "/" */ -+ } -+ } -+ -+ /* Sometimes we don't care about the tag */ -+ if(!need_tag || !*need_tag) -+ return (xer_check_tag_e)(XCT__UNK__MASK | ct); -+ -+ /* -+ * Determine the tag name. -+ */ -+ for(end = buf + size; buf < end; buf++, need_tag++) { -+ int b = *buf, n = *need_tag; -+ if(b != n) { -+ if(n == 0) { -+ switch(b) { -+ case 0x09: case 0x0a: case 0x0c: case 0x0d: -+ case 0x20: -+ /* "": whitespace is normal */ -+ return ct; -+ } -+ } -+ return (xer_check_tag_e)(XCT__UNK__MASK | ct); -+ } -+ if(b == 0) -+ return XCT_BROKEN; /* Embedded 0 in buf?! */ -+ } -+ if(*need_tag) -+ return (xer_check_tag_e)(XCT__UNK__MASK | ct); -+ -+ return ct; -+} -+ -+ -+#undef ADVANCE -+#define ADVANCE(num_bytes) do { \ -+ size_t num = (num_bytes); \ -+ buf_ptr = ((const char *)buf_ptr) + num; \ -+ size -= num; \ -+ consumed_myself += num; \ -+ } while(0) -+ -+#undef RETURN -+#define RETURN(_code) do { \ -+ rval.code = _code; \ -+ rval.consumed = consumed_myself; \ -+ if(rval.code != RC_OK) \ -+ ASN_DEBUG("Failed with %d", rval.code); \ -+ return rval; \ -+ } while(0) -+ -+#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ -+ ssize_t converted_size = body_receiver \ -+ (struct_key, chunk_buf, chunk_size, \ -+ (size_t)chunk_size < size); \ -+ if(converted_size == -1) RETURN(RC_FAIL); \ -+ if(converted_size == 0 \ -+ && size == (size_t)chunk_size) \ -+ RETURN(RC_WMORE); \ -+ chunk_size = converted_size; \ -+ } while(0) -+#define XER_GOT_EMPTY() do { \ -+ if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ -+ RETURN(RC_FAIL); \ -+ } while(0) -+ -+/* -+ * Generalized function for decoding the primitive values. -+ */ -+asn_dec_rval_t -+xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, -+ asn_struct_ctx_t *ctx, /* Type decoder context */ -+ void *struct_key, -+ const char *xml_tag, /* Expected XML tag */ -+ const void *buf_ptr, size_t size, -+ int (*opt_unexpected_tag_decoder) -+ (void *struct_key, const void *chunk_buf, size_t chunk_size), -+ ssize_t (*body_receiver) -+ (void *struct_key, const void *chunk_buf, size_t chunk_size, -+ int have_more) -+ ) { -+ -+ asn_dec_rval_t rval; -+ ssize_t consumed_myself = 0; -+ -+ (void)opt_codec_ctx; -+ -+ /* -+ * Phases of XER/XML processing: -+ * Phase 0: Check that the opening tag matches our expectations. -+ * Phase 1: Processing body and reacting on closing tag. -+ */ -+ if(ctx->phase > 1) RETURN(RC_FAIL); -+ for(;;) { -+ pxer_chunk_type_e ch_type; /* XER chunk type */ -+ ssize_t ch_size; /* Chunk size */ -+ xer_check_tag_e tcv; /* Tag check value */ -+ -+ /* -+ * Get the next part of the XML stream. -+ */ -+ ch_size = xer_next_token(&ctx->context, buf_ptr, size, -+ &ch_type); -+ switch(ch_size) { -+ case -1: RETURN(RC_FAIL); -+ case 0: -+ RETURN(RC_WMORE); -+ default: -+ switch(ch_type) { -+ case PXER_COMMENT: /* Got XML comment */ -+ ADVANCE(ch_size); /* Skip silently */ -+ continue; -+ case PXER_TEXT: -+ if(ctx->phase == 0) { -+ /* -+ * We have to ignore whitespace here, -+ * but in order to be forward compatible -+ * with EXTENDED-XER (EMBED-VALUES, #25) -+ * any text is just ignored here. -+ */ -+ } else { -+ XER_GOT_BODY(buf_ptr, ch_size, size); -+ } -+ ADVANCE(ch_size); -+ continue; -+ case PXER_TAG: -+ break; /* Check the rest down there */ -+ } -+ } -+ -+ assert(ch_type == PXER_TAG && size); -+ -+ tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); -+ /* -+ * Phase 0: -+ * Expecting the opening tag -+ * for the type being processed. -+ * Phase 1: -+ * Waiting for the closing XML tag. -+ */ -+ switch(tcv) { -+ case XCT_BOTH: -+ if(ctx->phase) break; -+ /* Finished decoding of an empty element */ -+ XER_GOT_EMPTY(); -+ ADVANCE(ch_size); -+ ctx->phase = 2; /* Phase out */ -+ RETURN(RC_OK); -+ case XCT_OPENING: -+ if(ctx->phase) break; -+ ADVANCE(ch_size); -+ ctx->phase = 1; /* Processing body phase */ -+ continue; -+ case XCT_CLOSING: -+ if(!ctx->phase) break; -+ ADVANCE(ch_size); -+ ctx->phase = 2; /* Phase out */ -+ RETURN(RC_OK); -+ case XCT_UNKNOWN_BO: -+ /* -+ * Certain tags in the body may be expected. -+ */ -+ if(opt_unexpected_tag_decoder -+ && opt_unexpected_tag_decoder(struct_key, -+ buf_ptr, ch_size) >= 0) { -+ /* Tag's processed fine */ -+ ADVANCE(ch_size); -+ if(!ctx->phase) { -+ /* We are not expecting -+ * the closing tag anymore. */ -+ ctx->phase = 2; /* Phase out */ -+ RETURN(RC_OK); -+ } -+ continue; -+ } -+ /* Fall through */ -+ default: -+ break; /* Unexpected tag */ -+ } -+ -+ ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag); -+ break; /* Dark and mysterious things have just happened */ -+ } -+ -+ RETURN(RC_FAIL); -+} -+ -+ -+int -+xer_is_whitespace(const void *chunk_buf, size_t chunk_size) { -+ const char *p = (const char *)chunk_buf; -+ const char *pend = p + chunk_size; -+ -+ for(; p < pend; p++) { -+ switch(*p) { -+ /* X.693, #8.1.4 -+ * HORISONTAL TAB (9) -+ * LINE FEED (10) -+ * CARRIAGE RETURN (13) -+ * SPACE (32) -+ */ -+ case 0x09: case 0x0a: case 0x0d: case 0x20: -+ break; -+ default: -+ return 0; -+ } -+ } -+ return 1; /* All whitespace */ -+} -+ -+/* -+ * This is a vastly simplified, non-validating XML tree skipper. -+ */ -+int -+xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) { -+ assert(*depth > 0); -+ switch(tcv) { -+ case XCT_BOTH: -+ case XCT_UNKNOWN_BO: -+ /* These negate each other. */ -+ return 0; -+ case XCT_OPENING: -+ case XCT_UNKNOWN_OP: -+ ++(*depth); -+ return 0; -+ case XCT_CLOSING: -+ case XCT_UNKNOWN_CL: -+ if(--(*depth) == 0) -+ return (tcv == XCT_CLOSING) ? 2 : 1; -+ return 0; -+ default: -+ return -1; -+ } -+} -diff --git a/asn1/asn1c/xer_decoder.h b/asn1/asn1c/xer_decoder.h -new file mode 100644 -index 0000000000000000000000000000000000000000..cf0d846fe72d66d0c03548e9f6f4b2c3ecab716d ---- /dev/null -+++ b/asn1/asn1c/xer_decoder.h -@@ -0,0 +1,106 @@ -+/*- -+ * Copyright (c) 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _XER_DECODER_H_ -+#define _XER_DECODER_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* -+ * The XER decoder of any ASN.1 type. May be invoked by the application. -+ */ -+asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void **struct_ptr, /* Pointer to a target structure's pointer */ -+ const void *buffer, /* Data to be decoded */ -+ size_t size /* Size of data buffer */ -+ ); -+ -+/* -+ * Type of the type-specific XER decoder function. -+ */ -+typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void **struct_ptr, -+ const char *opt_mname, /* Member name */ -+ const void *buf_ptr, size_t size -+ ); -+ -+/******************************* -+ * INTERNALLY USEFUL FUNCTIONS * -+ *******************************/ -+ -+/* -+ * Generalized function for decoding the primitive values. -+ * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 -+ * and others. This function should not be used by applications, as its API -+ * is subject to changes. -+ */ -+asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, -+ asn_struct_ctx_t *ctx, /* Type decoder context */ -+ void *struct_key, /* Treated as opaque pointer */ -+ const char *xml_tag, /* Expected XML tag name */ -+ const void *buf_ptr, size_t size, -+ int (*opt_unexpected_tag_decoder) -+ (void *struct_key, const void *chunk_buf, size_t chunk_size), -+ ssize_t (*body_receiver) -+ (void *struct_key, const void *chunk_buf, size_t chunk_size, -+ int have_more) -+ ); -+ -+ -+/* -+ * Fetch the next XER (XML) token from the stream. -+ * The function returns the number of bytes occupied by the chunk type, -+ * returned in the _ch_type. The _ch_type is only set (and valid) when -+ * the return value is greater than 0. -+ */ -+ typedef enum pxer_chunk_type { -+ PXER_TAG, /* Complete XER tag */ -+ PXER_TEXT, /* Plain text between XER tags */ -+ PXER_COMMENT /* A comment, may be part of */ -+ } pxer_chunk_type_e; -+ssize_t xer_next_token(int *stateContext, -+ const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); -+ -+/* -+ * This function checks the buffer against the tag name is expected to occur. -+ */ -+ typedef enum xer_check_tag { -+ XCT_BROKEN = 0, /* The tag is broken */ -+ XCT_OPENING = 1, /* This is the tag */ -+ XCT_CLOSING = 2, /* This is the tag */ -+ XCT_BOTH = 3, /* This is the tag */ -+ XCT__UNK__MASK = 4, /* Mask of everything unexpected */ -+ XCT_UNKNOWN_OP = 5, /* Unexpected tag */ -+ XCT_UNKNOWN_CL = 6, /* Unexpected tag */ -+ XCT_UNKNOWN_BO = 7 /* Unexpected tag */ -+ } xer_check_tag_e; -+xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, -+ const char *need_tag); -+ -+/* -+ * Check whether this buffer consists of entirely XER whitespace characters. -+ * RETURN VALUES: -+ * 1: Whitespace or empty string -+ * 0: Non-whitespace -+ */ -+int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); -+ -+/* -+ * Skip the series of anticipated extensions. -+ */ -+int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _XER_DECODER_H_ */ -diff --git a/asn1/asn1c/xer_encoder.c b/asn1/asn1c/xer_encoder.c -new file mode 100644 -index 0000000000000000000000000000000000000000..aa7cf040ad874dc1f8bfd8e353c3061b71493fdb ---- /dev/null -+++ b/asn1/asn1c/xer_encoder.c -@@ -0,0 +1,67 @@ -+/*- -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+#include -+ -+/* -+ * The XER encoder of any type. May be invoked by the application. -+ */ -+asn_enc_rval_t -+xer_encode(asn_TYPE_descriptor_t *td, void *sptr, -+ enum xer_encoder_flags_e xer_flags, -+ asn_app_consume_bytes_f *cb, void *app_key) { -+ asn_enc_rval_t er, tmper; -+ const char *mname; -+ size_t mlen; -+ int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; -+ -+ if(!td || !sptr) goto cb_failed; -+ -+ mname = td->xml_tag; -+ mlen = strlen(mname); -+ -+ _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); -+ -+ tmper = td->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); -+ if(tmper.encoded == -1) return tmper; -+ -+ _ASN_CALLBACK3("\n", xcan); -+ -+ er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; -+ -+ _ASN_ENCODED_OK(er); -+cb_failed: -+ _ASN_ENCODE_FAILED; -+} -+ -+/* -+ * This is a helper function for xer_fprint, which directs all incoming data -+ * into the provided file descriptor. -+ */ -+static int -+xer__print2fp(const void *buffer, size_t size, void *app_key) { -+ FILE *stream = (FILE *)app_key; -+ -+ if(fwrite(buffer, 1, size, stream) != size) -+ return -1; -+ -+ return 0; -+} -+ -+int -+xer_fprint(FILE *stream, asn_TYPE_descriptor_t *td, void *sptr) { -+ asn_enc_rval_t er; -+ -+ if(!stream) stream = stdout; -+ if(!td || !sptr) -+ return -1; -+ -+ er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); -+ if(er.encoded == -1) -+ return -1; -+ -+ return fflush(stream); -+} -diff --git a/asn1/asn1c/xer_encoder.h b/asn1/asn1c/xer_encoder.h -new file mode 100644 -index 0000000000000000000000000000000000000000..055e73c0c8b0dfd330c8d3f80c6d2b02270b3100 ---- /dev/null -+++ b/asn1/asn1c/xer_encoder.h -@@ -0,0 +1,59 @@ -+/*- -+ * Copyright (c) 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _XER_ENCODER_H_ -+#define _XER_ENCODER_H_ -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+struct asn_TYPE_descriptor_s; /* Forward declaration */ -+ -+/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ -+enum xer_encoder_flags_e { -+ /* Mode of encoding */ -+ XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ -+ XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ -+}; -+ -+/* -+ * The XER encoder of any type. May be invoked by the application. -+ */ -+asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ enum xer_encoder_flags_e xer_flags, -+ asn_app_consume_bytes_f *consume_bytes_cb, -+ void *app_key /* Arbitrary callback argument */ -+ ); -+ -+/* -+ * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) -+ * output into the chosen file pointer. -+ * RETURN VALUES: -+ * 0: The structure is printed. -+ * -1: Problem printing the structure. -+ * WARNING: No sensible errno value is returned. -+ */ -+int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); -+ -+/* -+ * Type of the generic XER encoder. -+ */ -+typedef asn_enc_rval_t (xer_type_encoder_f)( -+ struct asn_TYPE_descriptor_s *type_descriptor, -+ void *struct_ptr, /* Structure to be encoded */ -+ int ilevel, /* Level of indentation */ -+ enum xer_encoder_flags_e xer_flags, -+ asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ -+ void *app_key /* Arbitrary callback argument */ -+ ); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _XER_ENCODER_H_ */ -diff --git a/asn1/asn1c/xer_support.c b/asn1/asn1c/xer_support.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9e34e6923467a436e20690633c4091b6db4683cd ---- /dev/null -+++ b/asn1/asn1c/xer_support.c -@@ -0,0 +1,233 @@ -+/* -+ * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. -+ * Copyright (c) 2003, 2004, 2005 Lev Walkin . -+ * All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#include -+#include -+ -+/* Parser states */ -+typedef enum { -+ ST_TEXT, -+ ST_TAG_START, -+ ST_TAG_BODY, -+ ST_TAG_QUOTE_WAIT, -+ ST_TAG_QUOTED_STRING, -+ ST_TAG_UNQUOTED_STRING, -+ ST_COMMENT_WAIT_DASH1, /* ""[0] */ -+ ST_COMMENT_CLO_RT /* "-->"[1] */ -+} pstate_e; -+ -+static pxml_chunk_type_e final_chunk_type[] = { -+ PXML_TEXT, -+ PXML_TAG_END, -+ PXML_COMMENT_END, -+ PXML_TAG_END, -+ PXML_COMMENT_END, -+}; -+ -+ -+static int -+_charclass[256] = { -+ 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, -+ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, -+ 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, -+ 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0, /* 01234567 89 */ -+ 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* ABCDEFG HIJKLMNO */ -+ 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0, /* PQRSTUVW XYZ */ -+ 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* abcdefg hijklmno */ -+ 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0 /* pqrstuvw xyz */ -+}; -+#define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1) -+#define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2) -+#define ALPHA(c) (_charclass[(unsigned char)(c)] == 3) -+ -+/* Aliases for characters, ASCII/UTF-8 */ -+#define EXCLAM 0x21 /* '!' */ -+#define CQUOTE 0x22 /* '"' */ -+#define CDASH 0x2d /* '-' */ -+#define CSLASH 0x2f /* '/' */ -+#define LANGLE 0x3c /* '<' */ -+#define CEQUAL 0x3d /* '=' */ -+#define RANGLE 0x3e /* '>' */ -+#define CQUEST 0x3f /* '?' */ -+ -+/* Invoke token callback */ -+#define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ -+ int _ret; \ -+ pstate_e ns = _ns; \ -+ ssize_t _sz = (p - chunk_start) + _current_too; \ -+ if (!_sz) { \ -+ /* Shortcut */ \ -+ state = _ns; \ -+ break; \ -+ } \ -+ _ret = cb(type, chunk_start, _sz, key); \ -+ if(_ret < _sz) { \ -+ if(_current_too && _ret == -1) \ -+ state = ns; \ -+ goto finish; \ -+ } \ -+ chunk_start = p + _current_too; \ -+ state = ns; \ -+ } while(0) -+ -+#define TOKEN_CB(_type, _ns, _current_too) \ -+ TOKEN_CB_CALL(_type, _ns, _current_too, 0) -+ -+#define TOKEN_CB_FINAL(_type, _ns, _current_too) \ -+ TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1) -+ -+/* -+ * Parser itself -+ */ -+ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) { -+ pstate_e state = (pstate_e)*stateContext; -+ const char *chunk_start = (const char *)xmlbuf; -+ const char *p = chunk_start; -+ const char *end = p + size; -+ -+ for(; p < end; p++) { -+ int C = *(const unsigned char *)p; -+ switch(state) { -+ case ST_TEXT: -+ /* -+ * Initial state: we're in the middle of some text, -+ * or just have started. -+ */ -+ if (C == LANGLE) -+ /* We're now in the tag, probably */ -+ TOKEN_CB(PXML_TEXT, ST_TAG_START, 0); -+ break; -+ case ST_TAG_START: -+ if (ALPHA(C) || (C == CSLASH)) -+ state = ST_TAG_BODY; -+ else if (C == EXCLAM) -+ state = ST_COMMENT_WAIT_DASH1; -+ else -+ /* -+ * Not characters and not whitespace. -+ * Must be something like "3 < 4". -+ */ -+ TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */ -+ break; -+ case ST_TAG_BODY: -+ switch(C) { -+ case RANGLE: -+ /* End of the tag */ -+ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); -+ break; -+ case LANGLE: -+ /* -+ * The previous tag wasn't completed, but still -+ * recognized as valid. (Mozilla-compatible) -+ */ -+ TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0); -+ break; -+ case CEQUAL: -+ state = ST_TAG_QUOTE_WAIT; -+ break; -+ } -+ break; -+ case ST_TAG_QUOTE_WAIT: -+ /* -+ * State after the equal sign ("=") in the tag. -+ */ -+ switch(C) { -+ case CQUOTE: -+ state = ST_TAG_QUOTED_STRING; -+ break; -+ case RANGLE: -+ /* End of the tag */ -+ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); -+ break; -+ default: -+ if(!WHITESPACE(C)) -+ /* Unquoted string value */ -+ state = ST_TAG_UNQUOTED_STRING; -+ } -+ break; -+ case ST_TAG_QUOTED_STRING: -+ /* -+ * Tag attribute's string value in quotes. -+ */ -+ if(C == CQUOTE) { -+ /* Return back to the tag state */ -+ state = ST_TAG_BODY; -+ } -+ break; -+ case ST_TAG_UNQUOTED_STRING: -+ if(C == RANGLE) { -+ /* End of the tag */ -+ TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); -+ } else if(WHITESPACE(C)) { -+ /* Return back to the tag state */ -+ state = ST_TAG_BODY; -+ } -+ break; -+ case ST_COMMENT_WAIT_DASH1: -+ if(C == CDASH) { -+ state = ST_COMMENT_WAIT_DASH2; -+ } else { -+ /* Some ordinary tag. */ -+ state = ST_TAG_BODY; -+ } -+ break; -+ case ST_COMMENT_WAIT_DASH2: -+ if(C == CDASH) { -+ /* Seen "<--" */ -+ state = ST_COMMENT; -+ } else { -+ /* Some ordinary tag */ -+ state = ST_TAG_BODY; -+ } -+ break; -+ case ST_COMMENT: -+ if(C == CDASH) { -+ state = ST_COMMENT_CLO_DASH2; -+ } -+ break; -+ case ST_COMMENT_CLO_DASH2: -+ if(C == CDASH) { -+ state = ST_COMMENT_CLO_RT; -+ } else { -+ /* This is not an end of a comment */ -+ state = ST_COMMENT; -+ } -+ break; -+ case ST_COMMENT_CLO_RT: -+ if(C == RANGLE) { -+ TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1); -+ } else if(C == CDASH) { -+ /* Maintain current state, still waiting for '>' */ -+ } else { -+ state = ST_COMMENT; -+ } -+ break; -+ } /* switch(*ptr) */ -+ } /* for() */ -+ -+ /* -+ * Flush the partially processed chunk, state permitting. -+ */ -+ if(p - chunk_start) { -+ switch (state) { -+ case ST_COMMENT: -+ TOKEN_CB(PXML_COMMENT, state, 0); -+ break; -+ case ST_TEXT: -+ TOKEN_CB(PXML_TEXT, state, 0); -+ break; -+ default: break; /* a no-op */ -+ } -+ } -+ -+finish: -+ *stateContext = (int)state; -+ return chunk_start - (const char *)xmlbuf; -+} -+ -diff --git a/asn1/asn1c/xer_support.h b/asn1/asn1c/xer_support.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8b01944ab584c4bca90139c4b322fa5103030f49 ---- /dev/null -+++ b/asn1/asn1c/xer_support.h -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. -+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. -+ * Redistribution and modifications are permitted subject to BSD license. -+ */ -+#ifndef _XER_SUPPORT_H_ -+#define _XER_SUPPORT_H_ -+ -+#include /* Platform-specific types */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* -+ * Types of data transferred to the application. -+ */ -+typedef enum { -+ PXML_TEXT, /* Plain text between XML tags. */ -+ PXML_TAG, /* A tag, starting with '<'. */ -+ PXML_COMMENT, /* An XML comment, including "". */ -+ /* -+ * The following chunk types are reported if the chunk -+ * terminates the specified XML element. -+ */ -+ PXML_TAG_END, /* Tag ended */ -+ PXML_COMMENT_END /* Comment ended */ -+} pxml_chunk_type_e; -+ -+/* -+ * Callback function that is called by the parser when parsed data is -+ * available. The _opaque is the pointer to a field containing opaque user -+ * data specified in pxml_create() call. The chunk type is _type and the text -+ * data is the piece of buffer identified by _bufid (as supplied to -+ * pxml_feed() call) starting at offset _offset and of _size bytes size. -+ * The chunk is NOT '\0'-terminated. -+ */ -+typedef int (pxml_callback_f)(pxml_chunk_type_e _type, -+ const void *_chunk_data, size_t _chunk_size, void *_key); -+ -+/* -+ * Parse the given buffer as it were a chunk of XML data. -+ * Invoke the specified callback each time the meaninful data is found. -+ * This function returns number of bytes consumed from the bufer. -+ * It will always be lesser than or equal to the specified _size. -+ * The next invocation of this function must account the difference. -+ */ -+ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, -+ pxml_callback_f *cb, void *_key); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _XER_SUPPORT_H_ */ -diff --git a/asn1/configure.ac b/asn1/configure.ac -new file mode 100644 -index 0000000000000000000000000000000000000000..c3e398ea20d4112ed8308ba5eb822ab22d256436 ---- /dev/null -+++ b/asn1/configure.ac -@@ -0,0 +1,24 @@ -+AC_PREREQ(2.59) -+m4_include(../version.m4) -+AC_INIT([ipa-server], -+ IPA_VERSION, -+ [https://hosted.fedoraproject.org/projects/freeipa/newticket]) -+ -+AC_CONFIG_HEADERS([config.h]) -+AC_PROG_CC_C99 -+AC_PROG_LIBTOOL -+ -+AM_INIT_AUTOMAKE([foreign]) -+ -+AM_MAINTAINER_MODE -+ -+AC_SUBST(VERSION) -+ -+# Files -+ -+AC_CONFIG_FILES([ -+ Makefile -+ asn1c/Makefile -+]) -+ -+AC_OUTPUT -diff --git a/asn1/ipa_asn1.c b/asn1/ipa_asn1.c -new file mode 100644 -index 0000000000000000000000000000000000000000..50851a804f59bdb3fcb9ba832b093860d914452d ---- /dev/null -+++ b/asn1/ipa_asn1.c -@@ -0,0 +1,229 @@ -+#include -+#include -+#include "ipa_asn1.h" -+#include "GetKeytabControl.h" -+ -+static bool encode_GetKeytabControl(GetKeytabControl_t *gkctrl, -+ void **buf, size_t *len) -+{ -+ asn_enc_rval_t rval; -+ char *buffer = NULL; -+ size_t buflen; -+ bool ret = false; -+ -+ /* dry run to compute the size */ -+ rval = der_encode(&asn_DEF_GetKeytabControl, gkctrl, NULL, NULL); -+ if (rval.encoded == -1) goto done; -+ -+ buflen = rval.encoded; -+ buffer = malloc(buflen); -+ if (!buffer) goto done; -+ -+ /* now for real */ -+ rval = der_encode_to_buffer(&asn_DEF_GetKeytabControl, -+ gkctrl, buffer, buflen); -+ if (rval.encoded == -1) goto done; -+ -+ *buf = buffer; -+ *len = buflen; -+ ret = true; -+ -+done: -+ if (!ret) { -+ free(buffer); -+ } -+ return ret; -+} -+ -+bool ipaasn1_enc_getkt(bool newkt, const char *princ, const char *pwd, -+ long *etypes, int numtypes, void **buf, size_t *len) -+{ -+ GetKeytabControl_t gkctrl = { 0 }; -+ bool ret = false; -+ -+ if (newkt) { -+ gkctrl.present = GetKeytabControl_PR_newkeys; -+ if (OCTET_STRING_fromString(&gkctrl.choice.newkeys.serviceIdentity, -+ princ) != 0) goto done; -+ -+ for (int i = 0; i < numtypes; i++) { -+ long *tmp; -+ tmp = malloc(sizeof(long)); -+ if (!tmp) goto done; -+ *tmp = etypes[i]; -+ ASN_SEQUENCE_ADD(&gkctrl.choice.newkeys.enctypes.list, tmp); -+ } -+ -+ if (pwd) { -+ gkctrl.choice.newkeys.password = -+ OCTET_STRING_new_fromBuf(&asn_DEF_OCTET_STRING, pwd, -1); -+ if (!gkctrl.choice.newkeys.password) goto done; -+ } -+ } else { -+ gkctrl.present = GetKeytabControl_PR_curkeys; -+ if (OCTET_STRING_fromString(&gkctrl.choice.curkeys.serviceIdentity, -+ princ) != 0) goto done; -+ } -+ -+ ret = encode_GetKeytabControl(&gkctrl, buf, len); -+ -+done: -+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetKeytabControl, &gkctrl); -+ return ret; -+} -+ -+bool ipaasn1_enc_getktreply(int kvno, struct keys_container *keys, -+ void **buf, size_t *len) -+{ -+ GetKeytabControl_t gkctrl = { 0 }; -+ bool ret = false; -+ -+ gkctrl.present = GetKeytabControl_PR_reply; -+ gkctrl.choice.reply.newkvno = kvno; -+ -+ for (int i = 0; i < keys->nkeys; i++) { -+ KrbKey_t *KK; -+ KK = calloc(1, sizeof(KrbKey_t)); -+ if (!KK) goto done; -+ KK->key.type = keys->ksdata[i].key.enctype; -+ KK->key.value.buf = malloc(keys->ksdata[i].key.length); -+ if (!KK->key.value.buf) goto done; -+ memcpy(KK->key.value.buf, -+ keys->ksdata[i].key.contents, keys->ksdata[i].key.length); -+ KK->key.value.size = keys->ksdata[i].key.length; -+ -+ if (keys->ksdata[i].salt.data != NULL) { -+ KK->salt = calloc(1, sizeof(TypeValuePair_t)); -+ if (!KK->salt) goto done; -+ KK->salt->type = keys->ksdata[i].salttype; -+ KK->salt->value.buf = malloc(keys->ksdata[i].salt.length); -+ if (!KK->salt->value.buf) goto done; -+ memcpy(KK->salt->value.buf, -+ keys->ksdata[i].salt.data, keys->ksdata[i].salt.length); -+ KK->salt->value.size = keys->ksdata[i].salt.length; -+ } -+ -+ /* KK->key.s2kparams not used for now */ -+ -+ ASN_SEQUENCE_ADD(&gkctrl.choice.reply.keys.list, KK); -+ } -+ -+ ret = encode_GetKeytabControl(&gkctrl, buf, len); -+ -+done: -+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetKeytabControl, &gkctrl); -+ return ret; -+} -+ -+static GetKeytabControl_t *decode_GetKeytabControl(void *buf, size_t len) -+{ -+ GetKeytabControl_t *gkctrl = NULL; -+ asn_dec_rval_t rval; -+ -+ rval = ber_decode(NULL, &asn_DEF_GetKeytabControl, -+ (void **)&gkctrl, buf, len); -+ if (rval.code == RC_OK) { -+ return gkctrl; -+ } -+ return NULL; -+} -+ -+bool ipaasn1_dec_getkt(void *buf, size_t len, bool *newkt, -+ char **princ, char **pwd, long **etypes, int *numtypes) -+{ -+ GetKeytabControl_t *gkctrl; -+ bool ret = false; -+ int num; -+ -+ gkctrl = decode_GetKeytabControl(buf, len); -+ if (!gkctrl) return false; -+ -+ switch (gkctrl->present) { -+ case GetKeytabControl_PR_newkeys: -+ *newkt = true; -+ *princ = strndup((char *)gkctrl->choice.newkeys.serviceIdentity.buf, -+ gkctrl->choice.newkeys.serviceIdentity.size); -+ if (!*princ) goto done; -+ -+ num = gkctrl->choice.newkeys.enctypes.list.count; -+ *etypes = malloc(num * sizeof(long)); -+ *numtypes = 0; -+ if (!*etypes) goto done; -+ for (int i = 0; i < num; i++) { -+ (*etypes)[i] = *gkctrl->choice.newkeys.enctypes.list.array[i]; -+ (*numtypes)++; -+ } -+ -+ if (gkctrl->choice.newkeys.password) { -+ *pwd = strndup((char *)gkctrl->choice.newkeys.password->buf, -+ gkctrl->choice.newkeys.password->size); -+ if (!*pwd) goto done; -+ } -+ break; -+ case GetKeytabControl_PR_curkeys: -+ *newkt = false; -+ *princ = strndup((char *)gkctrl->choice.curkeys.serviceIdentity.buf, -+ gkctrl->choice.curkeys.serviceIdentity.size); -+ if (!*princ) goto done; -+ break; -+ default: -+ goto done; -+ } -+ -+ ret = true; -+ -+done: -+ ASN_STRUCT_FREE(asn_DEF_GetKeytabControl, gkctrl); -+ return ret; -+} -+ -+bool ipaasn1_dec_getktreply(void *buf, size_t len, -+ int *kvno, struct keys_container *keys) -+{ -+ GetKeytabControl_t *gkctrl; -+ struct KrbKey *KK; -+ bool ret = false; -+ int nkeys; -+ -+ gkctrl = decode_GetKeytabControl(buf, len); -+ if (!gkctrl) return false; -+ -+ if (gkctrl->present != GetKeytabControl_PR_reply) goto done; -+ -+ *kvno = gkctrl->choice.reply.newkvno; -+ -+ nkeys = gkctrl->choice.reply.keys.list.count; -+ -+ keys->nkeys = 0; -+ keys->ksdata = calloc(nkeys, sizeof(struct krb_key_salt)); -+ if (!keys->ksdata) goto done; -+ -+ for (int i = 0; i < nkeys; i++) { -+ KK = gkctrl->choice.reply.keys.list.array[i]; -+ keys->ksdata[i].enctype = KK->key.type; -+ keys->ksdata[i].key.enctype = KK->key.type; -+ keys->ksdata[i].key.contents = malloc(KK->key.value.size); -+ if (!keys->ksdata[i].key.contents) goto done; -+ memcpy(keys->ksdata[i].key.contents, -+ KK->key.value.buf, KK->key.value.size); -+ keys->ksdata[i].key.length = KK->key.value.size; -+ -+ if (KK->salt) { -+ keys->ksdata[i].salttype = KK->salt->type; -+ keys->ksdata[i].salt.data = malloc(KK->salt->value.size); -+ if (!keys->ksdata[i].salt.data) goto done; -+ memcpy(keys->ksdata[i].salt.data, -+ KK->salt->value.buf, KK->salt->value.size); -+ keys->ksdata[i].salt.length = KK->salt->value.size; -+ } -+ -+ /* KK->s2kparams is ignored for now */ -+ keys->nkeys++; -+ } -+ -+ ret = true; -+ -+done: -+ ASN_STRUCT_FREE(asn_DEF_GetKeytabControl, gkctrl); -+ return ret; -+} -diff --git a/asn1/ipa_asn1.h b/asn1/ipa_asn1.h -new file mode 100644 -index 0000000000000000000000000000000000000000..6ffcc5cc81992966654c21e923a1f8883b32833b ---- /dev/null -+++ b/asn1/ipa_asn1.h -@@ -0,0 +1,76 @@ -+#ifndef __IPA_ASN1_H_ -+#define __IPA_ASN1_H_ -+ -+#include "ipa_krb5.h" -+ -+/** -+ * @brief Encodes a Get Keytab Request Control -+ * -+ * @param newkt Whether this is a New Key request or a Current Key one -+ * @param princ The principal the keys belong to (this is required) -+ * @param pwd Optional, only for New Key reqs, the password to use to -+ * create the new keys -+ * @param etypes Optional, only for New Key reqs, list of desired -+ * enctypes -+ * @param numtypes Optional, Number of desired enctypes in etypes -+ * @param buf A void pointer wil lcontain pointer to an allocated -+ * buffer with the serialized control, must be freed -+ * @param len Length of the returned buffer -+ * -+ * @return True on success or False on failure -+ */ -+bool ipaasn1_enc_getkt(bool newkt, const char *princ, const char *pwd, -+ long *etypes, int numtypes, void **buf, size_t *len); -+ -+/** -+ * @brief Encodes a Get Keytab Reply Control -+ * -+ * @param kvno The new key version number -+ * @param keys A set of keys to return to the caller -+ * @param buf A void pointer wil lcontain pointer to an allocated -+ * buffer with the serialized control, must be freed -+ * @param len Length of the returned buffer -+ * -+ * @return True on success or False on failure -+ */ -+bool ipaasn1_enc_getktreply(int kvno, struct keys_container *keys, -+ void **buf, size_t *len); -+ -+/** -+ * @brief Decodes a Get Keytab Requst Control -+ * -+ * @param buf A pointer to the serialized buffer -+ * @param len The lenght of the buffer -+ * @param newkt Returns whether this is a New Key or Current Key request -+ * @param princ Returns the principal the keys belong to. -+ * @param pwd Optional: The password to use to create keys -+ * @param etypes Optional: The desired enctypes -+ * @param numtypes Optional: Number of desired enctypes in etypes -+ * -+ * @return True on success or False on failure -+ * -+ * NOTE: princ, pwd, etypes and numtypes should be zeroed before being -+ * passed in input, and the caller may need to free them even in -+ * case of failure. -+ */ -+bool ipaasn1_dec_getkt(void *buf, size_t len, bool *newkt, -+ char **princ, char **pwd, -+ long **etypes, int *numtypes); -+ -+/** -+ * @brief Decodes a Get Keytab Reply Control -+ * -+ * @param buf A pointer to the serialized buffer -+ * @param len The lenght of the buffer -+ * @param kvno The new key version number -+ * @param keys A set of keys generated by the server -+ * -+ * @return True on success or False on failure -+ * -+ * NOTE: keys should be a zeroed structure and the caller may need to free -+ * it even in case of failure. -+ */ -+bool ipaasn1_dec_getktreply(void *buf, size_t len, -+ int *kvno, struct keys_container *keys); -+ -+#endif /* __IPA_ASN1_H_ */ -diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h -index 1e036e4f8eb8f9a92af6fb6190f507e02ae38934..7b877aa665dd6cb4e0c1cf9d8153319cc8f61a20 100644 ---- a/util/ipa_krb5.h -+++ b/util/ipa_krb5.h -@@ -1,6 +1,7 @@ - #ifndef __IPA_KRB5_H_ - #define __IPA_KRB5_H_ - -+#include - #include - #include - --- -2.1.0 - diff --git a/SOURCES/0044-Fixed-missing-KRA-agent-cert-on-replica.patch b/SOURCES/0044-Fixed-missing-KRA-agent-cert-on-replica.patch new file mode 100644 index 0000000..826d8b5 --- /dev/null +++ b/SOURCES/0044-Fixed-missing-KRA-agent-cert-on-replica.patch @@ -0,0 +1,53 @@ +From 9d1657b3527e423e489a25fd7ee31692181f9f5b Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Sat, 1 Aug 2015 02:46:26 +0200 +Subject: [PATCH] Fixed missing KRA agent cert on replica. + +The code that exports the KRA agent certificate has been moved +such that it will be executed both on master and replica. + +https://fedorahosted.org/freeipa/ticket/5174 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/krainstance.py | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 50ab424b0e59becfea9e7af4b8d43a32ccbdc823..fa50c3dec897d63b9d3522d196054163f7b3369a 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -256,6 +256,15 @@ class KRAInstance(DogtagInstance): + os.remove(cfg_file) + + shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12) ++ ++ # export ipaCert with private key for client authentication ++ args = ["/usr/bin/pki", ++ "-d", paths.HTTPD_ALIAS_DIR, ++ "-C", paths.ALIAS_PWDFILE_TXT, ++ "client-cert-show", "ipaCert", ++ "--client-cert", paths.KRA_AGENT_PEM] ++ ipautil.run(args) ++ + self.log.debug("completed creating KRA instance") + + def __add_ra_user_to_agent_group(self): +@@ -330,14 +339,6 @@ class KRAInstance(DogtagInstance): + finally: + os.remove(filename) + +- # export ipaCert with private key for client authentication +- args = ["/usr/bin/pki", +- "-d", paths.HTTPD_ALIAS_DIR, +- "-C", paths.ALIAS_PWDFILE_TXT, +- "client-cert-show", "ipaCert", +- "--client-cert", paths.KRA_AGENT_PEM] +- ipautil.run(args) +- + def __add_vault_container(self): + sub_dict = { + 'SUFFIX': self.suffix, +-- +2.4.3 + diff --git a/SOURCES/0045-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch b/SOURCES/0045-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch deleted file mode 100644 index e8c728e..0000000 --- a/SOURCES/0045-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch +++ /dev/null @@ -1,813 +0,0 @@ -From 55172f11776453c0f8defb1363dd144b29f181d3 Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Mon, 17 Nov 2014 15:19:57 -0500 -Subject: [PATCH] Use asn1c helpers to encode/decode the getkeytab control - -Replaces manual encoding with automatically generated code. - -Fixes: -https://fedorahosted.org/freeipa/ticket/4718 -https://fedorahosted.org/freeipa/ticket/4728 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Nathaniel McCallum ---- - Makefile | 1 + - daemons/configure.ac | 2 + - .../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 7 +- - .../ipa-pwd-extop/ipa_pwd_extop.c | 241 ++++---------------- - ipa-client/Makefile.am | 4 + - ipa-client/configure.ac | 2 + - ipa-client/ipa-getkeytab.c | 246 ++++----------------- - 7 files changed, 107 insertions(+), 396 deletions(-) - -diff --git a/Makefile b/Makefile -index c1a298f91717246e8dab5e3f0de47d0ac9b2ae35..8fd0c60e392d720f47c8ee7c4b674727dc5eb789 100644 ---- a/Makefile -+++ b/Makefile -@@ -75,6 +75,7 @@ client: client-autogen - - bootstrap-autogen: version-update client-autogen - @echo "Building IPA $(IPA_VERSION)" -+ cd asn1; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - cd daemons; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR) --with-openldap; fi - cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - -diff --git a/daemons/configure.ac b/daemons/configure.ac -index bfcdeadcd1dc73762d8c773ee50210d9bdb91e92..e81aa60e381e035aff73bf27475fc0f101a5fbf9 100644 ---- a/daemons/configure.ac -+++ b/daemons/configure.ac -@@ -5,6 +5,7 @@ AC_INIT([ipa-server], - [https://hosted.fedoraproject.org/projects/freeipa/newticket]) - - AC_CONFIG_HEADERS([config.h]) -+AC_CONFIG_SUBDIRS([../asn1]) - - AM_INIT_AUTOMAKE([foreign]) - m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) -@@ -305,6 +306,7 @@ AC_SUBST(LDFLAGS) - - AC_CONFIG_FILES([ - Makefile -+ ../asn1/Makefile - ipa-kdb/Makefile - ipa-sam/Makefile - ipa-otpd/Makefile -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -index 4cf80ec802b40bb579a44fc9357c6a8119dab577..77beca2da0810ed5507d95b21f99d22f63b05fc1 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -@@ -6,6 +6,7 @@ KRB5_UTIL_DIR = ../../../util - KRB5_UTIL_SRCS = $(KRB5_UTIL_DIR)/ipa_krb5.c \ - $(KRB5_UTIL_DIR)/ipa_pwd.c \ - $(KRB5_UTIL_DIR)/ipa_pwd_ntlm.c -+ASN1_UTIL_DIR=../../../asn1 - - AM_CPPFLAGS = \ - -I. \ -@@ -13,6 +14,7 @@ AM_CPPFLAGS = \ - -I$(srcdir)/../libotp \ - -I$(PLUGIN_COMMON_DIR) \ - -I$(KRB5_UTIL_DIR) \ -+ -I$(ASN1_UTIL_DIR) \ - -I$(COMMON_BER_DIR) \ - -DPREFIX=\""$(prefix)"\" \ - -DBINDIR=\""$(bindir)"\" \ -@@ -38,7 +40,10 @@ AM_LDFLAGS = \ - # Plugin Binary - plugindir = $(libdir)/dirsrv/plugins - plugin_LTLIBRARIES = libipa_pwd_extop.la --libipa_pwd_extop_la_LIBADD = $(builddir)/../libotp/libotp.la -+libipa_pwd_extop_la_LIBADD = \ -+ $(builddir)/../libotp/libotp.la \ -+ $(ASN1_UTIL_DIR)/libipaasn1.la \ -+ $(NULL) - libipa_pwd_extop_la_SOURCES = \ - authcfg.c \ - common.c \ -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -index b87ae0dc7a180008228f31293b49212df80584e8..ceea49cab50b0836c882240f210339e60d26729b 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -@@ -40,6 +40,7 @@ - #include "ipapwd.h" - #include "util.h" - #include "authcfg.h" -+#include "ipa_asn1.h" - - /* - * Password Modify - LDAP Extended Operation. -@@ -1310,31 +1311,7 @@ free_and_return: - return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; - } - --/* Format of getkeytab request -- * -- * KeytabGetRequest ::= CHOICE { -- * newkeys [0] Newkeys, -- * curkeys [1] CurrentKeys, -- * reply [2] Reply -- * } -- * -- * NewKeys ::= SEQUENCE { -- * serviceIdentity [0] OCTET STRING, -- * enctypes [1] SEQUENCE OF Int16 -- * password [2] OCTET STRING OPTIONAL, -- * } -- * -- * CurrentKeys ::= SEQUENCE { -- * serviceIdentity [0] OCTET STRING, -- * } -- */ -- --#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) --#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) -- -+/* decode a getkeytab control request using libipaasn1 helpers */ - static int decode_getkeytab_request(struct berval *extop, bool *wantold, - char **_svcname, char **_password, - krb5_key_salt_tuple **kenctypes, -@@ -1342,96 +1319,44 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold, - { - int rc = LDAP_OPERATIONS_ERROR; - char *err_msg = NULL; -- BerElement *ber = NULL; -- ber_len_t tlen; -- ber_tag_t rtag; -- ber_tag_t ttag; -- ber_tag_t ctag; - char *svcname = NULL; - char *password = NULL; -- ber_int_t enctype; -+ long *etypes = NULL; -+ int numtypes = 0; - krb5_key_salt_tuple *enctypes = NULL; -- int num = 0; -- -- ber = ber_init(extop); -- if (ber == NULL) { -- err_msg = "KeytabGet Request decode failed.\n"; -- rc = LDAP_PROTOCOL_ERROR; -- goto done; -- } -- -- /* check this is a request */ -- rtag = ber_peek_tag(ber, &tlen); -- if (rtag != GK_REQUEST_NEWKEYS && rtag != GK_REQUEST_CURKEYS) { -- LOG_FATAL("ber_peek_tag failed, wrong request type\n"); -- err_msg = "Invalid payload.\n"; -- rc = LDAP_PROTOCOL_ERROR; -- goto done; -- } -- -- /* ber parse code */ -- ttag = ber_scanf(ber, "{ta", &ctag, &svcname); -- if (ttag == LBER_ERROR || ctag != GKREQ_SVCNAME_TAG) { -- LOG_FATAL("ber_scanf failed to decode service name\n"); -- err_msg = "Invalid payload.\n"; -+ bool newkt; -+ bool ret; -+ int i; -+ -+ ret = ipaasn1_dec_getkt(extop->bv_val, extop->bv_len, &newkt, -+ &svcname, &password, &etypes, &numtypes); -+ if (!ret) { -+ err_msg = "Failed to decode GetKeytab Control.\n"; - rc = LDAP_PROTOCOL_ERROR; - goto done; - } - -- if (rtag == GK_REQUEST_CURKEYS) { -- rc = LDAP_SUCCESS; -- goto done; -- } -- -- ttag = ber_peek_tag(ber, &tlen); -- if (ttag != GKREQ_ENCTYPES_TAG) { -- LOG_FATAL("ber_peek_tag failed to find enctypes\n"); -- err_msg = "Invalid payload.\n"; -- rc = LDAP_PROTOCOL_ERROR; -- goto done; -- } -- ttag = ber_peek_tag(ber, &tlen); -- for (num = 0; ttag == LBER_INTEGER; num++) { -- if ((num % 10) == 0) { -- /* allocate space for at least 10 more enctypes */ -- enctypes = realloc(enctypes, -- (num + 10) * sizeof(krb5_key_salt_tuple)); -+ if (newkt) { -+ if (numtypes) { -+ enctypes = malloc(numtypes * sizeof(krb5_key_salt_tuple)); - if (!enctypes) { - LOG_FATAL("allocation failed\n"); - err_msg = "Internal error\n"; - rc = LDAP_OPERATIONS_ERROR; - goto done; - } -- } -- -- ttag = ber_scanf(ber, "i", &enctype); -- if (ttag == LBER_ERROR) { -- LOG_FATAL("ber_scanf failed to decode enctype\n"); -- err_msg = "Invalid payload.\n"; -- rc = LDAP_PROTOCOL_ERROR; -- goto done; -- } -- -- enctypes[num].ks_enctype = enctype; -- enctypes[num].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; -- ttag = ber_peek_tag(ber, &tlen); -- } - -- /* ttag peek done as last step of the previous for loop */ -- if (ttag == GKREQ_PASSWORD_TAG) { -- /* optional password present */ -- ttag = ber_scanf(ber, "a", &password); -- if (ttag == LBER_ERROR) { -- LOG_FATAL("ber_scanf failed to decode password\n"); -- err_msg = "Invalid payload.\n"; -- rc = LDAP_PROTOCOL_ERROR; -- goto done; -+ for (i = 0; i < numtypes; i++) { -+ enctypes[i].ks_enctype = etypes[i]; -+ enctypes[i].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL; -+ } - } - } - - rc = LDAP_SUCCESS; - - done: -+ free(etypes); - if (rc != LDAP_SUCCESS) { - free(password); - free(svcname); -@@ -1440,78 +1365,34 @@ done: - } else { - *_password = password; - *_svcname = svcname; -- *wantold = (rtag == GK_REQUEST_CURKEYS); -+ *wantold = (newkt == false); - *kenctypes = enctypes; -- *num_kenctypes = num; -+ *num_kenctypes = numtypes; - } -- if (ber) ber_free(ber, 1); - return rc; - } - --/* Format of getkeytab reply -- * -- * Reply ::= SEQUENCE { -- * new_kvno Int32 -- * keys SEQUENCE OF KrbKey, -- * } -- * -- * KrbKey ::= SEQUENCE { -- * key [0] EncryptionKey, -- * salt [1] KrbSalt OPTIONAL, -- * s2kparams [2] OCTET STRING OPTIONAL, -- * } -- * -- * EncryptionKey ::= SEQUENCE { -- * keytype [0] Int32, -- * keyvalue [1] OCTET STRING -- * } -- * -- * KrbSalt ::= SEQUENCE { -- * type [0] Int32, -- * salt [1] OCTET STRING -- * } -- */ -- --#define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) --#define GKREP_KEY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) --#define GKREP_SALT_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREP_S2KPARAMS_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) --#define GKREP_KEYTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) --#define GKREP_KEYVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREP_SALTTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) --#define GKREP_SALTVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) -- - static int encode_getkeytab_reply(krb5_context krbctx, - krb5_keyblock *kmkey, int mkvno, - krb5_key_data *keys, int num_keys, - struct berval **_bvp) - { - int rc = LDAP_OPERATIONS_ERROR; -+ struct krb_key_salt ksdata[num_keys]; -+ struct keys_container ksc = { num_keys, ksdata }; - struct berval *bvp = NULL; -- BerElement *ber = NULL; -- ber_int_t kvno; -- krb5_data plain = { 0 }; -+ int kvno; -+ bool ret; - -- ber = ber_alloc(); -- if (!ber) { -- LOG_OOM(); -- goto done; -- } -+ memset(ksdata, '\0', num_keys * sizeof(struct krb_key_salt)); - - /* uses last key kvno */ - kvno = keys[num_keys-1].key_data_kvno; - -- rc = ber_printf(ber, "t{i{", GK_REPLY_TAG, kvno); -- if (rc == -1) { -- rc = LDAP_OPERATIONS_ERROR; -- LOG_FATAL("Failed to initiate key buffer\n"); -- goto done; -- } -- - for (int i = 0; i < num_keys; i++) { - krb5_enc_data cipher = { 0 }; -+ krb5_data plain = { 0 }; - krb5_int16 plen; -- void *p; - - /* retrieve plain key */ - memcpy(&plen, keys[i].key_data_contents[0], 2); -@@ -1521,13 +1402,12 @@ static int encode_getkeytab_reply(krb5_context krbctx, - cipher.kvno = mkvno; - - plain.length = le16toh(plen); -- p = realloc(plain.data, plain.length); -- if (!p) { -+ plain.data = malloc(plain.length); -+ if (!plain.data) { - LOG_FATAL("Failed to allocate plain buffer\n"); - rc = LDAP_OPERATIONS_ERROR; - goto done; - } -- plain.data = p; - - rc = krb5_c_decrypt(krbctx, kmkey, 0, 0, &cipher, &plain); - if (rc) { -@@ -1536,68 +1416,37 @@ static int encode_getkeytab_reply(krb5_context krbctx, - goto done; - } - -- rc = ber_printf(ber, -- "{t{tito}", -- GKREP_KEY_TAG, -- GKREP_KEYTYPE_TAG, -- (ber_int_t)keys[i].key_data_type[0], -- GKREP_KEYVALUE_TAG, -- plain.data, (ber_len_t)plain.length); -- if (rc == -1) { -- LOG_FATAL("Failed to encode key data\n"); -- rc = LDAP_OPERATIONS_ERROR; -- goto done; -- } -+ ksc.ksdata[i].enctype = keys[i].key_data_type[0]; -+ ksc.ksdata[i].key.enctype = keys[i].key_data_type[0]; -+ ksc.ksdata[i].key.contents = (void *)plain.data; -+ ksc.ksdata[i].key.length = plain.length; - - /* if salt available, add it */ - if (keys[i].key_data_length[1] != 0) { -- rc = ber_printf(ber, -- "t{tito}", -- GKREP_SALT_TAG, -- GKREP_SALTTYPE_TAG, -- (ber_int_t)keys[i].key_data_type[1], -- GKREP_SALTVALUE_TAG, -- keys[i].key_data_contents[1], -- (ber_len_t)keys[i].key_data_length[1]); -- if (rc == -1) { -- LOG_FATAL("Failed to encode salt data\n"); -- rc = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- } -- -- rc = ber_printf(ber, "}"); -- if (rc == -1) { -- LOG_FATAL("Failed to encode data\n"); -- rc = LDAP_OPERATIONS_ERROR; -- goto done; -+ ksc.ksdata[i].salttype = keys[i].key_data_type[1]; -+ ksc.ksdata[i].salt.data = (void *)keys[i].key_data_contents[1]; -+ ksc.ksdata[i].salt.length = keys[i].key_data_length[1]; - } - } - -- rc = ber_printf(ber, "}}"); -- if (rc == -1) { -- LOG_FATAL("Failed to terminate key buffer\n"); -- rc = LDAP_OPERATIONS_ERROR; -- goto done; -- } -+ bvp = calloc(1, sizeof(struct berval)); -+ if (!bvp) goto done; - -- rc = ber_flatten(ber, &bvp); -- if (rc == -1) { -- LOG_FATAL("Failed to encode key buffer\n"); -- rc = LDAP_OPERATIONS_ERROR; -- goto done; -- } -+ ret = ipaasn1_enc_getktreply(kvno, &ksc, -+ (void **)&bvp->bv_val, &bvp->bv_len); -+ if (!ret) goto done; - - rc = LDAP_SUCCESS; - - done: -+ for (int i = 0; i < ksc.nkeys; i ++) { -+ free(ksc.ksdata[i].key.contents); -+ } - if (rc != LDAP_SUCCESS) { - if (bvp) ber_bvfree(bvp); - } else { - *_bvp = bvp; - } -- if (ber) ber_free(ber, 1); -- free(plain.data); - return rc; - } - -diff --git a/ipa-client/Makefile.am b/ipa-client/Makefile.am -index 2df175e53b2a547acdad546db182b38011becd06..b9c7020f3b687b3c0030ed5166625e6ef07e2fa4 100644 ---- a/ipa-client/Makefile.am -+++ b/ipa-client/Makefile.am -@@ -14,11 +14,13 @@ export AM_CFLAGS - - KRB5_UTIL_DIR=../util - KRB5_UTIL_SRCS=$(KRB5_UTIL_DIR)/ipa_krb5.c -+ASN1_UTIL_DIR=../asn1 - - AM_CPPFLAGS = \ - -I. \ - -I$(srcdir) \ - -I$(KRB5_UTIL_DIR) \ -+ -I$(ASN1_UTIL_DIR) \ - -DPREFIX=\""$(prefix)"\" \ - -DBINDIR=\""$(bindir)"\" \ - -DLIBDIR=\""$(libdir)"\" \ -@@ -45,6 +47,7 @@ ipa_getkeytab_SOURCES = \ - $(NULL) - - ipa_getkeytab_LDADD = \ -+ ../asn1/libipaasn1.la \ - $(KRB5_LIBS) \ - $(OPENLDAP_LIBS) \ - $(SASL_LIBS) \ -@@ -80,6 +83,7 @@ ipa_join_LDADD = \ - $(NULL) - - SUBDIRS = \ -+ ../asn1 \ - ipaclient \ - ipa-install \ - man \ -diff --git a/ipa-client/configure.ac b/ipa-client/configure.ac -index 34625622d3e3bb64866b3b0b1a58d29e33f11a7d..78da8e6e413b8becbd4c75422abffb670050f446 100644 ---- a/ipa-client/configure.ac -+++ b/ipa-client/configure.ac -@@ -8,6 +8,7 @@ AC_PROG_LIBTOOL - - AC_CONFIG_SRCDIR([ipaclient/__init__.py]) - AC_CONFIG_HEADERS([config.h]) -+AC_CONFIG_SUBDIRS([../asn1]) - - AM_INIT_AUTOMAKE([foreign]) - -@@ -205,6 +206,7 @@ dnl --------------------------------------------------------------------------- - - AC_CONFIG_FILES([ - Makefile -+ ../asn1/Makefile - ipaclient/Makefile - ipa-install/Makefile - man/Makefile -diff --git a/ipa-client/ipa-getkeytab.c b/ipa-client/ipa-getkeytab.c -index bb43c333dca6560807a120103a1cb535fa87b76a..15255d6a33c8c298f138868ac545d4ebea415fe5 100644 ---- a/ipa-client/ipa-getkeytab.c -+++ b/ipa-client/ipa-getkeytab.c -@@ -40,6 +40,7 @@ - #include "config.h" - - #include "ipa_krb5.h" -+#include "ipa_asn1.h" - #include "ipa-client-common.h" - - static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit) -@@ -295,14 +296,15 @@ done: - return ret; - } - --static BerElement *get_control_data(LDAPControl **list, const char *repoid) -+static int find_control_data(LDAPControl **list, const char *repoid, -+ struct berval *data) - { - LDAPControl *control = NULL; - int i; - - if (!list) { - fprintf(stderr, _("Missing reply control list!\n")); -- return NULL; -+ return LDAP_OPERATIONS_ERROR; - } - - for (i = 0; list[i]; i++) { -@@ -312,10 +314,22 @@ static BerElement *get_control_data(LDAPControl **list, const char *repoid) - } - if (!control) { - fprintf(stderr, _("Missing reply control!\n")); -- return NULL; -+ return LDAP_OPERATIONS_ERROR; - } - -- return ber_init(&control->ldctl_value); -+ *data = control->ldctl_value; -+ return LDAP_SUCCESS; -+} -+ -+static BerElement *get_control_data(LDAPControl **list, const char *repoid) -+{ -+ struct berval data; -+ int ret; -+ -+ ret = find_control_data(list, repoid, &data); -+ if (ret != LDAP_SUCCESS) return NULL; -+ -+ return ber_init(&data); - } - - static int ldap_set_keytab(krb5_context krbctx, -@@ -435,124 +449,42 @@ error_out: - return -1; - } - --/* Format of getkeytab control -- * -- * KeytabGetRequest ::= CHOICE { -- * newkeys [0] Newkeys, -- * curkeys [1] CurrentKeys, -- * reply [2] Reply -- * } -- * -- * NewKeys ::= SEQUENCE { -- * serviceIdentity [0] OCTET STRING, -- * enctypes [1] SEQUENCE OF Int16 -- * password [2] OCTET STRING OPTIONAL, -- * } -- * -- * CurrentKeys ::= SEQUENCE { -- * serviceIdentity [0] OCTET STRING, -- * } -- * -- * Reply ::= SEQUENCE { -- * new_kvno Int32 -- * keys SEQUENCE OF KrbKey, -- * } -- * -- * KrbKey ::= SEQUENCE { -- * key [0] EncryptionKey, -- * salt [1] KrbSalt OPTIONAL, -- * s2kparams [2] OCTET STRING OPTIONAL, -- * } -- * -- * EncryptionKey ::= SEQUENCE { -- * keytype [0] Int32, -- * keyvalue [1] OCTET STRING -- * } -- * -- * KrbSalt ::= SEQUENCE { -- * type [0] Int32, -- * salt [1] OCTET STRING -- * } -- */ -- --#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0) --#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1) --#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) -- -+/* use asn1c generated code to fill up control */ - static struct berval *create_getkeytab_control(const char *svc_princ, bool gen, - const char *password, - struct krb_key_salt *encsalts, - int num_encsalts) - { -- struct berval *bval = NULL; -- BerElement *be; -- ber_tag_t ctag; -- ber_int_t e; -- int ret, i; -- -- be = ber_alloc_t(LBER_USE_DER); -- if (!be) { -- return NULL; -- } -- -- if (gen) { -- ctag = GK_REQUEST_NEWKEYS; -- } else { -- ctag = GK_REQUEST_CURKEYS; -- } -- -- ret = ber_printf(be, "t{ts", ctag, GKREQ_SVCNAME_TAG, svc_princ); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } -+ struct berval *result = NULL; -+ void *buffer = NULL; -+ size_t buflen; -+ long ets[num_encsalts]; -+ bool ret; -+ int i; - - if (gen) { -- ret = ber_printf(be, "t{", GKREQ_ENCTYPES_TAG); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } - for (i = 0; i < num_encsalts; i++) { -- e = encsalts[i].enctype; -- ret = ber_printf(be, "i", e); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } -- } -- ret = ber_printf(be, "}"); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } -- -- if (password) { -- ret = ber_printf(be, "ts", GKREQ_PASSWORD_TAG, password); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } -+ ets[i] = encsalts[i].enctype; - } - } -+ ret = ipaasn1_enc_getkt(gen, svc_princ, -+ password, ets, num_encsalts, -+ &buffer, &buflen); -+ if (!ret) goto done; - -- ret = ber_printf(be, "}"); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } -+ result = malloc(sizeof(struct berval)); -+ if (!result) goto done; - -- ret = ber_flatten(be, &bval); -- if (ret == -1) { -- ber_free(be, 1); -- goto done; -- } -+ result->bv_val = buffer; -+ result->bv_len = buflen; - - done: -- ber_free(be, 1); -- return bval; -+ if (result == NULL) { -+ if (buffer) { -+ free(buffer); -+ } -+ } -+ return result; - } - - #define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2) -@@ -571,13 +503,8 @@ static int ldap_get_keytab(krb5_context krbctx, bool generate, char *password, - struct berval *control = NULL; - LDAP *ld = NULL; - LDAPControl **srvctrl = NULL; -- BerElement *ber = NULL; -- ber_tag_t rtag; -- ber_tag_t ctag; -- ber_len_t tlen; -- ber_int_t vno; -- ber_int_t tint; -- struct berval tbval; -+ struct berval data; -+ bool res; - int ret; - - *err_msg = NULL; -@@ -609,98 +536,19 @@ static int ldap_get_keytab(krb5_context krbctx, bool generate, char *password, - goto done; - } - -- ber = get_control_data(srvctrl, KEYTAB_GET_OID); -- if (!ber) { -- *err_msg = _("Failed to find or parse reply control!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- -- rtag = ber_scanf(ber, "t{i{", &ctag, &vno); -- if (rtag == LBER_ERROR || ctag != GK_REPLY_TAG) { -- *err_msg = _("Failed to parse control head!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- -- keys->nkeys = 0; -- keys->ksdata = NULL; -- -- rtag = ber_peek_tag(ber, &tlen); -- for (int i = 0; rtag == LBER_SEQUENCE; i++) { -- if ((i % 5) == 0) { -- struct krb_key_salt *ksdata; -- ksdata = realloc(keys->ksdata, -- (i + 5) * sizeof(struct krb_key_salt)); -- if (!ksdata) { -- *err_msg = _("Out of memory!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- keys->ksdata = ksdata; -- } -- memset(&keys->ksdata[i], 0, sizeof(struct krb_key_salt)); -- keys->nkeys = i + 1; -- -- rtag = ber_scanf(ber, "{t{io}", &ctag, &tint, &tbval); -- if (rtag == LBER_ERROR || ctag != GKREP_KEY_TAG) { -- *err_msg = _("Failed to parse enctype in key data!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- keys->ksdata[i].enctype = tint; -- keys->ksdata[i].key.enctype = tint; -- keys->ksdata[i].key.length = tbval.bv_len; -- keys->ksdata[i].key.contents = malloc(tbval.bv_len); -- if (!keys->ksdata[i].key.contents) { -- *err_msg = _("Out of memory!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- memcpy(keys->ksdata[i].key.contents, tbval.bv_val, tbval.bv_len); -- ber_memfree(tbval.bv_val); -- -- rtag = ber_peek_tag(ber, &tlen); -- if (rtag == GKREP_SALT_TAG) { -- rtag = ber_scanf(ber, "t{io}", &ctag, &tint, &tbval); -- if (rtag == LBER_ERROR) { -- *err_msg = _("Failed to parse salt in key data!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- keys->ksdata[i].salttype = tint; -- keys->ksdata[i].salt.length = tbval.bv_len; -- keys->ksdata[i].salt.data = malloc(tbval.bv_len); -- if (!keys->ksdata[i].salt.data) { -- *err_msg = _("Out of memory!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- memcpy(keys->ksdata[i].salt.data, tbval.bv_val, tbval.bv_len); -- ber_memfree(tbval.bv_val); -- } -- rtag = ber_scanf(ber, "}"); -- if (rtag == LBER_ERROR) { -- *err_msg = _("Failed to parse ending of key data!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- -- rtag = ber_peek_tag(ber, &tlen); -- } -+ ret = find_control_data(srvctrl, KEYTAB_GET_OID, &data); -+ if (ret != LDAP_SUCCESS) goto done; - -- rtag = ber_scanf(ber, "}}"); -- if (rtag == LBER_ERROR) { -- *err_msg = _("Failed to parse ending of control!\n"); -+ res = ipaasn1_dec_getktreply(data.bv_val, data.bv_len, kvno, keys); -+ if (!res) { -+ *err_msg = _("Failed to decode control reply!\n"); - ret = LDAP_OPERATIONS_ERROR; - goto done; - } - -- *kvno = vno; - ret = LDAP_SUCCESS; - - done: -- if (ber) ber_free(ber, 1); - if (ld) ldap_unbind_ext(ld, NULL, NULL); - if (control) ber_bvfree(control); - free(es); --- -2.1.0 - diff --git a/SOURCES/0045-webui-add-LDAP-vs-Kerberos-behavior-description-to-u.patch b/SOURCES/0045-webui-add-LDAP-vs-Kerberos-behavior-description-to-u.patch new file mode 100644 index 0000000..0457ec3 --- /dev/null +++ b/SOURCES/0045-webui-add-LDAP-vs-Kerberos-behavior-description-to-u.patch @@ -0,0 +1,89 @@ +From f169531c4b4fec3485015a9673e5b0d3b76e30d6 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Mon, 10 Aug 2015 12:58:14 +0200 +Subject: [PATCH] webui: add LDAP vs Kerberos behavior description to user auth + types + +https://fedorahosted.org/freeipa/ticket/4935 + +Reviewed-By: David Kupka +--- + install/ui/src/freeipa/serverconfig.js | 5 ++++- + install/ui/src/freeipa/user.js | 5 ++++- + install/ui/test/data/ipa_init.json | 4 ++-- + ipalib/plugins/internal.py | 4 ++-- + 4 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/install/ui/src/freeipa/serverconfig.js b/install/ui/src/freeipa/serverconfig.js +index efe1805698372b45afae38d1f9dd883034ee03c6..70bb9574b8368d6a294dc171fdea2d03dfe56cab 100644 +--- a/install/ui/src/freeipa/serverconfig.js ++++ b/install/ui/src/freeipa/serverconfig.js +@@ -83,7 +83,10 @@ return { + { label: '@i18n:authtype.type_radius', value: 'radius' }, + { label: '@i18n:authtype.type_otp', value: 'otp' } + ], +- tooltip: '@i18n:authtype.config_tooltip' ++ tooltip: { ++ title: '@i18n:authtype.config_tooltip', ++ html: true ++ } + }, + { + $type: 'checkbox', +diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js +index 0e828c16b999ffd58504bc4e53d2748bcd16b042..a920e088aacd02585cd131dce725272f47e4cf1c 100644 +--- a/install/ui/src/freeipa/user.js ++++ b/install/ui/src/freeipa/user.js +@@ -188,7 +188,10 @@ return { + { label: '@i18n:authtype.type_radius', value: 'radius' }, + { label: '@i18n:authtype.type_otp', value: 'otp' } + ], +- tooltip: '@i18n:authtype.user_tooltip' ++ tooltip: { ++ title: '@i18n:authtype.user_tooltip', ++ html: true ++ } + }, + { + $type: 'entity_select', +diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json +index ef172950527512e71c28916274153036f17212fe..b80e44ffe8ead3d0b29196ca3af18e00d72a9f04 100644 +--- a/install/ui/test/data/ipa_init.json ++++ b/install/ui/test/data/ipa_init.json +@@ -49,12 +49,12 @@ + "show_results": "Show Results" + }, + "authtype": { +- "config_tooltip": "Implicit method (password) will be used if no method is chosen.", ++ "config_tooltip": "

Implicit method (password) will be used if no method is chosen.

Password + Two-factor: LDAP and Kerberos allow authentication with either one of the authentication types but Kerberos uses pre-authentication method which requires to use armor ccache.

RADIUS with another type: Kerberos always use RADIUS, but LDAP never does. LDAP only recognize the password and two-factor authentication options.

", + "type_otp": "Two factor authentication (password + OTP)", + "type_password": "Password", + "type_radius": "Radius", + "type_disabled": "Disable per-user override", +- "user_tooltip": "Per-user setting, overwrites the global setting if any option is checked." ++ "user_tooltip": "

Per-user setting, overwrites the global setting if any option is checked.

Password + Two-factor: LDAP and Kerberos allow authentication with either one of the authentication types but Kerberos uses pre-authentication method which requires to use armor ccache.

RADIUS with another type: Kerberos always use RADIUS, but LDAP never does. LDAP only recognize the password and two-factor authentication options.

", + }, + "buttons": { + "about": "About", +diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py +index f97885ceae8f3c0913a16c281c2faa8a918541e7..e1904d2d3d1e1523895554b8d8e58b1dfd070366 100644 +--- a/ipalib/plugins/internal.py ++++ b/ipalib/plugins/internal.py +@@ -191,12 +191,12 @@ class i18n_messages(Command): + "show_results": _("Show Results"), + }, + "authtype": { +- "config_tooltip": _("Implicit method (password) will be used if no method is chosen."), ++ "config_tooltip": _("

Implicit method (password) will be used if no method is chosen.

Password + Two-factor: LDAP and Kerberos allow authentication with either one of the authentication types but Kerberos uses pre-authentication method which requires to use armor ccache.

RADIUS with another type: Kerberos always use RADIUS, but LDAP never does. LDAP only recognize the password and two-factor authentication options.

"), + "type_otp": _("Two factor authentication (password + OTP)"), + "type_password": _("Password"), + "type_radius": _("Radius"), + "type_disabled": _("Disable per-user override"), +- "user_tooltip": _("Per-user setting, overwrites the global setting if any option is checked."), ++ "user_tooltip": _("

Per-user setting, overwrites the global setting if any option is checked.

Password + Two-factor: LDAP and Kerberos allow authentication with either one of the authentication types but Kerberos uses pre-authentication method which requires to use armor ccache.

RADIUS with another type: Kerberos always use RADIUS, but LDAP never does. LDAP only recognize the password and two-factor authentication options.

"), + }, + "buttons": { + "about": _("About"), +-- +2.4.3 + diff --git a/SOURCES/0046-Fix-read_ip_addresses-should-return-ipaddr-object.patch b/SOURCES/0046-Fix-read_ip_addresses-should-return-ipaddr-object.patch deleted file mode 100644 index f8c56c9..0000000 --- a/SOURCES/0046-Fix-read_ip_addresses-should-return-ipaddr-object.patch +++ /dev/null @@ -1,30 +0,0 @@ -From fa9c01f32c4c12db64bfeed287ca546223c2afbd Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 20 Nov 2014 17:45:46 +0100 -Subject: [PATCH] Fix: read_ip_addresses should return ipaddr object - -Interactive prompt callback returns list of str instead of CheckedIPAddress -instances. - -Ticket: https://fedorahosted.org/freeipa/ticket/4747 -Reviewed-By: Jan Cholasta ---- - ipaserver/install/installutils.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 1e010edc6bf569a879c4f68efd2b273f57b01770..b05b1550a3b7c33a939b4173e57bf1329581d58a 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -247,7 +247,7 @@ def read_ip_addresses(host_name, fstore): - except Exception, e: - print "Error: Invalid IP Address %s: %s" % (ip, e) - continue -- ips.append(ip) -+ ips.append(ip_parsed) - - return ips - --- -2.1.0 - diff --git a/SOURCES/0046-Fix-upgrade-of-sidgen-and-extdom-plugins.patch b/SOURCES/0046-Fix-upgrade-of-sidgen-and-extdom-plugins.patch new file mode 100644 index 0000000..c16440a --- /dev/null +++ b/SOURCES/0046-Fix-upgrade-of-sidgen-and-extdom-plugins.patch @@ -0,0 +1,99 @@ +From 0df0907537d53f731e5ffc833a7c8d2e2d1a51f7 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Mon, 10 Aug 2015 10:53:28 +0200 +Subject: [PATCH] Fix upgrade of sidgen and extdom plugins + +If configuration entries already exist, upgrade will not add them +again. + +https://fedorahosted.org/freeipa/ticket/5151 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/dsinstance.py | 28 +++++++++++++++++++++++++--- + ipaserver/install/server/upgrade.py | 9 ++++++--- + 2 files changed, 31 insertions(+), 6 deletions(-) + +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index b2558024f0b345700bc544757e0eecd8b1052a1d..f33a9e03a4148dde69fc61441c878f5126f8e455 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -925,20 +925,42 @@ class DsInstance(service.Service): + def __add_range_check_plugin(self): + self._ldap_mod("range-check-conf.ldif", self.sub_dict) + +- # These two methods are not local, they are also called from the upgrade code + def _add_sidgen_plugin(self): + """ + Add sidgen directory server plugin configuration if it does not already exist. + """ + self._ldap_mod('ipa-sidgen-conf.ldif', self.sub_dict) + ++ def add_sidgen_plugin(self): ++ """ ++ Add sidgen plugin configuration only if it does not already exist. ++ """ ++ dn = DN('cn=IPA SIDGEN,cn=plugins,cn=config') ++ try: ++ self.admin_conn.get_entry(dn) ++ except errors.NotFound: ++ self._add_sidgen_plugin() ++ else: ++ root_logger.debug("sidgen plugin is already configured") ++ + def _add_extdom_plugin(self): + """ +- Add directory server configuration for the extdom extended operation +- if it does not already exist. ++ Add directory server configuration for the extdom extended operation. + """ + self._ldap_mod('ipa-extdom-extop-conf.ldif', self.sub_dict) + ++ def add_extdom_plugin(self): ++ """ ++ Add extdom configuration if it does not already exist. ++ """ ++ dn = DN('cn=ipa_extdom_extop,cn=plugins,cn=config') ++ try: ++ self.admin_conn.get_entry(dn) ++ except errors.NotFound: ++ self._add_extdom_plugin() ++ else: ++ root_logger.debug("extdom plugin is already configured") ++ + def replica_populate(self): + self.ldap_connect() + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index f295655dc2aa592e0215f15017c9b65af49eef80..037127918cb4c205c5049446989bfdaa674967a4 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1261,11 +1261,11 @@ def ds_enable_sidgen_extdom_plugins(ds): + root_logger.info('[Enable sidgen and extdom plugins by default]') + + if sysupgrade.get_upgrade_state('ds', 'enable_ds_sidgen_extdom_plugins'): +- root_logger.info('sidgen and extdom plugins are enabled already') ++ root_logger.debug('sidgen and extdom plugins are enabled already') + return + +- ds._add_sidgen_plugin() +- ds._add_extdom_plugin() ++ ds.add_sidgen_plugin() ++ ds.add_extdom_plugin() + sysupgrade.set_upgrade_state('ds', 'enable_ds_sidgen_extdom_plugins', True) + + def ca_upgrade_schema(ca): +@@ -1415,7 +1415,10 @@ def upgrade_configuration(): + ds.fqdn = fqdn + ds.realm = api.env.realm + ds.suffix = ipautil.realm_to_suffix(api.env.realm) ++ ++ ds.ldap_connect() + ds_enable_sidgen_extdom_plugins(ds) ++ ds.ldap_disconnect() + + # Now 389-ds is available, run the remaining http tasks + if not http.is_kdcproxy_configured(): +-- +2.4.3 + diff --git a/SOURCES/0047-Give-more-info-on-virtual-command-access-denial.patch b/SOURCES/0047-Give-more-info-on-virtual-command-access-denial.patch new file mode 100644 index 0000000..8c25117 --- /dev/null +++ b/SOURCES/0047-Give-more-info-on-virtual-command-access-denial.patch @@ -0,0 +1,30 @@ +From 7416358e95e69a517424319ac31dfcc68bda2878 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Sun, 9 Aug 2015 01:54:41 -0400 +Subject: [PATCH] Give more info on virtual command access denial + +The current error message upon a virutal command access denial does +not give any information about the virtual operation that was +prohibited. Add more information to the ACIError message. + +Reviewed-By: Martin Babinsky +--- + ipalib/plugins/virtual.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/virtual.py b/ipalib/plugins/virtual.py +index 414de4c0011b4ae49083d7820a3cb3708e3e16b1..3bbe32e538ab108d7abc71785e27664fea5ea248 100644 +--- a/ipalib/plugins/virtual.py ++++ b/ipalib/plugins/virtual.py +@@ -62,7 +62,7 @@ class VirtualCommand(Command): + try: + if not ldap.can_write(operationdn, "objectclass"): + raise errors.ACIError( +- info=_('not allowed to perform this command')) ++ info=_('not allowed to perform operation: %s') % operation) + except errors.NotFound: + raise errors.ACIError(info=_('No such virtual command')) + +-- +2.4.3 + diff --git a/SOURCES/0047-Use-correct-service-name-in-cainstance.backup_config.patch b/SOURCES/0047-Use-correct-service-name-in-cainstance.backup_config.patch deleted file mode 100644 index 8ba39fc..0000000 --- a/SOURCES/0047-Use-correct-service-name-in-cainstance.backup_config.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 5147e5f6c0aa53201938f1d3f25316089434fcc2 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Fri, 21 Nov 2014 07:52:24 +0000 -Subject: [PATCH] Use correct service name in cainstance.backup_config - -https://fedorahosted.org/freeipa/ticket/4754 - -Reviewed-By: Martin Kosek ---- - ipaserver/install/cainstance.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 0c31d21648689ad5c577e9112fefdf47857b4915..ac494917744ce0fa2d8e38ce5ce9dab6b24bdebf 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1861,7 +1861,8 @@ def backup_config(dogtag_constants=None): - if dogtag_constants is None: - dogtag_constants = dogtag.configured_constants() - -- if services.knownservices.dogtag.is_running(): -+ if services.knownservices[dogtag_constants.SERVICE_NAME].is_running( -+ dogtag_constants.PKI_INSTANCE_NAME): - raise RuntimeError("Dogtag must be stopped when creating backup of %s" - % dogtag_constants.CS_CFG_PATH) - shutil.copy(dogtag_constants.CS_CFG_PATH, --- -2.1.0 - diff --git a/SOURCES/0048-Allow-SAN-extension-for-cert-request-self-service.patch b/SOURCES/0048-Allow-SAN-extension-for-cert-request-self-service.patch new file mode 100644 index 0000000..5de2f41 --- /dev/null +++ b/SOURCES/0048-Allow-SAN-extension-for-cert-request-self-service.patch @@ -0,0 +1,33 @@ +From a7532af44e518994b8124b09e32fb3f494150ba6 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Sun, 9 Aug 2015 03:25:58 -0400 +Subject: [PATCH] Allow SAN extension for cert-request self-service + +Users cannot self-issue a certificate with a subjectAltName +extension (e.g. with rfc822Name altNames). Suppress the +cert-request "request certificate with subjectaltname" permission +check when the bind principal is the target principal (i.e. +cert-request self-service). + +Fixes: https://fedorahosted.org/freeipa/ticket/5190 +Reviewed-By: Martin Babinsky +--- + ipalib/plugins/cert.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py +index 341bdd01766d50ba18ce7147d4408851e6f95487..d612e9d38da44e4fd4768d286f930e51c71a1031 100644 +--- a/ipalib/plugins/cert.py ++++ b/ipalib/plugins/cert.py +@@ -369,7 +369,7 @@ class cert_request(VirtualCommand): + error=_("Failure decoding Certificate Signing Request: %s") % e) + + # host principals may bypass allowed ext check +- if bind_principal_type != HOST: ++ if bind_principal != principal and bind_principal_type != HOST: + for ext in extensions: + operation = self._allowed_extensions.get(ext) + if operation: +-- +2.4.3 + diff --git a/SOURCES/0048-ipa-restore-Check-if-directory-is-provided-better-er.patch b/SOURCES/0048-ipa-restore-Check-if-directory-is-provided-better-er.patch deleted file mode 100644 index 0568548..0000000 --- a/SOURCES/0048-ipa-restore-Check-if-directory-is-provided-better-er.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 354f11fc9f417ba777e2e010597e72a013ae5d23 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Fri, 21 Nov 2014 06:30:17 -0500 -Subject: [PATCH] ipa-restore: Check if directory is provided + better errors. - -https://fedorahosted.org/freeipa/ticket/4683 - -Reviewed-By: Tomas Babej ---- - ipaserver/install/ipa_restore.py | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 93f176d302a49319940555a0be3037620143e1f3..f290bae4dc6455bb22c4e726e72efe98205d970e 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -152,6 +152,9 @@ class Restore(admintool.AdminTool): - else: - self.backup_dir = dirname - -+ if not os.path.isdir(dirname): -+ raise self.option_parser.error("must provide path to backup directory") -+ - if options.gpg_keyring: - if (not os.path.exists(options.gpg_keyring + '.pub') or - not os.path.exists(options.gpg_keyring + '.sec')): -@@ -213,7 +216,10 @@ class Restore(admintool.AdminTool): - try: - dirsrv = services.knownservices.dirsrv - -- self.read_header() -+ try: -+ self.read_header() -+ except IOError as e: -+ raise admintool.ScriptError('Cannot read backup metadata: %s' % e) - # These two checks would normally be in the validate method but - # we need to know the type of backup we're dealing with. - if (self.backup_type != 'FULL' and not options.data_only and -@@ -546,9 +552,9 @@ class Restore(admintool.AdminTool): - Read the backup file header that contains the meta data about - this particular backup. - ''' -- fd = open(self.header) -- config = SafeConfigParser() -- config.readfp(fd) -+ with open(self.header) as fd: -+ config = SafeConfigParser() -+ config.readfp(fd) - - self.backup_type = config.get('ipa', 'type') - self.backup_time = config.get('ipa', 'time') --- -2.1.0 - diff --git a/SOURCES/0049-Add-profile-for-DNP3-IEC-62351-8-certificates.patch b/SOURCES/0049-Add-profile-for-DNP3-IEC-62351-8-certificates.patch new file mode 100644 index 0000000..89d69ff --- /dev/null +++ b/SOURCES/0049-Add-profile-for-DNP3-IEC-62351-8-certificates.patch @@ -0,0 +1,180 @@ +From cfd3cbe627870f6a575e1fbdc52896c22bce4dcd Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Fri, 24 Jul 2015 09:32:51 -0400 +Subject: [PATCH] Add profile for DNP3 / IEC 62351-8 certificates + +The DNP3 smart-grid standard uses certificate with the IEC 62351-8 +IECUserRoles extension. Add a profile for DNP3 certificates which +copies the IECUserRoles extension from the CSR, if present. + +Also update cert-request to accept CSRs containing this extension. + +Fixes: https://fedorahosted.org/freeipa/ticket/4752 +Reviewed-By: Martin Babinsky +--- + install/share/profiles/IECUserRoles.cfg | 114 ++++++++++++++++++++++++++++++++ + install/share/profiles/Makefile.am | 1 + + ipalib/plugins/cert.py | 1 + + ipapython/dogtag.py | 1 + + 4 files changed, 117 insertions(+) + create mode 100644 install/share/profiles/IECUserRoles.cfg + +diff --git a/install/share/profiles/IECUserRoles.cfg b/install/share/profiles/IECUserRoles.cfg +new file mode 100644 +index 0000000000000000000000000000000000000000..9d2b4bb7932db42f6fc1f4e8edbc2bb741d8d8b6 +--- /dev/null ++++ b/install/share/profiles/IECUserRoles.cfg +@@ -0,0 +1,114 @@ ++profileId=IECUserRoles ++classId=caEnrollImpl ++desc=Enroll user certificates with IECUserRoles extension via IPA-RA agent authentication. ++visible=false ++enable=true ++enableBy=admin ++auth.instance_id=raCertAuth ++name=IPA-RA Agent-Authenticated Server Certificate Enrollment ++input.list=i1,i2 ++input.i1.class_id=certReqInputImpl ++input.i2.class_id=submitterInfoInputImpl ++output.list=o1 ++output.o1.class_id=certOutputImpl ++policyset.list=serverCertSet ++policyset.serverCertSet.list=1,2,3,4,5,6,7,8,9,10,11,12 ++policyset.serverCertSet.1.constraint.class_id=subjectNameConstraintImpl ++policyset.serverCertSet.1.constraint.name=Subject Name Constraint ++policyset.serverCertSet.1.constraint.params.pattern=CN=[^,]+,.+ ++policyset.serverCertSet.1.constraint.params.accept=true ++policyset.serverCertSet.1.default.class_id=subjectNameDefaultImpl ++policyset.serverCertSet.1.default.name=Subject Name Default ++policyset.serverCertSet.1.default.params.name=CN=$$request.req_subject_name.cn$$, $SUBJECT_DN_O ++policyset.serverCertSet.2.constraint.class_id=validityConstraintImpl ++policyset.serverCertSet.2.constraint.name=Validity Constraint ++policyset.serverCertSet.2.constraint.params.range=740 ++policyset.serverCertSet.2.constraint.params.notBeforeCheck=false ++policyset.serverCertSet.2.constraint.params.notAfterCheck=false ++policyset.serverCertSet.2.default.class_id=validityDefaultImpl ++policyset.serverCertSet.2.default.name=Validity Default ++policyset.serverCertSet.2.default.params.range=731 ++policyset.serverCertSet.2.default.params.startTime=0 ++policyset.serverCertSet.3.constraint.class_id=keyConstraintImpl ++policyset.serverCertSet.3.constraint.name=Key Constraint ++policyset.serverCertSet.3.constraint.params.keyType=RSA ++policyset.serverCertSet.3.constraint.params.keyParameters=1024,2048,3072,4096 ++policyset.serverCertSet.3.default.class_id=userKeyDefaultImpl ++policyset.serverCertSet.3.default.name=Key Default ++policyset.serverCertSet.4.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.4.constraint.name=No Constraint ++policyset.serverCertSet.4.default.class_id=authorityKeyIdentifierExtDefaultImpl ++policyset.serverCertSet.4.default.name=Authority Key Identifier Default ++policyset.serverCertSet.5.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.5.constraint.name=No Constraint ++policyset.serverCertSet.5.default.class_id=authInfoAccessExtDefaultImpl ++policyset.serverCertSet.5.default.name=AIA Extension Default ++policyset.serverCertSet.5.default.params.authInfoAccessADEnable_0=true ++policyset.serverCertSet.5.default.params.authInfoAccessADLocationType_0=URIName ++policyset.serverCertSet.5.default.params.authInfoAccessADLocation_0=http://$IPA_CA_RECORD.$DOMAIN/ca/ocsp ++policyset.serverCertSet.5.default.params.authInfoAccessADMethod_0=1.3.6.1.5.5.7.48.1 ++policyset.serverCertSet.5.default.params.authInfoAccessCritical=false ++policyset.serverCertSet.5.default.params.authInfoAccessNumADs=1 ++policyset.serverCertSet.6.constraint.class_id=keyUsageExtConstraintImpl ++policyset.serverCertSet.6.constraint.name=Key Usage Extension Constraint ++policyset.serverCertSet.6.constraint.params.keyUsageCritical=true ++policyset.serverCertSet.6.constraint.params.keyUsageDigitalSignature=true ++policyset.serverCertSet.6.constraint.params.keyUsageNonRepudiation=true ++policyset.serverCertSet.6.constraint.params.keyUsageDataEncipherment=true ++policyset.serverCertSet.6.constraint.params.keyUsageKeyEncipherment=true ++policyset.serverCertSet.6.constraint.params.keyUsageKeyAgreement=false ++policyset.serverCertSet.6.constraint.params.keyUsageKeyCertSign=false ++policyset.serverCertSet.6.constraint.params.keyUsageCrlSign=false ++policyset.serverCertSet.6.constraint.params.keyUsageEncipherOnly=false ++policyset.serverCertSet.6.constraint.params.keyUsageDecipherOnly=false ++policyset.serverCertSet.6.default.class_id=keyUsageExtDefaultImpl ++policyset.serverCertSet.6.default.name=Key Usage Default ++policyset.serverCertSet.6.default.params.keyUsageCritical=true ++policyset.serverCertSet.6.default.params.keyUsageDigitalSignature=true ++policyset.serverCertSet.6.default.params.keyUsageNonRepudiation=true ++policyset.serverCertSet.6.default.params.keyUsageDataEncipherment=true ++policyset.serverCertSet.6.default.params.keyUsageKeyEncipherment=true ++policyset.serverCertSet.6.default.params.keyUsageKeyAgreement=false ++policyset.serverCertSet.6.default.params.keyUsageKeyCertSign=false ++policyset.serverCertSet.6.default.params.keyUsageCrlSign=false ++policyset.serverCertSet.6.default.params.keyUsageEncipherOnly=false ++policyset.serverCertSet.6.default.params.keyUsageDecipherOnly=false ++policyset.serverCertSet.7.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.7.constraint.name=No Constraint ++policyset.serverCertSet.7.default.class_id=extendedKeyUsageExtDefaultImpl ++policyset.serverCertSet.7.default.name=Extended Key Usage Extension Default ++policyset.serverCertSet.7.default.params.exKeyUsageCritical=false ++policyset.serverCertSet.7.default.params.exKeyUsageOIDs=1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2 ++policyset.serverCertSet.8.constraint.class_id=signingAlgConstraintImpl ++policyset.serverCertSet.8.constraint.name=No Constraint ++policyset.serverCertSet.8.constraint.params.signingAlgsAllowed=SHA1withRSA,SHA256withRSA,SHA512withRSA,MD5withRSA,MD2withRSA,SHA1withDSA,SHA1withEC,SHA256withEC,SHA384withEC,SHA512withEC ++policyset.serverCertSet.8.default.class_id=signingAlgDefaultImpl ++policyset.serverCertSet.8.default.name=Signing Alg ++policyset.serverCertSet.8.default.params.signingAlg=- ++policyset.serverCertSet.9.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.9.constraint.name=No Constraint ++policyset.serverCertSet.9.default.class_id=crlDistributionPointsExtDefaultImpl ++policyset.serverCertSet.9.default.name=CRL Distribution Points Extension Default ++policyset.serverCertSet.9.default.params.crlDistPointsCritical=false ++policyset.serverCertSet.9.default.params.crlDistPointsNum=1 ++policyset.serverCertSet.9.default.params.crlDistPointsEnable_0=true ++policyset.serverCertSet.9.default.params.crlDistPointsIssuerName_0=$CRL_ISSUER ++policyset.serverCertSet.9.default.params.crlDistPointsIssuerType_0=DirectoryName ++policyset.serverCertSet.9.default.params.crlDistPointsPointName_0=http://$IPA_CA_RECORD.$DOMAIN/ipa/crl/MasterCRL.bin ++policyset.serverCertSet.9.default.params.crlDistPointsPointType_0=URIName ++policyset.serverCertSet.9.default.params.crlDistPointsReasons_0= ++policyset.serverCertSet.10.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.10.constraint.name=No Constraint ++policyset.serverCertSet.10.default.class_id=subjectKeyIdentifierExtDefaultImpl ++policyset.serverCertSet.10.default.name=Subject Key Identifier Extension Default ++policyset.serverCertSet.10.default.params.critical=false ++policyset.serverCertSet.11.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.11.constraint.name=No Constraint ++policyset.serverCertSet.11.default.class_id=userExtensionDefaultImpl ++policyset.serverCertSet.11.default.name=User Supplied Extension Default ++policyset.serverCertSet.11.default.params.userExtOID=2.5.29.17 ++policyset.serverCertSet.12.constraint.class_id=noConstraintImpl ++policyset.serverCertSet.12.constraint.name=No Constraint ++policyset.serverCertSet.12.default.class_id=userExtensionDefaultImpl ++policyset.serverCertSet.12.default.name=IECUserRoles Extension Default ++policyset.serverCertSet.12.default.params.userExtOID=1.2.840.10070.8.1 +diff --git a/install/share/profiles/Makefile.am b/install/share/profiles/Makefile.am +index 4e6cf975a0f51d02ec29bd07ac8cb9ccc8320818..b5ccb6e9317a93c040b7de0e0bc1ca5cb88c33fc 100644 +--- a/install/share/profiles/Makefile.am ++++ b/install/share/profiles/Makefile.am +@@ -3,6 +3,7 @@ NULL = + appdir = $(IPA_DATA_DIR)/profiles + app_DATA = \ + caIPAserviceCert.cfg \ ++ IECUserRoles.cfg \ + $(NULL) + + EXTRA_DIST = \ +diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py +index d612e9d38da44e4fd4768d286f930e51c71a1031..b6e6d7981846778896eabce1a29a88fdf9a639e1 100644 +--- a/ipalib/plugins/cert.py ++++ b/ipalib/plugins/cert.py +@@ -312,6 +312,7 @@ class cert_request(VirtualCommand): + '2.5.29.17': 'request certificate with subjectaltname', + '2.5.29.19': None, # Basic Constraints + '2.5.29.37': None, # Extended Key Usage ++ '1.2.840.10070.8.1': None, # IECUserRoles (DNP3 / IEC 62351-8) + } + + def execute(self, csr, **kw): +diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py +index 53085f7762fc828ed9fc6621fbf3a0c67ec6a656..0782d360ccf2ce2c90c4e9cfa66b5159e437e77c 100644 +--- a/ipapython/dogtag.py ++++ b/ipapython/dogtag.py +@@ -45,6 +45,7 @@ from ipapython.ipa_log_manager import * + INCLUDED_PROFILES = { + # ( profile_id , description , store_issued) + (u'caIPAserviceCert', u'Standard profile for network services', True), ++ (u'IECUserRoles', u'User profile that includes IECUserRoles extension from request', True), + } + + DEFAULT_PROFILE = u'caIPAserviceCert' +-- +2.4.3 + diff --git a/SOURCES/0049-Stop-tracking-certificates-before-restoring-them-in-.patch b/SOURCES/0049-Stop-tracking-certificates-before-restoring-them-in-.patch deleted file mode 100644 index f8870c5..0000000 --- a/SOURCES/0049-Stop-tracking-certificates-before-restoring-them-in-.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 318a05f1564e95ae3516d7cfdb6cd7c03a87b87d Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 20 Nov 2014 13:57:46 +0000 -Subject: [PATCH] Stop tracking certificates before restoring them in - ipa-restore - -https://fedorahosted.org/freeipa/ticket/4727 - -Reviewed-By: Petr Vobornik ---- - ipaserver/install/ipa_restore.py | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index f290bae4dc6455bb22c4e726e72efe98205d970e..9cb978a516f4f85307735b7428f6053461061022 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -26,7 +26,7 @@ import pwd - from ConfigParser import SafeConfigParser - - from ipalib import api, errors --from ipapython import version, ipautil, certdb -+from ipapython import version, ipautil, certdb, dogtag - from ipapython.ipautil import run, user_input - from ipapython import admintool - from ipapython.dn import DN -@@ -36,7 +36,7 @@ from ipaserver.install.cainstance import PKI_USER, create_ca_user - from ipaserver.install.replication import (wait_for_task, ReplicationManager, - get_cs_replication_manager) - from ipaserver.install import installutils --from ipaserver.install import httpinstance -+from ipaserver.install import dsinstance, httpinstance, cainstance - from ipapython import ipaldap - import ipapython.errors - from ipaplatform.tasks import tasks -@@ -676,6 +676,12 @@ class Restore(admintool.AdminTool): - self.log.error('%s', e) - - def cert_restore_prepare(self): -+ cainstance.stop_tracking_certificates( -+ dogtag.configured_constants()) -+ httpinstance.HTTPInstance().stop_tracking_certificates() -+ dsinstance.DsInstance().stop_tracking_certificates( -+ realm_to_serverid(api.env.realm)) -+ - for basename in ('cert8.db', 'key3.db', 'secmod.db', 'pwdfile.txt'): - filename = os.path.join(paths.IPA_NSSDB_DIR, basename) - try: -@@ -705,3 +711,5 @@ class Restore(admintool.AdminTool): - (nickname, paths.IPA_NSSDB_DIR, e)) - - tasks.reload_systemwide_ca_store() -+ -+ services.knownservices.certmonger.restart() --- -2.1.0 - diff --git a/SOURCES/0050-Fix-detection-of-encoding-in-zonemgr-option.patch b/SOURCES/0050-Fix-detection-of-encoding-in-zonemgr-option.patch deleted file mode 100644 index 2a526dd..0000000 --- a/SOURCES/0050-Fix-detection-of-encoding-in-zonemgr-option.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 296656789c1bc8e2667c989d10cac300f8b5b7fc Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Mon, 24 Nov 2014 12:46:37 +0100 -Subject: [PATCH] Fix detection of encoding in zonemgr option - -Ticket: https://fedorahosted.org/freeipa/ticket/4762 -Reviewed-By: Jan Cholasta ---- - ipaserver/install/bindinstance.py | 15 ++++++++------- - 1 file changed, 8 insertions(+), 7 deletions(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 5bf784e62aec7c323a84fc5130e53c3deb86e6fd..f02fe8647dd38d05734311406152c50108077561 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -401,13 +401,14 @@ def zonemgr_callback(option, opt_str, value, parser): - """ - Properly validate and convert --zonemgr Option to IA5String - """ -- # validate the value first -- try: -- # IDNA support requires unicode -- value = value.decode(sys.stdin.encoding) -- validate_zonemgr_str(value) -- except ValueError, e: -- parser.error("invalid zonemgr: " + unicode(e)) -+ if value is not None: -+ # validate the value first -+ try: -+ # IDNA support requires unicode -+ value = value.decode(getattr(sys.stdin, 'encoding', 'utf-8')) -+ validate_zonemgr_str(value) -+ except ValueError, e: -+ parser.error("invalid zonemgr: " + unicode(e)) - - parser.values.zonemgr = value - --- -2.1.0 - diff --git a/SOURCES/0050-Work-around-python-nss-bug-on-unrecognised-OIDs.patch b/SOURCES/0050-Work-around-python-nss-bug-on-unrecognised-OIDs.patch new file mode 100644 index 0000000..afa5653 --- /dev/null +++ b/SOURCES/0050-Work-around-python-nss-bug-on-unrecognised-OIDs.patch @@ -0,0 +1,50 @@ +From 688660a0545f5a29b6f4f2f06bbef23d3dbef688 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Fri, 24 Jul 2015 09:23:07 -0400 +Subject: [PATCH] Work around python-nss bug on unrecognised OIDs + +A bug in python-nss causes an error to be thrown when converting an +unrecognised OID to a string. If cert-request receives a PKCS #10 +CSR with an unknown extension, the error is thrown. + +Work around this error by first checking if the OID is recognised +and, if it is not, using a different method to obtain its string +representation. + +Once the python-nss bug is fixed, this workaround should be +reverted. https://bugzilla.redhat.com/show_bug.cgi?id=1246729 + +Reviewed-By: Martin Babinsky +--- + ipalib/pkcs10.py | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/ipalib/pkcs10.py b/ipalib/pkcs10.py +index 6299dfea43b7a3f4104f0b0ec78c4f105d9daf62..64670835127e96f1d724c5f32ed7a939d37b7f16 100644 +--- a/ipalib/pkcs10.py ++++ b/ipalib/pkcs10.py +@@ -53,7 +53,20 @@ def get_extensions(csr, datatype=PEM): + The return value is a tuple of strings + """ + request = load_certificate_request(csr, datatype) +- return tuple(nss.oid_dotted_decimal(ext.oid_tag)[4:] ++ ++ # Work around a bug in python-nss where nss.oid_dotted_decimal ++ # errors on unrecognised OIDs ++ # ++ # https://bugzilla.redhat.com/show_bug.cgi?id=1246729 ++ # ++ def get_prefixed_oid_str(ext): ++ """Returns a string like 'OID.1.2...'.""" ++ if ext.oid_tag == 0: ++ return repr(ext) ++ else: ++ return nss.oid_dotted_decimal(ext.oid) ++ ++ return tuple(get_prefixed_oid_str(ext)[4:] + for ext in request.extensions) + + class _PrincipalName(univ.Sequence): +-- +2.4.3 + diff --git a/SOURCES/0051-adtrust-install-Correctly-determine-4.2-FreeIPA-serv.patch b/SOURCES/0051-adtrust-install-Correctly-determine-4.2-FreeIPA-serv.patch new file mode 100644 index 0000000..6c46e62 --- /dev/null +++ b/SOURCES/0051-adtrust-install-Correctly-determine-4.2-FreeIPA-serv.patch @@ -0,0 +1,35 @@ +From 6cc7d00a8d6966b4be24fa9b3df12dcba094b6ef Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Tue, 11 Aug 2015 16:05:32 +0200 +Subject: [PATCH] adtrust-install: Correctly determine 4.2 FreeIPA servers + +We need to detect a list of FreeIPA 4.2 (and above) servers, since +only there is the required version of SSSD present. + +Since the maximum domain level for 4.2 is 0 (and not 1), we can filter +for any value of ipaMaxDomainLevel / ipaMinDomainLevel attributes +to generate the list. + +https://fedorahosted.org/freeipa/ticket/5199 + +Reviewed-By: Alexander Bokovoy +--- + install/tools/ipa-adtrust-install | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install +index 5340c31d16ed78da0cb39725d9ae93c76470b698..21e58dd9f25e82429ce8d0c776d1b512c2661809 100755 +--- a/install/tools/ipa-adtrust-install ++++ b/install/tools/ipa-adtrust-install +@@ -396,7 +396,7 @@ def main(): + # Search only masters which have support for domain levels + # because only these masters will have SSSD recent enough to support AD trust agents + (entries_m, truncated) = smb.admin_conn.find_entries( +- filter="(&(objectclass=ipaSupportedDomainLevelConfig)(!(ipaMaxDomainLevel=0)))", ++ filter="(&(objectclass=ipaSupportedDomainLevelConfig)(ipaMaxDomainLevel=*)(ipaMinDomainLevel=*))", + base_dn=masters_dn, attrs_list=['cn'], scope=ldap.SCOPE_ONELEVEL) + except errors.NotFound: + pass +-- +2.4.3 + diff --git a/SOURCES/0051-webui-use-domain-name-instead-of-domain-SID-in-idran.patch b/SOURCES/0051-webui-use-domain-name-instead-of-domain-SID-in-idran.patch deleted file mode 100644 index 63d5bae..0000000 --- a/SOURCES/0051-webui-use-domain-name-instead-of-domain-SID-in-idran.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 8918cc58cb4cd24a4332c9935be75add89fd3c8b Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Tue, 4 Nov 2014 13:38:12 +0100 -Subject: [PATCH] webui: use domain name instead of domain SID in idrange adder - dialog - -It's more user friendly. Almost nobody remembers SIDs. - -https://fedorahosted.org/freeipa/ticket/4661 - -Reviewed-By: Tomas Babej ---- - install/ui/src/freeipa/idrange.js | 16 +++++++--------- - ipatests/test_webui/task_range.py | 20 ++++++++++---------- - ipatests/test_webui/test_range.py | 4 ++-- - 3 files changed, 19 insertions(+), 21 deletions(-) - -diff --git a/install/ui/src/freeipa/idrange.js b/install/ui/src/freeipa/idrange.js -index 4e5dbfa00dcf80495d8a96f7fc961b9c6676691f..8af1598af335db2429512910d286bc3bada7b325 100644 ---- a/install/ui/src/freeipa/idrange.js -+++ b/install/ui/src/freeipa/idrange.js -@@ -138,9 +138,7 @@ return { - title: '@mo-param:idrange:ipasecondarybaserid:label' - }, - { -- name: 'ipanttrusteddomainsid', -- label: '@i18n:objects.idrange.ipanttrusteddomainsid', -- title: '@mo-param:idrange:ipanttrusteddomainsid:label', -+ name: 'ipanttrusteddomainname', - enabled: false - } - ], -@@ -153,14 +151,14 @@ return { - IPA.idrange_adder_policy = function(spec) { - /* - The logic for enabling/requiring ipabaserid, ipasecondarybaserid and -- ipanttrusteddomainsid is as follows: -+ ipanttrusteddomainname is as follows: - 1) for AD ranges (range type is ipa-ad-trust or ipa-ad-trust-posix): -- * ipanttrusteddomainsid is required -+ * ipanttrusteddomainname is required - * ipabaserid is required for ipa-ad-trust but disabled for - ipa-ad-trust-posix - * ipasecondarybaserid is disabled - 2) for local ranges -- * ipanttrusteddomainsid is disabled -+ * ipanttrusteddomainname is disabled - A) if server has AD trust support: - * both ipabaserid and ipasecondarybaserid are required - B) if server does not have AD trust support: -@@ -207,7 +205,7 @@ IPA.idrange_adder_policy = function(spec) { - var type_f = that.container.fields.get_field('iparangetype'); - var baserid_f = that.container.fields.get_field('ipabaserid'); - var secondarybaserid_f = that.container.fields.get_field('ipasecondarybaserid'); -- var trusteddomainsid_f = that.container.fields.get_field('ipanttrusteddomainsid'); -+ var trusteddomainname_f = that.container.fields.get_field('ipanttrusteddomainname'); - - var type_v = type_f.get_value()[0]; - var baserid_v = baserid_f.get_value()[0] || ''; -@@ -221,10 +219,10 @@ IPA.idrange_adder_policy = function(spec) { - } else { - disable(baserid_f); - } -- require(trusteddomainsid_f); -+ require(trusteddomainname_f); - disable(secondarybaserid_f); - } else { -- disable(trusteddomainsid_f); -+ disable(trusteddomainname_f); - - if (IPA.trust_enabled) { - require(baserid_f); -diff --git a/ipatests/test_webui/task_range.py b/ipatests/test_webui/task_range.py -index d46d345f03a2b50730e3107ef6f7c2222da4465c..b71285d1e6056b11e3e74703a568be27973de3bc 100644 ---- a/ipatests/test_webui/task_range.py -+++ b/ipatests/test_webui/task_range.py -@@ -59,13 +59,13 @@ class range_tasks(UI_driver): - self.max_id = max_id - self.max_rid = max_rid - -- def get_sid(self): -+ def get_domain(self): - result = self.execute_api_from_ui('trust_find', [], {}) - trusts = result['result']['result'] -- sid = None -+ domain = None - if trusts: -- sid = trusts[0]['ipanttrusteddomainsid'] -- return sid -+ domain = trusts[0]['cn'] -+ return domain - - def get_data(self, pkey, size=50, add_data=None): - -@@ -81,7 +81,7 @@ class range_tasks(UI_driver): - } - return data - -- def get_add_data(self, pkey, range_type='ipa-local', size=50, shift=100, sid=None): -+ def get_add_data(self, pkey, range_type='ipa-local', size=50, shift=100, domain=None): - - base_id = self.max_id + shift - self.max_id = base_id + size -@@ -98,19 +98,19 @@ class range_tasks(UI_driver): - ('callback', self.check_range_type_mod, range_type) - ] - -- if not sid: -+ if not domain: - base_rid = self.max_rid + shift - self.max_rid = base_rid + size - add.append(('textbox', 'ipasecondarybaserid', str(base_rid))) -- if sid: -- add.append(('textbox', 'ipanttrusteddomainsid', sid)) -+ if domain: -+ add.append(('textbox', 'ipanttrusteddomainname', domain)) - - return add - - def check_range_type_mod(self, range_type): - if range_type == 'ipa-local': -- self.assert_disabled("[name=ipanttrusteddomainsid]") -+ self.assert_disabled("[name=ipanttrusteddomainname]") - self.assert_disabled("[name=ipasecondarybaserid]", negative=True) - elif range_type == 'ipa-ad-trust': -- self.assert_disabled("[name=ipanttrusteddomainsid]", negative=True) -+ self.assert_disabled("[name=ipanttrusteddomainname]", negative=True) - self.assert_disabled("[name=ipasecondarybaserid]") -diff --git a/ipatests/test_webui/test_range.py b/ipatests/test_webui/test_range.py -index 5c2e33b90833d5e03014e72fad302e58c986ca25..e1c46e50a85171bafabe80bd772ed9ac983a6ca4 100644 ---- a/ipatests/test_webui/test_range.py -+++ b/ipatests/test_webui/test_range.py -@@ -74,11 +74,11 @@ class test_range(range_tasks): - - self.add_record(trust_mod.ENTITY, trust_data) - -- sid = self.get_sid() -+ domain = self.get_domain() - - self.navigate_to_entity(ENTITY) - -- add = self.get_add_data(pkey_ad, range_type='ipa-ad-trust', sid=sid) -+ add = self.get_add_data(pkey_ad, range_type='ipa-ad-trust', domain=domain) - data = self.get_data(pkey_ad, add_data=add) - self.add_record(ENTITY, data, navigate=False) - self.assert_record_value('Active Directory domain range', pkey_ad, column) --- -2.1.0 - diff --git a/SOURCES/0052-certprofile-import-improve-profile-format-documentat.patch b/SOURCES/0052-certprofile-import-improve-profile-format-documentat.patch new file mode 100644 index 0000000..e5e3287 --- /dev/null +++ b/SOURCES/0052-certprofile-import-improve-profile-format-documentat.patch @@ -0,0 +1,31 @@ +From c6c3ee0658fcda223bd98fed8d696bdb26add4ac Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 23 Jul 2015 18:22:19 +0200 +Subject: [PATCH] certprofile-import: improve profile format documentation + +The certprofile-import plugin expects a raw Dogtag config file. The XML +format is not supported. --help gives a hint about the correct file format. + +https://fedorahosted.org/freeipa/ticket/5089 + +Reviewed-By: Fraser Tweedale +--- + ipalib/plugins/certprofile.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index b0b76ca8e78f2482b5c08dad21d9161fd4c2c2d0..658fbca3b4eb851eb5a22190c443044f6ceb8491 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -221,7 +221,7 @@ class certprofile_import(LDAPCreate): + msg_summary = _('Imported profile "%(value)s"') + takes_options = ( + File('file', +- label=_('Filename'), ++ label=_('Filename of a raw profile. The XML format is not supported.'), + cli_name='file', + flags=('virtual_attribute',), + ), +-- +2.4.3 + diff --git a/SOURCES/0052-webui-normalize-idview-tab-labels.patch b/SOURCES/0052-webui-normalize-idview-tab-labels.patch deleted file mode 100644 index e00a15e..0000000 --- a/SOURCES/0052-webui-normalize-idview-tab-labels.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 6d8d3b19480e9072df1aababe14d449b64e25a55 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Tue, 4 Nov 2014 15:49:34 +0100 -Subject: [PATCH] webui: normalize idview tab labels - -ID View tab labels are no longer redundant. - -https://fedorahosted.org/freeipa/ticket/4650 - -Reviewed-By: Tomas Babej ---- - install/ui/src/freeipa/idviews.js | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/install/ui/src/freeipa/idviews.js b/install/ui/src/freeipa/idviews.js -index cbc78ae7c62916b6334a8ef0cdf12a92485b0876..823936401653096a0a649282e3b18f573de09804 100644 ---- a/install/ui/src/freeipa/idviews.js -+++ b/install/ui/src/freeipa/idviews.js -@@ -112,7 +112,7 @@ return { - nested_entity: 'idoverrideuser', - search_all_entries: true, - label: '@mo:idoverrideuser.label', -- tab_label: '@mo:idoverrideuser.label', -+ tab_label: '@mo:user.label', - name: 'idoverrideuser', - columns: [ - { -@@ -132,7 +132,7 @@ return { - nested_entity: 'idoverridegroup', - search_all_entries: true, - label: '@mo:idoverridegroup.label', -- tab_label: '@mo:idoverridegroup.label', -+ tab_label: '@mo:group.label', - name: 'idoverridegroup', - columns: [ - { -@@ -148,7 +148,7 @@ return { - $type: 'idview_appliedtohosts', - name: 'appliedtohosts', - attribute: 'appliedtohosts', -- tab_label: '@i18n:objects.idview.appliedtohosts', -+ tab_label: '@mo:host.label', - facet_group: 'appliedto', - actions: [ - 'idview_apply', --- -2.1.0 - diff --git a/SOURCES/0053-Fix-default-CA-ACL-added-during-upgrade.patch b/SOURCES/0053-Fix-default-CA-ACL-added-during-upgrade.patch new file mode 100644 index 0000000..7aa2975 --- /dev/null +++ b/SOURCES/0053-Fix-default-CA-ACL-added-during-upgrade.patch @@ -0,0 +1,31 @@ +From 3e8d1d09e5a1b19c64a0356d2b19dac74c20ad73 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Fri, 7 Aug 2015 03:21:43 -0400 +Subject: [PATCH] Fix default CA ACL added during upgrade + +The upgrade script is adding the default CA ACL with incorrect +attributes - usercategory=all instead of servicecategory=all. Fix +it to create the correct object. + +Fixes: https://fedorahosted.org/freeipa/ticket/5185 +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/upgrade.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 037127918cb4c205c5049446989bfdaa674967a4..692d0c77e0683f4ad35ebbc14d5a34decc098deb 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1306,7 +1306,7 @@ def add_default_caacl(ca): + + if not api.Command.caacl_find()['result']: + api.Command.caacl_add(u'hosts_services_caIPAserviceCert', +- hostcategory=u'all', usercategory=u'all') ++ hostcategory=u'all', servicecategory=u'all') + api.Command.caacl_add_profile(u'hosts_services_caIPAserviceCert', + certprofile=(u'caIPAserviceCert',)) + +-- +2.4.3 + diff --git a/SOURCES/0053-copy_schema_to_ca-Fallback-to-old-import-location-fo.patch b/SOURCES/0053-copy_schema_to_ca-Fallback-to-old-import-location-fo.patch deleted file mode 100644 index 080350d..0000000 --- a/SOURCES/0053-copy_schema_to_ca-Fallback-to-old-import-location-fo.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 5cea94bf6ba5ecbd9e18b0bf352ca82c62e6ee34 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 24 Nov 2014 15:01:29 +0100 -Subject: [PATCH] copy_schema_to_ca: Fallback to old import location for - ipaplatform.services - -This file is copied to older servers that might not have the ipaplatform -refactoring. -Import from the old location if the new one is not available. - -https://fedorahosted.org/freeipa/ticket/4763 - -Reviewed-By: Tomas Babej ---- - install/share/copy-schema-to-ca.py | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/install/share/copy-schema-to-ca.py b/install/share/copy-schema-to-ca.py -index fc53fe4cb52486cc618bec77aabe8283ad5eadbc..1614e11636c2f52e231ea2ff40d882209194c60a 100755 ---- a/install/share/copy-schema-to-ca.py -+++ b/install/share/copy-schema-to-ca.py -@@ -15,13 +15,17 @@ import sys - import pwd - import shutil - --from ipaplatform import services - from ipapython import ipautil, dogtag - from ipapython.ipa_log_manager import root_logger, standard_logging_setup - from ipaserver.install.dsinstance import DS_USER, schema_dirname - from ipaserver.install.cainstance import PKI_USER - from ipalib import api - -+try: -+ from ipaplatform import services -+except ImportError: -+ from ipapython import services # pylint: disable=no-name-in-module -+ - SERVERID = "PKI-IPA" - SCHEMA_FILENAMES = ( - "60kerberos.ldif", --- -2.1.0 - diff --git a/SOURCES/0054-Fix-KRB5PrincipalName-UPN-SAN-comparison.patch b/SOURCES/0054-Fix-KRB5PrincipalName-UPN-SAN-comparison.patch new file mode 100644 index 0000000..c17d7cf --- /dev/null +++ b/SOURCES/0054-Fix-KRB5PrincipalName-UPN-SAN-comparison.patch @@ -0,0 +1,35 @@ +From 34be9a7cd6eb4f379f09fd40d723fa83317f2b61 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Sun, 9 Aug 2015 05:55:04 -0400 +Subject: [PATCH] Fix KRB5PrincipalName / UPN SAN comparison + +Depending on how the target principal name is conveyed to the +command (i.e. with / without realm), the KRB5PrincipalName / UPN +subjectAltName validation could be comparing unequal strings and +erroneously rejecting a valid request. + +Normalise both side of the comparison to ensure that the principal +names contain realm information. + +Fixes: https://fedorahosted.org/freeipa/ticket/5191 +Reviewed-By: Martin Babinsky +--- + ipalib/plugins/cert.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py +index b6e6d7981846778896eabce1a29a88fdf9a639e1..610f2149363eaa74180e9de5c9ee1439446ef409 100644 +--- a/ipalib/plugins/cert.py ++++ b/ipalib/plugins/cert.py +@@ -474,7 +474,7 @@ class cert_request(VirtualCommand): + principal_type, alt_principal_string, ca, profile_id) + elif name_type in (pkcs10.SAN_OTHERNAME_KRB5PRINCIPALNAME, + pkcs10.SAN_OTHERNAME_UPN): +- if name != principal_string: ++ if split_any_principal(name) != principal: + raise errors.ACIError( + info=_("Principal '%s' in subject alt name does not " + "match requested principal") % name) +-- +2.4.3 + diff --git a/SOURCES/0054-Remove-redefinition-of-LOG-from-ipa-otp-lasttoken.patch b/SOURCES/0054-Remove-redefinition-of-LOG-from-ipa-otp-lasttoken.patch deleted file mode 100644 index bb2d6ec..0000000 --- a/SOURCES/0054-Remove-redefinition-of-LOG-from-ipa-otp-lasttoken.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b28d6f940b8e523d6077cddf6dbde40666428950 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 17:20:18 +0000 -Subject: [PATCH] Remove redefinition of LOG from ipa-otp-lasttoken - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -index d20fca1e705f7406362a3ba2def9ba102bd1622d..15b404dcdb6bd88c70ccc7c5fed7a5829483590b 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -@@ -47,9 +47,6 @@ - #include "util.h" - - #define PLUGIN_NAME "ipa-otp-lasttoken" --#define LOG(sev, ...) \ -- slapi_log_error(SLAPI_LOG_ ## sev, PLUGIN_NAME, \ -- "%s: %s\n", __func__, __VA_ARGS__), -1 - - static void *plugin_id; - static const Slapi_PluginDesc preop_desc = { --- -2.1.0 - diff --git a/SOURCES/0055-Unload-P11_Helper-object-s-library-when-it-is-finali.patch b/SOURCES/0055-Unload-P11_Helper-object-s-library-when-it-is-finali.patch deleted file mode 100644 index 2a2309d..0000000 --- a/SOURCES/0055-Unload-P11_Helper-object-s-library-when-it-is-finali.patch +++ /dev/null @@ -1,81 +0,0 @@ -From e31080c46bfba67d6ed3ac1fa8ded1cb69e4aa97 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 17:33:23 +0000 -Subject: [PATCH] Unload P11_Helper object's library when it is finalized in - ipap11helper - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - ipapython/ipap11helper/library.c | 5 +++++ - ipapython/ipap11helper/p11helper.c | 9 +++++++-- - 2 files changed, 12 insertions(+), 2 deletions(-) - -diff --git a/ipapython/ipap11helper/library.c b/ipapython/ipap11helper/library.c -index 51e24ebc2be5953a6820b768e75a3e8ccb026a64..619604dc6358e41c18c786adc64fe0326dde5f4b 100644 ---- a/ipapython/ipap11helper/library.c -+++ b/ipapython/ipap11helper/library.c -@@ -70,6 +70,11 @@ CK_C_GetFunctionList loadLibrary(char* module, void** moduleHandle) - - // Retrieve the entry point for C_GetFunctionList - pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList"); -+ if (pGetFunctionList == NULL) -+ { -+ dlclose(pDynLib); -+ return NULL; -+ } - - // Store the handle so we can dlclose it later - *moduleHandle = pDynLib; -diff --git a/ipapython/ipap11helper/p11helper.c b/ipapython/ipap11helper/p11helper.c -index 038c26c4520cc8f71edbee15b0ccd9bf292d7588..558185e8236b79d6c5ee0ca46afb257f5fec94ab 100644 ---- a/ipapython/ipap11helper/p11helper.c -+++ b/ipapython/ipap11helper/p11helper.c -@@ -66,6 +66,7 @@ PyObject_HEAD - CK_SLOT_ID slot; - CK_FUNCTION_LIST_PTR p11; - CK_SESSION_HANDLE session; -+void *module_handle; - } P11_Helper; - - typedef enum { -@@ -478,6 +479,7 @@ P11_Helper_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - self->slot = 0; - self->session = 0; - self->p11 = NULL; -+ self->module_handle = NULL; - } - - return (PyObject *) self; -@@ -496,12 +498,12 @@ static int P11_Helper_init(P11_Helper *self, PyObject *args, PyObject *kwds) { - CK_C_GetFunctionList pGetFunctionList = loadLibrary(library_path, - &module_handle); - if (!pGetFunctionList) { -- if (module_handle != NULL) -- unloadLibrary(module_handle); - PyErr_SetString(ipap11helperError, "Could not load the library."); - return -1; - } - -+ self->module_handle = module_handle; -+ - /* - * Load the function list - */ -@@ -567,9 +569,12 @@ P11_Helper_finalize(P11_Helper* self) { - */ - self->p11->C_Finalize(NULL); - -+ unloadLibrary(self->module_handle); -+ - self->p11 = NULL; - self->session = 0; - self->slot = 0; -+ self->module_handle = NULL; - - return Py_None; - } --- -2.1.0 - diff --git a/SOURCES/0055-adjust-search-so-that-it-works-for-non-admin-users.patch b/SOURCES/0055-adjust-search-so-that-it-works-for-non-admin-users.patch new file mode 100644 index 0000000..26d1181 --- /dev/null +++ b/SOURCES/0055-adjust-search-so-that-it-works-for-non-admin-users.patch @@ -0,0 +1,95 @@ +From 6c1ae29831a5fdea5a81412042ea73cc5df9f397 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Wed, 12 Aug 2015 10:35:38 +0200 +Subject: [PATCH] adjust search so that it works for non-admin users + +Non-admin user can now search for: +- hosts +- hostgroups +- netgroups +- servers +- services + +(Fixes ACI issue where search returns nothing when user does't have +read rights for an attribute in search_attributes. + +https://fedorahosted.org/freeipa/ticket/5167 + +Reviewed-By: Tomas Babej +--- + ipalib/plugins/host.py | 2 +- + ipalib/plugins/hostgroup.py | 1 + + ipalib/plugins/netgroup.py | 4 ++++ + ipalib/plugins/server.py | 1 + + ipalib/plugins/service.py | 3 +-- + 5 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py +index 410b4bd120743a6ad5787fbd2a55534b4f108601..3e882aefd210df73b7ffd15b5a4c1d2fc4173536 100644 +--- a/ipalib/plugins/host.py ++++ b/ipalib/plugins/host.py +@@ -292,7 +292,7 @@ class host(LDAPObject): + # object_class_config = 'ipahostobjectclasses' + search_attributes = [ + 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', +- 'nshardwareplatform', 'nsosversion', 'managedby', 'ipaallowedtoperform' ++ 'nshardwareplatform', 'nsosversion', 'managedby', + ] + default_attributes = [ + 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', +diff --git a/ipalib/plugins/hostgroup.py b/ipalib/plugins/hostgroup.py +index fafe40ad9a8d1693505b7d90e5d8fd12202a894b..30d474d80905f02c4f88742a2677220c150b3c7f 100644 +--- a/ipalib/plugins/hostgroup.py ++++ b/ipalib/plugins/hostgroup.py +@@ -78,6 +78,7 @@ class hostgroup(LDAPObject): + object_name_plural = _('host groups') + object_class = ['ipaobject', 'ipahostgroup'] + permission_filter_objectclasses = ['ipahostgroup'] ++ search_attributes = ['cn', 'description', 'member', 'memberof'] + default_attributes = ['cn', 'description', 'member', 'memberof', + 'memberindirect', 'memberofindirect', + ] +diff --git a/ipalib/plugins/netgroup.py b/ipalib/plugins/netgroup.py +index d535b383e048fd12d08bde9247f158d183a5bcad..e69aaf94a035d0c4af28585f84b4b1f8105b3fc3 100644 +--- a/ipalib/plugins/netgroup.py ++++ b/ipalib/plugins/netgroup.py +@@ -86,6 +86,10 @@ class netgroup(LDAPObject): + object_name_plural = _('netgroups') + object_class = ['ipaobject', 'ipaassociation', 'ipanisnetgroup'] + permission_filter_objectclasses = ['ipanisnetgroup'] ++ search_attributes = [ ++ 'cn', 'description', 'memberof', 'externalhost', 'nisdomainname', ++ 'memberuser', 'memberhost', 'member', 'usercategory', 'hostcategory', ++ ] + default_attributes = [ + 'cn', 'description', 'memberof', 'externalhost', 'nisdomainname', + 'memberuser', 'memberhost', 'member', 'memberindirect', +diff --git a/ipalib/plugins/server.py b/ipalib/plugins/server.py +index 7fc44197343dbb651782fbf79993cbbe8818efed..5808c9c5ea78fce4a15cd2e49740fbe20bca8358 100644 +--- a/ipalib/plugins/server.py ++++ b/ipalib/plugins/server.py +@@ -38,6 +38,7 @@ class server(LDAPObject): + object_name = _('server') + object_name_plural = _('servers') + object_class = ['top'] ++ search_attributes = ['cn'] + default_attributes = [ + 'cn', 'iparepltopomanagedsuffix', 'ipamindomainlevel', + 'ipamaxdomainlevel' +diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py +index a5e10921beac8b232f6b74640ef17713f7297a3d..a21d004c8a70d50385c94b12447d5fd5bc0851b4 100644 +--- a/ipalib/plugins/service.py ++++ b/ipalib/plugins/service.py +@@ -391,8 +391,7 @@ class service(LDAPObject): + ] + possible_objectclasses = ['ipakrbprincipal', 'ipaallowedoperations'] + permission_filter_objectclasses = ['ipaservice'] +- search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata', +- 'ipaallowedtoperform'] ++ search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata'] + default_attributes = ['krbprincipalname', 'usercertificate', 'managedby', + 'ipakrbauthzdata', 'memberof', 'ipaallowedtoperform'] + uuid_attribute = 'ipauniqueid' +-- +2.4.3 + diff --git a/SOURCES/0056-Fix-Kerberos-error-handling-in-ipa-sam.patch b/SOURCES/0056-Fix-Kerberos-error-handling-in-ipa-sam.patch deleted file mode 100644 index 7e6107e..0000000 --- a/SOURCES/0056-Fix-Kerberos-error-handling-in-ipa-sam.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5d835f8ace9ec1b89c67585b22cd230c497cf833 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 17:40:35 +0000 -Subject: [PATCH] Fix Kerberos error handling in ipa-sam - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-sam/ipa_sam.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c -index 3b69f9e8255490aac17d08033e2a3584c6bf9e24..e71129901b5ac1816c300b707e40c2e43d711338 100644 ---- a/daemons/ipa-sam/ipa_sam.c -+++ b/daemons/ipa-sam/ipa_sam.c -@@ -4233,7 +4233,7 @@ static int bind_callback(LDAP *ldap_struct, struct smbldap_state *ldap_state, vo - krb5_free_principal(data.context, in_creds.server); - krb5_free_principal(data.context, in_creds.client); - -- if (rc) { -+ if (rc != 0 && rc != KRB5KRB_AP_ERR_TKT_NYV && rc != KRB5KRB_AP_ERR_TKT_EXPIRED) { - rc = bind_callback_obtain_creds(&data); - if (rc) { - bind_callback_cleanup(&data, rc); --- -2.1.0 - diff --git a/SOURCES/0056-validate-mutually-exclusive-options-in-vault-add.patch b/SOURCES/0056-validate-mutually-exclusive-options-in-vault-add.patch new file mode 100644 index 0000000..11907c5 --- /dev/null +++ b/SOURCES/0056-validate-mutually-exclusive-options-in-vault-add.patch @@ -0,0 +1,38 @@ +From 97f52ad53a6284b20e275e8ae28c599d96fc0b30 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Wed, 12 Aug 2015 11:07:22 +0200 +Subject: [PATCH] validate mutually exclusive options in vault-add + +https://fedorahosted.org/freeipa/ticket/5195 + +Reviewed-By: Tomas Babej +--- + ipalib/plugins/vault.py | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index fe4eec325dde4a9ecd8a7ce5af1a124fc5c6a9ae..055e8d00f1616c15b217e7570eeedd46efba7c81 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -597,6 +597,18 @@ class vault_add(PKQuery, Local): + if 'public_key_file' in options: + del options['public_key_file'] + ++ if vault_type != u'symmetric' and (password or password_file): ++ raise errors.MutuallyExclusiveError( ++ reason=_('Password can be specified only for ' ++ 'symmetric vault') ++ ) ++ ++ if vault_type != u'asymmetric' and (public_key or public_key_file): ++ raise errors.MutuallyExclusiveError( ++ reason=_('Public key can be specified only for ' ++ 'asymmetric vault') ++ ) ++ + if self.api.env.in_server: + backend = self.api.Backend.ldap2 + else: +-- +2.4.3 + diff --git a/SOURCES/0057-Fix-unchecked-return-value-in-ipa-kdb.patch b/SOURCES/0057-Fix-unchecked-return-value-in-ipa-kdb.patch deleted file mode 100644 index 7cff879..0000000 --- a/SOURCES/0057-Fix-unchecked-return-value-in-ipa-kdb.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 253b6378741d4de5ca68fb60351ae22156a96359 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 18:10:27 +0000 -Subject: [PATCH] Fix unchecked return value in ipa-kdb - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index c8f6c76fb5b3bc7d47ec8a1551579d53d226027e..a4500070760e83994c8155a12ee6414b5ebee9e0 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -2070,7 +2070,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - krb5_princ_component(context, ks_client_princ, 1)->length, - ipactx->kdc_hostname, strlen(ipactx->kdc_hostname), - NULL, NULL, &result) == 0) { -- kerr = ipadb_reinit_mspac(ipactx, true); -+ (void)ipadb_reinit_mspac(ipactx, true); - } - } - --- -2.1.0 - diff --git a/SOURCES/0057-idranges-raise-an-error-when-local-IPA-ID-range-is-b.patch b/SOURCES/0057-idranges-raise-an-error-when-local-IPA-ID-range-is-b.patch new file mode 100644 index 0000000..1387dc3 --- /dev/null +++ b/SOURCES/0057-idranges-raise-an-error-when-local-IPA-ID-range-is-b.patch @@ -0,0 +1,110 @@ +From 887bd5f84d862dfb923c72a60b4491374be34d5f Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 7 Aug 2015 15:44:57 +0200 +Subject: [PATCH] idranges: raise an error when local IPA ID range is being + modified + +also show the message about the way UID/GID ranges are managed in FreeIPA in +the idrange-mod's help message + +https://fedorahosted.org/freeipa/ticket/4826 + +Reviewed-By: Tomas Babej +--- + ipalib/plugins/idrange.py | 52 ++++++++++++++++++++++++++--------------------- + 1 file changed, 29 insertions(+), 23 deletions(-) + +diff --git a/ipalib/plugins/idrange.py b/ipalib/plugins/idrange.py +index fb198d79d4c14ffd5f7dc633c9f01a1465ff01d7..2cec05bd8f837fb27803b869bf33fe389126506c 100644 +--- a/ipalib/plugins/idrange.py ++++ b/ipalib/plugins/idrange.py +@@ -31,6 +31,20 @@ if api.env.in_server and api.env.context in ['lite', 'server']: + except ImportError: + _dcerpc_bindings_installed = False + ++ID_RANGE_VS_DNA_WARNING = """======= ++WARNING: ++ ++DNA plugin in 389-ds will allocate IDs based on the ranges configured for the ++local domain. Currently the DNA plugin *cannot* be reconfigured itself based ++on the local ranges set via this family of commands. ++ ++Manual configuration change has to be done in the DNA plugin configuration for ++the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix ++IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be ++modified to match the new range. ++======= ++""" ++ + __doc__ = _(""" + ID ranges + +@@ -139,17 +153,8 @@ this domain has the SID S-1-5-21-123-456-789-1010 then 1010 id the RID of the + user. RIDs are unique in a domain, 32bit values and are used for users and + groups. + +-WARNING: +- +-DNA plugin in 389-ds will allocate IDs based on the ranges configured for the +-local domain. Currently the DNA plugin *cannot* be reconfigured itself based +-on the local ranges set via this family of commands. +- +-Manual configuration change has to be done in the DNA plugin configuration for +-the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix +-IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be +-modified to match the new range. +-""") ++{0} ++""".format(ID_RANGE_VS_DNA_WARNING)) + + register = Registry() + +@@ -386,17 +391,8 @@ class idrange_add(LDAPCreate): + + must be given to add a new range for a trusted AD domain. + +- WARNING: +- +- DNA plugin in 389-ds will allocate IDs based on the ranges configured for the +- local domain. Currently the DNA plugin *cannot* be reconfigured itself based +- on the local ranges set via this family of commands. +- +- Manual configuration change has to be done in the DNA plugin configuration for +- the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix +- IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be +- modified to match the new range. +- """) ++{0} ++""".format(ID_RANGE_VS_DNA_WARNING)) + + msg_summary = _('Added ID range "%(value)s"') + +@@ -670,7 +666,10 @@ class idrange_show(LDAPRetrieve): + + @register() + class idrange_mod(LDAPUpdate): +- __doc__ = _('Modify ID range.') ++ __doc__ = _("""Modify ID range. ++ ++{0} ++""".format(ID_RANGE_VS_DNA_WARNING)) + + msg_summary = _('Modified ID range "%(value)s"') + +@@ -688,6 +687,13 @@ class idrange_mod(LDAPUpdate): + except errors.NotFound: + self.obj.handle_not_found(*keys) + ++ if old_attrs['iparangetype'][0] == 'ipa-local': ++ raise errors.ExecutionError( ++ message=_('This command can not be used to change ID ' ++ 'allocation for local IPA domain. Run ' ++ '`ipa help idrange` for more information') ++ ) ++ + is_set = lambda x: (x in entry_attrs) and (entry_attrs[x] is not None) + in_updated_attrs = lambda x:\ + (x in entry_attrs and entry_attrs[x] is not None) or\ +-- +2.4.3 + diff --git a/SOURCES/0058-Fix-unchecked-return-values-in-ipa-winsync.patch b/SOURCES/0058-Fix-unchecked-return-values-in-ipa-winsync.patch deleted file mode 100644 index f333fd8..0000000 --- a/SOURCES/0058-Fix-unchecked-return-values-in-ipa-winsync.patch +++ /dev/null @@ -1,108 +0,0 @@ -From c7b939714ed7b39056c776e5b4a721dd192178bd Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 18:10:59 +0000 -Subject: [PATCH] Fix unchecked return values in ipa-winsync - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - .../ipa-winsync/ipa-winsync-config.c | 40 +++++++++++----------- - 1 file changed, 20 insertions(+), 20 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c b/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c -index 65ceaea685a276db91aab356dab617e260095873..8b62aed41bfe4704d542e37e70e9d128fa33507e 100644 ---- a/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c -+++ b/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c -@@ -905,9 +905,9 @@ ipa_winsync_config_refresh_domain( - - if (!iwdc->realm_name) { - /* error - could not find the IPA config entry with the realm name */ -- LOG_FATAL("Error: could not find the entry containing the realm name for " -- "ds subtree [%s] filter [%s] attr [%s]\n", -- slapi_sdn_get_dn(ds_subtree), realm_filter, realm_attr); -+ LOG_FATAL("Error: could not find the entry containing the realm name " -+ "[%d] ds subtree [%s] filter [%s] attr [%s]\n", -+ ret, slapi_sdn_get_dn(ds_subtree), realm_filter, realm_attr); - goto out; - } - -@@ -918,9 +918,9 @@ ipa_winsync_config_refresh_domain( - &new_user_objclasses, NULL); - if (!new_user_objclasses) { - /* error - could not find the entry containing list of objectclasses */ -- LOG_FATAL("Error: could not find the entry containing the new user objectclass list for " -- "ds subtree [%s] filter [%s] attr [%s]\n", -- slapi_sdn_get_dn(ds_subtree), new_entry_filter, new_user_oc_attr); -+ LOG_FATAL("Error: could not find the entry containing the new user objectclass list " -+ "[%d] ds subtree [%s] filter [%s] attr [%s]\n", -+ ret, slapi_sdn_get_dn(ds_subtree), new_entry_filter, new_user_oc_attr); - goto out; - } - -@@ -933,9 +933,9 @@ ipa_winsync_config_refresh_domain( - NULL, &iwdc->homedir_prefix); - if (!iwdc->homedir_prefix) { - /* error - could not find the home dir prefix */ -- LOG_FATAL("Error: could not find the entry containing the home directory prefix for " -- "ds subtree [%s] filter [%s] attr [%s]\n", -- slapi_sdn_get_dn(ds_subtree), new_entry_filter, homedir_prefix_attr); -+ LOG_FATAL("Error: could not find the entry containing the home directory prefix " -+ "[%d] ds subtree [%s] filter [%s] attr [%s]\n", -+ ret, slapi_sdn_get_dn(ds_subtree), new_entry_filter, homedir_prefix_attr); - goto out; - } - -@@ -950,8 +950,8 @@ ipa_winsync_config_refresh_domain( - NULL, &iwdc->login_shell); - if (!iwdc->login_shell) { - LOG("Warning: could not find the entry containing the login shell " -- "attribute for ds subtree [%s] filter [%s] attr [%s]\n", -- slapi_sdn_get_dn(ds_subtree), new_entry_filter, -+ "attribute [%d] ds subtree [%s] filter [%s] attr [%s]\n", -+ ret, slapi_sdn_get_dn(ds_subtree), new_entry_filter, - login_shell_attr); - } - } -@@ -969,9 +969,9 @@ ipa_winsync_config_refresh_domain( - NULL, &default_group_name); - if (!default_group_name) { - /* error - could not find the default group name */ -- LOG_FATAL("Error: could not find the entry containing the default group name for " -- "ds subtree [%s] filter [%s] attr [%s]\n", -- slapi_sdn_get_dn(ds_subtree), new_entry_filter, default_group_attr); -+ LOG_FATAL("Error: could not find the entry containing the default group name " -+ "[%d] ds subtree [%s] filter [%s] attr [%s]\n", -+ ret, slapi_sdn_get_dn(ds_subtree), new_entry_filter, default_group_attr); - goto out; - } - -@@ -1014,9 +1014,9 @@ ipa_winsync_config_refresh_domain( - NULL, &inactivated_group_dn); - if (!inactivated_group_dn) { - /* error - could not find the inactivated group dn */ -- LOG("Could not find the DN of the inactivated users group ds " -- "subtree [%s] filter [%s]. Ignoring\n", -- slapi_sdn_get_dn(ds_subtree), inactivated_filter); -+ LOG("Could not find the DN of the inactivated users group " -+ "[%d] ds subtree [%s] filter [%s]. Ignoring\n", -+ ret, slapi_sdn_get_dn(ds_subtree), inactivated_filter); - goto out; - } - } -@@ -1026,9 +1026,9 @@ ipa_winsync_config_refresh_domain( - NULL, &activated_group_dn); - if (!activated_group_dn) { - /* error - could not find the activated group dn */ -- LOG("Could not find the DN of the activated users group ds " -- "subtree [%s] filter [%s]. Ignoring\n", -- slapi_sdn_get_dn(ds_subtree), activated_filter); -+ LOG("Could not find the DN of the activated users group " -+ "[%d] ds subtree [%s] filter [%s]. Ignoring\n", -+ ret, slapi_sdn_get_dn(ds_subtree), activated_filter); - goto out; - } - } --- -2.1.0 - diff --git a/SOURCES/0058-install-Fix-server-and-replica-install-options.patch b/SOURCES/0058-install-Fix-server-and-replica-install-options.patch new file mode 100644 index 0000000..8c915c0 --- /dev/null +++ b/SOURCES/0058-install-Fix-server-and-replica-install-options.patch @@ -0,0 +1,211 @@ +From 8fd313b624e3da699280f81da1f88ef7149e6123 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 12 Aug 2015 07:49:53 +0200 +Subject: [PATCH] install: Fix server and replica install options + +https://fedorahosted.org/freeipa/ticket/5184 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/install.py | 55 ++++++------------------------ + ipaserver/install/server/replicainstall.py | 36 ++++--------------- + 2 files changed, 17 insertions(+), 74 deletions(-) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index b9bf3f34bdb7c32115e5c6a7038f11f901ab06b8..ff517513473a458a84f63c5c1308a8cc0b8699f8 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -1137,18 +1137,6 @@ def uninstall(installer): + class ServerCA(common.Installable, core.Group, core.Composite): + description = "certificate system" + +- setup_ca = Knob( +- bool, False, +- initializable=False, +- description="configure a dogtag CA", +- ) +- +- setup_kra = Knob( +- bool, False, +- initializable=False, +- description="configure a dogtag KRA", +- ) +- + external_ca = Knob( + bool, False, + description=("Generate a CSR for the IPA CA certificate to be signed " +@@ -1163,7 +1151,7 @@ class ServerCA(common.Installable, core.Group, core.Composite): + external_cert_files = Knob( + (list, str), None, + description=("File containing the IPA CA certificate and the external " +- "CA certificate chain (can be specified multiple times)"), ++ "CA certificate chain"), + cli_name='external-cert-file', + cli_aliases=['external_cert_file', 'external_ca_file'], + cli_metavar='FILE', +@@ -1308,6 +1296,7 @@ class ServerDNS(common.Installable, core.Group, core.Composite): + description=("The reverse DNS zone to use. This option can be used " + "multiple times"), + cli_name='reverse-zone', ++ cli_metavar='REVERSE_ZONE', + ) + + no_reverse = Knob( +@@ -1320,31 +1309,6 @@ class ServerDNS(common.Installable, core.Group, core.Composite): + description="Disable DNSSEC validation", + ) + +- dnssec_master = Knob( +- bool, False, +- initializable=False, +- description="Setup server to be DNSSEC key master", +- ) +- +- disable_dnssec_master = Knob( +- bool, False, +- initializable=False, +- description="Disable the DNSSEC master on this server", +- ) +- +- kasp_db_file = Knob( +- str, None, +- initializable=False, +- description="Copy OpenDNSSEC metadata from the specified file (will " +- "not create a new kasp.db file)", +- ) +- +- force = Knob( +- bool, False, +- initializable=False, +- description="Force install", +- ) +- + zonemgr = Knob( + str, None, + description=("DNS zone manager e-mail address. Defaults to " +@@ -1416,7 +1380,6 @@ class Server(common.Installable, common.Interactive, core.Composite): + master_password = Knob( + str, None, + sensitive=True, +- deprecated=True, + description="kerberos master password (normally autogenerated)", + cli_short_name='P', + ) +@@ -1466,11 +1429,13 @@ class Server(common.Installable, common.Interactive, core.Composite): + description=("Master Server IP Address. This option can be used " + "multiple times"), + cli_name='ip-address', ++ cli_metavar='IP_ADDRESS', + ) + + no_ntp = Knob( + bool, False, + description="do not configure ntp", ++ cli_short_name='N', + ) + + idstart = Knob( +@@ -1615,8 +1580,8 @@ class Server(common.Installable, common.Interactive, core.Composite): + # Automatically disable pkinit w/ dogtag until that is supported + self.ca.no_pkinit = True + +- self.setup_ca = self.ca.setup_ca +- self.setup_kra = self.ca.setup_kra ++ self.setup_ca = False ++ self.setup_kra = False + self.external_ca = self.ca.external_ca + self.external_ca_type = self.ca.external_ca_type + self.external_cert_files = self.ca.external_cert_files +@@ -1639,10 +1604,10 @@ class Server(common.Installable, common.Interactive, core.Composite): + self.reverse_zones = self.dns.reverse_zones + self.no_reverse = self.dns.no_reverse + self.no_dnssec_validation = self.dns.no_dnssec_validation +- self.dnssec_master = self.dns.dnssec_master +- self.disable_dnssec_master = self.dns.disable_dnssec_master +- self.kasp_db_file = self.dns.kasp_db_file +- self.force = self.dns.force ++ self.dnssec_master = False ++ self.disable_dnssec_master = False ++ self.kasp_db_file = None ++ self.force = False + self.zonemgr = self.dns.zonemgr + self.no_host_dns = self.dns.no_host_dns + self.no_dns_sshfp = self.dns.no_dns_sshfp +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 1ad291a1eada080361031a5723a0ea61679fc72e..dd8bc0d4bb7d8d9835a3e3e4dc24d1f67199d28f 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -679,6 +679,7 @@ class ReplicaDNS(common.Installable, core.Group, core.Composite): + description=("The reverse DNS zone to use. This option can be used " + "multiple times"), + cli_name='reverse-zone', ++ cli_metavar='REVERSE_ZONE', + ) + + no_reverse = Knob( +@@ -691,31 +692,6 @@ class ReplicaDNS(common.Installable, core.Group, core.Composite): + description="Disable DNSSEC validation", + ) + +- dnssec_master = Knob( +- bool, False, +- initializable=False, +- description="Setup server to be DNSSEC key master", +- ) +- +- disable_dnssec_master = Knob( +- bool, False, +- initializable=False, +- description="Disable the DNSSEC master on this server", +- ) +- +- force = Knob( +- bool, False, +- initializable=False, +- description="Force install", +- ) +- +- kasp_db_file = Knob( +- str, None, +- initializable=False, +- description="Copy OpenDNSSEC metadata from the specified file (will " +- "not create a new kasp.db file)", +- ) +- + no_host_dns = Knob( + bool, False, + description="Do not use DNS for hostname lookup during installation", +@@ -750,6 +726,7 @@ class Replica(common.Installable, common.Interactive, core.Composite): + description=("Replica server IP Address. This option can be used " + "multiple times"), + cli_name='ip-address', ++ cli_metavar='IP_ADDRESS', + ) + + password = Knob( +@@ -774,6 +751,7 @@ class Replica(common.Installable, common.Interactive, core.Composite): + no_ntp = Knob( + bool, False, + description="do not configure ntp", ++ cli_short_name='N', + ) + + no_ui_redirect = Knob( +@@ -864,10 +842,10 @@ class Replica(common.Installable, common.Interactive, core.Composite): + self.reverse_zones = self.dns.reverse_zones + self.no_reverse = self.dns.no_reverse + self.no_dnssec_validation = self.dns.no_dnssec_validation +- self.dnssec_master = self.dns.dnssec_master +- self.disable_dnssec_master = self.dns.disable_dnssec_master +- self.kasp_db_file = self.dns.kasp_db_file +- self.force = self.dns.force ++ self.dnssec_master = False ++ self.disable_dnssec_master = False ++ self.kasp_db_file = None ++ self.force = False + self.zonemgr = None + self.no_host_dns = self.dns.no_host_dns + self.no_dns_sshfp = self.dns.no_dns_sshfp +-- +2.4.3 + diff --git a/SOURCES/0059-Fix-unchecked-return-value-in-ipa-join.patch b/SOURCES/0059-Fix-unchecked-return-value-in-ipa-join.patch deleted file mode 100644 index f78a191..0000000 --- a/SOURCES/0059-Fix-unchecked-return-value-in-ipa-join.patch +++ /dev/null @@ -1,32 +0,0 @@ -From e6f71d031a114cd8fbd752e1ce8e2a02007a009b Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 18:12:02 +0000 -Subject: [PATCH] Fix unchecked return value in ipa-join - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - ipa-client/ipa-join.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ipa-client/ipa-join.c b/ipa-client/ipa-join.c -index 46f64572dcaeb3be61dadf87a07520ad21fb4f47..ac8251fef3b0a03de0920e8732b44bac208f55a6 100644 ---- a/ipa-client/ipa-join.c -+++ b/ipa-client/ipa-join.c -@@ -208,8 +208,11 @@ connect_ldap(const char *hostname, const char *binddn, const char *bindpw) { - struct berval bindpw_bv; - - if (debug) { -- ldapdebug=2; -+ ldapdebug = 2; - ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &ldapdebug); -+ if (ret != LDAP_OPT_SUCCESS) { -+ goto fail; -+ } - } - - if (ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, CAFILE) != LDAP_OPT_SUCCESS) --- -2.1.0 - diff --git a/SOURCES/0059-certprofile-add-profile-format-explanation.patch b/SOURCES/0059-certprofile-add-profile-format-explanation.patch new file mode 100644 index 0000000..fac47d7 --- /dev/null +++ b/SOURCES/0059-certprofile-add-profile-format-explanation.patch @@ -0,0 +1,49 @@ +From 056d185b4b2bfd7de423da7ff7a80f764c043810 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 23 Jul 2015 23:07:10 -0400 +Subject: [PATCH] certprofile: add profile format explanation + +Part of: https://fedorahosted.org/freeipa/ticket/5089 + +Reviewed-By: Tomas Babej +--- + ipalib/plugins/certprofile.py | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index 658fbca3b4eb851eb5a22190c443044f6ceb8491..1dd4f403ee4461b83c053eb36019a8896506bb81 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -47,9 +47,29 @@ EXAMPLES: + Show information about a profile: + ipa certprofile-show ShortLivedUserCert + ++ Save profile configuration to a file: ++ ipa certprofile-show caIPAserviceCert --out caIPAserviceCert.cfg ++ + Search for profiles that do not store certificates: + ipa certprofile-find --store=false + ++PROFILE CONFIGURATION FORMAT: ++ ++The profile configuration format is the raw property-list format ++used by Dogtag Certificate System. The XML format is not supported. ++ ++The following restrictions apply to profiles managed by FreeIPA: ++ ++- When importing a profile the "profileId" field, if present, must ++ match the ID given on the command line. ++ ++- The "classId" field must be set to "caEnrollImpl" ++ ++- The "auth.instance_id" field must be set to "raCertAuth" ++ ++- The "certReqInputImpl" input class and "certOutputImpl" output ++ class must be used. ++ + """) + + +-- +2.4.3 + diff --git a/SOURCES/0060-Fix-unchecked-return-value-in-krb5-common-utils.patch b/SOURCES/0060-Fix-unchecked-return-value-in-krb5-common-utils.patch deleted file mode 100644 index 2a04221..0000000 --- a/SOURCES/0060-Fix-unchecked-return-value-in-krb5-common-utils.patch +++ /dev/null @@ -1,30 +0,0 @@ -From d0f047e12c2c84ac9b5d98834bfa83c69987d681 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 10 Nov 2014 18:12:52 +0000 -Subject: [PATCH] Fix unchecked return value in krb5 common utils - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - util/ipa_krb5.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c -index 6334ed3b09b91a79648a16c0fd60dd6ff00d2fa2..feb23eae9099b83b96a26cf36b7cbc31b478c4f6 100644 ---- a/util/ipa_krb5.c -+++ b/util/ipa_krb5.c -@@ -730,6 +730,10 @@ struct berval *create_key_control(struct keys_container *keys, - - if (ksdata[i].salttype == NO_SALT) { - ret = ber_printf(be, "}"); -+ if (ret == -1) { -+ ber_free(be, 1); -+ return NULL; -+ } - continue; - } - --- -2.1.0 - diff --git a/SOURCES/0060-ULC-Prevent-preserved-users-from-being-assigned-memb.patch b/SOURCES/0060-ULC-Prevent-preserved-users-from-being-assigned-memb.patch new file mode 100644 index 0000000..d8dbffa --- /dev/null +++ b/SOURCES/0060-ULC-Prevent-preserved-users-from-being-assigned-memb.patch @@ -0,0 +1,155 @@ +From 6087dd789833738e99040d031473c76ed9d8723c Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 12 Aug 2015 11:03:40 +0200 +Subject: [PATCH] ULC: Prevent preserved users from being assigned membership + +https://fedorahosted.org/freeipa/ticket/5170 + +Reviewed-By: David Kupka +--- + ipalib/plugins/user.py | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 859939205f903fa4832524c8d2601141f3674bb5..4ea770ede7525149780f1486b5e4eb44699c8533 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -342,7 +342,7 @@ class user(baseuser): + ), + ) + +- def get_dn(self, *keys, **options): ++ def get_either_dn(self, *keys, **options): + ''' + Returns the DN of a user + The user can be active (active container) or delete (delete container) +@@ -351,7 +351,7 @@ class user(baseuser): + ldap = self.backend + # Check that this value is a Active user + try: +- active_dn = super(user, self).get_dn(*keys, **options) ++ active_dn = self.get_dn(*keys, **options) + ldap.get_entry(active_dn, ['dn']) + + # The Active user exists +@@ -402,7 +402,7 @@ class user_add(baseuser_add): + ) + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): +- assert isinstance(dn, DN) ++ dn = self.obj.get_either_dn(*keys, **options) + if not options.get('noprivate', False): + try: + # The Managed Entries plugin will allow a user to be created +@@ -599,7 +599,7 @@ class user_del(baseuser_del): + return super(user_del, self).forward(*keys, **options) + + def pre_callback(self, ldap, dn, *keys, **options): +- assert isinstance(dn, DN) ++ dn = self.obj.get_either_dn(*keys, **options) + + # For User life Cycle: user-del is a common plugin + # command to delete active user (active container) and +@@ -625,7 +625,7 @@ class user_del(baseuser_del): + + def execute(self, *keys, **options): + +- dn = self.obj.get_dn(*keys, **options) ++ dn = self.obj.get_either_dn(*keys, **options) + + # We are going to permanent delete or the user is already in the delete container. + delete_container = DN(self.obj.delete_container_dn, self.api.env.basedn) +@@ -644,7 +644,7 @@ class user_del(baseuser_del): + ldap = self.obj.backend + + # need to handle multiple keys (e.g. keys[-1]=(u'tb8', u'tb9').. +- active_dn = self.obj.get_dn(*keys, **options) ++ active_dn = self.obj.get_either_dn(*keys, **options) + superior_dn = DN(self.obj.delete_container_dn, api.env.basedn) + delete_dn = DN(active_dn[0], self.obj.delete_container_dn, api.env.basedn) + self.log.debug("preserve move %s -> %s" % (active_dn, delete_dn)) +@@ -701,6 +701,7 @@ class user_mod(baseuser_mod): + has_output_params = baseuser_mod.has_output_params + user_output_params + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): ++ dn = self.obj.get_either_dn(*keys, **options) + self.pre_common_callback(ldap, dn, entry_attrs, **options) + validate_nsaccountlock(entry_attrs) + return dn +@@ -777,6 +778,10 @@ class user_show(baseuser_show): + ), + ) + ++ def pre_callback(self, ldap, dn, attrs_list, *keys, **options): ++ dn = self.obj.get_either_dn(*keys, **options) ++ return dn ++ + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + convert_nsaccountlock(entry_attrs) + self.post_common_callback(ldap, dn, entry_attrs, **options) +@@ -813,7 +818,7 @@ class user_undel(LDAPQuery): + ldap = self.obj.backend + + # First check that the user exists and is a delete one +- delete_dn = self.obj.get_dn(*keys, **options) ++ delete_dn = self.obj.get_either_dn(*keys, **options) + if delete_dn.endswith(DN(self.obj.active_container_dn, api.env.basedn)): + raise errors.ValidationError( + name=self.obj.primary_key.cli_name, +@@ -860,7 +865,7 @@ class user_disable(LDAPQuery): + + check_protected_member(keys[-1]) + +- dn = self.obj.get_dn(*keys, **options) ++ dn = self.obj.get_either_dn(*keys, **options) + ldap.deactivate_entry(dn) + + return dict( +@@ -880,7 +885,7 @@ class user_enable(LDAPQuery): + def execute(self, *keys, **options): + ldap = self.obj.backend + +- dn = self.obj.get_dn(*keys, **options) ++ dn = self.obj.get_either_dn(*keys, **options) + + ldap.activate_entry(dn) + +@@ -904,7 +909,7 @@ class user_unlock(LDAPQuery): + msg_summary = _('Unlocked account "%(value)s"') + + def execute(self, *keys, **options): +- dn = self.obj.get_dn(*keys, **options) ++ dn = self.obj.get_either_dn(*keys, **options) + entry = self.obj.backend.get_entry( + dn, ['krbLastAdminUnlock', 'krbLoginFailedCount']) + +@@ -948,7 +953,7 @@ class user_status(LDAPQuery): + + def execute(self, *keys, **options): + ldap = self.obj.backend +- dn = self.obj.get_dn(*keys, **options) ++ dn = self.obj.get_either_dn(*keys, **options) + attr_list = ['krbloginfailedcount', 'krblastsuccessfulauth', 'krblastfailedauth', 'nsaccountlock'] + + disabled = False +@@ -1037,7 +1042,7 @@ class user_add_cert(LDAPAddAttribute): + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, + **options): +- assert isinstance(dn, DN) ++ dn = self.obj.get_either_dn(*keys, **options) + + self.obj.convert_usercertificate_pre(entry_attrs) + +@@ -1059,7 +1064,7 @@ class user_remove_cert(LDAPRemoveAttribute): + + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, + **options): +- assert isinstance(dn, DN) ++ dn = self.obj.get_either_dn(*keys, **options) + + self.obj.convert_usercertificate_pre(entry_attrs) + +-- +2.4.3 + diff --git a/SOURCES/0061-Asymmetric-vault-validate-public-key-in-client.patch b/SOURCES/0061-Asymmetric-vault-validate-public-key-in-client.patch new file mode 100644 index 0000000..8a5948a --- /dev/null +++ b/SOURCES/0061-Asymmetric-vault-validate-public-key-in-client.patch @@ -0,0 +1,45 @@ +From 9eae8d891a8b5d5320cb38b8e697681802cbf573 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 23 Jul 2015 20:30:21 +0200 +Subject: [PATCH] Asymmetric vault: validate public key in client + +The ipa vault commands now load and validate the public key for +asymmetric encryption, before sending it to the server. This prevents +invalid vaults and prohibits accidental exposure of private key +material. + +https://fedorahosted.org/freeipa/ticket/5142 +https://fedorahosted.org/freeipa/ticket/5143 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 055e8d00f1616c15b217e7570eeedd46efba7c81..ac608f5c7e2779da138c75a0f02bd5546f4aeffd 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -665,6 +665,19 @@ class vault_add(PKQuery, Local): + name='ipavaultpublickey', + error=_('Missing vault public key')) + ++ # validate public key and prevent users from accidentally ++ # sending a private key to the server. ++ try: ++ load_pem_public_key( ++ data=public_key, ++ backend=default_backend() ++ ) ++ except ValueError as e: ++ raise errors.ValidationError( ++ name='ipavaultpublickey', ++ error=_('Invalid or unsupported vault public key: %s') % e, ++ ) ++ + # create vault + response = self.api.Command.vault_add_internal(*args, **options) + +-- +2.4.3 + diff --git a/SOURCES/0061-Fix-memory-leak-in-GetKeytabControl-asn1-code.patch b/SOURCES/0061-Fix-memory-leak-in-GetKeytabControl-asn1-code.patch deleted file mode 100644 index 79d12ca..0000000 --- a/SOURCES/0061-Fix-memory-leak-in-GetKeytabControl-asn1-code.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 456593766c073ab9ea43052d7bb0fceffbff2221 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 24 Nov 2014 13:57:10 +0000 -Subject: [PATCH] Fix memory leak in GetKeytabControl asn1 code - -https://fedorahosted.org/freeipa/ticket/4713 - -Reviewed-By: Alexander Bokovoy ---- - asn1/ipa_asn1.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/asn1/ipa_asn1.c b/asn1/ipa_asn1.c -index 50851a804f59bdb3fcb9ba832b093860d914452d..9efca964ac340208f478483ecfbb70b32d72181c 100644 ---- a/asn1/ipa_asn1.c -+++ b/asn1/ipa_asn1.c -@@ -77,12 +77,12 @@ bool ipaasn1_enc_getktreply(int kvno, struct keys_container *keys, - { - GetKeytabControl_t gkctrl = { 0 }; - bool ret = false; -+ KrbKey_t *KK; - - gkctrl.present = GetKeytabControl_PR_reply; - gkctrl.choice.reply.newkvno = kvno; - - for (int i = 0; i < keys->nkeys; i++) { -- KrbKey_t *KK; - KK = calloc(1, sizeof(KrbKey_t)); - if (!KK) goto done; - KK->key.type = keys->ksdata[i].key.enctype; -@@ -109,9 +109,18 @@ bool ipaasn1_enc_getktreply(int kvno, struct keys_container *keys, - } - - ret = encode_GetKeytabControl(&gkctrl, buf, len); -+ KK = NULL; - - done: - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_GetKeytabControl, &gkctrl); -+ if (KK) { -+ free(KK->key.value.buf); -+ if (KK->salt) { -+ free(KK->salt->value.buf); -+ free(KK->salt); -+ } -+ free(KK); -+ } - return ret; - } - --- -2.1.0 - diff --git a/SOURCES/0062-AD-trust-improve-trust-validation.patch b/SOURCES/0062-AD-trust-improve-trust-validation.patch deleted file mode 100644 index 2bd259d..0000000 --- a/SOURCES/0062-AD-trust-improve-trust-validation.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 6d3e68480293b50cf3ac40ad09f3ab48de764089 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 24 Nov 2014 15:07:49 +0200 -Subject: [PATCH] AD trust: improve trust validation - -Trust validation requires AD DC to contact IPA server to verify that trust account -actually works. It can fail due to DNS or firewall issue or if AD DC was able to -resolve IPA master(s) via SRV records, it still may contact a replica that has -no trust data replicated yet. - -In case AD DC still returns 'access denied', wait 5 seconds and try validation again. -Repeat validation until we hit a limit of 10 attempts, at which point raise -exception telling what's happening. - -https://fedorahosted.org/freeipa/ticket/4764 - -Reviewed-By: Tomas Babej ---- - ipaserver/dcerpc.py | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index caeca3c4ab357193aef4d0e6a373240acfdf1993..e342c4973746a113c0ad4f15a1e6050583461ccf 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -58,6 +58,7 @@ import pysss - from ipaplatform.paths import paths - - from ldap.filter import escape_filter_chars -+from time import sleep - - __doc__ = _(""" - Classes to manage trust joins using DCE-RPC calls -@@ -93,6 +94,8 @@ dcerpc_error_codes = { - dcerpc_error_messages = { - "NT_STATUS_OBJECT_NAME_NOT_FOUND": - errors.NotFound(reason=_('Cannot find specified domain or server name')), -+ "WERR_NO_LOGON_SERVERS": -+ errors.RemoteRetrieveError(reason=_('AD DC was unable to reach any IPA domain controller. Most likely it is a DNS or firewall issue')), - "NT_STATUS_INVALID_PARAMETER_MIX": - errors.RequirementError(name=_('At least the domain or IP address should be specified')), - } -@@ -699,6 +702,7 @@ class TrustDomainInstance(object): - self._policy_handle = None - self.read_only = False - self.ftinfo_records = None -+ self.validation_attempts = 0 - - def __gen_lsa_connection(self, binding): - if self.creds is None: -@@ -1011,9 +1015,18 @@ class TrustDomainInstance(object): - netlogon.NETLOGON_CONTROL_TC_VERIFY, - another_domain.info['dns_domain']) - if (result and (result.flags and netlogon.NETLOGON_VERIFY_STATUS_RETURNED)): -- # netr_LogonControl2Ex() returns non-None result only if overall call -- # result was WERR_OK which means verification was correct. -- # We only check that it was indeed status for verification process -+ if (result.pdc_connection_status[0] != 0) and (result.tc_connection_status[0] != 0): -+ if result.pdc_connection_status[1] == "WERR_ACCESS_DENIED": -+ # Most likely AD DC hit another IPA replica which yet has no trust secret replicated -+ # Sleep and repeat again -+ self.validation_attempts += 1 -+ if self.validation_attempts < 10: -+ sleep(5) -+ return self.verify_trust(another_domain) -+ raise errors.ACIError(reason=_('IPA master denied trust validation requests from AD DC ' -+ '%(count)d times. Most likely AD DC contacted a replica ' -+ 'that has no trust information replicated yet.' % (self.validation_attempts))) -+ raise assess_dcerpc_exception(*result.pdc_connection_status) - return True - return False - --- -2.1.0 - diff --git a/SOURCES/0062-add-permission-System-Manage-User-Certificates.patch b/SOURCES/0062-add-permission-System-Manage-User-Certificates.patch new file mode 100644 index 0000000..8d0495e --- /dev/null +++ b/SOURCES/0062-add-permission-System-Manage-User-Certificates.patch @@ -0,0 +1,64 @@ +From 159fe81f0f45f83f90037ba3315a3558d0ab94cf Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Wed, 12 Aug 2015 14:48:09 +0200 +Subject: [PATCH] add permission: System: Manage User Certificates + +usercertificate attr was moved from "System Modify Users" to this +new permission. + +https://fedorahosted.org/freeipa/ticket/5177 + +Reviewed-By: Fraser Tweedale +--- + ACI.txt | 4 +++- + ipalib/plugins/user.py | 10 +++++++++- + 2 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/ACI.txt b/ACI.txt +index 60607b98deb74d0b7f45d24ee9359b0cf8162b0d..99099275e1383f16aca122e05e34b2330f4d06a3 100644 +--- a/ACI.txt ++++ b/ACI.txt +@@ -309,9 +309,11 @@ aci: (targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:S + dn: cn=users,cn=accounts,dc=ipa,dc=example + aci: (targetattr = "krbprincipalkey || passwordhistory || sambalmpassword || sambantpassword || userpassword")(targetfilter = "(&(!(memberOf=cn=admins,cn=groups,cn=accounts,dc=ipa,dc=example))(objectclass=posixaccount))")(version 3.0;acl "permission:System: Change User password";allow (write) groupdn = "ldap:///cn=System: Change User password,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=users,cn=accounts,dc=ipa,dc=example ++aci: (targetattr = "usercertificate")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User Certificates";allow (write) groupdn = "ldap:///cn=System: Manage User Certificates,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: cn=users,cn=accounts,dc=ipa,dc=example + aci: (targetattr = "ipasshpubkey")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Manage User SSH Public Keys";allow (write) groupdn = "ldap:///cn=System: Manage User SSH Public Keys,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=users,cn=accounts,dc=ipa,dc=example +-aci: (targetattr = "businesscategory || carlicense || cn || description || displayname || employeetype || facsimiletelephonenumber || gecos || givenname || homephone || inetuserhttpurl || initials || l || labeleduri || loginshell || manager || mepmanagedentry || mobile || objectclass || ou || pager || postalcode || preferredlanguage || roomnumber || secretary || seealso || sn || st || street || telephonenumber || title || usercertificate || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Modify Users";allow (write) groupdn = "ldap:///cn=System: Modify Users,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++aci: (targetattr = "businesscategory || carlicense || cn || description || displayname || employeetype || facsimiletelephonenumber || gecos || givenname || homephone || inetuserhttpurl || initials || l || labeleduri || loginshell || manager || mepmanagedentry || mobile || objectclass || ou || pager || postalcode || preferredlanguage || roomnumber || secretary || seealso || sn || st || street || telephonenumber || title || userclass")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Modify Users";allow (write) groupdn = "ldap:///cn=System: Modify Users,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,dc=ipa,dc=example + aci: (targetattr = "*")(target = "ldap:///cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read UPG Definition";allow (compare,read,search) groupdn = "ldap:///cn=System: Read UPG Definition,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=users,cn=accounts,dc=ipa,dc=example +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 4ea770ede7525149780f1486b5e4eb44699c8533..90ae7260abf935abf92b49da04c11bc76e836e49 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -259,6 +259,14 @@ class user(baseuser): + ], + 'default_privileges': {'User Administrators'}, + }, ++ 'System: Manage User Certificates': { ++ 'ipapermright': {'write'}, ++ 'ipapermdefaultattr': {'usercertificate'}, ++ 'default_privileges': { ++ 'User Administrators', ++ 'Modify Users and Reset passwords', ++ }, ++ }, + 'System: Modify Users': { + 'ipapermright': {'write'}, + 'ipapermdefaultattr': { +@@ -269,7 +277,7 @@ class user(baseuser): + 'mepmanagedentry', 'mobile', 'objectclass', 'ou', 'pager', + 'postalcode', 'roomnumber', 'secretary', 'seealso', 'sn', 'st', + 'street', 'telephonenumber', 'title', 'userclass', +- 'preferredlanguage', 'usercertificate', ++ 'preferredlanguage', + }, + 'replaces': [ + '(targetattr = "givenname || sn || cn || displayname || title || initials || loginshell || gecos || homephone || mobile || pager || facsimiletelephonenumber || telephonenumber || street || roomnumber || l || st || postalcode || manager || secretary || description || carlicense || labeleduri || inetuserhttpurl || seealso || employeetype || businesscategory || ou || mepmanagedentry || objectclass")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Users";allow (write) groupdn = "ldap:///cn=Modify Users,cn=permissions,cn=pbac,$SUFFIX";)', +-- +2.4.3 + diff --git a/SOURCES/0063-Add-TLS-1.2-to-the-protocol-list-in-mod_nss-config.patch b/SOURCES/0063-Add-TLS-1.2-to-the-protocol-list-in-mod_nss-config.patch deleted file mode 100644 index 647bde3..0000000 --- a/SOURCES/0063-Add-TLS-1.2-to-the-protocol-list-in-mod_nss-config.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 6b1fe8db7d5bb08899b3b1ed4a8a48e82d73f13e Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 25 Nov 2014 08:12:53 +0000 -Subject: [PATCH] Add TLS 1.2 to the protocol list in mod_nss config - -https://fedorahosted.org/freeipa/ticket/4653 - -Reviewed-By: Martin Kosek ---- - install/tools/ipa-upgradeconfig | 13 +++++++++++++ - ipaserver/install/httpinstance.py | 7 ++++--- - 2 files changed, 17 insertions(+), 3 deletions(-) - -diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig -index 3484f8e8768fe05dddb08e9a40e58d8ad9c2e1e7..6b687fbd73d01f6574cd8ea3193cedba4d5c0e67 100644 ---- a/install/tools/ipa-upgradeconfig -+++ b/install/tools/ipa-upgradeconfig -@@ -1274,6 +1274,18 @@ def fix_trust_flags(): - sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True) - - -+def update_mod_nss_protocol(http): -+ root_logger.info('[Updating mod_nss protocol versions]') -+ -+ if sysupgrade.get_upgrade_state('nss.conf', 'protocol_updated_tls12'): -+ root_logger.info("Protocol versions already updated") -+ return -+ -+ http.set_mod_nss_protocol() -+ -+ sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True) -+ -+ - def main(): - """ - Get some basics about the system. If getting those basics fail then -@@ -1375,6 +1387,7 @@ def main(): - http.change_mod_nss_port_from_http() - - http.stop() -+ update_mod_nss_protocol(http) - fix_trust_flags() - http.start() - -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 14efa5b937784054bd6aace9ba4cda8f0b46aeb6..f9e020039734c7ff61e06ead0e30fb28701d6fc8 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -115,7 +115,8 @@ class HTTPInstance(service.Service): - - - self.step("setting mod_nss port to 443", self.__set_mod_nss_port) -- self.step("setting mod_nss protocol list to TLSv1.0 and TLSv1.1", self.__set_mod_nss_protocol) -+ self.step("setting mod_nss protocol list to TLSv1.0 - TLSv1.2", -+ self.set_mod_nss_protocol) - self.step("setting mod_nss password file", self.__set_mod_nss_passwordfile) - self.step("enabling mod_nss renegotiate", self.enable_mod_nss_renegotiate) - self.step("adding URL rewriting rules", self.__add_include) -@@ -205,8 +206,8 @@ class HTTPInstance(service.Service): - def __set_mod_nss_nickname(self, nickname): - installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSNickname', nickname) - -- def __set_mod_nss_protocol(self): -- installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSProtocol', 'TLSv1.0,TLSv1.1', False) -+ def set_mod_nss_protocol(self): -+ installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSProtocol', 'TLSv1.0,TLSv1.1,TLSv1.2', False) - - def enable_mod_nss_renegotiate(self): - installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRenegotiation', 'on', False) --- -2.1.0 - diff --git a/SOURCES/0063-Add-permission-for-bypassing-CA-ACL-enforcement.patch b/SOURCES/0063-Add-permission-for-bypassing-CA-ACL-enforcement.patch new file mode 100644 index 0000000..480d85b --- /dev/null +++ b/SOURCES/0063-Add-permission-for-bypassing-CA-ACL-enforcement.patch @@ -0,0 +1,86 @@ +From 61487ce8cbcad43a711931e92c3c2ef9b160cc02 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Tue, 4 Aug 2015 01:13:09 -0400 +Subject: [PATCH] Add permission for bypassing CA ACL enforcement + +Add the "Request Certificate ignoring CA ACLs" permission and +associated ACI, initially assigned to "Certificate Administrators" +privilege. + +Update cert-request command to skip CA ACL enforcement when the bind +principal has this permission. + +Fixes: https://fedorahosted.org/freeipa/ticket/5099 +Reviewed-By: Martin Babinsky +--- + install/updates/40-delegation.update | 15 +++++++++++++++ + ipalib/plugins/cert.py | 13 ++++++++++--- + 2 files changed, 25 insertions(+), 3 deletions(-) + +diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update +index bc0736c5b6c07747586a56c2cbde9596c7522d1c..8d4f6296cbed7fcc968c2193022cb50b488c8561 100644 +--- a/install/updates/40-delegation.update ++++ b/install/updates/40-delegation.update +@@ -144,6 +144,21 @@ default:member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX + dn: $SUFFIX + add:aci:(targetattr = "objectclass")(target = "ldap:///cn=request certificate with subjectaltname,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0; acl "permission:Request Certificate with SubjectAltName"; allow (write) groupdn = "ldap:///cn=Request Certificate with SubjectAltName,cn=permissions,cn=pbac,$SUFFIX";) + ++dn: cn=request certificate ignore caacl,cn=virtual operations,cn=etc,$SUFFIX ++default:objectClass: top ++default:objectClass: nsContainer ++default:cn: request certificate ignore caacl ++ ++dn: cn=Request Certificate ignoring CA ACLs,cn=permissions,cn=pbac,$SUFFIX ++default:objectClass: top ++default:objectClass: groupofnames ++default:objectClass: ipapermission ++default:cn: Request Certificate ignoring CA ACLs ++default:member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX ++ ++dn: $SUFFIX ++add:aci:(targetattr = "objectclass")(target = "ldap:///cn=request certificate ignore caacl,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0; acl "permission:Request Certificate ignoring CA ACLs"; allow (write) groupdn = "ldap:///cn=Request Certificate ignoring CA ACLs,cn=permissions,cn=pbac,$SUFFIX";) ++ + + # Read privileges + dn: cn=RBAC Readers,cn=privileges,cn=pbac,$SUFFIX +diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py +index 610f2149363eaa74180e9de5c9ee1439446ef409..daa698b54f2cc1b645245d312fae0f0500239ea2 100644 +--- a/ipalib/plugins/cert.py ++++ b/ipalib/plugins/cert.py +@@ -345,8 +345,6 @@ class cert_request(VirtualCommand): + else: + principal_type = SERVICE + +- caacl_check(principal_type, principal_string, ca, profile_id) +- + bind_principal = split_any_principal(getattr(context, 'principal')) + bind_service, bind_name, bind_realm = bind_principal + +@@ -362,6 +360,15 @@ class cert_request(VirtualCommand): + self.check_access() + + try: ++ self.check_access("request certificate ignore caacl") ++ bypass_caacl = True ++ except errors.ACIError: ++ bypass_caacl = False ++ ++ if not bypass_caacl: ++ caacl_check(principal_type, principal_string, ca, profile_id) ++ ++ try: + subject = pkcs10.get_subject(csr) + extensions = pkcs10.get_extensions(csr) + subjectaltname = pkcs10.get_subjectaltname(csr) or () +@@ -469,7 +476,7 @@ class cert_request(VirtualCommand): + raise errors.ACIError(info=_( + "Insufficient privilege to create a certificate " + "with subject alt name '%s'.") % name) +- if alt_principal_string is not None: ++ if alt_principal_string is not None and not bypass_caacl: + caacl_check( + principal_type, alt_principal_string, ca, profile_id) + elif name_type in (pkcs10.SAN_OTHERNAME_KRB5PRINCIPALNAME, +-- +2.4.3 + diff --git a/SOURCES/0064-Added-CLI-param-and-ACL-for-vault-service-operations.patch b/SOURCES/0064-Added-CLI-param-and-ACL-for-vault-service-operations.patch new file mode 100644 index 0000000..278ea95 --- /dev/null +++ b/SOURCES/0064-Added-CLI-param-and-ACL-for-vault-service-operations.patch @@ -0,0 +1,383 @@ +From 366a208f9d7bbbf637d192d1dfcab4482f69c441 Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Tue, 11 Aug 2015 08:19:59 +0200 +Subject: [PATCH] Added CLI param and ACL for vault service operations. + +The CLIs to manage vault owners and members have been modified +to accept services with a new parameter. + +A new ACL has been added to allow a service to create its own +service container. + +https://fedorahosted.org/freeipa/ticket/5172 + +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Kosek +--- + API.txt | 12 ++- + VERSION | 4 +- + install/share/vault.update | 1 + + ipalib/plugins/vault.py | 177 +++++++++++++++++++++------------------------ + 4 files changed, 94 insertions(+), 100 deletions(-) + +diff --git a/API.txt b/API.txt +index 2e19d6b2f1e16cc1c89d71ed7d443145426a28e3..71df3a56595a012e6382414ad4453d30ede8155b 100644 +--- a/API.txt ++++ b/API.txt +@@ -5434,13 +5434,14 @@ output: Entry('result', , Gettext('A dictionary representing an LDA + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) + command: vault_add_member +-args: 1,9,3 ++args: 1,10,3 + arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('group*', alwaysask=True, cli_name='groups', csv=True) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') ++option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False) + option: Flag('shared?', autofill=True, default=False) + option: Str('user*', alwaysask=True, cli_name='users', csv=True) + option: Str('username?', cli_name='user') +@@ -5449,13 +5450,14 @@ output: Output('completed', , None) + output: Output('failed', , None) + output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) + command: vault_add_owner +-args: 1,9,3 ++args: 1,10,3 + arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('group*', alwaysask=True, cli_name='groups', csv=True) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') ++option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False) + option: Flag('shared?', autofill=True, default=False) + option: Str('user*', alwaysask=True, cli_name='users', csv=True) + option: Str('username?', cli_name='user') +@@ -5547,13 +5549,14 @@ output: Entry('result', , Gettext('A dictionary representing an LDA + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) + command: vault_remove_member +-args: 1,9,3 ++args: 1,10,3 + arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('group*', alwaysask=True, cli_name='groups', csv=True) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') ++option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False) + option: Flag('shared?', autofill=True, default=False) + option: Str('user*', alwaysask=True, cli_name='users', csv=True) + option: Str('username?', cli_name='user') +@@ -5562,13 +5565,14 @@ output: Output('completed', , None) + output: Output('failed', , None) + output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) + command: vault_remove_owner +-args: 1,9,3 ++args: 1,10,3 + arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('group*', alwaysask=True, cli_name='groups', csv=True) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') ++option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False) + option: Flag('shared?', autofill=True, default=False) + option: Str('user*', alwaysask=True, cli_name='users', csv=True) + option: Str('username?', cli_name='user') +diff --git a/VERSION b/VERSION +index ca43f3e0c06880d355c068514134187c5edda175..69351a8fa8e27c884c130ab49d3fab541cd09ff9 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=148 +-# Last change: ftweedal - add --out option to user-show ++IPA_API_VERSION_MINOR=149 ++# Last change: edewata - Added CLI param and ACL for vault service operations +diff --git a/install/share/vault.update b/install/share/vault.update +index 61a8940b544fbc839b931f337389ac35dc2d1ffa..14421b5189efe9b3d9491e845e74debca6e18941 100644 +--- a/install/share/vault.update ++++ b/install/share/vault.update +@@ -8,6 +8,7 @@ default: objectClass: top + default: objectClass: ipaVaultContainer + default: cn: vaults + default: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(version 3.0; acl "Allow users to create private container"; allow (add) userdn = "ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX";) ++default: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(version 3.0; acl "Allow services to create private container"; allow (add) userdn = "ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX";) + default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#USERDN";) + default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#GROUPDN";) + default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";) +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index ac608f5c7e2779da138c75a0f02bd5546f4aeffd..01c6096335d47b337253d4f2d1e0571200383c7a 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -44,7 +44,7 @@ from ipalib.crud import PKQuery, Retrieve, Update + from ipalib.plugable import Registry + from ipalib.plugins.baseldap import LDAPObject, LDAPCreate, LDAPDelete,\ + LDAPSearch, LDAPUpdate, LDAPRetrieve, LDAPAddMember, LDAPRemoveMember,\ +- pkey_to_value ++ LDAPModMember, pkey_to_value + from ipalib.request import context + from ipalib.plugins.user import split_principal + from ipalib import _, ngettext +@@ -93,122 +93,91 @@ The secret can only be retrieved using the private key. + """) + _(""" + EXAMPLES: + """) + _(""" +- List private vaults: ++ List vaults: + ipa vault-find ++ [--user |--service |--shared] + """) + _(""" +- List service vaults: +- ipa vault-find --service +-""") + _(""" +- List shared vaults: +- ipa vault-find --shared +-""") + _(""" +- List user vaults: +- ipa vault-find --user +-""") + _(""" +- Add a private vault: ++ Add a standard vault: + ipa vault-add +-""") + _(""" +- Add a service vault: +- ipa vault-add --service +-""") + _(""" +- Add a shared vault: +- ipa vault-add --shared +-""") + _(""" +- Add a user vault: +- ipa vault-add --user ++ [--user |--service |--shared] + """) + _(""" + Add a symmetric vault: +- ipa vault-add --type symmetric --password-file password.txt ++ ipa vault-add ++ [--user |--service |--shared] ++ --type symmetric --password-file password.txt + """) + _(""" + Add an asymmetric vault: +- ipa vault-add --type asymmetric --public-key-file public.pem ++ ipa vault-add ++ [--user |--service |--shared] ++ --type asymmetric --public-key-file public.pem + """) + _(""" +- Show a private vault: ++ Show a vault: + ipa vault-show ++ [--user |--service |--shared] + """) + _(""" +- Show a service vault: +- ipa vault-show --service ++ Modify a vault: ++ ipa vault-mod ++ [--user |--service |--shared] ++ --desc + """) + _(""" +- Show a shared vault: +- ipa vault-show --shared +-""") + _(""" +- Show a user vault: +- ipa vault-show --user +-""") + _(""" +- Modify a private vault: +- ipa vault-mod --desc +-""") + _(""" +- Modify a service vault: +- ipa vault-mod --service --desc +-""") + _(""" +- Modify a shared vault: +- ipa vault-mod --shared --desc +-""") + _(""" +- Modify a user vault: +- ipa vault-mod --user --desc +-""") + _(""" +- Delete a private vault: ++ Delete a vault: + ipa vault-del +-""") + _(""" +- Delete a service vault: +- ipa vault-del --service +-""") + _(""" +- Delete a shared vault: +- ipa vault-del --shared +-""") + _(""" +- Delete a user vault: +- ipa vault-del --user ++ [--user |--service |--shared] + """) + _(""" + Display vault configuration: + ipa vaultconfig-show + """) + _(""" +- Archive data into private vault: +- ipa vault-archive --in +-""") + _(""" +- Archive data into service vault: +- ipa vault-archive --service --in +-""") + _(""" +- Archive data into shared vault: +- ipa vault-archive --shared --in +-""") + _(""" +- Archive data into user vault: +- ipa vault-archive --user --in ++ Archive data into standard vault: ++ ipa vault-archive ++ [--user |--service |--shared] ++ --in + """) + _(""" + Archive data into symmetric vault: +- ipa vault-archive --in ++ ipa vault-archive ++ [--user |--service |--shared] ++ --in ++ --password-file password.txt + """) + _(""" + Archive data into asymmetric vault: +- ipa vault-archive --in +-""") + _(""" +- Retrieve data from private vault: +- ipa vault-retrieve --out +-""") + _(""" +- Retrieve data from service vault: +- ipa vault-retrieve --service --out +-""") + _(""" +- Retrieve data from shared vault: +- ipa vault-retrieve --shared --out ++ ipa vault-archive ++ [--user |--service |--shared] ++ --in + """) + _(""" +- Retrieve data from user vault: +- ipa vault-retrieve --user --out ++ Retrieve data from standard vault: ++ ipa vault-retrieve ++ [--user |--service |--shared] ++ --out + """) + _(""" + Retrieve data from symmetric vault: +- ipa vault-retrieve --out data.bin ++ ipa vault-retrieve ++ [--user |--service |--shared] ++ --out ++ --password-file password.txt + """) + _(""" + Retrieve data from asymmetric vault: +- ipa vault-retrieve --out data.bin --private-key-file private.pem ++ ipa vault-retrieve ++ [--user |--service |--shared] ++ --out --private-key-file private.pem + """) + _(""" +- Add a vault owner: +- ipa vault-add-owner --users ++ Add vault owners: ++ ipa vault-add-owner ++ [--user |--service |--shared] ++ [--users ] [--groups ] [--services ] + """) + _(""" +- Delete a vault owner: +- ipa vault-remove-owner --users ++ Delete vault owners: ++ ipa vault-remove-owner ++ [--user |--service |--shared] ++ [--users ] [--groups ] [--services ] + """) + _(""" +- Add a vault member: +- ipa vault-add-member --users ++ Add vault members: ++ ipa vault-add-member ++ [--user |--service |--shared] ++ [--users ] [--groups ] [--services ] + """) + _(""" +- Delete a vault member: +- ipa vault-remove-member --users ++ Delete vault members: ++ ipa vault-remove-member ++ [--user |--service |--shared] ++ [--users ] [--groups ] [--services ] + """) + + +@@ -285,8 +254,8 @@ class vault(LDAPObject): + 'ipavaulttype', + ] + attribute_members = { +- 'owner': ['user', 'group'], +- 'member': ['user', 'group'], ++ 'owner': ['user', 'group', 'service'], ++ 'member': ['user', 'group', 'service'], + } + + label = _('Vaults') +@@ -340,6 +309,11 @@ class vault(LDAPObject): + label=_('Owner groups'), + flags=['no_create', 'no_update', 'no_search'], + ), ++ Str( ++ 'owner_service?', ++ label=_('Owner services'), ++ flags=['no_create', 'no_update', 'no_search'], ++ ), + ) + + def get_dn(self, *keys, **options): +@@ -1432,8 +1406,23 @@ class vault_retrieve_internal(PKQuery): + return response + + ++class VaultModMember(LDAPModMember): ++ def get_options(self): ++ for param in super(VaultModMember, self).get_options(): ++ if param.name == 'service' and param not in vault_options: ++ param = param.clone_rename('services') ++ yield param ++ ++ def get_member_dns(self, **options): ++ if 'services' in options: ++ options['service'] = options.pop('services') ++ else: ++ options.pop('service', None) ++ return super(VaultModMember, self).get_member_dns(**options) ++ ++ + @register() +-class vault_add_owner(LDAPAddMember): ++class vault_add_owner(VaultModMember, LDAPAddMember): + __doc__ = _('Add owners to a vault.') + + takes_options = LDAPAddMember.takes_options + vault_options +@@ -1457,7 +1446,7 @@ class vault_add_owner(LDAPAddMember): + + + @register() +-class vault_remove_owner(LDAPRemoveMember): ++class vault_remove_owner(VaultModMember, LDAPRemoveMember): + __doc__ = _('Remove owners from a vault.') + + takes_options = LDAPRemoveMember.takes_options + vault_options +@@ -1481,14 +1470,14 @@ class vault_remove_owner(LDAPRemoveMember): + + + @register() +-class vault_add_member(LDAPAddMember): ++class vault_add_member(VaultModMember, LDAPAddMember): + __doc__ = _('Add members to a vault.') + + takes_options = LDAPAddMember.takes_options + vault_options + + + @register() +-class vault_remove_member(LDAPRemoveMember): ++class vault_remove_member(VaultModMember, LDAPRemoveMember): + __doc__ = _('Remove members from a vault.') + + takes_options = LDAPRemoveMember.takes_options + vault_options +-- +2.4.3 + diff --git a/SOURCES/0064-webui-add-radius-fields-to-user-page.patch b/SOURCES/0064-webui-add-radius-fields-to-user-page.patch deleted file mode 100644 index 57e905c..0000000 --- a/SOURCES/0064-webui-add-radius-fields-to-user-page.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 86a59f4a86fd0e7b60143aeb30ada95fad0f3f5f Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Thu, 13 Nov 2014 13:08:16 +0100 -Subject: [PATCH] webui: add radius fields to user page - -add --radius=ID --radius-username=radiusUserName to Web UI - -https://fedorahosted.org/freeipa/ticket/4686 - -Reviewed-By: Tomas Babej ---- - install/ui/src/freeipa/user.js | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js -index be01170b79b14f9094ba2a43a0a245d145df0cdf..4f53a27cf36ca65fe971982006062ad3b15d87c9 100644 ---- a/install/ui/src/freeipa/user.js -+++ b/install/ui/src/freeipa/user.js -@@ -159,6 +159,17 @@ return { - { label: '@i18n:authtype.type_otp', value: 'otp' } - ], - tooltip: '@i18n:authtype.user_tooltip' -+ }, -+ { -+ $type: 'entity_select', -+ name: 'ipatokenradiusconfiglink', -+ flags: ['w_if_no_aci'], -+ other_entity: 'radiusproxy', -+ other_field: 'cn' -+ }, -+ { -+ name: 'ipatokenradiususername', -+ flags: ['w_if_no_aci'] - } - ] - }, --- -2.1.0 - diff --git a/SOURCES/0065-Fix-zonemgr-option-encoding-detection.patch b/SOURCES/0065-Fix-zonemgr-option-encoding-detection.patch deleted file mode 100644 index e4698df..0000000 --- a/SOURCES/0065-Fix-zonemgr-option-encoding-detection.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 818fb211ae6e66de4014036cf2a003ade42a5c4a Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Tue, 25 Nov 2014 14:03:27 +0100 -Subject: [PATCH] Fix zonemgr option encoding detection - -Ticket: https://fedorahosted.org/freeipa/ticket/4766 -Reviewed-By: Jan Cholasta ---- - ipaserver/install/bindinstance.py | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index f02fe8647dd38d05734311406152c50108077561..547cf19ee36140b5f29fcf7d217933fa68e1952b 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -405,7 +405,10 @@ def zonemgr_callback(option, opt_str, value, parser): - # validate the value first - try: - # IDNA support requires unicode -- value = value.decode(getattr(sys.stdin, 'encoding', 'utf-8')) -+ encoding = getattr(sys.stdin, 'encoding', None) -+ if encoding is None: -+ encoding = 'utf-8' -+ value = value.decode(encoding) - validate_zonemgr_str(value) - except ValueError, e: - parser.error("invalid zonemgr: " + unicode(e)) --- -2.1.0 - diff --git a/SOURCES/0065-trusts-Detect-missing-Samba-instance.patch b/SOURCES/0065-trusts-Detect-missing-Samba-instance.patch new file mode 100644 index 0000000..50f4de4 --- /dev/null +++ b/SOURCES/0065-trusts-Detect-missing-Samba-instance.patch @@ -0,0 +1,189 @@ +From df641e93d2f88f642f476ad8c5b7313bdfce8d9e Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Thu, 6 Aug 2015 10:10:04 +0200 +Subject: [PATCH] trusts: Detect missing Samba instance + +In the event of invocation of trust related commands, IPA server needs to +contact local Samba instance. This is not possible on servers that +merely act as AD trust agents, since they do not have Samba instance +running. + +Properly detect the absence of the Samba instance and output +user-friendly +message which includes list of servers that are capable of running +the command, if such exist. + +List of commands affected: +* ipa trust-add +* ipa trust-fetch-domains +* all of the trustdomain commands available via CLI + +https://fedorahosted.org/freeipa/ticket/5165 + +Reviewed-By: Martin Babinsky +--- + ipalib/plugins/trust.py | 99 +++++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 79 insertions(+), 20 deletions(-) + +diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py +index 0bb5e6558b680ac1acad44461d78a571098c7b25..c7546692bdd8dd827ee9772b72a758042d97aa71 100644 +--- a/ipalib/plugins/trust.py ++++ b/ipalib/plugins/trust.py +@@ -199,6 +199,73 @@ def make_trust_dn(env, trust_type, dn): + return DN(dn, container_dn) + return dn + ++def find_adtrust_masters(ldap, api): ++ """ ++ Returns a list of names of IPA servers with ADTRUST component configured. ++ """ ++ ++ try: ++ entries, truncated = ldap.find_entries( ++ "cn=ADTRUST", ++ base_dn=api.env.container_masters + api.env.basedn ++ ) ++ except errors.NotFound: ++ entries = [] ++ ++ return [entry.dn[1].value for entry in entries] ++ ++def verify_samba_component_presence(ldap, api): ++ """ ++ Verifies that Samba is installed and configured on this particular master. ++ If Samba is not available, provide a heplful hint with the list of masters ++ capable of running the commands. ++ """ ++ ++ adtrust_present = api.Command['adtrust_is_enabled']()['result'] ++ ++ hint = _( ++ ' Alternatively, following servers are capable of running this ' ++ 'command: %(masters)s' ++ ) ++ ++ def raise_missing_component_error(message): ++ masters_with_adtrust = find_adtrust_masters(ldap, api) ++ ++ # If there are any masters capable of running Samba requiring commands ++ # let's advertise them directly ++ if masters_with_adtrust: ++ message += hint % dict(masters=', '.join(masters_with_adtrust)) ++ ++ raise errors.NotFound( ++ name=_('AD Trust setup'), ++ reason=message, ++ ) ++ ++ # We're ok in this case, bail out ++ if adtrust_present and _bindings_installed: ++ return ++ ++ # First check for packages missing ++ elif not _bindings_installed: ++ error_message=_( ++ 'Cannot perform the selected command without Samba 4 support ' ++ 'installed. Make sure you have installed server-trust-ad ' ++ 'sub-package of IPA.' ++ ) ++ ++ raise_missing_component_error(error_message) ++ ++ # Packages present, but ADTRUST instance is not configured ++ elif not adtrust_present: ++ error_message=_( ++ 'Cannot perform the selected command without Samba 4 instance ' ++ 'configured on this machine. Make sure you have run ' ++ 'ipa-adtrust-install on this server.' ++ ) ++ ++ raise_missing_component_error(error_message) ++ ++ + def generate_creds(trustinstance, style, **options): + """ + Generate string representing credentials using trust instance +@@ -554,6 +621,10 @@ sides. + has_output_params = LDAPCreate.has_output_params + trust_output_params + + def execute(self, *keys, **options): ++ ldap = self.obj.backend ++ ++ verify_samba_component_presence(ldap, self.api) ++ + full_join = self.validate_options(*keys, **options) + old_range, range_name, dom_sid = self.validate_range(*keys, **options) + result = self.execute_ad(full_join, *keys, **options) +@@ -569,7 +640,6 @@ sides. + created_range_type = old_range['result']['iparangetype'][0] + + trust_filter = "cn=%s" % result['value'] +- ldap = self.obj.backend + (trusts, truncated) = ldap.find_entries( + base_dn=DN(self.api.env.container_trusts, self.api.env.basedn), + filter=trust_filter) +@@ -642,16 +712,6 @@ sides. + def validate_options(self, *keys, **options): + trusted_realm_domain = keys[-1] + +- if not _bindings_installed: +- raise errors.NotFound( +- name=_('AD Trust setup'), +- reason=_( +- 'Cannot perform join operation without Samba 4 support ' +- 'installed. Make sure you have installed server-trust-ad ' +- 'sub-package of IPA' +- ) +- ) +- + if not _murmur_installed and 'base_id' not in options: + raise errors.ValidationError( + name=_('missing base_id'), +@@ -1398,6 +1458,9 @@ class trustdomain_del(LDAPDelete): + msg_summary = _('Removed information about the trusted domain "%(value)s"') + + def execute(self, *keys, **options): ++ ldap = self.api.Backend.ldap2 ++ verify_samba_component_presence(ldap, self.api) ++ + # Note that pre-/post- callback handling for LDAPDelete is causing pre_callback + # to always receive empty keys. We need to catch the case when root domain is being deleted + +@@ -1470,15 +1533,9 @@ class trust_fetch_domains(LDAPRetrieve): + ) + + def execute(self, *keys, **options): +- if not _bindings_installed: +- raise errors.NotFound( +- name=_('AD Trust setup'), +- reason=_( +- 'Cannot perform join operation without Samba 4 support ' +- 'installed. Make sure you have installed server-trust-ad ' +- 'sub-package of IPA' +- ) +- ) ++ ldap = self.api.Backend.ldap2 ++ verify_samba_component_presence(ldap, self.api) ++ + trust = self.api.Command.trust_show(keys[0], raw=True)['result'] + + result = dict() +@@ -1524,6 +1581,7 @@ class trustdomain_enable(LDAPQuery): + + def execute(self, *keys, **options): + ldap = self.api.Backend.ldap2 ++ verify_samba_component_presence(ldap, self.api) + + if keys[0].lower() == keys[1].lower(): + raise errors.ValidationError(name='domain', +@@ -1564,6 +1622,7 @@ class trustdomain_disable(LDAPQuery): + + def execute(self, *keys, **options): + ldap = self.api.Backend.ldap2 ++ verify_samba_component_presence(ldap, self.api) + + if keys[0].lower() == keys[1].lower(): + raise errors.ValidationError(name='domain', +-- +2.4.3 + diff --git a/SOURCES/0066-Catch-USBError-during-YubiKey-location.patch b/SOURCES/0066-Catch-USBError-during-YubiKey-location.patch deleted file mode 100644 index 157f4c8..0000000 --- a/SOURCES/0066-Catch-USBError-during-YubiKey-location.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 238225b49c52d44ab926c97c0f3bf9d93230d99a Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Fri, 7 Nov 2014 10:47:43 -0500 -Subject: [PATCH] Catch USBError during YubiKey location - -https://fedorahosted.org/freeipa/ticket/4693 - -Reviewed-By: Martin Kosek ---- - ipalib/plugins/otptoken_yubikey.py | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/ipalib/plugins/otptoken_yubikey.py b/ipalib/plugins/otptoken_yubikey.py -index 7095887ac7cdf5d4b7d0d30edc6cab0222246664..4c2594182c08a9de3f2f5861aac60b39a9ce022a 100644 ---- a/ipalib/plugins/otptoken_yubikey.py -+++ b/ipalib/plugins/otptoken_yubikey.py -@@ -25,6 +25,7 @@ from ipalib.plugins.otptoken import otptoken - - import os - -+import usb.core - import yubico - - __doc__ = _(""" -@@ -81,8 +82,10 @@ class otptoken_add_yubikey(Command): - # Open the YubiKey - try: - yk = yubico.find_yubikey() -- except yubico.yubikey.YubiKeyError, e: -- raise NotFound(reason=_('No YubiKey found')) -+ except usb.core.USBError as e: -+ raise NotFound(reason="No YubiKey found: %s" % e.strerror) -+ except yubico.yubikey.YubiKeyError as e: -+ raise NotFound(reason=e.reason) - - assert yk.version_num() >= (2, 1) - --- -2.1.0 - diff --git a/SOURCES/0066-winsync-migrate-Add-warning-about-passsync.patch b/SOURCES/0066-winsync-migrate-Add-warning-about-passsync.patch new file mode 100644 index 0000000..d3917e2 --- /dev/null +++ b/SOURCES/0066-winsync-migrate-Add-warning-about-passsync.patch @@ -0,0 +1,38 @@ +From cdbf2fcc214bf8a4f94e3b25b6a742ea1fc9f75c Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Mon, 17 Aug 2015 08:46:52 +0200 +Subject: [PATCH] winsync-migrate: Add warning about passsync + +https://fedorahosted.org/freeipa/ticket/5162 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/ipa_winsync_migrate.py | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/ipaserver/install/ipa_winsync_migrate.py b/ipaserver/install/ipa_winsync_migrate.py +index cbe068458cc0b6853573c9d23d4cb6386a816bb3..c327e502e6bfb6e402931e1962fe2410570b2bc2 100644 +--- a/ipaserver/install/ipa_winsync_migrate.py ++++ b/ipaserver/install/ipa_winsync_migrate.py +@@ -302,6 +302,12 @@ class WinsyncMigrate(admintool.AdminTool): + object_container_dn=DN(api.env.container_selinux, api.env.basedn), + ) + ++ def warn_passsync(self): ++ self.log.warning("Migration completed. Please note that if PassSync " ++ "was configured on the given Active Directory server, " ++ "it needs to be manually removed, otherwise it may try " ++ "to reset password for accounts that are no longer existent.") ++ + @classmethod + def main(cls, argv): + """ +@@ -343,3 +349,5 @@ class WinsyncMigrate(admintool.AdminTool): + self.migrate_hbac_memberships(entry) + self.migrate_selinux_memberships(entry) + self.ldap.delete_entry(entry) ++ ++ self.warn_passsync() +-- +2.4.3 + diff --git a/SOURCES/0067-Use-NSS-protocol-range-API-to-set-available-TLS-prot.patch b/SOURCES/0067-Use-NSS-protocol-range-API-to-set-available-TLS-prot.patch deleted file mode 100644 index 0fc2801..0000000 --- a/SOURCES/0067-Use-NSS-protocol-range-API-to-set-available-TLS-prot.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 8c544d9583c4172634f3180d6f90e6d4f37595ed Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Thu, 30 Oct 2014 11:52:14 -0400 -Subject: [PATCH] Use NSS protocol range API to set available TLS protocols - -Protocols are configured as an inclusive range from SSLv3 through -TLSv1.2. The allowed values in the range are ssl3, tls1.0, -tls1.1 and tls1.2. - -This is overridable per client by setting tls_version_min and/or -tls_version_max. - -https://fedorahosted.org/freeipa/ticket/4653 - -Reviewed-By: Jan Cholasta ---- - freeipa.spec.in | 2 +- - ipalib/constants.py | 4 ++++ - ipalib/rpc.py | 5 ++++- - ipapython/dogtag.py | 4 +++- - ipapython/nsslib.py | 17 +++++++++++++++-- - 5 files changed, 27 insertions(+), 5 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index e29f77de0db89035d15008c6be2da0ae7e96158a..1c975b3912d0a7470a32f1b7e314cfde74446e85 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -271,7 +271,7 @@ Requires: gnupg - Requires: iproute - Requires: keyutils - Requires: pyOpenSSL --Requires: python-nss >= 0.15 -+Requires: python-nss >= 0.16 - Requires: python-lxml - Requires: python-netaddr - Requires: libipa_hbac-python -diff --git a/ipalib/constants.py b/ipalib/constants.py -index 1eed7ca6ad0e5920318dadc68ed36fff6cf889f2..111bafe5ed0c3d2df58a1b6839feedc58a14fcc4 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -122,6 +122,10 @@ DEFAULT_CONFIG = ( - - ('rpc_protocol', 'jsonrpc'), - -+ # Define an inclusive range of SSL/TLS version support -+ ('tls_version_min', 'tls1.0'), -+ ('tls_version_max', 'tls1.2'), -+ - # Time to wait for a service to start, in seconds - ('startup_timeout', 300), - -diff --git a/ipalib/rpc.py b/ipalib/rpc.py -index 5934f0c26e4b7c0a44adbab978c1f9b319d72e9f..806f6bb9adf004660c9cb285cf31b09a988afa93 100644 ---- a/ipalib/rpc.py -+++ b/ipalib/rpc.py -@@ -68,6 +68,7 @@ from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT - KRB5_FCC_PERM, KRB5_FCC_NOFILE, KRB5_CC_FORMAT, KRB5_REALM_CANT_RESOLVE - from ipapython.dn import DN - from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES -+from ipalib import api - - COOKIE_NAME = 'ipa_session' - KEYRING_COOKIE_NAME = '%s_cookie:%%s' % COOKIE_NAME -@@ -488,7 +489,9 @@ class SSLTransport(LanguageAwareTransport): - if sys.version_info < (2, 7): - conn = NSSHTTPS(host, 443, dbdir=dbdir, no_init=no_init) - else: -- conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init) -+ conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init, -+ tls_version_min=api.env.tls_version_min, -+ tls_version_max=api.env.tls_version_max) - self.dbdir=dbdir - - conn.connect() -diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py -index 14824b99431e85dd73613befd72e500d370cfe2c..0e0aacca798377517244075ed6b07dff63e87358 100644 ---- a/ipapython/dogtag.py -+++ b/ipapython/dogtag.py -@@ -234,7 +234,9 @@ def https_request(host, port, url, secdir, password, nickname, **kw): - """ - - def connection_factory(host, port): -- conn = nsslib.NSSConnection(host, port, dbdir=secdir) -+ conn = nsslib.NSSConnection(host, port, dbdir=secdir, -+ tls_version_min=api.env.tls_version_min, -+ tls_version_max=api.env.tls_version_max) - conn.set_debuglevel(0) - conn.connect() - conn.sock.set_client_auth_data_callback( -diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py -index 93b0c56fcff4fc69841a6823aae8f694c1f76ff0..57fa3ff4fa5a044577f21fe43c2c0b0596c2e4f8 100644 ---- a/ipapython/nsslib.py -+++ b/ipapython/nsslib.py -@@ -171,7 +171,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): - default_port = httplib.HTTPSConnection.default_port - - def __init__(self, host, port=None, strict=None, -- dbdir=None, family=socket.AF_UNSPEC, no_init=False): -+ dbdir=None, family=socket.AF_UNSPEC, no_init=False, -+ tls_version_min='tls1.1', tls_version_max='tls1.2'): - """ - :param host: the server to connect to - :param port: the port to use (default is set in HTTPConnection) -@@ -180,6 +181,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): - :param no_init: do not initialize the NSS database. This requires - that the database has already been initialized or - the request will fail. -+ :param tls_min_version: mininum version of SSL/TLS supported -+ :param tls_max_version: maximum version of SSL/TLS supported. - """ - httplib.HTTPConnection.__init__(self, host, port, strict) - NSSAddressFamilyFallback.__init__(self, family) -@@ -199,6 +202,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): - nss.nss_init(dbdir) - ssl.set_domestic_policy() - nss.set_password_callback(self.password_callback) -+ self.tls_version_min = str(tls_version_min) -+ self.tls_version_max = str(tls_version_max) - - def _create_socket(self): - # TODO: remove the try block once python-nss is guaranteed to contain -@@ -218,6 +223,11 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): - self.sock = ssl.SSLSocket(family=self.family) - self.sock.set_ssl_option(ssl.SSL_SECURITY, True) - self.sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True) -+ try: -+ self.sock.set_ssl_version_range(self.tls_version_min, self.tls_version_max) -+ except NSPRError, e: -+ root_logger.error('Failed to set TLS range to %s, %s' % (self.tls_version_min, self.tls_version_max)) -+ raise - self.sock.set_ssl_option(ssl_require_safe_negotiation, False) - self.sock.set_ssl_option(ssl_enable_renegotiation, ssl_renegotiate_requires_xtn) - # Provide a callback which notifies us when the SSL handshake is complete -@@ -236,8 +246,11 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): - """ - Verify callback. If we get here then the certificate is ok. - """ -+ channel = sock.get_ssl_channel_info() -+ suite = ssl.get_cipher_suite_info(channel.cipher_suite) - root_logger.debug("handshake complete, peer = %s", sock.get_peer_name()) -- pass -+ root_logger.debug('Protocol: %s' % channel.protocol_version_str.upper()) -+ root_logger.debug('Cipher: %s' % suite.cipher_suite_name) - - def connect(self): - self.connect_socket(self.host, self.port) --- -2.1.0 - diff --git a/SOURCES/0067-winsync-migrate-Expand-the-man-page.patch b/SOURCES/0067-winsync-migrate-Expand-the-man-page.patch new file mode 100644 index 0000000..500fe82 --- /dev/null +++ b/SOURCES/0067-winsync-migrate-Expand-the-man-page.patch @@ -0,0 +1,57 @@ +From 6e006377d043155590024235d770cb37eb801652 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Mon, 17 Aug 2015 08:46:20 +0200 +Subject: [PATCH] winsync-migrate: Expand the man page + +https://fedorahosted.org/freeipa/ticket/5162 + +Reviewed-By: Martin Babinsky +--- + install/tools/man/ipa-winsync-migrate.1 | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/install/tools/man/ipa-winsync-migrate.1 b/install/tools/man/ipa-winsync-migrate.1 +index a1e01c83da6017d5cbe10297dbe84a4dd1741ec7..88702bad6fca66206dcbc1a90fce495eb33598fb 100644 +--- a/install/tools/man/ipa-winsync-migrate.1 ++++ b/install/tools/man/ipa-winsync-migrate.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Tomas Babej + .\" +-.TH "ipa-advise" "1" "Mar 10 2015" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-winsync-migrate" "1" "Mar 10 2015" "FreeIPA" "FreeIPA Manual Pages" + .SH "NAME" + ipa\-winsync\-migrate \- Seamless migration of AD users created by winsync to native AD users. + .SH "SYNOPSIS" +@@ -25,3 +25,28 @@ ipa\-winsync\-migrate + Migrates AD users created by winsync agreement to ID overrides in + the Default Trust View, thus preserving the actual POSIX attributes + already established. ++ ++Prior to the actual migration, the winsync replication agreement ++will be removed to protect the removal of the user accounts ++on the Active Directory side. ++ ++During the migration, group, assigned roles, HBAC rules and SELinux ++memberships of the synced users will be preserved. Any local copies ++(created by winsync) of the migrated users will be removed. ++ ++.SH "WARNINGS" ++After the migration, any PassSync agreements need to be removed ++from Active Directory Domain Controllers, otherwise they might ++attempt to update passwords for accounts that no longer exist ++on the IPA server. ++ ++.SH "OPTIONS" ++.TP ++\fB\-\-realm\fR ++The Active Directory realm the winsynced users belong to. ++.TP ++\fB\-\-server\fR ++The hostname of Active Directory Domain Controller the winsync replication agreement is established with. ++.TP ++\fB\-\-unattended\fR ++Never prompts for user input. +-- +2.4.3 + diff --git a/SOURCES/0068-Throw-zonemgr-error-message-before-installation-proc.patch b/SOURCES/0068-Throw-zonemgr-error-message-before-installation-proc.patch deleted file mode 100644 index d753f55..0000000 --- a/SOURCES/0068-Throw-zonemgr-error-message-before-installation-proc.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 453332215667d6ff9595e6dedeeb3ed5ba7e5bdf Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 27 Nov 2014 14:16:23 +0100 -Subject: [PATCH] Throw zonemgr error message before installation proceeds - -Ticket: https://fedorahosted.org/freeipa/ticket/4771 -Reviewed-By: Jan Cholasta ---- - ipalib/parameters.py | 35 +++++------------------------------ - ipalib/util.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 50 insertions(+), 30 deletions(-) - -diff --git a/ipalib/parameters.py b/ipalib/parameters.py -index 0cf14a4cd2900459ccd5d6d52912960c642223aa..7fa55fd6a6854ffa97da211ca5ef04b7ad974dc4 100644 ---- a/ipalib/parameters.py -+++ b/ipalib/parameters.py -@@ -112,7 +112,7 @@ from errors import ConversionError, RequirementError, ValidationError - from errors import PasswordMismatch, Base64DecodeError - from constants import TYPE_ERROR, CALLABLE_ERROR, LDAP_GENERALIZED_TIME_FORMAT - from text import Gettext, FixMe --from util import json_serialize -+from util import json_serialize, validate_idna_domain - from ipapython.dn import DN - from ipapython.dnsutil import DNSName - import dns.name -@@ -1950,36 +1950,11 @@ class DNSNameParam(Param): - error = None - - try: -- domain_name = DNSName(value) -- except dns.name.BadEscape: -- error = _('invalid escape code in domain name') -- except dns.name.EmptyLabel: -- error = _('empty DNS label') -- except dns.name.NameTooLong: -- error = _('domain name cannot be longer than 255 characters') -- except dns.name.LabelTooLong: -- error = _('DNS label cannot be longer than 63 characters') -- except dns.exception.SyntaxError: -- error = _('invalid domain name') -- else: -- #compare if IDN normalized and original domain match -- #there is N:1 mapping between unicode and IDNA names -- #user should use normalized names to avoid mistakes -- labels = re.split(u'[.\uff0e\u3002\uff61]', value, flags=re.UNICODE) -- try: -- map(lambda label: label.encode("ascii"), labels) -- except UnicodeError: -- # IDNA -- is_nonnorm = any(encodings.idna.nameprep(x) != x for x in labels) -- if is_nonnorm: -- error = _("domain name '%(domain)s' should be normalized to" -- ": %(normalized)s") % { -- 'domain': value, -- 'normalized': '.'.join([encodings.idna.nameprep(x) for x in labels])} -- if error: -+ validate_idna_domain(value) -+ except ValueError as e: - raise ConversionError(name=self.get_param_name(), index=index, -- error=error) -- value = domain_name -+ error=unicode(e)) -+ value = DNSName(value) - - if self.only_absolute and not value.is_absolute(): - value = value.make_absolute() -diff --git a/ipalib/util.py b/ipalib/util.py -index 7a283106d70ba6a3e25cc7129d57b44b80876882..2c17d80a0427a5c7e45a6a0b64fa1f4d39fffa8a 100644 ---- a/ipalib/util.py -+++ b/ipalib/util.py -@@ -28,6 +28,7 @@ import socket - import re - import decimal - import dns -+import encodings - import netaddr - from types import NoneType - from weakref import WeakKeyDictionary -@@ -277,6 +278,7 @@ def validate_zonemgr(zonemgr): - - def validate_zonemgr_str(zonemgr): - zonemgr = normalize_zonemgr(zonemgr) -+ validate_idna_domain(zonemgr) - zonemgr = DNSName(zonemgr) - return validate_zonemgr(zonemgr) - -@@ -589,3 +591,46 @@ def validate_dnssec_forwarder(ip_addr): - return False - - return True -+ -+ -+def validate_idna_domain(value): -+ """ -+ Validate if value is valid IDNA domain. -+ -+ If domain is not valid, raises ValueError -+ :param value: -+ :return: -+ """ -+ error = None -+ -+ try: -+ DNSName(value) -+ except dns.name.BadEscape: -+ error = _('invalid escape code in domain name') -+ except dns.name.EmptyLabel: -+ error = _('empty DNS label') -+ except dns.name.NameTooLong: -+ error = _('domain name cannot be longer than 255 characters') -+ except dns.name.LabelTooLong: -+ error = _('DNS label cannot be longer than 63 characters') -+ except dns.exception.SyntaxError: -+ error = _('invalid domain name') -+ else: -+ #compare if IDN normalized and original domain match -+ #there is N:1 mapping between unicode and IDNA names -+ #user should use normalized names to avoid mistakes -+ labels = re.split(u'[.\uff0e\u3002\uff61]', value, flags=re.UNICODE) -+ try: -+ map(lambda label: label.encode("ascii"), labels) -+ except UnicodeError: -+ # IDNA -+ is_nonnorm = any(encodings.idna.nameprep(x) != x for x in labels) -+ if is_nonnorm: -+ error = _("domain name '%(domain)s' should be normalized to" -+ ": %(normalized)s") % { -+ 'domain': value, -+ 'normalized': '.'.join([encodings.idna.nameprep(x) -+ for x in labels])} -+ -+ if error: -+ raise ValueError(error) --- -2.1.0 - diff --git a/SOURCES/0068-fix-typo-in-BasePathNamespace-member-pointing-to-ods.patch b/SOURCES/0068-fix-typo-in-BasePathNamespace-member-pointing-to-ods.patch new file mode 100644 index 0000000..f5bf21a --- /dev/null +++ b/SOURCES/0068-fix-typo-in-BasePathNamespace-member-pointing-to-ods.patch @@ -0,0 +1,55 @@ +From e106329ac5dbbbcf1e303d1311cd0d742f5d8803 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 13 Aug 2015 15:03:05 +0200 +Subject: [PATCH] fix typo in BasePathNamespace member pointing to ods exporter + config + +Reviewed-By: Martin Basti +--- + ipaplatform/base/paths.py | 2 +- + ipaserver/install/ipa_backup.py | 2 +- + ipaserver/install/odsexporterinstance.py | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 4c93c1f7162b0aeb4f798ef84e1ac8db4573518b..0dd3c7fda3020264a1ace8f2d13557cfddf18c2d 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -119,7 +119,7 @@ class BasePathNamespace(object): + SYSCONFIG_DIRSRV_PKI_IPA_DIR = "/etc/sysconfig/dirsrv-PKI-IPA" + SYSCONFIG_DIRSRV_SYSTEMD = "/etc/sysconfig/dirsrv.systemd" + SYSCONFIG_IPA_DNSKEYSYNCD = "/etc/sysconfig/ipa-dnskeysyncd" +- SYSOCNFIG_IPA_ODS_EXPORTER = "/etc/sysconfig/ipa-ods-exporter" ++ SYSCONFIG_IPA_ODS_EXPORTER = "/etc/sysconfig/ipa-ods-exporter" + SYSCONFIG_HTTPD = "/etc/sysconfig/httpd" + SYSCONFIG_KRB5KDC_DIR = "/etc/sysconfig/krb5kdc" + SYSCONFIG_NAMED = "/etc/sysconfig/named" +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index f7e032ae572f404f84ce48c1a5d72e78c31b4766..1bb6f810b16c8344ab957dd6259983189a88e89f 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -132,7 +132,7 @@ class Backup(admintool.AdminTool): + paths.SYSCONFIG_KRB5KDC_DIR, + paths.SYSCONFIG_PKI_CA_PKI_CA_DIR, + paths.SYSCONFIG_IPA_DNSKEYSYNCD, +- paths.SYSOCNFIG_IPA_ODS_EXPORTER, ++ paths.SYSCONFIG_IPA_ODS_EXPORTER, + paths.SYSCONFIG_NAMED, + paths.SYSCONFIG_ODS, + paths.ETC_SYSCONFIG_AUTHCONFIG, +diff --git a/ipaserver/install/odsexporterinstance.py b/ipaserver/install/odsexporterinstance.py +index c37095cfc3bba8c6724f45d23293bdf6f4a200ee..248943d6c0ca4b71815bcf7526d575842f6ce426 100644 +--- a/ipaserver/install/odsexporterinstance.py ++++ b/ipaserver/install/odsexporterinstance.py +@@ -86,7 +86,7 @@ class ODSExporterInstance(service.Service): + root_logger.error("DNSKeyExporter service already exists") + + def __setup_key_exporter(self): +- installutils.set_directive(paths.SYSOCNFIG_IPA_ODS_EXPORTER, ++ installutils.set_directive(paths.SYSCONFIG_IPA_ODS_EXPORTER, + 'SOFTHSM2_CONF', + paths.DNSSEC_SOFTHSM2_CONF, + quotes=False, separator='=') +-- +2.4.3 + diff --git a/SOURCES/0069-certs-Fix-incorrect-flag-handling-in-load_cacert.patch b/SOURCES/0069-certs-Fix-incorrect-flag-handling-in-load_cacert.patch deleted file mode 100644 index e8e73d1..0000000 --- a/SOURCES/0069-certs-Fix-incorrect-flag-handling-in-load_cacert.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 9c9050a11a14f548fe2f0f0746c686a8ccc09488 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Tue, 2 Dec 2014 13:13:51 +0100 -Subject: [PATCH] certs: Fix incorrect flag handling in load_cacert - -For CA certificates that are not certificates of IPA CA, we incorrectly -set the trust flags to ",,", regardless what the actual trust_flags -parameter was passed. - -Make the load_cacert method respect trust_flags and make it a required -argument. - -https://fedorahosted.org/freeipa/ticket/4779 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/certs.py | 6 ++---- - ipaserver/install/dsinstance.py | 2 +- - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py -index 5399a0fa566c6f7df81a9d1e347f6ac99e5188c9..7292cbbe3574f57d32daa6f1e310669486fa5eff 100644 ---- a/ipaserver/install/certs.py -+++ b/ipaserver/install/certs.py -@@ -238,7 +238,7 @@ class CertDB(object): - "-k", self.passwd_fname]) - self.set_perms(self.pk12_fname) - -- def load_cacert(self, cacert_fname, trust_flags='C,,'): -+ def load_cacert(self, cacert_fname, trust_flags): - """ - Load all the certificates from a given file. It is assumed that - this file creates CA certificates. -@@ -255,11 +255,9 @@ class CertDB(object): - (rdn, subject_dn) = get_cert_nickname(cert) - if subject_dn == ca_dn: - nick = get_ca_nickname(self.realm) -- tf = trust_flags - else: - nick = str(subject_dn) -- tf = ',,' -- self.nssdb.add_cert(cert, nick, tf, pem=True) -+ self.nssdb.add_cert(cert, nick, trust_flags, pem=True) - except RuntimeError: - break - -diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py -index da535347117166e6cb445b0ebf14ad71787f72ba..860ad992ea94b8275fdfd1b4435607375c1d3d80 100644 ---- a/ipaserver/install/dsinstance.py -+++ b/ipaserver/install/dsinstance.py -@@ -841,7 +841,7 @@ class DsInstance(service.Service): - certdb.cacert_name = cacert_name - status = True - try: -- certdb.load_cacert(cacert_fname) -+ certdb.load_cacert(cacert_fname, 'C,,') - except ipautil.CalledProcessError, e: - root_logger.critical("Error importing CA cert file named [%s]: %s" % - (cacert_fname, str(e))) --- -2.1.0 - diff --git a/SOURCES/0069-ipa-backup-archive-DNSSEC-zone-file-and-kasp.db.patch b/SOURCES/0069-ipa-backup-archive-DNSSEC-zone-file-and-kasp.db.patch new file mode 100644 index 0000000..f63f3b5 --- /dev/null +++ b/SOURCES/0069-ipa-backup-archive-DNSSEC-zone-file-and-kasp.db.patch @@ -0,0 +1,28 @@ +From 4d2932189ca9426492b2a69809e27c7aaca5e618 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 13 Aug 2015 15:05:36 +0200 +Subject: [PATCH] ipa-backup: archive DNSSEC zone file and kasp.db + +https://fedorahosted.org/freeipa/ticket/5159 + +Reviewed-By: Martin Basti +--- + ipaserver/install/ipa_backup.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 1bb6f810b16c8344ab957dd6259983189a88e89f..d7afb3654b09e88321f1ce9f279749b19c2f6414 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -171,6 +171,8 @@ class Backup(admintool.AdminTool): + paths.SVC_LIST_FILE, + paths.OPENDNSSEC_CONF_FILE, + paths.OPENDNSSEC_KASP_FILE, ++ paths.OPENDNSSEC_ZONELIST_FILE, ++ paths.OPENDNSSEC_KASP_DB, + paths.DNSSEC_SOFTHSM2_CONF, + paths.DNSSEC_SOFTHSM_PIN_SO, + paths.IPA_ODS_EXPORTER_KEYTAB, +-- +2.4.3 + diff --git a/SOURCES/0070-Preliminary-refactoring-of-libotp-files.patch b/SOURCES/0070-Preliminary-refactoring-of-libotp-files.patch deleted file mode 100644 index 95100d4..0000000 --- a/SOURCES/0070-Preliminary-refactoring-of-libotp-files.patch +++ /dev/null @@ -1,2309 +0,0 @@ -From d3c2efc7362f8eeb1cfb22b5d59bdec22226af65 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Mon, 10 Nov 2014 20:58:20 -0500 -Subject: [PATCH] Preliminary refactoring of libotp files - -There are no major changes in this commit other than changing filenames -and symbols to have consistent namespaces. This prepares for larger -changes to come in subsequent commits. - -Reviewed-By: Thierry Bordaz ---- - .../ipa-otp-lasttoken/Makefile.am | 1 - - .../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 10 +- - .../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h | 2 +- - daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 12 +- - daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c | 11 +- - daemons/ipa-slapi-plugins/libotp/Makefile.am | 10 +- - daemons/ipa-slapi-plugins/libotp/hotp.c | 170 ++++++ - daemons/ipa-slapi-plugins/libotp/hotp.h | 60 +++ - daemons/ipa-slapi-plugins/libotp/libotp.c | 573 --------------------- - daemons/ipa-slapi-plugins/libotp/libotp.h | 93 ---- - daemons/ipa-slapi-plugins/libotp/librfc.c | 170 ------ - daemons/ipa-slapi-plugins/libotp/librfc.h | 63 --- - daemons/ipa-slapi-plugins/libotp/otp_token.c | 572 ++++++++++++++++++++ - daemons/ipa-slapi-plugins/libotp/otp_token.h | 87 ++++ - daemons/ipa-slapi-plugins/libotp/t_hotp.c | 121 +++++ - daemons/ipa-slapi-plugins/libotp/t_librfc.c | 121 ----- - 17 files changed, 1033 insertions(+), 1044 deletions(-) - create mode 100644 daemons/ipa-slapi-plugins/libotp/hotp.c - create mode 100644 daemons/ipa-slapi-plugins/libotp/hotp.h - delete mode 100644 daemons/ipa-slapi-plugins/libotp/libotp.c - delete mode 100644 daemons/ipa-slapi-plugins/libotp/libotp.h - delete mode 100644 daemons/ipa-slapi-plugins/libotp/librfc.c - delete mode 100644 daemons/ipa-slapi-plugins/libotp/librfc.h - create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_token.c - create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_token.h - create mode 100644 daemons/ipa-slapi-plugins/libotp/t_hotp.c - delete mode 100644 daemons/ipa-slapi-plugins/libotp/t_librfc.c - -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am -index d12fbcc891c5f210028b1c02ffbd83908e50acc6..cb6340960818eb4874a70f36603feda93652370f 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/Makefile.am -@@ -3,7 +3,6 @@ PLUGIN_COMMON_DIR = ../common - AM_CPPFLAGS = \ - -I. \ - -I$(srcdir) \ -- -I$(srcdir)/../libotp \ - -I$(PLUGIN_COMMON_DIR) \ - -I/usr/include/dirsrv \ - -DPREFIX=\""$(prefix)"\" \ -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -index 15b404dcdb6bd88c70ccc7c5fed7a5829483590b..19217ba7fbf562231dd74b25cfd13a0f4d930e7c 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -@@ -41,7 +41,7 @@ - # include - #endif - --#include -+#include "../libotp/otp_token.h" - #include - - #include "util.h" -@@ -61,7 +61,7 @@ target_is_only_enabled_token(Slapi_PBlock *pb) - { - Slapi_DN *target_sdn = NULL; - Slapi_DN *token_sdn = NULL; -- struct otptoken **tokens; -+ struct otp_token **tokens; - char *user_dn = NULL; - bool match; - -@@ -75,10 +75,10 @@ target_is_only_enabled_token(Slapi_PBlock *pb) - return false; - - /* Get the SDN of the only enabled token. */ -- tokens = otptoken_find(plugin_id, user_dn, NULL, true, NULL); -+ tokens = otp_token_find(plugin_id, user_dn, NULL, true, NULL); - if (tokens != NULL && tokens[0] != NULL && tokens[1] == NULL) -- token_sdn = slapi_sdn_dup(otptoken_get_sdn(tokens[0])); -- otptoken_free_array(tokens); -+ token_sdn = slapi_sdn_dup(otp_token_get_sdn(tokens[0])); -+ otp_token_free_array(tokens); - if (token_sdn == NULL) - return false; - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -index 77beca2da0810ed5507d95b21f99d22f63b05fc1..eeb352611e5b67a2f6803b59414fb31c37f39f33 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -@@ -11,7 +11,6 @@ ASN1_UTIL_DIR=../../../asn1 - AM_CPPFLAGS = \ - -I. \ - -I$(srcdir) \ -- -I$(srcdir)/../libotp \ - -I$(PLUGIN_COMMON_DIR) \ - -I$(KRB5_UTIL_DIR) \ - -I$(ASN1_UTIL_DIR) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h -index f8851122b920bb8317d5d6b74915504a98a674cf..2e9d4fe86b34c64731728882db7c81e3871d7d07 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h -@@ -41,7 +41,7 @@ - # include - #endif - --#include -+#include "../libotp/otp_token.h" - - #include - #include -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -index 1f595d01d986ca2950672d796d62f5f78b05c212..1dff6db1a8cfcc295ba43d1c29d8887e3cf37fec 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -@@ -1140,11 +1140,11 @@ done: - static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry, - struct berval *creds) - { -- struct otptoken **tokens = NULL; -+ struct otp_token **tokens = NULL; - bool success = false; - - /* Find all of the user's active tokens. */ -- tokens = otptoken_find(ipapwd_plugin_id, dn, NULL, true, NULL); -+ tokens = otp_token_find(ipapwd_plugin_id, dn, NULL, true, NULL); - if (tokens == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME, - "%s: can't find tokens for '%s'.\n", __func__, dn); -@@ -1157,12 +1157,12 @@ static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry, - /* Loop through each token. */ - for (int i = 0; tokens[i] && !success; i++) { - /* Attempt authentication. */ -- success = otptoken_validate_berval(tokens[i], OTP_VALIDATE_STEPS, -+ success = otp_token_validate_berval(tokens[i], OTP_VALIDATE_STEPS, - creds, true); - - /* Truncate the password to remove the OTP code at the end. */ - if (success) { -- creds->bv_len -= otptoken_get_digits(tokens[i]); -+ creds->bv_len -= otp_token_get_digits(tokens[i]); - creds->bv_val[creds->bv_len] = '\0'; - } - -@@ -1170,10 +1170,10 @@ static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry, - "%s: token authentication %s " - "(user: '%s', token: '%s\').\n", __func__, - success ? "succeeded" : "failed", dn, -- slapi_sdn_get_ndn(otptoken_get_sdn(tokens[i]))); -+ slapi_sdn_get_ndn(otp_token_get_sdn(tokens[i]))); - } - -- otptoken_free_array(tokens); -+ otp_token_free_array(tokens); - return success; - } - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -index cbb4536e7d119f4550e4b523eb02e34d058ae7a1..10c49b724ee276d2b1fb89891a6eb4ee8eaa8fab 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -@@ -37,8 +37,7 @@ - * All rights reserved. - * END COPYRIGHT BLOCK **/ - -- --#include -+#include "../libotp/otp_token.h" - #include "syncreq.h" - - #define OTP_SYNC_MAX_STEPS 25 -@@ -56,7 +55,7 @@ bool sync_request_present(Slapi_PBlock *pb) - bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, - const char *user_dn) - { -- struct otptoken **tokens = NULL; -+ struct otp_token **tokens = NULL; - LDAPControl **controls = NULL; - struct berval *second = NULL; - struct berval *first = NULL; -@@ -91,10 +90,10 @@ bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, - /* Process the synchronization. */ - success = false; - if (ber_scanf(ber, "}") != LBER_ERROR) { -- tokens = otptoken_find(plugin_id, user_dn, token_dn, true, NULL); -+ tokens = otp_token_find(plugin_id, user_dn, token_dn, true, NULL); - if (tokens != NULL) { -- success = otptoken_sync_berval(tokens, OTP_SYNC_MAX_STEPS, first, second); -- otptoken_free_array(tokens); -+ success = otp_token_sync_berval(tokens, OTP_SYNC_MAX_STEPS, first, second); -+ otp_token_free_array(tokens); - } - } - -diff --git a/daemons/ipa-slapi-plugins/libotp/Makefile.am b/daemons/ipa-slapi-plugins/libotp/Makefile.am -index 6aa60c56a2293916ba7c1d773968055c3f94a4fe..012c8339199af5f63e6434b94109af2d93a38b45 100644 ---- a/daemons/ipa-slapi-plugins/libotp/Makefile.am -+++ b/daemons/ipa-slapi-plugins/libotp/Makefile.am -@@ -1,9 +1,11 @@ - MAINTAINERCLEANFILES = *~ Makefile.in - AM_CPPFLAGS = -I/usr/include/dirsrv - --noinst_LTLIBRARIES = librfc.la libotp.la --libotp_la_LIBADD = librfc.la -+noinst_LTLIBRARIES = libhotp.la libotp.la -+libhotp_la_SOURCES = hotp.c hotp.h -+libotp_la_SOURCES = otp_token.c otp_token.h -+libotp_la_LIBADD = libhotp.la - --check_PROGRAMS = t_librfc -+check_PROGRAMS = t_hotp - TESTS = $(check_PROGRAMS) --t_librfc_LDADD = $(NSPR_LIBS) $(NSS_LIBS) librfc.la -+t_hotp_LDADD = $(NSPR_LIBS) $(NSS_LIBS) libhotp.la -diff --git a/daemons/ipa-slapi-plugins/libotp/hotp.c b/daemons/ipa-slapi-plugins/libotp/hotp.c -new file mode 100644 -index 0000000000000000000000000000000000000000..619bc63ab1bee99d71c2f0fb887809762107c94c ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/hotp.c -@@ -0,0 +1,170 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2013 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+/* -+ * This file contains an implementation of HOTP (RFC 4226) and TOTP (RFC 6238). -+ * For details of how these algorithms work, please see the relevant RFCs. -+ */ -+ -+#include "hotp.h" -+#include -+ -+#include -+#include -+#include -+#include -+ -+struct digest_buffer { -+ uint8_t buf[SHA512_LENGTH]; -+ unsigned int len; -+}; -+ -+static const struct { -+ const char *algo; -+ CK_MECHANISM_TYPE mech; -+} algo2mech[] = { -+ { "sha1", CKM_SHA_1_HMAC }, -+ { "sha256", CKM_SHA256_HMAC }, -+ { "sha384", CKM_SHA384_HMAC }, -+ { "sha512", CKM_SHA512_HMAC }, -+ { } -+}; -+ -+/* -+ * This code is mostly cargo-cult taken from here: -+ * http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn5.html -+ * -+ * It should implement HMAC with the given mechanism (SHA: 1, 256, 384, 512). -+ */ -+static bool hmac(SECItem *key, CK_MECHANISM_TYPE mech, const SECItem *in, -+ struct digest_buffer *out) -+{ -+ SECItem param = { siBuffer, NULL, 0 }; -+ PK11SlotInfo *slot = NULL; -+ PK11SymKey *symkey = NULL; -+ PK11Context *ctx = NULL; -+ bool ret = false; -+ SECStatus s; -+ -+ slot = PK11_GetBestSlot(mech, NULL); -+ if (slot == NULL) { -+ slot = PK11_GetInternalKeySlot(); -+ if (slot == NULL) { -+ goto done; -+ } -+ } -+ -+ symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, -+ CKA_SIGN, key, NULL); -+ if (symkey == NULL) -+ goto done; -+ -+ ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, symkey, ¶m); -+ if (ctx == NULL) -+ goto done; -+ -+ s = PK11_DigestBegin(ctx); -+ if (s != SECSuccess) -+ goto done; -+ -+ s = PK11_DigestOp(ctx, in->data, in->len); -+ if (s != SECSuccess) -+ goto done; -+ -+ s = PK11_DigestFinal(ctx, out->buf, &out->len, sizeof(out->buf)); -+ if (s != SECSuccess) -+ goto done; -+ -+ ret = true; -+ -+done: -+ if (ctx != NULL) -+ PK11_DestroyContext(ctx, PR_TRUE); -+ if (symkey != NULL) -+ PK11_FreeSymKey(symkey); -+ if (slot != NULL) -+ PK11_FreeSlot(slot); -+ return ret; -+} -+ -+/* -+ * An implementation of HOTP (RFC 4226). -+ */ -+bool hotp(const struct hotp_token *token, uint64_t counter, uint32_t *out) -+{ -+ const SECItem cntr = { siBuffer, (uint8_t *) &counter, sizeof(counter) }; -+ SECItem keyitm = { siBuffer, token->key.bytes, token->key.len }; -+ CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC; -+ PRUint64 offset, binary, div; -+ struct digest_buffer digest; -+ int digits = token->digits; -+ int i; -+ -+ /* Convert counter to network byte order. */ -+ counter = PR_htonll(counter); -+ -+ /* Find the mech. */ -+ for (i = 0; algo2mech[i].algo; i++) { -+ if (strcasecmp(algo2mech[i].algo, token->algo) == 0) { -+ mech = algo2mech[i].mech; -+ break; -+ } -+ } -+ -+ /* Create the digits divisor. */ -+ for (div = 1; digits > 0; digits--) { -+ div *= 10; -+ } -+ -+ /* Do the digest. */ -+ if (!hmac(&keyitm, mech, &cntr, &digest)) { -+ return false; -+ } -+ -+ /* Truncate. */ -+ offset = digest.buf[digest.len - 1] & 0xf; -+ binary = (digest.buf[offset + 0] & 0x7f) << 0x18; -+ binary |= (digest.buf[offset + 1] & 0xff) << 0x10; -+ binary |= (digest.buf[offset + 2] & 0xff) << 0x08; -+ binary |= (digest.buf[offset + 3] & 0xff) << 0x00; -+ binary = binary % div; -+ -+ *out = binary; -+ return true; -+} -diff --git a/daemons/ipa-slapi-plugins/libotp/hotp.h b/daemons/ipa-slapi-plugins/libotp/hotp.h -new file mode 100644 -index 0000000000000000000000000000000000000000..06ae1fdae86df4ab124839cd62b61d99d908789a ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/hotp.h -@@ -0,0 +1,60 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2013 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+#pragma once -+ -+#include -+#include -+#include -+ -+struct hotp_token_key { -+ uint8_t *bytes; -+ size_t len; -+}; -+ -+struct hotp_token { -+ struct hotp_token_key key; -+ char *algo; -+ int digits; -+}; -+ -+/* -+ * An implementation of HOTP (RFC 4226). -+ */ -+bool hotp(const struct hotp_token *token, uint64_t counter, uint32_t *out); -diff --git a/daemons/ipa-slapi-plugins/libotp/libotp.c b/daemons/ipa-slapi-plugins/libotp/libotp.c -deleted file mode 100644 -index c65aef04348da5abdb1eeb6267e785f0342c7d51..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/libotp/libotp.c -+++ /dev/null -@@ -1,573 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2013 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- --#include "libotp.h" --#include "librfc.h" -- --#include --#include -- --#define TOKEN(s) "ipaToken" s --#define O(s) TOKEN("OTP" s) --#define T(s) TOKEN("TOTP" s) --#define H(s) TOKEN("HOTP" s) -- --#define IPA_OTP_DEFAULT_TOKEN_STEP 30 --#define IPA_OTP_OBJCLS_FILTER \ -- "(|(objectClass=ipaTokenTOTP)(objectClass=ipaTokenHOTP))" -- -- --enum otptoken_type { -- OTPTOKEN_NONE = 0, -- OTPTOKEN_TOTP, -- OTPTOKEN_HOTP, --}; -- --struct otptoken { -- Slapi_ComponentId *plugin_id; -- Slapi_DN *sdn; -- struct hotp_token token; -- enum otptoken_type type; -- union { -- struct { -- uint64_t watermark; -- unsigned int step; -- int offset; -- } totp; -- struct { -- uint64_t counter; -- } hotp; -- }; --}; -- --static const char *get_basedn(Slapi_DN *dn) --{ -- Slapi_DN *suffix = NULL; -- void *node = NULL; -- -- for (suffix = slapi_get_first_suffix(&node, 0); -- suffix != NULL; -- suffix = slapi_get_next_suffix(&node, 0)) { -- if (slapi_sdn_issuffix(dn, suffix)) -- return (char *) slapi_sdn_get_dn(suffix); -- } -- -- return NULL; --} -- --static inline bool is_algo_valid(const char *algo) --{ -- static const char *valid_algos[] = { "sha1", "sha256", "sha384", -- "sha512", NULL }; -- int i, ret; -- -- for (i = 0; valid_algos[i]; i++) { -- ret = strcasecmp(algo, valid_algos[i]); -- if (ret == 0) -- return true; -- } -- -- return false; --} -- --static const struct berval *entry_attr_get_berval(const Slapi_Entry* e, -- const char *type) --{ -- Slapi_Attr* attr = NULL; -- Slapi_Value *v; -- int ret; -- -- ret = slapi_entry_attr_find(e, type, &attr); -- if (ret != 0 || attr == NULL) -- return NULL; -- -- ret = slapi_attr_first_value(attr, &v); -- if (ret < 0) -- return NULL; -- -- return slapi_value_get_berval(v); --} -- --static bool writeattr(const struct otptoken *token, const char *attr, -- long long val) --{ -- Slapi_PBlock *pb = NULL; -- bool success = false; -- char value[32]; -- int ret; -- -- LDAPMod *mods[] = { -- &(LDAPMod) { -- LDAP_MOD_REPLACE, (char *) attr, -- .mod_values = (char *[]) { value, NULL } -- }, -- NULL -- }; -- -- snprintf(value, sizeof(value), "%lld", val); -- -- pb = slapi_pblock_new(); -- slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), -- mods, NULL, NULL, token->plugin_id, 0); -- if (slapi_modify_internal_pb(pb) != 0) -- goto error; -- if (slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret) != 0) -- goto error; -- if (ret != LDAP_SUCCESS) -- goto error; -- -- success = true; -- --error: -- slapi_pblock_destroy(pb); -- return success; --} -- --/** -- * Validate a token. -- * -- * If the second token code is specified, perform synchronization. -- */ --static bool validate(struct otptoken *token, time_t now, ssize_t step, -- uint32_t first, const uint32_t *second) --{ -- const char *attr; -- uint32_t tmp; -- -- /* Calculate the absolute step. */ -- switch (token->type) { -- case OTPTOKEN_TOTP: -- attr = T("watermark"); -- step = (now + token->totp.offset) / token->totp.step + step; -- if (token->totp.watermark > 0 && step < token->totp.watermark) -- return false; -- break; -- case OTPTOKEN_HOTP: -- if (step < 0) /* NEVER go backwards! */ -- return false; -- attr = H("counter"); -- step = token->hotp.counter + step; -- break; -- default: -- return false; -- } -- -- /* Validate the first code. */ -- if (!hotp(&token->token, step++, &tmp)) -- return false; -- -- if (first != tmp) -- return false; -- -- /* Validate the second code if specified. */ -- if (second != NULL) { -- if (!hotp(&token->token, step++, &tmp)) -- return false; -- -- if (*second != tmp) -- return false; -- } -- -- /* Write the step value. */ -- if (!writeattr(token, attr, step)) -- return false; -- -- /* Save our modifications to the object. */ -- switch (token->type) { -- case OTPTOKEN_TOTP: -- /* Perform optional synchronization steps. */ -- if (second != NULL) { -- tmp = (step - now / token->totp.step) * token->totp.step; -- if (!writeattr(token, T("clockOffset"), tmp)) -- return false; -- token->totp.offset = tmp; -- } -- token->totp.watermark = step; -- break; -- case OTPTOKEN_HOTP: -- token->hotp.counter = step; -- break; -- default: -- break; -- } -- -- return true; --} -- -- --static void otptoken_free(struct otptoken *token) --{ -- if (token == NULL) -- return; -- -- slapi_sdn_free(&token->sdn); -- free(token->token.key.bytes); -- slapi_ch_free_string(&token->token.algo); -- free(token); --} -- --void otptoken_free_array(struct otptoken **tokens) --{ -- if (tokens == NULL) -- return; -- -- for (size_t i = 0; tokens[i] != NULL; i++) -- otptoken_free(tokens[i]); -- -- free(tokens); --} -- --static struct otptoken *otptoken_new(Slapi_ComponentId *id, Slapi_Entry *entry) --{ -- const struct berval *tmp; -- struct otptoken *token; -- char **vals; -- -- token = calloc(1, sizeof(struct otptoken)); -- if (token == NULL) -- return NULL; -- token->plugin_id = id; -- -- /* Get the token type. */ -- vals = slapi_entry_attr_get_charray(entry, "objectClass"); -- if (vals == NULL) -- goto error; -- token->type = OTPTOKEN_NONE; -- for (int i = 0; vals[i] != NULL; i++) { -- if (strcasecmp(vals[i], "ipaTokenTOTP") == 0) -- token->type = OTPTOKEN_TOTP; -- else if (strcasecmp(vals[i], "ipaTokenHOTP") == 0) -- token->type = OTPTOKEN_HOTP; -- } -- slapi_ch_array_free(vals); -- if (token->type == OTPTOKEN_NONE) -- goto error; -- -- /* Get SDN. */ -- token->sdn = slapi_sdn_dup(slapi_entry_get_sdn(entry)); -- if (token->sdn == NULL) -- goto error; -- -- /* Get key. */ -- tmp = entry_attr_get_berval(entry, O("key")); -- if (tmp == NULL) -- goto error; -- token->token.key.len = tmp->bv_len; -- token->token.key.bytes = malloc(token->token.key.len); -- if (token->token.key.bytes == NULL) -- goto error; -- memcpy(token->token.key.bytes, tmp->bv_val, token->token.key.len); -- -- /* Get length. */ -- token->token.digits = slapi_entry_attr_get_int(entry, O("digits")); -- if (token->token.digits != 6 && token->token.digits != 8) -- goto error; -- -- /* Get algorithm. */ -- token->token.algo = slapi_entry_attr_get_charptr(entry, O("algorithm")); -- if (token->token.algo == NULL) -- token->token.algo = slapi_ch_strdup("sha1"); -- if (!is_algo_valid(token->token.algo)) -- goto error; -- -- switch (token->type) { -- case OTPTOKEN_TOTP: -- /* Get offset. */ -- token->totp.offset = slapi_entry_attr_get_int(entry, T("clockOffset")); -- -- /* Get watermark. */ -- token->totp.watermark = slapi_entry_attr_get_int(entry, T("watermark")); -- -- /* Get step. */ -- token->totp.step = slapi_entry_attr_get_uint(entry, T("timeStep")); -- if (token->totp.step == 0) -- token->totp.step = IPA_OTP_DEFAULT_TOKEN_STEP; -- break; -- case OTPTOKEN_HOTP: -- /* Get counter. */ -- token->hotp.counter = slapi_entry_attr_get_int(entry, H("counter")); -- break; -- default: -- break; -- } -- -- return token; -- --error: -- otptoken_free(token); -- return NULL; --} -- --static struct otptoken **find(Slapi_ComponentId *id, const char *user_dn, -- const char *token_dn, const char *intfilter, -- const char *extfilter) --{ -- struct otptoken **tokens = NULL; -- Slapi_Entry **entries = NULL; -- Slapi_PBlock *pb = NULL; -- Slapi_DN *sdn = NULL; -- char *filter = NULL; -- const char *basedn = NULL; -- size_t count = 0; -- int result = -1; -- -- if (intfilter == NULL) -- intfilter = ""; -- -- if (extfilter == NULL) -- extfilter = ""; -- -- /* Create the filter. */ -- if (user_dn == NULL) { -- filter = "(&" IPA_OTP_OBJCLS_FILTER "%s%s)"; -- filter = slapi_filter_sprintf(filter, intfilter, extfilter); -- } else { -- filter = "(&" IPA_OTP_OBJCLS_FILTER "(ipatokenOwner=%s%s)%s%s)"; -- filter = slapi_filter_sprintf(filter, ESC_AND_NORM_NEXT_VAL, -- user_dn, intfilter, extfilter); -- } -- -- /* Create the search. */ -- pb = slapi_pblock_new(); -- if (token_dn != NULL) { -- /* Find only the token specified. */ -- slapi_search_internal_set_pb(pb, token_dn, LDAP_SCOPE_BASE, filter, -- NULL, 0, NULL, NULL, id, 0); -- } else { -- sdn = slapi_sdn_new_dn_byval(user_dn); -- if (sdn == NULL) -- goto error; -- -- basedn = get_basedn(sdn); -- if (basedn == NULL) -- goto error; -- -- /* Find all user tokens. */ -- slapi_search_internal_set_pb(pb, basedn, -- LDAP_SCOPE_SUBTREE, filter, NULL, -- 0, NULL, NULL, id, 0); -- } -- slapi_search_internal_pb(pb); -- slapi_ch_free_string(&filter); -- -- /* Get the results. */ -- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result); -- if (result != LDAP_SUCCESS) -- goto error; -- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); -- if (entries == NULL) -- goto error; -- -- /* TODO: Can I get the count another way? */ -- for (count = 0; entries[count] != NULL; count++) -- continue; -- -- /* Create the array. */ -- tokens = calloc(count + 1, sizeof(*tokens)); -- if (tokens == NULL) -- goto error; -- for (count = 0; entries[count] != NULL; count++) { -- tokens[count] = otptoken_new(id, entries[count]); -- if (tokens[count] == NULL) { -- otptoken_free_array(tokens); -- tokens = NULL; -- goto error; -- } -- } -- --error: -- if (sdn != NULL) -- slapi_sdn_free(&sdn); -- slapi_pblock_destroy(pb); -- return tokens; --} -- --struct otptoken **otptoken_find(Slapi_ComponentId *id, const char *user_dn, -- const char *token_dn, bool active, -- const char *filter) --{ -- static const char template[] = -- "(|(ipatokenNotBefore<=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotBefore=*)))" -- "(|(ipatokenNotAfter>=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotAfter=*)))" -- "(|(ipatokenDisabled=FALSE)(!(ipatokenDisabled=*)))"; -- char actfilt[sizeof(template)]; -- struct tm tm; -- time_t now; -- -- if (!active) -- return find(id, user_dn, token_dn, NULL, filter); -- -- /* Get the current time. */ -- if (time(&now) == (time_t) -1) -- return NULL; -- if (gmtime_r(&now, &tm) == NULL) -- return NULL; -- -- /* Get the current time string. */ -- if (snprintf(actfilt, sizeof(actfilt), template, -- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -- tm.tm_hour, tm.tm_min, tm.tm_sec, -- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -- tm.tm_hour, tm.tm_min, tm.tm_sec) < 0) -- return NULL; -- -- return find(id, user_dn, token_dn, actfilt, filter); --} -- --int otptoken_get_digits(struct otptoken *token) --{ -- return token == NULL ? 0 : token->token.digits; --} -- --const Slapi_DN *otptoken_get_sdn(struct otptoken *token) --{ -- return token->sdn; --} -- --static bool otptoken_validate(struct otptoken *token, size_t steps, -- uint32_t code) --{ -- time_t now = 0; -- -- if (token == NULL) -- return false; -- -- /* We only need the local time for time-based tokens. */ -- if (token->type == OTPTOKEN_TOTP && time(&now) == (time_t) -1) -- return false; -- -- for (int i = 0; i <= steps; i++) { -- /* Validate the positive step. */ -- if (validate(token, now, i, code, NULL)) -- return true; -- -- /* Validate the negative step. */ -- if (validate(token, now, 0 - i, code, NULL)) -- return true; -- } -- -- return false; --} -- -- --/* -- * Convert code berval to decimal. -- * -- * NOTE: We can't use atol() or strtoul() because: -- * 1. If we have leading zeros, atol() fails. -- * 2. Neither support limiting conversion by length. -- */ --static bool bvtod(const struct berval *code, uint32_t *out) --{ -- *out = 0; -- -- for (ber_len_t i = 0; i < code->bv_len; i++) { -- if (code->bv_val[i] < '0' || code->bv_val[i] > '9') -- return false; -- *out *= 10; -- *out += code->bv_val[i] - '0'; -- } -- -- return code->bv_len != 0; --} -- --bool otptoken_validate_berval(struct otptoken *token, size_t steps, -- const struct berval *code, bool tail) --{ -- struct berval tmp; -- uint32_t otp; -- -- if (token == NULL || code == NULL) -- return false; -- tmp = *code; -- -- if (tmp.bv_len < token->token.digits) -- return false; -- -- if (tail) -- tmp.bv_val = &tmp.bv_val[tmp.bv_len - token->token.digits]; -- tmp.bv_len = token->token.digits; -- -- if (!bvtod(&tmp, &otp)) -- return false; -- -- return otptoken_validate(token, steps, otp); --} -- --static bool otptoken_sync(struct otptoken * const *tokens, size_t steps, -- uint32_t first_code, uint32_t second_code) --{ -- time_t now = 0; -- -- if (tokens == NULL) -- return false; -- -- if (time(&now) == (time_t) -1) -- return false; -- -- for (int i = 0; i <= steps; i++) { -- for (int j = 0; tokens[j] != NULL; j++) { -- /* Validate the positive step. */ -- if (validate(tokens[j], now, i, first_code, &second_code)) -- return true; -- -- /* Validate the negative step. */ -- if (validate(tokens[j], now, 0 - i, first_code, &second_code)) -- return true; -- } -- } -- -- return false; --} -- --bool otptoken_sync_berval(struct otptoken * const *tokens, size_t steps, -- const struct berval *first_code, -- const struct berval *second_code) --{ -- uint32_t second = 0; -- uint32_t first = 0; -- -- if (!bvtod(first_code, &first)) -- return false; -- -- if (!bvtod(second_code, &second)) -- return false; -- -- return otptoken_sync(tokens, steps, first, second); --} -diff --git a/daemons/ipa-slapi-plugins/libotp/libotp.h b/daemons/ipa-slapi-plugins/libotp/libotp.h -deleted file mode 100644 -index 24915f8667dfa13ffb1ae47d223df95d4622012e..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/libotp/libotp.h -+++ /dev/null -@@ -1,93 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2013 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- --#ifndef LIBOTP_H_ --#define LIBOTP_H_ -- --#ifdef HAVE_CONFIG_H --# include --#endif -- --#include --#include --#include -- --struct otptoken; -- --/* Frees the token array. */ --void otptoken_free_array(struct otptoken **tokens); -- --/* Find tokens. -- * -- * All criteria below are cumulative. For example, if you specify both dn and -- * active and the token at the dn specified isn't active, an empty array will -- * be returned. -- * -- * If user_dn is not NULL, the user's tokens are returned. -- * -- * If token_dn is not NULL, only this specified token is returned. -- * -- * If active is true, only tokens that are active are returned. -- * -- * If filter is not NULL, the filter will be added to the search criteria. -- * -- * Returns NULL on error. If no tokens are found, an empty array is returned. -- * The array is NULL terminated. -- */ --struct otptoken **otptoken_find(Slapi_ComponentId *id, const char *user_dn, -- const char *token_dn, bool active, -- const char *filter); -- --/* Get the length of the token code. */ --int otptoken_get_digits(struct otptoken *token); -- --/* Get the SDN of the token. */ --const Slapi_DN *otptoken_get_sdn(struct otptoken *token); -- --/* Validate the token code within a range of steps. If tail is true, -- * it will be assumed that the token is specified at the end of the string. */ --bool otptoken_validate_berval(struct otptoken *token, size_t steps, -- const struct berval *code, bool tail); -- --/* Synchronize the token within a range of steps. */ --bool otptoken_sync_berval(struct otptoken * const *tokens, size_t steps, -- const struct berval *first_code, -- const struct berval *second_code); -- --#endif /* LIBOTP_H_ */ -diff --git a/daemons/ipa-slapi-plugins/libotp/librfc.c b/daemons/ipa-slapi-plugins/libotp/librfc.c -deleted file mode 100644 -index d74820e957e3753834f376cd3ea0ae748e450243..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/libotp/librfc.c -+++ /dev/null -@@ -1,170 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2013 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- --/* -- * This file contains an implementation of HOTP (RFC 4226) and TOTP (RFC 6238). -- * For details of how these algorithms work, please see the relevant RFCs. -- */ -- --#include "librfc.h" --#include -- --#include --#include --#include --#include -- --struct digest_buffer { -- uint8_t buf[SHA512_LENGTH]; -- unsigned int len; --}; -- --static const struct { -- const char *algo; -- CK_MECHANISM_TYPE mech; --} algo2mech[] = { -- { "sha1", CKM_SHA_1_HMAC }, -- { "sha256", CKM_SHA256_HMAC }, -- { "sha384", CKM_SHA384_HMAC }, -- { "sha512", CKM_SHA512_HMAC }, -- { } --}; -- --/* -- * This code is mostly cargo-cult taken from here: -- * http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn5.html -- * -- * It should implement HMAC with the given mechanism (SHA: 1, 256, 384, 512). -- */ --static bool hmac(SECItem *key, CK_MECHANISM_TYPE mech, const SECItem *in, -- struct digest_buffer *out) --{ -- SECItem param = { siBuffer, NULL, 0 }; -- PK11SlotInfo *slot = NULL; -- PK11SymKey *symkey = NULL; -- PK11Context *ctx = NULL; -- bool ret = false; -- SECStatus s; -- -- slot = PK11_GetBestSlot(mech, NULL); -- if (slot == NULL) { -- slot = PK11_GetInternalKeySlot(); -- if (slot == NULL) { -- goto done; -- } -- } -- -- symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, -- CKA_SIGN, key, NULL); -- if (symkey == NULL) -- goto done; -- -- ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, symkey, ¶m); -- if (ctx == NULL) -- goto done; -- -- s = PK11_DigestBegin(ctx); -- if (s != SECSuccess) -- goto done; -- -- s = PK11_DigestOp(ctx, in->data, in->len); -- if (s != SECSuccess) -- goto done; -- -- s = PK11_DigestFinal(ctx, out->buf, &out->len, sizeof(out->buf)); -- if (s != SECSuccess) -- goto done; -- -- ret = true; -- --done: -- if (ctx != NULL) -- PK11_DestroyContext(ctx, PR_TRUE); -- if (symkey != NULL) -- PK11_FreeSymKey(symkey); -- if (slot != NULL) -- PK11_FreeSlot(slot); -- return ret; --} -- --/* -- * An implementation of HOTP (RFC 4226). -- */ --bool hotp(const struct hotp_token *token, uint64_t counter, uint32_t *out) --{ -- const SECItem cntr = { siBuffer, (uint8_t *) &counter, sizeof(counter) }; -- SECItem keyitm = { siBuffer, token->key.bytes, token->key.len }; -- CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC; -- PRUint64 offset, binary, div; -- struct digest_buffer digest; -- int digits = token->digits; -- int i; -- -- /* Convert counter to network byte order. */ -- counter = PR_htonll(counter); -- -- /* Find the mech. */ -- for (i = 0; algo2mech[i].algo; i++) { -- if (strcasecmp(algo2mech[i].algo, token->algo) == 0) { -- mech = algo2mech[i].mech; -- break; -- } -- } -- -- /* Create the digits divisor. */ -- for (div = 1; digits > 0; digits--) { -- div *= 10; -- } -- -- /* Do the digest. */ -- if (!hmac(&keyitm, mech, &cntr, &digest)) { -- return false; -- } -- -- /* Truncate. */ -- offset = digest.buf[digest.len - 1] & 0xf; -- binary = (digest.buf[offset + 0] & 0x7f) << 0x18; -- binary |= (digest.buf[offset + 1] & 0xff) << 0x10; -- binary |= (digest.buf[offset + 2] & 0xff) << 0x08; -- binary |= (digest.buf[offset + 3] & 0xff) << 0x00; -- binary = binary % div; -- -- *out = binary; -- return true; --} -diff --git a/daemons/ipa-slapi-plugins/libotp/librfc.h b/daemons/ipa-slapi-plugins/libotp/librfc.h -deleted file mode 100644 -index 04b117600fbcb03fd61258afdd892ae3d514a121..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/libotp/librfc.h -+++ /dev/null -@@ -1,63 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2013 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- --#ifndef LIBRFC_H_ --#define LIBRFC_H_ -- --#include --#include --#include -- --struct hotp_token_key { -- uint8_t *bytes; -- size_t len; --}; -- --struct hotp_token { -- struct hotp_token_key key; -- char *algo; -- int digits; --}; -- --/* -- * An implementation of HOTP (RFC 4226). -- */ --bool hotp(const struct hotp_token *token, uint64_t counter, uint32_t *out); -- --#endif /* LIBRFC_H_ */ -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c -new file mode 100644 -index 0000000000000000000000000000000000000000..7860c8aba6e12e319d633ee8e165403289a7528b ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c -@@ -0,0 +1,572 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2013 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+#include "otp_token.h" -+#include "hotp.h" -+ -+#include -+#include -+ -+#define TOKEN(s) "ipaToken" s -+#define O(s) TOKEN("OTP" s) -+#define T(s) TOKEN("TOTP" s) -+#define H(s) TOKEN("HOTP" s) -+ -+#define IPA_OTP_DEFAULT_TOKEN_STEP 30 -+#define IPA_OTP_OBJCLS_FILTER \ -+ "(|(objectClass=ipaTokenTOTP)(objectClass=ipaTokenHOTP))" -+ -+enum type { -+ TYPE_NONE = 0, -+ TYPE_TOTP, -+ TYPE_HOTP, -+}; -+ -+struct otp_token { -+ Slapi_ComponentId *plugin_id; -+ Slapi_DN *sdn; -+ struct hotp_token token; -+ enum type type; -+ union { -+ struct { -+ uint64_t watermark; -+ unsigned int step; -+ int offset; -+ } totp; -+ struct { -+ uint64_t counter; -+ } hotp; -+ }; -+}; -+ -+static const char *get_basedn(Slapi_DN *dn) -+{ -+ Slapi_DN *suffix = NULL; -+ void *node = NULL; -+ -+ for (suffix = slapi_get_first_suffix(&node, 0); -+ suffix != NULL; -+ suffix = slapi_get_next_suffix(&node, 0)) { -+ if (slapi_sdn_issuffix(dn, suffix)) -+ return (char *) slapi_sdn_get_dn(suffix); -+ } -+ -+ return NULL; -+} -+ -+static inline bool is_algo_valid(const char *algo) -+{ -+ static const char *valid_algos[] = { "sha1", "sha256", "sha384", -+ "sha512", NULL }; -+ int i, ret; -+ -+ for (i = 0; valid_algos[i]; i++) { -+ ret = strcasecmp(algo, valid_algos[i]); -+ if (ret == 0) -+ return true; -+ } -+ -+ return false; -+} -+ -+static const struct berval *entry_attr_get_berval(const Slapi_Entry* e, -+ const char *type) -+{ -+ Slapi_Attr* attr = NULL; -+ Slapi_Value *v; -+ int ret; -+ -+ ret = slapi_entry_attr_find(e, type, &attr); -+ if (ret != 0 || attr == NULL) -+ return NULL; -+ -+ ret = slapi_attr_first_value(attr, &v); -+ if (ret < 0) -+ return NULL; -+ -+ return slapi_value_get_berval(v); -+} -+ -+static bool writeattr(const struct otp_token *token, const char *attr, -+ long long val) -+{ -+ Slapi_PBlock *pb = NULL; -+ bool success = false; -+ char value[32]; -+ int ret; -+ -+ LDAPMod *mods[] = { -+ &(LDAPMod) { -+ LDAP_MOD_REPLACE, (char *) attr, -+ .mod_values = (char *[]) { value, NULL } -+ }, -+ NULL -+ }; -+ -+ snprintf(value, sizeof(value), "%lld", val); -+ -+ pb = slapi_pblock_new(); -+ slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), -+ mods, NULL, NULL, token->plugin_id, 0); -+ if (slapi_modify_internal_pb(pb) != 0) -+ goto error; -+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret) != 0) -+ goto error; -+ if (ret != LDAP_SUCCESS) -+ goto error; -+ -+ success = true; -+ -+error: -+ slapi_pblock_destroy(pb); -+ return success; -+} -+ -+/** -+ * Validate a token. -+ * -+ * If the second token code is specified, perform synchronization. -+ */ -+static bool validate(struct otp_token *token, time_t now, ssize_t step, -+ uint32_t first, const uint32_t *second) -+{ -+ const char *attr; -+ uint32_t tmp; -+ -+ /* Calculate the absolute step. */ -+ switch (token->type) { -+ case TYPE_TOTP: -+ attr = T("watermark"); -+ step = (now + token->totp.offset) / token->totp.step + step; -+ if (token->totp.watermark > 0 && step < token->totp.watermark) -+ return false; -+ break; -+ case TYPE_HOTP: -+ if (step < 0) /* NEVER go backwards! */ -+ return false; -+ attr = H("counter"); -+ step = token->hotp.counter + step; -+ break; -+ default: -+ return false; -+ } -+ -+ /* Validate the first code. */ -+ if (!hotp(&token->token, step++, &tmp)) -+ return false; -+ -+ if (first != tmp) -+ return false; -+ -+ /* Validate the second code if specified. */ -+ if (second != NULL) { -+ if (!hotp(&token->token, step++, &tmp)) -+ return false; -+ -+ if (*second != tmp) -+ return false; -+ } -+ -+ /* Write the step value. */ -+ if (!writeattr(token, attr, step)) -+ return false; -+ -+ /* Save our modifications to the object. */ -+ switch (token->type) { -+ case TYPE_TOTP: -+ /* Perform optional synchronization steps. */ -+ if (second != NULL) { -+ tmp = (step - now / token->totp.step) * token->totp.step; -+ if (!writeattr(token, T("clockOffset"), tmp)) -+ return false; -+ token->totp.offset = tmp; -+ } -+ token->totp.watermark = step; -+ break; -+ case TYPE_HOTP: -+ token->hotp.counter = step; -+ break; -+ default: -+ break; -+ } -+ -+ return true; -+} -+ -+static void otp_token_free(struct otp_token *token) -+{ -+ if (token == NULL) -+ return; -+ -+ slapi_sdn_free(&token->sdn); -+ free(token->token.key.bytes); -+ slapi_ch_free_string(&token->token.algo); -+ free(token); -+} -+ -+void otp_token_free_array(struct otp_token **tokens) -+{ -+ if (tokens == NULL) -+ return; -+ -+ for (size_t i = 0; tokens[i] != NULL; i++) -+ otp_token_free(tokens[i]); -+ -+ free(tokens); -+} -+ -+static struct otp_token *otp_token_new(Slapi_ComponentId *id, -+ Slapi_Entry *entry) -+{ -+ const struct berval *tmp; -+ struct otp_token *token; -+ char **vals; -+ -+ token = calloc(1, sizeof(struct otp_token)); -+ if (token == NULL) -+ return NULL; -+ token->plugin_id = id; -+ -+ /* Get the token type. */ -+ vals = slapi_entry_attr_get_charray(entry, "objectClass"); -+ if (vals == NULL) -+ goto error; -+ token->type = TYPE_NONE; -+ for (int i = 0; vals[i] != NULL; i++) { -+ if (strcasecmp(vals[i], "ipaTokenTOTP") == 0) -+ token->type = TYPE_TOTP; -+ else if (strcasecmp(vals[i], "ipaTokenHOTP") == 0) -+ token->type = TYPE_HOTP; -+ } -+ slapi_ch_array_free(vals); -+ if (token->type == TYPE_NONE) -+ goto error; -+ -+ /* Get SDN. */ -+ token->sdn = slapi_sdn_dup(slapi_entry_get_sdn(entry)); -+ if (token->sdn == NULL) -+ goto error; -+ -+ /* Get key. */ -+ tmp = entry_attr_get_berval(entry, O("key")); -+ if (tmp == NULL) -+ goto error; -+ token->token.key.len = tmp->bv_len; -+ token->token.key.bytes = malloc(token->token.key.len); -+ if (token->token.key.bytes == NULL) -+ goto error; -+ memcpy(token->token.key.bytes, tmp->bv_val, token->token.key.len); -+ -+ /* Get length. */ -+ token->token.digits = slapi_entry_attr_get_int(entry, O("digits")); -+ if (token->token.digits != 6 && token->token.digits != 8) -+ goto error; -+ -+ /* Get algorithm. */ -+ token->token.algo = slapi_entry_attr_get_charptr(entry, O("algorithm")); -+ if (token->token.algo == NULL) -+ token->token.algo = slapi_ch_strdup("sha1"); -+ if (!is_algo_valid(token->token.algo)) -+ goto error; -+ -+ switch (token->type) { -+ case TYPE_TOTP: -+ /* Get offset. */ -+ token->totp.offset = slapi_entry_attr_get_int(entry, T("clockOffset")); -+ -+ /* Get watermark. */ -+ token->totp.watermark = slapi_entry_attr_get_int(entry, T("watermark")); -+ -+ /* Get step. */ -+ token->totp.step = slapi_entry_attr_get_uint(entry, T("timeStep")); -+ if (token->totp.step == 0) -+ token->totp.step = IPA_OTP_DEFAULT_TOKEN_STEP; -+ break; -+ case TYPE_HOTP: -+ /* Get counter. */ -+ token->hotp.counter = slapi_entry_attr_get_int(entry, H("counter")); -+ break; -+ default: -+ break; -+ } -+ -+ return token; -+ -+error: -+ otp_token_free(token); -+ return NULL; -+} -+ -+static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, -+ const char *token_dn, const char *intfilter, -+ const char *extfilter) -+{ -+ struct otp_token **tokens = NULL; -+ Slapi_Entry **entries = NULL; -+ Slapi_PBlock *pb = NULL; -+ Slapi_DN *sdn = NULL; -+ char *filter = NULL; -+ const char *basedn = NULL; -+ size_t count = 0; -+ int result = -1; -+ -+ if (intfilter == NULL) -+ intfilter = ""; -+ -+ if (extfilter == NULL) -+ extfilter = ""; -+ -+ /* Create the filter. */ -+ if (user_dn == NULL) { -+ filter = "(&" IPA_OTP_OBJCLS_FILTER "%s%s)"; -+ filter = slapi_filter_sprintf(filter, intfilter, extfilter); -+ } else { -+ filter = "(&" IPA_OTP_OBJCLS_FILTER "(ipatokenOwner=%s%s)%s%s)"; -+ filter = slapi_filter_sprintf(filter, ESC_AND_NORM_NEXT_VAL, -+ user_dn, intfilter, extfilter); -+ } -+ -+ /* Create the search. */ -+ pb = slapi_pblock_new(); -+ if (token_dn != NULL) { -+ /* Find only the token specified. */ -+ slapi_search_internal_set_pb(pb, token_dn, LDAP_SCOPE_BASE, filter, -+ NULL, 0, NULL, NULL, id, 0); -+ } else { -+ sdn = slapi_sdn_new_dn_byval(user_dn); -+ if (sdn == NULL) -+ goto error; -+ -+ basedn = get_basedn(sdn); -+ if (basedn == NULL) -+ goto error; -+ -+ /* Find all user tokens. */ -+ slapi_search_internal_set_pb(pb, basedn, -+ LDAP_SCOPE_SUBTREE, filter, NULL, -+ 0, NULL, NULL, id, 0); -+ } -+ slapi_search_internal_pb(pb); -+ slapi_ch_free_string(&filter); -+ -+ /* Get the results. */ -+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &result); -+ if (result != LDAP_SUCCESS) -+ goto error; -+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); -+ if (entries == NULL) -+ goto error; -+ -+ /* TODO: Can I get the count another way? */ -+ for (count = 0; entries[count] != NULL; count++) -+ continue; -+ -+ /* Create the array. */ -+ tokens = calloc(count + 1, sizeof(*tokens)); -+ if (tokens == NULL) -+ goto error; -+ for (count = 0; entries[count] != NULL; count++) { -+ tokens[count] = otp_token_new(id, entries[count]); -+ if (tokens[count] == NULL) { -+ otp_token_free_array(tokens); -+ tokens = NULL; -+ goto error; -+ } -+ } -+ -+error: -+ if (sdn != NULL) -+ slapi_sdn_free(&sdn); -+ slapi_pblock_destroy(pb); -+ return tokens; -+} -+ -+struct otp_token ** -+otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, -+ bool active, const char *filter) -+{ -+ static const char template[] = -+ "(|(ipatokenNotBefore<=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotBefore=*)))" -+ "(|(ipatokenNotAfter>=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotAfter=*)))" -+ "(|(ipatokenDisabled=FALSE)(!(ipatokenDisabled=*)))"; -+ char actfilt[sizeof(template)]; -+ struct tm tm; -+ time_t now; -+ -+ if (!active) -+ return find(id, user_dn, token_dn, NULL, filter); -+ -+ /* Get the current time. */ -+ if (time(&now) == (time_t) -1) -+ return NULL; -+ if (gmtime_r(&now, &tm) == NULL) -+ return NULL; -+ -+ /* Get the current time string. */ -+ if (snprintf(actfilt, sizeof(actfilt), template, -+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -+ tm.tm_hour, tm.tm_min, tm.tm_sec, -+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, -+ tm.tm_hour, tm.tm_min, tm.tm_sec) < 0) -+ return NULL; -+ -+ return find(id, user_dn, token_dn, actfilt, filter); -+} -+ -+int otp_token_get_digits(struct otp_token *token) -+{ -+ return token == NULL ? 0 : token->token.digits; -+} -+ -+const Slapi_DN *otp_token_get_sdn(struct otp_token *token) -+{ -+ return token->sdn; -+} -+ -+static bool otp_token_validate(struct otp_token *token, size_t steps, -+ uint32_t code) -+{ -+ time_t now = 0; -+ -+ if (token == NULL) -+ return false; -+ -+ /* We only need the local time for time-based tokens. */ -+ if (token->type == TYPE_TOTP && time(&now) == (time_t) -1) -+ return false; -+ -+ for (int i = 0; i <= steps; i++) { -+ /* Validate the positive step. */ -+ if (validate(token, now, i, code, NULL)) -+ return true; -+ -+ /* Validate the negative step. */ -+ if (validate(token, now, 0 - i, code, NULL)) -+ return true; -+ } -+ -+ return false; -+} -+ -+ -+/* -+ * Convert code berval to decimal. -+ * -+ * NOTE: We can't use atol() or strtoul() because: -+ * 1. If we have leading zeros, atol() fails. -+ * 2. Neither support limiting conversion by length. -+ */ -+static bool bvtod(const struct berval *code, uint32_t *out) -+{ -+ *out = 0; -+ -+ for (ber_len_t i = 0; i < code->bv_len; i++) { -+ if (code->bv_val[i] < '0' || code->bv_val[i] > '9') -+ return false; -+ *out *= 10; -+ *out += code->bv_val[i] - '0'; -+ } -+ -+ return code->bv_len != 0; -+} -+ -+bool otp_token_validate_berval(struct otp_token *token, size_t steps, -+ const struct berval *code, bool tail) -+{ -+ struct berval tmp; -+ uint32_t otp; -+ -+ if (token == NULL || code == NULL) -+ return false; -+ tmp = *code; -+ -+ if (tmp.bv_len < token->token.digits) -+ return false; -+ -+ if (tail) -+ tmp.bv_val = &tmp.bv_val[tmp.bv_len - token->token.digits]; -+ tmp.bv_len = token->token.digits; -+ -+ if (!bvtod(&tmp, &otp)) -+ return false; -+ -+ return otp_token_validate(token, steps, otp); -+} -+ -+static bool otp_token_sync(struct otp_token * const *tokens, size_t steps, -+ uint32_t first_code, uint32_t second_code) -+{ -+ time_t now = 0; -+ -+ if (tokens == NULL) -+ return false; -+ -+ if (time(&now) == (time_t) -1) -+ return false; -+ -+ for (int i = 0; i <= steps; i++) { -+ for (int j = 0; tokens[j] != NULL; j++) { -+ /* Validate the positive step. */ -+ if (validate(tokens[j], now, i, first_code, &second_code)) -+ return true; -+ -+ /* Validate the negative step. */ -+ if (validate(tokens[j], now, 0 - i, first_code, &second_code)) -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+bool otp_token_sync_berval(struct otp_token * const *tokens, size_t steps, -+ const struct berval *first_code, -+ const struct berval *second_code) -+{ -+ uint32_t second = 0; -+ uint32_t first = 0; -+ -+ if (!bvtod(first_code, &first)) -+ return false; -+ -+ if (!bvtod(second_code, &second)) -+ return false; -+ -+ return otp_token_sync(tokens, steps, first, second); -+} -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.h b/daemons/ipa-slapi-plugins/libotp/otp_token.h -new file mode 100644 -index 0000000000000000000000000000000000000000..2f336780682b5ea2838b558079e2ae85f6e2afba ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.h -@@ -0,0 +1,87 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2013 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+#pragma once -+ -+#include -+#include -+#include -+ -+struct otp_token; -+ -+/* Frees the token array. */ -+void otp_token_free_array(struct otp_token **tokens); -+ -+/* Find tokens. -+ * -+ * All criteria below are cumulative. For example, if you specify both dn and -+ * active and the token at the dn specified isn't active, an empty array will -+ * be returned. -+ * -+ * If user_dn is not NULL, the user's tokens are returned. -+ * -+ * If token_dn is not NULL, only this specified token is returned. -+ * -+ * If active is true, only tokens that are active are returned. -+ * -+ * If filter is not NULL, the filter will be added to the search criteria. -+ * -+ * Returns NULL on error. If no tokens are found, an empty array is returned. -+ * The array is NULL terminated. -+ */ -+struct otp_token **otp_token_find(Slapi_ComponentId *id, const char *user_dn, -+ const char *token_dn, bool active, -+ const char *filter); -+ -+/* Get the length of the token code. */ -+int otp_token_get_digits(struct otp_token *token); -+ -+/* Get the SDN of the token. */ -+const Slapi_DN *otp_token_get_sdn(struct otp_token *token); -+ -+/* Validate the token code within a range of steps. If tail is true, -+ * it will be assumed that the token is specified at the end of the string. */ -+bool otp_token_validate_berval(struct otp_token *token, size_t steps, -+ const struct berval *code, bool tail); -+ -+/* Synchronize the token within a range of steps. */ -+bool otp_token_sync_berval(struct otp_token * const *tokens, size_t steps, -+ const struct berval *first_code, -+ const struct berval *second_code); -+ -diff --git a/daemons/ipa-slapi-plugins/libotp/t_hotp.c b/daemons/ipa-slapi-plugins/libotp/t_hotp.c -new file mode 100644 -index 0000000000000000000000000000000000000000..2e995fdaa3b2aa067790ade307792a95ded269a9 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/t_hotp.c -@@ -0,0 +1,121 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2013 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+#include "hotp.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define KEY(s) { (uint8_t *) s, sizeof(s) - 1 } -+ -+/* All HOTP test examples from RFC 4226 (Appendix D). */ -+static const struct hotp_token hotp_token = { -+ KEY("12345678901234567890"), -+ "sha1", -+ 6 -+}; -+static const uint32_t hotp_answers[] = { -+ 755224, -+ 287082, -+ 359152, -+ 969429, -+ 338314, -+ 254676, -+ 287922, -+ 162583, -+ 399871, -+ 520489 -+}; -+ -+/* All TOTP test examples from RFC 6238 (Appendix B). */ -+#define SHA1 { KEY("12345678901234567890"), "sha1", 8 } -+#define SHA256 { KEY("12345678901234567890123456789012"), "sha256", 8 } -+#define SHA512 { KEY("12345678901234567890123456789012" \ -+ "34567890123456789012345678901234"), "sha512", 8 } -+static const struct { -+ struct hotp_token token; -+ time_t time; -+ uint32_t answer; -+} totp_tests[] = { -+ { SHA1, 59, 94287082 }, -+ { SHA256, 59, 46119246 }, -+ { SHA512, 59, 90693936 }, -+ { SHA1, 1111111109, 7081804 }, -+ { SHA256, 1111111109, 68084774 }, -+ { SHA512, 1111111109, 25091201 }, -+ { SHA1, 1111111111, 14050471 }, -+ { SHA256, 1111111111, 67062674 }, -+ { SHA512, 1111111111, 99943326 }, -+ { SHA1, 1234567890, 89005924 }, -+ { SHA256, 1234567890, 91819424 }, -+ { SHA512, 1234567890, 93441116 }, -+ { SHA1, 2000000000, 69279037 }, -+ { SHA256, 2000000000, 90698825 }, -+ { SHA512, 2000000000, 38618901 }, -+#ifdef _LP64 /* Only do these tests on 64-bit systems. */ -+ { SHA1, 20000000000, 65353130 }, -+ { SHA256, 20000000000, 77737706 }, -+ { SHA512, 20000000000, 47863826 }, -+#endif -+}; -+ -+int -+main(int argc, const char *argv[]) -+{ -+ uint32_t otp; -+ int i; -+ -+ NSS_NoDB_Init("."); -+ -+ for (i = 0; i < sizeof(hotp_answers) / sizeof(*hotp_answers); i++) { -+ assert(hotp(&hotp_token, i, &otp)); -+ assert(otp == hotp_answers[i]); -+ } -+ -+ for (i = 0; i < sizeof(totp_tests) / sizeof(*totp_tests); i++) { -+ assert(hotp(&totp_tests[i].token, totp_tests[i].time / 30, &otp)); -+ assert(otp == totp_tests[i].answer); -+ } -+ -+ NSS_Shutdown(); -+ return 0; -+} -diff --git a/daemons/ipa-slapi-plugins/libotp/t_librfc.c b/daemons/ipa-slapi-plugins/libotp/t_librfc.c -deleted file mode 100644 -index f7eab7f78e99a825a444f8e496be924342d28b51..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/libotp/t_librfc.c -+++ /dev/null -@@ -1,121 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2013 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- --#include "librfc.h" -- --#include --#include --#include --#include --#include -- --#define KEY(s) { (uint8_t *) s, sizeof(s) - 1 } -- --/* All HOTP test examples from RFC 4226 (Appendix D). */ --static const struct hotp_token hotp_token = { -- KEY("12345678901234567890"), -- "sha1", -- 6 --}; --static const uint32_t hotp_answers[] = { -- 755224, -- 287082, -- 359152, -- 969429, -- 338314, -- 254676, -- 287922, -- 162583, -- 399871, -- 520489 --}; -- --/* All TOTP test examples from RFC 6238 (Appendix B). */ --#define SHA1 { KEY("12345678901234567890"), "sha1", 8 } --#define SHA256 { KEY("12345678901234567890123456789012"), "sha256", 8 } --#define SHA512 { KEY("12345678901234567890123456789012" \ -- "34567890123456789012345678901234"), "sha512", 8 } --static const struct { -- struct hotp_token token; -- time_t time; -- uint32_t answer; --} totp_tests[] = { -- { SHA1, 59, 94287082 }, -- { SHA256, 59, 46119246 }, -- { SHA512, 59, 90693936 }, -- { SHA1, 1111111109, 7081804 }, -- { SHA256, 1111111109, 68084774 }, -- { SHA512, 1111111109, 25091201 }, -- { SHA1, 1111111111, 14050471 }, -- { SHA256, 1111111111, 67062674 }, -- { SHA512, 1111111111, 99943326 }, -- { SHA1, 1234567890, 89005924 }, -- { SHA256, 1234567890, 91819424 }, -- { SHA512, 1234567890, 93441116 }, -- { SHA1, 2000000000, 69279037 }, -- { SHA256, 2000000000, 90698825 }, -- { SHA512, 2000000000, 38618901 }, --#ifdef _LP64 /* Only do these tests on 64-bit systems. */ -- { SHA1, 20000000000, 65353130 }, -- { SHA256, 20000000000, 77737706 }, -- { SHA512, 20000000000, 47863826 }, --#endif --}; -- --int --main(int argc, const char *argv[]) --{ -- uint32_t otp; -- int i; -- -- NSS_NoDB_Init("."); -- -- for (i = 0; i < sizeof(hotp_answers) / sizeof(*hotp_answers); i++) { -- assert(hotp(&hotp_token, i, &otp)); -- assert(otp == hotp_answers[i]); -- } -- -- for (i = 0; i < sizeof(totp_tests) / sizeof(*totp_tests); i++) { -- assert(hotp(&totp_tests[i].token, totp_tests[i].time / 30, &otp)); -- assert(otp == totp_tests[i].answer); -- } -- -- NSS_Shutdown(); -- return 0; --} --- -2.1.0 - diff --git a/SOURCES/0070-baseldap-Allow-overriding-member-param-label-in-LDAP.patch b/SOURCES/0070-baseldap-Allow-overriding-member-param-label-in-LDAP.patch new file mode 100644 index 0000000..87b97f6 --- /dev/null +++ b/SOURCES/0070-baseldap-Allow-overriding-member-param-label-in-LDAP.patch @@ -0,0 +1,40 @@ +From 1dfdb32cbd73a3b1144645c0208fee88b3530172 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 17 Aug 2015 09:39:21 +0200 +Subject: [PATCH] baseldap: Allow overriding member param label in + LDAPModMember + +https://fedorahosted.org/freeipa/ticket/5214 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/baseldap.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py +index 36a5d5f4918828a97b0b30d4613819f777722de8..31f38946afcbb51638bcab68a6e74ec309eba0e4 100644 +--- a/ipalib/plugins/baseldap.py ++++ b/ipalib/plugins/baseldap.py +@@ -1652,6 +1652,7 @@ class LDAPModMember(LDAPQuery): + """ + member_attributes = ['member'] + member_param_doc = _('%s') ++ member_param_label = _('member %s') + member_count_out = ('%i member processed.', '%i members processed.') + + def get_options(self): +@@ -1662,9 +1663,9 @@ class LDAPModMember(LDAPQuery): + ldap_obj = self.api.Object[ldap_obj_name] + name = to_cli(ldap_obj_name) + doc = self.member_param_doc % ldap_obj.object_name_plural ++ label = self.member_param_label % ldap_obj.object_name + yield Str('%s*' % name, cli_name='%ss' % name, doc=doc, +- label=_('member %s') % ldap_obj.object_name, +- csv=True, alwaysask=True) ++ label=label, csv=True, alwaysask=True) + + def get_member_dns(self, **options): + dns = {} +-- +2.4.3 + diff --git a/SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch b/SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch deleted file mode 100644 index 0372953..0000000 --- a/SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch +++ /dev/null @@ -1,1207 +0,0 @@ -From d19a011c84949c323194fe389f1e84d0dcc61c70 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Mon, 10 Nov 2014 22:46:44 -0500 -Subject: [PATCH] Move authentication configuration cache into libotp - -This enables plugins to share authentication configuration cache code. - -Additionally, update the caching mechanism to be declarative and faster. - -Reviewed-By: Thierry Bordaz ---- - .../ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c | 280 --------------------- - daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h | 82 ------ - .../ipa-pwd-extop/ipa_pwd_extop.c | 21 +- - daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 50 ++-- - daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c | 4 +- - daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h | 4 +- - daemons/ipa-slapi-plugins/libotp/Makefile.am | 2 +- - daemons/ipa-slapi-plugins/libotp/otp_config.c | 274 ++++++++++++++++++++ - daemons/ipa-slapi-plugins/libotp/otp_config.h | 65 +++++ - daemons/ipa-slapi-plugins/libotp/otp_token.c | 58 ++--- - daemons/ipa-slapi-plugins/libotp/otp_token.h | 11 +- - 12 files changed, 395 insertions(+), 457 deletions(-) - delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c - delete mode 100644 daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h - create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_config.c - create mode 100644 daemons/ipa-slapi-plugins/libotp/otp_config.h - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -index eeb352611e5b67a2f6803b59414fb31c37f39f33..1ab6c6704e401810772a5ababc7cc5eec19d2c83 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -@@ -44,7 +44,6 @@ libipa_pwd_extop_la_LIBADD = \ - $(ASN1_UTIL_DIR)/libipaasn1.la \ - $(NULL) - libipa_pwd_extop_la_SOURCES = \ -- authcfg.c \ - common.c \ - encoding.c \ - prepost.c \ -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c -deleted file mode 100644 -index 3ab5668edd7edcb9eaf247c18b964f6584c9d439..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.c -+++ /dev/null -@@ -1,280 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2014 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- --#include "authcfg.h" --#include "ipapwd.h" -- --#include "pratom.h" -- --static struct config { -- struct config *next; -- Slapi_DN *suffix; -- uint32_t config; --} *config; -- --static uint32_t string_to_config(const char *str) --{ -- static const struct { -- const char *string; -- uint32_t config; -- } map[] = { -- { "disabled", AUTHCFG_AUTH_TYPE_DISABLED }, -- { "password", AUTHCFG_AUTH_TYPE_PASSWORD }, -- { "otp", AUTHCFG_AUTH_TYPE_OTP }, -- { "pkinit", AUTHCFG_AUTH_TYPE_PKINIT }, -- { "radius", AUTHCFG_AUTH_TYPE_RADIUS }, -- {} -- }; -- -- for (uint32_t i = 0; map[i].string != NULL; i++) { -- if (strcasecmp(map[i].string, str) == 0) -- return map[i].config; -- } -- -- return AUTHCFG_AUTH_TYPE_NONE; --} -- --static uint32_t entry_to_config(Slapi_Entry *e) --{ -- char **auth_types = NULL; -- -- if (e == NULL) -- return AUTHCFG_AUTH_TYPE_NONE; -- -- /* Fetch the auth type values from the config entry. */ -- auth_types = slapi_entry_attr_get_charray(e, "ipaUserAuthType"); -- if (auth_types == NULL) -- return AUTHCFG_AUTH_TYPE_NONE; -- -- uint32_t types = AUTHCFG_AUTH_TYPE_NONE; -- for (uint32_t i = 0; auth_types[i] != NULL; i++) -- types |= string_to_config(auth_types[i]); -- -- slapi_ch_array_free(auth_types); -- -- return types; --} -- --static Slapi_DN *suffix_to_config_dn(Slapi_DN *suffix) --{ -- Slapi_DN *sdn = NULL; -- char *dn = NULL; -- -- if (suffix == NULL) -- return NULL; -- -- dn = PR_smprintf("cn=ipaConfig,cn=etc,%s", slapi_sdn_get_dn(suffix)); -- if (dn == NULL) -- return NULL; -- -- sdn = slapi_sdn_new_dn_byval(dn); -- PR_smprintf_free(dn); -- return sdn; --} -- --static uint32_t suffix_to_config(Slapi_DN *suffix) --{ -- static char *attrs[] = { "ipaUserAuthType", NULL }; -- Slapi_Entry *entry = NULL; -- Slapi_DN *sdn = NULL; -- uint32_t types; -- int ret; -- -- sdn = suffix_to_config_dn(suffix); -- if (sdn == NULL) -- return AUTHCFG_AUTH_TYPE_NONE; -- -- ret = slapi_search_internal_get_entry(sdn, attrs, &entry, -- ipapwd_get_plugin_id()); -- slapi_sdn_free(&sdn); -- if (ret != LDAP_SUCCESS) -- return AUTHCFG_AUTH_TYPE_NONE; -- -- types = entry_to_config(entry); -- slapi_entry_free(entry); -- -- return types; --} -- --static Slapi_DN *sdn_to_suffix(Slapi_DN *sdn) --{ -- Slapi_DN *suffix = NULL; -- void *node = NULL; -- -- if (sdn == NULL) -- return NULL; -- -- for (suffix = slapi_get_first_suffix(&node, 0); suffix != NULL; -- suffix = slapi_get_next_suffix(&node, 0)) { -- if (slapi_sdn_issuffix(sdn, suffix)) -- return suffix; -- } -- -- return NULL; --} -- --static bool sdn_is_config(Slapi_DN *sdn) --{ -- Slapi_DN *sfx = NULL; -- Slapi_DN *cfg = NULL; -- int cmp; -- -- if (sdn == NULL) -- return false; -- -- sfx = sdn_to_suffix(sdn); -- if (sfx == NULL) -- return false; -- -- cfg = suffix_to_config_dn(sfx); -- if (cfg == NULL) -- return false; -- -- cmp = slapi_sdn_compare(cfg, sdn); -- slapi_sdn_free(&cfg); -- return cmp == 0; --} -- --void cache_free(struct config **cfg) --{ -- if (cfg == NULL || *cfg == NULL) -- return; -- -- cache_free(&(*cfg)->next); -- free(*cfg); -- *cfg = NULL; --} -- --bool authcfg_init(void) --{ -- struct config *cfg = NULL; -- Slapi_DN *sfx = NULL; -- void *node = NULL; -- -- /* If we are already initialized, return true. */ -- if (config != NULL) -- return true; -- -- /* Look up the config for each suffix. */ -- for (sfx = slapi_get_first_suffix(&node, 0); sfx != NULL; -- sfx = slapi_get_next_suffix(&node, 0)) { -- cfg = calloc(1, sizeof(*cfg)); -- if (cfg == NULL) { -- authcfg_fini(); -- return false; -- } -- -- cfg->suffix = sfx; -- cfg->config = suffix_to_config(sfx); -- cfg->next = config; -- config = cfg; -- } -- -- return true; --} -- --void authcfg_fini(void) --{ -- cache_free(&config); --} -- --uint32_t authcfg_get_auth_types(Slapi_Entry *user_entry) --{ -- uint32_t glbl = AUTHCFG_AUTH_TYPE_NONE; -- uint32_t user = AUTHCFG_AUTH_TYPE_NONE; -- Slapi_DN *sfx = NULL; -- Slapi_DN *sdn = NULL; -- -- /* Find the root suffix. */ -- sdn = slapi_entry_get_sdn(user_entry); -- sfx = sdn_to_suffix(sdn); -- -- /* Find the global config. */ -- if (sfx != NULL) { -- for (struct config *cfg = config; cfg && sfx; cfg = cfg->next) { -- if (slapi_sdn_compare(sfx, cfg->suffix) == 0) { -- glbl = PR_ATOMIC_ADD(&cfg->config, 0); -- break; -- } -- } -- } -- -- /* Global disabled overrides user settings. */ -- if (glbl & AUTHCFG_AUTH_TYPE_DISABLED) -- return AUTHCFG_AUTH_TYPE_DISABLED; -- -- /* Get the user's config. */ -- user = entry_to_config(user_entry); -- -- if (user == AUTHCFG_AUTH_TYPE_NONE) { -- if (glbl == AUTHCFG_AUTH_TYPE_NONE) -- return AUTHCFG_AUTH_TYPE_PASSWORD; -- return glbl; -- } -- -- return user & ~AUTHCFG_AUTH_TYPE_DISABLED; --} -- --void authcfg_reload_global_config(Slapi_DN *sdn, Slapi_Entry *config_entry) --{ -- uint32_t glbl = AUTHCFG_AUTH_TYPE_NONE; -- Slapi_DN *sfx = NULL; -- Slapi_DN *dest; -- -- /* Get the destination DN. */ -- dest = config_entry == NULL ? NULL : slapi_entry_get_sdn(config_entry); -- -- /* Added, modified, moved into place. */ -- if (sdn_is_config(dest)) { -- sfx = sdn_to_suffix(dest); -- glbl = entry_to_config(config_entry); -- -- /* Deleted, moved out of place. */ -- } else if (sdn_is_config(sdn)) { -- sfx = sdn_to_suffix(sdn); -- } -- -- /* Reload config. */ -- for (struct config *cfg = config; cfg && sfx; cfg = cfg->next) { -- if (slapi_sdn_compare(sfx, cfg->suffix) == 0) { -- PR_ATOMIC_SET(&cfg->config, glbl); -- break; -- } -- } --} -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h -deleted file mode 100644 -index c2fc24605c0f915261a57967c43c35ab6e773263..0000000000000000000000000000000000000000 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/authcfg.h -+++ /dev/null -@@ -1,82 +0,0 @@ --/** BEGIN COPYRIGHT BLOCK -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation, either version 3 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see . -- * -- * Additional permission under GPLv3 section 7: -- * -- * In the following paragraph, "GPL" means the GNU General Public -- * License, version 3 or any later version, and "Non-GPL Code" means -- * code that is governed neither by the GPL nor a license -- * compatible with the GPL. -- * -- * You may link the code of this Program with Non-GPL Code and convey -- * linked combinations including the two, provided that such Non-GPL -- * Code only links to the code of this Program through those well -- * defined interfaces identified in the file named EXCEPTION found in -- * the source code files (the "Approved Interfaces"). The files of -- * Non-GPL Code may instantiate templates or use macros or inline -- * functions from the Approved Interfaces without causing the resulting -- * work to be covered by the GPL. Only the copyright holders of this -- * Program may make changes or additions to the list of Approved -- * Interfaces. -- * -- * Authors: -- * Nathaniel McCallum -- * -- * Copyright (C) 2014 Red Hat, Inc. -- * All rights reserved. -- * END COPYRIGHT BLOCK **/ -- -- --#ifndef AUTHCFG_H_ --#define AUTHCFG_H_ -- --#include --#include -- --#define AUTHCFG_AUTH_TYPE_NONE 0 --#define AUTHCFG_AUTH_TYPE_DISABLED 1 --#define AUTHCFG_AUTH_TYPE_PASSWORD 2 --#define AUTHCFG_AUTH_TYPE_OTP 4 --#define AUTHCFG_AUTH_TYPE_PKINIT 8 --#define AUTHCFG_AUTH_TYPE_RADIUS 16 -- --/* Initialize authentication configuration. -- * -- * Thread Safety: NO -- */ --bool authcfg_init(void); -- --/* Free global authentication configuration resources. -- * -- * Thread Safety: NO -- */ --void authcfg_fini(void); -- --/* Gets the permitted authentication types for the given user entry. -- * -- * The entry should be queried for the "ipaUserAuthType" attribute. -- * -- * Thread Safety: YES -- */ --uint32_t authcfg_get_auth_types(Slapi_Entry *user_entry); -- --/* Reloads configuration from the specified global config entry. -- * -- * If the provided entry isn't a global config entry, this is a no-op. -- * -- * Thread Safety: YES -- */ --void authcfg_reload_global_config(Slapi_DN *sdn, Slapi_Entry *config_entry); -- --#endif /* AUTHCFG_H_ */ -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -index ceea49cab50b0836c882240f210339e60d26729b..09c877f7010d3cc252c9f38e827cd33b63dea3b6 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c -@@ -39,7 +39,7 @@ - - #include "ipapwd.h" - #include "util.h" --#include "authcfg.h" -+#include "../libotp/otp_config.h" - #include "ipa_asn1.h" - - /* -@@ -89,6 +89,8 @@ Slapi_PluginDesc ipapwd_plugin_desc = { - void *ipapwd_plugin_id; - static int usetxn = 0; - -+extern struct otp_config *otp_config; -+ - void *ipapwd_get_plugin_id(void) - { - return ipapwd_plugin_id; -@@ -1792,16 +1794,6 @@ static int ipapwd_start( Slapi_PBlock *pb ) - Slapi_Entry *config_entry = NULL; - int ret; - -- /* NOTE: We never call authcfg_fini() from a destructor. This is because -- * it may race with threaded requests at shutdown. This leak should -- * only occur when the DS is exiting, so it isn't a big deal. -- */ -- if (!authcfg_init()) { -- LOG_FATAL("AuthConf initialization failed!\n"); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- - krberr = krb5_init_context(&krbctx); - if (krberr) { - LOG_FATAL("krb5_init_context failed\n"); -@@ -1871,11 +1863,16 @@ static int ipapwd_start( Slapi_PBlock *pb ) - - ret = LDAP_SUCCESS; - -+ /* NOTE: We never call otp_config_fini() from a destructor. This is because -+ * it may race with threaded requests at shutdown. This leak should -+ * only occur when the DS is exiting, so it isn't a big deal. -+ */ -+ otp_config = otp_config_init(ipapwd_plugin_id); -+ - done: - free(realm); - krb5_free_context(krbctx); - if (config_entry) slapi_entry_free(config_entry); -- if (ret != LDAP_SUCCESS) authcfg_fini(); - return ret; - } - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -index 1dff6db1a8cfcc295ba43d1c29d8887e3cf37fec..96c55f39ba2a9dc1e9fc80d5f7d46787803ece47 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c -@@ -63,7 +63,6 @@ - #include "ipapwd.h" - #include "util.h" - #include "syncreq.h" --#include "authcfg.h" - - #define IPAPWD_OP_NULL 0 - #define IPAPWD_OP_ADD 1 -@@ -75,6 +74,8 @@ extern Slapi_PluginDesc ipapwd_plugin_desc; - extern void *ipapwd_plugin_id; - extern const char *ipa_realm_tree; - -+struct otp_config *otp_config = NULL; -+ - /* structure with information for each extension */ - struct ipapwd_op_ext { - char *object_name; /* name of the object extended */ -@@ -967,23 +968,9 @@ static int ipapwd_regen_nthash(Slapi_PBlock *pb, Slapi_Mods *smods, - return ret; - } - --static int ipapwd_post_authcfg(Slapi_PBlock *pb) -+static int ipapwd_post_updatecfg(Slapi_PBlock *pb) - { -- Slapi_Entry *config_entry = NULL; -- Slapi_DN *sdn = NULL; -- int oprc = 0; -- -- /* Just bail if the operation failed. */ -- if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0) -- return 0; -- -- if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn) != 0) -- return 0; -- -- /* Ignore the error here (delete operations). */ -- slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &config_entry); -- -- authcfg_reload_global_config(sdn, config_entry); -+ otp_config_update(otp_config, pb); - return 0; - } - -@@ -1003,8 +990,7 @@ static int ipapwd_post_modadd(Slapi_PBlock *pb) - - LOG_TRACE("=>\n"); - -- /* Ignore error when parsing configuration. */ -- ipapwd_post_authcfg(pb); -+ otp_config_update(otp_config, pb); - - /* time to get the operation handler */ - ret = slapi_pblock_get(pb, SLAPI_OPERATION, &op); -@@ -1144,7 +1130,7 @@ static bool ipapwd_do_otp_auth(const char *dn, Slapi_Entry *bind_entry, - bool success = false; - - /* Find all of the user's active tokens. */ -- tokens = otp_token_find(ipapwd_plugin_id, dn, NULL, true, NULL); -+ tokens = otp_token_find(otp_config, dn, NULL, true, NULL); - if (tokens == NULL) { - slapi_log_error(SLAPI_LOG_FATAL, IPAPWD_PLUGIN_NAME, - "%s: can't find tokens for '%s'.\n", __func__, dn); -@@ -1190,11 +1176,7 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry, - uint32_t auth_types; - - /* Get the configured authentication types. */ -- auth_types = authcfg_get_auth_types(entry); -- -- /* If global disabled flag is set, just punt. */ -- if (auth_types & AUTHCFG_AUTH_TYPE_DISABLED) -- return true; -+ auth_types = otp_config_auth_types(otp_config, entry); - - /* - * IMPORTANT SECTION! -@@ -1206,14 +1188,14 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry, - * 2. If PWD is enabled or OTP succeeded, fall through to PWD validation. - */ - -- if (auth_types & AUTHCFG_AUTH_TYPE_OTP) { -+ if (auth_types & OTP_CONFIG_AUTH_TYPE_OTP) { - LOG_PLUGIN_NAME(IPAPWD_PLUGIN_NAME, - "Attempting OTP authentication for '%s'.\n", bind_dn); - if (ipapwd_do_otp_auth(bind_dn, entry, creds)) - return true; - } - -- return auth_types & AUTHCFG_AUTH_TYPE_PASSWORD; -+ return auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD; - } - - static int ipapwd_authenticate(const char *dn, Slapi_Entry *entry, -@@ -1461,7 +1443,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb) - } - - /* Attempt to handle a token synchronization request. */ -- if (syncreq && !sync_request_handle(ipapwd_get_plugin_id(), pb, dn)) -+ if (syncreq && !sync_request_handle(otp_config, pb, dn)) - goto invalid_creds; - - /* Attempt to write out kerberos keys for the user. */ -@@ -1513,9 +1495,9 @@ int ipapwd_post_init(Slapi_PBlock *pb) - ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *)ipapwd_post_modadd); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_authcfg); -+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *)ipapwd_post_updatecfg); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *)ipapwd_post_modadd); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_authcfg); -+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg); - - return ret; - } -@@ -1526,10 +1508,10 @@ int ipapwd_intpost_init(Slapi_PBlock *pb) - - ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03); - if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&ipapwd_plugin_desc); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_authcfg); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_authcfg); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_authcfg); -- if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_authcfg); -+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *)ipapwd_post_updatecfg); -+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *)ipapwd_post_updatecfg); -+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *)ipapwd_post_updatecfg); -+ if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *)ipapwd_post_updatecfg); - return ret; - } - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -index 10c49b724ee276d2b1fb89891a6eb4ee8eaa8fab..0aef438023e7f23d7219273e9f5efd5572e73c3f 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.c -@@ -52,7 +52,7 @@ bool sync_request_present(Slapi_PBlock *pb) - return ldap_control_find(OTP_SYNC_REQUEST_OID, controls, NULL) != NULL; - } - --bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, -+bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb, - const char *user_dn) - { - struct otp_token **tokens = NULL; -@@ -90,7 +90,7 @@ bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, - /* Process the synchronization. */ - success = false; - if (ber_scanf(ber, "}") != LBER_ERROR) { -- tokens = otp_token_find(plugin_id, user_dn, token_dn, true, NULL); -+ tokens = otp_token_find(cfg, user_dn, token_dn, true, NULL); - if (tokens != NULL) { - success = otp_token_sync_berval(tokens, OTP_SYNC_MAX_STEPS, first, second); - otp_token_free_array(tokens); -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h -index 34235901b7b2e49cc6e79423a92e0e4930c0b8cb..98a97c4c9f6d2e6bf74f97fc93053b3aebbc7821 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/syncreq.h -@@ -41,7 +41,7 @@ - #ifndef SYNCREQ_H_ - #define SYNCREQ_H_ - --#include -+#include "../libotp/otp_config.h" - #include - - /* -@@ -57,7 +57,7 @@ - - bool sync_request_present(Slapi_PBlock *pb); - --bool sync_request_handle(Slapi_ComponentId *plugin_id, Slapi_PBlock *pb, -+bool sync_request_handle(const struct otp_config *cfg, Slapi_PBlock *pb, - const char *user_dn); - - #endif /* SYNCREQ_H_ */ -diff --git a/daemons/ipa-slapi-plugins/libotp/Makefile.am b/daemons/ipa-slapi-plugins/libotp/Makefile.am -index 012c8339199af5f63e6434b94109af2d93a38b45..4428f6bdc38a4e4ec224d1fa70744d8381f7e0b1 100644 ---- a/daemons/ipa-slapi-plugins/libotp/Makefile.am -+++ b/daemons/ipa-slapi-plugins/libotp/Makefile.am -@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I/usr/include/dirsrv - - noinst_LTLIBRARIES = libhotp.la libotp.la - libhotp_la_SOURCES = hotp.c hotp.h --libotp_la_SOURCES = otp_token.c otp_token.h -+libotp_la_SOURCES = otp_config.c otp_config.h otp_token.c otp_token.h - libotp_la_LIBADD = libhotp.la - - check_PROGRAMS = t_hotp -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.c b/daemons/ipa-slapi-plugins/libotp/otp_config.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1b7c1e658f126e3d1e8eabd129bb69dc5c4ce970 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.c -@@ -0,0 +1,274 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2014 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+#include "otp_config.h" -+ -+#include -+#include -+ -+#define OTP_CONFIG_AUTH_TYPE_DISABLED (1 << 31) -+ -+struct spec { -+ uint32_t (*func)(Slapi_Entry *, const char *attr); -+ const char *prefix; -+ const char *attr; -+ uint32_t dflt; -+}; -+ -+struct record { -+ struct record *next; -+ const struct spec *spec; -+ Slapi_DN *sdn; -+ uint32_t value; -+}; -+ -+struct otp_config { -+ Slapi_ComponentId *plugin_id; -+ struct record *records; -+}; -+ -+static uint32_t string_to_types(const char *str) -+{ -+ static const struct { -+ const char *string; -+ uint32_t config; -+ } map[] = { -+ { "disabled", OTP_CONFIG_AUTH_TYPE_DISABLED }, -+ { "password", OTP_CONFIG_AUTH_TYPE_PASSWORD }, -+ { "otp", OTP_CONFIG_AUTH_TYPE_OTP }, -+ { "pkinit", OTP_CONFIG_AUTH_TYPE_PKINIT }, -+ { "radius", OTP_CONFIG_AUTH_TYPE_RADIUS }, -+ {} -+ }; -+ -+ for (uint32_t i = 0; map[i].string != NULL; i++) { -+ if (strcasecmp(map[i].string, str) == 0) -+ return map[i].config; -+ } -+ -+ return OTP_CONFIG_AUTH_TYPE_NONE; -+} -+ -+static uint32_t entry_to_authtypes(Slapi_Entry *e, const char *attr) -+{ -+ char **auth_types = NULL; -+ -+ if (e == NULL) -+ return OTP_CONFIG_AUTH_TYPE_NONE; -+ -+ /* Fetch the auth type values from the config entry. */ -+ auth_types = slapi_entry_attr_get_charray(e, attr); -+ if (auth_types == NULL) -+ return OTP_CONFIG_AUTH_TYPE_NONE; -+ -+ uint32_t types = OTP_CONFIG_AUTH_TYPE_NONE; -+ for (uint32_t i = 0; auth_types[i] != NULL; i++) -+ types |= string_to_types(auth_types[i]); -+ -+ slapi_ch_array_free(auth_types); -+ return types; -+} -+ -+static const struct spec authtypes = { -+ entry_to_authtypes, -+ "cn=ipaConfig,cn=etc,%s", -+ "ipaUserAuthType", -+ OTP_CONFIG_AUTH_TYPE_PASSWORD -+}; -+ -+static Slapi_DN *make_sdn(const char *prefix, const Slapi_DN *suffix) -+{ -+ char *dn = slapi_ch_smprintf(prefix, slapi_sdn_get_dn(suffix)); -+ return slapi_sdn_new_dn_passin(dn); -+} -+ -+static uint32_t find_value(const struct otp_config *cfg, -+ const Slapi_DN *suffix, const struct spec *spec) -+{ -+ uint32_t value = 0; -+ Slapi_DN *sdn; -+ -+ sdn = make_sdn(spec->prefix, suffix); -+ for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) { -+ if (rec->spec == spec) { -+ value = PR_ATOMIC_ADD(&rec->value, 0); -+ break; -+ } -+ } -+ -+ slapi_sdn_free(&sdn); -+ return value; -+} -+ -+static void update(const struct otp_config *cfg, Slapi_DN *src, -+ Slapi_Entry *entry) -+{ -+ Slapi_DN *dst = entry == NULL ? NULL : slapi_entry_get_sdn(entry); -+ -+ for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) { -+ uint32_t val = rec->spec->dflt; -+ -+ /* If added, modified or moved into place... */ -+ if (dst != NULL && slapi_sdn_compare(rec->sdn, dst) == 0) { -+ Slapi_Attr *attr = NULL; -+ if (slapi_entry_attr_find(entry, rec->spec->attr, &attr) == 0) -+ val = rec->spec->func(entry, rec->spec->attr); -+ -+ /* If NOT deleted or moved out of place... */ -+ } else if (slapi_sdn_compare(rec->sdn, src) != 0) -+ continue; -+ -+ PR_ATOMIC_SET(&rec->value, val); -+ } -+} -+ -+struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id) -+{ -+ static const struct spec *specs[] = { -+ &authtypes, -+ NULL -+ }; -+ -+ struct otp_config *cfg = NULL; -+ void *node = NULL; -+ -+ cfg = (typeof(cfg)) slapi_ch_calloc(1, sizeof(*cfg)); -+ cfg->plugin_id = plugin_id; -+ -+ /* Build the config table. */ -+ for (Slapi_DN *sfx = slapi_get_first_suffix(&node, 0); -+ sfx != NULL; -+ sfx = slapi_get_next_suffix(&node, 0)) { -+ for (size_t i = 0; specs[i] != NULL; i++) { -+ Slapi_Entry *entry = NULL; -+ struct record *rec; -+ -+ /* Create the config entry. */ -+ rec = (typeof(rec)) slapi_ch_calloc(1, sizeof(*rec)); -+ rec->spec = specs[i]; -+ rec->sdn = make_sdn(rec->spec->prefix, sfx); -+ -+ /* Add config to the list. */ -+ rec->next = cfg->records; -+ cfg->records = rec; -+ -+ /* Load the specified entry. */ -+ slapi_search_internal_get_entry(rec->sdn, NULL, &entry, plugin_id); -+ update(cfg, rec->sdn, entry); -+ slapi_entry_free(entry); -+ } -+ } -+ -+ return cfg; -+} -+ -+static void record_fini(struct record **rec) -+{ -+ if (rec == NULL || *rec == NULL) -+ return; -+ -+ record_fini(&(*rec)->next); -+ slapi_sdn_free(&(*rec)->sdn); -+ slapi_ch_free((void **) rec); -+} -+ -+void otp_config_fini(struct otp_config **cfg) -+{ -+ if (cfg == NULL || *cfg == NULL) -+ return; -+ -+ record_fini(&(*cfg)->records); -+ slapi_ch_free((void **) cfg); -+} -+ -+void otp_config_update(struct otp_config *cfg, Slapi_PBlock *pb) -+{ -+ Slapi_Entry *entry = NULL; -+ Slapi_DN *src = NULL; -+ int oprc = 0; -+ -+ /* Just bail if the operation failed. */ -+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 || oprc != 0) -+ return; -+ -+ /* Get the source SDN. */ -+ if (slapi_pblock_get(pb, SLAPI_TARGET_SDN, &src) != 0) -+ return; -+ -+ /* Ignore the error here (delete operations). */ -+ (void) slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &entry); -+ -+ update(cfg, src, entry); -+} -+ -+Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg) -+{ -+ if (cfg == NULL) -+ return NULL; -+ -+ return cfg->plugin_id; -+} -+ -+uint32_t otp_config_auth_types(const struct otp_config *cfg, -+ Slapi_Entry *user_entry) -+{ -+ uint32_t glbl = OTP_CONFIG_AUTH_TYPE_NONE; -+ uint32_t user = OTP_CONFIG_AUTH_TYPE_NONE; -+ const Slapi_DN *sfx; -+ -+ /* Load the global value. */ -+ sfx = slapi_get_suffix_by_dn(slapi_entry_get_sdn(user_entry)); -+ glbl = find_value(cfg, sfx, &authtypes); -+ -+ /* Load the user value if not disabled. */ -+ if ((glbl & OTP_CONFIG_AUTH_TYPE_DISABLED) == 0) -+ user = entry_to_authtypes(user_entry, authtypes.attr); -+ -+ /* Filter out the disabled flag. */ -+ glbl &= ~OTP_CONFIG_AUTH_TYPE_DISABLED; -+ user &= ~OTP_CONFIG_AUTH_TYPE_DISABLED; -+ -+ if (user != OTP_CONFIG_AUTH_TYPE_NONE) -+ return user; -+ -+ if (glbl != OTP_CONFIG_AUTH_TYPE_NONE) -+ return glbl; -+ -+ return OTP_CONFIG_AUTH_TYPE_PASSWORD; -+} -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.h b/daemons/ipa-slapi-plugins/libotp/otp_config.h -new file mode 100644 -index 0000000000000000000000000000000000000000..bfd514bd542b7d707e9eab4a9cdf31a4f6839ae5 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.h -@@ -0,0 +1,65 @@ -+/** BEGIN COPYRIGHT BLOCK -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program. If not, see . -+ * -+ * Additional permission under GPLv3 section 7: -+ * -+ * In the following paragraph, "GPL" means the GNU General Public -+ * License, version 3 or any later version, and "Non-GPL Code" means -+ * code that is governed neither by the GPL nor a license -+ * compatible with the GPL. -+ * -+ * You may link the code of this Program with Non-GPL Code and convey -+ * linked combinations including the two, provided that such Non-GPL -+ * Code only links to the code of this Program through those well -+ * defined interfaces identified in the file named EXCEPTION found in -+ * the source code files (the "Approved Interfaces"). The files of -+ * Non-GPL Code may instantiate templates or use macros or inline -+ * functions from the Approved Interfaces without causing the resulting -+ * work to be covered by the GPL. Only the copyright holders of this -+ * Program may make changes or additions to the list of Approved -+ * Interfaces. -+ * -+ * Authors: -+ * Nathaniel McCallum -+ * -+ * Copyright (C) 2014 Red Hat, Inc. -+ * All rights reserved. -+ * END COPYRIGHT BLOCK **/ -+ -+#pragma once -+ -+#include -+ -+#define OTP_CONFIG_AUTH_TYPE_NONE 0 -+#define OTP_CONFIG_AUTH_TYPE_PASSWORD (1 << 0) -+#define OTP_CONFIG_AUTH_TYPE_OTP (1 << 1) -+#define OTP_CONFIG_AUTH_TYPE_PKINIT (1 << 2) -+#define OTP_CONFIG_AUTH_TYPE_RADIUS (1 << 3) -+ -+struct otp_config; -+ -+struct otp_config *otp_config_init(Slapi_ComponentId *plugin_id); -+ -+void otp_config_fini(struct otp_config **cfg); -+ -+void otp_config_update(struct otp_config *cfg, Slapi_PBlock *pb); -+ -+Slapi_ComponentId *otp_config_plugin_id(const struct otp_config *cfg); -+ -+/* Gets the permitted authentication types for the given user entry. -+ * -+ * The entry should be queried for the "ipaUserAuthType" attribute. -+ */ -+uint32_t otp_config_auth_types(const struct otp_config *cfg, -+ Slapi_Entry *user_entry); -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c -index 7860c8aba6e12e319d633ee8e165403289a7528b..eef07268507444897d50509a54f2877866b9c07a 100644 ---- a/daemons/ipa-slapi-plugins/libotp/otp_token.c -+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c -@@ -59,7 +59,7 @@ enum type { - }; - - struct otp_token { -- Slapi_ComponentId *plugin_id; -+ const struct otp_config *cfg; - Slapi_DN *sdn; - struct hotp_token token; - enum type type; -@@ -75,21 +75,6 @@ struct otp_token { - }; - }; - --static const char *get_basedn(Slapi_DN *dn) --{ -- Slapi_DN *suffix = NULL; -- void *node = NULL; -- -- for (suffix = slapi_get_first_suffix(&node, 0); -- suffix != NULL; -- suffix = slapi_get_next_suffix(&node, 0)) { -- if (slapi_sdn_issuffix(dn, suffix)) -- return (char *) slapi_sdn_get_dn(suffix); -- } -- -- return NULL; --} -- - static inline bool is_algo_valid(const char *algo) - { - static const char *valid_algos[] = { "sha1", "sha256", "sha384", -@@ -142,8 +127,8 @@ static bool writeattr(const struct otp_token *token, const char *attr, - snprintf(value, sizeof(value), "%lld", val); - - pb = slapi_pblock_new(); -- slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), -- mods, NULL, NULL, token->plugin_id, 0); -+ slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn(token->sdn), mods, NULL, -+ NULL, otp_config_plugin_id(token->cfg), 0); - if (slapi_modify_internal_pb(pb) != 0) - goto error; - if (slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret) != 0) -@@ -251,7 +236,7 @@ void otp_token_free_array(struct otp_token **tokens) - free(tokens); - } - --static struct otp_token *otp_token_new(Slapi_ComponentId *id, -+static struct otp_token *otp_token_new(const struct otp_config *cfg, - Slapi_Entry *entry) - { - const struct berval *tmp; -@@ -261,7 +246,7 @@ static struct otp_token *otp_token_new(Slapi_ComponentId *id, - token = calloc(1, sizeof(struct otp_token)); - if (token == NULL) - return NULL; -- token->plugin_id = id; -+ token->cfg = cfg; - - /* Get the token type. */ - vals = slapi_entry_attr_get_charray(entry, "objectClass"); -@@ -333,16 +318,16 @@ error: - return NULL; - } - --static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, -+static struct otp_token **find(const struct otp_config *cfg, const char *user_dn, - const char *token_dn, const char *intfilter, - const char *extfilter) - { - struct otp_token **tokens = NULL; -+ const Slapi_DN *basedn = NULL; - Slapi_Entry **entries = NULL; - Slapi_PBlock *pb = NULL; - Slapi_DN *sdn = NULL; - char *filter = NULL; -- const char *basedn = NULL; - size_t count = 0; - int result = -1; - -@@ -367,20 +352,19 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, - if (token_dn != NULL) { - /* Find only the token specified. */ - slapi_search_internal_set_pb(pb, token_dn, LDAP_SCOPE_BASE, filter, -- NULL, 0, NULL, NULL, id, 0); -+ NULL, 0, NULL, NULL, -+ otp_config_plugin_id(cfg), 0); - } else { - sdn = slapi_sdn_new_dn_byval(user_dn); -- if (sdn == NULL) -- goto error; -- -- basedn = get_basedn(sdn); -+ basedn = slapi_get_suffix_by_dn(sdn); -+ slapi_sdn_free(&sdn); - if (basedn == NULL) - goto error; - - /* Find all user tokens. */ -- slapi_search_internal_set_pb(pb, basedn, -- LDAP_SCOPE_SUBTREE, filter, NULL, -- 0, NULL, NULL, id, 0); -+ slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(basedn), -+ LDAP_SCOPE_SUBTREE, filter, NULL, 0, -+ NULL, NULL, otp_config_plugin_id(cfg), 0); - } - slapi_search_internal_pb(pb); - slapi_ch_free_string(&filter); -@@ -402,7 +386,7 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, - if (tokens == NULL) - goto error; - for (count = 0; entries[count] != NULL; count++) { -- tokens[count] = otp_token_new(id, entries[count]); -+ tokens[count] = otp_token_new(cfg, entries[count]); - if (tokens[count] == NULL) { - otp_token_free_array(tokens); - tokens = NULL; -@@ -411,15 +395,13 @@ static struct otp_token **find(Slapi_ComponentId *id, const char *user_dn, - } - - error: -- if (sdn != NULL) -- slapi_sdn_free(&sdn); - slapi_pblock_destroy(pb); - return tokens; - } - --struct otp_token ** --otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, -- bool active, const char *filter) -+struct otp_token **otp_token_find(const struct otp_config *cfg, -+ const char *user_dn, const char *token_dn, -+ bool active, const char *filter) - { - static const char template[] = - "(|(ipatokenNotBefore<=%04d%02d%02d%02d%02d%02dZ)(!(ipatokenNotBefore=*)))" -@@ -430,7 +412,7 @@ otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, - time_t now; - - if (!active) -- return find(id, user_dn, token_dn, NULL, filter); -+ return find(cfg, user_dn, token_dn, NULL, filter); - - /* Get the current time. */ - if (time(&now) == (time_t) -1) -@@ -446,7 +428,7 @@ otp_token_find(Slapi_ComponentId *id, const char *user_dn, const char *token_dn, - tm.tm_hour, tm.tm_min, tm.tm_sec) < 0) - return NULL; - -- return find(id, user_dn, token_dn, actfilt, filter); -+ return find(cfg, user_dn, token_dn, actfilt, filter); - } - - int otp_token_get_digits(struct otp_token *token) -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.h b/daemons/ipa-slapi-plugins/libotp/otp_token.h -index 2f336780682b5ea2838b558079e2ae85f6e2afba..4b159077d933555d18e804174e29e22f1e8f0110 100644 ---- a/daemons/ipa-slapi-plugins/libotp/otp_token.h -+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.h -@@ -39,14 +39,15 @@ - - #pragma once - --#include -+#include "otp_config.h" - #include - #include - - struct otp_token; - - /* Frees the token array. */ --void otp_token_free_array(struct otp_token **tokens); -+void -+otp_token_free_array(struct otp_token **tokens); - - /* Find tokens. - * -@@ -65,9 +66,9 @@ void otp_token_free_array(struct otp_token **tokens); - * Returns NULL on error. If no tokens are found, an empty array is returned. - * The array is NULL terminated. - */ --struct otp_token **otp_token_find(Slapi_ComponentId *id, const char *user_dn, -- const char *token_dn, bool active, -- const char *filter); -+struct otp_token **otp_token_find(const struct otp_config *cfg, -+ const char *user_dn, const char *token_dn, -+ bool active, const char *filter); - - /* Get the length of the token code. */ - int otp_token_get_digits(struct otp_token *token); --- -2.1.0 - diff --git a/SOURCES/0071-vault-Fix-param-labels-in-output-of-vault-owner-comm.patch b/SOURCES/0071-vault-Fix-param-labels-in-output-of-vault-owner-comm.patch new file mode 100644 index 0000000..32eaecc --- /dev/null +++ b/SOURCES/0071-vault-Fix-param-labels-in-output-of-vault-owner-comm.patch @@ -0,0 +1,59 @@ +From ddb58a9dd79558764c992a4a965c2cca404b615a Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 17 Aug 2015 09:39:48 +0200 +Subject: [PATCH] vault: Fix param labels in output of vault owner commands + +https://fedorahosted.org/freeipa/ticket/5214 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 01c6096335d47b337253d4f2d1e0571200383c7a..b5a12d5c3da599d7f5afaed90f579ad3a23c27cd 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -314,6 +314,11 @@ class vault(LDAPObject): + label=_('Owner services'), + flags=['no_create', 'no_update', 'no_search'], + ), ++ Str( ++ 'owner?', ++ label=_('Failed owners'), ++ flags=['no_create', 'no_update', 'no_search'], ++ ), + ) + + def get_dn(self, *keys, **options): +@@ -1420,6 +1425,11 @@ class VaultModMember(LDAPModMember): + options.pop('service', None) + return super(VaultModMember, self).get_member_dns(**options) + ++ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): ++ for fail in failed.itervalues(): ++ fail['services'] = fail.pop('service', []) ++ return completed, dn ++ + + @register() + class vault_add_owner(VaultModMember, LDAPAddMember): +@@ -1428,6 +1438,7 @@ class vault_add_owner(VaultModMember, LDAPAddMember): + takes_options = LDAPAddMember.takes_options + vault_options + + member_attributes = ['owner'] ++ member_param_label = _('owner %s') + member_count_out = ('%i owner added.', '%i owners added.') + + has_output = ( +@@ -1452,6 +1463,7 @@ class vault_remove_owner(VaultModMember, LDAPRemoveMember): + takes_options = LDAPRemoveMember.takes_options + vault_options + + member_attributes = ['owner'] ++ member_param_label = _('owner %s') + member_count_out = ('%i owner removed.', '%i owners removed.') + + has_output = ( +-- +2.4.3 + diff --git a/SOURCES/0072-Enable-last-token-deletion-when-password-auth-type-i.patch b/SOURCES/0072-Enable-last-token-deletion-when-password-auth-type-i.patch deleted file mode 100644 index ab58dd6..0000000 --- a/SOURCES/0072-Enable-last-token-deletion-when-password-auth-type-i.patch +++ /dev/null @@ -1,327 +0,0 @@ -From 0aeae1d16bedd0f39f788644167675a99d30c3b2 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Tue, 11 Nov 2014 12:05:23 -0500 -Subject: [PATCH] Enable last token deletion when password auth type is - configured - -Also, ensure that the last token check only executes on DNs/entries that -are tokens. This resolves a large performance issue where a query was -being performed to load all the user's tokens on every del/mod operation. - -https://fedorahosted.org/freeipa/ticket/4697 -https://fedorahosted.org/freeipa/ticket/4719 - -Reviewed-By: Thierry Bordaz ---- - .../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 243 +++++++++++++++------ - 1 file changed, 173 insertions(+), 70 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -index 19217ba7fbf562231dd74b25cfd13a0f4d930e7c..233813745795344f31a7dcf1931cf74a09f1e552 100644 ---- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c -@@ -46,112 +46,171 @@ - - #include "util.h" - --#define PLUGIN_NAME "ipa-otp-lasttoken" -- --static void *plugin_id; --static const Slapi_PluginDesc preop_desc = { -- PLUGIN_NAME, -- "FreeIPA", -- "FreeIPA/1.0", -- "Protect the user's last active token" --}; -- --static bool --target_is_only_enabled_token(Slapi_PBlock *pb) -+#define PLUGIN_NAME "ipa-otp-lasttoken" -+#define OTP_CONTAINER "cn=otp,%s" -+ -+static struct otp_config *otp_config; -+ -+static bool entry_is_token(Slapi_Entry *entry) - { -- Slapi_DN *target_sdn = NULL; -- Slapi_DN *token_sdn = NULL; -- struct otp_token **tokens; -- char *user_dn = NULL; -- bool match; -+ char **ocls; - -- /* Ignore internal operations. */ -- if (slapi_op_internal(pb)) -+ ocls = slapi_entry_attr_get_charray(entry, SLAPI_ATTR_OBJECTCLASS); -+ for (size_t i = 0; ocls != NULL && ocls[i] != NULL; i++) { -+ if (strcasecmp(ocls[i], "ipaToken") == 0) { -+ slapi_ch_array_free(ocls); -+ return true; -+ } -+ } -+ -+ return false; -+} -+ -+static bool sdn_in_otp_container(Slapi_DN *sdn) -+{ -+ const Slapi_DN *base; -+ Slapi_DN *container; -+ bool result; -+ char *dn; -+ -+ base = slapi_get_suffix_by_dn(sdn); -+ if (base == NULL) - return false; - -- /* Get the current user's SDN. */ -- slapi_pblock_get(pb, SLAPI_CONN_DN, &user_dn); -- if (user_dn == NULL) -+ dn = slapi_ch_smprintf(OTP_CONTAINER, slapi_sdn_get_dn(base)); -+ if (dn == NULL) - return false; - -- /* Get the SDN of the only enabled token. */ -- tokens = otp_token_find(plugin_id, user_dn, NULL, true, NULL); -- if (tokens != NULL && tokens[0] != NULL && tokens[1] == NULL) -- token_sdn = slapi_sdn_dup(otp_token_get_sdn(tokens[0])); -+ container = slapi_sdn_new_dn_passin(dn); -+ result = slapi_sdn_issuffix(sdn, container); -+ slapi_sdn_free(&container); -+ -+ return result; -+} -+ -+static bool sdn_is_only_enabled_token(Slapi_DN *target_sdn, const char *user_dn) -+{ -+ struct otp_token **tokens; -+ bool result = false; -+ -+ tokens = otp_token_find(otp_config, user_dn, NULL, true, NULL); -+ -+ if (tokens != NULL && tokens[0] != NULL && tokens[1] == NULL) { -+ const Slapi_DN *token_sdn = otp_token_get_sdn(tokens[0]); -+ if (token_sdn != NULL) -+ result = slapi_sdn_compare(token_sdn, target_sdn) == 0; -+ } -+ - otp_token_free_array(tokens); -- if (token_sdn == NULL) -+ return result; -+} -+ -+static bool is_pwd_enabled(const char *user_dn) -+{ -+ char *attrs[] = { "ipaUserAuthType", NULL }; -+ Slapi_Entry *entry = NULL; -+ uint32_t authtypes; -+ Slapi_DN *sdn; -+ -+ sdn = slapi_sdn_new_dn_byval(user_dn); -+ if (sdn == NULL) - return false; - -- /* Get the target SDN. */ -- slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn); -- if (target_sdn == NULL) { -- slapi_sdn_free(&token_sdn); -+ slapi_search_internal_get_entry(sdn, attrs, &entry, -+ otp_config_plugin_id(otp_config)); -+ slapi_sdn_free(&sdn); -+ if (entry == NULL) -+ return false; -+ -+ authtypes = otp_config_auth_types(otp_config, entry); -+ slapi_entry_free(entry); -+ -+ return authtypes & OTP_CONFIG_AUTH_TYPE_PASSWORD; -+} -+ -+static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry) -+{ -+ Slapi_DN *target_sdn = NULL; -+ const char *bind_dn; -+ -+ /* Ignore internal operations. */ -+ if (slapi_op_internal(pb)) -+ return true; -+ -+ /* Load parameters. */ -+ (void) slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn); -+ (void) slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); -+ if (target_sdn == NULL || bind_dn == NULL) { -+ LOG_FATAL("Missing parameters!\n"); - return false; - } - -- /* Does the target SDN match the only enabled token SDN? */ -- match = slapi_sdn_compare(token_sdn, target_sdn) == 0; -- slapi_sdn_free(&token_sdn); -- return match; -+ if (entry != NULL -+ ? !entry_is_token(entry) -+ : !sdn_in_otp_container(target_sdn)) -+ return true; -+ -+ if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) -+ return true; -+ -+ if (is_pwd_enabled(bind_dn)) -+ return true; -+ -+ return false; - } - --static inline int --send_error(Slapi_PBlock *pb, int rc, char *errstr) -+static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr) - { -- slapi_send_ldap_result(pb, rc, NULL, errstr, 0, NULL); -+ slapi_send_ldap_result(pb, rc, NULL, (char *) errstr, 0, NULL); - if (slapi_pblock_set(pb, SLAPI_RESULT_CODE, &rc)) { - LOG_FATAL("slapi_pblock_set failed!\n"); - } - return rc; - } - --static int --preop_del(Slapi_PBlock *pb) -+static int preop_del(Slapi_PBlock *pb) - { -- if (!target_is_only_enabled_token(pb)) -+ if (is_allowed(pb, NULL)) - return 0; - - return send_error(pb, LDAP_UNWILLING_TO_PERFORM, - "Can't delete last active token"); - } - --static int --preop_mod(Slapi_PBlock *pb) -+static int preop_mod(Slapi_PBlock *pb) - { -- LDAPMod **mods = NULL; -+ static const struct { -+ const char *attr; -+ const char *msg; -+ } errors[] = { -+ {"ipatokenDisabled", "Can't disable last active token"}, -+ {"ipatokenOwner", "Can't change last active token's owner"}, -+ {"ipatokenNotBefore", "Can't change last active token's start time"}, -+ {"ipatokenNotAfter", "Can't change last active token's end time"}, -+ {} -+ }; - -- if (!target_is_only_enabled_token(pb)) -- return 0; -+ const LDAPMod **mods = NULL; -+ Slapi_Entry *entry = NULL; - -- /* Do not permit deactivation of the last active token. */ -- slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); -- for (int i = 0; mods != NULL && mods[i] != NULL; i++) { -- if (strcasecmp(mods[i]->mod_type, "ipatokenDisabled") == 0) { -- return send_error(pb, LDAP_UNWILLING_TO_PERFORM, -- "Can't disable last active token"); -- } -+ (void) slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &entry); -+ (void) slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); - -- if (strcasecmp(mods[i]->mod_type, "ipatokenOwner") == 0) { -- return send_error(pb, LDAP_UNWILLING_TO_PERFORM, -- "Can't change last active token's owner"); -- } -- -- if (strcasecmp(mods[i]->mod_type, "ipatokenNotBefore") == 0) { -- return send_error(pb, LDAP_UNWILLING_TO_PERFORM, -- "Can't change last active token's start time"); -- } -+ if (is_allowed(pb, entry)) -+ return 0; - -- if (strcasecmp(mods[i]->mod_type, "ipatokenNotAfter") == 0) { -- return send_error(pb, LDAP_UNWILLING_TO_PERFORM, -- "Can't change last active token's end time"); -+ /* If a protected attribute is modified, deny. */ -+ for (int i = 0; mods != NULL && mods[i] != NULL; i++) { -+ for (int j = 0; errors[j].attr != NULL; j++) { -+ if (strcasecmp(mods[i]->mod_type, errors[j].attr) == 0) -+ return send_error(pb, LDAP_UNWILLING_TO_PERFORM, errors[j].msg); - } - } - - return 0; - } - --static int --preop_init(Slapi_PBlock *pb) -+static int preop_init(Slapi_PBlock *pb) - { - int ret = 0; - -@@ -160,15 +219,59 @@ preop_init(Slapi_PBlock *pb) - return ret; - } - --int --ipa_otp_lasttoken_init(Slapi_PBlock *pb) -+static int update_config(Slapi_PBlock *pb) -+{ -+ otp_config_update(otp_config, pb); -+ return 0; -+} -+ -+static int intpostop_init(Slapi_PBlock *pb) -+{ -+ int ret = 0; -+ -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *) update_config); -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *) update_config); -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *) update_config); -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *) update_config); -+ -+ return ret; -+} -+ -+static int postop_init(Slapi_PBlock *pb) - { - int ret = 0; - -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN, (void *) update_config); -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *) update_config); -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *) update_config); -+ ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *) update_config); -+ -+ return ret; -+} -+ -+int ipa_otp_lasttoken_init(Slapi_PBlock *pb) -+{ -+ static const Slapi_PluginDesc preop_desc = { -+ PLUGIN_NAME, -+ "FreeIPA", -+ "FreeIPA/1.0", -+ "Protect the user's last active token" -+ }; -+ -+ Slapi_ComponentId *plugin_id = NULL; -+ int ret = 0; -+ - ret |= slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id); - ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); - ret |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &preop_desc); - ret |= slapi_register_plugin("betxnpreoperation", 1, __func__, preop_init, -- PLUGIN_NAME, NULL, plugin_id); -+ PLUGIN_NAME " betxnpreoperation", NULL, plugin_id); -+ ret |= slapi_register_plugin("postoperation", 1, __func__, postop_init, -+ PLUGIN_NAME " postoperation", NULL, plugin_id); -+ ret |= slapi_register_plugin("internalpostoperation", 1, __func__, intpostop_init, -+ PLUGIN_NAME " internalpostoperation", NULL, plugin_id); -+ -+ /* NOTE: leak otp_config on process exit. */ -+ otp_config = otp_config_init(plugin_id); - return ret; - } --- -2.1.0 - diff --git a/SOURCES/0072-Fixed-vault-container-ownership.patch b/SOURCES/0072-Fixed-vault-container-ownership.patch new file mode 100644 index 0000000..284f9ac --- /dev/null +++ b/SOURCES/0072-Fixed-vault-container-ownership.patch @@ -0,0 +1,60 @@ +From 82738f7ef90586668761a4f1215a734ab8c25f5a Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Mon, 10 Aug 2015 20:57:58 +0200 +Subject: [PATCH] Fixed vault container ownership. + +The vault-add command has been fixed such that if the user/service +private vault container does not exist yet it will be created and +owned by the user/service instead of the vault creator. + +https://fedorahosted.org/freeipa/ticket/5194 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index b5a12d5c3da599d7f5afaed90f579ad3a23c27cd..88c63071f04462aa240a70d3a3eeac2d04e66062 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -704,12 +704,33 @@ class vault_add_internal(LDAPCreate): + else: + owner_dn = self.api.Object.user.get_dn(name) + ++ parent_dn = DN(*dn[1:]) ++ ++ container_dn = DN(self.api.Object.vault.container_dn, ++ self.api.env.basedn) ++ ++ services_dn = DN(('cn', 'services'), container_dn) ++ users_dn = DN(('cn', 'users'), container_dn) ++ ++ if dn.endswith(services_dn): ++ # service container should be owned by the service ++ service = parent_dn[0]['cn'] ++ parent_owner_dn = self.api.Object.service.get_dn(service) ++ ++ elif dn.endswith(users_dn): ++ # user container should be owned by the user ++ user = parent_dn[0]['cn'] ++ parent_owner_dn = self.api.Object.user.get_dn(user) ++ ++ else: ++ parent_owner_dn = owner_dn ++ + try: +- parent_dn = DN(*dn[1:]) +- self.obj.create_container(parent_dn, owner_dn) +- except errors.DuplicateEntry, e: ++ self.obj.create_container(parent_dn, parent_owner_dn) ++ except errors.DuplicateEntry as e: + pass + ++ # vault should be owned by the creator + entry_attrs['owner'] = owner_dn + + return dn +-- +2.4.3 + diff --git a/SOURCES/0073-add-hosts-and-hostgroup-options-to-allow-retrieve-ke.patch b/SOURCES/0073-add-hosts-and-hostgroup-options-to-allow-retrieve-ke.patch deleted file mode 100644 index 0e544cf..0000000 --- a/SOURCES/0073-add-hosts-and-hostgroup-options-to-allow-retrieve-ke.patch +++ /dev/null @@ -1,878 +0,0 @@ -From 1d57cf654de99077d7ece28f9210d1a2d5dee5b7 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 1 Dec 2014 10:15:21 +0100 -Subject: [PATCH] add --hosts and --hostgroup options to allow/retrieve keytab - methods - -`--hosts` and `--hostgroup` options added to: -* service-allow-create-keytab -* service-allow-retrieve-keytab -* service-disallow-create-keytab -* service-disallow-retrieve-keytab -* host-allow-create-keytab -* host-allow-retrieve-keytab -* host-disallow-create-keytab -* host-disallow-retrieve-keytab - -in order to allow hosts to retrieve keytab of their services or related hosts as described on http://www.freeipa.org/page/V4/Keytab_Retrieval design page - -https://fedorahosted.org/freeipa/ticket/4777 - -Reviewed-By: Jan Cholasta ---- - API.txt | 32 ++++++-- - VERSION | 4 +- - ipalib/plugins/host.py | 28 +++++-- - ipalib/plugins/service.py | 28 +++++-- - ipatests/test_xmlrpc/test_host_plugin.py | 109 ++++++++++++++++++++++++++-- - ipatests/test_xmlrpc/test_service_plugin.py | 92 ++++++++++++++++++++--- - 6 files changed, 257 insertions(+), 36 deletions(-) - -diff --git a/API.txt b/API.txt -index 2a63f1e2349f0df69433fa7cb742e269cd42d79f..e9768bf1e87d6679c439b98ed696b720937099d2 100644 ---- a/API.txt -+++ b/API.txt -@@ -1826,10 +1826,12 @@ output: Output('completed', , None) - output: Output('failed', , None) - output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) - command: host_allow_create_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('fqdn', attribute=True, cli_name='hostname', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -1838,10 +1840,12 @@ output: Output('completed', , None) - output: Output('failed', , None) - output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) - command: host_allow_retrieve_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('fqdn', attribute=True, cli_name='hostname', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -1866,10 +1870,12 @@ output: Output('result', , None) - output: Output('summary', (, ), None) - output: PrimaryKey('value', None, None) - command: host_disallow_create_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('fqdn', attribute=True, cli_name='hostname', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -1878,10 +1884,12 @@ output: Output('completed', , None) - output: Output('failed', , None) - output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) - command: host_disallow_retrieve_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('fqdn', attribute=True, cli_name='hostname', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -3529,10 +3537,12 @@ output: Output('completed', , None) - output: Output('failed', , None) - output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) - command: service_allow_create_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -3541,10 +3551,12 @@ output: Output('completed', , None) - output: Output('failed', , None) - output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) - command: service_allow_retrieve_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -3568,10 +3580,12 @@ output: Output('result', , None) - output: Output('summary', (, ), None) - output: PrimaryKey('value', None, None) - command: service_disallow_create_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -@@ -3580,10 +3594,12 @@ output: Output('completed', , None) - output: Output('failed', , None) - output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) - command: service_disallow_retrieve_keytab --args: 1,6,3 -+args: 1,8,3 - arg: Str('krbprincipalname', attribute=True, cli_name='principal', multivalue=False, primary_key=True, query=True, required=True) - option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') - option: Str('group*', alwaysask=True, cli_name='groups', csv=True) -+option: Str('host*', alwaysask=True, cli_name='hosts', csv=True) -+option: Str('hostgroup*', alwaysask=True, cli_name='hostgroups', csv=True) - option: Flag('no_members', autofill=True, default=False, exclude='webui') - option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') - option: Str('user*', alwaysask=True, cli_name='users', csv=True) -diff --git a/VERSION b/VERSION -index 750b5058867ca5f073a083009c4aadeeb0240c35..bfbce5604e79008afd2893e406c634718159b1e9 100644 ---- a/VERSION -+++ b/VERSION -@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 - # # - ######################################################## - IPA_API_VERSION_MAJOR=2 --IPA_API_VERSION_MINOR=109 --# Last change: npmccallum - display qrcode by default -+IPA_API_VERSION_MINOR=110 -+# Last change: pvoborni - allow to retrieve keytab by hosts -diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py -index c4d4bdf6473e0f34c8c68754d6c98e93d173d8fa..39a7d3c25b9cb56fca486b2500da5fe7bd4a6fbc 100644 ---- a/ipalib/plugins/host.py -+++ b/ipalib/plugins/host.py -@@ -211,12 +211,24 @@ host_output_params = ( - Str('ipaallowedtoperform_read_keys_group', - label=_('Groups allowed to retrieve keytab'), - ), -+ Str('ipaallowedtoperform_read_keys_host', -+ label=_('Hosts allowed to retrieve keytab'), -+ ), -+ Str('ipaallowedtoperform_read_keys_hostgroup', -+ label=_('Host Groups allowed to retrieve keytab'), -+ ), - Str('ipaallowedtoperform_write_keys_user', - label=_('Users allowed to create keytab'), - ), - Str('ipaallowedtoperform_write_keys_group', - label=_('Groups allowed to create keytab'), - ), -+ Str('ipaallowedtoperform_write_keys_host', -+ label=_('Hosts allowed to create keytab'), -+ ), -+ Str('ipaallowedtoperform_write_keys_hostgroup', -+ label=_('Host Groups allowed to create keytab'), -+ ), - Str('ipaallowedtoperform_read_keys', - label=_('Failed allowed to retrieve keytab'), - ), -@@ -284,8 +296,8 @@ class host(LDAPObject): - 'managing': ['host'], - 'memberofindirect': ['hostgroup', 'netgroup', 'role', 'hbacrule', - 'sudorule'], -- 'ipaallowedtoperform_read_keys': ['user', 'group'], -- 'ipaallowedtoperform_write_keys': ['user', 'group'], -+ 'ipaallowedtoperform_read_keys': ['user', 'group', 'host', 'hostgroup'], -+ 'ipaallowedtoperform_write_keys': ['user', 'group', 'host', 'hostgroup'], - } - bindable = True - relationships = { -@@ -1201,7 +1213,8 @@ class host_remove_managedby(LDAPRemoveMember): - - @register() - class host_allow_retrieve_keytab(LDAPAddMember): -- __doc__ = _('Allow users or groups to retrieve a keytab of this host.') -+ __doc__ = _('Allow users, groups, hosts or host groups to retrieve a keytab' -+ ' of this host.') - member_attributes = ['ipaallowedtoperform_read_keys'] - has_output_params = LDAPAddMember.has_output_params + host_output_params - -@@ -1219,7 +1232,8 @@ class host_allow_retrieve_keytab(LDAPAddMember): - - @register() - class host_disallow_retrieve_keytab(LDAPRemoveMember): -- __doc__ = _('Disallow users or groups to retrieve a keytab of this host.') -+ __doc__ = _('Disallow users, groups, hosts or host groups to retrieve a ' -+ 'keytab of this host.') - member_attributes = ['ipaallowedtoperform_read_keys'] - has_output_params = LDAPRemoveMember.has_output_params + host_output_params - -@@ -1236,7 +1250,8 @@ class host_disallow_retrieve_keytab(LDAPRemoveMember): - - @register() - class host_allow_create_keytab(LDAPAddMember): -- __doc__ = _('Allow users or groups to create a keytab of this host.') -+ __doc__ = _('Allow users, groups, hosts or host groups to create a keytab ' -+ 'of this host.') - member_attributes = ['ipaallowedtoperform_write_keys'] - has_output_params = LDAPAddMember.has_output_params + host_output_params - -@@ -1254,7 +1269,8 @@ class host_allow_create_keytab(LDAPAddMember): - - @register() - class host_disallow_create_keytab(LDAPRemoveMember): -- __doc__ = _('Disallow users or groups to create a keytab of this host.') -+ __doc__ = _('Disallow users, groups, hosts or host groups to create a ' -+ 'keytab of this host.') - member_attributes = ['ipaallowedtoperform_write_keys'] - has_output_params = LDAPRemoveMember.has_output_params + host_output_params - -diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py -index 2f703544452c6d7ee2de8eceeb5f2a26afed44f2..b37dc7b4bf56b69df204fd29e9487f1390197bbe 100644 ---- a/ipalib/plugins/service.py -+++ b/ipalib/plugins/service.py -@@ -137,12 +137,24 @@ output_params = ( - Str('ipaallowedtoperform_read_keys_group', - label=_('Groups allowed to retrieve keytab'), - ), -+ Str('ipaallowedtoperform_read_keys_host', -+ label=_('Hosts allowed to retrieve keytab'), -+ ), -+ Str('ipaallowedtoperform_read_keys_hostgroup', -+ label=_('Host Groups allowed to retrieve keytab'), -+ ), - Str('ipaallowedtoperform_write_keys_user', - label=_('Users allowed to create keytab'), - ), - Str('ipaallowedtoperform_write_keys_group', - label=_('Groups allowed to create keytab'), - ), -+ Str('ipaallowedtoperform_write_keys_host', -+ label=_('Hosts allowed to create keytab'), -+ ), -+ Str('ipaallowedtoperform_write_keys_hostgroup', -+ label=_('Host Groups allowed to create keytab'), -+ ), - Str('ipaallowedtoperform_read_keys', - label=_('Failed allowed to retrieve keytab'), - ), -@@ -350,8 +362,8 @@ class service(LDAPObject): - attribute_members = { - 'managedby': ['host'], - 'memberof': ['role'], -- 'ipaallowedtoperform_read_keys': ['user', 'group'], -- 'ipaallowedtoperform_write_keys': ['user', 'group'], -+ 'ipaallowedtoperform_read_keys': ['user', 'group', 'host', 'hostgroup'], -+ 'ipaallowedtoperform_write_keys': ['user', 'group', 'host', 'hostgroup'], - } - bindable = True - relationships = { -@@ -711,7 +723,8 @@ class service_remove_host(LDAPRemoveMember): - - @register() - class service_allow_retrieve_keytab(LDAPAddMember): -- __doc__ = _('Allow users or groups to retrieve a keytab of this service.') -+ __doc__ = _('Allow users, groups, hosts or host groups to retrieve a keytab' -+ ' of this service.') - member_attributes = ['ipaallowedtoperform_read_keys'] - has_output_params = LDAPAddMember.has_output_params + output_params - -@@ -729,7 +742,8 @@ class service_allow_retrieve_keytab(LDAPAddMember): - - @register() - class service_disallow_retrieve_keytab(LDAPRemoveMember): -- __doc__ = _('Disallow users or groups to retrieve a keytab of this service.') -+ __doc__ = _('Disallow users, groups, hosts or host groups to retrieve a ' -+ 'keytab of this service.') - member_attributes = ['ipaallowedtoperform_read_keys'] - has_output_params = LDAPRemoveMember.has_output_params + output_params - -@@ -746,7 +760,8 @@ class service_disallow_retrieve_keytab(LDAPRemoveMember): - - @register() - class service_allow_create_keytab(LDAPAddMember): -- __doc__ = _('Allow users or groups to create a keytab of this service.') -+ __doc__ = _('Allow users, groups, hosts or host groups to create a keytab ' -+ 'of this service.') - member_attributes = ['ipaallowedtoperform_write_keys'] - has_output_params = LDAPAddMember.has_output_params + output_params - -@@ -764,7 +779,8 @@ class service_allow_create_keytab(LDAPAddMember): - - @register() - class service_disallow_create_keytab(LDAPRemoveMember): -- __doc__ = _('Disallow users or groups to create a keytab of this service.') -+ __doc__ = _('Disallow users, groups, hosts or host groups to create a ' -+ 'keytab of this service.') - member_attributes = ['ipaallowedtoperform_write_keys'] - has_output_params = LDAPRemoveMember.has_output_params + output_params - -diff --git a/ipatests/test_xmlrpc/test_host_plugin.py b/ipatests/test_xmlrpc/test_host_plugin.py -index 67acb765fc1716e10ac7846d8780bf031c9f079e..1c46ce9131554b799d25a15922d26ccb92763e93 100644 ---- a/ipatests/test_xmlrpc/test_host_plugin.py -+++ b/ipatests/test_xmlrpc/test_host_plugin.py -@@ -147,6 +147,9 @@ group1 = u'group1' - group1_dn = get_group_dn(group1) - group2 = u'group2' - group2_dn = get_group_dn(group2) -+hostgroup1 = u'testhostgroup1' -+hostgroup1_dn = DN(('cn',hostgroup1),('cn','hostgroups'),('cn','accounts'), -+ api.env.basedn) - - class test_host(Declarative): - -@@ -1420,6 +1423,8 @@ class test_host_allowed_to(Declarative): - ('group_del', [group1], {}), - ('group_del', [group2], {}), - ('host_del', [fqdn1], {}), -+ ('host_del', [fqdn3], {}), -+ ('hostgroup_del', [hostgroup1], {}), - ] - - tests = [ -@@ -1503,6 +1508,49 @@ class test_host_allowed_to(Declarative): - ), - ), - ), -+ dict( -+ desc='Create %r' % fqdn3, -+ command=( -+ 'host_add', [fqdn3], -+ dict( -+ force=True, -+ ), -+ ), -+ expected=dict( -+ value=fqdn3, -+ summary=u'Added host "%s"' % fqdn3, -+ result=dict( -+ dn=dn3, -+ fqdn=[fqdn3], -+ krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)], -+ objectclass=objectclasses.host, -+ ipauniqueid=[fuzzy_uuid], -+ managedby_host=[fqdn3], -+ has_keytab=False, -+ has_password=False, -+ ), -+ ), -+ ), -+ -+ dict( -+ desc='Create %r' % hostgroup1, -+ command=('hostgroup_add', [hostgroup1], -+ dict(description=u'Test hostgroup 1') -+ ), -+ expected=dict( -+ value=hostgroup1, -+ summary=u'Added hostgroup "testhostgroup1"', -+ result=dict( -+ dn=hostgroup1_dn, -+ cn=[hostgroup1], -+ objectclass=objectclasses.hostgroup, -+ description=[u'Test hostgroup 1'], -+ ipauniqueid=[fuzzy_uuid], -+ mepmanagedentry=[DN(('cn',hostgroup1),('cn','ng'),('cn','alt'), -+ api.env.basedn)], -+ ), -+ ), -+ ), - - # verify - dict( -@@ -1513,6 +1561,8 @@ class test_host_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -@@ -1535,6 +1585,8 @@ class test_host_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[[user1, u'This entry is already a member']], - ), - ), -@@ -1553,20 +1605,25 @@ class test_host_allowed_to(Declarative): - desc='Allow %r, %r to a retrieve keytab of %r' % ( - group1, group2, fqdn1), - command=('host_allow_retrieve_keytab', [fqdn1], -- dict(group=[group1, group2])), -+ dict(group=[group1, group2], host=[fqdn3], -+ hostgroup=[hostgroup1])), - expected=dict( - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -- completed=2, -+ completed=4, - result=dict( - dn=dn1, - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1, group2], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1581,6 +1638,8 @@ class test_host_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[[user2, u'This entry is not a member']], - ), - ), -@@ -1590,6 +1649,8 @@ class test_host_allowed_to(Declarative): - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1, group2], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1604,6 +1665,8 @@ class test_host_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -@@ -1613,6 +1676,8 @@ class test_host_allowed_to(Declarative): - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1623,22 +1688,29 @@ class test_host_allowed_to(Declarative): - desc='Allow %r, %r to a create keytab of %r' % ( - group1, user1, fqdn1), - command=('host_allow_create_keytab', [fqdn1], -- dict(group=[group1, group2], user=[user1])), -+ dict(group=[group1, group2], user=[user1], host=[fqdn3], -+ hostgroup=[hostgroup1])), - expected=dict( - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -- completed=3, -+ completed=5, - result=dict( - dn=dn1, - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1, group2], -+ ipaallowedtoperform_write_keys_host=[fqdn3], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1648,12 +1720,15 @@ class test_host_allowed_to(Declarative): - dict( - desc='Duplicate add: %r, %r' % (user1, group1), - command=('host_allow_create_keytab', [fqdn1], -- dict(group=[group1], user=[user1])), -+ dict(group=[group1], user=[user1], host=[fqdn3], -+ hostgroup=[hostgroup1])), - expected=dict( - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[[group1, u'This entry is already a member']], -+ host=[[fqdn3, u'This entry is already a member']], - user=[[user1, u'This entry is already a member']], -+ hostgroup=[[hostgroup1, u'This entry is already a member']], - ), - ), - completed=0, -@@ -1662,8 +1737,12 @@ class test_host_allowed_to(Declarative): - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1, group2], -+ ipaallowedtoperform_write_keys_host=[fqdn3], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1678,6 +1757,8 @@ class test_host_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[[user2, u'This entry is not a member']], - ), - ), -@@ -1687,8 +1768,12 @@ class test_host_allowed_to(Declarative): - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1, group2], -+ ipaallowedtoperform_write_keys_host=[fqdn3], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1703,6 +1788,8 @@ class test_host_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -@@ -1712,8 +1799,12 @@ class test_host_allowed_to(Declarative): - fqdn=[fqdn1], - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1], -+ ipaallowedtoperform_write_keys_host=[fqdn3], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1733,8 +1824,12 @@ class test_host_allowed_to(Declarative): - has_password=False, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1], -+ ipaallowedtoperform_write_keys_host=[fqdn3], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -@@ -1756,8 +1851,12 @@ class test_host_allowed_to(Declarative): - has_password=False, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn3], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1], -+ ipaallowedtoperform_write_keys_host=[fqdn3], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)], - managedby_host=[fqdn1], - ), -diff --git a/ipatests/test_xmlrpc/test_service_plugin.py b/ipatests/test_xmlrpc/test_service_plugin.py -index 927ce73f86a0025b8384cf0126ef00be3598975a..946dc572b0d0e5b3f26cd7bfd6ad8128f113493f 100644 ---- a/ipatests/test_xmlrpc/test_service_plugin.py -+++ b/ipatests/test_xmlrpc/test_service_plugin.py -@@ -54,6 +54,9 @@ group1 = u'group1' - group1_dn = get_group_dn(group1) - group2 = u'group2' - group2_dn = get_group_dn(group2) -+hostgroup1 = u'testhostgroup1' -+hostgroup1_dn = DN(('cn',hostgroup1),('cn','hostgroups'),('cn','accounts'), -+ api.env.basedn) - - class test_service(Declarative): - -@@ -770,6 +773,7 @@ class test_service_allowed_to(Declarative): - ('group_del', [group2], {}), - ('host_del', [fqdn1], {}), - ('service_del', [service1], {}), -+ ('hostgroup_del', [hostgroup1], {}), - ] - - tests = [ -@@ -858,6 +862,25 @@ class test_service_allowed_to(Declarative): - ), - ), - dict( -+ desc='Create %r' % hostgroup1, -+ command=('hostgroup_add', [hostgroup1], -+ dict(description=u'Test hostgroup 1') -+ ), -+ expected=dict( -+ value=hostgroup1, -+ summary=u'Added hostgroup "testhostgroup1"', -+ result=dict( -+ dn=hostgroup1_dn, -+ cn=[hostgroup1], -+ objectclass=objectclasses.hostgroup, -+ description=[u'Test hostgroup 1'], -+ ipauniqueid=[fuzzy_uuid], -+ mepmanagedentry=[DN(('cn',hostgroup1),('cn','ng'),('cn','alt'), -+ api.env.basedn)], -+ ), -+ ), -+ ), -+ dict( - desc='Create %r' % service1, - command=('service_add', [service1_no_realm], dict(force=True)), - expected=dict( -@@ -882,6 +905,8 @@ class test_service_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -@@ -903,6 +928,8 @@ class test_service_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[[user1, u'This entry is already a member']], - ), - ), -@@ -917,22 +944,27 @@ class test_service_allowed_to(Declarative): - ), - - dict( -- desc='Allow %r, %r to a retrieve keytab of %r' % ( -- group1, group2, service1), -+ desc='Allow %r, %r, %r to a retrieve keytab of %r' % ( -+ group1, group2, fqdn1, service1), - command=('service_allow_retrieve_keytab', [service1], -- dict(group=[group1, group2])), -+ dict(group=[group1, group2], host=[fqdn1], -+ hostgroup=[hostgroup1])), - expected=dict( - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -- completed=2, -+ completed=4, - result=dict( - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1, group2], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -947,6 +979,8 @@ class test_service_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[[user2, u'This entry is not a member']], - ), - ), -@@ -955,6 +989,8 @@ class test_service_allowed_to(Declarative): - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1, group2], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -969,6 +1005,8 @@ class test_service_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_read_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -@@ -977,6 +1015,8 @@ class test_service_allowed_to(Declarative): - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -984,24 +1024,31 @@ class test_service_allowed_to(Declarative): - ), - - dict( -- desc='Allow %r, %r to a create keytab of %r' % ( -- group1, user1, service1), -+ desc='Allow %r, %r, %r to a create keytab of %r' % ( -+ group1, user1, fqdn1, service1), - command=('service_allow_create_keytab', [service1], -- dict(group=[group1, group2], user=[user1])), -+ dict(group=[group1, group2], user=[user1], host=[fqdn1], -+ hostgroup=[hostgroup1])), - expected=dict( - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -- completed=3, -+ completed=5, - result=dict( - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1, group2], -+ ipaallowedtoperform_write_keys_host=[fqdn1], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -1011,12 +1058,15 @@ class test_service_allowed_to(Declarative): - dict( - desc='Duplicate add: %r, %r' % (user1, group1), - command=('service_allow_create_keytab', [service1], -- dict(group=[group1], user=[user1])), -+ dict(group=[group1], user=[user1], host=[fqdn1], -+ hostgroup=[hostgroup1])), - expected=dict( - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[[group1, u'This entry is already a member']], -+ host=[[fqdn1, u'This entry is already a member']], - user=[[user1, u'This entry is already a member']], -+ hostgroup=[[hostgroup1, u'This entry is already a member']], - ), - ), - completed=0, -@@ -1024,8 +1074,12 @@ class test_service_allowed_to(Declarative): - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1, group2], -+ ipaallowedtoperform_write_keys_host=[fqdn1], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -1040,6 +1094,8 @@ class test_service_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[[user2, u'This entry is not a member']], - ), - ), -@@ -1048,8 +1104,12 @@ class test_service_allowed_to(Declarative): - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1, group2], -+ ipaallowedtoperform_write_keys_host=[fqdn1], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -1064,6 +1124,8 @@ class test_service_allowed_to(Declarative): - failed=dict( - ipaallowedtoperform_write_keys=dict( - group=[], -+ host=[], -+ hostgroup=[], - user=[], - ), - ), -@@ -1072,8 +1134,12 @@ class test_service_allowed_to(Declarative): - dn=service1dn, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1], -+ ipaallowedtoperform_write_keys_host=[fqdn1], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -1091,8 +1157,12 @@ class test_service_allowed_to(Declarative): - has_keytab=False, - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1], -+ ipaallowedtoperform_write_keys_host=[fqdn1], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - krbprincipalname=[service1], - managedby_host=[fqdn1], - ), -@@ -1110,8 +1180,12 @@ class test_service_allowed_to(Declarative): - result=dict( - ipaallowedtoperform_read_keys_user=[user1], - ipaallowedtoperform_read_keys_group=[group1], -+ ipaallowedtoperform_read_keys_host=[fqdn1], -+ ipaallowedtoperform_read_keys_hostgroup=[hostgroup1], - ipaallowedtoperform_write_keys_user=[user1], - ipaallowedtoperform_write_keys_group=[group1], -+ ipaallowedtoperform_write_keys_host=[fqdn1], -+ ipaallowedtoperform_write_keys_hostgroup=[hostgroup1], - ipakrbokasdelegate=True, - krbprincipalname=[service1], - krbticketflags=[u'1048704'], --- -2.1.0 - diff --git a/SOURCES/0073-vault-normalize-service-principal-in-service-vault-o.patch b/SOURCES/0073-vault-normalize-service-principal-in-service-vault-o.patch new file mode 100644 index 0000000..328a3da --- /dev/null +++ b/SOURCES/0073-vault-normalize-service-principal-in-service-vault-o.patch @@ -0,0 +1,36 @@ +From 9e930edf8b3b4e65bf39043e7b033f0b5537b7e3 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 18 Aug 2015 12:14:36 +0200 +Subject: [PATCH] vault: normalize service principal in service vault + operations + +https://fedorahosted.org/freeipa/ticket/5233 + +Reviewed-By: Jan Cholasta +--- + ipalib/plugins/vault.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 88c63071f04462aa240a70d3a3eeac2d04e66062..a1508b63b8c8aa506eadad415ecf7fa4942c74fc 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -47,6 +47,7 @@ from ipalib.plugins.baseldap import LDAPObject, LDAPCreate, LDAPDelete,\ + LDAPModMember, pkey_to_value + from ipalib.request import context + from ipalib.plugins.user import split_principal ++from ipalib.plugins.service import normalize_principal + from ipalib import _, ngettext + from ipaplatform.paths import paths + from ipapython.dn import DN +@@ -214,6 +215,7 @@ vault_options = ( + Str( + 'service?', + doc=_('Service name of the service vault'), ++ normalizer=normalize_principal, + ), + Flag( + 'shared?', +-- +2.4.3 + diff --git a/SOURCES/0074-hosts-Display-assigned-ID-view-by-default-in-host-fi.patch b/SOURCES/0074-hosts-Display-assigned-ID-view-by-default-in-host-fi.patch deleted file mode 100644 index 906a2dc..0000000 --- a/SOURCES/0074-hosts-Display-assigned-ID-view-by-default-in-host-fi.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 4acf45785f917bb52382202279d5931469198f26 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Tue, 2 Dec 2014 15:40:40 +0100 -Subject: [PATCH] hosts: Display assigned ID view by default in host-find and - show commands - -Makes ipaassignedidview a default attribute and takes care about the -conversion from the DN to the proper ID view name. - -https://fedorahosted.org/freeipa/ticket/4774 - -Reviewed-By: Petr Vobornik -Reviewed-By: Jan Cholasta ---- - API.txt | 6 +++--- - VERSION | 4 ++-- - install/ui/src/freeipa/host.js | 1 - - ipalib/plugins/host.py | 21 ++++++++++++++++++--- - 4 files changed, 23 insertions(+), 9 deletions(-) - -diff --git a/API.txt b/API.txt -index e9768bf1e87d6679c439b98ed696b720937099d2..7949c49f9fb9e3cd7eceb64a05dd8e550eb48f8b 100644 ---- a/API.txt -+++ b/API.txt -@@ -1793,7 +1793,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui - option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False) - option: Flag('force', autofill=True, default=False) - option: Str('ip_address?') --option: DNParam('ipaassignedidview', attribute=True, cli_name='ipaassignedidview', multivalue=False, required=False) -+option: Str('ipaassignedidview', attribute=True, cli_name='ipaassignedidview', multivalue=False, required=False) - option: Bool('ipakrbokasdelegate', attribute=False, cli_name='ok_as_delegate', multivalue=False, required=False) - option: Bool('ipakrbrequirespreauth', attribute=False, cli_name='requires_pre_auth', multivalue=False, required=False) - option: Str('ipasshpubkey', attribute=True, cli_name='sshpubkey', csv=True, multivalue=True, required=False) -@@ -1909,7 +1909,7 @@ option: Str('in_hostgroup*', cli_name='in_hostgroups', csv=True) - option: Str('in_netgroup*', cli_name='in_netgroups', csv=True) - option: Str('in_role*', cli_name='in_roles', csv=True) - option: Str('in_sudorule*', cli_name='in_sudorules', csv=True) --option: DNParam('ipaassignedidview', attribute=True, autofill=False, cli_name='ipaassignedidview', multivalue=False, query=True, required=False) -+option: Str('ipaassignedidview', attribute=True, autofill=False, cli_name='ipaassignedidview', multivalue=False, query=True, required=False) - option: Str('l', attribute=True, autofill=False, cli_name='locality', multivalue=False, query=True, required=False) - option: Str('macaddress', attribute=True, autofill=False, cli_name='macaddress', csv=True, multivalue=True, pattern='^([a-fA-F0-9]{2}[:|\\-]?){5}[a-fA-F0-9]{2}$', query=True, required=False) - option: Str('man_by_host*', cli_name='man_by_hosts', csv=True) -@@ -1945,7 +1945,7 @@ 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('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False) --option: DNParam('ipaassignedidview', attribute=True, autofill=False, cli_name='ipaassignedidview', multivalue=False, required=False) -+option: Str('ipaassignedidview', attribute=True, autofill=False, cli_name='ipaassignedidview', multivalue=False, required=False) - option: Bool('ipakrbokasdelegate', attribute=False, autofill=False, cli_name='ok_as_delegate', multivalue=False, required=False) - option: Bool('ipakrbrequirespreauth', attribute=False, autofill=False, cli_name='requires_pre_auth', multivalue=False, required=False) - option: Str('ipasshpubkey', attribute=True, autofill=False, cli_name='sshpubkey', csv=True, multivalue=True, required=False) -diff --git a/VERSION b/VERSION -index bfbce5604e79008afd2893e406c634718159b1e9..196be85e83de96f501352ca93f2c7ed6876ea641 100644 ---- a/VERSION -+++ b/VERSION -@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 - # # - ######################################################## - IPA_API_VERSION_MAJOR=2 --IPA_API_VERSION_MINOR=110 --# Last change: pvoborni - allow to retrieve keytab by hosts -+IPA_API_VERSION_MINOR=112 -+# Last change: tbabej - change ipaassignedidview to Str -diff --git a/install/ui/src/freeipa/host.js b/install/ui/src/freeipa/host.js -index 455ff8f50ec58104d4e046ec0fabf2a7e89eeeb2..1120c82e708f20081ee9ec5f5c1b4c349d101b15 100644 ---- a/install/ui/src/freeipa/host.js -+++ b/install/ui/src/freeipa/host.js -@@ -117,7 +117,6 @@ return { - name: 'ipaassignedidview', - $type: 'link', - label: '@i18n:objects.idview.ipaassignedidview', -- ui_formatter: 'dn', - other_entity: 'idview' - } - ] -diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py -index 39a7d3c25b9cb56fca486b2500da5fe7bd4a6fbc..41710f3b87b5f60ac6e9b0765a25562b7074e2e8 100644 ---- a/ipalib/plugins/host.py -+++ b/ipalib/plugins/host.py -@@ -22,7 +22,7 @@ from nss.error import NSPRError - import string - - from ipalib import api, errors, util --from ipalib import Str, Flag, Bytes, DNParam -+from ipalib import Str, Flag, Bytes - from ipalib.plugable import Registry - from ipalib.plugins.baseldap import (LDAPQuery, LDAPObject, LDAPCreate, - LDAPDelete, LDAPUpdate, LDAPSearch, -@@ -162,6 +162,17 @@ def update_sshfp_record(zone, record, entry_attrs): - except errors.EmptyModlist: - pass - -+ -+def convert_ipaassignedidview_post(entry_attrs, options): -+ """ -+ Converts the ID View DN to its name for the better looking output. -+ """ -+ -+ if 'ipaassignedidview' in entry_attrs and not options.get('raw'): -+ idview_name = entry_attrs.single_value['ipaassignedidview'][0].value -+ entry_attrs.single_value['ipaassignedidview'] = idview_name -+ -+ - host_output_params = ( - Flag('has_keytab', - label=_('Keytab'), -@@ -286,7 +297,7 @@ class host(LDAPObject): - 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', - 'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof', - 'managedby', 'memberindirect', 'memberofindirect', 'macaddress', -- 'userclass', 'ipaallowedtoperform' -+ 'userclass', 'ipaallowedtoperform', 'ipaassignedidview', - ] - uuid_attribute = 'ipauniqueid' - attribute_members = { -@@ -513,7 +524,8 @@ class host(LDAPObject): - doc=_('Host category (semantics placed on this attribute are for ' - 'local interpretation)'), - ), -- DNParam('ipaassignedidview?', -+ Str('ipaassignedidview?', -+ label=_('Assigned ID View'), - flags=['no_option'], - ), - ) + ticket_flags_params -@@ -949,6 +961,7 @@ class host_mod(LDAPUpdate): - self.obj.suppress_netgroup_memberof(ldap, entry_attrs) - - convert_sshpubkey_post(ldap, dn, entry_attrs) -+ convert_ipaassignedidview_post(entry_attrs, options) - - return dn - -@@ -1035,6 +1048,7 @@ class host_find(LDAPSearch): - entry_attrs['managing'] = self.obj.get_managed_hosts(entry_attrs.dn) - - convert_sshpubkey_post(ldap, entry_attrs.dn, entry_attrs) -+ convert_ipaassignedidview_post(entry_attrs, options) - - return truncated - -@@ -1070,6 +1084,7 @@ class host_show(LDAPRetrieve): - self.obj.suppress_netgroup_memberof(ldap, entry_attrs) - - convert_sshpubkey_post(ldap, dn, entry_attrs) -+ convert_ipaassignedidview_post(entry_attrs, options) - - return dn - --- -2.1.0 - diff --git a/SOURCES/0074-vault-validate-vault-type.patch b/SOURCES/0074-vault-validate-vault-type.patch new file mode 100644 index 0000000..5440f69 --- /dev/null +++ b/SOURCES/0074-vault-validate-vault-type.patch @@ -0,0 +1,87 @@ +From fc704bf5248ae3b224ce5066231bb826008f375d Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 18 Aug 2015 12:50:54 +0200 +Subject: [PATCH] vault: validate vault type + +https://fedorahosted.org/freeipa/ticket/5211 + +Reviewed-By: Jan Cholasta +--- + API.txt | 6 +++--- + VERSION | 4 ++-- + ipalib/plugins/vault.py | 5 +++-- + 3 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/API.txt b/API.txt +index 71df3a56595a012e6382414ad4453d30ede8155b..a39b22b602e0baf5d283732d18d83b2a25d5cf50 100644 +--- a/API.txt ++++ b/API.txt +@@ -5423,7 +5423,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui + option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False) + option: Bytes('ipavaultpublickey', attribute=True, cli_name='public_key', multivalue=False, required=False) + option: Bytes('ipavaultsalt', attribute=True, cli_name='salt', multivalue=False, required=False) +-option: Str('ipavaulttype', attribute=True, autofill=True, cli_name='type', default=u'standard', multivalue=False, required=False) ++option: StrEnum('ipavaulttype', attribute=True, autofill=True, cli_name='type', default=u'standard', multivalue=False, required=False, values=(u'standard', u'symmetric', u'asymmetric')) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') +@@ -5513,7 +5513,7 @@ arg: Str('criteria?', noextrawhitespace=False) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('cn', attribute=True, autofill=False, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=False) + option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False) +-option: Str('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'standard', multivalue=False, query=True, required=False) ++option: StrEnum('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'standard', multivalue=False, query=True, required=False, values=(u'standard', u'symmetric', u'asymmetric')) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('pkey_only?', autofill=True, default=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +@@ -5536,7 +5536,7 @@ option: Str('delattr*', cli_name='delattr', exclude='webui') + option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False) + option: Bytes('ipavaultpublickey', attribute=True, autofill=False, cli_name='public_key', multivalue=False, required=False) + option: Bytes('ipavaultsalt', attribute=True, autofill=False, cli_name='salt', multivalue=False, required=False) +-option: Str('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'standard', multivalue=False, required=False) ++option: StrEnum('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'standard', multivalue=False, required=False, values=(u'standard', u'symmetric', u'asymmetric')) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Flag('rights', autofill=True, default=False) +diff --git a/VERSION b/VERSION +index 69351a8fa8e27c884c130ab49d3fab541cd09ff9..6569eeb70fa4e8065b5abb9dc89bd4cc6d42bd15 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=149 +-# Last change: edewata - Added CLI param and ACL for vault service operations ++IPA_API_VERSION_MINOR=150 ++# Last change: pvoborni - change type of vault type option to StrEnum +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index a1508b63b8c8aa506eadad415ecf7fa4942c74fc..4d430ee88658e7ba7f2863ca4ef1e8672e298923 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -38,7 +38,7 @@ import krbV + + from ipalib.frontend import Command, Object, Local + from ipalib import api, errors +-from ipalib import Bytes, Str, Flag ++from ipalib import Bytes, Flag, Str, StrEnum + from ipalib import output + from ipalib.crud import PKQuery, Retrieve, Update + from ipalib.plugable import Registry +@@ -279,11 +279,12 @@ class vault(LDAPObject): + label=_('Description'), + doc=_('Vault description'), + ), +- Str( ++ StrEnum( + 'ipavaulttype?', + cli_name='type', + label=_('Type'), + doc=_('Vault type'), ++ values=(u'standard', u'symmetric', u'asymmetric', ), + default=u'standard', + autofill=True, + ), +-- +2.4.3 + diff --git a/SOURCES/0075-Prefer-TCP-connections-to-UDP-in-krb5-clients.patch b/SOURCES/0075-Prefer-TCP-connections-to-UDP-in-krb5-clients.patch deleted file mode 100644 index 42e9d66..0000000 --- a/SOURCES/0075-Prefer-TCP-connections-to-UDP-in-krb5-clients.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 0538c3040f65dea97a8e98eab7be2c8fc8ff17a9 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Fri, 5 Dec 2014 11:18:55 -0500 -Subject: [PATCH] Prefer TCP connections to UDP in krb5 clients - -In general, TCP is a better fit for FreeIPA due to large packet sizes. - -However, there is also a specific need for TCP when using OTP. If a UDP -packet is delivered to the server and the server takes longer to process -it than the client timeout (likely), the OTP value will be resent. -Unfortunately, this will cause failures or even lockouts. Switching to -TCP avoids this problem altogether. - -https://fedorahosted.org/freeipa/ticket/4725 - -Reviewed-By: Martin Kosek ---- - install/share/krb5.conf.template | 1 + - install/tools/ipa-replica-conncheck | 1 + - ipa-client/ipa-install/ipa-client-install | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/install/share/krb5.conf.template b/install/share/krb5.conf.template -index 7c82083e3331cfacccc1995cd9dfa6ddd88edd1f..6cb5ee34704cd6158e882bfa89fc597f3ff1bb0f 100644 ---- a/install/share/krb5.conf.template -+++ b/install/share/krb5.conf.template -@@ -12,6 +12,7 @@ includedir /var/lib/sss/pubconf/krb5.include.d/ - rdns = false - ticket_lifetime = 24h - forwardable = yes -+ udp_preference_limit = 0 - $OTHER_LIBDEFAULTS - [realms] - $REALM = { -diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck -index 88e42bafbc600fb7c36b7727c770e75edccd2196..22348fc2158e59afc2e1aa51e3d3f51e90b99e39 100755 ---- a/install/tools/ipa-replica-conncheck -+++ b/install/tools/ipa-replica-conncheck -@@ -208,6 +208,7 @@ def configure_krb5_conf(realm, kdc, filename): - libdefaults.append({'name':'rdns', 'type':'option', 'value':'false'}) - libdefaults.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'}) - libdefaults.append({'name':'forwardable', 'type':'option', 'value':'yes'}) -+ libdefaults.append({'name':'udp_preference_limit', 'type':'option', 'value':'0'}) - - opts.append({'name':'libdefaults', 'type':'section', 'value': libdefaults}) - opts.append({'name':'empty', 'type':'empty'}) -diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install -index 7b1e2f8b0b873375c14d02558dce65b68a5ad173..75a1711a7e1fdc9359ad02d55ad94d65af51ea93 100755 ---- a/ipa-client/ipa-install/ipa-client-install -+++ b/ipa-client/ipa-install/ipa-client-install -@@ -1047,6 +1047,7 @@ def configure_krb5_conf(cli_realm, cli_domain, cli_server, cli_kdc, dnsok, - libopts.append({'name':'rdns', 'type':'option', 'value':'false'}) - libopts.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'}) - libopts.append({'name':'forwardable', 'type':'option', 'value':'yes'}) -+ libopts.append({'name':'udp_preference_limit', 'type':'option', 'value':'0'}) - - # Configure KEYRING CCACHE if supported - if kernel_keyring.is_persistent_keyring_supported(): --- -2.1.0 - diff --git a/SOURCES/0075-install-Fix-replica-install-with-custom-certificates.patch b/SOURCES/0075-install-Fix-replica-install-with-custom-certificates.patch new file mode 100644 index 0000000..6753e81 --- /dev/null +++ b/SOURCES/0075-install-Fix-replica-install-with-custom-certificates.patch @@ -0,0 +1,43 @@ +From c2a1e876492bc630d3d5f74a2482cf9c94be763d Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 18 Aug 2015 12:51:26 +0200 +Subject: [PATCH] install: Fix replica install with custom certificates + +https://fedorahosted.org/freeipa/ticket/5226 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/replicainstall.py | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index dd8bc0d4bb7d8d9835a3e3e4dc24d1f67199d28f..0725c7763e505ca0cc5a8892414a3c36c557cf1d 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -573,14 +573,15 @@ def install(installer): + otpd.create_instance('OTPD', config.host_name, config.dirman_password, + ipautil.realm_to_suffix(config.realm_name)) + +- CA = cainstance.CAInstance( +- config.realm_name, certs.NSS_DIR, +- dogtag_constants=dogtag_constants) +- CA.dm_password = config.dirman_password +- +- CA.configure_certmonger_renewal() +- CA.import_ra_cert(config.dir + "/ra.p12") +- CA.fix_ra_perms() ++ if ipautil.file_exists(config.dir + "/cacert.p12"): ++ CA = cainstance.CAInstance( ++ config.realm_name, certs.NSS_DIR, ++ dogtag_constants=dogtag_constants) ++ CA.dm_password = config.dirman_password ++ ++ CA.configure_certmonger_renewal() ++ CA.import_ra_cert(config.dir + "/ra.p12") ++ CA.fix_ra_perms() + + # The DS instance is created before the keytab, add the SSL cert we + # generated +-- +2.4.3 + diff --git a/SOURCES/0076-trusts-harden-trust-fetch-domains-oddjobd-based-scri.patch b/SOURCES/0076-trusts-harden-trust-fetch-domains-oddjobd-based-scri.patch new file mode 100644 index 0000000..afdc77b --- /dev/null +++ b/SOURCES/0076-trusts-harden-trust-fetch-domains-oddjobd-based-scri.patch @@ -0,0 +1,135 @@ +From 2c577bc650613f5adfcc1efed0bfa40187eb362e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 13 Aug 2015 17:18:57 +0300 +Subject: [PATCH] trusts: harden trust-fetch-domains oddjobd-based script + +When ipa-getkeytab is used to fetch trusted domain object credentials, +the fetched entry has always kvno 1. ipa-getkeytab always adds a key to +keytab which means older key versions will be in the SSSD keytab and +will confuse libkrb5 ccache initialization code as all kvno values are +equal to 1. Wrong key is picked up then and kinit fails. + +To solve this problem, always remove existing +/var/lib/sss/keytabs/forest.keytab before retrieving a new one. + +To make sure script's input cannot be used to define what should be +removed (by passing a relative path), make sure we retrieve trusted +forest name from LDAP. If it is not possible to retrieve, the script +will issue an exception and quit. If abrtd is running, this will be +recorded as a 'crash' and an attempt to use script by malicious user +would be recorded as well in the abrtd journal. + +Additionally, as com.redhat.idm.trust-fetch-domains will create +ID ranges for the domains of the trusted forest if they don't exist, +it needs permissions to do so. The permission should be granted only +to cifs/ipa.master@IPA.REALM services which means they must have +krbprincipalname=cifs/*@IPA.REALM,cn=services,... DN and be members of +cn=adtrust agents,cn=sysaccounts,... group. + +Solves https://bugzilla.redhat.com/show_bug.cgi?id=1250190 + +Ticket https://fedorahosted.org/freeipa/ticket/5182 + +Reviewed-By: Tomas Babej +--- + install/oddjob/com.redhat.idm.trust-fetch-domains | 29 +++++++++++++++++++---- + install/updates/20-aci.update | 4 ++++ + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains +index e50c81e50e73b258bf08737c2d9a13a8832eb69f..6a2171d5f1936fabd00081bbbcea562a0e7041b8 100755 +--- a/install/oddjob/com.redhat.idm.trust-fetch-domains ++++ b/install/oddjob/com.redhat.idm.trust-fetch-domains +@@ -41,6 +41,9 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): + "-p", oneway_principal, + "-k", oneway_keytab_name, + "-r"] ++ if os.path.isfile(oneway_keytab_name): ++ os.unlink(oneway_keytab_name) ++ + (stdout, stderr, retcode) = ipautil.run(getkeytab_args, + env={'KRB5CCNAME': ccache_name, 'LANG': 'C'}, + raiseonerr=False) +@@ -111,7 +114,6 @@ from ipalib.plugins import trust + # retrieve the keys to oneway_keytab_name. + + keytab_name = '/etc/samba/samba.keytab' +-oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab' + + principal = str('cifs/' + api.env.host) + +@@ -137,10 +139,20 @@ else: + old_ccache = os.environ.get('KRB5CCNAME') + api.Backend.ldap2.connect(ccache) + ++# Retrieve own NetBIOS name and trusted forest's name. ++# We use script's input to retrieve the trusted forest's name to sanitize input ++# for file-level access as we might need to wipe out keytab in /var/lib/sss/keytabs + own_trust_dn = DN(('cn', api.env.domain),('cn','ad'), ('cn', 'etc'), api.env.basedn) + own_trust_entry = api.Backend.ldap2.get_entry(own_trust_dn, ['ipantflatname']) +-own_trust_flatname = own_trust_entry['ipantflatname'][0].upper() ++own_trust_flatname = own_trust_entry.single_value.get('ipantflatname').upper() ++trusted_domain_dn = DN(('cn', trusted_domain.lower()), api.env.container_adtrusts, api.env.basedn) ++trusted_domain_entry = api.Backend.ldap2.get_entry(trusted_domain_dn, ['cn']) ++trusted_domain = trusted_domain_entry.single_value.get('cn').lower() + ++# At this point if we didn't find trusted forest name, an exception will be raised ++# and script will quit. This is actually intended. ++ ++oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab' + oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper())) + + # If keytab does not exist, retrieve it +@@ -152,11 +164,18 @@ try: + # The keytab may have stale key material (from older trust-add run) + if not os.path.isfile(oneway_ccache_name): + oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) ++ else: ++ oneway_ccache_check = KRB5_CCache(oneway_ccache_name) ++ if not oneway_ccache_check.credential_is_valid(oneway_principal): ++ # If credentials were invalid, obtain them again ++ oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) ++ else: ++ oneway_ccache = oneway_ccache_check.ccache + except krbV.Krb5Error as e: + # If there was failure on using keytab, assume it is stale and retrieve again + retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal) + +-if oneway_ccache: ++try: + # There wasn existing ccache, validate its content + oneway_ccache_check = KRB5_CCache(oneway_ccache_name) + if not oneway_ccache_check.credential_is_valid(oneway_principal): +@@ -164,7 +183,7 @@ if oneway_ccache: + oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) + else: + oneway_ccache = oneway_ccache_check.ccache +-else: ++except krbV.Krb5Error as e: + oneway_ccache = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) + + # We are done: we have ccache with TDO credentials and can fetch domains +@@ -193,7 +212,7 @@ if domains: + dom['range_type'] = u'ipa-ad-trust' + # Do not pass ipaserver.dcerpc.TrustInstance to trust.add_range + # to force it using existing credentials cache +- trust.add_range(None, range_name, dom['ipanttrusteddomainsid'], ++ trust.add_range(api, None, range_name, dom['ipanttrusteddomainsid'], + trusted_domain, name, **dom) + except errors.DuplicateEntry: + # Ignore updating duplicate entries +diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update +index 0bdeeb6acefad4f79385a1ddaec95df2e40377fb..cba1897e1fd1136fbcbd7c6ccaf03bfa4b696a44 100644 +--- a/install/updates/20-aci.update ++++ b/install/updates/20-aci.update +@@ -87,3 +87,7 @@ add:aci:(targetattr = "usercertificate")(version 3.0;acl "selfservice:Users can + # Hosts can add their own services + dn: cn=services,cn=accounts,$SUFFIX + add:aci: (target = "ldap:///krbprincipalname=*/($$dn)@$REALM,cn=services,cn=accounts,$SUFFIX")(targetfilter = "(objectClass=ipaKrbPrincipal)")(version 3.0;acl "Hosts can add own services"; allow(add) userdn="ldap:///fqdn=($$dn),cn=computers,cn=accounts,$SUFFIX";) ++ ++# CIFS service on the master can manage ID ranges ++dn: cn=ranges,cn=etc,$SUFFIX ++add:aci: (target = "ldap:///cn=*,cn=ranges,cn=etc,$SUFFIX")(targetfilter = "(objectClass=ipaIDrange)")(version 3.0;acl "CIFS service can manage ID ranges for trust"; allow(all) userdn="ldap:///krbprincipalname=cifs/*@$REALM,cn=services,cn=accounts,$SUFFIX" and groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";) +-- +2.4.3 + diff --git a/SOURCES/0076-webui-fix-service-unprovisioning.patch b/SOURCES/0076-webui-fix-service-unprovisioning.patch deleted file mode 100644 index 89d44ef..0000000 --- a/SOURCES/0076-webui-fix-service-unprovisioning.patch +++ /dev/null @@ -1,30 +0,0 @@ -From e70d7becc295aacdc1c90f64fe65266a8c0d0205 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Thu, 27 Nov 2014 12:47:42 +0100 -Subject: [PATCH] webui: fix service unprovisioning - -Missed part of field refactoring caused that service could not be unprovisioned. - -https://fedorahosted.org/freeipa/ticket/4770 - -Reviewed-By: Martin Basti ---- - install/ui/src/freeipa/service.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/service.js b/install/ui/src/freeipa/service.js -index 3e47981bdbda9cd076eab75da0f5133503af6f3d..94842a912c77a55acad9d2f0881f3ad23915f700 100644 ---- a/install/ui/src/freeipa/service.js -+++ b/install/ui/src/freeipa/service.js -@@ -467,7 +467,7 @@ IPA.service.unprovision_dialog = function(spec) { - that.unprovision = function() { - - var principal_f = that.facet.fields.get_field('krbprincipalname'); -- var pkey = principal_f.values[0]; -+ var pkey = principal_f.get_value()[0]; - - rpc.command({ - entity: that.entity.name, --- -2.1.0 - diff --git a/SOURCES/0077-user-undel-Fix-error-messages.patch b/SOURCES/0077-user-undel-Fix-error-messages.patch new file mode 100644 index 0000000..fb41e39 --- /dev/null +++ b/SOURCES/0077-user-undel-Fix-error-messages.patch @@ -0,0 +1,41 @@ +From f021f35447a0b71957b2294b1000f9229ea064f6 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Thu, 13 Aug 2015 08:11:38 +0200 +Subject: [PATCH] user-undel: Fix error messages. + +https://fedorahosted.org/freeipa/ticket/5207 + +Reviewed-By: Martin Basti +--- + ipalib/plugins/user.py | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 90ae7260abf935abf92b49da04c11bc76e836e49..418c51bdafc4e462e2decfe1e8541aaf49705cb0 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -827,16 +827,14 @@ class user_undel(LDAPQuery): + + # First check that the user exists and is a delete one + delete_dn = self.obj.get_either_dn(*keys, **options) +- if delete_dn.endswith(DN(self.obj.active_container_dn, api.env.basedn)): +- raise errors.ValidationError( +- name=self.obj.primary_key.cli_name, +- error=_('User %r is already active') % keys[-1][0]) + try: + entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn) + except errors.NotFound: +- raise errors.ValidationError( +- name=self.obj.primary_key.cli_name, +- error=_('User %r not found') % keys[-1][0]) ++ self.obj.handle_not_found(*keys) ++ if delete_dn.endswith(DN(self.obj.active_container_dn, ++ api.env.basedn)): ++ raise errors.InvocationError( ++ message=_('user "%s" is already active') % keys[-1]) + + active_dn = DN(delete_dn[0], self.obj.active_container_dn, api.env.basedn) + +-- +2.4.3 + diff --git a/SOURCES/0077-webui-increase-duration-of-notification-messages.patch b/SOURCES/0077-webui-increase-duration-of-notification-messages.patch deleted file mode 100644 index 7c49e9f..0000000 --- a/SOURCES/0077-webui-increase-duration-of-notification-messages.patch +++ /dev/null @@ -1,30 +0,0 @@ -From d6f71c1fc95f4d266d15e2f5e516f2947da97a25 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Fri, 5 Dec 2014 16:21:19 +0100 -Subject: [PATCH] webui: increase duration of notification messages - -by 66% - -https://fedorahosted.org/freeipa/ticket/4792 - -Reviewed-By: Martin Basti ---- - install/ui/src/freeipa/ipa.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js -index 137f11e832ff8d0b6dd1b50060f8537c7b117616..a78d1f0638ec5d750b5aee52197c5b04feae3f94 100644 ---- a/install/ui/src/freeipa/ipa.js -+++ b/install/ui/src/freeipa/ipa.js -@@ -1198,7 +1198,7 @@ IPA.get_succeeded = function(data) { - */ - IPA.config = { - default_priority: 500, -- message_timeout: 3000, // [ms] -+ message_timeout: 5000, // [ms] - message_timeout_length: 50 // [chars] - }; - --- -2.1.0 - diff --git a/SOURCES/0078-Fix-automatic-CA-cert-renewal-endless-loop-in-dogtag.patch b/SOURCES/0078-Fix-automatic-CA-cert-renewal-endless-loop-in-dogtag.patch deleted file mode 100644 index 797a2fa..0000000 --- a/SOURCES/0078-Fix-automatic-CA-cert-renewal-endless-loop-in-dogtag.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 90fde5a437f23cac0534f66bc3564c9c676010ab Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 3 Dec 2014 07:43:15 +0000 -Subject: [PATCH] Fix automatic CA cert renewal endless loop in - dogtag-ipa-ca-renew-agent - -Reset profile name after requesting the CA cert from Dogtag to prevent the -automatic renewal request from being restarted in subsequent calls. - -https://fedorahosted.org/freeipa/ticket/4765 - -Reviewed-By: David Kupka ---- - install/certmonger/dogtag-ipa-ca-renew-agent-submit | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index 0a2cff148810e4800c02121afc68911c221d34d7..e0dd33fda6036ed2fb003a89c35eacb1784a5e25 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -408,8 +408,10 @@ def renew_ca_cert(): - "IPA CA certificate is about to expire, " - "use ipa-cacert-manage to renew it") - elif state == 'request': -+ profile = os.environ['CERTMONGER_CA_PROFILE'] - os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert' - result = call_handler(request_and_store_cert) -+ os.environ['CERTMONGER_CA_PROFILE'] = profile - - if result[0] == WAIT: - return (result[0], '%s:%s' % (state, result[1])) --- -2.1.0 - diff --git a/SOURCES/0078-Prohibit-deletion-of-predefined-profiles.patch b/SOURCES/0078-Prohibit-deletion-of-predefined-profiles.patch new file mode 100644 index 0000000..5f1c49e --- /dev/null +++ b/SOURCES/0078-Prohibit-deletion-of-predefined-profiles.patch @@ -0,0 +1,87 @@ +From ba321efe715dbbb3b4be22cb786995cf441e1a74 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 13 Aug 2015 02:32:54 -0400 +Subject: [PATCH] Prohibit deletion of predefined profiles + +Deletion of predefined profiles, including the default profile, +should not be allowed. Detect this case and raise an error. + +Also update the predefined profiles collection to use namedtuple, +making it easier to access the various components. + +Fixes: https://fedorahosted.org/freeipa/ticket/5198 +Reviewed-By: Alexander Bokovoy +--- + ipalib/plugins/certprofile.py | 13 +++++++++++-- + ipapython/dogtag.py | 8 +++++--- + 2 files changed, 16 insertions(+), 5 deletions(-) + +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index 1dd4f403ee4461b83c053eb36019a8896506bb81..007cc543406b7e5705fd7474f3685cd6a9ce6aca 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -3,6 +3,7 @@ + # + + import re ++from operator import attrgetter + + from ipalib import api, Bool, File, Str + from ipalib import output, util +@@ -14,6 +15,7 @@ from ipalib.plugins.baseldap import ( + from ipalib.request import context + from ipalib import ngettext + from ipalib.text import _ ++from ipapython.dogtag import INCLUDED_PROFILES + from ipapython.version import API_VERSION + + from ipalib import errors +@@ -287,9 +289,16 @@ class certprofile_del(LDAPDelete): + __doc__ = _("Delete a Certificate Profile.") + msg_summary = _('Deleted profile "%(value)s"') + +- def execute(self, *args, **kwargs): ++ def pre_callback(self, ldap, dn, *keys, **options): + ca_enabled_check() +- return super(certprofile_del, self).execute(*args, **kwargs) ++ ++ if keys[0] in map(attrgetter('profile_id'), INCLUDED_PROFILES): ++ raise errors.ValidationError(name='profile_id', ++ error=_("Predefined profile '%(profile_id)s' cannot be deleted") ++ % {'profile_id': keys[0]} ++ ) ++ ++ return dn + + def post_callback(self, ldap, dn, *keys, **options): + with self.api.Backend.ra_certprofile as profile_api: +diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py +index 0782d360ccf2ce2c90c4e9cfa66b5159e437e77c..3f0d08154d21a3072e344c311c3e70e414d9dee4 100644 +--- a/ipapython/dogtag.py ++++ b/ipapython/dogtag.py +@@ -17,6 +17,7 @@ + # along with this program. If not, see . + # + ++import collections + import os + import httplib + import xml.dom.minidom +@@ -42,10 +43,11 @@ from ipapython.ipa_log_manager import * + # the configured version. + + ++Profile = collections.namedtuple('Profile', ['profile_id', 'description', 'store_issued']) ++ + INCLUDED_PROFILES = { +- # ( profile_id , description , store_issued) +- (u'caIPAserviceCert', u'Standard profile for network services', True), +- (u'IECUserRoles', u'User profile that includes IECUserRoles extension from request', True), ++ Profile(u'caIPAserviceCert', u'Standard profile for network services', True), ++ Profile(u'IECUserRoles', u'User profile that includes IECUserRoles extension from request', True), + } + + DEFAULT_PROFILE = u'caIPAserviceCert' +-- +2.4.3 + diff --git a/SOURCES/0079-Do-not-renew-the-IPA-CA-cert-by-serial-number-in-dog.patch b/SOURCES/0079-Do-not-renew-the-IPA-CA-cert-by-serial-number-in-dog.patch deleted file mode 100644 index c7adb92..0000000 --- a/SOURCES/0079-Do-not-renew-the-IPA-CA-cert-by-serial-number-in-dog.patch +++ /dev/null @@ -1,34 +0,0 @@ -From a292db4ee5cc30161948d8e71f3b998f978ae7f9 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 4 Dec 2014 15:34:55 +0000 -Subject: [PATCH] Do not renew the IPA CA cert by serial number in - dogtag-ipa-ca-renew-agent - -Always use the full CSR when renewing the IPA CA certificate with Dogtag. The -IPA CA certificate may be issued by an external CA, in which case renewal by -serial number does not make sense and will fail if the IPA CA was initially -installed as a subordinate of an external CA. - -https://fedorahosted.org/freeipa/ticket/4784 - -Reviewed-By: David Kupka ---- - install/certmonger/dogtag-ipa-ca-renew-agent-submit | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index e0dd33fda6036ed2fb003a89c35eacb1784a5e25..c63c0c2c5f863e05cafad293a60d9157c732e7ad 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -147,7 +147,7 @@ def request_cert(): - path = paths.DOGTAG_IPA_RENEW_AGENT_SUBMIT - args = [path] + sys.argv[1:] - if os.environ.get('CERTMONGER_CA_PROFILE') == 'caCACert': -- args += ['-O', 'bypassCAnotafter=true'] -+ args += ['-N', '-O', 'bypassCAnotafter=true'] - stdout, stderr, rc = ipautil.run(args, raiseonerr=False, env=os.environ) - sys.stderr.write(stderr) - sys.stderr.flush() --- -2.1.0 - diff --git a/SOURCES/0079-improve-the-handling-of-krb5-related-errors-in-dnsse.patch b/SOURCES/0079-improve-the-handling-of-krb5-related-errors-in-dnsse.patch new file mode 100644 index 0000000..6faaa63 --- /dev/null +++ b/SOURCES/0079-improve-the-handling-of-krb5-related-errors-in-dnsse.patch @@ -0,0 +1,92 @@ +From 61d06ac1701a6a3a4afe75bcff64f271991a82ec Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Tue, 18 Aug 2015 18:33:37 +0200 +Subject: [PATCH] improve the handling of krb5-related errors in dnssec daemons + +ipa-dnskeysync* and ipa-ods-exporter handle kerberos errors more gracefully +instead of crashing with tracebacks. + +https://fedorahosted.org/freeipa/ticket/5229 + +Reviewed-By: Martin Basti +--- + daemons/dnssec/ipa-dnskeysync-replica | 10 +++++++++- + daemons/dnssec/ipa-dnskeysyncd | 4 ++-- + daemons/dnssec/ipa-ods-exporter | 10 +++++++++- + 3 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/daemons/dnssec/ipa-dnskeysync-replica b/daemons/dnssec/ipa-dnskeysync-replica +index 551c2f21d5b85b76a7281f719ce722a6c5830cf7..b80b38962957f922cc871ead471f8da0831bec4d 100755 +--- a/daemons/dnssec/ipa-dnskeysync-replica ++++ b/daemons/dnssec/ipa-dnskeysync-replica +@@ -12,6 +12,7 @@ from binascii import hexlify + from datetime import datetime + import dns.dnssec + import fcntl ++from krbV import Krb5Error + import logging + import os + from pprint import pprint +@@ -141,7 +142,14 @@ log.setLevel(level=logging.DEBUG) + PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host)) + log.debug('Kerberos principal: %s', PRINCIPAL) + ccache_filename = os.path.join(WORKDIR, 'ipa-dnskeysync-replica.ccache') +-ipautil.kinit_keytab(PRINCIPAL, paths.IPA_DNSKEYSYNCD_KEYTAB, ccache_filename) ++ ++try: ++ ipautil.kinit_keytab(PRINCIPAL, paths.IPA_DNSKEYSYNCD_KEYTAB, ++ ccache_filename, attempts=5) ++except Krb5Error as e: ++ log.critical('Kerberos authentication failed: %s', e) ++ sys.exit(1) ++ + os.environ['KRB5CCNAME'] = ccache_filename + log.debug('Got TGT') + +diff --git a/daemons/dnssec/ipa-dnskeysyncd b/daemons/dnssec/ipa-dnskeysyncd +index a0fcf8b4b2f27627f3ebcb089e212eefda2adbd3..660e34b45084dd5a31967e9493f488632ec00932 100755 +--- a/daemons/dnssec/ipa-dnskeysyncd ++++ b/daemons/dnssec/ipa-dnskeysyncd +@@ -66,9 +66,9 @@ PRINCIPAL = str('%s/%s' % (DAEMONNAME, api.env.host)) + log.debug('Kerberos principal: %s', PRINCIPAL) + ccache_filename = os.path.join(WORKDIR, 'ipa-dnskeysyncd.ccache') + try: +- ipautil.kinit_keytab(PRINCIPAL, KEYTAB_FB, ccache_filename) ++ ipautil.kinit_keytab(PRINCIPAL, KEYTAB_FB, ccache_filename, attempts=5) + except Exception as ex: +- log.critical(ex) ++ log.critical("Kerberos authentication failed: %s", ex) + # signal failure and let init system to restart the daemon + sys.exit(1) + os.environ['KRB5CCNAME'] = ccache_filename +diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter +index 4c6649c2fbfe77e563ab70276a92b59201fcbace..4d5423797fc9d4bdd0a432bac96b8209bb98c6d8 100755 +--- a/daemons/dnssec/ipa-ods-exporter ++++ b/daemons/dnssec/ipa-ods-exporter +@@ -20,6 +20,7 @@ from datetime import datetime + import dateutil.tz + import dns.dnssec + import fcntl ++from krbV import Krb5Error + import logging + import os + import subprocess +@@ -482,7 +483,14 @@ ipalib.api.finalize() + PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host)) + log.debug('Kerberos principal: %s', PRINCIPAL) + ccache_name = os.path.join(WORKDIR, 'ipa-ods-exporter.ccache') +-ipautil.kinit_keytab(PRINCIPAL, paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name) ++ ++try: ++ ipautil.kinit_keytab(PRINCIPAL, paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name, ++ attempts=5) ++except Krb5Error as e: ++ log.critical('Kerberos authentication failed: %s', e) ++ sys.exit(1) ++ + os.environ['KRB5CCNAME'] = ccache_name + log.debug('Got TGT') + +-- +2.4.3 + diff --git a/SOURCES/0080-Improve-validation-of-instance-and-backend-options-i.patch b/SOURCES/0080-Improve-validation-of-instance-and-backend-options-i.patch deleted file mode 100644 index f8e9fd5..0000000 --- a/SOURCES/0080-Improve-validation-of-instance-and-backend-options-i.patch +++ /dev/null @@ -1,169 +0,0 @@ -From cc256391c89c9d8d7c8ae9e1ce647396cded0674 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 1 Dec 2014 12:12:15 +0000 -Subject: [PATCH] Improve validation of --instance and --backend options in - ipa-restore - -https://fedorahosted.org/freeipa/ticket/4744 - -Reviewed-By: David Kupka ---- - ipaplatform/base/paths.py | 2 +- - ipaserver/install/ipa_backup.py | 2 +- - ipaserver/install/ipa_restore.py | 73 ++++++++++++++++++++++++---------------- - 3 files changed, 46 insertions(+), 31 deletions(-) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index e28147ab4aa1faa3859c38665a83f57fb67e96b2..8bfab1bc92f79b5e76555b35a8b646e1ff56f84b 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -261,7 +261,7 @@ class BasePathNamespace(object): - VAR_LIB_DIRSRV_INSTANCE_SCRIPTS_TEMPLATE = "/var/lib/dirsrv/scripts-%s" - VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s" - SLAPD_INSTANCE_BACKUP_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/bak/%s" -- IPACA_DIRSRV_INSTANCE_DB_TEMPLATE = "/var/lib/dirsrv/slapd-%s/db/ipaca" -+ SLAPD_INSTANCE_DB_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/db/%s" - SLAPD_INSTANCE_LDIF_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-%s/ldif" - VAR_LIB_SLAPD_PKI_IPA_DIR_TEMPLATE = "/var/lib/dirsrv/slapd-PKI-IPA" - VAR_LIB_IPA = "/var/lib/ipa" -diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py -index 5d583f7e9186f20ebe8187ba70db28de0c255ae7..72d1475d6db92b6b9e715afdae85d169a036c085 100644 ---- a/ipaserver/install/ipa_backup.py -+++ b/ipaserver/install/ipa_backup.py -@@ -292,7 +292,7 @@ class Backup(admintool.AdminTool): - - for instance in [realm_to_serverid(api.env.realm), 'PKI-IPA']: - if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance): -- if os.path.exists(paths.IPACA_DIRSRV_INSTANCE_DB_TEMPLATE % instance): -+ if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % (instance, 'ipaca')): - self.db2ldif(instance, 'ipaca', online=options.online) - self.db2ldif(instance, 'userRoot', online=options.online) - self.db2bak(instance, online=options.online) -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 9cb978a516f4f85307735b7428f6053461061022..097703938a7ba3820f4acae2148760146464fa08 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -188,15 +188,35 @@ class Restore(admintool.AdminTool): - self.log.info("Preparing restore from %s on %s", - self.backup_dir, api.env.host) - -- if not options.instance: -- instances = [] -- for instance in [realm_to_serverid(api.env.realm), 'PKI-IPA']: -- if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance): -- instances.append(instance) -+ if options.instance and options.backend: -+ database = (options.instance, options.backend) -+ if not os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % -+ database): -+ raise admintool.ScriptError( -+ "Instance %s with backend %s does not exist" % database) -+ -+ databases = [database] - else: -- instances = [options.instance] -- if options.data_only and not instances: -- raise admintool.ScriptError('No instances to restore to') -+ if options.instance: -+ instances = [options.instance] -+ else: -+ instances = [realm_to_serverid(api.env.realm), 'PKI-IPA'] -+ -+ if options.backend: -+ backends = [options.backend] -+ else: -+ backends = ['userRoot', 'ipaca'] -+ -+ databases = [] -+ for instance in instances: -+ for backend in backends: -+ database = (instance, backend) -+ if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % -+ database): -+ databases.append(database) -+ -+ if options.data_only and not databases: -+ raise admintool.ScriptError('No instances to restore to') - - create_ds_user() - pent = pwd.getpwnam(DS_USER) -@@ -223,7 +243,7 @@ class Restore(admintool.AdminTool): - # These two checks would normally be in the validate method but - # we need to know the type of backup we're dealing with. - if (self.backup_type != 'FULL' and not options.data_only and -- not instances): -+ not databases): - raise admintool.ScriptError('Cannot restore a data backup into an empty system') - if (self.backup_type == 'FULL' and not options.data_only and - (options.instance or options.backend)): -@@ -244,6 +264,15 @@ class Restore(admintool.AdminTool): - not user_input("Continue to restore?", False)): - raise admintool.ScriptError("Aborted") - -+ self.extract_backup(options.gpg_keyring) -+ -+ for database in databases: -+ ldifname = '%s-%s.ldif' % database -+ ldiffile = os.path.join(self.dir, ldifname) -+ if not os.path.exists(ldiffile): -+ raise admintool.ScriptError( -+ "Instance %s with backend %s not in backup" % database) -+ - # Big fat warning - if (not options.unattended and - not user_input("Restoring data will overwrite existing live data. Continue to restore?", False)): -@@ -261,7 +290,6 @@ class Restore(admintool.AdminTool): - self.log.info("Disabling all replication.") - self.disable_agreements() - -- self.extract_backup(options.gpg_keyring) - if options.data_only: - if not options.online: - self.log.info('Stopping Directory Server') -@@ -295,16 +323,8 @@ class Restore(admintool.AdminTool): - # userRoot backend in it and the main IPA instance. If we - # have a unified instance we need to restore both userRoot and - # ipaca. -- for instance in instances: -- if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % instance): -- if options.backend is None: -- self.ldif2db(instance, 'userRoot', online=options.online) -- if os.path.exists(paths.IPACA_DIRSRV_INSTANCE_DB_TEMPLATE % instance): -- self.ldif2db(instance, 'ipaca', online=options.online) -- else: -- self.ldif2db(instance, options.backend, online=options.online) -- else: -- raise admintool.ScriptError('389-ds instance %s does not exist' % instance) -+ for instance, backend in databases: -+ self.ldif2db(instance, backend, online=options.online) - - if options.data_only: - if not options.online: -@@ -447,20 +467,15 @@ class Restore(admintool.AdminTool): - try: - conn.add_entry(ent) - except Exception, e: -- raise admintool.ScriptError( -- 'Unable to bind to LDAP server: %s' % e) -+ self.log.error("Unable to bind to LDAP server: %s" % e) -+ return - - self.log.info("Waiting for LDIF to finish") - wait_for_task(conn, dn) - else: - args = ['%s/ldif2db' % self.__find_scripts_dir(instance), -- '-i', ldiffile] -- if backend is not None: -- args.append('-n') -- args.append(backend) -- else: -- args.append('-n') -- args.append('userRoot') -+ '-i', ldiffile, -+ '-n', backend] - (stdout, stderr, rc) = run(args, raiseonerr=False) - if rc != 0: - self.log.critical("ldif2db failed: %s" % stderr) --- -2.1.0 - diff --git a/SOURCES/0080-client-Add-support-for-multiple-IP-addresses-during-.patch b/SOURCES/0080-client-Add-support-for-multiple-IP-addresses-during-.patch new file mode 100644 index 0000000..2212e58 --- /dev/null +++ b/SOURCES/0080-client-Add-support-for-multiple-IP-addresses-during-.patch @@ -0,0 +1,398 @@ +From 12cafe49be52deca889c6a909f6451a464085b06 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Sun, 4 Jan 2015 15:04:18 -0500 +Subject: [PATCH] client: Add support for multiple IP addresses during + installation. + +https://fedorahosted.org/freeipa/ticket/4249 + +Reviewed-By: Martin Basti +--- + ipa-client/ipa-install/ipa-client-install | 289 +++++++++++++++++++++++------- + 1 file changed, 223 insertions(+), 66 deletions(-) + +diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install +index 91323ae115a27d221bcbc43fee887c56d99c8635..793de4fc950ad73b1d88f9ab4bd5178afc8b813d 100755 +--- a/ipa-client/ipa-install/ipa-client-install ++++ b/ipa-client/ipa-install/ipa-client-install +@@ -32,6 +32,7 @@ try: + from optparse import SUPPRESS_HELP, OptionGroup, OptionValueError + import shutil + from krbV import Krb5Error ++ import dns + + import nss.nss as nss + import SSSDConfig +@@ -180,9 +181,15 @@ def parse_options(): + basic_group.add_option("--configure-firefox", dest="configure_firefox", + action="store_true", default=False, + help="configure Firefox") +- parser.add_option_group(basic_group) + basic_group.add_option("--firefox-dir", dest="firefox_dir", default=None, + help="specify directory where Firefox is installed (for example: '/usr/lib/firefox')") ++ basic_group.add_option("--ip-address", dest="ip_addresses", default=[], ++ action="append", help="Specify IP address that should be added to DNS." ++ " This option can be used multiple times") ++ basic_group.add_option("--all-ip-addresses", dest="all_ip_addresses", ++ default=False, action="store_true", help="All routable IP" ++ " addresses configured on any inteface will be added to DNS") ++ parser.add_option_group(basic_group) + + sssd_group = OptionGroup(parser, "SSSD options") + sssd_group.add_option("--permit", dest="permit", +@@ -223,6 +230,15 @@ def parse_options(): + if options.no_nisdomain and options.nisdomain: + parser.error("--no-nisdomain cannot be used together with --nisdomain") + ++ if options.ip_addresses: ++ if options.dns_updates: ++ parser.error("--ip-address cannot be used together with" ++ " --enable-dns-updates") ++ ++ if options.all_ip_addresses: ++ parser.error("--ip-address cannot be used together with" ++ " --all-ip-addresses") ++ + return safe_opts, options + + def logging_setup(options): +@@ -1285,6 +1301,11 @@ def configure_sssd_conf(fstore, cli_realm, cli_domain, cli_server, options, clie + + if options.dns_updates: + domain.set_option('dyndns_update', True) ++ if options.all_ip_addresses: ++ domain.set_option('dyndns_iface', '*') ++ else: ++ iface = get_server_connection_interface(cli_server[0]) ++ domain.set_option('dyndns_iface', iface) + if options.krb5_offline_passwords: + domain.set_option('krb5_store_password_if_offline', True) + +@@ -1501,39 +1522,41 @@ def unconfigure_nisdomain(): + services.knownservices.domainname.disable() + + +-def resolve_ipaddress(server): +- """ Connect to the server's LDAP port in order to determine what ip +- address this machine uses as "public" ip (relative to the server). +- +- Returns a tuple with the IP address and address family when +- connection was successful. Socket error is raised otherwise. +- """ +- last_socket_error = None +- +- for res in socket.getaddrinfo(server, 389, socket.AF_UNSPEC, +- socket.SOCK_STREAM): +- af, socktype, proto, canonname, sa = res +- try: +- s = socket.socket(af, socktype, proto) +- except socket.error, e: +- last_socket_error = e +- s = None ++def get_iface_from_ip(ip_addr): ++ ipresult = ipautil.run([paths.IP, '-oneline', 'address', 'show']) ++ for line in ipresult[0].split('\n'): ++ fields = line.split() ++ if len(fields) < 6: + continue +- ++ if fields[2] not in ['inet', 'inet6']: ++ continue ++ (ip, mask) = fields[3].rsplit('/', 1) ++ if ip == ip_addr: ++ return fields[1] ++ else: ++ raise RuntimeError("IP %s not assigned to any interface." % ip_addr) ++ ++ ++def get_local_ipaddresses(iface=None): ++ args = [paths.IP, '-oneline', 'address', 'show'] ++ if iface: ++ args += ['dev', iface] ++ ipresult = ipautil.run(args) ++ lines = ipresult[0].split('\n') ++ ips = [] ++ for line in lines: ++ fields = line.split() ++ if len(fields) < 6: ++ continue ++ if fields[2] not in ['inet', 'inet6']: ++ continue ++ (ip, mask) = fields[3].rsplit('/', 1) + try: +- s.connect(sa) +- sockname = s.getsockname() +- +- # For both IPv4 and IPv6 own IP address is always the first item +- return (sockname[0], af) +- except socket.error, e: +- last_socket_error = e +- finally: +- if s: +- s.close() ++ ips.append(ipautil.CheckedIPAddress(ip)) ++ except ValueError: ++ continue ++ return ips + +- if last_socket_error is not None: +- raise last_socket_error # pylint: disable=E0702 + + def do_nsupdate(update_txt): + root_logger.debug("Writing nsupdate commands to %s:", UPDATE_FILE) +@@ -1558,21 +1581,24 @@ def do_nsupdate(update_txt): + + return result + +-UPDATE_TEMPLATE_A = """ +-debug ++DELETE_TEMPLATE_A = """ + update delete $HOSTNAME. IN A + show + send +-update add $HOSTNAME. $TTL IN A $IPADDRESS +-show +-send + """ + +-UPDATE_TEMPLATE_AAAA = """ +-debug ++DELETE_TEMPLATE_AAAA = """ + update delete $HOSTNAME. IN AAAA + show + send ++""" ++ADD_TEMPLATE_A = """ ++update add $HOSTNAME. $TTL IN A $IPADDRESS ++show ++send ++""" ++ ++ADD_TEMPLATE_AAAA = """ + update add $HOSTNAME. $TTL IN AAAA $IPADDRESS + show + send +@@ -1581,46 +1607,174 @@ send + UPDATE_FILE = paths.IPA_DNS_UPDATE_TXT + CCACHE_FILE = paths.IPA_DNS_CCACHE + +-def update_dns(server, hostname): + ++def update_dns(server, hostname, options): + try: +- (ip, af) = resolve_ipaddress(server) +- except socket.gaierror, e: +- root_logger.debug("update_dns: could not connect to server: %s", e) +- root_logger.error("Cannot update DNS records! " +- "Failed to connect to server '%s'.", server) +- return +- +- sub_dict = dict(HOSTNAME=hostname, +- IPADDRESS=ip, +- TTL=1200 +- ) +- +- if af == socket.AF_INET: +- template = UPDATE_TEMPLATE_A +- elif af == socket.AF_INET6: +- template = UPDATE_TEMPLATE_AAAA ++ ips = get_local_ipaddresses() ++ except CalledProcessError as e: ++ root_logger.error("Cannot update DNS records. %s" % e) ++ root_logger.debug("Unable to get local IP addresses.") ++ ++ if options.all_ip_addresses: ++ update_ips = ips ++ elif options.ip_addresses: ++ update_ips = [] ++ for ip in options.ip_addresses: ++ update_ips.append(ipautil.CheckedIPAddress(ip)) + else: +- root_logger.info("Failed to determine this machine's ip address.") +- root_logger.warning("Failed to update DNS A record.") ++ try: ++ iface = get_server_connection_interface(server) ++ except RuntimeError as e: ++ root_logger.error("Cannot update DNS records. %s" % e) ++ return ++ try: ++ update_ips = get_local_ipaddresses(iface) ++ except CalledProcessError as e: ++ root_logger.error("Cannot update DNS records. %s" % e) ++ return ++ ++ if not update_ips: ++ root_logger.info("Failed to determine this machine's ip address(es).") + return + +- update_txt = ipautil.template_str(template, sub_dict) ++ update_txt = "debug\n" ++ update_txt += ipautil.template_str(DELETE_TEMPLATE_A, ++ dict(HOSTNAME=hostname)) ++ update_txt += ipautil.template_str(DELETE_TEMPLATE_AAAA, ++ dict(HOSTNAME=hostname)) ++ ++ for ip in update_ips: ++ sub_dict = dict(HOSTNAME=hostname, IPADDRESS=ip, TTL=1200) ++ if ip.version == 4: ++ template = ADD_TEMPLATE_A ++ elif ip.version == 6: ++ template = ADD_TEMPLATE_AAAA ++ update_txt += ipautil.template_str(template, sub_dict) ++ ++ if not do_nsupdate(update_txt): ++ root_logger.error("Failed to update DNS records.") ++ verify_dns_update(hostname, update_ips) ++ + +- if do_nsupdate(update_txt): +- root_logger.info("DNS server record set to: %s -> %s", hostname, ip) ++def verify_dns_update(fqdn, ips): ++ """ ++ Verify that the fqdn resolves to all IP addresses and ++ that there's matching PTR record for every IP address. ++ """ ++ # verify A/AAAA records ++ missing_ips = [str(ip) for ip in ips] ++ extra_ips = [] ++ for record_type in [dns.rdatatype.A, dns.rdatatype.AAAA]: ++ root_logger.debug('DNS resolver: Query: %s IN %s' % ++ (fqdn, dns.rdatatype.to_text(record_type))) ++ try: ++ answers = dns.resolver.query(fqdn, record_type) ++ except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN): ++ root_logger.debug('DNS resolver: No record.') ++ except dns.resolver.NoNameservers: ++ root_logger.debug('DNS resolver: No nameservers answered the' ++ 'query.') ++ except dns.exception.DNSException: ++ root_logger.debug('DNS resolver error.') ++ else: ++ for rdata in answers: ++ try: ++ missing_ips.remove(rdata.address) ++ except ValueError: ++ extra_ips.append(rdata.address) ++ ++ # verify PTR records ++ fqdn_name = dns.name.from_text(fqdn) ++ wrong_reverse = {} ++ missing_reverse = [str(ip) for ip in ips] ++ for ip in ips: ++ ip_str = str(ip) ++ addr = dns.reversename.from_address(ip_str) ++ root_logger.debug('DNS resolver: Query: %s IN PTR' % addr) ++ try: ++ answers = dns.resolver.query(addr, dns.rdatatype.PTR) ++ except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN): ++ root_logger.debug('DNS resolver: No record.') ++ except dns.resolver.NoNameservers: ++ root_logger.debug('DNS resolver: No nameservers answered the' ++ 'query.') ++ except dns.exception.DNSException: ++ root_logger.debug('DNS resolver error.') ++ else: ++ missing_reverse.remove(ip_str) ++ for rdata in answers: ++ if not rdata.target == fqdn_name: ++ wrong_reverse.setdefault(ip_str, []).append(rdata.target) ++ ++ if missing_ips: ++ root_logger.warning('Missing A/AAAA record(s) for host %s: %s.' % ++ (fqdn, ', '.join(missing_ips))) ++ if extra_ips: ++ root_logger.warning('Extra A/AAAA record(s) for host %s: %s.' % ++ (fqdn, ', '.join(extra_ips))) ++ if missing_reverse: ++ root_logger.warning('Missing reverse record(s) for address(es): %s.' % ++ ', '.join(missing_reverse)) ++ if wrong_reverse: ++ root_logger.warning('Incorrect reverse record(s):') ++ for ip in wrong_reverse: ++ for target in wrong_reverse[ip]: ++ root_logger.warning('%s is pointing to %s instead of %s' % ++ (ip, target, fqdn_name)) ++ ++def get_server_connection_interface(server): ++ # connect to IPA server, get all ip addresses of inteface used to connect ++ for res in socket.getaddrinfo(server, 389, socket.AF_UNSPEC, socket.SOCK_STREAM): ++ (af, socktype, proto, canonname, sa) = res ++ try: ++ s = socket.socket(af, socktype, proto) ++ except socket.error as e: ++ last_error = e ++ s = None ++ continue ++ try: ++ s.connect(sa) ++ sockname = s.getsockname() ++ ip = sockname[0] ++ except socket.error as e: ++ last_error = e ++ continue ++ finally: ++ if s: ++ s.close() ++ try: ++ return get_iface_from_ip(ip) ++ except (CalledProcessError, RuntimeError) as e: ++ last_error = e + else: +- root_logger.error("Failed to update DNS records.") ++ msg = "Cannot get server connection interface" ++ if last_error: ++ msg += ": %s" % (last_error) ++ raise RuntimeError(msg) + +-def client_dns(server, hostname, dns_updates=False): ++ ++def client_dns(server, hostname, options): + + dns_ok = ipautil.is_host_resolvable(hostname) + + if not dns_ok: +- root_logger.warning("Hostname (%s) not found in DNS", hostname) ++ root_logger.warning("Hostname (%s) does not have A/AAAA record.", ++ hostname) ++ ++ if (options.dns_updates or options.all_ip_addresses or options.ip_addresses ++ or not dns_ok): ++ update_dns(server, hostname, options) + +- if dns_updates or not dns_ok: +- update_dns(server, hostname) ++ ++def check_ip_addresses(options): ++ if options.ip_addresses: ++ for ip in options.ip_addresses: ++ try: ++ ipautil.CheckedIPAddress(ip, match_local=True) ++ except ValueError as e: ++ root_logger.error(e) ++ return False ++ return True + + def update_ssh_keys(server, hostname, ssh_dir, create_sshfp): + if not os.path.isdir(ssh_dir): +@@ -2127,6 +2281,9 @@ def install(options, env, fstore, statestore): + if not options.ca_cert_file and get_cert_path(options.ca_cert_file) == CACERT: + root_logger.warning("Using existing certificate '%s'.", CACERT) + ++ if not check_ip_addresses(options): ++ return CLIENT_INSTALL_ERROR ++ + # Create the discovery instance + ds = ipadiscovery.IPADiscovery() + +@@ -2717,7 +2874,7 @@ def install(options, env, fstore, statestore): + root_logger.info("Added CA certificates to the default NSS database.") + + if not options.on_master: +- client_dns(cli_server[0], hostname, options.dns_updates) ++ client_dns(cli_server[0], hostname, options) + configure_certmonger(fstore, subject_base, cli_realm, hostname, + options, ca_enabled) + +-- +2.4.3 + diff --git a/SOURCES/0081-revert-removal-of-cn-attribute-from-idnsRecord.patch b/SOURCES/0081-revert-removal-of-cn-attribute-from-idnsRecord.patch deleted file mode 100644 index d619512..0000000 --- a/SOURCES/0081-revert-removal-of-cn-attribute-from-idnsRecord.patch +++ /dev/null @@ -1,31 +0,0 @@ -From a34f3eeb1f4501a43e978ddafdd50d46fa77a3b5 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Thu, 4 Dec 2014 17:30:20 +0100 -Subject: [PATCH] revert removal of cn attribute from idnsRecord - -The removal, which was done in IPA-3.2, causes replication issues between IPA < 3.2 and IPA 4.1. Because IPA 4.1 adds two more attributes. - -https://fedorahosted.org/freeipa/ticket/4794 - -Reviewed-By: Thierry Bordaz -Reviewed-By: Jan Cholasta ---- - install/share/60ipadns.ldif | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/share/60ipadns.ldif b/install/share/60ipadns.ldif -index 678a5b483f7abbd0df2907513577573109297943..8fd0bb9e7c10f56c1d1c45b6ec9e8f1f9f7e7cef 100644 ---- a/install/share/60ipadns.ldif -+++ b/install/share/60ipadns.ldif -@@ -63,7 +63,7 @@ attributeTypes: ( 2.16.840.1.113730.3.8.5.25 NAME 'idnsSecKeyRevoke' DESC 'DNSKE - attributeTypes: ( 2.16.840.1.113730.3.8.5.26 NAME 'idnsSecKeySep' DESC 'DNSKEY SEP flag (equivalent to bit 15): RFC 4035' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v4.1' ) - attributeTypes: ( 2.16.840.1.113730.3.8.5.27 NAME 'idnsSecAlgorithm' DESC 'DNSKEY algorithm: string used as mnemonic' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v4.1' ) - attributeTypes: ( 2.16.840.1.113730.3.8.5.28 NAME 'idnsSecKeyRef' DESC 'PKCS#11 URI of the key' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.1' ) --objectClasses: ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( 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 ) ) -+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 ) ) - 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.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' ) --- -2.1.0 - diff --git a/SOURCES/0081-vault-Fix-vault-find-with-criteria.patch b/SOURCES/0081-vault-Fix-vault-find-with-criteria.patch new file mode 100644 index 0000000..8b33fad --- /dev/null +++ b/SOURCES/0081-vault-Fix-vault-find-with-criteria.patch @@ -0,0 +1,28 @@ +From a97b7c5bd372c7a581c440564f4e9d6f3c12a3ea Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 18 Aug 2015 21:11:52 +0200 +Subject: [PATCH] vault: Fix vault-find with criteria + +https://fedorahosted.org/freeipa/ticket/5212 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 4d430ee88658e7ba7f2863ca4ef1e8672e298923..ff021a6a2106b6bcbd690b50bf58e49249e80500 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -802,7 +802,7 @@ class vault_find(LDAPSearch): + raise errors.InvocationError( + format=_('KRA service is not enabled')) + +- base_dn = self.obj.get_dn(*args, **options) ++ base_dn = self.obj.get_dn(None, **options) + + return (filter, base_dn, scope) + +-- +2.4.3 + diff --git a/SOURCES/0082-Check-subject-name-encoding-in-ipa-cacert-manage-ren.patch b/SOURCES/0082-Check-subject-name-encoding-in-ipa-cacert-manage-ren.patch deleted file mode 100644 index efe906b..0000000 --- a/SOURCES/0082-Check-subject-name-encoding-in-ipa-cacert-manage-ren.patch +++ /dev/null @@ -1,51 +0,0 @@ -From c39b8f8c8fd3af8e4587cd1c454a87c7fefb6490 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 4 Dec 2014 08:15:46 +0000 -Subject: [PATCH] Check subject name encoding in ipa-cacert-manage renew - -https://fedorahosted.org/freeipa/ticket/4781 - -Reviewed-By: David Kupka ---- - ipaserver/install/ipa_cacert_manage.py | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py -index 2a8d95fdbebecf543a05afd47275c32684cad970..8fda6a263454e8a4046baa1da069cdcddeb177a9 100644 ---- a/ipaserver/install/ipa_cacert_manage.py -+++ b/ipaserver/install/ipa_cacert_manage.py -@@ -213,18 +213,21 @@ class CACertManage(admintool.AdminTool): - try: - nss_cert = x509.load_certificate(old_cert, x509.DER) - subject = nss_cert.subject -+ der_subject = x509.get_der_subject(old_cert, x509.DER) - #pylint: disable=E1101 - pkinfo = nss_cert.subject_public_key_info.format() - #pylint: enable=E1101 - - nss_cert = x509.load_certificate_from_file(cert_file.name) -+ cert = nss_cert.der_data - if nss_cert.subject != subject: - raise admintool.ScriptError("Subject name mismatch") -+ if x509.get_der_subject(cert, x509.DER) != der_subject: -+ raise admintool.ScriptError("Subject name encoding mismatch") - #pylint: disable=E1101 - if nss_cert.subject_public_key_info.format() != pkinfo: - raise admintool.ScriptError("Subject public key info mismatch") - #pylint: enable=E1101 -- cert = nss_cert.der_data - finally: - del nss_cert - nss.nss_shutdown() -@@ -238,7 +241,7 @@ class CACertManage(admintool.AdminTool): - tmpdb.add_cert(cert, 'IPA CA', 'C,,') - except ipautil.CalledProcessError, e: - raise admintool.ScriptError( -- "Not compatible with the current CA certificate: %s", e) -+ "Not compatible with the current CA certificate: %s" % e) - - ca_certs = x509.load_certificate_list_from_file(ca_file.name) - for ca_cert in ca_certs: --- -2.1.0 - diff --git a/SOURCES/0082-vault-Add-container-information-to-vault-command-res.patch b/SOURCES/0082-vault-Add-container-information-to-vault-command-res.patch new file mode 100644 index 0000000..731126b --- /dev/null +++ b/SOURCES/0082-vault-Add-container-information-to-vault-command-res.patch @@ -0,0 +1,112 @@ +From 23dd6ad21e09a14a802c7776bf073f22011f7eb6 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 18 Aug 2015 21:44:13 +0200 +Subject: [PATCH] vault: Add container information to vault command results + +https://fedorahosted.org/freeipa/ticket/5150 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index ff021a6a2106b6bcbd690b50bf58e49249e80500..712e2d5ddfa723eb84b80a261289a7cf1c75674f 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -322,6 +322,21 @@ class vault(LDAPObject): + label=_('Failed owners'), + flags=['no_create', 'no_update', 'no_search'], + ), ++ Str( ++ 'service?', ++ label=_('Vault service'), ++ flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ++ ), ++ Flag( ++ 'shared?', ++ label=_('Shared vault'), ++ flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ++ ), ++ Str( ++ 'username?', ++ label=_('Vault user'), ++ flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ++ ), + ) + + def get_dn(self, *keys, **options): +@@ -523,6 +538,17 @@ class vault(LDAPObject): + raise errors.AuthenticationError( + message=_('Invalid credentials')) + ++ def get_container_attribute(self, entry, options): ++ if options.get('raw', False): ++ return ++ container_dn = DN(self.container_dn, self.api.env.basedn) ++ if entry.dn.endswith(DN(('cn', 'services'), container_dn)): ++ entry['service'] = entry.dn[1]['cn'] ++ elif entry.dn.endswith(DN(('cn', 'shared'), container_dn)): ++ entry['shared'] = True ++ elif entry.dn.endswith(DN(('cn', 'users'), container_dn)): ++ entry['username'] = entry.dn[1]['cn'] ++ + + @register() + class vault_add(PKQuery, Local): +@@ -738,6 +764,10 @@ class vault_add_internal(LDAPCreate): + + return dn + ++ def post_callback(self, ldap, dn, entry, *keys, **options): ++ self.obj.get_container_attribute(entry, options) ++ return dn ++ + + @register() + class vault_del(LDAPDelete): +@@ -806,6 +836,11 @@ class vault_find(LDAPSearch): + + return (filter, base_dn, scope) + ++ def post_callback(self, ldap, entries, truncated, *args, **options): ++ for entry in entries: ++ self.obj.get_container_attribute(entry, options) ++ return truncated ++ + def exc_callback(self, args, options, exc, call_func, *call_args, + **call_kwargs): + if call_func.__name__ == 'find_entries': +@@ -836,6 +871,10 @@ class vault_mod(LDAPUpdate): + + return dn + ++ def post_callback(self, ldap, dn, entry_attrs, *keys, **options): ++ self.obj.get_container_attribute(entry_attrs, options) ++ return dn ++ + + @register() + class vault_show(LDAPRetrieve): +@@ -854,6 +893,10 @@ class vault_show(LDAPRetrieve): + + return dn + ++ def post_callback(self, ldap, dn, entry_attrs, *keys, **options): ++ self.obj.get_container_attribute(entry_attrs, options) ++ return dn ++ + + @register() + class vaultconfig(Object): +@@ -1452,6 +1495,7 @@ class VaultModMember(LDAPModMember): + def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): + for fail in failed.itervalues(): + fail['services'] = fail.pop('service', []) ++ self.obj.get_container_attribute(entry_attrs, options) + return completed, dn + + +-- +2.4.3 + diff --git a/SOURCES/0083-Refer-the-user-to-freeipa.org-when-something-goes-wr.patch b/SOURCES/0083-Refer-the-user-to-freeipa.org-when-something-goes-wr.patch deleted file mode 100644 index 7c26966..0000000 --- a/SOURCES/0083-Refer-the-user-to-freeipa.org-when-something-goes-wr.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 675251b626028e8eb9b869ba661f919cec16da3c Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 9 Dec 2014 12:47:58 +0000 -Subject: [PATCH] Refer the user to freeipa.org when something goes wrong in - ipa-cacert-manage - -https://fedorahosted.org/freeipa/ticket/4781 - -Reviewed-By: Martin Kosek -Reviewed-By: Martin Basti ---- - ipaserver/install/ipa_cacert_manage.py | 23 ++++++++++++++++++----- - 1 file changed, 18 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py -index 8fda6a263454e8a4046baa1da069cdcddeb177a9..e074601692207253671ad4be6bca35458793625e 100644 ---- a/ipaserver/install/ipa_cacert_manage.py -+++ b/ipaserver/install/ipa_cacert_manage.py -@@ -221,12 +221,21 @@ class CACertManage(admintool.AdminTool): - nss_cert = x509.load_certificate_from_file(cert_file.name) - cert = nss_cert.der_data - if nss_cert.subject != subject: -- raise admintool.ScriptError("Subject name mismatch") -+ raise admintool.ScriptError( -+ "Subject name mismatch (visit " -+ "http://www.freeipa.org/page/Troubleshooting for " -+ "troubleshooting guide)") - if x509.get_der_subject(cert, x509.DER) != der_subject: -- raise admintool.ScriptError("Subject name encoding mismatch") -+ raise admintool.ScriptError( -+ "Subject name encoding mismatch (visit " -+ "http://www.freeipa.org/page/Troubleshooting for " -+ "troubleshooting guide)") - #pylint: disable=E1101 - if nss_cert.subject_public_key_info.format() != pkinfo: -- raise admintool.ScriptError("Subject public key info mismatch") -+ raise admintool.ScriptError( -+ "Subject public key info mismatch (visit " -+ "http://www.freeipa.org/page/Troubleshooting for " -+ "troubleshooting guide)") - #pylint: enable=E1101 - finally: - del nss_cert -@@ -253,7 +262,9 @@ class CACertManage(admintool.AdminTool): - tmpdb.verify_ca_cert_validity('IPA CA') - except ValueError, e: - raise admintool.ScriptError( -- "Not a valid CA certificate: %s" % e) -+ "Not a valid CA certificate: %s (visit " -+ "http://www.freeipa.org/page/Troubleshooting for " -+ "troubleshooting guide)" % e) - - trust_chain = tmpdb.get_trust_chain('IPA CA')[:-1] - for nickname in trust_chain: -@@ -340,7 +351,9 @@ class CACertManage(admintool.AdminTool): - tmpdb.verify_ca_cert_validity(nickname) - except ValueError, e: - raise admintool.ScriptError( -- "Not a valid CA certificate: %s" % e) -+ "Not a valid CA certificate: %s (visit " -+ "http://www.freeipa.org/page/Troubleshooting for " -+ "troubleshooting guide)" % e) - - trust_flags = options.trust_flags - if ((set(trust_flags) - set(',CPTcgpuw')) or --- -2.1.0 - diff --git a/SOURCES/0083-Server-Upgrade-Start-DS-before-CA-is-started.patch b/SOURCES/0083-Server-Upgrade-Start-DS-before-CA-is-started.patch new file mode 100644 index 0000000..db04618 --- /dev/null +++ b/SOURCES/0083-Server-Upgrade-Start-DS-before-CA-is-started.patch @@ -0,0 +1,61 @@ +From dc32238b191a84f0677e2d3ae47f5b319946faf9 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 18 Aug 2015 18:01:09 +0200 +Subject: [PATCH] Server Upgrade: Start DS before CA is started. + +https://fedorahosted.org/freeipa/ticket/5232 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/server/upgrade.py | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 692d0c77e0683f4ad35ebbc14d5a34decc098deb..a57682a4bbdaab2a15b4e415223e2f5faa67ba73 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1328,6 +1328,13 @@ def upgrade_configuration(): + raise RuntimeError("ipa-rewrite.conf doesn't exists (is this server?)") + + # Ok, we are an IPA server, do the additional tests ++ ds_serverid = installutils.realm_to_serverid(api.env.realm) ++ ds = dsinstance.DsInstance() ++ ++ # start DS, CA will not start without running DS, and cause error ++ ds_running = ds.is_running() ++ if not ds_running: ++ ds.start(ds_serverid) + + check_certs() + +@@ -1359,7 +1366,6 @@ def upgrade_configuration(): + 'ca.crl.MasterCRL.enableCRLUpdates', '=') + sub_dict['CLONE']='#' if crl.lower() == 'true' else '' + +- ds_serverid = installutils.realm_to_serverid(api.env.realm) + ds_dirname = dsinstance.config_dirname(ds_serverid) + + upgrade_file(sub_dict, paths.HTTPD_IPA_CONF, +@@ -1396,7 +1402,6 @@ def upgrade_configuration(): + http.change_mod_nss_port_from_http() + http.configure_certmonger_renewal_guard() + +- ds = dsinstance.DsInstance() + ds.configure_dirsrv_ccache() + + # ldap2 connection is not valid after DS restart, close connection otherwise +@@ -1526,6 +1531,11 @@ def upgrade_configuration(): + + set_sssd_domain_option('ipa_server_mode', 'True') + ++ if ds_running and not ds.is_running(): ++ ds.start(ds_serverid) ++ elif not ds_running and ds.is_running(): ++ ds.stop(ds_serverid) ++ + + def upgrade_check(options): + try: +-- +2.4.3 + diff --git a/SOURCES/0084-Show-SSHFP-record-containing-space-in-fingerprint.patch b/SOURCES/0084-Show-SSHFP-record-containing-space-in-fingerprint.patch deleted file mode 100644 index 9379cb0..0000000 --- a/SOURCES/0084-Show-SSHFP-record-containing-space-in-fingerprint.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 208c877a8d9981d11d90fc6599e15f5f40bd3168 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 4 Dec 2014 15:11:00 +0100 -Subject: [PATCH] Show SSHFP record containing space in fingerprint - -SSHFP records added by nsupdate contains extra space (valid), framework -couldn't handle it. - -Ticket: https://fedorahosted.org/freeipa/ticket/4790 -Ticket: https://fedorahosted.org/freeipa/ticket/4789 -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/dns.py | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py -index c5d96a8c4fcdf101254ecefb60cb83d63bee6310..34afc189866993481229bb68a5edd77e0a4eaff3 100644 ---- a/ipalib/plugins/dns.py -+++ b/ipalib/plugins/dns.py -@@ -1437,6 +1437,14 @@ class SSHFPRecord(DNSRecord): - ), - ) - -+ def _get_part_values(self, value): -+ # fingerprint part can contain space in LDAP, return it as one part -+ values = value.split(None, 2) -+ if len(values) != len(self.parts): -+ return None -+ return tuple(values) -+ -+ - class TARecord(DNSRecord): - rrtype = 'TA' - supported = False --- -2.1.0 - diff --git a/SOURCES/0084-cert-request-remove-allowed-extensions-check.patch b/SOURCES/0084-cert-request-remove-allowed-extensions-check.patch new file mode 100644 index 0000000..ee3a5c0 --- /dev/null +++ b/SOURCES/0084-cert-request-remove-allowed-extensions-check.patch @@ -0,0 +1,72 @@ +From 5a39de97688f517acf5dea952c82b6535352744b Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 13 Aug 2015 01:42:06 -0400 +Subject: [PATCH] cert-request: remove allowed extensions check + +cert-request currently permits a limited number of request +extensions; uncommon and esoteric extensions are prohibited and this +limits the usefulness of custom profiles. + +The Dogtag profile has total control over what goes into the final +certificate and has the option to reject request based on the +request extensions present or their values, so there is little +reason to restrict what extensions can be used in FreeIPA. Remove +the check. + +Fixes: https://fedorahosted.org/freeipa/ticket/5205 +Reviewed-By: Jan Cholasta +--- + ipalib/plugins/cert.py | 22 +++------------------- + 1 file changed, 3 insertions(+), 19 deletions(-) + +diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py +index daa698b54f2cc1b645245d312fae0f0500239ea2..7a07039a8488cc11d9bf05ef23642b8059d5921e 100644 +--- a/ipalib/plugins/cert.py ++++ b/ipalib/plugins/cert.py +@@ -306,15 +306,6 @@ class cert_request(VirtualCommand): + ), + ) + +- _allowed_extensions = { +- '2.5.29.14': None, # Subject Key Identifier +- '2.5.29.15': None, # Key Usage +- '2.5.29.17': 'request certificate with subjectaltname', +- '2.5.29.19': None, # Basic Constraints +- '2.5.29.37': None, # Extended Key Usage +- '1.2.840.10070.8.1': None, # IECUserRoles (DNP3 / IEC 62351-8) +- } +- + def execute(self, csr, **kw): + ca_enabled_check() + +@@ -376,12 +367,10 @@ class cert_request(VirtualCommand): + raise errors.CertificateOperationError( + error=_("Failure decoding Certificate Signing Request: %s") % e) + +- # host principals may bypass allowed ext check ++ # self-service and host principals may bypass SAN permission check + if bind_principal != principal and bind_principal_type != HOST: +- for ext in extensions: +- operation = self._allowed_extensions.get(ext) +- if operation: +- self.check_access(operation) ++ if '2.5.29.17' in extensions: ++ self.check_access('request certificate with subjectaltname') + + dn = None + principal_obj = None +@@ -433,11 +422,6 @@ class cert_request(VirtualCommand): + "any of user's email addresses") + ) + +- for ext in extensions: +- if ext not in self._allowed_extensions: +- raise errors.ValidationError( +- name='csr', error=_("extension %s is forbidden") % ext) +- + # We got this far so the principal entry exists, can we write it? + if not ldap.can_write(dn, "usercertificate"): + raise errors.ACIError(info=_("Insufficient 'write' privilege " +-- +2.4.3 + diff --git a/SOURCES/0085-Always-add-etc-hosts-record-when-DNS-is-being-config.patch b/SOURCES/0085-Always-add-etc-hosts-record-when-DNS-is-being-config.patch deleted file mode 100644 index fced922..0000000 --- a/SOURCES/0085-Always-add-etc-hosts-record-when-DNS-is-being-config.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 51aa38b3b2c851a5f745dadafcd8accb078fec13 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 16 Dec 2014 20:35:05 -0500 -Subject: [PATCH] Always add /etc/hosts record when DNS is being configured. - -This was done previosly but accidentally removed when later with patch for -ticket #3575. - -https://fedorahosted.org/freeipa/ticket/4817 - -Reviewed-By: Martin Basti ---- - ipaserver/install/installutils.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index b05b1550a3b7c33a939b4173e57bf1329581d58a..0ab09abea03c8b317e7d00466e127cda00ed17d9 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -494,7 +494,7 @@ def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses - hosts_record = record_in_hosts(str(ip_address)) - - if hosts_record is None: -- if ip_add_to_hosts: -+ if ip_add_to_hosts or setup_dns: - print "Adding ["+str(ip_address)+" "+host_name+"] to your /etc/hosts file" - fstore.backup_file(paths.HOSTS) - add_record_to_hosts(str(ip_address), host_name) --- -2.1.0 - diff --git a/SOURCES/0085-client-Add-description-of-ip-address-and-all-ip-addr.patch b/SOURCES/0085-client-Add-description-of-ip-address-and-all-ip-addr.patch new file mode 100644 index 0000000..0f5366a --- /dev/null +++ b/SOURCES/0085-client-Add-description-of-ip-address-and-all-ip-addr.patch @@ -0,0 +1,33 @@ +From 492e167705075bcecc6f7a79a6476496a2303986 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Wed, 19 Aug 2015 12:28:34 +0200 +Subject: [PATCH] client: Add description of --ip-address and + --all-ip-addresses to man page + +https://fedorahosted.org/freeipa/ticket/4249 + +Reviewed-By: Martin Basti +--- + ipa-client/man/ipa-client-install.1 | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ipa-client/man/ipa-client-install.1 b/ipa-client/man/ipa-client-install.1 +index 41437f0ec2fe432c8088cb57cfe01b482e4116e6..0fafd8a3f2ee24b400b1cbeada4ddf7cea9493b0 100644 +--- a/ipa-client/man/ipa-client-install.1 ++++ b/ipa-client/man/ipa-client-install.1 +@@ -180,6 +180,12 @@ Request certificate for the machine. The certificate will be stored in /etc/ipa/ + \fB\-\-automount\-location\fR=\fILOCATION\fR + Configure automount by running ipa\-client\-automount(1) with \fILOCATION\fR as + automount location. ++.TP ++\fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR ++Use \fIIP_ADDRESS\fR in DNS A/AAAA record for this host. May be specified multiple times to add multiple DNS records. ++.TP ++\fB\-\-all\-ip\-addresses\fR ++Create DNS A/AAAA record for each IP address on this host. + + .SS "SSSD OPTIONS" + .TP +-- +2.4.3 + diff --git a/SOURCES/0086-Avoid-calling-ldap-functions-without-a-context.patch b/SOURCES/0086-Avoid-calling-ldap-functions-without-a-context.patch deleted file mode 100644 index 103cc3d..0000000 --- a/SOURCES/0086-Avoid-calling-ldap-functions-without-a-context.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 1a4a6e0350e1b95e4c5185fdd299f2c1a2273a94 Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Fri, 12 Dec 2014 13:56:51 -0500 -Subject: [PATCH] Avoid calling ldap functions without a context - -We need to make sure we have a ld context before we can load the -configuration, otherwise ldap APIs will abort crashing the KDC. - -If we have an issue connecting to LDAP the lcontext will be NULL, but -we are not checking that condition when we try to refresh the global -configuration. - -https://fedorahosted.org/freeipa/ticket/4810 - -Signed-off-by: Simo Sorce -Reviewed-By: Martin Kosek ---- - daemons/ipa-kdb/ipa_kdb.c | 19 ++++++++++++++++--- - 1 file changed, 16 insertions(+), 3 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c -index e5101bdd0ad880888fd58fd93a5ca8133868db98..d20b6a1f4666a40f1f0523c5ee9b729e27b666ad 100644 ---- a/daemons/ipa-kdb/ipa_kdb.c -+++ b/daemons/ipa-kdb/ipa_kdb.c -@@ -224,6 +224,10 @@ static int ipadb_load_global_config(struct ipadb_context *ipactx) - int ret; - char **authz_data_list; - -+ if (!ipactx || !ipactx->lcontext) { -+ return EINVAL; -+ } -+ - ret = asprintf(&base, "cn=ipaConfig,cn=etc,%s", ipactx->base); - if (ret == -1) { - ret = ENOMEM; -@@ -295,10 +299,19 @@ const struct ipadb_global_config * - ipadb_get_global_config(struct ipadb_context *ipactx) - { - time_t now = 0; -+ int ret; - -- if (time(&now) != (time_t)-1 -- && now - ipactx->config.last_update > IPADB_GLOBAL_CONFIG_CACHE_TIME) -- ipadb_load_global_config(ipactx); -+ if (time(&now) != (time_t)-1 && -+ now - ipactx->config.last_update > IPADB_GLOBAL_CONFIG_CACHE_TIME) { -+ if (!ipactx->lcontext) { -+ ret = ipadb_get_connection(ipactx); -+ if (ret != 0) -+ return NULL; -+ } -+ ret = ipadb_load_global_config(ipactx); -+ if (ret != 0) -+ return NULL; -+ } - - return &ipactx->config; - } --- -2.1.0 - diff --git a/SOURCES/0086-Backup-resore-authentication-control-configuration.patch b/SOURCES/0086-Backup-resore-authentication-control-configuration.patch new file mode 100644 index 0000000..f47ed94 --- /dev/null +++ b/SOURCES/0086-Backup-resore-authentication-control-configuration.patch @@ -0,0 +1,115 @@ +From fcd40cd3f47b15dae8c2e964e890b69906045f32 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Wed, 19 Aug 2015 08:10:03 +0200 +Subject: [PATCH] Backup/resore authentication control configuration + +https://fedorahosted.org/freeipa/ticket/5071 + +Reviewed-By: Martin Babinsky +--- + ipaplatform/base/tasks.py | 15 +++++++++++++++ + ipaplatform/redhat/authconfig.py | 6 ++++++ + ipaplatform/redhat/tasks.py | 8 ++++++++ + ipaserver/install/ipa_backup.py | 4 ++++ + ipaserver/install/ipa_restore.py | 4 ++++ + 5 files changed, 37 insertions(+) + +diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py +index 08fdb494a3bfc6c59bebf4af2f72f54a26724700..65715145af533c90038b3e8667da07fd28b7ec56 100644 +--- a/ipaplatform/base/tasks.py ++++ b/ipaplatform/base/tasks.py +@@ -150,6 +150,21 @@ class BaseTaskNamespace(object): + + return + ++ def backup_auth_configuration(self, path): ++ """ ++ Create backup of access control configuration. ++ :param path: store the backup here. This will be passed to ++ restore_auth_configuration as well. ++ """ ++ return ++ ++ def restore_auth_configuration(self, path): ++ """ ++ Restore backup of access control configuration. ++ :param path: restore the backup from here. ++ """ ++ return ++ + def set_selinux_booleans(self, required_settings, backup_func=None): + """Set the specified SELinux booleans + +diff --git a/ipaplatform/redhat/authconfig.py b/ipaplatform/redhat/authconfig.py +index 901eb51637d193d80bc3927929d7d436065ec262..edefee8b2b4922ad67cdbac158615ef32c776bb4 100644 +--- a/ipaplatform/redhat/authconfig.py ++++ b/ipaplatform/redhat/authconfig.py +@@ -84,3 +84,9 @@ class RedHatAuthConfig(object): + + args = self.build_args() + ipautil.run(["/usr/sbin/authconfig"] + args) ++ ++ def backup(self, path): ++ ipautil.run(["/usr/sbin/authconfig", "--savebackup", path]) ++ ++ def restore(self, path): ++ ipautil.run(["/usr/sbin/authconfig", "--restorebackup", path]) +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index b26604aa736eb472c88bc0dcbc3a4b515712ce9d..1af99d318c6745b1e5285c7829c2b292f86c8390 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -161,6 +161,14 @@ class RedHatTaskNamespace(BaseTaskNamespace): + auth_config.add_option("nostart") + auth_config.execute() + ++ def backup_auth_configuration(self, path): ++ auth_config = RedHatAuthConfig() ++ auth_config.backup(path) ++ ++ def restore_auth_configuration(self, path): ++ auth_config = RedHatAuthConfig() ++ auth_config.restore(path) ++ + def reload_systemwide_ca_store(self): + try: + ipautil.run([paths.UPDATE_CA_TRUST]) +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index d7afb3654b09e88321f1ce9f279749b19c2f6414..0ba44b280dfb7c9d9cbbe2470392c3c98ef35bcc 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -41,6 +41,7 @@ from ipapython import ipaldap + from ipalib.session import ISO8601_DATETIME_FMT + from ipalib.constants import CACERT + from ConfigParser import SafeConfigParser ++from ipaplatform.tasks import tasks + + """ + A test gpg can be generated like this: +@@ -302,6 +303,9 @@ class Backup(admintool.AdminTool): + self.db2ldif(instance, 'userRoot', online=options.online) + self.db2bak(instance, online=options.online) + if not options.data_only: ++ # create backup of auth configuration ++ auth_backup_path = os.path.join(paths.VAR_LIB_IPA, 'auth_backup') ++ tasks.backup_auth_configuration(auth_backup_path) + self.file_backup(options) + self.finalize_backup(options.data_only, options.gpg, options.gpg_keyring) + +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 528a6daf0d4b6d3dfc69b6bbf8e8b05ad91ce02d..8960626d0f0e438ef198e2d92803983e520051a8 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -386,6 +386,10 @@ class Restore(admintool.AdminTool): + self.log.info('Starting Directory Server') + dirsrv.start(capture_output=False) + else: ++ # restore access controll configuration ++ auth_backup_path = os.path.join(paths.VAR_LIB_IPA, 'auth_backup') ++ if os.path.exists(auth_backup_path): ++ tasks.restore_auth_configuration(auth_backup_path) + # explicitly enable then disable the pki tomcatd service to + # re-register its instance. FIXME, this is really wierd. + services.knownservices.pki_tomcatd.enable() +-- +2.4.3 + diff --git a/SOURCES/0087-Add-flag-to-list-all-service-and-user-vaults.patch b/SOURCES/0087-Add-flag-to-list-all-service-and-user-vaults.patch new file mode 100644 index 0000000..e70f3de --- /dev/null +++ b/SOURCES/0087-Add-flag-to-list-all-service-and-user-vaults.patch @@ -0,0 +1,179 @@ +From 0fac76b07e7b15eb46e4db942d5c9890b704549d Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 19 Aug 2015 13:32:01 +0200 +Subject: [PATCH] Add flag to list all service and user vaults + +The vault-find plugin has two additional arguments to list all +service vaults or user vaults. Since the name of a vault is only unique +for a particular user or service, the commands also print the vault user +or vault service. The virtual attributes were added in rev +01dd951ddc0181b559eb3dd5ff0336c81e245628. + +Example: + +$ ipa vault-find --users +---------------- +2 vaults matched +---------------- + Vault name: myvault + Type: standard + Vault user: admin + + Vault name: UserVault + Type: standard + Vault user: admin +---------------------------- +Number of entries returned 2 +---------------------------- + +$ ipa vault-find --services +---------------- +2 vaults matched +---------------- + Vault name: myvault + Type: standard + Vault service: HTTP/ipatest.freeipa.local@FREEIPA.LOCAL + + Vault name: myvault + Type: standard + Vault service: ldap/ipatest.freeipa.local@FREEIPA.LOCAL +---------------------------- +Number of entries returned 2 +---------------------------- + +https://fedorahosted.org/freeipa/ticket/5150 + +Reviewed-By: Jan Cholasta +--- + API.txt | 4 +++- + VERSION | 4 ++-- + ipalib/plugins/vault.py | 48 +++++++++++++++++++++++++++++++++--------------- + 3 files changed, 38 insertions(+), 18 deletions(-) + +diff --git a/API.txt b/API.txt +index a39b22b602e0baf5d283732d18d83b2a25d5cf50..f23d9a40c647a3c4d209419631794cd36e8e5e2f 100644 +--- a/API.txt ++++ b/API.txt +@@ -5508,7 +5508,7 @@ output: Output('result', , None) + output: Output('summary', (, ), None) + output: ListOfPrimaryKeys('value', None, None) + command: vault_find +-args: 1,13,4 ++args: 1,15,4 + arg: Str('criteria?', noextrawhitespace=False) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('cn', attribute=True, autofill=False, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=False) +@@ -5518,10 +5518,12 @@ option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('pkey_only?', autofill=True, default=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') ++option: Flag('services?', autofill=True, default=False) + option: Flag('shared?', autofill=True, default=False) + option: Int('sizelimit?', autofill=False, minvalue=0) + option: Int('timelimit?', autofill=False, minvalue=0) + option: Str('username?', cli_name='user') ++option: Flag('users?', autofill=True, default=False) + option: Str('version?', exclude='webui') + output: Output('count', , None) + output: ListOfEntries('result', (, ), Gettext('A list of LDAP entries', domain='ipa', localedir=None)) +diff --git a/VERSION b/VERSION +index 6569eeb70fa4e8065b5abb9dc89bd4cc6d42bd15..31a4af4a819415740e5c8db9259f934e13418cb5 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=150 +-# Last change: pvoborni - change type of vault type option to StrEnum ++IPA_API_VERSION_MINOR=151 ++# Last change: cheimes - Add flag to list all service and user vaults +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 712e2d5ddfa723eb84b80a261289a7cf1c75674f..83dc085b5aadb4e2878e29d17449f0808cc7a9c2 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -343,21 +343,11 @@ class vault(LDAPObject): + """ + Generates vault DN from parameters. + """ +- + service = options.get('service') + shared = options.get('shared') + user = options.get('username') + +- count = 0 +- if service: +- count += 1 +- +- if shared: +- count += 1 +- +- if user: +- count += 1 +- ++ count = (bool(service) + bool(shared) + bool(user)) + if count > 1: + raise errors.MutuallyExclusiveError( + reason=_('Service, shared, and user options ' + +@@ -387,8 +377,10 @@ class vault(LDAPObject): + parent_dn = DN(('cn', service), ('cn', 'services'), container_dn) + elif shared: + parent_dn = DN(('cn', 'shared'), container_dn) +- else: ++ elif user: + parent_dn = DN(('cn', user), ('cn', 'users'), container_dn) ++ else: ++ raise RuntimeError + + return DN(rdns, parent_dn) + +@@ -814,7 +806,16 @@ class vault_del(LDAPDelete): + class vault_find(LDAPSearch): + __doc__ = _('Search for vaults.') + +- takes_options = LDAPSearch.takes_options + vault_options ++ takes_options = LDAPSearch.takes_options + vault_options + ( ++ Flag( ++ 'services?', ++ doc=_('List all service vaults'), ++ ), ++ Flag( ++ 'users?', ++ doc=_('List all user vaults'), ++ ), ++ ) + + has_output_params = LDAPSearch.has_output_params + +@@ -832,9 +833,26 @@ class vault_find(LDAPSearch): + raise errors.InvocationError( + format=_('KRA service is not enabled')) + +- base_dn = self.obj.get_dn(None, **options) ++ if options.get('users') or options.get('services'): ++ mutex = ['service', 'services', 'shared', 'username', 'users'] ++ count = sum(bool(options.get(option)) for option in mutex) ++ if count > 1: ++ raise errors.MutuallyExclusiveError( ++ reason=_('Service(s), shared, and user(s) options ' + ++ 'cannot be specified simultaneously')) ++ ++ scope = ldap.SCOPE_SUBTREE ++ container_dn = DN(self.obj.container_dn, ++ self.api.env.basedn) ++ ++ if options.get('services'): ++ base_dn = DN(('cn', 'services'), container_dn) ++ else: ++ base_dn = DN(('cn', 'users'), container_dn) ++ else: ++ base_dn = self.obj.get_dn(None, **options) + +- return (filter, base_dn, scope) ++ return filter, base_dn, scope + + def post_callback(self, ldap, entries, truncated, *args, **options): + for entry in entries: +-- +2.4.3 + diff --git a/SOURCES/0087-Remove-the-removal-of-the-ccache.patch b/SOURCES/0087-Remove-the-removal-of-the-ccache.patch deleted file mode 100644 index 0a025b1..0000000 --- a/SOURCES/0087-Remove-the-removal-of-the-ccache.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 86509bce6c14f4b7c791e0de2494c3df2f0aba2d Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Tue, 16 Dec 2014 14:47:42 -0500 -Subject: [PATCH] Remove the removal of the ccache - -It is not necessary to remove the ccache on upgrades on modern IPA -servers, even if the ccache contains stale data either it is re-initialized by -mod_auth_kerb or a new ccache collection is created (if completely unrelated -credentials were present), at least when using DIR or keyring ccaches. - -This line causes wrong SELinux labels to be set in the kernel keyring on -uprades, which the cause the apache server to fail to use th ccache. - -https://fedorahosted.org/freeipa/ticket/4815 - -Reviewed-By: Martin Kosek ---- - install/tools/ipa-upgradeconfig | 1 - - 1 file changed, 1 deletion(-) - mode change 100644 => 100755 install/tools/ipa-upgradeconfig - -diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig -old mode 100644 -new mode 100755 -index 6b687fbd73d01f6574cd8ea3193cedba4d5c0e67..005f3a72df115e63c81a7ca8825fb12cac0a5f81 ---- a/install/tools/ipa-upgradeconfig -+++ b/install/tools/ipa-upgradeconfig -@@ -1382,7 +1382,6 @@ def main(): - fstore.restore_file(removed_sysconfig_file) - - http = httpinstance.HTTPInstance(fstore) -- http.remove_httpd_ccache() - http.configure_selinux_for_httpd() - http.change_mod_nss_port_from_http() - --- -2.1.0 - diff --git a/SOURCES/0088-Add-user-stage-command.patch b/SOURCES/0088-Add-user-stage-command.patch new file mode 100644 index 0000000..7de1560 --- /dev/null +++ b/SOURCES/0088-Add-user-stage-command.patch @@ -0,0 +1,205 @@ +From d5e7ef94033660aed43edb0f2dc4e1eb096579aa Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Mon, 17 Aug 2015 20:11:21 +0200 +Subject: [PATCH] Add user-stage command + +This patch replaces 'stageuser-add --from-delete' with new command +user-stage. + +Original way always required to specify first and last name, and +overall combination of options was hard to manage. The new command +requires only login of deleted user (user-del --preserve). + +https://fedorahosted.org/freeipa/ticket/5041 + +Reviewed-By: Thierry Bordaz +Reviewed-By: Jan Cholasta +--- + API.txt | 10 ++++++++- + VERSION | 4 ++-- + ipalib/plugins/stageuser.py | 44 +++++++------------------------------- + ipalib/plugins/user.py | 51 +++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 70 insertions(+), 39 deletions(-) + +diff --git a/API.txt b/API.txt +index f23d9a40c647a3c4d209419631794cd36e8e5e2f..b0f456e725a6c3d24c1071b282de5a28c3b5a671 100644 +--- a/API.txt ++++ b/API.txt +@@ -4211,7 +4211,7 @@ option: Str('displayname', attribute=True, autofill=True, cli_name='displayname' + option: Str('employeenumber', attribute=True, cli_name='employeenumber', multivalue=False, required=False) + option: Str('employeetype', attribute=True, cli_name='employeetype', multivalue=False, required=False) + option: Str('facsimiletelephonenumber', attribute=True, cli_name='fax', multivalue=True, required=False) +-option: Flag('from_delete?', autofill=True, cli_name='from_delete', default=False) ++option: DeprecatedParam('from_delete?', cli_name='from_delete', default=False) + option: Str('gecos', attribute=True, autofill=True, cli_name='gecos', multivalue=False, required=False) + option: Int('gidnumber', attribute=True, cli_name='gidnumber', minvalue=1, multivalue=False, required=False) + option: Str('givenname', attribute=True, cli_name='first', multivalue=False, required=True) +@@ -5371,6 +5371,14 @@ option: Str('version?', exclude='webui') + output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) ++command: user_stage ++args: 1,2,3 ++arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=True, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', 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', , None) ++output: Output('summary', (, ), None) ++output: ListOfPrimaryKeys('value', None, None) + command: user_status + args: 1,4,4 + arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True) +diff --git a/VERSION b/VERSION +index 31a4af4a819415740e5c8db9259f934e13418cb5..9fe2f4d4f9ff6ffd42c2ee7493c385b0a432a6a0 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=151 +-# Last change: cheimes - Add flag to list all service and user vaults ++IPA_API_VERSION_MINOR=152 ++# Last change: mbasti - add 'user-stage' command +diff --git a/ipalib/plugins/stageuser.py b/ipalib/plugins/stageuser.py +index 41844712042c4456fc515afd316af60b612f164f..b6d98005314ab671af345aacb2e3c9f08193e155 100644 +--- a/ipalib/plugins/stageuser.py ++++ b/ipalib/plugins/stageuser.py +@@ -23,7 +23,8 @@ import posixpath + import os + from copy import deepcopy + from ipalib import api, errors +-from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime ++from ipalib import (Flag, Int, Password, Str, Bool, StrEnum, DateTime, ++ DeprecatedParam) + from ipalib.plugable import Registry + from ipalib.plugins.baseldap import LDAPCreate, LDAPQuery, LDAPSearch, DN, entry_to_dict, pkey_to_value + from ipalib.plugins import baseldap +@@ -260,7 +261,7 @@ class stageuser_add(baseuser_add): + has_output_params = baseuser_add.has_output_params + stageuser_output_params + + takes_options = LDAPCreate.takes_options + ( +- Flag('from_delete?', ++ DeprecatedParam('from_delete?', + doc=_('Create Stage user in from a delete user'), + cli_name='from_delete', + default=False, +@@ -270,13 +271,12 @@ class stageuser_add(baseuser_add): + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + assert isinstance(dn, DN) + +- if not options.get('from_delete'): +- # then givenname and sn are required attributes +- if 'givenname' not in entry_attrs: +- raise errors.RequirementError(name='givenname', error=_('givenname is required')) ++ # then givenname and sn are required attributes ++ if 'givenname' not in entry_attrs: ++ raise errors.RequirementError(name='givenname', error=_('givenname is required')) + +- if 'sn' not in entry_attrs: +- raise errors.RequirementError(name='sn', error=_('sn is required')) ++ if 'sn' not in entry_attrs: ++ raise errors.RequirementError(name='sn', error=_('sn is required')) + + # we don't want an user private group to be created for this user + # add NO_UPG_MAGIC description attribute to let the DS plugin know +@@ -367,34 +367,6 @@ class stageuser_add(baseuser_add): + + return dn + +- def execute(self, *keys, **options): +- ''' +- A stage entry may be taken from the Delete container. +- In that case we rather do 'MODRDN' than 'ADD'. +- ''' +- if options.get('from_delete'): +- ldap = self.obj.backend +- +- staging_dn = self.obj.get_dn(*keys, **options) +- delete_dn = DN(staging_dn[0], self.obj.delete_container_dn, api.env.basedn) +- new_dn = DN(staging_dn[0], self.obj.stage_container_dn, api.env.basedn) +- # Check that this value is a Active user +- try: +- entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn, ['dn']) +- except errors.NotFound: +- self.obj.handle_not_found(*keys) +- +- self._exc_wrapper(keys, options, ldap.move_entry)( +- delete_dn, new_dn) +- entry_attrs = entry_to_dict(entry_attrs, **options) +- entry_attrs['dn'] = new_dn +- +- if self.obj.primary_key and keys[-1] is not None: +- return dict(result=entry_attrs, value=keys[-1]) +- return dict(result=entry_attrs, value=u'') +- else: +- return super(stageuser_add, self).execute(*keys, **options) +- + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + assert isinstance(dn, DN) + config = ldap.get_ipa_config() +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index 418c51bdafc4e462e2decfe1e8541aaf49705cb0..d7cf9666d43b69b0cab91cfa0c98a8373f095ab5 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -859,6 +859,57 @@ class user_undel(LDAPQuery): + value=pkey_to_value(keys[0], options), + ) + ++ ++@register() ++class user_stage(LDAPMultiQuery): ++ __doc__ = _('Move deleted user into staged area') ++ ++ has_output = output.standard_multi_delete ++ msg_summary = _('Staged user account "%(value)s"') ++ ++ def execute(self, *keys, **options): ++ staged = [] ++ failed = [] ++ ++ for key in keys[-1]: ++ single_keys = keys[:-1] + (key,) ++ multi_keys = keys[:-1] + ((key,),) ++ ++ user = self.api.Command.user_show(*single_keys, all=True)['result'] ++ new_options = {} ++ for param in self.api.Command.stageuser_add.options(): ++ try: ++ value = user[param.name] ++ except KeyError: ++ continue ++ if param.multivalue and not isinstance(value, (list, tuple)): ++ value = [value] ++ elif not param.multivalue and isinstance(value, (list, tuple)): ++ value = value[0] ++ new_options[param.name] = value ++ ++ try: ++ self.api.Command.stageuser_add(*single_keys, **new_options) ++ try: ++ self.api.Command.user_del(*multi_keys, preserve=False) ++ except errors.ExecutionError: ++ self.api.Command.stageuser_del(*multi_keys) ++ raise ++ except errors.ExecutionError: ++ if not options['continue']: ++ raise ++ failed.append(key) ++ else: ++ staged.append(key) ++ ++ return dict( ++ result=dict( ++ failed=pkey_to_value(failed, options), ++ ), ++ value=pkey_to_value(staged, options), ++ ) ++ ++ + @register() + class user_disable(LDAPQuery): + __doc__ = _('Disable a user account.') +-- +2.4.3 + diff --git a/SOURCES/0088-Fix-Upgrade-forwardzones-zones-after-adding-newer-re.patch b/SOURCES/0088-Fix-Upgrade-forwardzones-zones-after-adding-newer-re.patch deleted file mode 100644 index 0c36e4f..0000000 --- a/SOURCES/0088-Fix-Upgrade-forwardzones-zones-after-adding-newer-re.patch +++ /dev/null @@ -1,145 +0,0 @@ -From c04aa879436f190f82265b87255e2a7a27939975 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Tue, 6 Jan 2015 10:36:06 +0100 -Subject: [PATCH] Fix: Upgrade forwardzones zones after adding newer replica - -Patch fixes issue, when forwardzones has not been upgraded after adding -replica >=4.0 into topology with IPA 3.x servers. - -Ticket: https://fedorahosted.org/freeipa/ticket/4818 -Reviewed-By: Petr Spacek ---- - install/share/dns.ldif | 2 ++ - install/updates/40-dns.update | 1 + - ipaserver/install/plugins/dns.py | 65 +++++++++++++++++++++------------------- - 3 files changed, 37 insertions(+), 31 deletions(-) - -diff --git a/install/share/dns.ldif b/install/share/dns.ldif -index 2c6050f8598b82e3f0e476d5bff5522f4b54e521..05f5684c385db653a049a15bf490efe0d95e4a38 100644 ---- a/install/share/dns.ldif -+++ b/install/share/dns.ldif -@@ -2,8 +2,10 @@ dn: cn=dns,$SUFFIX - changetype: add - objectClass: idnsConfigObject - objectClass: nsContainer -+objectClass: ipaConfigObject - objectClass: top - cn: dns -+ipaConfigString: DNSVersion 1 - aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX" or userattr = "parent[0,1].managedby#GROUPDN";) - aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";) - aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";) -diff --git a/install/updates/40-dns.update b/install/updates/40-dns.update -index 00fc97fcafc98ee6ef6e0c36b2005635867287b2..251df5907217344fb7bda3adcdef0d5c79c449ab 100644 ---- a/install/updates/40-dns.update -+++ b/install/updates/40-dns.update -@@ -2,6 +2,7 @@ - # update DNS container - dn: cn=dns, $SUFFIX - addifexist: objectClass: idnsConfigObject -+addifexist: objectClass: ipaConfigObject - addifexist: aci:'(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)' - addifexist: aci:'(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)' - addifexist: aci:'(targetattr = "idnsname || 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 || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || dlvrecord || idnssecinlinesigning || nsec3paramrecord || tlsarecord ")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)' -diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py -index 62cf588d27155acb03026f69ea09ff15582d26dc..ea4aec9741e4714cacdb677bd850730462623fa7 100644 ---- a/ipaserver/install/plugins/dns.py -+++ b/ipaserver/install/plugins/dns.py -@@ -18,6 +18,7 @@ - # along with this program. If not, see . - - import ldap as _ldap -+import re - import traceback - import time - -@@ -144,32 +145,6 @@ class update_dns_limits(PostUpdate): - api.register(update_dns_limits) - - --class update_check_forwardzones(PreSchemaUpdate): -- """ -- Check if the idnsforwardzone objectclass is in LDAP schema. -- If not update is required (update_to_forward_zones), set sysupgrade state -- 'update_to_forward_zones' to True -- """ -- -- def execute(self, **options): -- state = sysupgrade.get_upgrade_state('dns', 'update_to_forward_zones') -- if state is False: -- # no upgrade is needed -- return (False, False, []) -- ldap = self.obj.backend -- if not dns_container_exists(ldap): # No DNS installed -- return (False, False, []) -- result = ldap.schema.get_obj(_ldap.schema.models.ObjectClass, 'idnsforwardzone') -- if result is None: -- sysupgrade.set_upgrade_state('dns', 'update_to_forward_zones', True) -- self.log.info('Prepared upgrade to forward zones') -- else: -- sysupgrade.set_upgrade_state('dns', 'update_to_forward_zones', False) -- return (False, False, []) -- --api.register(update_check_forwardzones) -- -- - class update_master_to_dnsforwardzones(PostUpdate): - """ - Update all zones to meet requirements in the new FreeIPA versions -@@ -188,10 +163,41 @@ class update_master_to_dnsforwardzones(PostUpdate): - - def execute(self, **options): - ldap = self.obj.backend -- if not sysupgrade.get_upgrade_state('dns', 'update_to_forward_zones'): -- # forward zones was tranformed before, nothing to do -+ # check LDAP if forwardzones already uses new semantics -+ dns_container_dn = DN(api.env.container_dns, api.env.basedn) -+ try: -+ container_entry = ldap.get_entry(dns_container_dn) -+ except errors.NotFound: -+ # DNS container not found, nothing to upgrade - return (False, False, []) - -+ for config_option in container_entry.get("ipaConfigString", []): -+ matched = re.match("^DNSVersion\s+(?P\d+)$", -+ config_option, flags=re.I) -+ if matched and int(matched.group("version")) >= 1: -+ # forwardzones already uses new semantics, -+ # no upgrade is required -+ return (False, False, []) -+ -+ self.log.info('Updating forward zones') -+ # update the DNSVersion, following upgrade can be executed only once -+ container_entry.setdefault( -+ 'ipaConfigString', []).append(u"DNSVersion 1") -+ ldap.update_entry(container_entry) -+ -+ # Updater in IPA version from 4.0 to 4.1.2 doesn't work well, this -+ # should detect if update in past has been executed, and set proper -+ # DNSVersion into LDAP -+ try: -+ fwzones = api.Command.dnsforwardzone_find()['result'] -+ except errors.NotFound: -+ # No forwardzones found, update probably has not been executed yet -+ pass -+ else: -+ if fwzones: -+ # fwzones exist, do not execute upgrade again -+ return (False, False, []) -+ - try: - # raw values are required to store into ldif - zones = api.Command.dnszone_find(all=True, -@@ -345,9 +351,6 @@ class update_master_to_dnsforwardzones(PostUpdate): - self.log.info('Zone %s was sucessfully transformed to forward zone', - zone['idnsname'][0]) - -- -- sysupgrade.set_upgrade_state('dns', 'update_to_forward_zones', False) -- - return (False, False, []) - - api.register(update_master_to_dnsforwardzones) --- -2.1.0 - diff --git a/SOURCES/0089-Fix-zone-find-during-forwardzone-upgrade.patch b/SOURCES/0089-Fix-zone-find-during-forwardzone-upgrade.patch deleted file mode 100644 index 327daa9..0000000 --- a/SOURCES/0089-Fix-zone-find-during-forwardzone-upgrade.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 1f1c7156564e7d7c2183e54811c69bc74ff21a98 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Wed, 7 Jan 2015 13:21:04 +0100 -Subject: [PATCH] Fix zone find during forwardzone upgrade - -https://fedorahosted.org/freeipa/ticket/4818 - -Reviewed-By: Petr Spacek ---- - ipaserver/install/plugins/dns.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py -index ea4aec9741e4714cacdb677bd850730462623fa7..aa7bf5f0bbc0db6f10f047f390246cfbfda32b73 100644 ---- a/ipaserver/install/plugins/dns.py -+++ b/ipaserver/install/plugins/dns.py -@@ -198,12 +198,16 @@ class update_master_to_dnsforwardzones(PostUpdate): - # fwzones exist, do not execute upgrade again - return (False, False, []) - -+ zones = [] - try: - # raw values are required to store into ldif - zones = api.Command.dnszone_find(all=True, - raw=True, - sizelimit=0)['result'] - except errors.NotFound: -+ pass -+ -+ if not zones: - self.log.info('No DNS zone to update found') - return (False, False, []) - --- -2.1.0 - diff --git a/SOURCES/0089-trusts-format-Kerberos-principal-properly-when-fetch.patch b/SOURCES/0089-trusts-format-Kerberos-principal-properly-when-fetch.patch new file mode 100644 index 0000000..bf4caea --- /dev/null +++ b/SOURCES/0089-trusts-format-Kerberos-principal-properly-when-fetch.patch @@ -0,0 +1,46 @@ +From e9fdf223cdb39e685ad9c57a7348016917d5cba2 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 20 Aug 2015 15:12:42 +0300 +Subject: [PATCH] trusts: format Kerberos principal properly when fetching + trust topology + +For bidirectional trust if we have AD administrator credentials, we +should be using them with Kerberos authentication. If we don't have +AD administrator credentials, we should be using +HTTP/ipa.master@IPA.REALM credentials. This means we should ask +formatting 'creds' object in Kerberos style. + +For one-way trust we'll be fetching trust topology as TDO object, +authenticating with pre-created Kerberos credentials cache, so in all +cases we do use Kerberos authentication to talk to Active Directory +domain controllers over cross-forest trust link. + +Part of trust refactoring series. +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1250190 +Fixes: https://fedorahosted.org/freeipa/ticket/5182 +Reviewed-By: Tomas Babej +--- + ipalib/plugins/trust.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py +index c7546692bdd8dd827ee9772b72a758042d97aa71..173463ae7d4134b5bd155cc5fa920bfabd0a6958 100644 +--- a/ipalib/plugins/trust.py ++++ b/ipalib/plugins/trust.py +@@ -1479,7 +1479,12 @@ class trustdomain_del(LDAPDelete): + + def fetch_domains_from_trust(myapi, trustinstance, trust_entry, **options): + trust_name = trust_entry['cn'][0] +- creds = generate_creds(trustinstance, style=CRED_STYLE_SAMBA, **options) ++ # We want to use Kerberos if we have admin credentials even with SMB calls ++ # as eventually use of NTLMSSP will be deprecated for trusted domain operations ++ # If admin credentials are missing, 'creds' will be None and fetch_domains ++ # will use HTTP/ipa.master@IPA.REALM principal, e.g. Kerberos authentication ++ # as well. ++ creds = generate_creds(trustinstance, style=CRED_STYLE_KERBEROS, **options) + server = options.get('realm_server', None) + domains = ipaserver.dcerpc.fetch_domains(myapi, + trustinstance.local_flatname, +-- +2.4.3 + diff --git a/SOURCES/0090-Change-internal-rsa_-public-private-_key-variable-na.patch b/SOURCES/0090-Change-internal-rsa_-public-private-_key-variable-na.patch new file mode 100644 index 0000000..0232220 --- /dev/null +++ b/SOURCES/0090-Change-internal-rsa_-public-private-_key-variable-na.patch @@ -0,0 +1,52 @@ +From 6031fed29f3e81450b48b73eba0f9e716efcb73f Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Tue, 28 Jul 2015 16:12:40 +0200 +Subject: [PATCH] Change internal rsa_(public|private)_key variable names + +In two places the vault plugin refers to rsa public or rsa private key +although the code can handle just any kind of asymmetric algorithms, +e.g. ECDSA. The patch just renames the occurences to avoid more +confusion in the future. + +Reviewed-By: Simo Sorce +Reviewed-By: Martin Basti +--- + ipalib/plugins/vault.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 83dc085b5aadb4e2878e29d17449f0808cc7a9c2..4b2c8a518e5c9a93e5490841a3d2177536c905b1 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -486,11 +486,11 @@ class vault(LDAPObject): + return fernet.encrypt(data) + + elif public_key: +- rsa_public_key = load_pem_public_key( ++ public_key_obj = load_pem_public_key( + data=public_key, + backend=default_backend() + ) +- return rsa_public_key.encrypt( ++ return public_key_obj.encrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), +@@ -513,12 +513,12 @@ class vault(LDAPObject): + + elif private_key: + try: +- rsa_private_key = load_pem_private_key( ++ private_key_obj = load_pem_private_key( + data=private_key, + password=None, + backend=default_backend() + ) +- return rsa_private_key.decrypt( ++ return private_key_obj.decrypt( + data, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), +-- +2.4.3 + diff --git a/SOURCES/0090-migrate-ds-fix-compat-plugin-check.patch b/SOURCES/0090-migrate-ds-fix-compat-plugin-check.patch deleted file mode 100644 index 79e57f9..0000000 --- a/SOURCES/0090-migrate-ds-fix-compat-plugin-check.patch +++ /dev/null @@ -1,44 +0,0 @@ -From b196396dad7ef31d98d2937f80b629ecf9489c38 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 12 Jan 2015 13:08:11 +0100 -Subject: [PATCH] migrate-ds: fix compat plugin check - -After ACI refactoring, admin cannot read Schema Compatibility plugin configuration and therefore migrade-ds won't find if compat plugin is enabled. - -Now the check si done by looking if cn=compat subtree is present. - -https://fedorahosted.org/freeipa/ticket/4825 - -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/migration.py | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py -index fa3d512bf1434c7d349713f78c292b481021303a..cd1fa73f8f514fa5441bea482199291450c87008 100644 ---- a/ipalib/plugins/migration.py -+++ b/ipalib/plugins/migration.py -@@ -140,7 +140,6 @@ _dn_err_msg = _('Malformed DN') - - _supported_schemas = (u'RFC2307bis', u'RFC2307') - --_compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config')) - - def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs): - assert isinstance(dn, DN) -@@ -879,10 +878,8 @@ can use their Kerberos accounts.''') - #check whether the compat plugin is enabled - if not options.get('compat'): - try: -- check_compat = ldap.get_entry(_compat_dn) -- if check_compat is not None and \ -- check_compat.get('nsslapd-pluginenabled', [''])[0].lower() == 'on': -- return dict(result={}, failed={}, enabled=True, compat=False) -+ ldap.get_entry(DN(('cn', 'compat'), (api.env.basedn))) -+ return dict(result={}, failed={}, enabled=True, compat=False) - except errors.NotFound: - pass - --- -2.1.0 - diff --git a/SOURCES/0091-improve-the-usability-of-ipa-user-del-preserve-comma.patch b/SOURCES/0091-improve-the-usability-of-ipa-user-del-preserve-comma.patch new file mode 100644 index 0000000..21a27bc --- /dev/null +++ b/SOURCES/0091-improve-the-usability-of-ipa-user-del-preserve-comma.patch @@ -0,0 +1,170 @@ +From 8208a3b4a642b19ebf112d29f4b3f4feae1a6011 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 19 Aug 2015 14:43:14 +0200 +Subject: [PATCH] improve the usability of `ipa user-del --preserve` command + +`ipa user-del` with `--preserve` option will now process multiple entries and +handle `--continue` option in a manner analogous to `ipa user-del` in normal +mode. + +In addition, it is now no longer possible to permanently delete a user by +accidentally running `ipa user-del --preserve` twice. + +https://fedorahosted.org/freeipa/ticket/5234 +https://fedorahosted.org/freeipa/ticket/5236 + +Reviewed-By: Thierry Bordaz +Reviewed-By: Martin Basti +--- + ipalib/plugins/user.py | 123 ++++++++++++++++++++++++++----------------------- + 1 file changed, 66 insertions(+), 57 deletions(-) + +diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py +index d7cf9666d43b69b0cab91cfa0c98a8373f095ab5..cb47cbb4869cb978f87603817033580647cc2d17 100644 +--- a/ipalib/plugins/user.py ++++ b/ipalib/plugins/user.py +@@ -593,6 +593,60 @@ class user_del(baseuser_del): + ), + ) + ++ def _preserve_user(self, pkey, delete_container, **options): ++ assert isinstance(delete_container, DN) ++ ++ dn = self.obj.get_either_dn(pkey, **options) ++ delete_dn = DN(dn[0], delete_container) ++ ldap = self.obj.backend ++ self.log.debug("preserve move %s -> %s" % (dn, delete_dn)) ++ ++ if dn.endswith(delete_container): ++ raise errors.ExecutionError( ++ _('%s: user is already preserved' % pkey) ++ ) ++ # Check that this value is a Active user ++ try: ++ original_entry_attrs = self._exc_wrapper( ++ pkey, options, ldap.get_entry)(dn, ['dn']) ++ except errors.NotFound: ++ self.obj.handle_not_found(pkey) ++ ++ # start to move the entry to Delete container ++ self._exc_wrapper(pkey, options, ldap.move_entry)(dn, delete_dn, ++ del_old=True) ++ ++ # Then clear the credential attributes ++ attrs_to_clear = ['krbPrincipalKey', 'krbLastPwdChange', ++ 'krbPasswordExpiration', 'userPassword'] ++ ++ entry_attrs = self._exc_wrapper(pkey, options, ldap.get_entry)( ++ delete_dn, attrs_to_clear) ++ ++ clearedCredential = False ++ for attr in attrs_to_clear: ++ if attr.lower() in entry_attrs: ++ del entry_attrs[attr] ++ clearedCredential = True ++ if clearedCredential: ++ self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs) ++ ++ # Then restore some original entry attributes ++ attrs_to_restore = ['secretary', 'managedby', 'manager', 'ipauniqueid', ++ 'uidnumber', 'gidnumber', 'passwordHistory'] ++ ++ entry_attrs = self._exc_wrapper( ++ pkey, options, ldap.get_entry)(delete_dn, attrs_to_restore) ++ ++ restoreAttr = False ++ for attr in attrs_to_restore: ++ if ((attr.lower() in original_entry_attrs) and ++ not (attr.lower() in entry_attrs)): ++ restoreAttr = True ++ entry_attrs[attr.lower()] = original_entry_attrs[attr.lower()] ++ if restoreAttr: ++ self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs) ++ + def forward(self, *keys, **options): + if self.api.env.context == 'cli': + if options['no_preserve'] and options['preserve']: +@@ -633,68 +687,23 @@ class user_del(baseuser_del): + + def execute(self, *keys, **options): + +- dn = self.obj.get_either_dn(*keys, **options) +- + # We are going to permanent delete or the user is already in the delete container. + delete_container = DN(self.obj.delete_container_dn, self.api.env.basedn) +- user_from_delete_container = dn.endswith(delete_container) +- +- if not options.get('preserve', True) or user_from_delete_container: +- # Remove any ID overrides tied with this user +- remove_ipaobject_overrides(self.obj.backend, self.obj.api, dn) +- +- # Issue a true DEL on that entry +- return super(user_del, self).execute(*keys, **options) + + # The user to delete is active and there is no 'no_preserve' option + if options.get('preserve', False): +- +- ldap = self.obj.backend +- +- # need to handle multiple keys (e.g. keys[-1]=(u'tb8', u'tb9').. +- active_dn = self.obj.get_either_dn(*keys, **options) +- superior_dn = DN(self.obj.delete_container_dn, api.env.basedn) +- delete_dn = DN(active_dn[0], self.obj.delete_container_dn, api.env.basedn) +- self.log.debug("preserve move %s -> %s" % (active_dn, delete_dn)) +- +- # Check that this value is a Active user +- try: +- original_entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(active_dn, ['dn']) +- except errors.NotFound: +- raise +- +- # start to move the entry to Delete container +- self._exc_wrapper(keys, options, ldap.move_entry)(active_dn, delete_dn, del_old=True) +- +- # Then clear the credential attributes +- attrs_to_clear = ['krbPrincipalKey', 'krbLastPwdChange', 'krbPasswordExpiration', 'userPassword'] +- try: +- entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn, attrs_to_clear) +- except errors.NotFound: +- raise +- clearedCredential = False +- for attr in attrs_to_clear: +- if attr.lower() in entry_attrs: +- del entry_attrs[attr] +- clearedCredential = True +- if clearedCredential: +- self._exc_wrapper(keys, options, ldap.update_entry)(entry_attrs) +- +- # Then restore some original entry attributes +- attrs_to_restore = [ 'secretary', 'managedby', 'manager', 'ipauniqueid', 'uidnumber', 'gidnumber', 'passwordHistory'] +- try: +- entry_attrs = self._exc_wrapper(keys, options, ldap.get_entry)(delete_dn, attrs_to_restore) +- except errors.NotFound: +- raise +- restoreAttr = False +- for attr in attrs_to_restore: +- if (attr.lower() in original_entry_attrs) and not (attr.lower() in entry_attrs): +- restoreAttr = True +- entry_attrs[attr.lower()] = original_entry_attrs[attr.lower()] +- if restoreAttr: +- self._exc_wrapper(keys, options, ldap.update_entry)(entry_attrs) +- +- val = dict(result=dict(failed=[]), value=[keys[-1][0]]) ++ failed = [] ++ preserved = [] ++ for pkey in keys[-1]: ++ try: ++ self._preserve_user(pkey, delete_container, **options) ++ preserved.append(pkey_to_value(pkey, options)) ++ except: ++ if not options.get('continue', False): ++ raise ++ failed.append(pkey_to_value(pkey, options)) ++ ++ val = dict(result=dict(failed=failed), value=preserved) + return val + else: + return super(user_del, self).execute(*keys, **options) +-- +2.4.3 + diff --git a/SOURCES/0091-rpcclient-use-json_encode_binary-for-verbose-output.patch b/SOURCES/0091-rpcclient-use-json_encode_binary-for-verbose-output.patch deleted file mode 100644 index d9a2916..0000000 --- a/SOURCES/0091-rpcclient-use-json_encode_binary-for-verbose-output.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 83caef88e10d30e001506c3792852b42ad97e8ab Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 12 Jan 2015 14:18:49 +0100 -Subject: [PATCH] rpcclient: use json_encode_binary for verbose output - -`json.dumps` is not able to process some IPA's object types and therefore requires to preprocess it with `json_encode_binary` call. This step was not used in rpcclient's verbose output. - -https://fedorahosted.org/freeipa/ticket/4773 - -Reviewed-By: Martin Basti ---- - ipalib/rpc.py | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/ipalib/rpc.py b/ipalib/rpc.py -index 806f6bb9adf004660c9cb285cf31b09a988afa93..05ef3143324b0f6d260678ad354464511f907eac 100644 ---- a/ipalib/rpc.py -+++ b/ipalib/rpc.py -@@ -967,6 +967,7 @@ class JSONServerProxy(object): - def __request(self, name, args): - payload = {'method': unicode(name), 'params': args, 'id': 0} - version = args[1].get('version', VERSION_WITHOUT_CAPABILITIES) -+ payload = json_encode_binary(payload, version) - - if self.__verbose >= 2: - root_logger.info('Request: %s', -@@ -975,7 +976,7 @@ class JSONServerProxy(object): - response = self.__transport.request( - self.__host, - self.__handler, -- json.dumps(json_encode_binary(payload, version)), -+ json.dumps(payload), - verbose=self.__verbose >= 3, - ) - -@@ -985,8 +986,11 @@ class JSONServerProxy(object): - raise JSONError(str(e)) - - if self.__verbose >= 2: -- root_logger.info('Response: %s', -- json.dumps(response, sort_keys=True, indent=4)) -+ root_logger.info( -+ 'Response: %s', -+ json.dumps(json_encode_binary(response, version), -+ sort_keys=True, indent=4) -+ ) - error = response.get('error') - if error: - try: --- -2.1.0 - diff --git a/SOURCES/0092-DNSSEC-fix-forward-zone-forwarders-checks.patch b/SOURCES/0092-DNSSEC-fix-forward-zone-forwarders-checks.patch new file mode 100644 index 0000000..d4945d7 --- /dev/null +++ b/SOURCES/0092-DNSSEC-fix-forward-zone-forwarders-checks.patch @@ -0,0 +1,47 @@ +From 0f44ee49596f565f78144f676f431cb7f29bf15b Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Mon, 24 Aug 2015 12:53:30 +0200 +Subject: [PATCH] DNSSEC: fix forward zone forwarders checks + +https://fedorahosted.org/freeipa/ticket/5179 + +Reviewed-By: Petr Spacek +--- + ipalib/util.py | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/ipalib/util.py b/ipalib/util.py +index 649a4875fde0b44844749946cce53d81f7f6eea4..a3500ae29b56ac6a289fbec97d15cf026baf7068 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -694,20 +694,21 @@ def validate_dnssec_zone_forwarder_step2(ipa_ip_addr, fwzone, log=None, + ans_cd = _resolve_record(fwzone, rtype, nameserver_ip=ipa_ip_addr, + edns0=True, dnssec=True, flag_cd=True, + timeout=timeout) ++ except NXDOMAIN as e: ++ # sometimes CD flag is ignored and NXDomain is returned ++ _log_response(log, e) ++ raise DNSSECValidationError(owner=fwzone, rtype=rtype, ip=ipa_ip_addr) + except DNSException as e: + _log_response(log, e) ++ raise UnresolvableRecordError(owner=fwzone, rtype=rtype, ++ ip=ipa_ip_addr, error=e) + + try: + ans_do = _resolve_record(fwzone, rtype, nameserver_ip=ipa_ip_addr, + edns0=True, dnssec=True, timeout=timeout) +- except NXDOMAIN as e: +- # sometimes CD flag is ignored and NXDomain is returned +- _log_response(log, e) +- raise DNSSECValidationError(owner=fwzone, rtype=rtype, ip=ipa_ip_addr) + except DNSException as e: + _log_response(log, e) +- raise UnresolvableRecordError(owner=fwzone, rtype=rtype, ip=ipa_ip_addr, +- error=e) ++ raise DNSSECValidationError(owner=fwzone, rtype=rtype, ip=ipa_ip_addr) + else: + if (ans_do.canonical_name == ans_cd.canonical_name + and ans_do.rrset == ans_cd.rrset): +-- +2.4.3 + diff --git a/SOURCES/0092-Remove-ipanttrustauthincoming-ipanttrustauthoutgoing.patch b/SOURCES/0092-Remove-ipanttrustauthincoming-ipanttrustauthoutgoing.patch deleted file mode 100644 index f06b63a..0000000 --- a/SOURCES/0092-Remove-ipanttrustauthincoming-ipanttrustauthoutgoing.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 6fdff1b5891c9e8984dcaa265491c3cc9600aa0d Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 13 Jan 2015 13:23:16 +0100 -Subject: [PATCH] Remove ipanttrustauthincoming/ipanttrustauthoutgoing from ipa - trust-add output. - -https://fedorahosted.org/freeipa/ticket/4787 - -Reviewed-By: Petr Vobornik ---- - ipalib/plugins/trust.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 736cb6f573f9a18eca882db136133205c583b67d..22fbb9c7cb1d3a71f65e24d8d3bc27f62d5a44a5 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -508,6 +508,8 @@ sides. - result['verified'])] - - del result['verified'] -+ result['result'].pop('ipanttrustauthoutgoing', None) -+ result['result'].pop('ipanttrustauthincoming', None) - - return result - --- -2.1.0 - diff --git a/SOURCES/0093-Abort-backup-restoration-on-not-matching-host.patch b/SOURCES/0093-Abort-backup-restoration-on-not-matching-host.patch deleted file mode 100644 index e479b01..0000000 --- a/SOURCES/0093-Abort-backup-restoration-on-not-matching-host.patch +++ /dev/null @@ -1,36 +0,0 @@ -From fe282611598ebdd97e9ca64d4da43c8916b5eb4a Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Sun, 11 Jan 2015 18:45:11 -0500 -Subject: [PATCH] Abort backup restoration on not matching host. - -When restoring backup on master other than it was created there is high risk -of unexpected and hard-to-debug behavior. Refuse such restore. - -https://fedorahosted.org/freeipa/ticket/4823 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/ipa_restore.py | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 097703938a7ba3820f4acae2148760146464fa08..3b4cf6a7c05245076abde7a9c13e53bc9636b69a 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -249,11 +249,9 @@ class Restore(admintool.AdminTool): - (options.instance or options.backend)): - raise admintool.ScriptError('Restore must be in data-only mode when restoring a specific instance or backend.') - if self.backup_host != api.env.host: -- self.log.warning('Host name %s does not match backup name %s' % -+ raise admintool.ScriptError( -+ 'Host name %s does not match backup name %s' % - (api.env.host, self.backup_host)) -- if (not options.unattended and -- not user_input("Continue to restore?", False)): -- raise admintool.ScriptError("Aborted") - if self.backup_ipa_version != str(version.VERSION): - self.log.warning( - "Restoring data from a different release of IPA.\n" --- -2.1.0 - diff --git a/SOURCES/0093-Added-support-for-changing-vault-encryption.patch b/SOURCES/0093-Added-support-for-changing-vault-encryption.patch new file mode 100644 index 0000000..466806e --- /dev/null +++ b/SOURCES/0093-Added-support-for-changing-vault-encryption.patch @@ -0,0 +1,656 @@ +From d3271ee9de63d9c6275184875d05762666ba9088 Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Fri, 31 Jul 2015 07:53:15 +0200 +Subject: [PATCH] Added support for changing vault encryption. + +The vault-mod command has been modified to support changing vault +encryption attributes (i.e. type, password, public/private keys) +in addition to normal attributes (i.e. description). Changing the +encryption requires retrieving the stored secret with the old +attributes and rearchiving it with the new attributes. + +https://fedorahosted.org/freeipa/ticket/5176 + +Reviewed-By: Martin Basti +--- + API.txt | 27 +++- + VERSION | 4 +- + ipalib/plugins/vault.py | 233 ++++++++++++++++++++++++++-- + ipatests/test_xmlrpc/test_vault_plugin.py | 249 ++++++++++++++++++++++++++++++ + 4 files changed, 498 insertions(+), 15 deletions(-) + +diff --git a/API.txt b/API.txt +index b0f456e725a6c3d24c1071b282de5a28c3b5a671..8105cfb5ba61cabcf5c0f7e1c6e44dfc0cacc9cb 100644 +--- a/API.txt ++++ b/API.txt +@@ -5474,11 +5474,12 @@ output: Output('completed', , None) + output: Output('failed', , None) + output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) + command: vault_archive +-args: 1,10,3 ++args: 1,11,3 + arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Bytes('data?') + option: Str('in?') ++option: Flag('override_password?', autofill=True, default=False) + option: Str('password?', cli_name='password') + option: Str('password_file?', cli_name='password_file') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +@@ -5538,6 +5539,30 @@ output: ListOfEntries('result', (, ), Gettext('A list + output: Output('summary', (, ), None) + output: Output('truncated', , None) + command: vault_mod ++args: 1,18,3 ++arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) ++option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') ++option: Flag('change_password?', autofill=True, default=False) ++option: Str('description?', cli_name='desc') ++option: Bytes('ipavaultpublickey?', cli_name='public_key') ++option: Bytes('ipavaultsalt?', cli_name='salt') ++option: Str('ipavaulttype?', cli_name='type') ++option: Str('new_password?', cli_name='new_password') ++option: Str('new_password_file?', cli_name='new_password_file') ++option: Str('old_password?', cli_name='old_password') ++option: Str('old_password_file?', cli_name='old_password_file') ++option: Bytes('private_key?', cli_name='private_key') ++option: Str('private_key_file?', cli_name='private_key_file') ++option: Str('public_key_file?', cli_name='public_key_file') ++option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') ++option: Str('service?') ++option: Flag('shared?', autofill=True, default=False) ++option: Str('username?', cli_name='user') ++option: Str('version?', exclude='webui') ++output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) ++output: Output('summary', (, ), None) ++output: PrimaryKey('value', None, None) ++command: vault_mod_internal + args: 1,15,3 + arg: Str('cn', attribute=True, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=True) + option: Str('addattr*', cli_name='addattr', exclude='webui') +diff --git a/VERSION b/VERSION +index 9fe2f4d4f9ff6ffd42c2ee7493c385b0a432a6a0..3fdd2db88a7b2b6d3bd36ba0d7257c9994bc06af 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=152 +-# Last change: mbasti - add 'user-stage' command ++IPA_API_VERSION_MINOR=153 ++# Last change: edewata - Added support for changing vault encryption. +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 4b2c8a518e5c9a93e5490841a3d2177536c905b1..6a07a76b5b85680536b27fd147d8ec1583bb0bc7 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -116,11 +116,37 @@ EXAMPLES: + ipa vault-show + [--user |--service |--shared] + """) + _(""" +- Modify a vault: ++ Modify vault description: + ipa vault-mod + [--user |--service |--shared] + --desc + """) + _(""" ++ Modify vault type: ++ ipa vault-mod ++ [--user |--service |--shared] ++ --type ++ [old password/private key] ++ [new password/public key] ++""") + _(""" ++ Modify symmetric vault password: ++ ipa vault-mod ++ [--user |--service |--shared] ++ --change-password ++ ipa vault-mod ++ [--user |--service |--shared] ++ --old-password ++ --new-password ++ ipa vault-mod ++ [--user |--service |--shared] ++ --old-password-file ++ --new-password-file ++""") + _(""" ++ Modify asymmetric vault keys: ++ ipa vault-mod ++ [--user |--service |--shared] ++ --private-key-file ++ --public-key-file ++""") + _(""" + Delete a vault: + ipa vault-del + [--user |--service |--shared] +@@ -457,7 +483,7 @@ class vault(LDAPObject): + + print ' ** Passwords do not match! **' + +- def get_existing_password(self, new=False): ++ def get_existing_password(self): + """ + Gets existing password from user. + """ +@@ -871,9 +897,182 @@ class vault_find(LDAPSearch): + + + @register() +-class vault_mod(LDAPUpdate): ++class vault_mod(PKQuery, Local): + __doc__ = _('Modify a vault.') + ++ takes_options = vault_options + ( ++ Str( ++ 'description?', ++ cli_name='desc', ++ doc=_('Vault description'), ++ ), ++ Str( ++ 'ipavaulttype?', ++ cli_name='type', ++ doc=_('Vault type'), ++ ), ++ Bytes( ++ 'ipavaultsalt?', ++ cli_name='salt', ++ doc=_('Vault salt'), ++ ), ++ Flag( ++ 'change_password?', ++ doc=_('Change password'), ++ ), ++ Str( ++ 'old_password?', ++ cli_name='old_password', ++ doc=_('Old vault password'), ++ ), ++ Str( # TODO: use File parameter ++ 'old_password_file?', ++ cli_name='old_password_file', ++ doc=_('File containing the old vault password'), ++ ), ++ Str( ++ 'new_password?', ++ cli_name='new_password', ++ doc=_('New vault password'), ++ ), ++ Str( # TODO: use File parameter ++ 'new_password_file?', ++ cli_name='new_password_file', ++ doc=_('File containing the new vault password'), ++ ), ++ Bytes( ++ 'private_key?', ++ cli_name='private_key', ++ doc=_('Old vault private key'), ++ ), ++ Str( # TODO: use File parameter ++ 'private_key_file?', ++ cli_name='private_key_file', ++ doc=_('File containing the old vault private key'), ++ ), ++ Bytes( ++ 'ipavaultpublickey?', ++ cli_name='public_key', ++ doc=_('New vault public key'), ++ ), ++ Str( # TODO: use File parameter ++ 'public_key_file?', ++ cli_name='public_key_file', ++ doc=_('File containing the new vault public key'), ++ ), ++ ) ++ ++ has_output = output.standard_entry ++ ++ def forward(self, *args, **options): ++ ++ vault_type = options.pop('ipavaulttype', False) ++ salt = options.pop('ipavaultsalt', False) ++ change_password = options.pop('change_password', False) ++ ++ old_password = options.pop('old_password', None) ++ old_password_file = options.pop('old_password_file', None) ++ new_password = options.pop('new_password', None) ++ new_password_file = options.pop('new_password_file', None) ++ ++ old_private_key = options.pop('private_key', None) ++ old_private_key_file = options.pop('private_key_file', None) ++ new_public_key = options.pop('ipavaultpublickey', None) ++ new_public_key_file = options.pop('public_key_file', None) ++ ++ if self.api.env.in_server: ++ backend = self.api.Backend.ldap2 ++ else: ++ backend = self.api.Backend.rpcclient ++ if not backend.isconnected(): ++ backend.connect(ccache=krbV.default_context().default_ccache()) ++ ++ # determine the vault type based on parameters specified ++ if vault_type: ++ pass ++ ++ elif change_password or new_password or new_password_file or salt: ++ vault_type = u'symmetric' ++ ++ elif new_public_key or new_public_key_file: ++ vault_type = u'asymmetric' ++ ++ # if vault type is specified, retrieve existing secret ++ if vault_type: ++ opts = options.copy() ++ opts.pop('description', None) ++ ++ opts['password'] = old_password ++ opts['password_file'] = old_password_file ++ opts['private_key'] = old_private_key ++ opts['private_key_file'] = old_private_key_file ++ ++ response = self.api.Command.vault_retrieve(*args, **opts) ++ data = response['result']['data'] ++ ++ opts = options.copy() ++ ++ # if vault type is specified, update crypto attributes ++ if vault_type: ++ opts['ipavaulttype'] = vault_type ++ ++ if vault_type == u'standard': ++ opts['ipavaultsalt'] = None ++ opts['ipavaultpublickey'] = None ++ ++ elif vault_type == u'symmetric': ++ if salt: ++ opts['ipavaultsalt'] = salt ++ else: ++ opts['ipavaultsalt'] = os.urandom(16) ++ ++ opts['ipavaultpublickey'] = None ++ ++ elif vault_type == u'asymmetric': ++ ++ # get new vault public key ++ if new_public_key and new_public_key_file: ++ raise errors.MutuallyExclusiveError( ++ reason=_('New public key specified multiple times')) ++ ++ elif new_public_key: ++ pass ++ ++ elif new_public_key_file: ++ new_public_key = validated_read('public_key_file', ++ new_public_key_file, ++ mode='rb') ++ ++ else: ++ raise errors.ValidationError( ++ name='ipavaultpublickey', ++ error=_('Missing new vault public key')) ++ ++ opts['ipavaultsalt'] = None ++ opts['ipavaultpublickey'] = new_public_key ++ ++ response = self.api.Command.vault_mod_internal(*args, **opts) ++ ++ # if vault type is specified, rearchive existing secret ++ if vault_type: ++ opts = options.copy() ++ opts.pop('description', None) ++ ++ opts['data'] = data ++ opts['password'] = new_password ++ opts['password_file'] = new_password_file ++ opts['override_password'] = True ++ ++ self.api.Command.vault_archive(*args, **opts) ++ ++ return response ++ ++ ++@register() ++class vault_mod_internal(LDAPUpdate): ++ ++ NO_CLI = True ++ + takes_options = LDAPUpdate.takes_options + vault_options + + msg_summary = _('Modified vault "%(value)s"') +@@ -994,6 +1193,10 @@ class vault_archive(PKQuery, Local): + cli_name='password_file', + doc=_('File containing the vault password'), + ), ++ Flag( ++ 'override_password?', ++ doc=_('Override existing password'), ++ ), + ) + + has_output = output.standard_entry +@@ -1008,6 +1211,8 @@ class vault_archive(PKQuery, Local): + password = options.get('password') + password_file = options.get('password_file') + ++ override_password = options.pop('override_password', False) ++ + # don't send these parameters to server + if 'data' in options: + del options['data'] +@@ -1062,15 +1267,19 @@ class vault_archive(PKQuery, Local): + password = password.rstrip('\n') + + else: +- password = self.obj.get_existing_password() +- +- # verify password by retrieving existing data +- opts = options.copy() +- opts['password'] = password +- try: +- self.api.Command.vault_retrieve(*args, **opts) +- except errors.NotFound: +- pass ++ if override_password: ++ password = self.obj.get_new_password() ++ else: ++ password = self.obj.get_existing_password() ++ ++ if not override_password: ++ # verify password by retrieving existing data ++ opts = options.copy() ++ opts['password'] = password ++ try: ++ self.api.Command.vault_retrieve(*args, **opts) ++ except errors.NotFound: ++ pass + + salt = vault['ipavaultsalt'][0] + +diff --git a/ipatests/test_xmlrpc/test_vault_plugin.py b/ipatests/test_xmlrpc/test_vault_plugin.py +index fe2f2f67d664e0640fdda99fd3e2f068ee61cb01..40ce46406702740ef5a781c3d3569b4f2e088b92 100644 +--- a/ipatests/test_xmlrpc/test_vault_plugin.py ++++ b/ipatests/test_xmlrpc/test_vault_plugin.py +@@ -36,6 +36,7 @@ asymmetric_vault_name = u'asymmetric_test_vault' + secret = ''.join(map(chr, xrange(0, 256))) + + password = u'password' ++other_password = u'other_password' + + public_key = """ + -----BEGIN PUBLIC KEY----- +@@ -79,6 +80,48 @@ kUlCMj24a8XsShzYTWBIyW2ngvGe3pQ9PfjkUdm0LGZjYITCBvgOKw== + -----END RSA PRIVATE KEY----- + """ + ++other_public_key = """ ++-----BEGIN PUBLIC KEY----- ++MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7E/QLVyKjrgDctZ50U7 ++rmtL7Ks1QLoccp9WvZJ6WI1rYd0fX5FySS4dI6QTNZc6qww8NeNuZtkoxT9m1wkk ++Rl/3wK7fWNLenH/+VHOaTQc20exg7ztfsO7JIsmKmigtticdR5C4jLfjcOp+WjLH ++w3zrmrO5SIZ8njxMoDcQJa2vu/t281U/I7ti8ue09FSitIECU05vgmPS+MnXR8HK ++PxXqrNkjl29mXNbPiByWwlse3Prwved9I7fwgpiHJqUBFudD/0tZ4DWyLG7t9wM1 ++O8gRaRg1r+ENVpmMSvXo4+8+bR3rEYddD5zU7nKXafeuthXlXplae/8uZmCiSI63 ++TwIDAQAB ++-----END PUBLIC KEY----- ++""" ++ ++other_private_key = """ ++-----BEGIN RSA PRIVATE KEY----- ++MIIEpgIBAAKCAQEAv7E/QLVyKjrgDctZ50U7rmtL7Ks1QLoccp9WvZJ6WI1rYd0f ++X5FySS4dI6QTNZc6qww8NeNuZtkoxT9m1wkkRl/3wK7fWNLenH/+VHOaTQc20exg ++7ztfsO7JIsmKmigtticdR5C4jLfjcOp+WjLHw3zrmrO5SIZ8njxMoDcQJa2vu/t2 ++81U/I7ti8ue09FSitIECU05vgmPS+MnXR8HKPxXqrNkjl29mXNbPiByWwlse3Prw ++ved9I7fwgpiHJqUBFudD/0tZ4DWyLG7t9wM1O8gRaRg1r+ENVpmMSvXo4+8+bR3r ++EYddD5zU7nKXafeuthXlXplae/8uZmCiSI63TwIDAQABAoIBAQCA+0GFR9F+isjx ++Xy+qBpKmxLl8kKKvX8r+cSpLOkEqTlW/rqqKgnI0vVuL/L2UJKKsLvpghBxoBZyC ++RCvtatBGrhIlS0UrHg/9m73Ek1hylfUUAQokTn4PrkwWJSgmm/xOATmZSs5ymNTn ++yFCmXl69sdNR77YvD5bQXeBtOT+bKXy7yQ1TmYPwwSjL+WSlMV6ZfE3HNVmxPTpk ++CTFS638cJblWk9MUIy8HIlhu6If2P4RnHr7ZGGivhREayvs0zXcAfqhIyFHruxSE ++yYnmqH9paWjv5mP3YyLoKr+NUvvxnBr/9wCTt0TKgG8G6rpkHuPDLQni9wUGnew8 ++QdMgFEohAoGBAPH4vaVB5gDVfvIqwJBsBLHpPq72GvxjrM/exD0jIIpXZxz9gCql ++CmC5b1RS1uy8PMoc/RO4CE7UTLaTesciP6LjTD1RhH3rLLJO8/iVC1RXgMrCLHLm ++ZQnDhIQGGNQxpvBjQy5ZOWat2dFxYhHN630IFPOtrWsOmJ5HsL1JrjzxAoGBAMrO ++R1zNwQ42VbJS6AFshZVjmUV2h3REGh4zG/9IqL0Hz493hyCTGoDPLLXIbtkqNqzQ ++XibSZ9RMVPKKTiNQTx91DTgh4Anz8xUr84tA2iAf3ayNWKi3Y3GhmP2EWp1qYeom ++kV8Uq0lt4dHZuEo3LuqvbtbzlF9qUXqKS5qy6Tg/AoGBAKCp02o2HjzxhS/QeTmr ++r1ZeE7PiTzrECAuh01TwzPtuW1XhcEdgfEqK9cPcmT5pIkflBZkhOcr1pdYYiI5O ++TEigeY/BX6KoE251hALLG9GtpCN82DyWhAH+oy9ySOwj5793eTT+I2HtD1LE4SQH ++QVQsmJTP/fS2pVl7KnwUvy9RAoGBAKzo2qchNewsHzx+uxgbsnkABfnXaP2T4sDE ++yqYJCPTB6BFl02vOf9Y6zN/gF8JH333P2bY3xhaXTgXMLXqmSg+D+NVW7HEP8Lyo ++UGj1zgN9p74qdODEGqETKiFb6vYzcW/1mhP6x18/tDz658k+611kXZge7O288+MK ++bhNjXrx5AoGBAMox25PcxVgOjCd9+LdUcIOG6LQ971eCH1NKL9YAekICnwMrStbK ++veCYju6ok4ZWnMiH8MR1jgC39RWtjJZwynCuPXUP2/vZkoVf1tCZyz7dSm8TdS/2 ++5NdOHVy7+NQcEPSm7/FmXdpcR9ZSGAuxMBfnEUibdyz5LdJGnFUN/+HS ++-----END RSA PRIVATE KEY----- ++""" ++ + + class test_vault_plugin(Declarative): + +@@ -580,6 +623,48 @@ class test_vault_plugin(Declarative): + }, + + { ++ 'desc': 'Change standard vault to symmetric vault', ++ 'command': ( ++ 'vault_mod', ++ [standard_vault_name], ++ { ++ 'ipavaulttype': u'symmetric', ++ 'new_password': password, ++ }, ++ ), ++ 'expected': { ++ 'value': standard_vault_name, ++ 'summary': u'Modified vault "%s"' % standard_vault_name, ++ 'result': { ++ 'cn': [standard_vault_name], ++ 'ipavaulttype': [u'symmetric'], ++ 'ipavaultsalt': [fuzzy_string], ++ 'owner_user': [u'admin'], ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Retrieve secret from standard vault converted to ' ++ 'symmetric vault', ++ 'command': ( ++ 'vault_retrieve', ++ [standard_vault_name], ++ { ++ 'password': password, ++ }, ++ ), ++ 'expected': { ++ 'value': standard_vault_name, ++ 'summary': 'Retrieved data from vault "%s"' ++ % standard_vault_name, ++ 'result': { ++ 'data': secret, ++ }, ++ }, ++ }, ++ ++ { + 'desc': 'Create symmetric vault', + 'command': ( + 'vault_add', +@@ -642,6 +727,90 @@ class test_vault_plugin(Declarative): + }, + + { ++ 'desc': 'Change symmetric vault password', ++ 'command': ( ++ 'vault_mod', ++ [symmetric_vault_name], ++ { ++ 'old_password': password, ++ 'new_password': other_password, ++ }, ++ ), ++ 'expected': { ++ 'value': symmetric_vault_name, ++ 'summary': u'Modified vault "%s"' % symmetric_vault_name, ++ 'result': { ++ 'cn': [symmetric_vault_name], ++ 'ipavaulttype': [u'symmetric'], ++ 'ipavaultsalt': [fuzzy_string], ++ 'owner_user': [u'admin'], ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Retrieve secret from symmetric vault with new password', ++ 'command': ( ++ 'vault_retrieve', ++ [symmetric_vault_name], ++ { ++ 'password': other_password, ++ }, ++ ), ++ 'expected': { ++ 'value': symmetric_vault_name, ++ 'summary': 'Retrieved data from vault "%s"' ++ % symmetric_vault_name, ++ 'result': { ++ 'data': secret, ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Change symmetric vault to asymmetric vault', ++ 'command': ( ++ 'vault_mod', ++ [symmetric_vault_name], ++ { ++ 'ipavaulttype': u'asymmetric', ++ 'old_password': other_password, ++ 'ipavaultpublickey': public_key, ++ }, ++ ), ++ 'expected': { ++ 'value': symmetric_vault_name, ++ 'summary': u'Modified vault "%s"' % symmetric_vault_name, ++ 'result': { ++ 'cn': [symmetric_vault_name], ++ 'ipavaulttype': [u'asymmetric'], ++ 'ipavaultpublickey': [public_key], ++ 'owner_user': [u'admin'], ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Retrieve secret from symmetric vault converted to ' ++ 'asymmetric vault', ++ 'command': ( ++ 'vault_retrieve', ++ [symmetric_vault_name], ++ { ++ 'private_key': private_key, ++ }, ++ ), ++ 'expected': { ++ 'value': symmetric_vault_name, ++ 'summary': 'Retrieved data from vault "%s"' ++ % symmetric_vault_name, ++ 'result': { ++ 'data': secret, ++ }, ++ }, ++ }, ++ ++ { + 'desc': 'Create asymmetric vault', + 'command': ( + 'vault_add', +@@ -702,4 +871,84 @@ class test_vault_plugin(Declarative): + }, + }, + ++ { ++ 'desc': 'Change asymmetric vault keys', ++ 'command': ( ++ 'vault_mod', ++ [asymmetric_vault_name], ++ { ++ 'private_key': private_key, ++ 'ipavaultpublickey': other_public_key, ++ }, ++ ), ++ 'expected': { ++ 'value': asymmetric_vault_name, ++ 'summary': u'Modified vault "%s"' % asymmetric_vault_name, ++ 'result': { ++ 'cn': [asymmetric_vault_name], ++ 'ipavaulttype': [u'asymmetric'], ++ 'ipavaultpublickey': [other_public_key], ++ 'owner_user': [u'admin'], ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Retrieve secret from asymmetric vault with new keys', ++ 'command': ( ++ 'vault_retrieve', ++ [asymmetric_vault_name], ++ { ++ 'private_key': other_private_key, ++ }, ++ ), ++ 'expected': { ++ 'value': asymmetric_vault_name, ++ 'summary': 'Retrieved data from vault "%s"' ++ % asymmetric_vault_name, ++ 'result': { ++ 'data': secret, ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Change asymmetric vault to standard vault', ++ 'command': ( ++ 'vault_mod', ++ [asymmetric_vault_name], ++ { ++ 'ipavaulttype': u'standard', ++ 'private_key': other_private_key, ++ }, ++ ), ++ 'expected': { ++ 'value': asymmetric_vault_name, ++ 'summary': u'Modified vault "%s"' % asymmetric_vault_name, ++ 'result': { ++ 'cn': [asymmetric_vault_name], ++ 'ipavaulttype': [u'standard'], ++ 'owner_user': [u'admin'], ++ }, ++ }, ++ }, ++ ++ { ++ 'desc': 'Retrieve secret from asymmetric vault converted to ' ++ 'standard vault', ++ 'command': ( ++ 'vault_retrieve', ++ [asymmetric_vault_name], ++ {}, ++ ), ++ 'expected': { ++ 'value': asymmetric_vault_name, ++ 'summary': 'Retrieved data from vault "%s"' ++ % asymmetric_vault_name, ++ 'result': { ++ 'data': secret, ++ }, ++ }, ++ }, ++ + ] +-- +2.4.3 + diff --git a/SOURCES/0094-Fix-ipa-restore-on-systems-without-IPA-installed.patch b/SOURCES/0094-Fix-ipa-restore-on-systems-without-IPA-installed.patch deleted file mode 100644 index a95caa7..0000000 --- a/SOURCES/0094-Fix-ipa-restore-on-systems-without-IPA-installed.patch +++ /dev/null @@ -1,34 +0,0 @@ -From ce55779854e90bb03230dc010092dddf1e9fde67 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 12 Jan 2015 17:03:22 +0000 -Subject: [PATCH] Fix ipa-restore on systems without IPA installed - -https://fedorahosted.org/freeipa/ticket/4824 - -Reviewed-By: Petr Vobornik ---- - ipaserver/install/ipa_restore.py | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 3b4cf6a7c05245076abde7a9c13e53bc9636b69a..f3a60fcc7a60c38c0d2ae1e52fc4fe7712411ec1 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -692,8 +692,12 @@ class Restore(admintool.AdminTool): - cainstance.stop_tracking_certificates( - dogtag.configured_constants()) - httpinstance.HTTPInstance().stop_tracking_certificates() -- dsinstance.DsInstance().stop_tracking_certificates( -- realm_to_serverid(api.env.realm)) -+ try: -+ dsinstance.DsInstance().stop_tracking_certificates( -+ realm_to_serverid(api.env.realm)) -+ except OSError: -+ # When IPA is not installed, DS NSS DB does not exist -+ pass - - for basename in ('cert8.db', 'key3.db', 'secmod.db', 'pwdfile.txt'): - filename = os.path.join(paths.IPA_NSSDB_DIR, basename) --- -2.1.0 - diff --git a/SOURCES/0094-vault-change-default-vault-type-to-symmetric.patch b/SOURCES/0094-vault-change-default-vault-type-to-symmetric.patch new file mode 100644 index 0000000..791afdb --- /dev/null +++ b/SOURCES/0094-vault-change-default-vault-type-to-symmetric.patch @@ -0,0 +1,115 @@ +From 1c3faaeec41e54896536f2a3f2c3a2034d99bbdf Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 25 Aug 2015 18:25:50 +0200 +Subject: [PATCH] vault: change default vault type to symmetric + +https://fedorahosted.org/freeipa/ticket/5251 + +Reviewed-By: Martin Basti +--- + API.txt | 8 ++++---- + VERSION | 4 ++-- + ipalib/plugins/vault.py | 11 ++++++++--- + 3 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/API.txt b/API.txt +index 8105cfb5ba61cabcf5c0f7e1c6e44dfc0cacc9cb..871ddb5b7ee8b9bbae219eac673d52ad7229edc7 100644 +--- a/API.txt ++++ b/API.txt +@@ -5411,7 +5411,7 @@ option: Str('addattr*', cli_name='addattr', exclude='webui') + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('description?', cli_name='desc') + option: Bytes('ipavaultpublickey?', cli_name='public_key') +-option: Str('ipavaulttype?', cli_name='type') ++option: StrEnum('ipavaulttype?', autofill=True, cli_name='type', default=u'symmetric', values=(u'standard', u'symmetric', u'asymmetric')) + option: Str('password?', cli_name='password') + option: Str('password_file?', cli_name='password_file') + option: Str('public_key_file?', cli_name='public_key_file') +@@ -5431,7 +5431,7 @@ option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui + option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False) + option: Bytes('ipavaultpublickey', attribute=True, cli_name='public_key', multivalue=False, required=False) + option: Bytes('ipavaultsalt', attribute=True, cli_name='salt', multivalue=False, required=False) +-option: StrEnum('ipavaulttype', attribute=True, autofill=True, cli_name='type', default=u'standard', multivalue=False, required=False, values=(u'standard', u'symmetric', u'asymmetric')) ++option: StrEnum('ipavaulttype', attribute=True, autofill=True, cli_name='type', default=u'symmetric', multivalue=False, required=False, values=(u'standard', u'symmetric', u'asymmetric')) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Str('service?') +@@ -5522,7 +5522,7 @@ arg: Str('criteria?', noextrawhitespace=False) + option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') + option: Str('cn', attribute=True, autofill=False, cli_name='name', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.-]+$', primary_key=True, query=True, required=False) + option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False) +-option: StrEnum('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'standard', multivalue=False, query=True, required=False, values=(u'standard', u'symmetric', u'asymmetric')) ++option: StrEnum('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'symmetric', multivalue=False, query=True, required=False, values=(u'standard', u'symmetric', u'asymmetric')) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('pkey_only?', autofill=True, default=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +@@ -5571,7 +5571,7 @@ option: Str('delattr*', cli_name='delattr', exclude='webui') + option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False) + option: Bytes('ipavaultpublickey', attribute=True, autofill=False, cli_name='public_key', multivalue=False, required=False) + option: Bytes('ipavaultsalt', attribute=True, autofill=False, cli_name='salt', multivalue=False, required=False) +-option: StrEnum('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'standard', multivalue=False, required=False, values=(u'standard', u'symmetric', u'asymmetric')) ++option: StrEnum('ipavaulttype', attribute=True, autofill=False, cli_name='type', default=u'symmetric', multivalue=False, required=False, values=(u'standard', u'symmetric', u'asymmetric')) + option: Flag('no_members', autofill=True, default=False, exclude='webui') + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') + option: Flag('rights', autofill=True, default=False) +diff --git a/VERSION b/VERSION +index 3fdd2db88a7b2b6d3bd36ba0d7257c9994bc06af..c102e020bbbec921b0f4a2141d1c768ac093acf8 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=153 +-# Last change: edewata - Added support for changing vault encryption. ++IPA_API_VERSION_MINOR=154 ++# Last change: pvoborni - change default vault type to 'symmetric' +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 6a07a76b5b85680536b27fd147d8ec1583bb0bc7..667524465031b6d027afbabeea48871e29c0e1e4 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -101,6 +101,7 @@ EXAMPLES: + Add a standard vault: + ipa vault-add + [--user |--service |--shared] ++ --type standard + """) + _(""" + Add a symmetric vault: + ipa vault-add +@@ -311,7 +312,7 @@ class vault(LDAPObject): + label=_('Type'), + doc=_('Vault type'), + values=(u'standard', u'symmetric', u'asymmetric', ), +- default=u'standard', ++ default=u'symmetric', + autofill=True, + ), + Bytes( +@@ -578,10 +579,14 @@ class vault_add(PKQuery, Local): + cli_name='desc', + doc=_('Vault description'), + ), +- Str( ++ StrEnum( + 'ipavaulttype?', + cli_name='type', ++ label=_('Type'), + doc=_('Vault type'), ++ values=(u'standard', u'symmetric', u'asymmetric', ), ++ default=u'symmetric', ++ autofill=True, + ), + Str( + 'password?', +@@ -609,7 +614,7 @@ class vault_add(PKQuery, Local): + + def forward(self, *args, **options): + +- vault_type = options.get('ipavaulttype', u'standard') ++ vault_type = options.get('ipavaulttype') + password = options.get('password') + password_file = options.get('password_file') + public_key = options.get('ipavaultpublickey') +-- +2.4.3 + diff --git a/SOURCES/0095-Remove-RUV-from-LDIF-files-before-using-them-in-ipa-.patch b/SOURCES/0095-Remove-RUV-from-LDIF-files-before-using-them-in-ipa-.patch deleted file mode 100644 index 28976ce..0000000 --- a/SOURCES/0095-Remove-RUV-from-LDIF-files-before-using-them-in-ipa-.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 761257efc18f9f5efedae110ba8cfa5feeb9f8f7 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 12 Jan 2015 15:37:33 +0000 -Subject: [PATCH] Remove RUV from LDIF files before using them in ipa-restore - -https://fedorahosted.org/freeipa/ticket/4822 - -Reviewed-By: Petr Vobornik ---- - ipaserver/install/ipa_restore.py | 36 +++++++++++++++++++++++++++++++++++- - 1 file changed, 35 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index f3a60fcc7a60c38c0d2ae1e52fc4fe7712411ec1..cd98d07f5f7c7b2ea1b1fef9a272229475efcdc9 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -24,6 +24,7 @@ import tempfile - import time - import pwd - from ConfigParser import SafeConfigParser -+import ldif - - from ipalib import api, errors - from ipapython import version, ipautil, certdb, dogtag -@@ -94,6 +95,32 @@ def decrypt_file(tmpdir, filename, keyring): - return dest - - -+class RemoveRUVParser(ldif.LDIFParser): -+ def __init__(self, input_file, writer, logger): -+ ldif.LDIFParser.__init__(self, input_file) -+ self.writer = writer -+ self.log = logger -+ -+ def handle(self, dn, entry): -+ objectclass = None -+ nsuniqueid = None -+ -+ for name, value in entry.iteritems(): -+ name = name.lower() -+ if name == 'objectclass': -+ objectclass = [x.lower() for x in value] -+ elif name == 'nsuniqueid': -+ nsuniqueid = [x.lower() for x in value] -+ -+ if (objectclass and nsuniqueid and -+ 'nstombstone' in objectclass and -+ 'ffffffff-ffffffff-ffffffff-ffffffff' in nsuniqueid): -+ self.log.debug("Removing RUV entry %s", dn) -+ return -+ -+ self.writer.unparse(dn, entry) -+ -+ - class Restore(admintool.AdminTool): - command_name = 'ipa-restore' - log_file_name = paths.IPARESTORE_LOG -@@ -447,7 +474,14 @@ class Restore(admintool.AdminTool): - dn = DN(('cn', cn), ('cn', 'import'), ('cn', 'tasks'), ('cn', 'config')) - - ldifname = '%s-%s.ldif' % (instance, backend) -- ldiffile = os.path.join(self.dir, ldifname) -+ srcldiffile = os.path.join(self.dir, ldifname) -+ ldiffile = '%s.noruv' % srcldiffile -+ -+ with open(ldiffile, 'wb') as out_file: -+ ldif_writer = ldif.LDIFWriter(out_file) -+ with open(srcldiffile, 'rb') as in_file: -+ ldif_parser = RemoveRUVParser(in_file, ldif_writer, self.log) -+ ldif_parser.parse() - - if online: - conn = self.get_connection() --- -2.1.0 - diff --git a/SOURCES/0095-fix-missing-information-in-object-metadata.patch b/SOURCES/0095-fix-missing-information-in-object-metadata.patch new file mode 100644 index 0000000..5c60f17 --- /dev/null +++ b/SOURCES/0095-fix-missing-information-in-object-metadata.patch @@ -0,0 +1,51 @@ +From 6ed7f2846c04c5b6a570787b8022797c279aaaee Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 25 Aug 2015 16:26:00 +0200 +Subject: [PATCH] fix missing information in object metadata + +Missing 'required' values in takes_params causes Web UI to treat required +fields as optional. + +Regression caused by ba0a1c6b33e2519a48754602413c8379fb1f0ff1 + +https://fedorahosted.org/freeipa/ticket/5258 + +Reviewed-By: Martin Basti +--- + ipalib/parameters.py | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/ipalib/parameters.py b/ipalib/parameters.py +index 6cc6f8c9244abb9e895782f40cbdde63b2144d22..5ced5067ed2657962c35d7d675c4ddd822df6a36 100644 +--- a/ipalib/parameters.py ++++ b/ipalib/parameters.py +@@ -922,12 +922,23 @@ class Param(ReadOnly): + + def __json__(self): + json_dict = {} +- for key in self.__kw: +- json_dict[key] = json_serialize(self.__kw[key]) ++ for (a, k, d) in self.kwargs: ++ if k in (callable, DefaultFrom): ++ continue ++ elif isinstance(getattr(self, a), frozenset): ++ json_dict[a] = [k for k in getattr(self, a, [])] ++ else: ++ val = getattr(self, a, '') ++ if val is None: ++ # ignore 'not set' because lack of their presence is ++ # the information itself ++ continue ++ json_dict[a] = json_serialize(val) ++ + json_dict['class'] = self.__class__.__name__ + json_dict['name'] = self.name + json_dict['type'] = self.type.__name__ +- json_dict['flags'] = json_serialize([f for f in self.flags]) ++ + return json_dict + + +-- +2.4.3 + diff --git a/SOURCES/0096-Fix-CA-certificate-renewal-syslog-alert.patch b/SOURCES/0096-Fix-CA-certificate-renewal-syslog-alert.patch deleted file mode 100644 index b1e3792..0000000 --- a/SOURCES/0096-Fix-CA-certificate-renewal-syslog-alert.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 88ec82165561af0d14ec07a82f37156c5d2fa0da Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 8 Jan 2015 16:01:42 +0000 -Subject: [PATCH] Fix CA certificate renewal syslog alert - -https://fedorahosted.org/freeipa/ticket/4820 - -Reviewed-By: David Kupka ---- - install/certmonger/dogtag-ipa-ca-renew-agent-submit | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index c63c0c2c5f863e05cafad293a60d9157c732e7ad..3c6e8175c337f65046f8631f4393aecfbf207f4d 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -403,7 +403,7 @@ def renew_ca_cert(): - - if state == 'retrieve': - result = call_handler(retrieve_cert) -- if result[0] == WAIT_WITH_DELAY and not is_self_signed: -+ if result[0] == REJECTED and not is_self_signed: - syslog.syslog(syslog.LOG_ALERT, - "IPA CA certificate is about to expire, " - "use ipa-cacert-manage to renew it") --- -2.1.0 - diff --git a/SOURCES/0096-webui-add-option-to-establish-bidirectional-trust.patch b/SOURCES/0096-webui-add-option-to-establish-bidirectional-trust.patch new file mode 100644 index 0000000..0532445 --- /dev/null +++ b/SOURCES/0096-webui-add-option-to-establish-bidirectional-trust.patch @@ -0,0 +1,46 @@ +From 85a5f70811b223edf86ce395b9ec781e788758d1 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 25 Aug 2015 17:17:04 +0200 +Subject: [PATCH] webui: add option to establish bidirectional trust + +https://fedorahosted.org/freeipa/ticket/5259 + +Reviewed-By: Tomas Babej +--- + install/ui/src/freeipa/trust.js | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/install/ui/src/freeipa/trust.js b/install/ui/src/freeipa/trust.js +index 51cfefb99fe10010385b528af209ad535e88b673..f26e2f21b7c8a97536a0a5cb23484da4173d6463 100644 +--- a/install/ui/src/freeipa/trust.js ++++ b/install/ui/src/freeipa/trust.js +@@ -172,6 +172,12 @@ return { + widget: 'realm.realm_server' + }, + { ++ $type: 'checkbox', ++ name: 'bidirectional', ++ metadata: '@mc-opt:trust_add:bidirectional', ++ widget: 'realm.bidirectional' ++ }, ++ { + name: 'realm_admin', + label: '@i18n:objects.trust.account', + widget: 'method.realm_admin' +@@ -224,7 +230,12 @@ return { + $type: 'details_section', + name: 'realm', + widgets: [ +- 'realm_server' ++ 'realm_server', ++ { ++ $type: 'checkbox', ++ name: 'bidirectional', ++ tooltip: '@mc-opt:trust_add:bidirectional:doc' ++ } + ] + }, + { +-- +2.4.3 + diff --git a/SOURCES/0097-Do-not-crash-on-unknown-services-in-installutils.sto.patch b/SOURCES/0097-Do-not-crash-on-unknown-services-in-installutils.sto.patch deleted file mode 100644 index f876241..0000000 --- a/SOURCES/0097-Do-not-crash-on-unknown-services-in-installutils.sto.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 3229a4c7ae1167103e954d5101bac1d56b28ce0d Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 13 Jan 2015 10:59:08 +0000 -Subject: [PATCH] Do not crash on unknown services in - installutils.stopped_service - -https://fedorahosted.org/freeipa/ticket/4835 - -Reviewed-By: David Kupka ---- - ipaserver/install/installutils.py | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 0ab09abea03c8b317e7d00466e127cda00ed17d9..e40535d4822f603ea432094c85396c59222dbe5c 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -870,20 +870,22 @@ def stopped_service(service, instance_name=""): - 'the next set of commands is being executed.', service, - log_instance_name) - -+ service_obj = services.service(service) -+ - # Figure out if the service is running, if not, yield -- if not services.knownservices[service].is_running(instance_name): -+ if not service_obj.is_running(instance_name): - root_logger.debug('Service %s%s is not running, continue.', service, - log_instance_name) - yield - else: - # Stop the service, do the required stuff and start it again - root_logger.debug('Stopping %s%s.', service, log_instance_name) -- services.knownservices[service].stop(instance_name) -+ service_obj.stop(instance_name) - try: - yield - finally: - root_logger.debug('Starting %s%s.', service, log_instance_name) -- services.knownservices[service].start(instance_name) -+ service_obj.start(instance_name) - - def check_entropy(): - ''' --- -2.1.0 - diff --git a/SOURCES/0097-Removed-clear-text-passwords-from-KRA-install-log.patch b/SOURCES/0097-Removed-clear-text-passwords-from-KRA-install-log.patch new file mode 100644 index 0000000..b5dda55 --- /dev/null +++ b/SOURCES/0097-Removed-clear-text-passwords-from-KRA-install-log.patch @@ -0,0 +1,95 @@ +From bb60e6d76d0dfa8106e195cc830b3ce685e84f77 Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Sat, 22 Aug 2015 01:14:16 +0200 +Subject: [PATCH] Removed clear text passwords from KRA install log. + +The ipa-kra-install tool has been modified to use password files +instead of clear text passwords when invoking pki tool such that +the passwords are no longer visible in ipaserver-kra-install.log. + +https://fedorahosted.org/freeipa/ticket/5246 + +Reviewed-By: Alexander Bokovoy +--- + ipaplatform/base/paths.py | 2 ++ + ipaserver/install/krainstance.py | 16 ++++++++-------- + 2 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 0dd3c7fda3020264a1ace8f2d13557cfddf18c2d..5c8f25d6ef85fab2b9b30a660cd1c0360dbe9931 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -343,6 +343,8 @@ class BasePathNamespace(object): + SLAPD_INSTANCE_SOCKET_TEMPLATE = "/var/run/slapd-%s.socket" + ALL_SLAPD_INSTANCE_SOCKETS = "/var/run/slapd-*.socket" + ADMIN_CERT_PATH = '/root/.dogtag/pki-tomcat/ca_admin.cert' ++ KRA_NSSDB_PASSWORD_FILE = "/root/.dogtag/pki-tomcat/kra/password.conf" ++ KRA_PKCS12_PASSWORD_FILE = "/root/.dogtag/pki-tomcat/kra/pkcs12_password.conf" + ENTROPY_AVAIL = '/proc/sys/kernel/random/entropy_avail' + LDIF2DB = '/usr/sbin/ldif2db' + DB2LDIF = '/usr/sbin/db2ldif' +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index fa50c3dec897d63b9d3522d196054163f7b3369a..e5cdbf5e7714603041e3f0156e87311994175b18 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -275,16 +275,16 @@ class KRAInstance(DogtagInstance): + # import CA certificate into temporary security database + args = ["/usr/bin/pki", + "-d", self.agent_db, +- "-c", self.admin_password, ++ "-C", paths.KRA_NSSDB_PASSWORD_FILE, + "client-cert-import", + "--pkcs12", paths.KRACERT_P12, +- "--pkcs12-password", self.admin_password] ++ "--pkcs12-password-file", paths.KRA_PKCS12_PASSWORD_FILE] + ipautil.run(args) + + # trust CA certificate + args = ["/usr/bin/pki", + "-d", self.agent_db, +- "-c", self.admin_password, ++ "-C", paths.KRA_NSSDB_PASSWORD_FILE, + "client-cert-mod", "Certificate Authority - %s" % api.env.realm, + "--trust", "CT,c,"] + ipautil.run(args) +@@ -292,16 +292,16 @@ class KRAInstance(DogtagInstance): + # import Dogtag admin certificate into temporary security database + args = ["/usr/bin/pki", + "-d", self.agent_db, +- "-c", self.admin_password, ++ "-C", paths.KRA_NSSDB_PASSWORD_FILE, + "client-cert-import", + "--pkcs12", paths.DOGTAG_ADMIN_P12, +- "--pkcs12-password", self.admin_password] ++ "--pkcs12-password-file", paths.KRA_PKCS12_PASSWORD_FILE] + ipautil.run(args) + + # as Dogtag admin, create ipakra user in KRA + args = ["/usr/bin/pki", + "-d", self.agent_db, +- "-c", self.admin_password, ++ "-C", paths.KRA_NSSDB_PASSWORD_FILE, + "-n", "ipa-ca-agent", + "kra-user-add", "ipakra", + "--fullName", "IPA KRA User"] +@@ -310,7 +310,7 @@ class KRAInstance(DogtagInstance): + # as Dogtag admin, add ipakra into KRA agents group + args = ["/usr/bin/pki", + "-d", self.agent_db, +- "-c", self.admin_password, ++ "-C", paths.KRA_NSSDB_PASSWORD_FILE, + "-n", "ipa-ca-agent", + "kra-user-membership-add", "ipakra", "Data Recovery Manager Agents"] + ipautil.run(args) +@@ -330,7 +330,7 @@ class KRAInstance(DogtagInstance): + # as Dogtag admin, upload and assign ipaCert to ipakra + args = ["/usr/bin/pki", + "-d", self.agent_db, +- "-c", self.admin_password, ++ "-C", paths.KRA_NSSDB_PASSWORD_FILE, + "-n", "ipa-ca-agent", + "kra-user-cert-add", "ipakra", + "--input", filename] +-- +2.4.3 + diff --git a/SOURCES/0098-Restart-dogtag-when-its-server-certificate-is-renewe.patch b/SOURCES/0098-Restart-dogtag-when-its-server-certificate-is-renewe.patch deleted file mode 100644 index e8be4da..0000000 --- a/SOURCES/0098-Restart-dogtag-when-its-server-certificate-is-renewe.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 19494c2409d40fc25387ddafe94c59ef09f68a86 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 6 Jan 2015 13:08:54 +0000 -Subject: [PATCH] Restart dogtag when its server certificate is renewed - -https://fedorahosted.org/freeipa/ticket/4803 - -Reviewed-By: David Kupka ---- - install/tools/ipa-upgradeconfig | 6 +++--- - ipaserver/install/cainstance.py | 7 ++++--- - 2 files changed, 7 insertions(+), 6 deletions(-) - -diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig -index 005f3a72df115e63c81a7ca8825fb12cac0a5f81..b00161d58418d6205c0ba0db0260af272ec96130 100755 ---- a/install/tools/ipa-upgradeconfig -+++ b/install/tools/ipa-upgradeconfig -@@ -778,7 +778,7 @@ def certificate_renewal_update(ca): - dogtag_constants = dogtag.configured_constants() - - # bump version when requests is changed -- version = 2 -+ version = 3 - requests = ( - ( - dogtag_constants.ALIAS_DIR, -@@ -824,8 +824,8 @@ def certificate_renewal_update(ca): - dogtag_constants.ALIAS_DIR, - 'Server-Cert cert-pki-ca', - 'dogtag-ipa-renew-agent', -- None, -- None, -+ 'stop_pkicad', -+ 'renew_ca_cert', - None, - ), - ) -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index ac494917744ce0fa2d8e38ce5ce9dab6b24bdebf..aac7f4c7ccbad5a68bfd9756c7f7638416e3f6a0 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1534,16 +1534,17 @@ class CAInstance(service.Service): - done by the renewal script, renew_ca_cert once all the subsystem - certificates are renewed. - """ -+ nickname = 'Server-Cert cert-pki-ca' - pin = self.__get_ca_pin() - try: - certmonger.dogtag_start_tracking( - ca='dogtag-ipa-renew-agent', -- nickname='Server-Cert cert-pki-ca', -+ nickname=nickname, - pin=pin, - pinfile=None, - secdir=self.dogtag_constants.ALIAS_DIR, -- pre_command=None, -- post_command=None) -+ pre_command='stop_pkicad', -+ post_command='renew_ca_cert "%s"' % nickname) - except RuntimeError, e: - root_logger.error( - "certmonger failed to start tracking certificate: %s" % e) --- -2.1.0 - diff --git a/SOURCES/0098-certprofile-prevent-rename-modrdn.patch b/SOURCES/0098-certprofile-prevent-rename-modrdn.patch new file mode 100644 index 0000000..5fab0b7 --- /dev/null +++ b/SOURCES/0098-certprofile-prevent-rename-modrdn.patch @@ -0,0 +1,30 @@ +From 80767a47c9eda6c82f172b87a6a901be9ebf0c9a Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Mon, 24 Aug 2015 20:25:10 -0400 +Subject: [PATCH] certprofile: prevent rename (modrdn) + +Fixes: https://fedorahosted.org/freeipa/ticket/5247 +Reviewed-By: Alexander Bokovoy +--- + ipalib/plugins/certprofile.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index 007cc543406b7e5705fd7474f3685cd6a9ce6aca..a0ffa38608400860994c771e4eba81304ead27be 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -323,8 +323,9 @@ class certprofile_mod(LDAPUpdate): + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + ca_enabled_check() + # Once a profile id is set it cannot be changed +- if 'cn' in entry_attrs: +- raise errors.ACIError(info=_('cn is immutable')) ++ if 'rename' in options or 'cn' in entry_attrs: ++ raise errors.ProtectedEntryError(label='certprofile', key=keys[0], ++ reason=_('Certificate profiles cannot be renamed')) + if 'file' in options: + with self.api.Backend.ra_certprofile as profile_api: + profile_api.disable_profile(keys[0]) +-- +2.4.3 + diff --git a/SOURCES/0099-Make-certificate-renewal-process-synchronized.patch b/SOURCES/0099-Make-certificate-renewal-process-synchronized.patch deleted file mode 100644 index 3275e64..0000000 --- a/SOURCES/0099-Make-certificate-renewal-process-synchronized.patch +++ /dev/null @@ -1,581 +0,0 @@ -From c0d13f5e58cb84eb3162aec1c2202329230c120d Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 8 Jan 2015 09:06:46 +0000 -Subject: [PATCH] Make certificate renewal process synchronized - -Synchronization is achieved using a global renewal lock. - -https://fedorahosted.org/freeipa/ticket/4803 - -Reviewed-By: David Kupka ---- - freeipa.spec.in | 1 + - install/certmonger/Makefile.am | 1 + - .../certmonger/dogtag-ipa-ca-renew-agent-submit | 4 +- - install/certmonger/ipa-server-guard | 55 +++++++++++ - install/restart_scripts/renew_ca_cert | 11 ++- - install/restart_scripts/renew_ra_cert | 11 ++- - install/restart_scripts/restart_dirsrv | 10 +- - install/restart_scripts/restart_httpd | 10 +- - install/restart_scripts/stop_pkicad | 4 + - install/tools/ipa-upgradeconfig | 3 + - ipaplatform/base/paths.py | 2 + - ipaserver/install/cainstance.py | 38 ++++++++ - ipaserver/install/certs.py | 104 +++++++++++++++++++++ - ipaserver/install/httpinstance.py | 42 +++++++++ - 14 files changed, 290 insertions(+), 6 deletions(-) - create mode 100755 install/certmonger/ipa-server-guard - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 1c975b3912d0a7470a32f1b7e314cfde74446e85..b72d05a4c16d58144207233f2078a336b087604d 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -650,6 +650,7 @@ fi - %{_sbindir}/ipa-advise - %{_sbindir}/ipa-cacert-manage - %{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit -+%{_libexecdir}/certmonger/ipa-server-guard - %{_libexecdir}/ipa-otpd - %dir %{_libexecdir}/ipa - %{_libexecdir}/ipa/ipa-dnskeysyncd -diff --git a/install/certmonger/Makefile.am b/install/certmonger/Makefile.am -index ef6a0a635eed77a582bf0c43b40593678326c8eb..2dc476f188cb284f60a284a6cf90cf3c1ee8692f 100644 ---- a/install/certmonger/Makefile.am -+++ b/install/certmonger/Makefile.am -@@ -3,6 +3,7 @@ NULL = - appdir = $(libexecdir)/certmonger/ - app_SCRIPTS = \ - dogtag-ipa-ca-renew-agent-submit \ -+ ipa-server-guard \ - $(NULL) - - EXTRA_DIST = \ -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index 3c6e8175c337f65046f8631f4393aecfbf207f4d..7b91fc61148912c77d0ae962b3847d73e8d0720e 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -38,7 +38,7 @@ from ipapython.dn import DN - from ipalib import api, errors, pkcs10, x509 - from ipaplatform.paths import paths - from ipaserver.plugins.ldap2 import ldap2 --from ipaserver.install import cainstance -+from ipaserver.install import cainstance, certs - - # This is a certmonger CA helper script for IPA CA subsystem cert renewal. See - # https://git.fedorahosted.org/cgit/certmonger.git/tree/doc/submit.txt for more -@@ -437,6 +437,7 @@ def main(): - return OPERATION_NOT_SUPPORTED_BY_HELPER - - tmpdir = tempfile.mkdtemp(prefix="tmp-") -+ certs.renewal_lock.acquire() - try: - principal = str('host/%s@%s' % (api.env.host, api.env.realm)) - ipautil.kinit_hostprincipal(paths.KRB5_KEYTAB, tmpdir, principal) -@@ -456,6 +457,7 @@ def main(): - print item - return res[0] - finally: -+ certs.renewal_lock.release() - shutil.rmtree(tmpdir) - - try: -diff --git a/install/certmonger/ipa-server-guard b/install/certmonger/ipa-server-guard -new file mode 100755 -index 0000000000000000000000000000000000000000..5e31d89b7731a2bafb85cd7fed4a4b9bd6709a2a ---- /dev/null -+++ b/install/certmonger/ipa-server-guard -@@ -0,0 +1,55 @@ -+#!/usr/bin/python2 -E -+# -+# Authors: -+# Jan Cholasta -+# -+# Copyright (C) 2015 Red Hat -+# see file 'COPYING' for use and warranty information -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program. If not, see . -+ -+import os -+# Prevent garbage from readline on standard output -+# (see https://fedorahosted.org/freeipa/ticket/4064) -+if not os.isatty(1): -+ os.environ['TERM'] = 'dumb' -+import sys -+import syslog -+import traceback -+ -+from ipapython import ipautil -+from ipaserver.install import certs -+ -+ -+def main(): -+ if len(sys.argv) < 2: -+ raise RuntimeError("Not enough arguments") -+ -+ with certs.renewal_lock: -+ stdout, stderr, rc = ipautil.run(sys.argv[1:], raiseonerr=False, -+ env=os.environ) -+ sys.stdout.write(stdout) -+ sys.stdout.flush() -+ sys.stderr.write(stderr) -+ sys.stderr.flush() -+ -+ return rc -+ -+ -+try: -+ sys.exit(main()) -+except Exception, e: -+ syslog.syslog(syslog.LOG_ERR, traceback.format_exc()) -+ print "Internal error" -+ sys.exit(3) -diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert -index 2ad2038703a74fe3549708549091633b35695907..261c424381d8246ab2ca6da2689a7f90010b2a97 100644 ---- a/install/restart_scripts/renew_ca_cert -+++ b/install/restart_scripts/renew_ca_cert -@@ -35,7 +35,8 @@ from ipaserver.plugins.ldap2 import ldap2 - from ipaplatform import services - from ipaplatform.paths import paths - --def main(): -+ -+def _main(): - nickname = sys.argv[1] - - api.bootstrap(context='restart') -@@ -209,6 +210,14 @@ def main(): - syslog.syslog( - syslog.LOG_NOTICE, "Started %s" % dogtag_service.service_name) - -+ -+def main(): -+ try: -+ _main() -+ finally: -+ certs.renewal_lock.release('renew_ca_cert') -+ -+ - try: - main() - except Exception: -diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert -index 6d4b81a5393dcaced56a8335cd0ec6b7a994acdc..7dae3562380e919b2cc5f53825820291fc93fdc5 100644 ---- a/install/restart_scripts/renew_ra_cert -+++ b/install/restart_scripts/renew_ra_cert -@@ -32,9 +32,10 @@ from ipaserver.install import certs, cainstance - from ipaplatform import services - from ipaplatform.paths import paths - --nickname = 'ipaCert' - --def main(): -+def _main(): -+ nickname = 'ipaCert' -+ - api.bootstrap(context='restart') - api.finalize() - -@@ -68,6 +69,12 @@ def main(): - else: - syslog.syslog(syslog.LOG_NOTICE, "Restarted httpd") - -+ -+def main(): -+ with certs.renewal_lock: -+ _main() -+ -+ - try: - main() - except Exception: -diff --git a/install/restart_scripts/restart_dirsrv b/install/restart_scripts/restart_dirsrv -index 837378191765babbcb4b09afec37ab82cb675e28..723644215cb76aa83b2d8eee70070b979986c0cc 100644 ---- a/install/restart_scripts/restart_dirsrv -+++ b/install/restart_scripts/restart_dirsrv -@@ -24,8 +24,10 @@ import syslog - import traceback - from ipalib import api - from ipaplatform import services -+from ipaserver.install import certs - --def main(): -+ -+def _main(): - try: - instance = sys.argv[1] - except IndexError: -@@ -41,6 +43,12 @@ def main(): - except Exception, e: - syslog.syslog(syslog.LOG_ERR, "Cannot restart dirsrv (instance: '%s'): %s" % (instance, str(e))) - -+ -+def main(): -+ with certs.renewal_lock: -+ _main() -+ -+ - try: - main() - except Exception: -diff --git a/install/restart_scripts/restart_httpd b/install/restart_scripts/restart_httpd -index e3ef73c4fad29bd0ca4dda167352ad023d5ff31f..f060a3091d439b7811d680b75d9995f5cc391e53 100644 ---- a/install/restart_scripts/restart_httpd -+++ b/install/restart_scripts/restart_httpd -@@ -22,8 +22,10 @@ - import syslog - import traceback - from ipaplatform import services -+from ipaserver.install import certs - --def main(): -+ -+def _main(): - syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd') - - try: -@@ -31,6 +33,12 @@ def main(): - except Exception, e: - syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e)) - -+ -+def main(): -+ with certs.renewal_lock: -+ _main() -+ -+ - try: - main() - except Exception: -diff --git a/install/restart_scripts/stop_pkicad b/install/restart_scripts/stop_pkicad -index b8866f16edbec8c58327616324357f7f23ba368a..871e5e7616701ef6925fa2725cb1a90ad0aae512 100644 ---- a/install/restart_scripts/stop_pkicad -+++ b/install/restart_scripts/stop_pkicad -@@ -25,6 +25,8 @@ import traceback - from ipapython import dogtag - from ipalib import api - from ipaplatform import services -+from ipaserver.install import certs -+ - - def main(): - api.bootstrap(context='restart') -@@ -34,6 +36,8 @@ def main(): - dogtag_service = services.knownservices[configured_constants.SERVICE_NAME] - dogtag_instance = configured_constants.PKI_INSTANCE_NAME - -+ certs.renewal_lock.acquire('renew_ca_cert') -+ - syslog.syslog(syslog.LOG_NOTICE, "Stopping %s" % dogtag_service.service_name) - try: - dogtag_service.stop(dogtag_instance) -diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig -index b00161d58418d6205c0ba0db0260af272ec96130..3f671c3bd5ebb643201b13b2024447bb1273c292 100755 ---- a/install/tools/ipa-upgradeconfig -+++ b/install/tools/ipa-upgradeconfig -@@ -1372,6 +1372,8 @@ def main(): - ) - upgrade_pki(ca, fstore) - -+ ca.configure_certmonger_renewal_guard() -+ - update_dbmodules(api.env.realm) - uninstall_ipa_kpasswd() - -@@ -1384,6 +1386,7 @@ def main(): - http = httpinstance.HTTPInstance(fstore) - http.configure_selinux_for_httpd() - http.change_mod_nss_port_from_http() -+ http.configure_certmonger_renewal_guard() - - http.stop() - update_mod_nss_protocol(http) -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index 8bfab1bc92f79b5e76555b35a8b646e1ff56f84b..f78c1f940a101038226ff98e229df775028e3bf1 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -204,6 +204,7 @@ class BasePathNamespace(object): - LIBSOFTHSM2_SO_64 = "/usr/lib64/pkcs11/libsofthsm2.so" - DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT = "/usr/libexec/certmonger/dogtag-ipa-ca-renew-agent-submit" - DOGTAG_IPA_RENEW_AGENT_SUBMIT = "/usr/libexec/certmonger/dogtag-ipa-renew-agent-submit" -+ IPA_SERVER_GUARD = "/usr/libexec/certmonger/ipa-server-guard" - IPA_DNSKEYSYNCD_REPLICA = "/usr/libexec/ipa/ipa-dnskeysync-replica" - IPA_DNSKEYSYNCD = "/usr/libexec/ipa/ipa-dnskeysyncd" - IPA_ODS_EXPORTER = "/usr/libexec/ipa/ipa-ods-exporter" -@@ -320,6 +321,7 @@ class BasePathNamespace(object): - VAR_OPENDNSSEC_DIR = "/var/opendnssec" - OPENDNSSEC_KASP_DB = "/var/opendnssec/kasp.db" - VAR_RUN_DIRSRV_DIR = "/var/run/dirsrv" -+ IPA_RENEWAL_LOCK = "/var/run/ipa/renewal.lock" - SVC_LIST_FILE = "/var/run/ipa/services.list" - IPA_MEMCACHED_DIR = "/var/run/ipa_memcached" - VAR_RUN_IPA_MEMCACHED = "/var/run/ipa_memcached/ipa_memcached" -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index aac7f4c7ccbad5a68bfd9756c7f7638416e3f6a0..13a75bbb568a25d155325e7084406eb19e8ffc92 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -37,6 +37,8 @@ import stat - import syslog - import ConfigParser - import dbus -+import shlex -+import pipes - - from ipapython import dogtag - from ipapython.certdb import get_ca_nickname -@@ -1422,6 +1424,16 @@ class CAInstance(service.Service): - if path: - iface.remove_known_ca(path) - -+ helper = self.restore_state('certmonger_dogtag_helper') -+ if helper: -+ path = iface.find_ca_by_nickname('dogtag-ipa-renew-agent') -+ if path: -+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path) -+ ca_iface = dbus.Interface(ca_obj, -+ 'org.freedesktop.DBus.Properties') -+ ca_iface.Set('org.fedorahosted.certmonger.ca', -+ 'external-helper', helper) -+ - cmonger.stop() - - # remove CRL files -@@ -1481,6 +1493,32 @@ class CAInstance(service.Service): - 'dogtag-ipa-ca-renew-agent', - paths.DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT, []) - -+ self.configure_certmonger_renewal_guard() -+ -+ def configure_certmonger_renewal_guard(self): -+ if not self.is_configured(): -+ return -+ -+ bus = dbus.SystemBus() -+ obj = bus.get_object('org.fedorahosted.certmonger', -+ '/org/fedorahosted/certmonger') -+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') -+ path = iface.find_ca_by_nickname('dogtag-ipa-renew-agent') -+ if path: -+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path) -+ ca_iface = dbus.Interface(ca_obj, -+ 'org.freedesktop.DBus.Properties') -+ helper = ca_iface.Get('org.fedorahosted.certmonger.ca', -+ 'external-helper') -+ if helper: -+ args = shlex.split(helper) -+ if args[0] != paths.IPA_SERVER_GUARD: -+ self.backup_state('certmonger_dogtag_helper', helper) -+ args = [paths.IPA_SERVER_GUARD] + args -+ helper = ' '.join(pipes.quote(a) for a in args) -+ ca_iface.Set('org.fedorahosted.certmonger.ca', -+ 'external-helper', helper) -+ - def configure_agent_renewal(self): - try: - certmonger.dogtag_start_tracking( -diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py -index 7292cbbe3574f57d32daa6f1e310669486fa5eff..bc7dccf805386e9fa84b58d2ff9346085e1b93b1 100644 ---- a/ipaserver/install/certs.py -+++ b/ipaserver/install/certs.py -@@ -26,6 +26,10 @@ import xml.dom.minidom - import pwd - import base64 - from hashlib import sha1 -+import fcntl -+import time -+import datetime -+import ConfigParser as configparser - - from ipapython.ipa_log_manager import root_logger - from ipapython import dogtag -@@ -647,3 +651,103 @@ class CertDB(object): - - def export_pem_cert(self, nickname, location): - return self.nssdb.export_pem_cert(nickname, location) -+ -+ -+class _CrossProcessLock(object): -+ _DATETIME_FORMAT = '%Y%m%d%H%M%S%f' -+ -+ def __init__(self, filename): -+ self._filename = filename -+ -+ def __enter__(self): -+ self.acquire() -+ -+ def __exit__(self, exc_type, exc_value, traceback): -+ self.release() -+ -+ def acquire(self, owner=None): -+ self._do(self._acquire, owner) -+ -+ def release(self, owner=None): -+ self._do(self._release, owner) -+ -+ def _acquire(self, owner): -+ now = datetime.datetime.utcnow() -+ -+ if self._locked and now >= self._expire: -+ self._locked = False -+ -+ if self._locked: -+ return False -+ -+ self._locked = True -+ self._owner = owner -+ self._expire = now + datetime.timedelta(hours=1) -+ -+ return True -+ -+ def _release(self, owner): -+ if not self._locked or self._owner != owner: -+ raise RuntimeError("lock not acquired by %s" % owner) -+ -+ self._locked = False -+ self._owner = None -+ self._expire = None -+ -+ return True -+ -+ def _do(self, func, owner): -+ if owner is None: -+ owner = '%s[%s]' % (os.path.basename(sys.argv[0]), os.getpid()) -+ -+ while True: -+ with open(self._filename, 'a+') as f: -+ fcntl.flock(f, fcntl.LOCK_EX) -+ -+ f.seek(0) -+ self._read(f) -+ -+ if func(owner): -+ f.seek(0) -+ f.truncate() -+ self._write(f) -+ return -+ -+ time.sleep(10) -+ -+ def _read(self, fileobj): -+ p = configparser.RawConfigParser() -+ p.readfp(fileobj) -+ -+ try: -+ self._locked = p.getboolean('lock', 'locked') -+ -+ if self._locked: -+ self._owner = p.get('lock', 'owner') -+ -+ expire = p.get('lock', 'expire') -+ try: -+ self._expire = datetime.datetime.strptime( -+ expire, self._DATETIME_FORMAT) -+ except ValueError: -+ raise configparser.Error -+ except configparser.Error: -+ self._locked = False -+ self._owner = None -+ self._expire = None -+ -+ def _write(self, fileobj): -+ p = configparser.RawConfigParser() -+ p.add_section('lock') -+ -+ locked = '1' if self._locked else '0' -+ p.set('lock', 'locked', locked) -+ -+ if self._locked: -+ expire = self._expire.strftime(self._DATETIME_FORMAT) -+ p.set('lock', 'owner', self._owner) -+ p.set('lock', 'expire', expire) -+ -+ p.write(fileobj) -+ -+renewal_lock = _CrossProcessLock(paths.IPA_RENEWAL_LOCK) -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index f9e020039734c7ff61e06ead0e30fb28701d6fc8..2fb315b6b822343860a9c31b016d6a0a22388488 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -23,6 +23,9 @@ import tempfile - import pwd - import shutil - import re -+import dbus -+import shlex -+import pipes - - import service - import certs -@@ -121,6 +124,9 @@ class HTTPInstance(service.Service): - self.step("enabling mod_nss renegotiate", self.enable_mod_nss_renegotiate) - self.step("adding URL rewriting rules", self.__add_include) - self.step("configuring httpd", self.__configure_http) -+ if self.ca_is_configured: -+ self.step("configure certmonger for renewals", -+ self.configure_certmonger_renewal_guard) - self.step("setting up ssl", self.__setup_ssl) - self.step("importing CA certificates from LDAP", self.__import_ca_certs) - if autoconfig: -@@ -221,6 +227,27 @@ class HTTPInstance(service.Service): - if installutils.update_file(paths.HTTPD_NSS_CONF, '', 'Include conf.d/ipa-rewrite.conf\n') != 0: - print "Adding Include conf.d/ipa-rewrite to %s failed." % paths.HTTPD_NSS_CONF - -+ def configure_certmonger_renewal_guard(self): -+ bus = dbus.SystemBus() -+ obj = bus.get_object('org.fedorahosted.certmonger', -+ '/org/fedorahosted/certmonger') -+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') -+ path = iface.find_ca_by_nickname('IPA') -+ if path: -+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path) -+ ca_iface = dbus.Interface(ca_obj, -+ 'org.freedesktop.DBus.Properties') -+ helper = ca_iface.Get('org.fedorahosted.certmonger.ca', -+ 'external-helper') -+ if helper: -+ args = shlex.split(helper) -+ if args[0] != paths.IPA_SERVER_GUARD: -+ self.backup_state('certmonger_ipa_helper', helper) -+ args = [paths.IPA_SERVER_GUARD] + args -+ helper = ' '.join(pipes.quote(a) for a in args) -+ ca_iface.Set('org.fedorahosted.certmonger.ca', -+ 'external-helper', helper) -+ - def __setup_ssl(self): - fqdn = self.fqdn - -@@ -355,6 +382,21 @@ class HTTPInstance(service.Service): - self.stop() - - self.stop_tracking_certificates() -+ -+ helper = self.restore_state('certmonger_ipa_helper') -+ if helper: -+ bus = dbus.SystemBus() -+ obj = bus.get_object('org.fedorahosted.certmonger', -+ '/org/fedorahosted/certmonger') -+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') -+ path = iface.find_ca_by_nickname('IPA') -+ if path: -+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path) -+ ca_iface = dbus.Interface(ca_obj, -+ 'org.freedesktop.DBus.Properties') -+ ca_iface.Set('org.fedorahosted.certmonger.ca', -+ 'external-helper', helper) -+ - if not enabled is None and not enabled: - self.disable() - --- -2.1.0 - diff --git a/SOURCES/0099-vault-Limit-size-of-data-stored-in-vault.patch b/SOURCES/0099-vault-Limit-size-of-data-stored-in-vault.patch new file mode 100644 index 0000000..3606295 --- /dev/null +++ b/SOURCES/0099-vault-Limit-size-of-data-stored-in-vault.patch @@ -0,0 +1,57 @@ +From a9367de918ae4f28159275b32f1d6d4716de0122 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Wed, 26 Aug 2015 14:11:21 +0200 +Subject: [PATCH] vault: Limit size of data stored in vault + +https://fedorahosted.org/freeipa/ticket/5231 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 667524465031b6d027afbabeea48871e29c0e1e4..e369eeee20f5652942681f7c3e268e6173005452 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -237,6 +237,7 @@ def validated_read(argname, filename, mode='r', encoding=None): + + register = Registry() + ++MAX_VAULT_DATA_SIZE = 2**20 # = 1 MB + + vault_options = ( + Str( +@@ -1233,10 +1234,28 @@ class vault_archive(PKQuery, Local): + raise errors.MutuallyExclusiveError( + reason=_('Input data specified multiple times')) + ++ elif data: ++ if len(data) > MAX_VAULT_DATA_SIZE: ++ raise errors.ValidationError(name="data", error=_( ++ "Size of data exceeds the limit. Current vault data size " ++ "limit is %(limit)d B") ++ % {'limit': MAX_VAULT_DATA_SIZE}) ++ + elif input_file: ++ try: ++ stat = os.stat(input_file) ++ except OSError as exc: ++ raise errors.ValidationError(name="in", error=_( ++ "Cannot read file '%(filename)s': %(exc)s") ++ % {'filename': input_file, 'exc': exc[1]}) ++ if stat.st_size > MAX_VAULT_DATA_SIZE: ++ raise errors.ValidationError(name="in", error=_( ++ "Size of data exceeds the limit. Current vault data size " ++ "limit is %(limit)d B") ++ % {'limit': MAX_VAULT_DATA_SIZE}) + data = validated_read('in', input_file, mode='rb') + +- elif not data: ++ else: + data = '' + + if self.api.env.in_server: +-- +2.4.3 + diff --git a/SOURCES/0100-Fix-validation-of-ipa-restore-options.patch b/SOURCES/0100-Fix-validation-of-ipa-restore-options.patch deleted file mode 100644 index c0ee533..0000000 --- a/SOURCES/0100-Fix-validation-of-ipa-restore-options.patch +++ /dev/null @@ -1,313 +0,0 @@ -From 5ec39e80a626e833d8fec24b1797b9c25c072784 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 12 Jan 2015 12:44:21 +0000 -Subject: [PATCH] Fix validation of ipa-restore options - -Fix restore mode checks. Do some of the existing checks earlier to make them -effective. Check if --instance and --backend exist both in the filesystem and -in the backup. - -Log backup type and restore mode before performing restore. - -Update ipa-restore man page. - -https://fedorahosted.org/freeipa/ticket/4797 - -Reviewed-By: Petr Vobornik -Reviewed-By: Martin Kosek ---- - install/tools/man/ipa-restore.1 | 10 +-- - ipaserver/install/ipa_restore.py | 175 +++++++++++++++++++++++---------------- - 2 files changed, 108 insertions(+), 77 deletions(-) - -diff --git a/install/tools/man/ipa-restore.1 b/install/tools/man/ipa-restore.1 -index 31734b259524e4b07312a4009184e725aafc3728..98242e246ab888f326af5ccfa6420fc080261891 100644 ---- a/install/tools/man/ipa-restore.1 -+++ b/install/tools/man/ipa-restore.1 -@@ -64,17 +64,17 @@ Restore the data only. The default is to restore everything in the backup. - The full path to a GPG keyring. The keyring consists of two files, a public and a private key (.sec and .pub respectively). Specify the path without an extension. - .TP - \fB\-\-no\-logs\fR --Exclude the IPA service log files in the backup (if they were backed up). Applicable only with a full backup. -+Exclude the IPA service log files in the backup (if they were backed up). - .TP - \fB\-\-online\fR --Perform the restore on\-line. Requires the \-\-data option. -+Perform the restore on\-line. Requires data\-only backup or the \-\-data option. - .TP - \fB\-\-instance\fR=\fIINSTANCE\fR --The backend to restore within an instance or instances. --.TP --Restore only the databases in this 389\-ds instance. The default is to restore all found (at most this is the IPA REALM instance and the PKI\-IPA instance). -+Restore only the databases in this 389\-ds instance. The default is to restore all found (at most this is the IPA REALM instance and the PKI\-IPA instance). Requires data\-only backup or the \-\-data option. - .TP - \fB\-\-backend\fR=\fIBACKEND\fR -+The backend to restore within an instance or instances. Requires data\-only backup or the \-\-data option. -+.TP - \fB\-\-v\fR, \fB\-\-verbose\fR - Print debugging information - .TP -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index cd98d07f5f7c7b2ea1b1fef9a272229475efcdc9..be487166d9b2319aeee5fcb54bf4779afcac5afa 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -25,6 +25,7 @@ import time - import pwd - from ConfigParser import SafeConfigParser - import ldif -+import itertools - - from ipalib import api, errors - from ipapython import version, ipautil, certdb, dogtag -@@ -161,32 +162,25 @@ class Restore(admintool.AdminTool): - - - def validate_options(self): -+ parser = self.option_parser - options = self.options - super(Restore, self).validate_options(needs_root=True) -- if options.data_only: -- installutils.check_server_configuration() - - if len(self.args) < 1: -- self.option_parser.error( -- "must provide the backup to restore") -+ parser.error("must provide the backup to restore") - elif len(self.args) > 1: -- self.option_parser.error( -- "must provide exactly one name for the backup") -+ parser.error("must provide exactly one name for the backup") - - dirname = self.args[0] - if not os.path.isabs(dirname): -- self.backup_dir = os.path.join(BACKUP_DIR, dirname) -- else: -- self.backup_dir = dirname -- -+ dirname = os.path.join(BACKUP_DIR, dirname) - if not os.path.isdir(dirname): -- raise self.option_parser.error("must provide path to backup directory") -+ parser.error("must provide path to backup directory") - - if options.gpg_keyring: - if (not os.path.exists(options.gpg_keyring + '.pub') or -- not os.path.exists(options.gpg_keyring + '.sec')): -- raise admintool.ScriptError('No such key %s' % -- options.gpg_keyring) -+ not os.path.exists(options.gpg_keyring + '.sec')): -+ parser.error("no such key %s" % options.gpg_keyring) - - - def ask_for_options(self): -@@ -212,38 +206,88 @@ class Restore(admintool.AdminTool): - api.bootstrap(in_server=False, context='restore') - api.finalize() - -+ self.backup_dir = self.args[0] -+ if not os.path.isabs(self.backup_dir): -+ self.backup_dir = os.path.join(BACKUP_DIR, self.backup_dir) -+ - self.log.info("Preparing restore from %s on %s", -- self.backup_dir, api.env.host) -+ self.backup_dir, api.env.host) - -- if options.instance and options.backend: -- database = (options.instance, options.backend) -- if not os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % -- database): -- raise admintool.ScriptError( -- "Instance %s with backend %s does not exist" % database) -+ self.header = os.path.join(self.backup_dir, 'header') -+ -+ try: -+ self.read_header() -+ except IOError as e: -+ raise admintool.ScriptError("Cannot read backup metadata: %s" % e) -+ -+ if options.data_only: -+ restore_type = 'DATA' -+ else: -+ restore_type = self.backup_type -+ -+ instances = [realm_to_serverid(api.env.realm), 'PKI-IPA'] -+ backends = ['userRoot', 'ipaca'] - -- databases = [database] -+ # These checks would normally be in the validate method but -+ # we need to know the type of backup we're dealing with. -+ if restore_type == 'FULL': -+ if options.online: -+ raise admintool.ScriptError( -+ "File restoration cannot be done online") -+ if options.instance or options.backend: -+ raise admintool.ScriptError( -+ "Restore must be in data-only mode when restoring a " -+ "specific instance or backend") - else: -+ installutils.check_server_configuration() -+ - if options.instance: -+ instance_dir = (paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % -+ options.instance) -+ if not os.path.exists(instance_dir): -+ raise admintool.ScriptError( -+ "Instance %s does not exist" % options.instance) -+ - instances = [options.instance] -- else: -- instances = [realm_to_serverid(api.env.realm), 'PKI-IPA'] - - if options.backend: -+ for instance in instances: -+ db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % -+ (instance, options.backend)) -+ if os.path.exists(db_dir): -+ break -+ else: -+ raise admintool.ScriptError( -+ "Backend %s does not exist" % options.backend) -+ - backends = [options.backend] -+ -+ for instance, backend in itertools.product(instances, backends): -+ db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % -+ (instance, backend)) -+ if os.path.exists(db_dir): -+ break - else: -- backends = ['userRoot', 'ipaca'] -+ raise admintool.ScriptError( -+ "Cannot restore a data backup into an empty system") - -- databases = [] -- for instance in instances: -- for backend in backends: -- database = (instance, backend) -- if os.path.exists(paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % -- database): -- databases.append(database) -+ self.log.info("Performing %s restore from %s backup" % -+ (restore_type, self.backup_type)) - -- if options.data_only and not databases: -- raise admintool.ScriptError('No instances to restore to') -+ if self.backup_host != api.env.host: -+ raise admintool.ScriptError( -+ "Host name %s does not match backup name %s" % -+ (api.env.host, self.backup_host)) -+ -+ if self.backup_ipa_version != str(version.VERSION): -+ self.log.warning( -+ "Restoring data from a different release of IPA.\n" -+ "Data is version %s.\n" -+ "Server is running %s." % -+ (self.backup_ipa_version, str(version.VERSION))) -+ if (not options.unattended and -+ not user_input("Continue to restore?", False)): -+ raise admintool.ScriptError("Aborted") - - create_ds_user() - pent = pwd.getpwnam(DS_USER) -@@ -257,46 +301,35 @@ class Restore(admintool.AdminTool): - - os.chown(self.dir, pent.pw_uid, pent.pw_gid) - -- self.header = os.path.join(self.backup_dir, 'header') -- - cwd = os.getcwd() - try: - dirsrv = services.knownservices.dirsrv - -- try: -- self.read_header() -- except IOError as e: -- raise admintool.ScriptError('Cannot read backup metadata: %s' % e) -- # These two checks would normally be in the validate method but -- # we need to know the type of backup we're dealing with. -- if (self.backup_type != 'FULL' and not options.data_only and -- not databases): -- raise admintool.ScriptError('Cannot restore a data backup into an empty system') -- if (self.backup_type == 'FULL' and not options.data_only and -- (options.instance or options.backend)): -- raise admintool.ScriptError('Restore must be in data-only mode when restoring a specific instance or backend.') -- if self.backup_host != api.env.host: -- raise admintool.ScriptError( -- 'Host name %s does not match backup name %s' % -- (api.env.host, self.backup_host)) -- if self.backup_ipa_version != str(version.VERSION): -- self.log.warning( -- "Restoring data from a different release of IPA.\n" -- "Data is version %s.\n" -- "Server is running %s." % -- (self.backup_ipa_version, str(version.VERSION))) -- if (not options.unattended and -- not user_input("Continue to restore?", False)): -- raise admintool.ScriptError("Aborted") -- - self.extract_backup(options.gpg_keyring) - -- for database in databases: -- ldifname = '%s-%s.ldif' % database -- ldiffile = os.path.join(self.dir, ldifname) -- if not os.path.exists(ldiffile): -+ databases = [] -+ for instance in instances: -+ for backend in backends: -+ database = (instance, backend) -+ ldiffile = os.path.join(self.dir, '%s-%s.ldif' % database) -+ if os.path.exists(ldiffile): -+ databases.append(database) -+ -+ if options.instance: -+ for instance, backend in databases: -+ if instance == options.instance: -+ break -+ else: -+ raise admintool.ScriptError( -+ "Instance %s not found in backup" % options.instance) -+ -+ if options.backend: -+ for instance, backend in databases: -+ if backend == options.backend: -+ break -+ else: - raise admintool.ScriptError( -- "Instance %s with backend %s not in backup" % database) -+ "Backend %s not found in backup" % options.backend) - - # Big fat warning - if (not options.unattended and -@@ -315,7 +348,7 @@ class Restore(admintool.AdminTool): - self.log.info("Disabling all replication.") - self.disable_agreements() - -- if options.data_only: -+ if restore_type != 'FULL': - if not options.online: - self.log.info('Stopping Directory Server') - dirsrv.stop(capture_output=False) -@@ -332,11 +365,9 @@ class Restore(admintool.AdminTool): - - - # We do either a full file restore or we restore data. -- if self.backup_type == 'FULL' and not options.data_only: -+ if restore_type == 'FULL': - if 'CA' in self.backup_services: - create_ca_user() -- if options.online: -- raise admintool.ScriptError('File restoration cannot be done online.') - self.cert_restore_prepare() - self.file_restore(options.no_logs) - self.cert_restore() -@@ -351,7 +382,7 @@ class Restore(admintool.AdminTool): - for instance, backend in databases: - self.ldif2db(instance, backend, online=options.online) - -- if options.data_only: -+ if restore_type != 'FULL': - if not options.online: - self.log.info('Starting Directory Server') - dirsrv.start(capture_output=False) --- -2.1.0 - diff --git a/SOURCES/0100-ipactl-Do-not-start-stop-restart-single-service-mult.patch b/SOURCES/0100-ipactl-Do-not-start-stop-restart-single-service-mult.patch new file mode 100644 index 0000000..a6dde81 --- /dev/null +++ b/SOURCES/0100-ipactl-Do-not-start-stop-restart-single-service-mult.patch @@ -0,0 +1,89 @@ +From 92224c6e83ca7ad196478b0057b523b6f2b7d150 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Wed, 26 Aug 2015 15:10:16 +0200 +Subject: [PATCH] ipactl: Do not start/stop/restart single service multiple + times + +In case multiple services are provided by single system daemon +it is not needed to start/stop/restart it mutiple time. + +https://fedorahosted.org/freeipa/ticket/5248 + +Reviewed-By: Petr Vobornik +--- + install/tools/ipactl | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/install/tools/ipactl b/install/tools/ipactl +index 52dfe67ddb65939bc1f431ccc67d9f03114c0454..acad7ff3771561d5dce530317b65aaf117f153a1 100755 +--- a/install/tools/ipactl ++++ b/install/tools/ipactl +@@ -45,6 +45,16 @@ def check_IPA_configuration(): + raise IpactlError("IPA is not configured " + + "(see man pages of ipa-server-install for help)", 6) + ++def deduplicate(lst): ++ new_lst = [] ++ s = set(lst) ++ for i in lst: ++ if i in s: ++ s.remove(i) ++ new_lst.append(i) ++ ++ return new_lst ++ + def is_dirsrv_debugging_enabled(): + """ + Check the 389-ds instance to see if debugging is enabled. +@@ -283,6 +293,7 @@ def ipa_start(options): + # no service to start + return + ++ svc_list = deduplicate(svc_list) + for svc in svc_list: + svchandle = services.service(svc) + try: +@@ -321,6 +332,7 @@ def ipa_stop(options): + finally: + raise IpactlError() + ++ svc_list = deduplicate(svc_list) + for svc in reversed(svc_list): + svchandle = services.service(svc) + try: +@@ -398,6 +410,7 @@ def ipa_restart(options): + + if len(old_svc_list) != 0: + # we need to definitely stop some services ++ old_svc_list = deduplicate(old_svc_list) + for svc in reversed(old_svc_list): + svchandle = services.service(svc) + try: +@@ -422,7 +435,7 @@ def ipa_restart(options): + + if len(svc_list) != 0: + # there are services to restart +- ++ svc_list = deduplicate(svc_list) + for svc in svc_list: + svchandle = services.service(svc) + try: +@@ -444,6 +457,7 @@ def ipa_restart(options): + + if len(new_svc_list) != 0: + # we still need to start some services ++ new_svc_list = deduplicate(new_svc_list) + for svc in new_svc_list: + svchandle = services.service(svc) + try: +@@ -494,6 +508,7 @@ def ipa_status(options): + if len(svc_list) == 0: + return + ++ svc_list = deduplicate(svc_list) + for svc in svc_list: + svchandle = services.service(svc) + try: +-- +2.4.3 + diff --git a/SOURCES/0101-Allow-PassSync-user-to-locate-and-update-NT-users.patch b/SOURCES/0101-Allow-PassSync-user-to-locate-and-update-NT-users.patch deleted file mode 100644 index bddc767..0000000 --- a/SOURCES/0101-Allow-PassSync-user-to-locate-and-update-NT-users.patch +++ /dev/null @@ -1,284 +0,0 @@ -From 3998814d3abb5143f06479d2dbf93bf28285a66e Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Tue, 13 Jan 2015 18:09:17 +0100 -Subject: [PATCH] Allow PassSync user to locate and update NT users - -Add new PassSync Service privilege that have sufficient access to -let AD PassSync service search for NT users and update the password. -To make sure existing PassSync user keeps working, it is added as -a member of the new privilege. - -New update plugin is added to add link to the new privilege to the -potentially existing PassSync user to avoid breaking the PassSync -service. - -https://fedorahosted.org/freeipa/ticket/4837 - -Reviewed-By: David Kupka ---- - ACI.txt | 2 + - install/updates/40-delegation.update | 30 +++++++++++ - ipalib/plugins/user.py | 12 +++++ - ipaserver/install/plugins/Makefile.am | 1 + - ipaserver/install/plugins/update_passsync.py | 78 ++++++++++++++++++++++++++++ - ipaserver/install/replication.py | 54 ++++++++++--------- - 6 files changed, 152 insertions(+), 25 deletions(-) - create mode 100644 ipaserver/install/plugins/update_passsync.py - -diff --git a/ACI.txt b/ACI.txt -index 6680f658ee1aa0f961b2681f700557ce6b9238f8..fe45d063e7d48c487e380ca3568b0f9368762c6d 100644 ---- a/ACI.txt -+++ b/ACI.txt -@@ -267,6 +267,8 @@ aci: (targetattr = "krblastadminunlock || krblastfailedauth || krblastpwdchange - dn: cn=users,cn=accounts,dc=ipa,dc=example - aci: (targetattr = "memberof")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Membership";allow (compare,read,search) userdn = "ldap:///all";) - dn: cn=users,cn=accounts,dc=ipa,dc=example -+aci: (targetattr = "ntuniqueid || ntuseracctexpires || ntusercodepage || ntuserdeleteaccount || ntuserdomainid || ntuserlastlogoff || ntuserlastlogon")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User NT Attributes";allow (compare,read,search) groupdn = "ldap:///cn=System: Read User NT Attributes,cn=permissions,cn=pbac,dc=ipa,dc=example";) -+dn: cn=users,cn=accounts,dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || description || displayname || entryusn || gecos || gidnumber || givenname || homedirectory || initials || ipantsecurityidentifier || loginshell || manager || modifytimestamp || objectclass || sn || title || uid || uidnumber")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Standard Attributes";allow (compare,read,search) userdn = "ldap:///anyone";) - dn: dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=*,cn=views,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Views Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";) -diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update -index 988de5e1962fabc6787f5914522b8f133e71a8ff..a79f906ea3e29b8b6755a62ac84d318d6abdd6cc 100644 ---- a/install/updates/40-delegation.update -+++ b/install/updates/40-delegation.update -@@ -184,3 +184,33 @@ default:description: Read list of IPA masters - dn: cn=masters,cn=ipa,cn=etc,$SUFFIX - add:aci:'(targetfilter = "(objectClass=nsContainer)")(targetattr = "cn || objectClass || ipaConfigString")(version 3.0; acl "Read IPA Masters"; allow (read, search, compare) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)' - add:aci:'(targetfilter = "(objectClass=nsContainer)")(targetattr = "ipaConfigString")(version 3.0; acl "Modify IPA Masters"; allow (write) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)' -+ -+# PassSync -+dn: cn=PassSync Service,cn=privileges,cn=pbac,$SUFFIX -+default:objectClass: nestedgroup -+default:objectClass: groupofnames -+default:objectClass: top -+default:cn: PassSync Service -+default:description: PassSync Service -+ -+dn: cn=Read PassSync Managers Configuration,cn=permissions,cn=pbac,$SUFFIX -+default:objectClass: groupofnames -+default:objectClass: ipapermission -+default:objectClass: top -+default:cn: Read PassSync Managers Configuration -+default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX -+default:ipapermissiontype: SYSTEM -+ -+dn: cn=config -+add:aci: '(targetattr = "cn || createtimestamp || entryusn || modifytimestamp || objectclass || passsyncmanagersdns*")(target = "ldap:///cn=ipa_pwd_extop,cn=plugins,cn=config")(version 3.0;acl "permission:Read PassSync Managers Configuration";allow (compare,read,search) groupdn = "ldap:///cn=Read PassSync Managers Configuration,cn=permissions,cn=pbac,$SUFFIX";)' -+ -+dn: cn=Modify PassSync Managers Configuration,cn=permissions,cn=pbac,$SUFFIX -+default:objectClass: groupofnames -+default:objectClass: ipapermission -+default:objectClass: top -+default:cn: Modify PassSync Managers Configuration -+default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX -+default:ipapermissiontype: SYSTEM -+ -+dn: cn=config -+add:aci: '(targetattr = "passsyncmanagersdns*")(target = "ldap:///cn=ipa_pwd_extop,cn=plugins,cn=config")(version 3.0;acl "permission:Modify PassSync Managers Configuration";allow (write) groupdn = "ldap:///cn=Modify PassSync Managers Configuration,cn=permissions,cn=pbac,$SUFFIX";)' -diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py -index e206289248dfe9ae79bd87271ff2c7672fb98b4f..56585b9f86593c0c5879139103bc71707b88e15f 100644 ---- a/ipalib/plugins/user.py -+++ b/ipalib/plugins/user.py -@@ -373,10 +373,12 @@ class user(LDAPObject): - 'replaces': [ - '(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";)', - '(targetfilter = "(!(memberOf=cn=admins,cn=groups,cn=accounts,$SUFFIX))")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";)', -+ '(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Windows PassSync service can write passwords"; allow (write) userdn="ldap:///uid=passsync,cn=sysaccounts,cn=etc,$SUFFIX";)', - ], - 'default_privileges': { - 'User Administrators', - 'Modify Users and Reset passwords', -+ 'PassSync Service', - }, - }, - 'System: Manage User SSH Public Keys': { -@@ -446,6 +448,16 @@ class user(LDAPObject): - 'homedirectory', 'loginshell', - }, - }, -+ 'System: Read User NT Attributes': { -+ 'ipapermbindruletype': 'permission', -+ 'ipapermright': {'read', 'search', 'compare'}, -+ 'ipapermdefaultattr': { -+ 'ntuserdomainid', 'ntuniqueid', 'ntuseracctexpires', -+ 'ntusercodepage', 'ntuserdeleteaccount', 'ntuserlastlogoff', -+ 'ntuserlastlogon', -+ }, -+ 'default_privileges': {'PassSync Service'}, -+ }, - } - - label = _('Users') -diff --git a/ipaserver/install/plugins/Makefile.am b/ipaserver/install/plugins/Makefile.am -index d651297ac141b0f05831e7fabbb9b561cdd239c7..ead1d8f7d972c1b016bac8f2b8f7fd1f9a71b563 100644 ---- a/ipaserver/install/plugins/Makefile.am -+++ b/ipaserver/install/plugins/Makefile.am -@@ -14,6 +14,7 @@ app_PYTHON = \ - update_referint.py \ - ca_renewal_master.py \ - update_uniqueness.py \ -+ update_passsync.py \ - $(NULL) - - EXTRA_DIST = \ -diff --git a/ipaserver/install/plugins/update_passsync.py b/ipaserver/install/plugins/update_passsync.py -new file mode 100644 -index 0000000000000000000000000000000000000000..d6595a06f4deb62b853d716012a8c594c6a76451 ---- /dev/null -+++ b/ipaserver/install/plugins/update_passsync.py -@@ -0,0 +1,78 @@ -+# -+# Copyright (C) 2014 FreeIPA Contributors see COPYING for license -+# -+ -+from ipaserver.install.plugins import MIDDLE, LAST -+from ipaserver.install.plugins.baseupdate import PreUpdate, PostUpdate -+from ipalib import api, errors -+from ipapython.dn import DN -+from ipapython.ipa_log_manager import root_logger -+from ipaserver.install import sysupgrade -+ -+class update_passync_privilege_check(PreUpdate): -+ order = MIDDLE -+ -+ def execute(self, **options): -+ update_done = sysupgrade.get_upgrade_state('winsync', 'passsync_privilege_updated') -+ if update_done: -+ root_logger.debug("PassSync privilege update pre-check not needed") -+ return False, False, [] -+ -+ root_logger.debug("Check if there is existing PassSync privilege") -+ -+ passsync_privilege_dn = DN(('cn','PassSync Service'), -+ self.api.env.container_privilege, -+ self.api.env.basedn) -+ -+ ldap = self.obj.backend -+ try: -+ ldap.get_entry(passsync_privilege_dn, ['']) -+ except errors.NotFound: -+ root_logger.debug("PassSync privilege not found, this is a new update") -+ sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', False) -+ else: -+ root_logger.debug("PassSync privilege found, skip updating PassSync") -+ sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', True) -+ -+ return False, False, [] -+ -+api.register(update_passync_privilege_check) -+ -+class update_passync_privilege_update(PostUpdate): -+ """ -+ Add PassSync user as a member of PassSync privilege, if it exists -+ """ -+ -+ order = LAST -+ -+ def execute(self, **options): -+ update_done = sysupgrade.get_upgrade_state('winsync', 'passsync_privilege_updated') -+ if update_done: -+ root_logger.debug("PassSync privilege update not needed") -+ return False, False, [] -+ -+ root_logger.debug("Add PassSync user as a member of PassSync privilege") -+ ldap = self.obj.backend -+ passsync_dn = DN(('uid','passsync'), ('cn', 'sysaccounts'), ('cn', 'etc'), -+ api.env.basedn) -+ passsync_privilege_dn = DN(('cn','PassSync Service'), -+ self.api.env.container_privilege, -+ self.api.env.basedn) -+ -+ try: -+ entry = ldap.get_entry(passsync_dn, ['']) -+ except errors.NotFound: -+ root_logger.debug("PassSync user not found, no update needed") -+ sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', True) -+ return False, False, [] -+ else: -+ root_logger.debug("PassSync user found, do update") -+ -+ update = {'dn': passsync_privilege_dn, -+ 'updates': ["add:member:'%s'" % passsync_dn]} -+ updates = {passsync_privilege_dn: update} -+ -+ sysupgrade.set_upgrade_state('winsync', 'passsync_privilege_updated', True) -+ return (False, True, [updates]) -+ -+api.register(update_passync_privilege_update) -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 5778cab036ad87ccb5b69254aa307a6bc8dec871..66764c22f69328942fe2e4581cfafb3806438d7c 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -528,39 +528,43 @@ class ReplicationManager(object): - print "The user for the Windows PassSync service is %s" % pass_dn - try: - conn.get_entry(pass_dn) -- print "Windows PassSync entry exists, not resetting password" -- return -+ print "Windows PassSync system account exists, not resetting password" - except errors.NotFound: -- pass -- -- # The user doesn't exist, add it -- entry = conn.make_entry( -- pass_dn, -- objectclass=["account", "simplesecurityobject"], -- uid=["passsync"], -- userPassword=[password], -- ) -- conn.add_entry(entry) -+ # The user doesn't exist, add it -+ print "Adding Windows PassSync system account" -+ entry = conn.make_entry( -+ pass_dn, -+ objectclass=["account", "simplesecurityobject"], -+ uid=["passsync"], -+ userPassword=[password], -+ ) -+ conn.add_entry(entry) - -- # Add it to the list of users allowed to bypass password policy -+ # Add the user to the list of users allowed to bypass password policy - extop_dn = DN(('cn', 'ipa_pwd_extop'), ('cn', 'plugins'), ('cn', 'config')) - entry = conn.get_entry(extop_dn) -- pass_mgrs = entry.get('passSyncManagersDNs') -- if not pass_mgrs: -- pass_mgrs = [] -- if not isinstance(pass_mgrs, list): -- pass_mgrs = [pass_mgrs] -+ pass_mgrs = entry.get('passSyncManagersDNs', []) - pass_mgrs.append(pass_dn) - mod = [(ldap.MOD_REPLACE, 'passSyncManagersDNs', pass_mgrs)] -- conn.modify_s(extop_dn, mod) -- -- # And finally grant it permission to write passwords -- mod = [(ldap.MOD_ADD, 'aci', -- ['(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Windows PassSync service can write passwords"; allow (write) userdn="ldap:///%s";)' % pass_dn])] - try: -- conn.modify_s(self.suffix, mod) -+ conn.modify_s(extop_dn, mod) -+ except ldap.TYPE_OR_VALUE_EXISTS: -+ root_logger.debug("Plugin '%s' already '%s' in passSyncManagersDNs", -+ extop_dn, pass_dn) -+ -+ # And finally add it is a member of PassSync privilege to allow -+ # displaying user NT attributes and reset passwords -+ passsync_privilege_dn = DN(('cn','PassSync Service'), -+ api.env.container_privilege, -+ api.env.basedn) -+ members = entry.get('member', []) -+ members.append(pass_dn) -+ mod = [(ldap.MOD_REPLACE, 'member', members)] -+ try: -+ conn.modify_s(passsync_privilege_dn, mod) - except ldap.TYPE_OR_VALUE_EXISTS: -- root_logger.debug("passsync aci already exists in suffix %s on %s" % (self.suffix, conn.host)) -+ root_logger.debug("PassSync service '%s' already have '%s' as member", -+ passsync_privilege_dn, pass_dn) - - def setup_winsync_agmt(self, entry, win_subtree=None): - if win_subtree is None: --- -2.1.0 - diff --git a/SOURCES/0101-cert-renewal-Include-KRA-users-in-Dogtag-LDAP-update.patch b/SOURCES/0101-cert-renewal-Include-KRA-users-in-Dogtag-LDAP-update.patch new file mode 100644 index 0000000..fb706b1 --- /dev/null +++ b/SOURCES/0101-cert-renewal-Include-KRA-users-in-Dogtag-LDAP-update.patch @@ -0,0 +1,46 @@ +From a4ea0af1fb74ac9bdf9afe1bee62cddf65f5160e Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 27 Aug 2015 07:23:39 +0200 +Subject: [PATCH] cert renewal: Include KRA users in Dogtag LDAP update + +https://fedorahosted.org/freeipa/ticket/5253 + +Reviewed-By: Alexander Bokovoy +--- + ipaserver/install/cainstance.py | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 5fd3017e16e0d7ed4b4f8eead0e59266fdaff097..ecd9300036353426097d929918be974cbbb5c69d 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -1575,7 +1575,7 @@ def update_people_entry(dercert): + + Returns True or False + """ +- base_dn = DN(('ou','People'), ('o','ipaca')) ++ base_dn = DN(('o', 'ipaca')) + serial_number = x509.get_serial_number(dercert, datatype=x509.DER) + subject = x509.get_subject(dercert, datatype=x509.DER) + issuer = x509.get_issuer(dercert, datatype=x509.DER) +@@ -1591,9 +1591,14 @@ def update_people_entry(dercert): + conn = ldap2.ldap2(api, ldap_uri=dogtag_uri) + conn.connect(autobind=True) + +- db_filter = conn.make_filter( +- {'description': ';%s;%s' % (issuer, subject)}, +- exact=False, trailing_wildcard=False) ++ db_filter = conn.combine_filters( ++ [ ++ conn.make_filter({'objectClass': 'inetOrgPerson'}), ++ conn.make_filter( ++ {'description': ';%s;%s' % (issuer, subject)}, ++ exact=False, trailing_wildcard=False), ++ ], ++ conn.MATCH_ALL) + try: + entries = conn.get_entries(base_dn, conn.SCOPE_SUBTREE, db_filter) + except errors.NotFound: +-- +2.5.1 + diff --git a/SOURCES/0102-Allow-Replication-Administrators-manipulate-Winsync-.patch b/SOURCES/0102-Allow-Replication-Administrators-manipulate-Winsync-.patch deleted file mode 100644 index 627f6e6..0000000 --- a/SOURCES/0102-Allow-Replication-Administrators-manipulate-Winsync-.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 18e8a2c23dd05724867cd5da82f5fe20936e3df2 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Wed, 14 Jan 2015 16:36:16 +0100 -Subject: [PATCH] Allow Replication Administrators manipulate Winsync - Agreements - -Replication Administrators members were not able to set up changelog5 -entry in cn=config or list winsync agreements. - -To allow reading winsync replicas, the original deny ACI cn=replica -had to be removed as it prevented admins from reading the entries, -but just anonymous/authenticated users. - -https://fedorahosted.org/freeipa/ticket/4836 - -Reviewed-By: David Kupka ---- - install/updates/20-aci.update | 2 +- - install/updates/40-delegation.update | 23 +++++++++++++++++++++++ - 2 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update -index 9bbb7e4bb8d51b3d957d1f63d2c889e793276598..b920ef83d8580911d9a9c577e3ed6a9356da69e2 100644 ---- a/install/updates/20-aci.update -+++ b/install/updates/20-aci.update -@@ -26,7 +26,7 @@ dn: $SUFFIX - add:aci:'(targetfilter="(&(objectclass=nsContainer)(!(objectclass=krbPwdPolicy)))")(target!="ldap:///cn=masters,cn=ipa,cn=etc,$SUFFIX")(targetattr="objectclass || cn")(version 3.0; acl "Anonymous read access to containers"; allow(read, search, compare) userdn = "ldap:///anyone";)' - - dn: cn=replicas,cn=ipa,cn=etc,$SUFFIX --add:aci:'(targetfilter="(objectclass=nsContainer)")(version 3.0; acl "Deny read access to replica configuration"; deny(read, search, compare) userdn = "ldap:///anyone";)' -+remove:aci:'(targetfilter="(objectclass=nsContainer)")(version 3.0; acl "Deny read access to replica configuration"; deny(read, search, compare) userdn = "ldap:///anyone";)' - - # Read access to masters and their services - dn: cn=masters,cn=ipa,cn=etc,$SUFFIX -diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update -index a79f906ea3e29b8b6755a62ac84d318d6abdd6cc..32af498190a23ddfd202a5cad75409f60a70d78b 100644 ---- a/install/updates/40-delegation.update -+++ b/install/updates/40-delegation.update -@@ -214,3 +214,26 @@ default:ipapermissiontype: SYSTEM - - dn: cn=config - add:aci: '(targetattr = "passsyncmanagersdns*")(target = "ldap:///cn=ipa_pwd_extop,cn=plugins,cn=config")(version 3.0;acl "permission:Modify PassSync Managers Configuration";allow (write) groupdn = "ldap:///cn=Modify PassSync Managers Configuration,cn=permissions,cn=pbac,$SUFFIX";)' -+ -+# Replication Administrators -+dn: cn=Read LDBM Database Configuration,cn=permissions,cn=pbac,$SUFFIX -+default:objectClass: groupofnames -+default:objectClass: ipapermission -+default:objectClass: top -+default:cn: Read LDBM Database Configuration -+default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX -+default:ipapermissiontype: SYSTEM -+ -+dn: cn=config -+add:aci: '(targetattr = "cn || createtimestamp || entryusn || modifytimestamp || nsslapd-directory* || objectclass")(target = "ldap:///cn=config,cn=ldbm database,cn=plugins,cn=config")(version 3.0;acl "permission:Read LDBM Database Configuration";allow (compare,read,search) groupdn = "ldap:///cn=Read LDBM Database Configuration,cn=permissions,cn=pbac,$SUFFIX";)' -+ -+dn: cn=Add Configuration Sub-Entries,cn=permissions,cn=pbac,$SUFFIX -+default:objectClass: groupofnames -+default:objectClass: ipapermission -+default:objectClass: top -+default:cn: Add Configuration Sub-Entries -+default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX -+default:ipapermissiontype: SYSTEM -+ -+dn: cn=config -+add:aci: '(version 3.0;acl "permission:Add Configuration Sub-Entries";allow (add) groupdn = "ldap:///cn=Add Configuration Sub-Entries,cn=permissions,cn=pbac,$SUFFIX";)' --- -2.1.0 - diff --git a/SOURCES/0102-cert-renewal-Automatically-update-KRA-agent-PEM-file.patch b/SOURCES/0102-cert-renewal-Automatically-update-KRA-agent-PEM-file.patch new file mode 100644 index 0000000..0350832 --- /dev/null +++ b/SOURCES/0102-cert-renewal-Automatically-update-KRA-agent-PEM-file.patch @@ -0,0 +1,45 @@ +From f0e3715b39ea2682f4ef689f5d5864e16117fb00 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 27 Aug 2015 07:37:24 +0200 +Subject: [PATCH] cert renewal: Automatically update KRA agent PEM file + +https://fedorahosted.org/freeipa/ticket/5253 + +Reviewed-By: Alexander Bokovoy +--- + install/restart_scripts/renew_ra_cert | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert +index 1f8fcae6fa09033f7a5c6448e0bbef14a5f76844..93ffd4035723831f3955bcdf5a2082fd1ec5e22a 100644 +--- a/install/restart_scripts/renew_ra_cert ++++ b/install/restart_scripts/renew_ra_cert +@@ -29,7 +29,7 @@ import traceback + + from ipapython import ipautil + from ipalib import api +-from ipaserver.install import certs, cainstance ++from ipaserver.install import certs, cainstance, krainstance + from ipaplatform import services + from ipaplatform.paths import paths + +@@ -60,6 +60,16 @@ def _main(): + + # Load it into dogtag + cainstance.update_people_entry(dercert) ++ ++ kra = krainstance.KRAInstance(api.env.realm) ++ if kra.is_installed(): ++ # export ipaCert with private key for client authentication ++ args = ["/usr/bin/pki", ++ "-d", paths.HTTPD_ALIAS_DIR, ++ "-C", paths.ALIAS_PWDFILE_TXT, ++ "client-cert-show", "ipaCert", ++ "--client-cert", paths.KRA_AGENT_PEM] ++ ipautil.run(args) + finally: + shutil.rmtree(tmpdir) + +-- +2.5.1 + diff --git a/SOURCES/0103-DNSSEC-remove-DNSSEC-is-experimental-warnings.patch b/SOURCES/0103-DNSSEC-remove-DNSSEC-is-experimental-warnings.patch new file mode 100644 index 0000000..eeb2b27 --- /dev/null +++ b/SOURCES/0103-DNSSEC-remove-DNSSEC-is-experimental-warnings.patch @@ -0,0 +1,72 @@ +From 36d0ae5682bd4e71ba3c27900f4699c07aa27f68 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Mon, 31 Aug 2015 13:51:02 +0200 +Subject: [PATCH] DNSSEC: remove "DNSSEC is experimental" warnings + +https://fedorahosted.org/freeipa/ticket/5265 + +Reviewed-By: Martin Babinsky +--- + ipalib/plugins/dns.py | 18 ------------------ + ipaserver/install/dns.py | 2 -- + 2 files changed, 20 deletions(-) + +diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py +index 512a653c3cc8ee641debec0d20f58e17eff08266..a3d562edb186682a872073e6c83a416b6a4cbc09 100644 +--- a/ipalib/plugins/dns.py ++++ b/ipalib/plugins/dns.py +@@ -2624,22 +2624,6 @@ class dnszone(DNSZoneBase): + messages.add_message(options.get('version', VERSION_WITHOUT_CAPABILITIES), + result, messages.ForwardersWarning()) + +- def _warning_dnssec_experimental(self, result, *keys, **options): +- # add warning when user use option --dnssec +- if 'idnssecinlinesigning' in options: +- if options['idnssecinlinesigning'] is True: +- messages.add_message(options['version'], result, +- messages.DNSSECWarning( +- additional_info=_("Visit 'http://www.freeipa.org/page/Releases/4.1.0#DNSSEC_Support'.") +- )) +- else: +- messages.add_message(options['version'], result, +- messages.DNSSECWarning( +- additional_info=_("If you encounter any problems please " +- "report them and restart 'named' service on affected IPA " +- "server.") +- )) +- + def _warning_name_server_option(self, result, context, **options): + if getattr(context, 'show_warning_nameserver_option', False): + messages.add_message( +@@ -2735,7 +2719,6 @@ class dnszone_add(DNSZoneBase_add): + result = super(dnszone_add, self).execute(*keys, **options) + self._warning_deprecated_option(result, **options) + self.obj._warning_forwarding(result, **options) +- self.obj._warning_dnssec_experimental(result, *keys, **options) + self.obj._warning_name_server_option(result, context, **options) + self.obj._warning_fw_zone_is_not_effective(result, *keys, **options) + return result +@@ -2826,7 +2809,6 @@ class dnszone_mod(DNSZoneBase_mod): + def execute(self, *keys, **options): + result = super(dnszone_mod, self).execute(*keys, **options) + self.obj._warning_forwarding(result, **options) +- self.obj._warning_dnssec_experimental(result, *keys, **options) + self.obj._warning_name_server_option(result, context, **options) + return result + +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index 9430d189978b0984b0b71d7d754516a4135053fb..538e99fbe01a34cee627f1cebd938be19777c134 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -126,8 +126,6 @@ def install_check(standalone, replica, options, hostname): + print "NOTE: DNSSEC zone signing is not enabled by default" + print "" + if options.dnssec_master: +- print "DNSSEC support is experimental!" +- print "" + print "Plan carefully, replacing DNSSEC key master is not recommended" + print "" + print "" +-- +2.5.1 + diff --git a/SOURCES/0103-Do-not-assume-certmonger-is-running-in-httpinstance.patch b/SOURCES/0103-Do-not-assume-certmonger-is-running-in-httpinstance.patch deleted file mode 100644 index af80ec4..0000000 --- a/SOURCES/0103-Do-not-assume-certmonger-is-running-in-httpinstance.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 13fec89bb4a2ddfda7d1ad0da18c6c4be77373d6 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 20 Jan 2015 09:38:43 +0000 -Subject: [PATCH] Do not assume certmonger is running in httpinstance - -https://fedorahosted.org/freeipa/ticket/4835 - -Reviewed-By: David Kupka ---- - ipaserver/install/httpinstance.py | 48 +++++++++++++++++++++++---------------- - 1 file changed, 29 insertions(+), 19 deletions(-) - -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 2fb315b6b822343860a9c31b016d6a0a22388488..cda85ab02b8054748e671935fcfbc3993257c53e 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -39,6 +39,7 @@ from ipaserver.install import sysupgrade - from ipalib import api - from ipaplatform.tasks import tasks - from ipaplatform.paths import paths -+from ipaplatform import services - - - SELINUX_BOOLEAN_SETTINGS = dict( -@@ -228,25 +229,34 @@ class HTTPInstance(service.Service): - print "Adding Include conf.d/ipa-rewrite to %s failed." % paths.HTTPD_NSS_CONF - - def configure_certmonger_renewal_guard(self): -- bus = dbus.SystemBus() -- obj = bus.get_object('org.fedorahosted.certmonger', -- '/org/fedorahosted/certmonger') -- iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') -- path = iface.find_ca_by_nickname('IPA') -- if path: -- ca_obj = bus.get_object('org.fedorahosted.certmonger', path) -- ca_iface = dbus.Interface(ca_obj, -- 'org.freedesktop.DBus.Properties') -- helper = ca_iface.Get('org.fedorahosted.certmonger.ca', -- 'external-helper') -- if helper: -- args = shlex.split(helper) -- if args[0] != paths.IPA_SERVER_GUARD: -- self.backup_state('certmonger_ipa_helper', helper) -- args = [paths.IPA_SERVER_GUARD] + args -- helper = ' '.join(pipes.quote(a) for a in args) -- ca_iface.Set('org.fedorahosted.certmonger.ca', -- 'external-helper', helper) -+ certmonger = services.knownservices.certmonger -+ certmonger_stopped = not certmonger.is_running() -+ -+ if certmonger_stopped: -+ certmonger.start() -+ try: -+ bus = dbus.SystemBus() -+ obj = bus.get_object('org.fedorahosted.certmonger', -+ '/org/fedorahosted/certmonger') -+ iface = dbus.Interface(obj, 'org.fedorahosted.certmonger') -+ path = iface.find_ca_by_nickname('IPA') -+ if path: -+ ca_obj = bus.get_object('org.fedorahosted.certmonger', path) -+ ca_iface = dbus.Interface(ca_obj, -+ 'org.freedesktop.DBus.Properties') -+ helper = ca_iface.Get('org.fedorahosted.certmonger.ca', -+ 'external-helper') -+ if helper: -+ args = shlex.split(helper) -+ if args[0] != paths.IPA_SERVER_GUARD: -+ self.backup_state('certmonger_ipa_helper', helper) -+ args = [paths.IPA_SERVER_GUARD] + args -+ helper = ' '.join(pipes.quote(a) for a in args) -+ ca_iface.Set('org.fedorahosted.certmonger.ca', -+ 'external-helper', helper) -+ finally: -+ if certmonger_stopped: -+ certmonger.stop() - - def __setup_ssl(self): - fqdn = self.fqdn --- -2.1.0 - diff --git a/SOURCES/0104-Backup-back-up-the-hosts-file.patch b/SOURCES/0104-Backup-back-up-the-hosts-file.patch new file mode 100644 index 0000000..e581e41 --- /dev/null +++ b/SOURCES/0104-Backup-back-up-the-hosts-file.patch @@ -0,0 +1,27 @@ +From 89b5a01486f8a5200323c753f6ac278d089ba05e Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 1 Sep 2015 16:24:44 +0200 +Subject: [PATCH] Backup: back up the hosts file + +https://fedorahosted.org/freeipa/ticket/5275 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/ipa_backup.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 0ba44b280dfb7c9d9cbbe2470392c3c98ef35bcc..8df1005a222220a0ece95a3691766ed3cd00a0d9 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -178,6 +178,7 @@ class Backup(admintool.AdminTool): + paths.DNSSEC_SOFTHSM_PIN_SO, + paths.IPA_ODS_EXPORTER_KEYTAB, + paths.IPA_DNSKEYSYNCD_KEYTAB, ++ paths.HOSTS, + ) + tuple( + os.path.join(base, file) + for base in (paths.NSS_DB_DIR, paths.IPA_NSSDB_DIR) +-- +2.5.1 + diff --git a/SOURCES/0104-Replication-Administrators-cannot-remove-replication.patch b/SOURCES/0104-Replication-Administrators-cannot-remove-replication.patch deleted file mode 100644 index c6b0bc8..0000000 --- a/SOURCES/0104-Replication-Administrators-cannot-remove-replication.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0bea7bc245fe1471008d20c78626c2fa2572e91c Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Mon, 19 Jan 2015 12:42:11 +0100 -Subject: [PATCH] Replication Administrators cannot remove replication - agreements - -Replication agreement deletion requires read access to DNA range -setting. The read access was accidently removed during PermissionV2 -refactoring. - -Add the read ACI back as a special SYSTEM permission. - -https://fedorahosted.org/freeipa/ticket/4848 - -Reviewed-By: Martin Basti ---- - install/updates/40-replication.update | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/install/updates/40-replication.update b/install/updates/40-replication.update -index 619d14663eeb6f692864c960dfd3542fc22cb581..f46ab19f0090ba313880e6d99636f50397f8d33b 100644 ---- a/install/updates/40-replication.update -+++ b/install/updates/40-replication.update -@@ -14,3 +14,14 @@ default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX - - dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config - add:aci: '(targetattr=dnaNextRange || dnaNextValue || dnaMaxValue)(version 3.0;acl "permission:Modify DNA Range";allow (write) groupdn = "ldap:///cn=Modify DNA Range,cn=permissions,cn=pbac,$SUFFIX";)' -+ -+dn: cn=Read DNA Range,cn=permissions,cn=pbac,$SUFFIX -+default:objectClass: top -+default:objectClass: groupofnames -+default:objectClass: ipapermission -+default:cn: Read DNA Range -+default:ipapermissiontype: SYSTEM -+default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX -+ -+dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config -+add:aci: '(targetattr=cn || dnaMaxValue || dnaNextRange || dnaNextValue || dnaThreshold || dnaType || objectclass)(version 3.0;acl "permission:Read DNA Range";allow (read, search, compare) groupdn = "ldap:///cn=Read DNA Range,cn=permissions,cn=pbac,$SUFFIX";)' --- -2.1.0 - diff --git a/SOURCES/0105-Put-LDIF-files-to-their-original-location-in-ipa-res.patch b/SOURCES/0105-Put-LDIF-files-to-their-original-location-in-ipa-res.patch deleted file mode 100644 index 1eca1dc..0000000 --- a/SOURCES/0105-Put-LDIF-files-to-their-original-location-in-ipa-res.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0717bc9dcaddf4f43bb9412af979b37a5a61c55b Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 20 Jan 2015 11:22:29 +0000 -Subject: [PATCH] Put LDIF files to their original location in ipa-restore - -This prevents SELinux failures during online data restore. - -https://fedorahosted.org/freeipa/ticket/4822 - -Reviewed-By: Martin Kosek ---- - ipaserver/install/ipa_restore.py | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index be487166d9b2319aeee5fcb54bf4779afcac5afa..562a793c2c9383d7495c84a817ac9f7a1407f9bb 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -504,10 +504,17 @@ class Restore(admintool.AdminTool): - cn = time.strftime('import_%Y_%m_%d_%H_%M_%S') - dn = DN(('cn', cn), ('cn', 'import'), ('cn', 'tasks'), ('cn', 'config')) - -+ ldifdir = paths.SLAPD_INSTANCE_LDIF_DIR_TEMPLATE % instance - ldifname = '%s-%s.ldif' % (instance, backend) -+ ldiffile = os.path.join(ldifdir, ldifname) - srcldiffile = os.path.join(self.dir, ldifname) -- ldiffile = '%s.noruv' % srcldiffile - -+ if not os.path.exists(ldifdir): -+ pent = pwd.getpwnam(DS_USER) -+ os.mkdir(ldifdir, 0770) -+ os.chown(ldifdir, pent.pw_uid, pent.pw_gid) -+ -+ ipautil.backup_file(ldiffile) - with open(ldiffile, 'wb') as out_file: - ldif_writer = ldif.LDIFWriter(out_file) - with open(srcldiffile, 'rb') as in_file: --- -2.1.0 - diff --git a/SOURCES/0105-certprofile-remove-rename-option.patch b/SOURCES/0105-certprofile-remove-rename-option.patch new file mode 100644 index 0000000..a3d7d58 --- /dev/null +++ b/SOURCES/0105-certprofile-remove-rename-option.patch @@ -0,0 +1,74 @@ +From 4b6bd162df3eed18c124527467b9beea930169db Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Tue, 1 Sep 2015 21:04:34 -0400 +Subject: [PATCH] certprofile: remove 'rename' option + +The initial fix of ticket 5247 rejected renames, but left the option +behind for API compatibility. Remove the option now, according to +the consensus that because it never worked, it is fine to remove it. + +Fixes: https://fedorahosted.org/freeipa/ticket/5247 +Reviewed-By: Petr Vobornik +--- + API.txt | 3 +-- + VERSION | 4 ++-- + ipalib/plugins/certprofile.py | 3 +-- + 3 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/API.txt b/API.txt +index 871ddb5b7ee8b9bbae219eac673d52ad7229edc7..5253e1585e000f39d6e185a94548037dfe54d4d8 100644 +--- a/API.txt ++++ b/API.txt +@@ -731,7 +731,7 @@ output: Entry('result', , Gettext('A dictionary representing an LDA + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) + command: certprofile_mod +-args: 1,11,3 ++args: 1,10,3 + arg: Str('cn', attribute=True, cli_name='id', multivalue=False, 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') +@@ -740,7 +740,6 @@ option: Str('description', attribute=True, autofill=False, cli_name='desc', mult + option: File('file?', cli_name='file') + option: Bool('ipacertprofilestoreissued', attribute=True, autofill=False, cli_name='store', default=True, multivalue=False, required=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') +-option: Str('rename', cli_name='rename', multivalue=False, primary_key=True, required=False) + option: Flag('rights', autofill=True, default=False) + option: Str('setattr*', cli_name='setattr', exclude='webui') + option: Str('version?', exclude='webui') +diff --git a/VERSION b/VERSION +index c102e020bbbec921b0f4a2141d1c768ac093acf8..da721fdd548023dc3dcd9b4f6a8ba72922a3c6f2 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=154 +-# Last change: pvoborni - change default vault type to 'symmetric' ++IPA_API_VERSION_MINOR=155 ++# Last change: ftweedal - remove certprofile 'rename' option +diff --git a/ipalib/plugins/certprofile.py b/ipalib/plugins/certprofile.py +index a0ffa38608400860994c771e4eba81304ead27be..bd835f4c241ba1936555869d481262a8093bbb42 100644 +--- a/ipalib/plugins/certprofile.py ++++ b/ipalib/plugins/certprofile.py +@@ -115,7 +115,6 @@ class certprofile(LDAPObject): + search_attributes = [ + 'cn', 'description', 'ipacertprofilestoreissued' + ] +- rdn_is_primary_key = True + label = _('Certificate Profiles') + label_singular = _('Certificate Profile') + +@@ -323,7 +322,7 @@ class certprofile_mod(LDAPUpdate): + def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): + ca_enabled_check() + # Once a profile id is set it cannot be changed +- if 'rename' in options or 'cn' in entry_attrs: ++ if 'cn' in entry_attrs: + raise errors.ProtectedEntryError(label='certprofile', key=keys[0], + reason=_('Certificate profiles cannot be renamed')) + if 'file' in options: +-- +2.5.1 + diff --git a/SOURCES/0106-Add-anonymous-read-ACI-for-DUA-profile.patch b/SOURCES/0106-Add-anonymous-read-ACI-for-DUA-profile.patch deleted file mode 100644 index dd94dc2..0000000 --- a/SOURCES/0106-Add-anonymous-read-ACI-for-DUA-profile.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 113834837e775bfa40604d131725e9b34248465c Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Tue, 20 Jan 2015 17:57:07 +0100 -Subject: [PATCH] Add anonymous read ACI for DUA profile - -DUA profile(s) are consumed by Solaris clients. - -https://fedorahosted.org/freeipa/ticket/4850 - -Reviewed-By: Jan Cholasta ---- - ACI.txt | 2 ++ - .../install/plugins/update_managed_permissions.py | 20 ++++++++++++++++++++ - 2 files changed, 22 insertions(+) - -diff --git a/ACI.txt b/ACI.txt -index fe45d063e7d48c487e380ca3568b0f9368762c6d..67d583fabc295deb8aa5aab329bce5100c1b9088 100644 ---- a/ACI.txt -+++ b/ACI.txt -@@ -298,6 +298,8 @@ dn: cn=certificates,cn=ipa,cn=etc,dc=ipa,dc=example - aci: (targetattr = "cacertificate || cn || createtimestamp || entryusn || ipacertissuerserial || ipacertsubject || ipaconfigstring || ipakeyextusage || ipakeytrust || ipakeyusage || ipapublickey || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipacertificate)")(version 3.0;acl "permission:System: Read Certificate Store Entries";allow (compare,read,search) userdn = "ldap:///anyone";) - dn: cn=dna,cn=ipa,cn=etc,dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || dnahostname || dnaportnum || dnaremainingvalues || dnaremotebindmethod || dnaremoteconnprotocol || dnasecureportnum || entryusn || modifytimestamp || objectclass")(targetfilter = "(objectclass=dnasharedconfig)")(version 3.0;acl "permission:System: Read DNA Configuration";allow (compare,read,search) userdn = "ldap:///all";) -+dn: ou=profile,dc=ipa,dc=example -+aci: (targetattr = "attributemap || authenticationmethod || bindtimelimit || cn || createtimestamp || credentiallevel || defaultsearchbase || defaultsearchscope || defaultserverlist || dereferencealiases || entryusn || followreferrals || modifytimestamp || objectclass || objectclassmap || ou || preferredserverlist || profilettl || searchtimelimit || serviceauthenticationmethod || servicecredentiallevel || servicesearchdescriptor")(targetfilter = "(|(objectclass=organizationalUnit)(objectclass=DUAConfigProfile))")(version 3.0;acl "permission:System: Read DUA Profile";allow (compare,read,search) userdn = "ldap:///anyone";) - dn: cn=masters,cn=ipa,cn=etc,dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || entryusn || ipaconfigstring || modifytimestamp || objectclass")(targetfilter = "(objectclass=nscontainer)")(version 3.0;acl "permission:System: Read IPA Masters";allow (compare,read,search) groupdn = "ldap:///cn=System: Read IPA Masters,cn=permissions,cn=pbac,dc=ipa,dc=example";) - dn: cn=config -diff --git a/ipaserver/install/plugins/update_managed_permissions.py b/ipaserver/install/plugins/update_managed_permissions.py -index 032485aac5b84b12b91464f16870c9940b18bc2d..430a2919a315bfd8d8e6174a915890d44b782c5c 100644 ---- a/ipaserver/install/plugins/update_managed_permissions.py -+++ b/ipaserver/install/plugins/update_managed_permissions.py -@@ -320,6 +320,26 @@ NONOBJECT_PERMISSIONS = { - 'winsyncsubtreepair', - }, - 'default_privileges': {'Replication Administrators'}, -+ }, -+ 'System: Read DUA Profile': { -+ 'ipapermlocation': DN('ou=profile', api.env.basedn), -+ 'ipapermtargetfilter': { -+ '(|' -+ '(objectclass=organizationalUnit)' -+ '(objectclass=DUAConfigProfile)' -+ ')' -+ }, -+ 'ipapermbindruletype': 'anonymous', -+ 'ipapermright': {'read', 'search', 'compare'}, -+ 'ipapermdefaultattr': { -+ 'objectclass', 'ou', 'cn', 'defaultServerList', -+ 'preferredServerList', 'defaultSearchBase', 'defaultSearchScope', -+ 'searchTimeLimit', 'bindTimeLimit', 'credentialLevel', -+ 'authenticationMethod', 'followReferrals', 'dereferenceAliases', -+ 'serviceSearchDescriptor', 'serviceCredentialLevel', -+ 'serviceAuthenticationMethod', 'objectclassMap', 'attributeMap', -+ 'profileTTL' -+ }, - } - } - --- -2.1.0 - diff --git a/SOURCES/0106-Installer-do-not-modify-etc-hosts-before-user-agreem.patch b/SOURCES/0106-Installer-do-not-modify-etc-hosts-before-user-agreem.patch new file mode 100644 index 0000000..a158b1d --- /dev/null +++ b/SOURCES/0106-Installer-do-not-modify-etc-hosts-before-user-agreem.patch @@ -0,0 +1,235 @@ +From b6c7247319575a376ac9a480ae6ceda39a2bd968 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 1 Sep 2015 19:05:01 +0200 +Subject: [PATCH] Installer: do not modify /etc/hosts before user agreement + +https://fedorahosted.org/freeipa/ticket/4561 + +As side effect this also fixes: +https://fedorahosted.org/freeipa/ticket/5266 + +Reviewed-By: David Kupka +--- + ipaserver/install/dns.py | 9 ++++++-- + ipaserver/install/installutils.py | 36 +++++++++++++++++++----------- + ipaserver/install/server/install.py | 14 ++++++++++-- + ipaserver/install/server/replicainstall.py | 12 +++++++++- + 4 files changed, 53 insertions(+), 18 deletions(-) + +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index 538e99fbe01a34cee627f1cebd938be19777c134..099e35dc331722607c8ca02cdbc7a0e66f8c4754 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -19,6 +19,7 @@ from ipapython.ipaldap import AUTOBIND_ENABLED + from ipapython.ipautil import user_input + from ipaserver.install.installutils import get_server_ip_address + from ipaserver.install.installutils import read_dns_forwarders ++from ipaserver.install.installutils import update_hosts_file + from ipaserver.install import bindinstance + from ipaserver.install import dnskeysyncinstance + from ipaserver.install import ntpinstance +@@ -225,8 +226,8 @@ def install_check(standalone, replica, options, hostname): + "the original kasp.db file." % + ", ".join([str(zone) for zone in dnssec_zones])) + +- ip_addresses = get_server_ip_address( +- hostname, fstore, options.unattended, True, options.ip_addresses) ++ ip_addresses = get_server_ip_address(hostname, options.unattended, ++ True, options.ip_addresses) + + if options.no_forwarders: + dns_forwarders = () +@@ -277,6 +278,10 @@ def install(standalone, replica, options): + + conf_ntp = ntpinstance.NTPInstance(fstore).is_enabled() + ++ if standalone: ++ # otherwise this is done by server/replica installer ++ update_hosts_file(ip_addresses, api.env.host, fstore) ++ + bind = bindinstance.BindInstance(fstore, ldapi=True, + autobind=AUTOBIND_ENABLED) + bind.setup(api.env.host, ip_addresses, api.env.realm, api.env.domain, +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 02e8526317dbab909ed48a1823000922ce6e6b7a..81a025597c97b41377c35a6714bf1d3001c868cc 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -264,7 +264,8 @@ def read_ip_address(host_name, fstore): + + return ip_parsed + +-def read_ip_addresses(host_name, fstore): ++ ++def read_ip_addresses(): + ips = [] + print "Enter the IP address to use, or press Enter to finish." + while True: +@@ -470,7 +471,7 @@ def get_host_name(no_host_dns): + verify_fqdn(hostname, no_host_dns) + return hostname + +-def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses): ++def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses): + # Check we have a public IP that is associated with the hostname + try: + hostaddr = resolve_host(host_name) +@@ -483,8 +484,6 @@ def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses + print >> sys.stderr, "Please fix your /etc/hosts file and restart the setup program" + sys.exit(1) + +- ip_add_to_hosts = False +- + ips = [] + if len(hostaddr): + for ha in hostaddr: +@@ -495,7 +494,7 @@ def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses + + if not ips and not ip_addresses: + if not unattended: +- ip_addresses = read_ip_addresses(host_name, fstore) ++ ip_addresses = read_ip_addresses() + + if ip_addresses: + if setup_dns: +@@ -511,22 +510,16 @@ def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses + print >>sys.stderr, "Provided but not resolved address(es): %s" % \ + ", ".join(str(ip) for ip in (set(ip_addresses) - set(ips))) + sys.exit(1) +- ip_add_to_hosts = True + + if not ips: + print >> sys.stderr, "No usable IP address provided nor resolved." + sys.exit(1) + + for ip_address in ips: +- # check /etc/hosts sanity, add a record when needed ++ # check /etc/hosts sanity + hosts_record = record_in_hosts(str(ip_address)) + +- if hosts_record is None: +- if ip_add_to_hosts or setup_dns: +- print "Adding ["+str(ip_address)+" "+host_name+"] to your /etc/hosts file" +- fstore.backup_file(paths.HOSTS) +- add_record_to_hosts(str(ip_address), host_name) +- else: ++ if hosts_record is not None: + primary_host = hosts_record[1][0] + if primary_host != host_name: + print >>sys.stderr, "Error: there is already a record in /etc/hosts for IP address %s:" \ +@@ -539,6 +532,23 @@ def get_server_ip_address(host_name, fstore, unattended, setup_dns, ip_addresses + + return ips + ++ ++def update_hosts_file(ip_addresses, host_name, fstore): ++ """ ++ Update hosts with specified addresses ++ :param ip_addresses: list of IP addresses ++ :return: ++ """ ++ if not fstore.has_file(paths.HOSTS): ++ fstore.backup_file(paths.HOSTS) ++ for ip_address in ip_addresses: ++ if record_in_hosts(str(ip_address)): ++ continue ++ print "Adding [{address!s} {name}] to your /etc/hosts file".format( ++ address=ip_address, name=host_name) ++ add_record_to_hosts(str(ip_address), host_name) ++ ++ + def expand_replica_info(filename, password): + """ + Decrypt and expand a replica installation file into a temporary +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index ff517513473a458a84f63c5c1308a8cc0b8699f8..9d7036a7786a35e6aa2429254d62c8afb30970db 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -32,7 +32,8 @@ from ipaserver.install import ( + otpdinstance, replication, service, sysupgrade) + from ipaserver.install.installutils import ( + IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address, +- is_ipa_configured, load_pkcs12, read_password, verify_fqdn) ++ is_ipa_configured, load_pkcs12, read_password, verify_fqdn, ++ update_hosts_file) + from ipaserver.plugins.ldap2 import ldap2 + try: + from ipaserver.install import adtrustinstance +@@ -607,10 +608,15 @@ def install_check(installer): + dns.install_check(False, False, options, host_name) + ip_addresses = dns.ip_addresses + else: +- ip_addresses = get_server_ip_address(host_name, fstore, ++ ip_addresses = get_server_ip_address(host_name, + not installer.interactive, False, + options.ip_addresses) + ++ # installer needs to update hosts file when DNS subsystem will be ++ # installed or custom addresses are used ++ if options.ip_addresses or options.setup_dns: ++ installer._update_hosts_file = True ++ + print + print "The IPA Master Server will be configured with:" + print "Hostname: %s" % host_name +@@ -709,6 +715,9 @@ def install(installer): + # configure /etc/sysconfig/network to contain the custom hostname + tasks.backup_and_replace_hostname(fstore, sstore, host_name) + ++ if installer._update_hosts_file: ++ update_hosts_file(ip_addresses, host_name, fstore) ++ + # Create DS user/group if it doesn't exist yet + dsinstance.create_ds_user() + +@@ -1494,6 +1503,7 @@ class Server(common.Installable, common.Interactive, core.Composite): + self._external_cert_file = None + self._external_ca_file = None + self._ca_cert = None ++ self._update_hosts_file = False + + #pylint: disable=no-member + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 0725c7763e505ca0cc5a8892414a3c36c557cf1d..6f9a6141fe9af44806244ce52df59c191dc966b0 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -502,11 +502,17 @@ def install_check(installer): + + if options.setup_dns: + dns.install_check(False, True, options, config.host_name) ++ config.ips = dns.ip_addresses + else: + config.ips = installutils.get_server_ip_address( +- config.host_name, fstore, not installer.interactive, False, ++ config.host_name, not installer.interactive, False, + options.ip_addresses) + ++ # installer needs to update hosts file when DNS subsystem will be ++ # installed or custom addresses are used ++ if options.setup_dns or options.ip_addresses: ++ installer._update_hosts_file = True ++ + # check connection + if not options.skip_conncheck: + replica_conn_check( +@@ -528,6 +534,9 @@ def install(installer): + + dogtag_constants = dogtag.install_constants + ++ if installer._update_hosts_file: ++ installutils.update_hosts_file(config.ips, config.host_name, fstore) ++ + # Create DS user/group if it doesn't exist yet + dsinstance.create_ds_user() + +@@ -785,6 +794,7 @@ class Replica(common.Installable, common.Interactive, core.Composite): + + self._top_dir = None + self._config = None ++ self._update_hosts_file = False + + #pylint: disable=no-member + +-- +2.5.1 + diff --git a/SOURCES/0107-DNSSEC-backup-and-restore-opendnssec-zone-list-file.patch b/SOURCES/0107-DNSSEC-backup-and-restore-opendnssec-zone-list-file.patch new file mode 100644 index 0000000..b07436f --- /dev/null +++ b/SOURCES/0107-DNSSEC-backup-and-restore-opendnssec-zone-list-file.patch @@ -0,0 +1,43 @@ +From 7b04b9e603bf6517458cccae7509e99f10c8a0ec Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 1 Sep 2015 12:10:00 +0200 +Subject: [PATCH] DNSSEC: backup and restore opendnssec zone list file + +When zone list is not restored after unninstall, this may slow down +enbaling DNSSEC signing for zones and print unwanted +errors into log after new installation. + +Related to: https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Petr Spacek +--- + ipaserver/install/opendnssecinstance.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py +index 0f1af828ea245046330fdfab77db130ca14faba3..c5377d910d8f38a1ea0e05461ecf1b92f05ca2ca 100644 +--- a/ipaserver/install/opendnssecinstance.py ++++ b/ipaserver/install/opendnssecinstance.py +@@ -171,6 +171,9 @@ class OpenDNSSECInstance(service.Service): + if not self.fstore.has_file(paths.OPENDNSSEC_KASP_FILE): + self.fstore.backup_file(paths.OPENDNSSEC_KASP_FILE) + ++ if not self.fstore.has_file(paths.OPENDNSSEC_ZONELIST_FILE): ++ self.fstore.backup_file(paths.OPENDNSSEC_ZONELIST_FILE) ++ + pin_fd = open(paths.DNSSEC_SOFTHSM_PIN, "r") + pin = pin_fd.read() + pin_fd.close() +@@ -357,7 +360,8 @@ class OpenDNSSECInstance(service.Service): + paths.IPA_KASP_DB_BACKUP) + + for f in [paths.OPENDNSSEC_CONF_FILE, paths.OPENDNSSEC_KASP_FILE, +- paths.OPENDNSSEC_KASP_DB, paths.SYSCONFIG_ODS]: ++ paths.OPENDNSSEC_KASP_DB, paths.SYSCONFIG_ODS, ++ paths.OPENDNSSEC_ZONELIST_FILE]: + try: + self.fstore.restore_file(f) + except ValueError, error: +-- +2.5.1 + diff --git a/SOURCES/0107-Revert-Make-all-ipatokenTOTP-attributes-mandatory.patch b/SOURCES/0107-Revert-Make-all-ipatokenTOTP-attributes-mandatory.patch deleted file mode 100644 index da907c4..0000000 --- a/SOURCES/0107-Revert-Make-all-ipatokenTOTP-attributes-mandatory.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 04eb9743de09e5d2bc00d6a775249c3c2c439a2d Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 21 Jan 2015 07:57:03 +0000 -Subject: [PATCH] Revert "Make all ipatokenTOTP attributes mandatory" - -This prevents schema replication conflicts which cause replication failures -with older versions of IPA. Details in -https://bugzilla.redhat.com/show_bug.cgi?id=1176995#c7 - -This reverts commit adcd373931c50d91550f6b74b191d08ecce5b137. - -https://fedorahosted.org/freeipa/ticket/4833 - -Reviewed-By: Martin Kosek ---- - install/share/70ipaotp.ldif | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/share/70ipaotp.ldif b/install/share/70ipaotp.ldif -index bc95556682ef65ba375aa2f3cab6f53621641b3f..61cb8f63b9b4aba80a2785afb46bff206ab0eff0 100644 ---- a/install/share/70ipaotp.ldif -+++ b/install/share/70ipaotp.ldif -@@ -25,7 +25,7 @@ attributeTypes: (2.16.840.1.113730.3.8.16.1.20 NAME 'ipatokenUserMapAttribute' D - attributeTypes: (2.16.840.1.113730.3.8.16.1.21 NAME 'ipatokenHOTPcounter' DESC 'HOTP counter' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') - attributeTypes: (2.16.840.1.113730.3.8.16.1.22 NAME 'ipatokenTOTPwatermark' DESC 'TOTP watermark' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') - objectClasses: (2.16.840.1.113730.3.8.16.2.1 NAME 'ipaToken' SUP top ABSTRACT DESC 'Abstract token class for tokens' MUST (ipatokenUniqueID) MAY (description $ managedBy $ ipatokenOwner $ ipatokenDisabled $ ipatokenNotBefore $ ipatokenNotAfter $ ipatokenVendor $ ipatokenModel $ ipatokenSerial) X-ORIGIN 'IPA OTP') --objectClasses: (2.16.840.1.113730.3.8.16.2.2 NAME 'ipatokenTOTP' SUP ipaToken STRUCTURAL DESC 'TOTP Token Type' MUST (ipatokenOTPkey $ ipatokenOTPalgorithm $ ipatokenOTPdigits $ ipatokenTOTPclockOffset $ ipatokenTOTPtimeStep) MAY (ipatokenTOTPwatermark) X-ORIGIN 'IPA OTP') -+objectClasses: (2.16.840.1.113730.3.8.16.2.2 NAME 'ipatokenTOTP' SUP ipaToken STRUCTURAL DESC 'TOTP Token Type' MAY (ipatokenOTPkey $ ipatokenOTPalgorithm $ ipatokenOTPdigits $ ipatokenTOTPclockOffset $ ipatokenTOTPtimeStep $ ipatokenTOTPwatermark) X-ORIGIN 'IPA OTP') - objectClasses: (2.16.840.1.113730.3.8.16.2.3 NAME 'ipatokenRadiusProxyUser' SUP top AUXILIARY DESC 'Radius Proxy User' MAY (ipatokenRadiusConfigLink $ ipatokenRadiusUserName) X-ORIGIN 'IPA OTP') - objectClasses: (2.16.840.1.113730.3.8.16.2.4 NAME 'ipatokenRadiusConfiguration' SUP top STRUCTURAL DESC 'Proxy Radius Configuration' MUST (cn $ ipatokenRadiusServer $ ipatokenRadiusSecret) MAY (description $ ipatokenRadiusTimeout $ ipatokenRadiusRetries $ ipatokenUserMapAttribute) X-ORIGIN 'IPA OTP') - objectClasses: (2.16.840.1.113730.3.8.16.2.5 NAME 'ipatokenHOTP' SUP ipaToken STRUCTURAL DESC 'HOTP Token Type' MUST (ipatokenOTPkey $ ipatokenOTPalgorithm $ ipatokenOTPdigits $ ipatokenHOTPcounter) X-ORIGIN 'IPA OTP') --- -2.1.0 - diff --git a/SOURCES/0108-Create-correct-log-directories-during-full-restore-i.patch b/SOURCES/0108-Create-correct-log-directories-during-full-restore-i.patch deleted file mode 100644 index 5b916f5..0000000 --- a/SOURCES/0108-Create-correct-log-directories-during-full-restore-i.patch +++ /dev/null @@ -1,57 +0,0 @@ -From ed5044ffc209e842c000d1c47980de6e0ab8e52a Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 26 Jan 2015 10:39:48 +0000 -Subject: [PATCH] Create correct log directories during full restore in - ipa-restore - -https://fedorahosted.org/freeipa/ticket/4865 - -Reviewed-By: Martin Kosek ---- - ipaserver/install/ipa_restore.py | 29 ++++++++++++++--------------- - 1 file changed, 14 insertions(+), 15 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 562a793c2c9383d7495c84a817ac9f7a1407f9bb..6de73e640d101a72aacc7ce73a6937c222da4ebb 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -713,22 +713,21 @@ class Restore(admintool.AdminTool): - not exist then tomcat will fail to start. - - The directory is different depending on whether we have a d9-based -- or a d10-based installation. We can tell based on whether there is -- a PKI-IPA 389-ds instance. -+ or a d10-based installation. - """ -- if os.path.exists(paths.ETC_SLAPD_PKI_IPA_DIR): # dogtag 9 -- topdir = paths.PKI_CA_LOG_DIR -- dirs = [topdir, -- '/var/log/pki-ca/signedAudit,'] -- else: # dogtag 10 -- topdir = paths.TOMCAT_TOPLEVEL_DIR -- dirs = [topdir, -- paths.TOMCAT_CA_DIR, -- paths.TOMCAT_CA_ARCHIVE_DIR, -- paths.TOMCAT_SIGNEDAUDIT_DIR,] -- -- if os.path.exists(topdir): -- return -+ dirs = [] -+ # dogtag 9 -+ if (os.path.exists(paths.VAR_LIB_PKI_CA_DIR) and -+ not os.path.exists(paths.PKI_CA_LOG_DIR)): -+ dirs += [paths.PKI_CA_LOG_DIR, -+ os.path.join(paths.PKI_CA_LOG_DIR, 'signedAudit')] -+ # dogtag 10 -+ if (os.path.exists(paths.VAR_LIB_PKI_TOMCAT_DIR) and -+ not os.path.exists(paths.TOMCAT_TOPLEVEL_DIR)): -+ dirs += [paths.TOMCAT_TOPLEVEL_DIR, -+ paths.TOMCAT_CA_DIR, -+ paths.TOMCAT_CA_ARCHIVE_DIR, -+ paths.TOMCAT_SIGNEDAUDIT_DIR] - - try: - pent = pwd.getpwnam(PKI_USER) --- -2.1.0 - diff --git a/SOURCES/0108-DNSSEC-remove-ccache-and-keytab-of-ipa-ods-exporter.patch b/SOURCES/0108-DNSSEC-remove-ccache-and-keytab-of-ipa-ods-exporter.patch new file mode 100644 index 0000000..bb67a96 --- /dev/null +++ b/SOURCES/0108-DNSSEC-remove-ccache-and-keytab-of-ipa-ods-exporter.patch @@ -0,0 +1,63 @@ +From 832335c92c7ce21ffb8ea9315837aebc2a085d88 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 1 Sep 2015 16:17:16 +0200 +Subject: [PATCH] DNSSEC: remove ccache and keytab of ipa-ods-exporter + +Reusing old ccache after reinstall causes authentication error. And +prevents DNSSEC from working. + +Related to ticket: https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Petr Spacek +--- + daemons/dnssec/ipa-ods-exporter | 2 +- + ipaplatform/base/paths.py | 1 + + ipaserver/install/odsexporterinstance.py | 7 +++++++ + 3 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter +index 4d5423797fc9d4bdd0a432bac96b8209bb98c6d8..62eca71da10ee6f3efd4d391a274278875714570 100755 +--- a/daemons/dnssec/ipa-ods-exporter ++++ b/daemons/dnssec/ipa-ods-exporter +@@ -482,7 +482,7 @@ ipalib.api.finalize() + # Kerberos initialization + PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host)) + log.debug('Kerberos principal: %s', PRINCIPAL) +-ccache_name = os.path.join(WORKDIR, 'ipa-ods-exporter.ccache') ++ccache_name = paths.IPA_ODS_EXPORTER_CCACHE + + try: + ipautil.kinit_keytab(PRINCIPAL, paths.IPA_ODS_EXPORTER_KEYTAB, ccache_name, +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 5c8f25d6ef85fab2b9b30a660cd1c0360dbe9931..a407c1273f01b3465bcb1985dd41f2f242346a62 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -333,6 +333,7 @@ class BasePathNamespace(object): + NAMED_RUN = "/var/named/data/named.run" + VAR_OPENDNSSEC_DIR = "/var/opendnssec" + OPENDNSSEC_KASP_DB = "/var/opendnssec/kasp.db" ++ IPA_ODS_EXPORTER_CCACHE = "/var/opendnssec/tmp/ipa-ods-exporter.ccache" + VAR_RUN_DIRSRV_DIR = "/var/run/dirsrv" + KRB5CC_HTTPD = "/var/run/httpd/ipa/krbcache/krb5ccache" + IPA_RENEWAL_LOCK = "/var/run/ipa/renewal.lock" +diff --git a/ipaserver/install/odsexporterinstance.py b/ipaserver/install/odsexporterinstance.py +index 248943d6c0ca4b71815bcf7526d575842f6ce426..db45d2b812ff6d2d56cb8fb326119658bd1f4b7e 100644 +--- a/ipaserver/install/odsexporterinstance.py ++++ b/ipaserver/install/odsexporterinstance.py +@@ -93,6 +93,13 @@ class ODSExporterInstance(service.Service): + + def __setup_principal(self): + assert self.ods_uid is not None ++ ++ for f in [paths.IPA_ODS_EXPORTER_CCACHE, paths.IPA_ODS_EXPORTER_KEYTAB]: ++ try: ++ os.remove(f) ++ except OSError: ++ pass ++ + dns_exporter_principal = "ipa-ods-exporter/" + self.fqdn + "@" + self.realm + installutils.kadmin_addprinc(dns_exporter_principal) + +-- +2.5.1 + diff --git a/SOURCES/0109-DNSSEC-prevent-ipa-ods-exporter-from-looping-after-s.patch b/SOURCES/0109-DNSSEC-prevent-ipa-ods-exporter-from-looping-after-s.patch new file mode 100644 index 0000000..2bad936 --- /dev/null +++ b/SOURCES/0109-DNSSEC-prevent-ipa-ods-exporter-from-looping-after-s.patch @@ -0,0 +1,47 @@ +From 29cf6ce568747eca90497a29aa21927ac2b69496 Mon Sep 17 00:00:00 2001 +From: Petr Spacek +Date: Mon, 31 Aug 2015 17:58:07 +0200 +Subject: [PATCH] DNSSEC: prevent ipa-ods-exporter from looping after service + auto-restart + +It might happen that systemd will restart the service even if there is +no incomming connection to service socket. In that case we want to exit +because HSM synchronization is done before socket.accept() and we want +to synchronize HSM and DNS zones at the same time. + +https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Martin Basti +Reviewed-By: Oleg Fayans +--- + daemons/dnssec/ipa-ods-exporter | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter +index 62eca71da10ee6f3efd4d391a274278875714570..9544db149aed6574a8962d6c8e6b6f1bc520d6db 100755 +--- a/daemons/dnssec/ipa-ods-exporter ++++ b/daemons/dnssec/ipa-ods-exporter +@@ -25,6 +25,7 @@ import logging + import os + import subprocess + import socket ++import select + import sys + import systemd.daemon + import systemd.journal +@@ -346,7 +347,12 @@ def receive_systemd_command(log): + raise KeyError('Exactly one socket is expected.') + + sck = socket.fromfd(fds[0], socket.AF_UNIX, socket.SOCK_STREAM) ++ rlist, wlist, xlist = select.select([sck], [], [], 0) ++ if not rlist: ++ log.critical('socket activation did not return socket with a command') ++ sys.exit(0) + ++ log.debug('accepting new connection') + conn, addr = sck.accept() + log.debug('accepted new connection %s', repr(conn)) + +-- +2.5.1 + diff --git a/SOURCES/0109-Do-not-crash-when-replica-is-unreachable-in-ipa-rest.patch b/SOURCES/0109-Do-not-crash-when-replica-is-unreachable-in-ipa-rest.patch deleted file mode 100644 index d770803..0000000 --- a/SOURCES/0109-Do-not-crash-when-replica-is-unreachable-in-ipa-rest.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 394e24cee7dfb8f1d860b936f7a865e8cace8c71 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 27 Jan 2015 07:38:06 +0000 -Subject: [PATCH] Do not crash when replica is unreachable in ipa-restore - -https://fedorahosted.org/freeipa/ticket/4857 - -Reviewed-By: Martin Kosek ---- - ipaserver/install/ipa_restore.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 6de73e640d101a72aacc7ce73a6937c222da4ebb..efe3b9b1c0c10775b3a72b9d843924263526209a 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -458,6 +458,7 @@ class Restore(admintool.AdminTool): - self.dirman_password) - except Exception, e: - self.log.critical("Unable to disable agreement on %s: %s" % (master, e)) -+ continue - - master_dn = DN(('cn', master), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) - try: -@@ -482,6 +483,7 @@ class Restore(admintool.AdminTool): - self.dirman_password) - except Exception, e: - self.log.critical("Unable to disable agreement on %s: %s" % (master, e)) -+ continue - - host_entries = repl.find_ipa_replication_agreements() - hosts = [rep.single_value.get('nsds5replicahost') --- -2.1.0 - diff --git a/SOURCES/0110-DNSSEC-Fix-deadlock-in-ipa-ods-exporter-ods-enforcer.patch b/SOURCES/0110-DNSSEC-Fix-deadlock-in-ipa-ods-exporter-ods-enforcer.patch new file mode 100644 index 0000000..51fd00d --- /dev/null +++ b/SOURCES/0110-DNSSEC-Fix-deadlock-in-ipa-ods-exporter-ods-enforcer.patch @@ -0,0 +1,97 @@ +From c50f7610b1781ccbd6f169805d29d84e34e46db8 Mon Sep 17 00:00:00 2001 +From: Petr Spacek +Date: Mon, 31 Aug 2015 18:01:12 +0200 +Subject: [PATCH] DNSSEC: Fix deadlock in ipa-ods-exporter <-> ods-enforcerd + interaction + +https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Martin Basti +Reviewed-By: Oleg Fayans +--- + daemons/dnssec/ipa-ods-exporter | 39 +++++++++++++++++++++++++++++++-------- + 1 file changed, 31 insertions(+), 8 deletions(-) + +diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter +index 9544db149aed6574a8962d6c8e6b6f1bc520d6db..76c7e484c65888b3d722448ee669ca8d95e3f3d9 100755 +--- a/daemons/dnssec/ipa-ods-exporter ++++ b/daemons/dnssec/ipa-ods-exporter +@@ -368,12 +368,12 @@ def parse_command(cmd): + """ + if cmd == 'ipa-hsm-update': + return (0, +- 'HSM synchronization finished, exiting.', ++ 'HSM synchronization finished, skipping zone synchronization.', + None) + + elif cmd == 'ipa-full-update': + return (None, +- 'Synchronization of all zones requested.', ++ 'Synchronization of all zones was finished.', + None) + + elif not cmd.startswith('update '): +@@ -386,7 +386,7 @@ def parse_command(cmd): + else: + zone_name = cmd2ods_zone_name(cmd) + return (None, +- 'Update request for zone "%s" queued.\n' % zone_name, ++ 'Zone was "%s" updated.\n' % zone_name, + zone_name) + + def send_systemd_reply(conn, reply): +@@ -541,18 +541,29 @@ except KeyError as e: + + exitcode, msg, zone_name = parse_command(cmd) + +-if conn: +- send_systemd_reply(conn, msg) + if exitcode is not None: ++ if conn: ++ send_systemd_reply(conn, msg) + log.info(msg) + sys.exit(exitcode) + else: + log.debug(msg) + + # Open DB directly and read key timestamps etc. +-with ods_db_lock(): +- db = sqlite3.connect(paths.OPENDNSSEC_KASP_DB, +- isolation_level="EXCLUSIVE") ++db = None ++try: ++ # LOCK WARNING: ++ # ods-enforcerd is holding kasp.db.our_lock when processing all zones and ++ # the lock is unlocked only after all calls to ods-signer are finished, ++ # i.e. when ods-enforcerd receives reply from each ods-signer call. ++ # ++ # Consequently, ipa-ods-exporter (ods-signerd implementation) must not ++ # request kasp.db.our_lock to prevent deadlocks. ++ # SQLite transaction isolation should suffice. ++ # Beware: Reply can be sent back only after DB is unlocked and closed ++ # otherwise ods-enforcerd will fail. ++ ++ db = sqlite3.connect(paths.OPENDNSSEC_KASP_DB) + db.row_factory = sqlite3.Row + db.execute('BEGIN') + +@@ -564,4 +575,16 @@ with ods_db_lock(): + for zone_row in db.execute("SELECT name FROM zones"): + sync_zone(log, ldap, dns_dn, zone_row['name']) + ++except Exception as ex: ++ msg = "ipa-ods-exporter exception: %s" % ex ++ raise ex ++ ++finally: ++ try: ++ if db: ++ db.close() ++ finally: ++ if conn: ++ send_systemd_reply(conn, msg) ++ + log.debug('Done') +-- +2.5.1 + diff --git a/SOURCES/0110-idviews-Allow-setting-ssh-public-key-on-ipauseroverr.patch b/SOURCES/0110-idviews-Allow-setting-ssh-public-key-on-ipauseroverr.patch deleted file mode 100644 index fb67ee0..0000000 --- a/SOURCES/0110-idviews-Allow-setting-ssh-public-key-on-ipauseroverr.patch +++ /dev/null @@ -1,36 +0,0 @@ -From f6a6555e5dff1c3132529f7671b1978eab10315e Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 27 Jan 2015 16:12:19 +0100 -Subject: [PATCH] idviews: Allow setting ssh public key on ipauseroverride-add - -https://fedorahosted.org/freeipa/ticket/4868 - -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/idviews.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ipalib/plugins/idviews.py b/ipalib/plugins/idviews.py -index 9c8721018325f56e681f168b55c31055bfd07345..aa2c89163d875a813b0b850125e522935e2ef44f 100644 ---- a/ipalib/plugins/idviews.py -+++ b/ipalib/plugins/idviews.py -@@ -665,6 +665,7 @@ class idoverrideuser(baseidoverride): - } - - object_class = baseidoverride.object_class + ['ipaUserOverride'] -+ possible_objectclasses = ['ipasshuser', 'ipaSshGroupOfPubKeys'] - default_attributes = baseidoverride.default_attributes + [ - 'homeDirectory', 'uidNumber', 'uid', 'ipaOriginalUid', 'loginShell', - 'ipaSshPubkey', 'gidNumber', 'gecos', -@@ -779,6 +780,8 @@ class idoverrideuser_add(baseidoverride_add): - dn = super(idoverrideuser_add, self).pre_callback(ldap, dn, - entry_attrs, attrs_list, *keys, **options) - -+ entry_attrs['objectclass'].append('ipasshuser') -+ - # Update the ipaOriginalUid - self.obj.update_original_uid_reference(entry_attrs) - return dn --- -2.1.0 - diff --git a/SOURCES/0111-DNSSEC-Fix-HSM-synchronization-in-ipa-dnskeysyncd-wh.patch b/SOURCES/0111-DNSSEC-Fix-HSM-synchronization-in-ipa-dnskeysyncd-wh.patch new file mode 100644 index 0000000..705c9c7 --- /dev/null +++ b/SOURCES/0111-DNSSEC-Fix-HSM-synchronization-in-ipa-dnskeysyncd-wh.patch @@ -0,0 +1,27 @@ +From fec0e8360bbd2ead6eb522348ed2b05bd6fdf7bb Mon Sep 17 00:00:00 2001 +From: Petr Spacek +Date: Mon, 31 Aug 2015 18:03:33 +0200 +Subject: [PATCH] DNSSEC: Fix HSM synchronization in ipa-dnskeysyncd when + running on DNSSEC key master + +https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Martin Basti +Reviewed-By: Oleg Fayans +--- + ipapython/dnssec/keysyncer.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipapython/dnssec/keysyncer.py b/ipapython/dnssec/keysyncer.py +index 837602fb4e7c74a7099a351c727d1435b5645706..de5b5aa5f670db4c58fb92b989e181d45d887b55 100644 +--- a/ipapython/dnssec/keysyncer.py ++++ b/ipapython/dnssec/keysyncer.py +@@ -177,4 +177,4 @@ class KeySyncer(SyncReplConsumer): + return + if not self.init_done: + return +- ipautil.run([paths.ODS_SIGNER]) ++ ipautil.run([paths.ODS_SIGNER, 'ipa-hsm-update']) +-- +2.5.1 + diff --git a/SOURCES/0111-Fix-ipa-pwd-extop-global-configuration-caching.patch b/SOURCES/0111-Fix-ipa-pwd-extop-global-configuration-caching.patch deleted file mode 100644 index 5758f5f..0000000 --- a/SOURCES/0111-Fix-ipa-pwd-extop-global-configuration-caching.patch +++ /dev/null @@ -1,39 +0,0 @@ -From f0a61fa88284f8872f1496c0c0b24908d70274c8 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Thu, 29 Jan 2015 16:58:16 -0500 -Subject: [PATCH] Fix ipa-pwd-extop global configuration caching - -This fix is already upstream as part of the following commit: - 9baa93da1cbf56c2a6f7e82e099bc3ff3f19e2e4 - -https://bugzilla.redhat.com/show_bug.cgi?id=1187342 ---- - daemons/ipa-slapi-plugins/libotp/otp_config.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/libotp/otp_config.c b/daemons/ipa-slapi-plugins/libotp/otp_config.c -index 1b7c1e658f126e3d1e8eabd129bb69dc5c4ce970..f600789f34ca87bf57ac3ee7d551843680cc86f1 100644 ---- a/daemons/ipa-slapi-plugins/libotp/otp_config.c -+++ b/daemons/ipa-slapi-plugins/libotp/otp_config.c -@@ -126,10 +126,14 @@ static uint32_t find_value(const struct otp_config *cfg, - - sdn = make_sdn(spec->prefix, suffix); - for (struct record *rec = cfg->records; rec != NULL; rec = rec->next) { -- if (rec->spec == spec) { -- value = PR_ATOMIC_ADD(&rec->value, 0); -- break; -- } -+ if (rec->spec != spec) -+ continue; -+ -+ if (slapi_sdn_compare(sdn, rec->sdn) != 0) -+ continue; -+ -+ value = PR_ATOMIC_ADD(&rec->value, 0); -+ break; - } - - slapi_sdn_free(&sdn); --- -2.1.0 - diff --git a/SOURCES/0112-DNSSEC-Fix-key-metadata-export.patch b/SOURCES/0112-DNSSEC-Fix-key-metadata-export.patch new file mode 100644 index 0000000..719266d --- /dev/null +++ b/SOURCES/0112-DNSSEC-Fix-key-metadata-export.patch @@ -0,0 +1,32 @@ +From b250ac5d752b3565b4fdfb74e8de38784ba93d89 Mon Sep 17 00:00:00 2001 +From: Petr Spacek +Date: Mon, 31 Aug 2015 18:40:50 +0200 +Subject: [PATCH] DNSSEC: Fix key metadata export + +Incorrect SQL join condition could lead to situation where metadata from +ZSK and KSK were interchanged. + +https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Martin Basti +Reviewed-By: Oleg Fayans +--- + daemons/dnssec/ipa-ods-exporter | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter +index 76c7e484c65888b3d722448ee669ca8d95e3f3d9..e0c88936d5983297483c504d422c8d1ee483b6cf 100755 +--- a/daemons/dnssec/ipa-ods-exporter ++++ b/daemons/dnssec/ipa-ods-exporter +@@ -174,7 +174,7 @@ def get_ods_keys(zone_name): + + # get all keys for given zone ID + cur = db.execute("SELECT kp.HSMkey_id, kp.generate, kp.algorithm, dnsk.publish, dnsk.active, dnsk.retire, dnsk.dead, dnsk.keytype " +- "FROM keypairs AS kp JOIN dnsseckeys AS dnsk ON kp.id = dnsk.id " ++ "FROM keypairs AS kp JOIN dnsseckeys AS dnsk ON kp.id = dnsk.keypair_id " + "WHERE dnsk.zone_id = ?", (zone_id,)) + keys = {} + for row in cur: +-- +2.5.1 + diff --git a/SOURCES/0112-group-detach-does-not-add-correct-objectclasses.patch b/SOURCES/0112-group-detach-does-not-add-correct-objectclasses.patch deleted file mode 100644 index e6f1196..0000000 --- a/SOURCES/0112-group-detach-does-not-add-correct-objectclasses.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 225b31ba835e5c082dc116a9ca9a5d94eaaaf102 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Fri, 30 Jan 2015 13:11:30 +0100 -Subject: [PATCH] group-detach does not add correct objectclasses - -https://fedorahosted.org/freeipa/ticket/4874 ---- - ipalib/plugins/group.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py -index d25ed9a1958119a5872db85e958323fdb8205366..5d33ba217137f31e59a9e63cb69a442b138e156b 100644 ---- a/ipalib/plugins/group.py -+++ b/ipalib/plugins/group.py -@@ -653,6 +653,7 @@ class group_detach(LDAPQuery): - objectclasses = list(set(def_objectclass + objectclasses)) - - group_attrs['mepManagedBy'] = None -+ group_attrs['objectclass'] = objectclasses - ldap.update_entry(group_attrs) - - return dict( --- -1.9.3 - diff --git a/SOURCES/0113-Always-return-absolute-idnsname-in-dnszone-commands.patch b/SOURCES/0113-Always-return-absolute-idnsname-in-dnszone-commands.patch deleted file mode 100644 index ea41cde..0000000 --- a/SOURCES/0113-Always-return-absolute-idnsname-in-dnszone-commands.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 9b01d87626de2c5a0cb9b5e0d10959b13f03fbba Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 15 Jan 2015 13:13:55 +0100 -Subject: [PATCH] Always return absolute idnsname in dnszone commands - -Ticket: https://fedorahosted.org/freeipa/ticket/4722 -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/dns.py | 36 ++++++++++++++++++++++++++++++++++-- - 1 file changed, 34 insertions(+), 2 deletions(-) - -diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py -index 34afc189866993481229bb68a5edd77e0a4eaff3..ea4c212b42631e8513a13d2a7f5a859b2176376b 100644 ---- a/ipalib/plugins/dns.py -+++ b/ipalib/plugins/dns.py -@@ -1848,6 +1848,18 @@ class DNSZoneBase(LDAPObject): - except errors.NotFound: - raise e # re-raise original exception - -+ def _make_zonename_absolute(self, entry_attrs, **options): -+ """ -+ Zone names can be relative in IPA < 4.0, make sure we always return -+ absolute zone name from ldap -+ """ -+ if options.get('raw'): -+ return -+ -+ if "idnsname" in entry_attrs: -+ entry_attrs.single_value['idnsname'] = ( -+ entry_attrs.single_value['idnsname'].make_absolute()) -+ - - class DNSZoneBase_add(LDAPCreate): - -@@ -1895,6 +1907,11 @@ class DNSZoneBase_del(LDAPDelete): - class DNSZoneBase_mod(LDAPUpdate): - has_output_params = LDAPUpdate.has_output_params + dnszone_output_params - -+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -+ assert isinstance(dn, DN) -+ self.obj._make_zonename_absolute(entry_attrs, **options) -+ return dn -+ - - class DNSZoneBase_find(LDAPSearch): - __doc__ = _('Search for DNS zones (SOA records).') -@@ -1929,6 +1946,11 @@ class DNSZoneBase_find(LDAPSearch): - filter = _create_idn_filter(self, ldap, *args, **options) - return (filter, base_dn, scope) - -+ def post_callback(self, ldap, entries, truncated, *args, **options): -+ for entry_attrs in entries: -+ self.obj._make_zonename_absolute(entry_attrs, **options) -+ return truncated -+ - - class DNSZoneBase_show(LDAPRetrieve): - has_output_params = LDAPRetrieve.has_output_params + dnszone_output_params -@@ -1939,6 +1961,11 @@ class DNSZoneBase_show(LDAPRetrieve): - self.obj.handle_not_found(*keys) - return dn - -+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -+ assert isinstance(dn, DN) -+ self.obj._make_zonename_absolute(entry_attrs, **options) -+ return dn -+ - - class DNSZoneBase_disable(LDAPQuery): - has_output = output.standard_value -@@ -2539,7 +2566,8 @@ class dnszone_mod(DNSZoneBase_mod): - return result - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -- assert isinstance(dn, DN) -+ dn = super(dnszone_mod, self).post_callback(ldap, dn, entry_attrs, -+ *keys, **options) - self.obj._rr_zone_postprocess(entry_attrs, **options) - return dn - -@@ -2576,6 +2604,9 @@ class dnszone_find(DNSZoneBase_find): - return (filter, base_dn, scope) - - def post_callback(self, ldap, entries, truncated, *args, **options): -+ truncated = super(dnszone_find, self).post_callback(ldap, entries, -+ truncated, *args, -+ **options) - for entry_attrs in entries: - self.obj._rr_zone_postprocess(entry_attrs, **options) - return truncated -@@ -2592,7 +2623,8 @@ class dnszone_show(DNSZoneBase_show): - return result - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -- assert isinstance(dn, DN) -+ dn = super(dnszone_show, self).post_callback(ldap, dn, entry_attrs, -+ *keys, **options) - self.obj._rr_zone_postprocess(entry_attrs, **options) - return dn - --- -2.1.0 - diff --git a/SOURCES/0113-DNSSEC-Wrap-master-key-using-RSA-OAEP-instead-of-old.patch b/SOURCES/0113-DNSSEC-Wrap-master-key-using-RSA-OAEP-instead-of-old.patch new file mode 100644 index 0000000..abc1a74 --- /dev/null +++ b/SOURCES/0113-DNSSEC-Wrap-master-key-using-RSA-OAEP-instead-of-old.patch @@ -0,0 +1,40 @@ +From 7bcdc22d4e08739837039027f7c939a7469b8110 Mon Sep 17 00:00:00 2001 +From: Petr Spacek +Date: Tue, 1 Sep 2015 18:16:06 +0200 +Subject: [PATCH] DNSSEC: Wrap master key using RSA OAEP instead of old PKCS + v1.5. + +https://fedorahosted.org/freeipa/ticket/5273 + +Reviewed-By: Martin Basti +--- + daemons/dnssec/ipa-ods-exporter | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/daemons/dnssec/ipa-ods-exporter b/daemons/dnssec/ipa-ods-exporter +index e0c88936d5983297483c504d422c8d1ee483b6cf..f30a2253a713d857aa4e7566e52a0a45f7bd50c2 100755 +--- a/daemons/dnssec/ipa-ods-exporter ++++ b/daemons/dnssec/ipa-ods-exporter +@@ -53,8 +53,7 @@ KEYTAB_FB = paths.IPA_ODS_EXPORTER_KEYTAB + ODS_SE_MAXLINE = 1024 # from ODS common/config.h + ODS_DB_LOCK_PATH = "%s%s" % (paths.OPENDNSSEC_KASP_DB, '.our_lock') + +-# TODO: MECH_RSA_OAEP +-SECRETKEY_WRAPPING_MECH = 'rsaPkcs' ++SECRETKEY_WRAPPING_MECH = 'rsaPkcsOaep' + PRIVKEY_WRAPPING_MECH = 'aesKeyWrapPad' + + # DNSKEY flag constants +@@ -294,7 +293,8 @@ def master2ldap_master_keys_sync(log, ldapkeydb, localhsm): + hexlify(mkey_id), hexlify(replica_key_id))) + replica_key = localhsm.replica_pubkeys_wrap[replica_key_id] + keydata = localhsm.p11.export_wrapped_key(mkey_local.handle, +- replica_key.handle, _ipap11helper.MECH_RSA_PKCS) ++ replica_key.handle, ++ wrappingmech_name2id[SECRETKEY_WRAPPING_MECH]) + mkey_ldap.add_wrapped_data(keydata, SECRETKEY_WRAPPING_MECH, + replica_key_id) + +-- +2.5.1 + diff --git a/SOURCES/0114-ipa-kdb-reject-principals-from-disabled-domains-as-a.patch b/SOURCES/0114-ipa-kdb-reject-principals-from-disabled-domains-as-a.patch deleted file mode 100644 index 9ffb3ce..0000000 --- a/SOURCES/0114-ipa-kdb-reject-principals-from-disabled-domains-as-a.patch +++ /dev/null @@ -1,30 +0,0 @@ -From b46e3a309e8aa9a629037afb6ca7972d98e943e9 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 10 Dec 2014 14:59:38 +0200 -Subject: [PATCH] ipa-kdb: reject principals from disabled domains as a KDC - policy - -Fixes https://fedorahosted.org/freeipa/ticket/4788 - -Reviewed-By: Sumit Bose -Reviewed-By: Simo Sorce ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index a4500070760e83994c8155a12ee6414b5ebee9e0..e3215db4ea11632dce8f039fc6b89c4a09acd87a 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -1375,7 +1375,7 @@ static krb5_error_code filter_logon_info(krb5_context context, - &domain->parent->sid_blacklist_incoming[k], true); - if (result) { - filter_logon_info_log_message(info->info->info3.base.domain_sid); -- return EINVAL; -+ return KRB5KDC_ERR_POLICY; - } - } - } --- -2.1.0 - diff --git a/SOURCES/0114-ldap-Make-ldap2-connection-management-thread-safe-ag.patch b/SOURCES/0114-ldap-Make-ldap2-connection-management-thread-safe-ag.patch new file mode 100644 index 0000000..0c98cc6 --- /dev/null +++ b/SOURCES/0114-ldap-Make-ldap2-connection-management-thread-safe-ag.patch @@ -0,0 +1,177 @@ +From 96cadaec3c16b296627991ed517d7015fbe2882f Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 2 Sep 2015 14:04:17 +0200 +Subject: [PATCH] ldap: Make ldap2 connection management thread-safe again + +This fixes the connection code in LDAPClient to not store the LDAP connection +in an attribute of the object, which in combination with ldap2's per-thread +connections lead to race conditions resulting in connection failures. ldap2 +code was updated accordingly. + +https://fedorahosted.org/freeipa/ticket/5268 + +Reviewed-By: Tomas Babej +--- + ipapython/ipaldap.py | 32 +++++++++----------------------- + ipaserver/plugins/ldap2.py | 29 +++++++++++++---------------- + 2 files changed, 22 insertions(+), 39 deletions(-) + +diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py +index ef7c41a37c1f46290afbb11f912d7a4b8ea224c9..4443db03bcee25033abf63786016a7931f7eed20 100644 +--- a/ipapython/ipaldap.py ++++ b/ipapython/ipaldap.py +@@ -710,11 +710,10 @@ class LDAPClient(object): + self._decode_attrs = decode_attrs + + self.log = log_mgr.get_logger(self) +- self._conn = None + self._has_schema = False + self._schema = None + +- self._connect() ++ self._conn = self._connect() + + @property + def conn(self): +@@ -1023,29 +1022,16 @@ class LDAPClient(object): + """ + Close the connection. + """ +- if self._conn is not None: +- self._disconnect() ++ self._conn = None + + def _connect(self): +- if self._conn is not None: +- raise errors.DatabaseError( +- desc="Can't connect to server", info="Already connected") +- + with self.error_handler(): +- # bypass ldap2's locking +- object.__setattr__(self, '_conn', +- ldap.initialize(self.ldap_uri)) ++ conn = ldap.initialize(self.ldap_uri) + + if self._start_tls: +- self._conn.start_tls_s() +- +- def _disconnect(self): +- if self._conn is None: +- raise errors.DatabaseError( +- desc="Can't disconnect from server", info="Not connected") ++ conn.start_tls_s() + +- # bypass ldap2's locking +- object.__setattr__(self, '_conn', None) ++ return conn + + def simple_bind(self, bind_dn, bind_password, server_controls=None, + client_controls=None): +@@ -1059,7 +1045,7 @@ class LDAPClient(object): + assert isinstance(bind_dn, DN) + bind_dn = str(bind_dn) + bind_password = self.encode(bind_password) +- self._conn.simple_bind_s( ++ self.conn.simple_bind_s( + bind_dn, bind_password, server_controls, client_controls) + + def external_bind(self, user_name, server_controls=None, +@@ -1070,7 +1056,7 @@ class LDAPClient(object): + with self.error_handler(): + auth_tokens = ldap.sasl.external(user_name) + self._flush_schema() +- self._conn.sasl_interactive_bind_s( ++ self.conn.sasl_interactive_bind_s( + '', auth_tokens, server_controls, client_controls) + + def gssapi_bind(self, server_controls=None, client_controls=None): +@@ -1080,7 +1066,7 @@ class LDAPClient(object): + with self.error_handler(): + auth_tokens = ldap.sasl.sasl({}, 'GSSAPI') + self._flush_schema() +- self._conn.sasl_interactive_bind_s( ++ self.conn.sasl_interactive_bind_s( + '', auth_tokens, server_controls, client_controls) + + def unbind(self): +@@ -1089,7 +1075,7 @@ class LDAPClient(object): + """ + with self.error_handler(): + self._flush_schema() +- self._conn.unbind_s() ++ self.conn.unbind_s() + + def make_dn_from_attr(self, attr, value, parent_dn=None): + """ +diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py +index 68feee4f09eb12e50867dfbe3c482a359838aa82..deb0592ab68ab8eb712a6d29fdffd8776e2e289a 100644 +--- a/ipaserver/plugins/ldap2.py ++++ b/ipaserver/plugins/ldap2.py +@@ -76,10 +76,7 @@ class ldap2(CrudBackend, LDAPClient): + # do not set it + pass + +- def _disconnect(self): +- pass +- +- def __del__(self): ++ def close(self): + if self.isconnected(): + self.disconnect() + +@@ -118,10 +115,11 @@ class ldap2(CrudBackend, LDAPClient): + if debug_level: + _ldap.set_option(_ldap.OPT_DEBUG_LEVEL, debug_level) + +- LDAPClient._connect(self) +- conn = self._conn ++ client = LDAPClient(self.ldap_uri, ++ force_schema_updates=self._force_schema_updates) ++ conn = client._conn + +- with self.error_handler(): ++ with client.error_handler(): + if self.ldap_uri.startswith('ldapi://') and ccache: + conn.set_option(_ldap.OPT_HOST_NAME, self.api.env.host) + minssf = conn.get_option(_ldap.OPT_X_SASL_SSF_MIN) +@@ -147,29 +145,28 @@ class ldap2(CrudBackend, LDAPClient): + context=krbV.default_context()).principal().name + + os.environ['KRB5CCNAME'] = ccache +- self.gssapi_bind(server_controls=serverctrls, +- client_controls=clientctrls) ++ client.gssapi_bind(server_controls=serverctrls, ++ client_controls=clientctrls) + setattr(context, 'principal', principal) + else: + # no kerberos ccache, use simple bind or external sasl + if autobind: + pent = pwd.getpwuid(os.geteuid()) +- self.external_bind(pent.pw_name, ++ client.external_bind(pent.pw_name, ++ server_controls=serverctrls, ++ client_controls=clientctrls) ++ else: ++ client.simple_bind(bind_dn, bind_pw, + server_controls=serverctrls, + client_controls=clientctrls) +- else: +- self.simple_bind(bind_dn, bind_pw, +- server_controls=serverctrls, +- client_controls=clientctrls) + + return conn + + def destroy_connection(self): + """Disconnect from LDAP server.""" + try: +- if self._conn is not None: ++ if self.conn is not None: + self.unbind() +- LDAPClient._disconnect(self) + except errors.PublicError: + # ignore when trying to unbind multiple times + pass +-- +2.5.1 + diff --git a/SOURCES/0115-Using-LDAPI-to-setup-CA-and-KRA-agents.patch b/SOURCES/0115-Using-LDAPI-to-setup-CA-and-KRA-agents.patch new file mode 100644 index 0000000..8dc5c60 --- /dev/null +++ b/SOURCES/0115-Using-LDAPI-to-setup-CA-and-KRA-agents.patch @@ -0,0 +1,271 @@ +From 0ceb0c7b9730314cb8dfff7d2af9ef811a96aa13 Mon Sep 17 00:00:00 2001 +From: "Endi S. Dewata" +Date: Thu, 27 Aug 2015 06:44:29 +0200 +Subject: [PATCH] Using LDAPI to setup CA and KRA agents. + +The CA and KRA installation code has been modified to use LDAPI +to create the CA and KRA agents directly in the CA and KRA +database. This way it's no longer necessary to use the Directory +Manager password or CA and KRA admin certificate. + +https://fedorahosted.org/freeipa/ticket/5257 + +Reviewed-By: Martin Basti +--- + ipaplatform/base/paths.py | 2 - + ipaserver/install/cainstance.py | 49 ++++++++++------- + ipaserver/install/krainstance.py | 113 +++++++++++++++------------------------ + 3 files changed, 72 insertions(+), 92 deletions(-) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index a407c1273f01b3465bcb1985dd41f2f242346a62..ff75e0d7a5a0250ce71e67b0302bbaab64c5e935 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -344,8 +344,6 @@ class BasePathNamespace(object): + SLAPD_INSTANCE_SOCKET_TEMPLATE = "/var/run/slapd-%s.socket" + ALL_SLAPD_INSTANCE_SOCKETS = "/var/run/slapd-*.socket" + ADMIN_CERT_PATH = '/root/.dogtag/pki-tomcat/ca_admin.cert' +- KRA_NSSDB_PASSWORD_FILE = "/root/.dogtag/pki-tomcat/kra/password.conf" +- KRA_PKCS12_PASSWORD_FILE = "/root/.dogtag/pki-tomcat/kra/pkcs12_password.conf" + ENTROPY_AVAIL = '/proc/sys/kernel/random/entropy_avail' + LDIF2DB = '/usr/sbin/ldif2db' + DB2LDIF = '/usr/sbin/db2ldif' +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index ecd9300036353426097d929918be974cbbb5c69d..a4504a35a42b8c8ea2a96738c82c546ebebf569f 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -464,7 +464,7 @@ class CAInstance(DogtagInstance): + self.step("restarting certificate server", self.restart_instance) + self.step("requesting RA certificate from CA", self.__request_ra_certificate) + self.step("issuing RA agent certificate", self.__issue_ra_cert) +- self.step("adding RA agent as a trusted user", self.__configure_ra) ++ self.step("adding RA agent as a trusted user", self.__create_ca_agent) + self.step("authorizing RA to modify profiles", self.__configure_profiles_acl) + self.step("configure certmonger for renewals", self.configure_certmonger_renewal) + self.step("configure certificate renewals", self.configure_renewal) +@@ -903,18 +903,26 @@ class CAInstance(DogtagInstance): + + self.configure_agent_renewal() + +- def __configure_ra(self): +- # Create an RA user in the CA LDAP server and add that user to +- # the appropriate groups so it can issue certificates without +- # manual intervention. +- conn = ipaldap.IPAdmin(self.fqdn, self.ds_port) +- conn.do_simple_bind(DN(('cn', 'Directory Manager')), self.dm_password) ++ def __create_ca_agent(self): ++ """ ++ Create CA agent, assign a certificate, and add the user to ++ the appropriate groups for accessing CA services. ++ """ + +- decoded = base64.b64decode(self.ra_cert) ++ # get ipaCert certificate ++ cert_data = base64.b64decode(self.ra_cert) ++ cert = x509.load_certificate(cert_data, x509.DER) + +- entry_dn = DN(('uid', "ipara"), ('ou', 'People'), self.basedn) ++ # connect to CA database ++ server_id = installutils.realm_to_serverid(api.env.realm) ++ dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id ++ conn = ldap2.ldap2(api, ldap_uri=dogtag_uri) ++ conn.connect(autobind=True) ++ ++ # create ipara user with ipaCert certificate ++ user_dn = DN(('uid', "ipara"), ('ou', 'People'), self.basedn) + entry = conn.make_entry( +- entry_dn, ++ user_dn, + objectClass=['top', 'person', 'organizationalPerson', + 'inetOrgPerson', 'cmsuser'], + uid=["ipara"], +@@ -922,23 +930,24 @@ class CAInstance(DogtagInstance): + cn=["ipara"], + usertype=["agentType"], + userstate=["1"], +- userCertificate=[decoded], ++ userCertificate=[cert_data], + description=['2;%s;%s;%s' % ( +- str(self.requestId), ++ cert.serial_number, + DN(('CN', 'Certificate Authority'), self.subject_base), + DN(('CN', 'IPA RA'), self.subject_base))]) +- + conn.add_entry(entry) + +- dn = DN(('cn', 'Certificate Manager Agents'), ('ou', 'groups'), self.basedn) +- modlist = [(0, 'uniqueMember', '%s' % entry_dn)] +- conn.modify_s(dn, modlist) ++ # add ipara user to Certificate Manager Agents group ++ group_dn = DN(('cn', 'Certificate Manager Agents'), ('ou', 'groups'), ++ self.basedn) ++ conn.add_entry_to_group(user_dn, group_dn, 'uniqueMember') + +- dn = DN(('cn', 'Registration Manager Agents'), ('ou', 'groups'), self.basedn) +- modlist = [(0, 'uniqueMember', '%s' % entry_dn)] +- conn.modify_s(dn, modlist) ++ # add ipara user to Registration Manager Agents group ++ group_dn = DN(('cn', 'Registration Manager Agents'), ('ou', 'groups'), ++ self.basedn) ++ conn.add_entry_to_group(user_dn, group_dn, 'uniqueMember') + +- conn.unbind() ++ conn.disconnect() + + def __configure_profiles_acl(self): + """Allow the Certificate Manager Agents group to modify profiles.""" +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index e5cdbf5e7714603041e3f0156e87311994175b18..958fe6fb095e69f83342ce8299d1586b8bbacd47 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -25,17 +25,21 @@ import sys + import tempfile + + from ipalib import api ++from ipalib import x509 + from ipaplatform import services + from ipaplatform.paths import paths ++from ipapython import certdb + from ipapython import dogtag + from ipapython import ipautil + from ipapython.dn import DN + from ipaserver.install import certs + from ipaserver.install import cainstance ++from ipaserver.install import installutils + from ipaserver.install import ldapupdate + from ipaserver.install import service + from ipaserver.install.dogtaginstance import DogtagInstance + from ipaserver.install.dogtaginstance import DEFAULT_DSPORT, PKI_USER ++from ipaserver.plugins import ldap2 + from ipapython.ipa_log_manager import log_mgr + + # When IPA is installed with DNS support, this CNAME should hold all IPA +@@ -111,8 +115,8 @@ class KRAInstance(DogtagInstance): + + self.step("configuring KRA instance", self.__spawn_instance) + if not self.clone: +- self.step("add RA user to KRA agent group", +- self.__add_ra_user_to_agent_group) ++ self.step("create KRA agent", ++ self.__create_kra_agent) + self.step("restarting KRA", self.restart_instance) + self.step("configure certmonger for renewals", + self.configure_certmonger_renewal) +@@ -267,77 +271,46 @@ class KRAInstance(DogtagInstance): + + self.log.debug("completed creating KRA instance") + +- def __add_ra_user_to_agent_group(self): ++ def __create_kra_agent(self): + """ +- Add RA agent created for CA to KRA agent group. ++ Create KRA agent, assign a certificate, and add the user to ++ the appropriate groups for accessing KRA services. + """ + +- # import CA certificate into temporary security database +- args = ["/usr/bin/pki", +- "-d", self.agent_db, +- "-C", paths.KRA_NSSDB_PASSWORD_FILE, +- "client-cert-import", +- "--pkcs12", paths.KRACERT_P12, +- "--pkcs12-password-file", paths.KRA_PKCS12_PASSWORD_FILE] +- ipautil.run(args) +- +- # trust CA certificate +- args = ["/usr/bin/pki", +- "-d", self.agent_db, +- "-C", paths.KRA_NSSDB_PASSWORD_FILE, +- "client-cert-mod", "Certificate Authority - %s" % api.env.realm, +- "--trust", "CT,c,"] +- ipautil.run(args) +- +- # import Dogtag admin certificate into temporary security database +- args = ["/usr/bin/pki", +- "-d", self.agent_db, +- "-C", paths.KRA_NSSDB_PASSWORD_FILE, +- "client-cert-import", +- "--pkcs12", paths.DOGTAG_ADMIN_P12, +- "--pkcs12-password-file", paths.KRA_PKCS12_PASSWORD_FILE] +- ipautil.run(args) +- +- # as Dogtag admin, create ipakra user in KRA +- args = ["/usr/bin/pki", +- "-d", self.agent_db, +- "-C", paths.KRA_NSSDB_PASSWORD_FILE, +- "-n", "ipa-ca-agent", +- "kra-user-add", "ipakra", +- "--fullName", "IPA KRA User"] +- ipautil.run(args) +- +- # as Dogtag admin, add ipakra into KRA agents group +- args = ["/usr/bin/pki", +- "-d", self.agent_db, +- "-C", paths.KRA_NSSDB_PASSWORD_FILE, +- "-n", "ipa-ca-agent", +- "kra-user-membership-add", "ipakra", "Data Recovery Manager Agents"] +- ipautil.run(args) +- +- # assign ipaCert to ipakra +- (file, filename) = tempfile.mkstemp() +- os.close(file) +- try: +- # export ipaCert without private key +- args = ["/usr/bin/pki", +- "-d", paths.HTTPD_ALIAS_DIR, +- "-C", paths.ALIAS_PWDFILE_TXT, +- "client-cert-show", "ipaCert", +- "--cert", filename] +- ipautil.run(args) +- +- # as Dogtag admin, upload and assign ipaCert to ipakra +- args = ["/usr/bin/pki", +- "-d", self.agent_db, +- "-C", paths.KRA_NSSDB_PASSWORD_FILE, +- "-n", "ipa-ca-agent", +- "kra-user-cert-add", "ipakra", +- "--input", filename] +- ipautil.run(args) +- +- finally: +- os.remove(filename) ++ # get ipaCert certificate ++ with certdb.NSSDatabase(paths.HTTPD_ALIAS_DIR) as ipa_nssdb: ++ cert_data = ipa_nssdb.get_cert("ipaCert") ++ cert = x509.load_certificate(cert_data, x509.DER) ++ ++ # connect to KRA database ++ server_id = installutils.realm_to_serverid(api.env.realm) ++ dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id ++ conn = ldap2.ldap2(api, ldap_uri=dogtag_uri) ++ conn.connect(autobind=True) ++ ++ # create ipakra user with ipaCert certificate ++ user_dn = DN(('uid', "ipakra"), ('ou', 'people'), self.basedn) ++ entry = conn.make_entry( ++ user_dn, ++ objectClass=['top', 'person', 'organizationalPerson', ++ 'inetOrgPerson', 'cmsuser'], ++ uid=["ipakra"], ++ sn=["IPA KRA User"], ++ cn=["IPA KRA User"], ++ usertype=["undefined"], ++ userCertificate=[cert_data], ++ description=['2;%s;%s;%s' % ( ++ cert.serial_number, ++ DN(('CN', 'Certificate Authority'), self.subject_base), ++ DN(('CN', 'IPA RA'), self.subject_base))]) ++ conn.add_entry(entry) ++ ++ # add ipakra user to Data Recovery Manager Agents group ++ group_dn = DN(('cn', 'Data Recovery Manager Agents'), ('ou', 'groups'), ++ self.basedn) ++ conn.add_entry_to_group(user_dn, group_dn, 'uniqueMember') ++ ++ conn.disconnect() + + def __add_vault_container(self): + sub_dict = { +-- +2.5.1 + diff --git a/SOURCES/0115-ipalib-Make-sure-correct-attribute-name-is-reference.patch b/SOURCES/0115-ipalib-Make-sure-correct-attribute-name-is-reference.patch deleted file mode 100644 index 5a31c67..0000000 --- a/SOURCES/0115-ipalib-Make-sure-correct-attribute-name-is-reference.patch +++ /dev/null @@ -1,47 +0,0 @@ -From ce31d4124e20261cbd561f688110046945b082c1 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Thu, 19 Feb 2015 17:10:37 +0100 -Subject: [PATCH] ipalib: Make sure correct attribute name is referenced for - fax - -Fixes the invalid attribute name reference in the -'System: Read User Addressbook Attributes' permission. - -https://fedorahosted.org/freeipa/ticket/4883 - -Reviewed-By: Martin Kosek -Reviewed-By: Alexander Bokovoy ---- - ACI.txt | 2 +- - ipalib/plugins/user.py | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ACI.txt b/ACI.txt -index 67d583fabc295deb8aa5aab329bce5100c1b9088..fa1dcc4a8c9fd0c610dadcb2c368f700d26d4011 100644 ---- a/ACI.txt -+++ b/ACI.txt -@@ -255,7 +255,7 @@ aci: (targetattr = "businesscategory || carlicense || cn || description || displ - dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,dc=ipa,dc=example - aci: (targetattr = "*")(target = "ldap:///cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read UPG Definition";allow (compare,read,search) groupdn = "ldap:///cn=System: Read UPG Definition,cn=permissions,cn=pbac,dc=ipa,dc=example";) - dn: cn=users,cn=accounts,dc=ipa,dc=example --aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber || destinationindicator || employeenumber || employeetype || fax || homephone || homepostaladdress || inetuserhttpurl || inetuserstatus || internationalisdnnumber || jpegphoto || l || labeleduri || mail || mobile || o || ou || pager || photo || physicaldeliveryofficename || postaladdress || postalcode || postofficebox || preferreddeliverymethod || preferredlanguage || registeredaddress || roomnumber || secretary || seealso || st || street || telephonenumber || teletexterminalidentifier || telexnumber || usercertificate || usersmimecertificate || x121address || x500uniqueidentifier")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Addressbook Attributes";allow (compare,read,search) userdn = "ldap:///all";) -+aci: (targetattr = "audio || businesscategory || carlicense || departmentnumber || destinationindicator || employeenumber || employeetype || facsimiletelephonenumber || homephone || homepostaladdress || inetuserhttpurl || inetuserstatus || internationalisdnnumber || jpegphoto || l || labeleduri || mail || mobile || o || ou || pager || photo || physicaldeliveryofficename || postaladdress || postalcode || postofficebox || preferreddeliverymethod || preferredlanguage || registeredaddress || roomnumber || secretary || seealso || st || street || telephonenumber || teletexterminalidentifier || telexnumber || usercertificate || usersmimecertificate || x121address || x500uniqueidentifier")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Read User Addressbook Attributes";allow (compare,read,search) userdn = "ldap:///all";) - dn: dc=ipa,dc=example - aci: (targetattr = "cn || createtimestamp || entryusn || gecos || gidnumber || homedirectory || loginshell || modifytimestamp || objectclass || uid || uidnumber")(target = "ldap:///cn=users,cn=compat,dc=ipa,dc=example")(version 3.0;acl "permission:System: Read User Compat Tree";allow (compare,read,search) userdn = "ldap:///anyone";) - dn: cn=users,cn=accounts,dc=ipa,dc=example -diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py -index 56585b9f86593c0c5879139103bc71707b88e15f..abe5ee26b8e48681eeb0cbb3bcff8617e212225c 100644 ---- a/ipalib/plugins/user.py -+++ b/ipalib/plugins/user.py -@@ -276,7 +276,7 @@ class user(LDAPObject): - 'ipapermright': {'read', 'search', 'compare'}, - 'ipapermdefaultattr': { - 'seealso', 'telephonenumber', -- 'fax', 'l', 'ou', 'st', 'postalcode', 'street', -+ 'facsimiletelephonenumber', 'l', 'ou', 'st', 'postalcode', 'street', - 'destinationindicator', 'internationalisdnnumber', - 'physicaldeliveryofficename', 'postaladdress', 'postofficebox', - 'preferreddeliverymethod', 'registeredaddress', --- -2.1.0 - diff --git a/SOURCES/0116-Restore-default.conf-and-use-it-to-build-API.patch b/SOURCES/0116-Restore-default.conf-and-use-it-to-build-API.patch deleted file mode 100644 index 59ba9e7..0000000 --- a/SOURCES/0116-Restore-default.conf-and-use-it-to-build-API.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 0dfae3e9f16d91116a6769e25bbbee0ef1e485d2 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 4 Mar 2015 10:06:47 -0500 -Subject: [PATCH] Restore default.conf and use it to build API. - -When restoring ipa after uninstallation we need to extract and load -configuration of the restored environment. - -https://fedorahosted.org/freeipa/ticket/4896 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/ipa_restore.py | 64 ++++++++++++++++++++++++++++++---------- - 1 file changed, 48 insertions(+), 16 deletions(-) - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index efe3b9b1c0c10775b3a72b9d843924263526209a..a5ecd5f62bc85918fe697d98109bd3a82120f355 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -27,7 +27,7 @@ from ConfigParser import SafeConfigParser - import ldif - import itertools - --from ipalib import api, errors -+from ipalib import api, errors, constants - from ipapython import version, ipautil, certdb, dogtag - from ipapython.ipautil import run, user_input - from ipapython import admintool -@@ -203,15 +203,12 @@ class Restore(admintool.AdminTool): - options = self.options - super(Restore, self).run() - -- api.bootstrap(in_server=False, context='restore') -- api.finalize() -- - self.backup_dir = self.args[0] - if not os.path.isabs(self.backup_dir): - self.backup_dir = os.path.join(BACKUP_DIR, self.backup_dir) - - self.log.info("Preparing restore from %s on %s", -- self.backup_dir, api.env.host) -+ self.backup_dir, constants.FQDN) - - self.header = os.path.join(self.backup_dir, 'header') - -@@ -225,9 +222,6 @@ class Restore(admintool.AdminTool): - else: - restore_type = self.backup_type - -- instances = [realm_to_serverid(api.env.realm), 'PKI-IPA'] -- backends = ['userRoot', 'ipaca'] -- - # These checks would normally be in the validate method but - # we need to know the type of backup we're dealing with. - if restore_type == 'FULL': -@@ -241,6 +235,8 @@ class Restore(admintool.AdminTool): - else: - installutils.check_server_configuration() - -+ self.init_api() -+ - if options.instance: - instance_dir = (paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % - options.instance) -@@ -248,10 +244,10 @@ class Restore(admintool.AdminTool): - raise admintool.ScriptError( - "Instance %s does not exist" % options.instance) - -- instances = [options.instance] -+ self.instances = [options.instance] - - if options.backend: -- for instance in instances: -+ for instance in self.instances: - db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % - (instance, options.backend)) - if os.path.exists(db_dir): -@@ -260,9 +256,10 @@ class Restore(admintool.AdminTool): - raise admintool.ScriptError( - "Backend %s does not exist" % options.backend) - -- backends = [options.backend] -+ self.backends = [options.backend] - -- for instance, backend in itertools.product(instances, backends): -+ for instance, backend in itertools.product(self.instances, -+ self.backends): - db_dir = (paths.SLAPD_INSTANCE_DB_DIR_TEMPLATE % - (instance, backend)) - if os.path.exists(db_dir): -@@ -274,10 +271,10 @@ class Restore(admintool.AdminTool): - self.log.info("Performing %s restore from %s backup" % - (restore_type, self.backup_type)) - -- if self.backup_host != api.env.host: -+ if self.backup_host != constants.FQDN: - raise admintool.ScriptError( - "Host name %s does not match backup name %s" % -- (api.env.host, self.backup_host)) -+ (constants.FQDN, self.backup_host)) - - if self.backup_ipa_version != str(version.VERSION): - self.log.warning( -@@ -307,9 +304,13 @@ class Restore(admintool.AdminTool): - - self.extract_backup(options.gpg_keyring) - -+ if restore_type == 'FULL': -+ self.restore_default_conf() -+ self.init_api(confdir=self.dir + paths.ETC_IPA) -+ - databases = [] -- for instance in instances: -- for backend in backends: -+ for instance in self.instances: -+ for backend in self.backends: - database = (instance, backend) - ldiffile = os.path.join(self.dir, '%s-%s.ldif' % database) - if os.path.exists(ldiffile): -@@ -607,6 +608,30 @@ class Restore(admintool.AdminTool): - self.log.critical("bak2db failed: %s" % stderr) - - -+ def restore_default_conf(self): -+ ''' -+ Restore paths.IPA_DEFAULT_CONF to temporary directory. -+ -+ Primary purpose of this method is to get cofiguration for api -+ finalization when restoring ipa after uninstall. -+ ''' -+ cwd = os.getcwd() -+ os.chdir(self.dir) -+ args = ['tar', -+ '--xattrs', -+ '--selinux', -+ '-xzf', -+ os.path.join(self.dir, 'files.tar'), -+ paths.IPA_DEFAULT_CONF[1:], -+ ] -+ -+ (stdout, stderr, rc) = run(args, raiseonerr=False) -+ if rc != 0: -+ self.log.critical('Restoring %s failed: %s' % -+ (paths.IPA_DEFAULT_CONF, stderr)) -+ os.chdir(cwd) -+ -+ - def file_restore(self, nologs=False): - ''' - Restore all the files in the tarball. -@@ -803,3 +828,10 @@ class Restore(admintool.AdminTool): - tasks.reload_systemwide_ca_store() - - services.knownservices.certmonger.restart() -+ -+ def init_api(self, **overrides): -+ api.bootstrap(in_server=False, context='restore', **overrides) -+ api.finalize() -+ -+ self.instances = [realm_to_serverid(api.env.realm), 'PKI-IPA'] -+ self.backends = ['userRoot', 'ipaca'] --- -2.1.0 - diff --git a/SOURCES/0116-load-RA-backend-plugins-during-standalone-CA-install.patch b/SOURCES/0116-load-RA-backend-plugins-during-standalone-CA-install.patch new file mode 100644 index 0000000..d4d8af4 --- /dev/null +++ b/SOURCES/0116-load-RA-backend-plugins-during-standalone-CA-install.patch @@ -0,0 +1,35 @@ +From c26fec494cc348282d037efb88927f70df17f584 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 4 Sep 2015 15:14:48 +0200 +Subject: [PATCH] load RA backend plugins during standalone CA install on + CA-less IPA master + +CA-less IPA master has 'ra_plugin' set to 'none' in IPA config. When setting +up Dogtag CA on the master we must override this setting in order to load +dogtag backend plugins and succesfully complete CA installation. + +https://fedorahosted.org/freeipa/ticket/5288 + +Reviewed-By: Jan Cholasta +--- + install/tools/ipa-ca-install | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install +index 8b1cea8d557f315ae38c2448e816ca0b2557077f..6564e4d0304d4e189b133c495b75f200b04e2988 100755 +--- a/install/tools/ipa-ca-install ++++ b/install/tools/ipa-ca-install +@@ -160,7 +160,9 @@ def install_master(safe_options, options): + if not dsinstance.DsInstance().is_configured(): + sys.exit("IPA server is not configured on this system.\n") + +- api.bootstrap(in_server=True) ++ # override ra_plugin setting read from default.conf so that we have ++ # functional dogtag backend plugins during CA install ++ api.bootstrap(in_server=True, ra_plugin='dogtag') + api.finalize() + + dm_password = options.password +-- +2.5.1 + diff --git a/SOURCES/0117-Handle-timeout-error-in-ipa-httpd-kdcproxy.patch b/SOURCES/0117-Handle-timeout-error-in-ipa-httpd-kdcproxy.patch new file mode 100644 index 0000000..389ac69 --- /dev/null +++ b/SOURCES/0117-Handle-timeout-error-in-ipa-httpd-kdcproxy.patch @@ -0,0 +1,39 @@ +From 6b5411bd9bf98bd7c4bb695b37c2e878f4b0f1ef Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 10 Sep 2015 11:54:32 +0200 +Subject: [PATCH] Handle timeout error in ipa-httpd-kdcproxy + +The ipa-httpd-kdcproxy script now handles LDAP timeout errors correctly. +A timeout does no longer result into an Apache startup error. + +https://fedorahosted.org/freeipa/ticket/5292 + +Reviewed-By: Martin Basti +--- + install/tools/ipa-httpd-kdcproxy | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/install/tools/ipa-httpd-kdcproxy b/install/tools/ipa-httpd-kdcproxy +index 60b22f2cc321d416871c74f3b4d580594c186a85..5e9863f8bd82e1628030b0b767a6697ab2a1d7bd 100755 +--- a/install/tools/ipa-httpd-kdcproxy ++++ b/install/tools/ipa-httpd-kdcproxy +@@ -24,6 +24,7 @@ This script creates or removes the symlink from /etc/ipa/ipa-kdc-proxy.conf + to /etc/httpd/conf.d/. It's called from ExecStartPre hook in httpd.service. + """ + import os ++import socket + import sys + + from ipalib import api, errors +@@ -81,7 +82,7 @@ class KDCProxyConfig(object): + # EXTERNAL bind as root user + self.con.ldapi = True + self.con.do_bind(timeout=self.time_limit) +- except errors.NetworkError as e: ++ except (errors.NetworkError, socket.timeout) as e: + msg = 'Unable to connect to dirsrv: %s' % e + raise CheckError(msg) + except errors.AuthorizationError as e: +-- +2.4.3 + diff --git a/SOURCES/0117-Limit-deadlocks-between-DS-plugin-DNA-and-slapi-nis.patch b/SOURCES/0117-Limit-deadlocks-between-DS-plugin-DNA-and-slapi-nis.patch deleted file mode 100644 index 2f75ad2..0000000 --- a/SOURCES/0117-Limit-deadlocks-between-DS-plugin-DNA-and-slapi-nis.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 7a98d658d662f0cec33ba6207474d8271029b4bd Mon Sep 17 00:00:00 2001 -From: root -Date: Wed, 4 Mar 2015 11:11:45 +0100 -Subject: [PATCH] Limit deadlocks between DS plugin DNA and slapi-nis - - Deadlock can occur if DNA plugin (shared) config and Schema-compat plugin config - are updated at the same time. - Schema-compat should ignore update on DNA config. - - https://fedorahosted.org/freeipa/ticket/4927 - -Reviewed-By: Jan Cholasta ---- - install/updates/10-schema_compat.update | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/install/updates/10-schema_compat.update b/install/updates/10-schema_compat.update -index b8c79012d121116f9cf53908fbe4eeeebe9d3d82..4484bdcce15736eeaffcc99edc694094b16fd0ed 100644 ---- a/install/updates/10-schema_compat.update -+++ b/install/updates/10-schema_compat.update -@@ -22,6 +22,7 @@ remove: schema-compat-ignore-subtree: cn=changelog - remove: schema-compat-ignore-subtree: o=ipaca - add: schema-compat-restrict-subtree: '$SUFFIX' - add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' -+add: schema-compat-ignore-subtree: 'cn=dna,cn=ipa,cn=etc,$SUFFIX' - - # Change padding for host and userCategory so the pad returns the same value - # as the original, '' or -. -@@ -31,6 +32,7 @@ remove: schema-compat-ignore-subtree: cn=changelog - remove: schema-compat-ignore-subtree: o=ipaca - add: schema-compat-restrict-subtree: '$SUFFIX' - add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' -+add: schema-compat-ignore-subtree: 'cn=dna,cn=ipa,cn=etc,$SUFFIX' - - dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config - default:objectClass: top -@@ -49,6 +51,7 @@ remove: schema-compat-ignore-subtree: cn=changelog - remove: schema-compat-ignore-subtree: o=ipaca - add: schema-compat-restrict-subtree: '$SUFFIX' - add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' -+add: schema-compat-ignore-subtree: 'cn=dna,cn=ipa,cn=etc,$SUFFIX' - - dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config - add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} -@@ -58,12 +61,14 @@ remove: schema-compat-ignore-subtree: cn=changelog - remove: schema-compat-ignore-subtree: o=ipaca - add: schema-compat-restrict-subtree: '$SUFFIX' - add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' -+add: schema-compat-ignore-subtree: 'cn=dna,cn=ipa,cn=etc,$SUFFIX' - - dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config - remove: schema-compat-ignore-subtree: cn=changelog - remove: schema-compat-ignore-subtree: o=ipaca - add: schema-compat-restrict-subtree: '$SUFFIX' - add: schema-compat-restrict-subtree: 'cn=Schema Compatibility,cn=plugins,cn=config' -+add: schema-compat-ignore-subtree: 'cn=dna,cn=ipa,cn=etc,$SUFFIX' - - dn: cn=Schema Compatibility,cn=plugins,cn=config - # We need to run schema-compat pre-bind callback before --- -2.1.0 - diff --git a/SOURCES/0118-Add-configure-check-for-cwrap-libraries.patch b/SOURCES/0118-Add-configure-check-for-cwrap-libraries.patch deleted file mode 100644 index 6dfaf34..0000000 --- a/SOURCES/0118-Add-configure-check-for-cwrap-libraries.patch +++ /dev/null @@ -1,53 +0,0 @@ -From d6ea80f9c0a5b7d6bd44e32297af3718c1e782ff Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 24 Feb 2015 15:29:00 +0100 -Subject: [PATCH] Add configure check for cwrap libraries - -Currently only nss-wrapper is checked, checks for other crwap libraries -can be added e.g. as - -AM_CHECK_WRAPPER(uid_wrapper, HAVE_UID_WRAPPER) - -Reviewed-By: Alexander Bokovoy ---- - daemons/configure.ac | 24 ++++++++++++++++++++++++ - 1 file changed, 24 insertions(+) - -diff --git a/daemons/configure.ac b/daemons/configure.ac -index e81aa60e381e035aff73bf27475fc0f101a5fbf9..932a8f7fd5230c90071cf26cc83f6aee5173457d 100644 ---- a/daemons/configure.ac -+++ b/daemons/configure.ac -@@ -224,6 +224,30 @@ PKG_CHECK_EXISTS(cmocka, - ) - AM_CONDITIONAL([HAVE_CMOCKA], [test x$have_cmocka = xyes]) - -+dnl A macro to check presence of a cwrap (http://cwrap.org) wrapper on the system -+dnl Usage: -+dnl AM_CHECK_WRAPPER(name, conditional) -+dnl If the cwrap library is found, sets the HAVE_$name conditional -+AC_DEFUN([AM_CHECK_WRAPPER], -+[ -+ FOUND_WRAPPER=0 -+ -+ AC_MSG_CHECKING([for $1]) -+ PKG_CHECK_EXISTS([$1], -+ [ -+ AC_MSG_RESULT([yes]) -+ FOUND_WRAPPER=1 -+ ], -+ [ -+ AC_MSG_RESULT([no]) -+ AC_MSG_WARN([cwrap library $1 not found, some tests will not run]) -+ ]) -+ -+ AM_CONDITIONAL($2, [ test x$FOUND_WRAPPER = x1]) -+]) -+ -+AM_CHECK_WRAPPER(nss_wrapper, HAVE_NSS_WRAPPER) -+ - dnl -- dirsrv is needed for the extdom unit tests -- - PKG_CHECK_MODULES([DIRSRV], [dirsrv >= 1.3.0]) - dnl -- sss_idmap is needed by the extdom exop -- --- -2.1.0 - diff --git a/SOURCES/0118-Server-Upgrade-backup-CS.cfg-when-dogtag-is-turned-o.patch b/SOURCES/0118-Server-Upgrade-backup-CS.cfg-when-dogtag-is-turned-o.patch new file mode 100644 index 0000000..2edc965 --- /dev/null +++ b/SOURCES/0118-Server-Upgrade-backup-CS.cfg-when-dogtag-is-turned-o.patch @@ -0,0 +1,36 @@ +From 908019639e5e0975d3cd73c3c851319224737dcd Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 10 Sep 2015 18:46:00 +0200 +Subject: [PATCH] Server Upgrade: backup CS.cfg when dogtag is turned off + +Is unable to made CS.cfg when dogtag is running. + +https://fedorahosted.org/freeipa/ticket/5287 + +Reviewed-By: David Kupka +--- + ipaserver/install/server/upgrade.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index a57682a4bbdaab2a15b4e415223e2f5faa67ba73..5288f8fcc5fb56b13773e3bb8ea6a5a6c8c0e8a9 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1354,10 +1354,13 @@ def upgrade_configuration(): + sub_dict['SUBJECT_BASE'] = subject_base + + ca = cainstance.CAInstance(api.env.realm, certs.NSS_DIR) +- ca.backup_config() + + with installutils.stopped_service(configured_constants.SERVICE_NAME, + configured_constants.PKI_INSTANCE_NAME): ++ ++ # Dogtag must be stopped to be able to backup CS.cfg config ++ ca.backup_config() ++ + # migrate CRL publish dir before the location in ipa.conf is updated + ca_restart = migrate_crl_publish_dir(ca) + +-- +2.4.3 + diff --git a/SOURCES/0119-IPA-Restore-allows-to-specify-files-that-should-be-r.patch b/SOURCES/0119-IPA-Restore-allows-to-specify-files-that-should-be-r.patch new file mode 100644 index 0000000..27a4fda --- /dev/null +++ b/SOURCES/0119-IPA-Restore-allows-to-specify-files-that-should-be-r.patch @@ -0,0 +1,75 @@ +From 98e289720cbe58e2d921ee95d316644c1bb5cce8 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 10 Sep 2015 16:35:54 +0200 +Subject: [PATCH] IPA Restore: allows to specify files that should be removed + +Some files/directories should be removed before backup files are copied +to filesystem. + +In case of DNSSEC, the /var/lib/ipa/dnssec/tokens directory has to be +removed, otherwise tokens that are backed up and existing tokens will be +mixed and SOFTHSM log in will not work + +https://fedorahosted.org/freeipa/ticket/5293 + +Reviewed-By: David Kupka +--- + ipaserver/install/ipa_restore.py | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 8960626d0f0e438ef198e2d92803983e520051a8..dc57a4937365ad1db960955cf21e1bf2d2eb3dda 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -128,6 +128,14 @@ class Restore(admintool.AdminTool): + + description = "Restore IPA files and databases." + ++ # directories and files listed here will be removed from filesystem before ++ # files from backup are copied ++ DIRS_TO_BE_REMOVED = [ ++ paths.DNSSEC_TOKENS_DIR, ++ ] ++ ++ FILES_TO_BE_REMOVED = [] ++ + def __init__(self, options, args): + super(Restore, self).__init__(options, args) + self._conn = None +@@ -365,6 +373,7 @@ class Restore(admintool.AdminTool): + + # We do either a full file restore or we restore data. + if restore_type == 'FULL': ++ self.remove_old_files() + if 'CA' in self.backup_services: + create_ca_user() + self.cert_restore_prepare() +@@ -640,6 +649,25 @@ class Restore(admintool.AdminTool): + (paths.IPA_DEFAULT_CONF, stderr)) + os.chdir(cwd) + ++ def remove_old_files(self): ++ """ ++ Removes all directories, files or temporal files that should be ++ removed before backup files are copied, to prevent errors. ++ """ ++ for d in self.DIRS_TO_BE_REMOVED: ++ try: ++ shutil.rmtree(d) ++ except OSError as e: ++ if e.errno != 2: # 2: dir does not exist ++ self.log.warning("Could not remove directory: %s (%s)", ++ d, e) ++ ++ for f in self.FILES_TO_BE_REMOVED: ++ try: ++ os.remove(f) ++ except OSError as e: ++ if e.errno != 2: # 2: file does not exist ++ self.log.warning("Could not remove file: %s (%s)", f, e) + + def file_restore(self, nologs=False): + ''' +-- +2.4.3 + diff --git a/SOURCES/0119-extdom-handle-ERANGE-return-code-for-getXXYYY_r-call.patch b/SOURCES/0119-extdom-handle-ERANGE-return-code-for-getXXYYY_r-call.patch deleted file mode 100644 index 72bc2d4..0000000 --- a/SOURCES/0119-extdom-handle-ERANGE-return-code-for-getXXYYY_r-call.patch +++ /dev/null @@ -1,776 +0,0 @@ -From 14310dab1698da8afbc107c5c76a3c01c9aeb20e Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 24 Feb 2015 15:33:39 +0100 -Subject: [PATCH] extdom: handle ERANGE return code for getXXYYY_r() calls - -The getXXYYY_r() calls require a buffer to store the variable data of -the passwd and group structs. If the provided buffer is too small ERANGE -is returned and the caller can try with a larger buffer again. - -Cmocka/cwrap based unit-tests for get*_r_wrapper() are added. - -Resolves https://fedorahosted.org/freeipa/ticket/4908 - -Reviewed-By: Alexander Bokovoy ---- - .../ipa-slapi-plugins/ipa-extdom-extop/Makefile.am | 31 ++- - .../ipa-extdom-extop/ipa_extdom.h | 9 + - .../ipa-extdom-extop/ipa_extdom_cmocka_tests.c | 226 +++++++++++++++ - .../ipa-extdom-extop/ipa_extdom_common.c | 309 +++++++++++++++------ - .../ipa-extdom-extop/test_data/group | 2 + - .../ipa-extdom-extop/test_data/passwd | 2 + - .../ipa-extdom-extop/test_data/test_setup.sh | 3 + - 7 files changed, 498 insertions(+), 84 deletions(-) - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/group - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/passwd - create mode 100644 daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -index 0008476796f5b20f62f2c32e7b291b787fa7a6fc..a1679812ef3c5de8c6e18433cbb991a99ad0b6c8 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -@@ -35,9 +35,20 @@ libipa_extdom_extop_la_LIBADD = \ - $(SSSNSSIDMAP_LIBS) \ - $(NULL) - -+TESTS = -+check_PROGRAMS = -+ - if HAVE_CHECK --TESTS = extdom_tests --check_PROGRAMS = extdom_tests -+TESTS += extdom_tests -+check_PROGRAMS += extdom_tests -+endif -+ -+if HAVE_CMOCKA -+if HAVE_NSS_WRAPPER -+TESTS_ENVIRONMENT = . ./test_data/test_setup.sh; -+TESTS += extdom_cmocka_tests -+check_PROGRAMS += extdom_cmocka_tests -+endif - endif - - extdom_tests_SOURCES = \ -@@ -55,6 +66,22 @@ extdom_tests_LDADD = \ - $(SSSNSSIDMAP_LIBS) \ - $(NULL) - -+extdom_cmocka_tests_SOURCES = \ -+ ipa_extdom_cmocka_tests.c \ -+ ipa_extdom_common.c \ -+ $(NULL) -+extdom_cmocka_tests_CFLAGS = $(CMOCKA_CFLAGS) -+extdom_cmocka_tests_LDFLAGS = \ -+ -rpath $(shell pkg-config --libs-only-L dirsrv | sed -e 's/-L//') \ -+ $(NULL) -+extdom_cmocka_tests_LDADD = \ -+ $(CMOCKA_LIBS) \ -+ $(LDAP_LIBS) \ -+ $(DIRSRV_LIBS) \ -+ $(SSSNSSIDMAP_LIBS) \ -+ $(NULL) -+ -+ - appdir = $(IPA_DATA_DIR) - app_DATA = \ - ipa-extdom-extop-conf.ldif \ -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -index 56ca5009b1aa427f6c059b78ac392c768e461e2e..40bf933920fdd2ca19e5ef195aaa8fb820446cc5 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -@@ -174,4 +174,13 @@ int check_request(struct extdom_req *req, enum extdom_version version); - int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req, - struct berval **berval); - int pack_response(struct extdom_res *res, struct berval **ret_val); -+int get_buffer(size_t *_buf_len, char **_buf); -+int getpwnam_r_wrapper(size_t buf_max, const char *name, -+ struct passwd *pwd, char **_buf, size_t *_buf_len); -+int getpwuid_r_wrapper(size_t buf_max, uid_t uid, -+ struct passwd *pwd, char **_buf, size_t *_buf_len); -+int getgrnam_r_wrapper(size_t buf_max, const char *name, -+ struct group *grp, char **_buf, size_t *_buf_len); -+int getgrgid_r_wrapper(size_t buf_max, gid_t gid, -+ struct group *grp, char **_buf, size_t *_buf_len); - #endif /* _IPA_EXTDOM_H_ */ -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d5bacd7e8c9dc0a71eea70162406c7e5b67384ad ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -@@ -0,0 +1,226 @@ -+/* -+ Authors: -+ Sumit Bose -+ -+ Copyright (C) 2015 Red Hat -+ -+ Extdom tests -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 3 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program. If not, see . -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+ -+#include "ipa_extdom.h" -+ -+#define MAX_BUF (1024*1024*1024) -+ -+void test_getpwnam_r_wrapper(void **state) -+{ -+ int ret; -+ struct passwd pwd; -+ char *buf; -+ size_t buf_len; -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getpwnam_r_wrapper(MAX_BUF, "non_exisiting_user", &pwd, &buf, -+ &buf_len); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = getpwnam_r_wrapper(MAX_BUF, "user", &pwd, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(pwd.pw_name, "user"); -+ assert_string_equal(pwd.pw_passwd, "x"); -+ assert_int_equal(pwd.pw_uid, 12345); -+ assert_int_equal(pwd.pw_gid, 23456); -+ assert_string_equal(pwd.pw_gecos, "gecos"); -+ assert_string_equal(pwd.pw_dir, "/home/user"); -+ assert_string_equal(pwd.pw_shell, "/bin/shell"); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getpwnam_r_wrapper(MAX_BUF, "user_big", &pwd, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(pwd.pw_name, "user_big"); -+ assert_string_equal(pwd.pw_passwd, "x"); -+ assert_int_equal(pwd.pw_uid, 12346); -+ assert_int_equal(pwd.pw_gid, 23457); -+ assert_int_equal(strlen(pwd.pw_gecos), 4000 * strlen("gecos")); -+ assert_string_equal(pwd.pw_dir, "/home/user_big"); -+ assert_string_equal(pwd.pw_shell, "/bin/shell"); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getpwnam_r_wrapper(1024, "user_big", &pwd, &buf, &buf_len); -+ assert_int_equal(ret, ERANGE); -+ free(buf); -+} -+ -+void test_getpwuid_r_wrapper(void **state) -+{ -+ int ret; -+ struct passwd pwd; -+ char *buf; -+ size_t buf_len; -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getpwuid_r_wrapper(MAX_BUF, 99999, &pwd, &buf, &buf_len); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = getpwuid_r_wrapper(MAX_BUF, 12345, &pwd, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(pwd.pw_name, "user"); -+ assert_string_equal(pwd.pw_passwd, "x"); -+ assert_int_equal(pwd.pw_uid, 12345); -+ assert_int_equal(pwd.pw_gid, 23456); -+ assert_string_equal(pwd.pw_gecos, "gecos"); -+ assert_string_equal(pwd.pw_dir, "/home/user"); -+ assert_string_equal(pwd.pw_shell, "/bin/shell"); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getpwuid_r_wrapper(MAX_BUF, 12346, &pwd, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(pwd.pw_name, "user_big"); -+ assert_string_equal(pwd.pw_passwd, "x"); -+ assert_int_equal(pwd.pw_uid, 12346); -+ assert_int_equal(pwd.pw_gid, 23457); -+ assert_int_equal(strlen(pwd.pw_gecos), 4000 * strlen("gecos")); -+ assert_string_equal(pwd.pw_dir, "/home/user_big"); -+ assert_string_equal(pwd.pw_shell, "/bin/shell"); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getpwuid_r_wrapper(1024, 12346, &pwd, &buf, &buf_len); -+ assert_int_equal(ret, ERANGE); -+ free(buf); -+} -+ -+void test_getgrnam_r_wrapper(void **state) -+{ -+ int ret; -+ struct group grp; -+ char *buf; -+ size_t buf_len; -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getgrnam_r_wrapper(MAX_BUF, "non_exisiting_group", &grp, &buf, &buf_len); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = getgrnam_r_wrapper(MAX_BUF, "group", &grp, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(grp.gr_name, "group"); -+ assert_string_equal(grp.gr_passwd, "x"); -+ assert_int_equal(grp.gr_gid, 11111); -+ assert_string_equal(grp.gr_mem[0], "member0001"); -+ assert_string_equal(grp.gr_mem[1], "member0002"); -+ assert_null(grp.gr_mem[2]); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getgrnam_r_wrapper(MAX_BUF, "group_big", &grp, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(grp.gr_name, "group_big"); -+ assert_string_equal(grp.gr_passwd, "x"); -+ assert_int_equal(grp.gr_gid, 22222); -+ assert_string_equal(grp.gr_mem[0], "member0001"); -+ assert_string_equal(grp.gr_mem[1], "member0002"); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getgrnam_r_wrapper(1024, "group_big", &grp, &buf, &buf_len); -+ assert_int_equal(ret, ERANGE); -+ free(buf); -+} -+ -+void test_getgrgid_r_wrapper(void **state) -+{ -+ int ret; -+ struct group grp; -+ char *buf; -+ size_t buf_len; -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getgrgid_r_wrapper(MAX_BUF, 99999, &grp, &buf, &buf_len); -+ assert_int_equal(ret, ENOENT); -+ -+ ret = getgrgid_r_wrapper(MAX_BUF, 11111, &grp, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(grp.gr_name, "group"); -+ assert_string_equal(grp.gr_passwd, "x"); -+ assert_int_equal(grp.gr_gid, 11111); -+ assert_string_equal(grp.gr_mem[0], "member0001"); -+ assert_string_equal(grp.gr_mem[1], "member0002"); -+ assert_null(grp.gr_mem[2]); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getgrgid_r_wrapper(MAX_BUF, 22222, &grp, &buf, &buf_len); -+ assert_int_equal(ret, 0); -+ assert_string_equal(grp.gr_name, "group_big"); -+ assert_string_equal(grp.gr_passwd, "x"); -+ assert_int_equal(grp.gr_gid, 22222); -+ assert_string_equal(grp.gr_mem[0], "member0001"); -+ assert_string_equal(grp.gr_mem[1], "member0002"); -+ free(buf); -+ -+ ret = get_buffer(&buf_len, &buf); -+ assert_int_equal(ret, 0); -+ -+ ret = getgrgid_r_wrapper(1024, 22222, &grp, &buf, &buf_len); -+ assert_int_equal(ret, ERANGE); -+ free(buf); -+} -+ -+int main(int argc, const char *argv[]) -+{ -+ const UnitTest tests[] = { -+ unit_test(test_getpwnam_r_wrapper), -+ unit_test(test_getpwuid_r_wrapper), -+ unit_test(test_getgrnam_r_wrapper), -+ unit_test(test_getgrgid_r_wrapper), -+ }; -+ -+ return run_tests(tests); -+} -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -index 20fdd62b20f28f5384cf83b8be5819f721c6c3db..cbe336963ffbafadd5a7b8029a65fafe506f75e8 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -@@ -49,6 +49,188 @@ - - #define MAX(a,b) (((a)>(b))?(a):(b)) - #define SSSD_DOMAIN_SEPARATOR '@' -+#define MAX_BUF (1024*1024*1024) -+ -+ -+ -+int get_buffer(size_t *_buf_len, char **_buf) -+{ -+ long pw_max; -+ long gr_max; -+ size_t buf_len; -+ char *buf; -+ -+ pw_max = sysconf(_SC_GETPW_R_SIZE_MAX); -+ gr_max = sysconf(_SC_GETGR_R_SIZE_MAX); -+ -+ buf_len = MAX(16384, MAX(pw_max, gr_max)); -+ -+ buf = malloc(sizeof(char) * buf_len); -+ if (buf == NULL) { -+ return LDAP_OPERATIONS_ERROR; -+ } -+ -+ *_buf_len = buf_len; -+ *_buf = buf; -+ -+ return LDAP_SUCCESS; -+} -+ -+static int inc_buffer(size_t buf_max, size_t *_buf_len, char **_buf) -+{ -+ size_t tmp_len; -+ char *tmp_buf; -+ -+ tmp_buf = *_buf; -+ tmp_len = *_buf_len; -+ -+ tmp_len *= 2; -+ if (tmp_len > buf_max) { -+ return ERANGE; -+ } -+ -+ tmp_buf = realloc(tmp_buf, tmp_len); -+ if (tmp_buf == NULL) { -+ return ENOMEM; -+ } -+ -+ *_buf_len = tmp_len; -+ *_buf = tmp_buf; -+ -+ return 0; -+} -+ -+int getpwnam_r_wrapper(size_t buf_max, const char *name, -+ struct passwd *pwd, char **_buf, size_t *_buf_len) -+{ -+ char *buf = NULL; -+ size_t buf_len = 0; -+ int ret; -+ struct passwd *result = NULL; -+ -+ buf = *_buf; -+ buf_len = *_buf_len; -+ -+ while (buf != NULL -+ && (ret = getpwnam_r(name, pwd, buf, buf_len, &result)) == ERANGE) { -+ ret = inc_buffer(buf_max, &buf_len, &buf); -+ if (ret != 0) { -+ if (ret == ERANGE) { -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ } -+ goto done; -+ } -+ } -+ -+ if (ret == 0 && result == NULL) { -+ ret = ENOENT; -+ } -+ -+done: -+ *_buf = buf; -+ *_buf_len = buf_len; -+ -+ return ret; -+} -+ -+int getpwuid_r_wrapper(size_t buf_max, uid_t uid, -+ struct passwd *pwd, char **_buf, size_t *_buf_len) -+{ -+ char *buf = NULL; -+ size_t buf_len = 0; -+ int ret; -+ struct passwd *result = NULL; -+ -+ buf = *_buf; -+ buf_len = *_buf_len; -+ -+ while (buf != NULL -+ && (ret = getpwuid_r(uid, pwd, buf, buf_len, &result)) == ERANGE) { -+ ret = inc_buffer(buf_max, &buf_len, &buf); -+ if (ret != 0) { -+ if (ret == ERANGE) { -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ } -+ goto done; -+ } -+ } -+ -+ if (ret == 0 && result == NULL) { -+ ret = ENOENT; -+ } -+ -+done: -+ *_buf = buf; -+ *_buf_len = buf_len; -+ -+ return ret; -+} -+ -+int getgrnam_r_wrapper(size_t buf_max, const char *name, -+ struct group *grp, char **_buf, size_t *_buf_len) -+{ -+ char *buf = NULL; -+ size_t buf_len = 0; -+ int ret; -+ struct group *result = NULL; -+ -+ buf = *_buf; -+ buf_len = *_buf_len; -+ -+ while (buf != NULL -+ && (ret = getgrnam_r(name, grp, buf, buf_len, &result)) == ERANGE) { -+ ret = inc_buffer(buf_max, &buf_len, &buf); -+ if (ret != 0) { -+ if (ret == ERANGE) { -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ } -+ goto done; -+ } -+ } -+ -+ if (ret == 0 && result == NULL) { -+ ret = ENOENT; -+ } -+ -+done: -+ *_buf = buf; -+ *_buf_len = buf_len; -+ -+ return ret; -+} -+ -+int getgrgid_r_wrapper(size_t buf_max, gid_t gid, -+ struct group *grp, char **_buf, size_t *_buf_len) -+{ -+ char *buf = NULL; -+ size_t buf_len = 0; -+ int ret; -+ struct group *result = NULL; -+ -+ buf = *_buf; -+ buf_len = *_buf_len; -+ -+ while (buf != NULL -+ && (ret = getgrgid_r(gid, grp, buf, buf_len, &result)) == ERANGE) { -+ ret = inc_buffer(buf_max, &buf_len, &buf); -+ if (ret != 0) { -+ if (ret == ERANGE) { -+ LOG("Buffer too small, increase ipaExtdomMaxNssBufSize.\n"); -+ } -+ goto done; -+ } -+ } -+ -+ if (ret == 0 && result == NULL) { -+ ret = ENOENT; -+ } -+ -+done: -+ *_buf = buf; -+ *_buf_len = buf_len; -+ -+ return ret; -+} - - int parse_request_data(struct berval *req_val, struct extdom_req **_req) - { -@@ -191,33 +373,6 @@ int check_request(struct extdom_req *req, enum extdom_version version) - return LDAP_SUCCESS; - } - --static int get_buffer(size_t *_buf_len, char **_buf) --{ -- long pw_max; -- long gr_max; -- size_t buf_len; -- char *buf; -- -- pw_max = sysconf(_SC_GETPW_R_SIZE_MAX); -- gr_max = sysconf(_SC_GETGR_R_SIZE_MAX); -- -- if (pw_max == -1 && gr_max == -1) { -- buf_len = 16384; -- } else { -- buf_len = MAX(pw_max, gr_max); -- } -- -- buf = malloc(sizeof(char) * buf_len); -- if (buf == NULL) { -- return LDAP_OPERATIONS_ERROR; -- } -- -- *_buf_len = buf_len; -- *_buf = buf; -- -- return LDAP_SUCCESS; --} -- - static int get_user_grouplist(const char *name, gid_t gid, - size_t *_ngroups, gid_t **_groups ) - { -@@ -323,7 +478,6 @@ static int pack_ber_user(enum response_types response_type, - size_t buf_len; - char *buf = NULL; - struct group grp; -- struct group *grp_result; - size_t c; - char *locat; - char *short_user_name = NULL; -@@ -375,13 +529,13 @@ static int pack_ber_user(enum response_types response_type, - } - - for (c = 0; c < ngroups; c++) { -- ret = getgrgid_r(groups[c], &grp, buf, buf_len, &grp_result); -+ ret = getgrgid_r_wrapper(MAX_BUF, groups[c], &grp, &buf, &buf_len); - if (ret != 0) { -- ret = LDAP_NO_SUCH_OBJECT; -- goto done; -- } -- if (grp_result == NULL) { -- ret = LDAP_NO_SUCH_OBJECT; -+ if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ } - goto done; - } - -@@ -542,7 +696,6 @@ static int handle_uid_request(enum request_types request_type, uid_t uid, - { - int ret; - struct passwd pwd; -- struct passwd *pwd_result = NULL; - char *sid_str = NULL; - enum sss_id_type id_type; - size_t buf_len; -@@ -568,13 +721,13 @@ static int handle_uid_request(enum request_types request_type, uid_t uid, - - ret = pack_ber_sid(sid_str, berval); - } else { -- ret = getpwuid_r(uid, &pwd, buf, buf_len, &pwd_result); -+ ret = getpwuid_r_wrapper(MAX_BUF, uid, &pwd, &buf, &buf_len); - if (ret != 0) { -- ret = LDAP_NO_SUCH_OBJECT; -- goto done; -- } -- if (pwd_result == NULL) { -- ret = LDAP_NO_SUCH_OBJECT; -+ if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ } - goto done; - } - -@@ -610,7 +763,6 @@ static int handle_gid_request(enum request_types request_type, gid_t gid, - { - int ret; - struct group grp; -- struct group *grp_result = NULL; - char *sid_str = NULL; - enum sss_id_type id_type; - size_t buf_len; -@@ -635,13 +787,13 @@ static int handle_gid_request(enum request_types request_type, gid_t gid, - - ret = pack_ber_sid(sid_str, berval); - } else { -- ret = getgrgid_r(gid, &grp, buf, buf_len, &grp_result); -+ ret = getgrgid_r_wrapper(MAX_BUF, gid, &grp, &buf, &buf_len); - if (ret != 0) { -- ret = LDAP_NO_SUCH_OBJECT; -- goto done; -- } -- if (grp_result == NULL) { -- ret = LDAP_NO_SUCH_OBJECT; -+ if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ } - goto done; - } - -@@ -676,9 +828,7 @@ static int handle_sid_request(enum request_types request_type, const char *sid, - { - int ret; - struct passwd pwd; -- struct passwd *pwd_result = NULL; - struct group grp; -- struct group *grp_result = NULL; - char *domain_name = NULL; - char *fq_name = NULL; - char *object_name = NULL; -@@ -724,14 +874,13 @@ static int handle_sid_request(enum request_types request_type, const char *sid, - switch(id_type) { - case SSS_ID_TYPE_UID: - case SSS_ID_TYPE_BOTH: -- ret = getpwnam_r(fq_name, &pwd, buf, buf_len, &pwd_result); -+ ret = getpwnam_r_wrapper(MAX_BUF, fq_name, &pwd, &buf, &buf_len); - if (ret != 0) { -- ret = LDAP_NO_SUCH_OBJECT; -- goto done; -- } -- -- if (pwd_result == NULL) { -- ret = LDAP_NO_SUCH_OBJECT; -+ if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ } - goto done; - } - -@@ -755,14 +904,13 @@ static int handle_sid_request(enum request_types request_type, const char *sid, - pwd.pw_shell, kv_list, berval); - break; - case SSS_ID_TYPE_GID: -- ret = getgrnam_r(fq_name, &grp, buf, buf_len, &grp_result); -+ ret = getgrnam_r_wrapper(MAX_BUF, fq_name, &grp, &buf, &buf_len); - if (ret != 0) { -- ret = LDAP_NO_SUCH_OBJECT; -- goto done; -- } -- -- if (grp_result == NULL) { -- ret = LDAP_NO_SUCH_OBJECT; -+ if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ } - goto done; - } - -@@ -806,9 +954,7 @@ static int handle_name_request(enum request_types request_type, - int ret; - char *fq_name = NULL; - struct passwd pwd; -- struct passwd *pwd_result = NULL; - struct group grp; -- struct group *grp_result = NULL; - char *sid_str = NULL; - enum sss_id_type id_type; - size_t buf_len; -@@ -842,15 +988,8 @@ static int handle_name_request(enum request_types request_type, - goto done; - } - -- ret = getpwnam_r(fq_name, &pwd, buf, buf_len, &pwd_result); -- if (ret != 0) { -- /* according to the man page there are a couple of error codes -- * which can indicate that the user was not found. To be on the -- * safe side we fail back to the group lookup on all errors. */ -- pwd_result = NULL; -- } -- -- if (pwd_result != NULL) { -+ ret = getpwnam_r_wrapper(MAX_BUF, fq_name, &pwd, &buf, &buf_len); -+ if (ret == 0) { - if (request_type == REQ_FULL_WITH_GROUPS) { - ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type); - if (ret != 0 || !(id_type == SSS_ID_TYPE_UID -@@ -868,15 +1007,21 @@ static int handle_name_request(enum request_types request_type, - domain_name, pwd.pw_name, pwd.pw_uid, - pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir, - pwd.pw_shell, kv_list, berval); -+ } else if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; - } else { /* no user entry found */ -- ret = getgrnam_r(fq_name, &grp, buf, buf_len, &grp_result); -+ /* according to the getpwnam() man page there are a couple of -+ * error codes which can indicate that the user was not found. To -+ * be on the safe side we fail back to the group lookup on all -+ * errors. */ -+ ret = getgrnam_r_wrapper(MAX_BUF, fq_name, &grp, &buf, &buf_len); - if (ret != 0) { -- ret = LDAP_NO_SUCH_OBJECT; -- goto done; -- } -- -- if (grp_result == NULL) { -- ret = LDAP_NO_SUCH_OBJECT; -+ if (ret == ENOMEM || ret == ERANGE) { -+ ret = LDAP_OPERATIONS_ERROR; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ } - goto done; - } - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/group b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/group -new file mode 100644 -index 0000000000000000000000000000000000000000..8d1b012871b21cc9d5ffdba2168f35ef3e8a5f81 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/group -@@ -0,0 +1,2 @@ -+group:x:11111:member0001,member0002 -+group_big:x:22222:member0001,member0002,member0003,member0004,member0005,member0006,member0007,member0008,member0009,member0010,member0011,member0012,member0013,member0014,member0015,member0016,member0017,member0018,member0019,member0020,member0021,member0022,member0023,member0024,member0025,member0026,member0027,member0028,member0029,member0030,member0031,member0032,member0033,member0034,member0035,member0036,member0037,member0038,member0039,member0040,member0041,member0042,member0043,member0044,member0045,member0046,member0047,member0048,member0049,member0050,member0051,member0052,member0053,member0054,member0055,member0056,member0057,member0058,member0059,member0060,member0061,member0062,member0063,member0064,member0065,member0066,member0067,member0068,member0069,member0070,member0071,member0072,member0073,member0074,member0075,member0076,member0077,member0078,member0079,member0080,member0081,member0082,member0083,member0084,member0085,member0086,member0087,member0088,member0089,member0090,member0091,member0092,member0093,member0094,member0095,member0096,member0097,member0098,member0099,member0100,member0101,member0102,member0103,member0104,member0105,member0106,member0107,member0108,member0109,member0110,member0111,member0112,member0113,member0114,member0115,member0116,member0117,member0118,member0119,member0120,member0121,member0122,member0123,member0124,member0125,member0126,member0127,member0128,member0129,member0130,member0131,member0132,member0133,member0134,member0135,member0136,member0137,member0138,member0139,member0140,member0141,member0142,member0143,member0144,member0145,member0146,member0147,member0148,member0149,member0150,member0151,member0152,member0153,member0154,member0155,member0156,member0157,member0158,member0159,member0160,member0161,member0162,member0163,member0164,member0165,member0166,member0167,member0168,member0169,member0170,member0171,member0172,member0173,member0174,member0175,member0176,member0177,member0178,member0179,member0180,member0181,member0182,member0183,member0184,member0185,member0186,member0187,member0188,member0189,member0190,member0191,member0192,member0193,member0194,member0195,member0196,member0197,member0198,member0199,member0200,member0201,member0202,member0203,member0204,member0205,member0206,member0207,member0208,member0209,member0210,member0211,member0212,member0213,member0214,member0215,member0216,member0217,member0218,member0219,member0220,member0221,member0222,member0223,member0224,member0225,member0226,member0227,member0228,member0229,member0230,member0231,member0232,member0233,member0234,member0235,member0236,member0237,member0238,member0239,member0240,member0241,member0242,member0243,member0244,member0245,member0246,member0247,member0248,member0249,member0250,member0251,member0252,member0253,member0254,member0255,member0256,member0257,member0258,member0259,member0260,member0261,member0262,member0263,member0264,member0265,member0266,member0267,member0268,member0269,member0270,member0271,member0272,member0273,member0274,member0275,member0276,member0277,member0278,member0279,member0280,member0281,member0282,member0283,member0284,member0285,member0286,member0287,member0288,member0289,member0290,member0291,member0292,member0293,member0294,member0295,member0296,member0297,member0298,member0299,member0300,member0301,member0302,member0303,member0304,member0305,member0306,member0307,member0308,member0309,member0310,member0311,member0312,member0313,member0314,member0315,member0316,member0317,member0318,member0319,member0320,member0321,member0322,member0323,member0324,member0325,member0326,member0327,member0328,member0329,member0330,member0331,member0332,member0333,member0334,member0335,member0336,member0337,member0338,member0339,member0340,member0341,member0342,member0343,member0344,member0345,member0346,member0347,member0348,member0349,member0350,member0351,member0352,member0353,member0354,member0355,member0356,member0357,member0358,member0359,member0360,member0361,member0362,member0363,member0364,member0365,member0366,member0367,member0368,member0369,member0370,member0371,member0372,member0373,member0374,member0375,member0376,member0377,member0378,member0379,member0380,member0381,member0382,member0383,member0384,member0385,member0386,member0387,member0388,member0389,member0390,member0391,member0392,member0393,member0394,member0395,member0396,member0397,member0398,member0399,member0400,member0401,member0402,member0403,member0404,member0405,member0406,member0407,member0408,member0409,member0410,member0411,member0412,member0413,member0414,member0415,member0416,member0417,member0418,member0419,member0420,member0421,member0422,member0423,member0424,member0425,member0426,member0427,member0428,member0429,member0430,member0431,member0432,member0433,member0434,member0435,member0436,member0437,member0438,member0439,member0440,member0441,member0442,member0443,member0444,member0445,member0446,member0447,member0448,member0449,member0450,member0451,member0452,member0453,member0454,member0455,member0456,member0457,member0458,member0459,member0460,member0461,member0462,member0463,member0464,member0465,member0466,member0467,member0468,member0469,member0470,member0471,member0472,member0473,member0474,member0475,member0476,member0477,member0478,member0479,member0480,member0481,member0482,member0483,member0484,member0485,member0486,member0487,member0488,member0489,member0490,member0491,member0492,member0493,member0494,member0495,member0496,member0497,member0498,member0499,member0500,member0501,member0502,member0503,member0504,member0505,member0506,member0507,member0508,member0509,member0510,member0511,member0512,member0513,member0514,member0515,member0516,member0517,member0518,member0519,member0520,member0521,member0522,member0523,member0524,member0525,member0526,member0527,member0528,member0529,member0530,member0531,member0532,member0533,member0534,member0535,member0536,member0537,member0538,member0539,member0540,member0541,member0542,member0543,member0544,member0545,member0546,member0547,member0548,member0549,member0550,member0551,member0552,member0553,member0554,member0555,member0556,member0557,member0558,member0559,member0560,member0561,member0562,member0563,member0564,member0565,member0566,member0567,member0568,member0569,member0570,member0571,member0572,member0573,member0574,member0575,member0576,member0577,member0578,member0579,member0580,member0581,member0582,member0583,member0584,member0585,member0586,member0587,member0588,member0589,member0590,member0591,member0592,member0593,member0594,member0595,member0596,member0597,member0598,member0599,member0600,member0601,member0602,member0603,member0604,member0605,member0606,member0607,member0608,member0609,member0610,member0611,member0612,member0613,member0614,member0615,member0616,member0617,member0618,member0619,member0620,member0621,member0622,member0623,member0624,member0625,member0626,member0627,member0628,member0629,member0630,member0631,member0632,member0633,member0634,member0635,member0636,member0637,member0638,member0639,member0640,member0641,member0642,member0643,member0644,member0645,member0646,member0647,member0648,member0649,member0650,member0651,member0652,member0653,member0654,member0655,member0656,member0657,member0658,member0659,member0660,member0661,member0662,member0663,member0664,member0665,member0666,member0667,member0668,member0669,member0670,member0671,member0672,member0673,member0674,member0675,member0676,member0677,member0678,member0679,member0680,member0681,member0682,member0683,member0684,member0685,member0686,member0687,member0688,member0689,member0690,member0691,member0692,member0693,member0694,member0695,member0696,member0697,member0698,member0699,member0700,member0701,member0702,member0703,member0704,member0705,member0706,member0707,member0708,member0709,member0710,member0711,member0712,member0713,member0714,member0715,member0716,member0717,member0718,member0719,member0720,member0721,member0722,member0723,member0724,member0725,member0726,member0727,member0728,member0729,member0730,member0731,member0732,member0733,member0734,member0735,member0736,member0737,member0738,member0739,member0740,member0741,member0742,member0743,member0744,member0745,member0746,member0747,member0748,member0749,member0750,member0751,member0752,member0753,member0754,member0755,member0756,member0757,member0758,member0759,member0760,member0761,member0762,member0763,member0764,member0765,member0766,member0767,member0768,member0769,member0770,member0771,member0772,member0773,member0774,member0775,member0776,member0777,member0778,member0779,member0780,member0781,member0782,member0783,member0784,member0785,member0786,member0787,member0788,member0789,member0790,member0791,member0792,member0793,member0794,member0795,member0796,member0797,member0798,member0799,member0800,member0801,member0802,member0803,member0804,member0805,member0806,member0807,member0808,member0809,member0810,member0811,member0812,member0813,member0814,member0815,member0816,member0817,member0818,member0819,member0820,member0821,member0822,member0823,member0824,member0825,member0826,member0827,member0828,member0829,member0830,member0831,member0832,member0833,member0834,member0835,member0836,member0837,member0838,member0839,member0840,member0841,member0842,member0843,member0844,member0845,member0846,member0847,member0848,member0849,member0850,member0851,member0852,member0853,member0854,member0855,member0856,member0857,member0858,member0859,member0860,member0861,member0862,member0863,member0864,member0865,member0866,member0867,member0868,member0869,member0870,member0871,member0872,member0873,member0874,member0875,member0876,member0877,member0878,member0879,member0880,member0881,member0882,member0883,member0884,member0885,member0886,member0887,member0888,member0889,member0890,member0891,member0892,member0893,member0894,member0895,member0896,member0897,member0898,member0899,member0900,member0901,member0902,member0903,member0904,member0905,member0906,member0907,member0908,member0909,member0910,member0911,member0912,member0913,member0914,member0915,member0916,member0917,member0918,member0919,member0920,member0921,member0922,member0923,member0924,member0925,member0926,member0927,member0928,member0929,member0930,member0931,member0932,member0933,member0934,member0935,member0936,member0937,member0938,member0939,member0940,member0941,member0942,member0943,member0944,member0945,member0946,member0947,member0948,member0949,member0950,member0951,member0952,member0953,member0954,member0955,member0956,member0957,member0958,member0959,member0960,member0961,member0962,member0963,member0964,member0965,member0966,member0967,member0968,member0969,member0970,member0971,member0972,member0973,member0974,member0975,member0976,member0977,member0978,member0979,member0980,member0981,member0982,member0983,member0984,member0985,member0986,member0987,member0988,member0989,member0990,member0991,member0992,member0993,member0994,member0995,member0996,member0997,member0998,member0999,member1000,member1001,member1002,member1003,member1004,member1005,member1006,member1007,member1008,member1009,member1010,member1011,member1012,member1013,member1014,member1015,member1016,member1017,member1018,member1019,member1020,member1021,member1022,member1023,member1024,member1025,member1026,member1027,member1028,member1029,member1030,member1031,member1032,member1033,member1034,member1035,member1036,member1037,member1038,member1039,member1040,member1041,member1042,member1043,member1044,member1045,member1046,member1047,member1048,member1049,member1050,member1051,member1052,member1053,member1054,member1055,member1056,member1057,member1058,member1059,member1060,member1061,member1062,member1063,member1064,member1065,member1066,member1067,member1068,member1069,member1070,member1071,member1072,member1073,member1074,member1075,member1076,member1077,member1078,member1079,member1080,member1081,member1082,member1083,member1084,member1085,member1086,member1087,member1088,member1089,member1090,member1091,member1092,member1093,member1094,member1095,member1096,member1097,member1098,member1099,member1100,member1101,member1102,member1103,member1104,member1105,member1106,member1107,member1108,member1109,member1110,member1111,member1112,member1113,member1114,member1115,member1116,member1117,member1118,member1119,member1120,member1121,member1122,member1123,member1124,member1125,member1126,member1127,member1128,member1129,member1130,member1131,member1132,member1133,member1134,member1135,member1136,member1137,member1138,member1139,member1140,member1141,member1142,member1143,member1144,member1145,member1146,member1147,member1148,member1149,member1150,member1151,member1152,member1153,member1154,member1155,member1156,member1157,member1158,member1159,member1160,member1161,member1162,member1163,member1164,member1165,member1166,member1167,member1168,member1169,member1170,member1171,member1172,member1173,member1174,member1175,member1176,member1177,member1178,member1179,member1180,member1181,member1182,member1183,member1184,member1185,member1186,member1187,member1188,member1189,member1190,member1191,member1192,member1193,member1194,member1195,member1196,member1197,member1198,member1199,member1200,member1201,member1202,member1203,member1204,member1205,member1206,member1207,member1208,member1209,member1210,member1211,member1212,member1213,member1214,member1215,member1216,member1217,member1218,member1219,member1220,member1221,member1222,member1223,member1224,member1225,member1226,member1227,member1228,member1229,member1230,member1231,member1232,member1233,member1234,member1235,member1236,member1237,member1238,member1239,member1240,member1241,member1242,member1243,member1244,member1245,member1246,member1247,member1248,member1249,member1250,member1251,member1252,member1253,member1254,member1255,member1256,member1257,member1258,member1259,member1260,member1261,member1262,member1263,member1264,member1265,member1266,member1267,member1268,member1269,member1270,member1271,member1272,member1273,member1274,member1275,member1276,member1277,member1278,member1279,member1280,member1281,member1282,member1283,member1284,member1285,member1286,member1287,member1288,member1289,member1290,member1291,member1292,member1293,member1294,member1295,member1296,member1297,member1298,member1299,member1300,member1301,member1302,member1303,member1304,member1305,member1306,member1307,member1308,member1309,member1310,member1311,member1312,member1313,member1314,member1315,member1316,member1317,member1318,member1319,member1320,member1321,member1322,member1323,member1324,member1325,member1326,member1327,member1328,member1329,member1330,member1331,member1332,member1333,member1334,member1335,member1336,member1337,member1338,member1339,member1340,member1341,member1342,member1343,member1344,member1345,member1346,member1347,member1348,member1349,member1350,member1351,member1352,member1353,member1354,member1355,member1356,member1357,member1358,member1359,member1360,member1361,member1362,member1363,member1364,member1365,member1366,member1367,member1368,member1369,member1370,member1371,member1372,member1373,member1374,member1375,member1376,member1377,member1378,member1379,member1380,member1381,member1382,member1383,member1384,member1385,member1386,member1387,member1388,member1389,member1390,member1391,member1392,member1393,member1394,member1395,member1396,member1397,member1398,member1399,member1400,member1401,member1402,member1403,member1404,member1405,member1406,member1407,member1408,member1409,member1410,member1411,member1412,member1413,member1414,member1415,member1416,member1417,member1418,member1419,member1420,member1421,member1422,member1423,member1424,member1425,member1426,member1427,member1428,member1429,member1430,member1431,member1432,member1433,member1434,member1435,member1436,member1437,member1438,member1439,member1440,member1441,member1442,member1443,member1444,member1445,member1446,member1447,member1448,member1449,member1450,member1451,member1452,member1453,member1454,member1455,member1456,member1457,member1458,member1459,member1460,member1461,member1462,member1463,member1464,member1465,member1466,member1467,member1468,member1469,member1470,member1471,member1472,member1473,member1474,member1475,member1476,member1477,member1478,member1479,member1480,member1481,member1482,member1483,member1484,member1485,member1486,member1487,member1488,member1489,member1490,member1491,member1492,member1493,member1494,member1495,member1496,member1497,member1498,member1499,member1500,member1501,member1502,member1503,member1504,member1505,member1506,member1507,member1508,member1509,member1510,member1511,member1512,member1513,member1514,member1515,member1516,member1517,member1518,member1519,member1520,member1521,member1522,member1523,member1524,member1525,member1526,member1527,member1528,member1529,member1530,member1531,member1532,member1533,member1534,member1535,member1536,member1537,member1538,member1539,member1540,member1541,member1542,member1543,member1544,member1545,member1546,member1547,member1548,member1549,member1550,member1551,member1552,member1553,member1554,member1555,member1556,member1557,member1558,member1559,member1560,member1561,member1562,member1563,member1564,member1565,member1566,member1567,member1568,member1569,member1570,member1571,member1572,member1573,member1574,member1575,member1576,member1577,member1578,member1579,member1580,member1581,member1582,member1583,member1584,member1585,member1586,member1587,member1588,member1589,member1590,member1591,member1592,member1593,member1594,member1595,member1596,member1597,member1598,member1599,member1600,member1601,member1602,member1603,member1604,member1605,member1606,member1607,member1608,member1609,member1610,member1611,member1612,member1613,member1614,member1615,member1616,member1617,member1618,member1619,member1620,member1621,member1622,member1623,member1624,member1625,member1626,member1627,member1628,member1629,member1630,member1631,member1632,member1633,member1634,member1635,member1636,member1637,member1638,member1639,member1640,member1641,member1642,member1643,member1644,member1645,member1646,member1647,member1648,member1649,member1650,member1651,member1652,member1653,member1654,member1655,member1656,member1657,member1658,member1659,member1660,member1661,member1662,member1663,member1664,member1665,member1666,member1667,member1668,member1669,member1670,member1671,member1672,member1673,member1674,member1675,member1676,member1677,member1678,member1679,member1680,member1681,member1682,member1683,member1684,member1685,member1686,member1687,member1688,member1689,member1690,member1691,member1692,member1693,member1694,member1695,member1696,member1697,member1698,member1699,member1700,member1701,member1702,member1703,member1704,member1705,member1706,member1707,member1708,member1709,member1710,member1711,member1712,member1713,member1714,member1715,member1716,member1717,member1718,member1719,member1720,member1721,member1722,member1723,member1724,member1725,member1726,member1727,member1728,member1729,member1730,member1731,member1732,member1733,member1734,member1735,member1736,member1737,member1738,member1739,member1740,member1741,member1742,member1743,member1744,member1745,member1746,member1747,member1748,member1749,member1750,member1751,member1752,member1753,member1754,member1755,member1756,member1757,member1758,member1759,member1760,member1761,member1762,member1763,member1764,member1765,member1766,member1767,member1768,member1769,member1770,member1771,member1772,member1773,member1774,member1775,member1776,member1777,member1778,member1779,member1780,member1781,member1782,member1783,member1784,member1785,member1786,member1787,member1788,member1789,member1790,member1791,member1792,member1793,member1794,member1795,member1796,member1797,member1798,member1799,member1800,member1801,member1802,member1803,member1804,member1805,member1806,member1807,member1808,member1809,member1810,member1811,member1812,member1813,member1814,member1815,member1816,member1817,member1818,member1819,member1820,member1821,member1822,member1823,member1824,member1825,member1826,member1827,member1828,member1829,member1830,member1831,member1832,member1833,member1834,member1835,member1836,member1837,member1838,member1839,member1840,member1841,member1842,member1843,member1844,member1845,member1846,member1847,member1848,member1849,member1850,member1851,member1852,member1853,member1854,member1855,member1856,member1857,member1858,member1859,member1860,member1861,member1862,member1863,member1864,member1865,member1866,member1867,member1868,member1869,member1870,member1871,member1872,member1873,member1874,member1875,member1876,member1877,member1878,member1879,member1880,member1881,member1882,member1883,member1884,member1885,member1886,member1887,member1888,member1889,member1890,member1891,member1892,member1893,member1894,member1895,member1896,member1897,member1898,member1899,member1900,member1901,member1902,member1903,member1904,member1905,member1906,member1907,member1908,member1909,member1910,member1911,member1912,member1913,member1914,member1915,member1916,member1917,member1918,member1919,member1920,member1921,member1922,member1923,member1924,member1925,member1926,member1927,member1928,member1929,member1930,member1931,member1932,member1933,member1934,member1935,member1936,member1937,member1938,member1939,member1940,member1941,member1942,member1943,member1944,member1945,member1946,member1947,member1948,member1949,member1950,member1951,member1952,member1953,member1954,member1955,member1956,member1957,member1958,member1959,member1960,member1961,member1962,member1963,member1964,member1965,member1966,member1967,member1968,member1969,member1970,member1971,member1972,member1973,member1974,member1975,member1976,member1977,member1978,member1979,member1980,member1981,member1982,member1983,member1984,member1985,member1986,member1987,member1988,member1989,member1990,member1991,member1992,member1993,member1994,member1995,member1996,member1997,member1998,member1999,member2000, -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/passwd b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/passwd -new file mode 100644 -index 0000000000000000000000000000000000000000..971e9bdb8a5d43d915ce0adc42ac29f2f95ade52 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/passwd -@@ -0,0 +1,2 @@ -+user:x:12345:23456:gecos:/home/user:/bin/shell -+user_big:x:12346:23457:gecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecosgecos:/home/user_big:/bin/shell -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh -new file mode 100644 -index 0000000000000000000000000000000000000000..ad839f340efe989a91cd6902f59c9a41483f68e0 ---- /dev/null -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/test_data/test_setup.sh -@@ -0,0 +1,3 @@ -+export LD_PRELOAD=$(pkg-config --libs nss_wrapper) -+export NSS_WRAPPER_PASSWD=./test_data/passwd -+export NSS_WRAPPER_GROUP=./test_data/group --- -2.1.0 - diff --git a/SOURCES/0120-config-allow-user-host-attributes-with-tagging-optio.patch b/SOURCES/0120-config-allow-user-host-attributes-with-tagging-optio.patch new file mode 100644 index 0000000..926c779 --- /dev/null +++ b/SOURCES/0120-config-allow-user-host-attributes-with-tagging-optio.patch @@ -0,0 +1,35 @@ +From 19f9ad712fc8d8652d66b8aac8befd9d83dad721 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 16 Sep 2015 08:24:22 +0200 +Subject: [PATCH] config: allow user/host attributes with tagging options + +https://fedorahosted.org/freeipa/ticket/5295 + +Reviewed-By: David Kupka +--- + ipalib/plugins/config.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py +index 6267313d5e9af2d97f45f987115de143d7aa7915..76368c0887f782153c3131c7833f78afe86dcf89 100644 +--- a/ipalib/plugins/config.py ++++ b/ipalib/plugins/config.py +@@ -262,6 +262,7 @@ class config_mod(LDAPUpdate): + fields = entry_attrs[k].split(',') + for a in fields: + a = a.strip() ++ a, tomato, olive = a.partition(';') + if a not in allowed_attrs: + raise errors.ValidationError( + name=k, error=_('attribute "%s" not allowed') % a +@@ -281,6 +282,7 @@ class config_mod(LDAPUpdate): + if self.api.Object[obj].uuid_attribute: + checked_attrs = checked_attrs + [self.api.Object[obj].uuid_attribute] + for obj_attr in checked_attrs: ++ obj_attr, tomato, olive = obj_attr.partition(';') + if obj_attr in OPERATIONAL_ATTRIBUTES: + continue + if obj_attr in self.api.Object[obj].params and \ +-- +2.4.3 + diff --git a/SOURCES/0120-extdom-make-nss-buffer-configurable.patch b/SOURCES/0120-extdom-make-nss-buffer-configurable.patch deleted file mode 100644 index 6d68642..0000000 --- a/SOURCES/0120-extdom-make-nss-buffer-configurable.patch +++ /dev/null @@ -1,254 +0,0 @@ -From 637807410ae730436f9ca647092250ead70faa1c Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 2 Mar 2015 10:59:34 +0100 -Subject: [PATCH] extdom: make nss buffer configurable - -The get*_r_wrapper() calls expect a maximum buffer size to avoid memory -shortage if too many threads try to allocate buffers e.g. for large -groups. With this patch this size can be configured by setting -ipaExtdomMaxNssBufSize in the plugin config object -cn=ipa_extdom_extop,cn=plugins,cn=config. - -Related to https://fedorahosted.org/freeipa/ticket/4908 - -Reviewed-By: Alexander Bokovoy ---- - .../ipa-extdom-extop/ipa_extdom.h | 1 + - .../ipa-extdom-extop/ipa_extdom_common.c | 59 ++++++++++++++-------- - .../ipa-extdom-extop/ipa_extdom_extop.c | 10 ++++ - 3 files changed, 48 insertions(+), 22 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -index 40bf933920fdd2ca19e5ef195aaa8fb820446cc5..d4c851169ddadc869a59c53075f9fc7f33321085 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h -@@ -150,6 +150,7 @@ struct extdom_res { - struct ipa_extdom_ctx { - Slapi_ComponentId *plugin_id; - char *base_dn; -+ size_t max_nss_buf_size; - }; - - struct domain_info { -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -index cbe336963ffbafadd5a7b8029a65fafe506f75e8..47bcb179f04e08c64d92f55809b84f2d59622344 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c -@@ -49,9 +49,6 @@ - - #define MAX(a,b) (((a)>(b))?(a):(b)) - #define SSSD_DOMAIN_SEPARATOR '@' --#define MAX_BUF (1024*1024*1024) -- -- - - int get_buffer(size_t *_buf_len, char **_buf) - { -@@ -464,7 +461,8 @@ static int pack_ber_sid(const char *sid, struct berval **berval) - - #define SSSD_SYSDB_SID_STR "objectSIDString" - --static int pack_ber_user(enum response_types response_type, -+static int pack_ber_user(struct ipa_extdom_ctx *ctx, -+ enum response_types response_type, - const char *domain_name, const char *user_name, - uid_t uid, gid_t gid, - const char *gecos, const char *homedir, -@@ -529,7 +527,8 @@ static int pack_ber_user(enum response_types response_type, - } - - for (c = 0; c < ngroups; c++) { -- ret = getgrgid_r_wrapper(MAX_BUF, groups[c], &grp, &buf, &buf_len); -+ ret = getgrgid_r_wrapper(ctx->max_nss_buf_size, -+ groups[c], &grp, &buf, &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -691,7 +690,8 @@ static int pack_ber_name(const char *domain_name, const char *name, - return LDAP_SUCCESS; - } - --static int handle_uid_request(enum request_types request_type, uid_t uid, -+static int handle_uid_request(struct ipa_extdom_ctx *ctx, -+ enum request_types request_type, uid_t uid, - const char *domain_name, struct berval **berval) - { - int ret; -@@ -721,7 +721,8 @@ static int handle_uid_request(enum request_types request_type, uid_t uid, - - ret = pack_ber_sid(sid_str, berval); - } else { -- ret = getpwuid_r_wrapper(MAX_BUF, uid, &pwd, &buf, &buf_len); -+ ret = getpwuid_r_wrapper(ctx->max_nss_buf_size, uid, &pwd, &buf, -+ &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -744,7 +745,8 @@ static int handle_uid_request(enum request_types request_type, uid_t uid, - } - } - -- ret = pack_ber_user((request_type == REQ_FULL ? RESP_USER -+ ret = pack_ber_user(ctx, -+ (request_type == REQ_FULL ? RESP_USER - : RESP_USER_GROUPLIST), - domain_name, pwd.pw_name, pwd.pw_uid, - pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir, -@@ -758,7 +760,8 @@ done: - return ret; - } - --static int handle_gid_request(enum request_types request_type, gid_t gid, -+static int handle_gid_request(struct ipa_extdom_ctx *ctx, -+ enum request_types request_type, gid_t gid, - const char *domain_name, struct berval **berval) - { - int ret; -@@ -787,7 +790,8 @@ static int handle_gid_request(enum request_types request_type, gid_t gid, - - ret = pack_ber_sid(sid_str, berval); - } else { -- ret = getgrgid_r_wrapper(MAX_BUF, gid, &grp, &buf, &buf_len); -+ ret = getgrgid_r_wrapper(ctx->max_nss_buf_size, gid, &grp, &buf, -+ &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -823,7 +827,8 @@ done: - return ret; - } - --static int handle_sid_request(enum request_types request_type, const char *sid, -+static int handle_sid_request(struct ipa_extdom_ctx *ctx, -+ enum request_types request_type, const char *sid, - struct berval **berval) - { - int ret; -@@ -874,7 +879,8 @@ static int handle_sid_request(enum request_types request_type, const char *sid, - switch(id_type) { - case SSS_ID_TYPE_UID: - case SSS_ID_TYPE_BOTH: -- ret = getpwnam_r_wrapper(MAX_BUF, fq_name, &pwd, &buf, &buf_len); -+ ret = getpwnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &pwd, &buf, -+ &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -897,14 +903,16 @@ static int handle_sid_request(enum request_types request_type, const char *sid, - } - } - -- ret = pack_ber_user((request_type == REQ_FULL ? RESP_USER -+ ret = pack_ber_user(ctx, -+ (request_type == REQ_FULL ? RESP_USER - : RESP_USER_GROUPLIST), - domain_name, pwd.pw_name, pwd.pw_uid, - pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir, - pwd.pw_shell, kv_list, berval); - break; - case SSS_ID_TYPE_GID: -- ret = getgrnam_r_wrapper(MAX_BUF, fq_name, &grp, &buf, &buf_len); -+ ret = getgrnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &grp, &buf, -+ &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -947,7 +955,8 @@ done: - return ret; - } - --static int handle_name_request(enum request_types request_type, -+static int handle_name_request(struct ipa_extdom_ctx *ctx, -+ enum request_types request_type, - const char *name, const char *domain_name, - struct berval **berval) - { -@@ -988,7 +997,8 @@ static int handle_name_request(enum request_types request_type, - goto done; - } - -- ret = getpwnam_r_wrapper(MAX_BUF, fq_name, &pwd, &buf, &buf_len); -+ ret = getpwnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &pwd, &buf, -+ &buf_len); - if (ret == 0) { - if (request_type == REQ_FULL_WITH_GROUPS) { - ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type); -@@ -1002,7 +1012,8 @@ static int handle_name_request(enum request_types request_type, - goto done; - } - } -- ret = pack_ber_user((request_type == REQ_FULL ? RESP_USER -+ ret = pack_ber_user(ctx, -+ (request_type == REQ_FULL ? RESP_USER - : RESP_USER_GROUPLIST), - domain_name, pwd.pw_name, pwd.pw_uid, - pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir, -@@ -1015,7 +1026,8 @@ static int handle_name_request(enum request_types request_type, - * error codes which can indicate that the user was not found. To - * be on the safe side we fail back to the group lookup on all - * errors. */ -- ret = getgrnam_r_wrapper(MAX_BUF, fq_name, &grp, &buf, &buf_len); -+ ret = getgrnam_r_wrapper(ctx->max_nss_buf_size, fq_name, &grp, &buf, -+ &buf_len); - if (ret != 0) { - if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; -@@ -1061,20 +1073,23 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req, - - switch (req->input_type) { - case INP_POSIX_UID: -- ret = handle_uid_request(req->request_type, req->data.posix_uid.uid, -+ ret = handle_uid_request(ctx, req->request_type, -+ req->data.posix_uid.uid, - req->data.posix_uid.domain_name, berval); - - break; - case INP_POSIX_GID: -- ret = handle_gid_request(req->request_type, req->data.posix_gid.gid, -+ ret = handle_gid_request(ctx, req->request_type, -+ req->data.posix_gid.gid, - req->data.posix_uid.domain_name, berval); - - break; - case INP_SID: -- ret = handle_sid_request(req->request_type, req->data.sid, berval); -+ ret = handle_sid_request(ctx, req->request_type, req->data.sid, berval); - break; - case INP_NAME: -- ret = handle_name_request(req->request_type, req->data.name.object_name, -+ ret = handle_name_request(ctx, req->request_type, -+ req->data.name.object_name, - req->data.name.domain_name, berval); - - break; -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -index aa66c145bc6cf2b77fdfe37be18da67588dc0439..e53f968db040a37fbd6a193f87b3671eeabda89d 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -@@ -40,6 +40,8 @@ - #include "ipa_extdom.h" - #include "util.h" - -+#define DEFAULT_MAX_NSS_BUFFER (128*1024*1024) -+ - Slapi_PluginDesc ipa_extdom_plugin_desc = { - IPA_EXTDOM_FEATURE_DESC, - "FreeIPA project", -@@ -185,6 +187,14 @@ static int ipa_extdom_init_ctx(Slapi_PBlock *pb, struct ipa_extdom_ctx **_ctx) - goto done; - } - -+ ctx->max_nss_buf_size = slapi_entry_attr_get_uint(e, -+ "ipaExtdomMaxNssBufSize"); -+ if (ctx->max_nss_buf_size == 0) { -+ ctx->max_nss_buf_size = DEFAULT_MAX_NSS_BUFFER; -+ } -+ LOG("Maximal nss buffer size set to [%d]!\n", ctx->max_nss_buf_size); -+ -+ ret = 0; - - done: - if (ret) { --- -2.1.0 - diff --git a/SOURCES/0121-extdom-return-LDAP_NO_SUCH_OBJECT-to-the-client.patch b/SOURCES/0121-extdom-return-LDAP_NO_SUCH_OBJECT-to-the-client.patch deleted file mode 100644 index 083a8c2..0000000 --- a/SOURCES/0121-extdom-return-LDAP_NO_SUCH_OBJECT-to-the-client.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0ce5d4e89e1a619bbae28105ece7033f8dbadce4 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 4 Mar 2015 13:39:04 +0100 -Subject: [PATCH] extdom: return LDAP_NO_SUCH_OBJECT to the client - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -index e53f968db040a37fbd6a193f87b3671eeabda89d..1ea0c1320accc66235d6f1a41055de434aeacab7 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -@@ -123,8 +123,12 @@ static int ipa_extdom_extop(Slapi_PBlock *pb) - - ret = handle_request(ctx, req, &ret_val); - if (ret != LDAP_SUCCESS) { -- rc = LDAP_OPERATIONS_ERROR; -- err_msg = "Failed to handle the request.\n"; -+ if (ret == LDAP_NO_SUCH_OBJECT) { -+ rc = LDAP_NO_SUCH_OBJECT; -+ } else { -+ rc = LDAP_OPERATIONS_ERROR; -+ err_msg = "Failed to handle the request.\n"; -+ } - goto done; - } - --- -2.1.0 - diff --git a/SOURCES/0121-winsync-Add-inetUser-objectclass-to-the-passsync-sys.patch b/SOURCES/0121-winsync-Add-inetUser-objectclass-to-the-passsync-sys.patch new file mode 100644 index 0000000..f3350a8 --- /dev/null +++ b/SOURCES/0121-winsync-Add-inetUser-objectclass-to-the-passsync-sys.patch @@ -0,0 +1,52 @@ +From e2c2bd871a0282628364dcb83d1feba44c5f71dc Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Tue, 15 Sep 2015 11:28:18 +0200 +Subject: [PATCH] winsync: Add inetUser objectclass to the passsync sysaccount + +https://bugzilla.redhat.com/show_bug.cgi?id=1262315 + +Reviewed-By: Petr Vobornik +--- + install/updates/73-winsync.update | 3 +++ + install/updates/Makefile.am | 1 + + ipaserver/install/replication.py | 2 +- + 3 files changed, 5 insertions(+), 1 deletion(-) + create mode 100644 install/updates/73-winsync.update + +diff --git a/install/updates/73-winsync.update b/install/updates/73-winsync.update +new file mode 100644 +index 0000000000000000000000000000000000000000..538eaa1cb6f97a73bfaadd61ac2ce9e9137739cf +--- /dev/null ++++ b/install/updates/73-winsync.update +@@ -0,0 +1,3 @@ ++# Add a inetUser objectclass to the passsync user ++dn: uid=passsync,cn=sysaccounts,cn=etc,$SUFFIX ++addifexist: objectClass: inetUser +diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am +index 2693e4f8f81dc1464a43041e5104ea4363440933..1f4a91c9bb4222f99ad7a7ad16e376aeef7f525b 100644 +--- a/install/updates/Makefile.am ++++ b/install/updates/Makefile.am +@@ -51,6 +51,7 @@ app_DATA = \ + 62-ranges.update \ + 71-idviews.update \ + 72-domainlevels.update \ ++ 73-winsync.update \ + 90-post_upgrade_plugins.update \ + $(NULL) + +diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py +index 2b36a5eb9287bf1789009a3198e540e333869e98..4bd3849e5e91c7251856362891f6c8848da43448 100644 +--- a/ipaserver/install/replication.py ++++ b/ipaserver/install/replication.py +@@ -565,7 +565,7 @@ class ReplicationManager(object): + print "Adding Windows PassSync system account" + entry = conn.make_entry( + pass_dn, +- objectclass=["account", "simplesecurityobject"], ++ objectclass=["account", "simplesecurityobject", "inetUser"], + uid=["passsync"], + userPassword=[password], + ) +-- +2.4.3 + diff --git a/SOURCES/0122-baseldap-make-subtree-deletion-optional-in-LDAPDelet.patch b/SOURCES/0122-baseldap-make-subtree-deletion-optional-in-LDAPDelet.patch new file mode 100644 index 0000000..5065a0a --- /dev/null +++ b/SOURCES/0122-baseldap-make-subtree-deletion-optional-in-LDAPDelet.patch @@ -0,0 +1,37 @@ +From 8cd08a619b275155e21d71c1368a73c8814a8640 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 17 Sep 2015 11:14:54 +0200 +Subject: [PATCH] baseldap: make subtree deletion optional in LDAPDelete + +https://fedorahosted.org/freeipa/ticket/5250 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/baseldap.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py +index 31f38946afcbb51638bcab68a6e74ec309eba0e4..15b6bb2365705bb6b0dc0df258c6a5b59c4b7d8d 100644 +--- a/ipalib/plugins/baseldap.py ++++ b/ipalib/plugins/baseldap.py +@@ -1565,6 +1565,8 @@ class LDAPDelete(LDAPMultiQuery): + + has_output_params = global_output_params + ++ subtree_delete = True ++ + def execute(self, *keys, **options): + ldap = self.obj.backend + +@@ -1600,6 +1602,8 @@ class LDAPDelete(LDAPMultiQuery): + except errors.NotFound: + self.obj.handle_not_found(*nkeys) + except errors.NotAllowedOnNonLeaf: ++ if not self.subtree_delete: ++ raise + # this entry is not a leaf entry, delete all child nodes + delete_subtree(dn) + +-- +2.4.3 + diff --git a/SOURCES/0122-extdom-fix-memory-leak.patch b/SOURCES/0122-extdom-fix-memory-leak.patch deleted file mode 100644 index 094b9fd..0000000 --- a/SOURCES/0122-extdom-fix-memory-leak.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a19a8e4174560ca6c7a23aa821c14713415b4c5d Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 4 Mar 2015 17:53:08 +0100 -Subject: [PATCH] extdom: fix memory leak - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -index 1ea0c1320accc66235d6f1a41055de434aeacab7..dc7785877fc321ddaa5b6967d1c1b06cb454bbbf 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -@@ -154,6 +154,7 @@ done: - LOG("%s", err_msg); - } - slapi_send_ldap_result(pb, rc, NULL, err_msg, 0, NULL); -+ ber_bvfree(ret_val); - return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; - } - --- -2.1.0 - diff --git a/SOURCES/0123-certstore-Make-certificate-retrieval-more-robust.patch b/SOURCES/0123-certstore-Make-certificate-retrieval-more-robust.patch deleted file mode 100644 index f177c08..0000000 --- a/SOURCES/0123-certstore-Make-certificate-retrieval-more-robust.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 2805b17bb7f204c25ed27bea1ee4fb999ae3d9d7 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 17 Mar 2015 09:28:47 +0000 -Subject: [PATCH] certstore: Make certificate retrieval more robust - -https://fedorahosted.org/freeipa/ticket/4565 - -Reviewed-By: David Kupka ---- - ipalib/certstore.py | 74 +++++++++++++++++++++++++++++++++++++---------------- - 1 file changed, 52 insertions(+), 22 deletions(-) - -diff --git a/ipalib/certstore.py b/ipalib/certstore.py -index 8a9b41015127fcb1b2b5e01da10f0defcee18265..3a5555c95251fdf3384c7dd21cb19d2125a469f5 100644 ---- a/ipalib/certstore.py -+++ b/ipalib/certstore.py -@@ -239,6 +239,31 @@ def put_ca_cert(ldap, base_dn, dercert, nickname, trusted=None, - pass - - -+def make_compat_ca_certs(certs, realm, ipa_ca_subject): -+ """ -+ Make CA certificates and associated key policy from DER certificates. -+ """ -+ result = [] -+ -+ for cert in certs: -+ subject, issuer_serial, public_key_info = _parse_cert(cert) -+ subject = DN(subject) -+ -+ if ipa_ca_subject is not None and subject == DN(ipa_ca_subject): -+ nickname = get_ca_nickname(realm) -+ ext_key_usage = {x509.EKU_SERVER_AUTH, -+ x509.EKU_CLIENT_AUTH, -+ x509.EKU_EMAIL_PROTECTION, -+ x509.EKU_CODE_SIGNING} -+ else: -+ nickname = str(subject) -+ ext_key_usage = {x509.EKU_SERVER_AUTH} -+ -+ result.append((cert, nickname, True, ext_key_usage)) -+ -+ return result -+ -+ - def get_ca_certs(ldap, base_dn, compat_realm, compat_ipa_ca, - filter_subject=None): - """ -@@ -250,6 +275,7 @@ def get_ca_certs(ldap, base_dn, compat_realm, compat_ipa_ca, - filter_subject = [str(subj).replace('\\;', '\\3b') - for subj in filter_subject] - -+ certs = [] - config_dn = DN(('cn', 'ipa'), ('cn', 'etc'), base_dn) - container_dn = DN(('cn', 'certificates'), config_dn) - try: -@@ -265,7 +291,6 @@ def get_ca_certs(ldap, base_dn, compat_realm, compat_ipa_ca, - 'ipaPublicKey', 'ipaKeyTrust', 'ipaKeyExtUsage', - 'cACertificate;binary']) - -- certs = [] - for entry in result: - nickname = entry.single_value['cn'] - trusted = entry.single_value.get('ipaKeyTrust', 'unknown').lower() -@@ -281,34 +306,39 @@ def get_ca_certs(ldap, base_dn, compat_realm, compat_ipa_ca, - ext_key_usage.discard(x509.EKU_PLACEHOLDER) - - for cert in entry.get('cACertificate;binary', []): -+ try: -+ _parse_cert(cert) -+ except ValueError: -+ certs = [] -+ break - certs.append((cert, nickname, trusted, ext_key_usage)) -- -- return certs - except errors.NotFound: - try: - ldap.get_entry(container_dn, ['']) - except errors.NotFound: -- pass -- else: -- return [] -- -- # Fallback to cn=CAcert,cn=ipa,cn=etc,SUFFIX -- dn = DN(('cn', 'CAcert'), config_dn) -- entry = ldap.get_entry(dn, ['cACertificate;binary']) -- -- cert = entry.single_value['cACertificate;binary'] -- subject, issuer_serial, public_key_info = _parse_cert(cert) -- if filter_subject is not None and subject not in filter_subject: -- return [] -+ # Fallback to cn=CAcert,cn=ipa,cn=etc,SUFFIX -+ dn = DN(('cn', 'CAcert'), config_dn) -+ entry = ldap.get_entry(dn, ['cACertificate;binary']) -+ -+ cert = entry.single_value['cACertificate;binary'] -+ try: -+ subject, issuer_serial, public_key_info = _parse_cert(cert) -+ except ValueError: -+ pass -+ else: -+ if filter_subject is not None and subject not in filter_subject: -+ raise errors.NotFound(reason="no matching entry found") - -- nickname = get_ca_nickname(compat_realm) -- ext_key_usage = {x509.EKU_SERVER_AUTH} -- if compat_ipa_ca: -- ext_key_usage |= {x509.EKU_CLIENT_AUTH, -- x509.EKU_EMAIL_PROTECTION, -- x509.EKU_CODE_SIGNING} -+ if compat_ipa_ca: -+ ca_subject = subject -+ else: -+ ca_subject = None -+ certs = make_compat_ca_certs([cert], compat_realm, ca_subject) - -- return [(cert, nickname, True, ext_key_usage)] -+ if certs: -+ return certs -+ else: -+ raise errors.NotFound(reason="no such entry") - - - def trust_flags_to_key_policy(trust_flags): --- -2.1.0 - diff --git a/SOURCES/0123-vault-add-vault-container-commands.patch b/SOURCES/0123-vault-add-vault-container-commands.patch new file mode 100644 index 0000000..3ea8578 --- /dev/null +++ b/SOURCES/0123-vault-add-vault-container-commands.patch @@ -0,0 +1,364 @@ +From 83bfd97806d3900f62cac007b66cc8daa0c45234 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 25 Aug 2015 19:56:00 +0200 +Subject: [PATCH] vault: add vault container commands + +adds commands: +* vaultcontainer-show [--service |--user |--shared ] +* vaultcontainer-del [--service |--user |--shared ] +* vaultcontainer-add-owner + [--service |--user |--shared ] + [--users ] [--groups ] [--services ] +* vaultcontainer-remove-owner + [--service |--user |--shared ] + [--users ] [--groups ] [--services ] + +https://fedorahosted.org/freeipa/ticket/5250 + +Reviewed-By: Petr Vobornik +--- + API.txt | 53 +++++++++++ + VERSION | 4 +- + ipalib/plugins/vault.py | 243 +++++++++++++++++++++++++++++++++++++++++++----- + 3 files changed, 277 insertions(+), 23 deletions(-) + +diff --git a/API.txt b/API.txt +index 5253e1585e000f39d6e185a94548037dfe54d4d8..4d36a9885157de13529573b3a386b4ef39eba176 100644 +--- a/API.txt ++++ b/API.txt +@@ -5667,6 +5667,59 @@ option: Str('version?', exclude='webui') + output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) + output: Output('summary', (, ), None) + output: PrimaryKey('value', None, None) ++command: vaultcontainer_add_owner ++args: 0,10,3 ++option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') ++option: Str('group*', alwaysask=True, cli_name='groups', csv=True) ++option: Flag('no_members', autofill=True, default=False, exclude='webui') ++option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') ++option: Str('service?') ++option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False) ++option: Flag('shared?', autofill=True, default=False) ++option: Str('user*', alwaysask=True, cli_name='users', csv=True) ++option: Str('username?', cli_name='user') ++option: Str('version?', exclude='webui') ++output: Output('completed', , None) ++output: Output('failed', , None) ++output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) ++command: vaultcontainer_del ++args: 0,5,3 ++option: Flag('continue', autofill=True, cli_name='continue', default=False) ++option: Str('service?') ++option: Flag('shared?', autofill=True, default=False) ++option: Str('username?', cli_name='user') ++option: Str('version?', exclude='webui') ++output: Output('result', , None) ++output: Output('summary', (, ), None) ++output: ListOfPrimaryKeys('value', None, None) ++command: vaultcontainer_remove_owner ++args: 0,10,3 ++option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') ++option: Str('group*', alwaysask=True, cli_name='groups', csv=True) ++option: Flag('no_members', autofill=True, default=False, exclude='webui') ++option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui') ++option: Str('service?') ++option: Str('services', alwaysask=True, cli_name='services', csv=True, multivalue=True, required=False) ++option: Flag('shared?', autofill=True, default=False) ++option: Str('user*', alwaysask=True, cli_name='users', csv=True) ++option: Str('username?', cli_name='user') ++option: Str('version?', exclude='webui') ++output: Output('completed', , None) ++output: Output('failed', , None) ++output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) ++command: vaultcontainer_show ++args: 0,8,3 ++option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui') ++option: Flag('no_members', autofill=True, 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('service?') ++option: Flag('shared?', autofill=True, default=False) ++option: Str('username?', cli_name='user') ++option: Str('version?', exclude='webui') ++output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) ++output: Output('summary', (, ), None) ++output: PrimaryKey('value', None, None) + capability: messages 2.52 + capability: optional_uid_params 2.54 + capability: permissions2 2.69 +diff --git a/VERSION b/VERSION +index da721fdd548023dc3dcd9b4f6a8ba72922a3c6f2..c2b5c87a2615d77e75259edfb8e3a6b7740fac52 100644 +--- a/VERSION ++++ b/VERSION +@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 + # # + ######################################################## + IPA_API_VERSION_MAJOR=2 +-IPA_API_VERSION_MINOR=155 +-# Last change: ftweedal - remove certprofile 'rename' option ++IPA_API_VERSION_MINOR=156 ++# Last change: pvoborni - add vault container commands +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index e369eeee20f5652942681f7c3e268e6173005452..733741dfc2c87995055599cc3816f321ec344496 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -257,6 +257,228 @@ vault_options = ( + ) + + ++class VaultModMember(LDAPModMember): ++ def get_options(self): ++ for param in super(VaultModMember, self).get_options(): ++ if param.name == 'service' and param not in vault_options: ++ param = param.clone_rename('services') ++ yield param ++ ++ def get_member_dns(self, **options): ++ if 'services' in options: ++ options['service'] = options.pop('services') ++ else: ++ options.pop('service', None) ++ return super(VaultModMember, self).get_member_dns(**options) ++ ++ def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): ++ for fail in failed.itervalues(): ++ fail['services'] = fail.pop('service', []) ++ self.obj.get_container_attribute(entry_attrs, options) ++ return completed, dn ++ ++ ++@register() ++class vaultcontainer(LDAPObject): ++ __doc__ = _(""" ++ Vault Container object. ++ """) ++ ++ container_dn = api.env.container_vault ++ ++ object_name = _('vaultcontainer') ++ object_name_plural = _('vaultcontainers') ++ object_class = ['ipaVaultContainer'] ++ ++ attribute_members = { ++ 'owner': ['user', 'group', 'service'], ++ } ++ ++ label = _('Vault Containers') ++ label_singular = _('Vault Container') ++ ++ takes_params = ( ++ Str( ++ 'owner_user?', ++ label=_('Owner users'), ++ ), ++ Str( ++ 'owner_group?', ++ label=_('Owner groups'), ++ ), ++ Str( ++ 'owner_service?', ++ label=_('Owner services'), ++ ), ++ Str( ++ 'owner?', ++ label=_('Failed owners'), ++ ), ++ Str( ++ 'service?', ++ label=_('Vault service'), ++ flags={'virtual_attribute'}, ++ ), ++ Flag( ++ 'shared?', ++ label=_('Shared vault'), ++ flags={'virtual_attribute'}, ++ ), ++ Str( ++ 'username?', ++ label=_('Vault user'), ++ flags={'virtual_attribute'}, ++ ), ++ ) ++ ++ def get_dn(self, *keys, **options): ++ """ ++ Generates vault DN from parameters. ++ """ ++ service = options.get('service') ++ shared = options.get('shared') ++ user = options.get('username') ++ ++ count = (bool(service) + bool(shared) + bool(user)) ++ if count > 1: ++ raise errors.MutuallyExclusiveError( ++ reason=_('Service, shared and user options ' + ++ 'cannot be specified simultaneously')) ++ ++ parent_dn = super(vaultcontainer, self).get_dn(*keys, **options) ++ ++ if not count: ++ principal = getattr(context, 'principal') ++ ++ if principal.startswith('host/'): ++ raise errors.NotImplementedError( ++ reason=_('Host is not supported')) ++ ++ (name, realm) = split_principal(principal) ++ if '/' in name: ++ service = name ++ else: ++ user = name ++ ++ if service: ++ dn = DN(('cn', service), ('cn', 'services'), parent_dn) ++ elif shared: ++ dn = DN(('cn', 'shared'), parent_dn) ++ elif user: ++ dn = DN(('cn', user), ('cn', 'users'), parent_dn) ++ else: ++ raise RuntimeError ++ ++ return dn ++ ++ def get_container_attribute(self, entry, options): ++ if options.get('raw', False): ++ return ++ container_dn = DN(self.container_dn, self.api.env.basedn) ++ if entry.dn.endswith(DN(('cn', 'services'), container_dn)): ++ entry['service'] = entry.dn[0]['cn'] ++ elif entry.dn.endswith(DN(('cn', 'shared'), container_dn)): ++ entry['shared'] = True ++ elif entry.dn.endswith(DN(('cn', 'users'), container_dn)): ++ entry['username'] = entry.dn[0]['cn'] ++ ++ ++@register() ++class vaultcontainer_show(LDAPRetrieve): ++ __doc__ = _('Display information about a vault container.') ++ ++ takes_options = LDAPRetrieve.takes_options + vault_options ++ ++ has_output_params = LDAPRetrieve.has_output_params ++ ++ def pre_callback(self, ldap, dn, attrs_list, *keys, **options): ++ assert isinstance(dn, DN) ++ ++ if not self.api.Command.kra_is_enabled()['result']: ++ raise errors.InvocationError( ++ format=_('KRA service is not enabled')) ++ ++ return dn ++ ++ def post_callback(self, ldap, dn, entry_attrs, *keys, **options): ++ self.obj.get_container_attribute(entry_attrs, options) ++ return dn ++ ++ ++@register() ++class vaultcontainer_del(LDAPDelete): ++ __doc__ = _('Delete a vault container.') ++ ++ takes_options = LDAPDelete.takes_options + vault_options ++ ++ msg_summary = _('Deleted vault container') ++ ++ subtree_delete = False ++ ++ def pre_callback(self, ldap, dn, *keys, **options): ++ assert isinstance(dn, DN) ++ ++ if not self.api.Command.kra_is_enabled()['result']: ++ raise errors.InvocationError( ++ format=_('KRA service is not enabled')) ++ ++ return dn ++ ++ def execute(self, *keys, **options): ++ keys = keys + (u'',) ++ return super(vaultcontainer_del, self).execute(*keys, **options) ++ ++ ++@register() ++class vaultcontainer_add_owner(VaultModMember, LDAPAddMember): ++ __doc__ = _('Add owners to a vault container.') ++ ++ takes_options = LDAPAddMember.takes_options + vault_options ++ ++ member_attributes = ['owner'] ++ member_param_label = _('owner %s') ++ member_count_out = ('%i owner added.', '%i owners added.') ++ ++ has_output = ( ++ output.Entry('result'), ++ output.Output( ++ 'failed', ++ type=dict, ++ doc=_('Owners that could not be added'), ++ ), ++ output.Output( ++ 'completed', ++ type=int, ++ doc=_('Number of owners added'), ++ ), ++ ) ++ ++ ++@register() ++class vaultcontainer_remove_owner(VaultModMember, LDAPRemoveMember): ++ __doc__ = _('Remove owners from a vault container.') ++ ++ takes_options = LDAPRemoveMember.takes_options + vault_options ++ ++ member_attributes = ['owner'] ++ member_param_label = _('owner %s') ++ member_count_out = ('%i owner removed.', '%i owners removed.') ++ ++ has_output = ( ++ output.Entry('result'), ++ output.Output( ++ 'failed', ++ type=dict, ++ doc=_('Owners that could not be removed'), ++ ), ++ output.Output( ++ 'completed', ++ type=int, ++ doc=_('Number of owners removed'), ++ ), ++ ) ++ ++ + @register() + class vault(LDAPObject): + __doc__ = _(""" +@@ -1729,27 +1951,6 @@ class vault_retrieve_internal(PKQuery): + return response + + +-class VaultModMember(LDAPModMember): +- def get_options(self): +- for param in super(VaultModMember, self).get_options(): +- if param.name == 'service' and param not in vault_options: +- param = param.clone_rename('services') +- yield param +- +- def get_member_dns(self, **options): +- if 'services' in options: +- options['service'] = options.pop('services') +- else: +- options.pop('service', None) +- return super(VaultModMember, self).get_member_dns(**options) +- +- def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): +- for fail in failed.itervalues(): +- fail['services'] = fail.pop('service', []) +- self.obj.get_container_attribute(entry_attrs, options) +- return completed, dn +- +- + @register() + class vault_add_owner(VaultModMember, LDAPAddMember): + __doc__ = _('Add owners to a vault.') +-- +2.4.3 + diff --git a/SOURCES/0124-client-install-Do-not-crash-on-invalid-CA-certificat.patch b/SOURCES/0124-client-install-Do-not-crash-on-invalid-CA-certificat.patch deleted file mode 100644 index c3f097b..0000000 --- a/SOURCES/0124-client-install-Do-not-crash-on-invalid-CA-certificat.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 175dbfb667a9989593eaef2f35586d2afbfdc66c Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 17 Mar 2015 09:29:21 +0000 -Subject: [PATCH] client-install: Do not crash on invalid CA certificate in - LDAP - -When CA certificates in LDAP are corrupted, use the otherwise acquired CA -certificates from before. - -https://fedorahosted.org/freeipa/ticket/4565 - -Reviewed-By: David Kupka ---- - ipa-client/ipa-install/ipa-client-install | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - -diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install -index 75a1711a7e1fdc9359ad02d55ad94d65af51ea93..c60124472005670834496569f550f0ffd986aa27 100755 ---- a/ipa-client/ipa-install/ipa-client-install -+++ b/ipa-client/ipa-install/ipa-client-install -@@ -2585,14 +2585,15 @@ def install(options, env, fstore, statestore): - except ValueError: - pass - -+ ca_certs = x509.load_certificate_list_from_file(CACERT) -+ ca_certs = [cert.der_data for cert in ca_certs] -+ - with certdb.NSSDatabase() as tmp_db: - # Add CA certs to a temporary NSS database - try: - pwd_file = ipautil.write_tmp_file(ipautil.ipa_generate_password()) - tmp_db.create_db(pwd_file.name) - -- ca_certs = x509.load_certificate_list_from_file(CACERT) -- ca_certs = [cert.der_data for cert in ca_certs] - for i, cert in enumerate(ca_certs): - tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), 'C,,') - except CalledProcessError, e: -@@ -2665,8 +2666,16 @@ def install(options, env, fstore, statestore): - return CLIENT_INSTALL_ERROR - - # Get CA certificates from the certificate store -- ca_certs = get_certs_from_ldap(cli_server[0], cli_basedn, cli_realm, -- ca_enabled) -+ try: -+ ca_certs = get_certs_from_ldap(cli_server[0], cli_basedn, cli_realm, -+ ca_enabled) -+ except errors.NoCertificateError: -+ if ca_enabled: -+ ca_subject = DN(('CN', 'Certificate Authority'), subject_base) -+ else: -+ ca_subject = None -+ ca_certs = certstore.make_compat_ca_certs(ca_certs, cli_realm, -+ ca_subject) - ca_certs_trust = [(c, n, certstore.key_policy_to_trust_flags(t, True, u)) - for (c, n, t, u) in ca_certs] - --- -2.1.0 - diff --git a/SOURCES/0124-vault-set-owner-to-current-user-on-container-creatio.patch b/SOURCES/0124-vault-set-owner-to-current-user-on-container-creatio.patch new file mode 100644 index 0000000..5c92146 --- /dev/null +++ b/SOURCES/0124-vault-set-owner-to-current-user-on-container-creatio.patch @@ -0,0 +1,50 @@ +From 8defa7ddd68ade04f71254fc86762ac235721cce Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 3 Sep 2015 08:46:59 +0200 +Subject: [PATCH] vault: set owner to current user on container creation + +This reverts commit 419754b1c11139435ae5b5082a51026da0d5e730. + +https://fedorahosted.org/freeipa/ticket/5250 + +Reviewed-By: Petr Vobornik +--- + ipalib/plugins/vault.py | 21 +-------------------- + 1 file changed, 1 insertion(+), 20 deletions(-) + +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 733741dfc2c87995055599cc3816f321ec344496..d9551c2f0cfc16973131c61db45bc606d2844fb6 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -981,27 +981,8 @@ class vault_add_internal(LDAPCreate): + + parent_dn = DN(*dn[1:]) + +- container_dn = DN(self.api.Object.vault.container_dn, +- self.api.env.basedn) +- +- services_dn = DN(('cn', 'services'), container_dn) +- users_dn = DN(('cn', 'users'), container_dn) +- +- if dn.endswith(services_dn): +- # service container should be owned by the service +- service = parent_dn[0]['cn'] +- parent_owner_dn = self.api.Object.service.get_dn(service) +- +- elif dn.endswith(users_dn): +- # user container should be owned by the user +- user = parent_dn[0]['cn'] +- parent_owner_dn = self.api.Object.user.get_dn(user) +- +- else: +- parent_owner_dn = owner_dn +- + try: +- self.obj.create_container(parent_dn, parent_owner_dn) ++ self.obj.create_container(parent_dn, owner_dn) + except errors.DuplicateEntry as e: + pass + +-- +2.4.3 + diff --git a/SOURCES/0125-client-Fix-ca_is_enabled-calls.patch b/SOURCES/0125-client-Fix-ca_is_enabled-calls.patch deleted file mode 100644 index f5f8d22..0000000 --- a/SOURCES/0125-client-Fix-ca_is_enabled-calls.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 424b8c73fa0c92ea8befe6e918c0bcaee384ed6b Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 17 Mar 2015 09:35:49 +0000 -Subject: [PATCH] client: Fix ca_is_enabled calls - -The command was added in API version 2.107. Old IPA servers may crash with -NetworkError on ca_is_enabled, handle this case gracefully. - -https://fedorahosted.org/freeipa/ticket/4565 - -Reviewed-By: David Kupka ---- - ipa-client/ipa-install/ipa-client-install | 4 ++-- - ipa-client/ipaclient/ipa_certupdate.py | 4 ++-- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install -index c60124472005670834496569f550f0ffd986aa27..b7b3d05b6b6d1c9635084e0c01aa7443bb559db2 100755 ---- a/ipa-client/ipa-install/ipa-client-install -+++ b/ipa-client/ipa-install/ipa-client-install -@@ -2645,10 +2645,10 @@ def install(options, env, fstore, statestore): - try: - result = api.Backend.rpcclient.forward( - 'ca_is_enabled', -- version=u'2.0', -+ version=u'2.107', - ) - ca_enabled = result['result'] -- except errors.CommandError: -+ except (errors.CommandError, errors.NetworkError): - result = api.Backend.rpcclient.forward( - 'env', - server=True, -diff --git a/ipa-client/ipaclient/ipa_certupdate.py b/ipa-client/ipaclient/ipa_certupdate.py -index 031a34c3a54a02d43978eedcb794678a1550702b..5ec5026f5ff7bf93227ce0a551fbf5cf60b9175d 100644 ---- a/ipa-client/ipaclient/ipa_certupdate.py -+++ b/ipa-client/ipaclient/ipa_certupdate.py -@@ -63,10 +63,10 @@ class CertUpdate(admintool.AdminTool): - try: - result = api.Backend.rpcclient.forward( - 'ca_is_enabled', -- version=u'2.0', -+ version=u'2.107', - ) - ca_enabled = result['result'] -- except errors.CommandError: -+ except (errors.CommandError, errors.NetworkError): - result = api.Backend.rpcclient.forward( - 'env', - server=True, --- -2.1.0 - diff --git a/SOURCES/0125-vault-update-access-control.patch b/SOURCES/0125-vault-update-access-control.patch new file mode 100644 index 0000000..7351dab --- /dev/null +++ b/SOURCES/0125-vault-update-access-control.patch @@ -0,0 +1,51 @@ +From a2f2794513b30bb6b2cbdf96872e5d5904bf114d Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 3 Sep 2015 09:02:41 +0200 +Subject: [PATCH] vault: update access control + +Do not allow vault and container owners to manage owners. Allow adding vaults +and containers only if owner is set to the current user. + +https://fedorahosted.org/freeipa/ticket/5250 + +Reviewed-By: Petr Vobornik +--- + install/share/vault.update | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/install/share/vault.update b/install/share/vault.update +index 14421b5189efe9b3d9491e845e74debca6e18941..4f0023840b34c2d2bae4e362e34be1764c430ad1 100644 +--- a/install/share/vault.update ++++ b/install/share/vault.update +@@ -7,14 +7,20 @@ dn: cn=vaults,cn=kra,$SUFFIX + default: objectClass: top + default: objectClass: ipaVaultContainer + default: cn: vaults +-default: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(version 3.0; acl "Allow users to create private container"; allow (add) userdn = "ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX";) +-default: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(version 3.0; acl "Allow services to create private container"; allow (add) userdn = "ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#GROUPDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect vault members can access the vault"; allow(read, search, compare) userattr="member#GROUPDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault owners can manage the vault"; allow(read, search, compare, write) userattr="owner#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect vault owners can manage the vault"; allow(read, search, compare, write) userattr="owner#GROUPDN";) ++default: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow users to create private container"; allow(add) userdn="ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) ++default: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow services to create private container"; allow(add) userdn="ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) ++default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Container owners can access the container"; allow(read, search, compare) userattr="owner#USERDN";) ++default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Indirect container owners can access the container"; allow(read, search, compare) userattr="owner#GROUPDN";) ++default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Container owners can manage the container"; allow(write, delete) userattr="owner#USERDN";) ++default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Indirect container owners can manage the container"; allow(write, delete) userattr="owner#GROUPDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(version 3.0; acl "Container owners can add vaults in the container"; allow(add) userattr="parent[1].owner#USERDN" and userattr="owner#SELFDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(version 3.0; acl "Indirect container owners can add vaults in the container"; allow(add) userattr="parent[1].owner#GROUPDN" and userattr="owner#SELFDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Vault owners can access the vault"; allow(read, search, compare) userattr="owner#USERDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Indirect vault owners can access the vault"; allow(read, search, compare) userattr="owner#GROUPDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Indirect vault members can access the vault"; allow(read, search, compare) userattr="member#GROUPDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || member")(version 3.0; acl "Vault owners can manage the vault"; allow(write, delete) userattr="owner#USERDN";) ++default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || member")(version 3.0; acl "Indirect vault owners can manage the vault"; allow(write, delete) userattr="owner#GROUPDN";) + + dn: cn=services,cn=vaults,cn=kra,$SUFFIX + default: objectClass: top +-- +2.4.3 + diff --git a/SOURCES/0126-upload_cacrt-Fix-empty-cACertificate-in-cn-CAcert.patch b/SOURCES/0126-upload_cacrt-Fix-empty-cACertificate-in-cn-CAcert.patch deleted file mode 100644 index 6435cfd..0000000 --- a/SOURCES/0126-upload_cacrt-Fix-empty-cACertificate-in-cn-CAcert.patch +++ /dev/null @@ -1,106 +0,0 @@ -From e6bdbe215ae3fba629eea69e4413c44fea7cd02b Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 17 Mar 2015 08:23:40 +0000 -Subject: [PATCH] upload_cacrt: Fix empty cACertificate in cn=CAcert - -https://fedorahosted.org/freeipa/ticket/4565 - -Reviewed-By: David Kupka ---- - ipaserver/install/plugins/upload_cacrt.py | 54 +++++++++++++++++-------------- - 1 file changed, 30 insertions(+), 24 deletions(-) - -diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py -index 66270ae7613e935fc8df4bc90aa5001296e1c06d..4d5ce52d4073660fc0c1c1ba09e993b250e11fcb 100644 ---- a/ipaserver/install/plugins/upload_cacrt.py -+++ b/ipaserver/install/plugins/upload_cacrt.py -@@ -20,7 +20,7 @@ - from ipaserver.install.plugins import MIDDLE - from ipaserver.install.plugins.baseupdate import PostUpdate - from ipaserver.install import certs --from ipalib import api, certstore -+from ipalib import api, errors, certstore - from ipapython import certdb - from ipapython.dn import DN - -@@ -45,7 +45,7 @@ class update_upload_cacrt(PostUpdate): - if ca_chain: - ca_nickname = ca_chain[-1] - -- updates = {} -+ ldap = self.obj.backend - - for nickname, trust_flags in db.list_certs(): - if 'u' in trust_flags: -@@ -53,40 +53,46 @@ class update_upload_cacrt(PostUpdate): - if nickname == ca_nickname and ca_enabled: - trust_flags = 'CT,C,C' - cert = db.get_cert_from_db(nickname, pem=False) -+ trust, ca, eku = certstore.trust_flags_to_key_policy(trust_flags) -+ -+ dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), -+ ('cn','etc'), self.api.env.basedn) -+ entry = ldap.make_entry(dn) -+ - try: -- dn, entry = self._make_entry(cert, nickname, trust_flags) -+ certstore.init_ca_entry(entry, cert, nickname, trust, eku) - except Exception, e: - self.log.warning("Failed to create entry for %s: %s", - nickname, e) - continue - if nickname == ca_nickname: - ca_cert = cert -+ config = entry.setdefault('ipaConfigString', []) - if ca_enabled: -- entry.append('ipaConfigString:ipaCA') -- entry.append('ipaConfigString:compatCA') -- updates[dn] = {'dn': dn, 'default': entry} -+ config.append('ipaCa') -+ config.append('ipaCa') -+ -+ try: -+ ldap.add_entry(entry) -+ except errors.DuplicateEntry: -+ pass - - if ca_cert: - dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn','etc'), - self.api.env.basedn) -- entry = ['objectclass:nsContainer', -- 'objectclass:pkiCA', -- 'cn:CAcert', -- 'cACertificate;binary:%s' % ca_cert, -- ] -- updates[dn] = {'dn': dn, 'default': entry} -- -- return (False, True, [updates]) -- -- def _make_entry(self, cert, nickname, trust_flags): -- dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'), -- ('cn','etc'), self.api.env.basedn) -- -- entry = dict() -- trust, ca, eku = certstore.trust_flags_to_key_policy(trust_flags) -- certstore.init_ca_entry(entry, cert, nickname, trust, eku) -- entry = ['%s:%s' % (a, v) for a, vs in entry.iteritems() for v in vs] -+ try: -+ entry = ldap.get_entry(dn) -+ except errors.NotFound: -+ entry = ldap.make_entry(dn) -+ entry['objectclass'] = ['nsContainer', 'pkiCA'] -+ entry.single_value['cn'] = 'CAcert' -+ entry.single_value['cACertificate;binary'] = ca_cert -+ ldap.add_entry(entry) -+ else: -+ if '' in entry['cACertificate;binary']: -+ entry.single_value['cACertificate;binary'] = ca_cert -+ ldap.update_entry(entry) - -- return dn, entry -+ return (False, False, []) - - api.register(update_upload_cacrt) --- -2.1.0 - diff --git a/SOURCES/0126-vault-add-permissions-and-administrator-privilege.patch b/SOURCES/0126-vault-add-permissions-and-administrator-privilege.patch new file mode 100644 index 0000000..1686d3b --- /dev/null +++ b/SOURCES/0126-vault-add-permissions-and-administrator-privilege.patch @@ -0,0 +1,196 @@ +From abcc2cbec338d22d86bd64f1af89e780cdad5a9f Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 3 Sep 2015 09:32:11 +0200 +Subject: [PATCH] vault: add permissions and administrator privilege + +https://fedorahosted.org/freeipa/ticket/5250 + +Reviewed-By: Petr Vobornik +--- + ACI.txt | 22 ++++++++ + install/updates/40-delegation.update | 8 +++ + ipalib/plugins/vault.py | 98 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 128 insertions(+) + +diff --git a/ACI.txt b/ACI.txt +index 99099275e1383f16aca122e05e34b2330f4d06a3..40fa822217eaee8d0966491b10cdf7e0739a87ce 100644 +--- a/ACI.txt ++++ b/ACI.txt +@@ -338,6 +338,28 @@ dn: cn=users,cn=accounts,dc=ipa,dc=example + aci: (targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Remove Users";allow (delete) groupdn = "ldap:///cn=System: Remove Users,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=users,cn=accounts,dc=ipa,dc=example + aci: (targetattr = "krblastadminunlock || krbloginfailedcount || nsaccountlock")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "permission:System: Unlock User";allow (write) groupdn = "ldap:///cn=System: Unlock User,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVault)")(version 3.0;acl "permission:System: Add Vaults";allow (add) groupdn = "ldap:///cn=System: Add Vaults,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVault)")(version 3.0;acl "permission:System: Delete Vaults";allow (delete) groupdn = "ldap:///cn=System: Delete Vaults,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "member")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVault)")(version 3.0;acl "permission:System: Manage Vault Membership";allow (write) groupdn = "ldap:///cn=System: Manage Vault Membership,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "owner")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVault)")(version 3.0;acl "permission:System: Manage Vault Ownership";allow (write) groupdn = "ldap:///cn=System: Manage Vault Ownership,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "cn || description || ipavaultpublickey || ipavaultsalt || ipavaulttype || objectclass")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVault)")(version 3.0;acl "permission:System: Modify Vaults";allow (write) groupdn = "ldap:///cn=System: Modify Vaults,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "cn || createtimestamp || description || entryusn || ipavaultpublickey || ipavaultsalt || ipavaulttype || member || memberhost || memberuser || modifytimestamp || objectclass || owner")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVault)")(version 3.0;acl "permission:System: Read Vaults";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Vaults,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVaultContainer)")(version 3.0;acl "permission:System: Add Vault Containers";allow (add) groupdn = "ldap:///cn=System: Add Vault Containers,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVaultContainer)")(version 3.0;acl "permission:System: Delete Vault Containers";allow (delete) groupdn = "ldap:///cn=System: Delete Vault Containers,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "owner")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVaultContainer)")(version 3.0;acl "permission:System: Manage Vault Container Ownership";allow (write) groupdn = "ldap:///cn=System: Manage Vault Container Ownership,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "cn || description || objectclass")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVaultContainer)")(version 3.0;acl "permission:System: Modify Vault Containers";allow (write) groupdn = "ldap:///cn=System: Modify Vault Containers,cn=permissions,cn=pbac,dc=ipa,dc=example";) ++dn: dc=ipa,dc=example ++aci: (targetattr = "cn || createtimestamp || description || entryusn || modifytimestamp || objectclass || owner")(target = "ldap:///cn=vaults,cn=kra,dc=ipa,dc=example")(targetfilter = "(objectclass=ipaVaultContainer)")(version 3.0;acl "permission:System: Read Vault Containers";allow (compare,read,search) groupdn = "ldap:///cn=System: Read Vault Containers,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=ca_renewal,cn=ipa,cn=etc,dc=ipa,dc=example + aci: (target = "ldap:///cn=caSigningCert cert-pki-ca,cn=ca_renewal,cn=ipa,cn=etc,dc=ipa,dc=example")(targetfilter = "(objectclass=pkiuser)")(version 3.0;acl "permission:System: Add CA Certificate For Renewal";allow (add) groupdn = "ldap:///cn=System: Add CA Certificate For Renewal,cn=permissions,cn=pbac,dc=ipa,dc=example";) + dn: cn=certificates,cn=ipa,cn=etc,dc=ipa,dc=example +diff --git a/install/updates/40-delegation.update b/install/updates/40-delegation.update +index 8d4f6296cbed7fcc968c2193022cb50b488c8561..08906a663c818695b8af29449c6ce8fab2dfdbee 100644 +--- a/install/updates/40-delegation.update ++++ b/install/updates/40-delegation.update +@@ -260,3 +260,11 @@ default:objectClass: groupofnames + default:objectClass: top + default:cn: CA Administrator + default:description: CA Administrator ++ ++# Vault Administrators ++dn: cn=Vault Administrators,cn=privileges,cn=pbac,$SUFFIX ++default:objectClass: nestedgroup ++default:objectClass: groupofnames ++default:objectClass: top ++default:cn: Vault Administrators ++default:description: Vault Administrators +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index d9551c2f0cfc16973131c61db45bc606d2844fb6..1159a84d58eb152cccdd791c96a1c876754bfa7d 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -289,6 +289,7 @@ class vaultcontainer(LDAPObject): + object_name = _('vaultcontainer') + object_name_plural = _('vaultcontainers') + object_class = ['ipaVaultContainer'] ++ permission_filter_objectclasses = ['ipaVaultContainer'] + + attribute_members = { + 'owner': ['user', 'group', 'service'], +@@ -297,6 +298,48 @@ class vaultcontainer(LDAPObject): + label = _('Vault Containers') + label_singular = _('Vault Container') + ++ managed_permissions = { ++ 'System: Read Vault Containers': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'read', 'search', 'compare'}, ++ 'ipapermdefaultattr': { ++ 'objectclass', 'cn', 'description', 'owner', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Add Vault Containers': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'add'}, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Delete Vault Containers': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'delete'}, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Modify Vault Containers': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'write'}, ++ 'ipapermdefaultattr': { ++ 'objectclass', 'cn', 'description', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Manage Vault Container Ownership': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'write'}, ++ 'ipapermdefaultattr': { ++ 'owner', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ } ++ + takes_params = ( + Str( + 'owner_user?', +@@ -491,6 +534,7 @@ class vault(LDAPObject): + object_name_plural = _('vaults') + + object_class = ['ipaVault'] ++ permission_filter_objectclasses = ['ipaVault'] + default_attributes = [ + 'cn', + 'description', +@@ -513,6 +557,60 @@ class vault(LDAPObject): + label = _('Vaults') + label_singular = _('Vault') + ++ managed_permissions = { ++ 'System: Read Vaults': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'read', 'search', 'compare'}, ++ 'ipapermdefaultattr': { ++ 'objectclass', 'cn', 'description', 'ipavaulttype', ++ 'ipavaultsalt', 'ipavaultpublickey', 'owner', 'member', ++ 'memberuser', 'memberhost', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Add Vaults': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'add'}, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Delete Vaults': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'delete'}, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Modify Vaults': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'write'}, ++ 'ipapermdefaultattr': { ++ 'objectclass', 'cn', 'description', 'ipavaulttype', ++ 'ipavaultsalt', 'ipavaultpublickey', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Manage Vault Ownership': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'write'}, ++ 'ipapermdefaultattr': { ++ 'owner', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ 'System: Manage Vault Membership': { ++ 'ipapermlocation': api.env.basedn, ++ 'ipapermtarget': DN(api.env.container_vault, api.env.basedn), ++ 'ipapermright': {'write'}, ++ 'ipapermdefaultattr': { ++ 'member', ++ }, ++ 'default_privileges': {'Vault Administrators'}, ++ }, ++ } ++ + takes_params = ( + Str( + 'cn', +-- +2.4.3 + diff --git a/SOURCES/0127-install-support-KRA-update.patch b/SOURCES/0127-install-support-KRA-update.patch new file mode 100644 index 0000000..449803d --- /dev/null +++ b/SOURCES/0127-install-support-KRA-update.patch @@ -0,0 +1,213 @@ +From 78eaf8b944f1b8f177aedabeaaeaa72c1dc4091e Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 14 Sep 2015 07:56:44 +0200 +Subject: [PATCH] install: support KRA update + +https://fedorahosted.org/freeipa/ticket/5250 + +Reviewed-By: Petr Vobornik +--- + freeipa.spec.in | 1 - + install/share/Makefile.am | 2 +- + install/share/vault.ldif | 29 +++++++++++++++++++++++++++++ + install/share/vault.update | 38 -------------------------------------- + install/updates/40-vault.update | 23 +++++++++++++++++++++++ + install/updates/Makefile.am | 1 + + ipaplatform/base/paths.py | 1 - + ipaserver/install/krainstance.py | 7 ++++++- + 8 files changed, 60 insertions(+), 42 deletions(-) + create mode 100644 install/share/vault.ldif + delete mode 100644 install/share/vault.update + create mode 100644 install/updates/40-vault.update + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index e9ba596fec1f8d179d4f834485e35a4814db898d..d8e24a5af47fbfca89ccb9c3d07dcfca5a8073d9 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -746,7 +746,6 @@ fi + %{_usr}/share/ipa/copy-schema-to-ca.py* + %{_usr}/share/ipa/*.ldif + %{_usr}/share/ipa/*.uldif +-%{_usr}/share/ipa/*.update + %{_usr}/share/ipa/*.template + %dir %{_usr}/share/ipa/advise + %dir %{_usr}/share/ipa/advise/legacy +diff --git a/install/share/Makefile.am b/install/share/Makefile.am +index 80e959a751a0800c4d56c379a73b68a2f12570d7..d68c40e693a1d86c70d8ccd81ef2c915b2e1f61e 100644 +--- a/install/share/Makefile.am ++++ b/install/share/Makefile.am +@@ -83,7 +83,7 @@ app_DATA = \ + copy-schema-to-ca.py \ + sasl-mapping-fallback.ldif \ + schema-update.ldif \ +- vault.update \ ++ vault.ldif \ + kdcproxy.conf \ + kdcproxy-enable.uldif \ + kdcproxy-disable.uldif \ +diff --git a/install/share/vault.ldif b/install/share/vault.ldif +new file mode 100644 +index 0000000000000000000000000000000000000000..06dd83c5c45bd3143b8374965b9a02d311afdb42 +--- /dev/null ++++ b/install/share/vault.ldif +@@ -0,0 +1,29 @@ ++dn: cn=kra,$SUFFIX ++changetype: add ++objectClass: top ++objectClass: nsContainer ++cn: kra ++ ++dn: cn=vaults,cn=kra,$SUFFIX ++changetype: add ++objectClass: top ++objectClass: ipaVaultContainer ++cn: vaults ++ ++dn: cn=services,cn=vaults,cn=kra,$SUFFIX ++changetype: add ++objectClass: top ++objectClass: ipaVaultContainer ++cn: services ++ ++dn: cn=shared,cn=vaults,cn=kra,$SUFFIX ++changetype: add ++objectClass: top ++objectClass: ipaVaultContainer ++cn: shared ++ ++dn: cn=users,cn=vaults,cn=kra,$SUFFIX ++changetype: add ++objectClass: top ++objectClass: ipaVaultContainer ++cn: users +diff --git a/install/share/vault.update b/install/share/vault.update +deleted file mode 100644 +index 4f0023840b34c2d2bae4e362e34be1764c430ad1..0000000000000000000000000000000000000000 +--- a/install/share/vault.update ++++ /dev/null +@@ -1,38 +0,0 @@ +-dn: cn=kra,$SUFFIX +-default: objectClass: top +-default: objectClass: nsContainer +-default: cn: kra +- +-dn: cn=vaults,cn=kra,$SUFFIX +-default: objectClass: top +-default: objectClass: ipaVaultContainer +-default: cn: vaults +-default: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow users to create private container"; allow(add) userdn="ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) +-default: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow services to create private container"; allow(add) userdn="ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) +-default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Container owners can access the container"; allow(read, search, compare) userattr="owner#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Indirect container owners can access the container"; allow(read, search, compare) userattr="owner#GROUPDN";) +-default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Container owners can manage the container"; allow(write, delete) userattr="owner#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Indirect container owners can manage the container"; allow(write, delete) userattr="owner#GROUPDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(version 3.0; acl "Container owners can add vaults in the container"; allow(add) userattr="parent[1].owner#USERDN" and userattr="owner#SELFDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(version 3.0; acl "Indirect container owners can add vaults in the container"; allow(add) userattr="parent[1].owner#GROUPDN" and userattr="owner#SELFDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Vault owners can access the vault"; allow(read, search, compare) userattr="owner#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Indirect vault owners can access the vault"; allow(read, search, compare) userattr="owner#GROUPDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Indirect vault members can access the vault"; allow(read, search, compare) userattr="member#GROUPDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || member")(version 3.0; acl "Vault owners can manage the vault"; allow(write, delete) userattr="owner#USERDN";) +-default: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || member")(version 3.0; acl "Indirect vault owners can manage the vault"; allow(write, delete) userattr="owner#GROUPDN";) +- +-dn: cn=services,cn=vaults,cn=kra,$SUFFIX +-default: objectClass: top +-default: objectClass: ipaVaultContainer +-default: cn: services +- +-dn: cn=shared,cn=vaults,cn=kra,$SUFFIX +-default: objectClass: top +-default: objectClass: ipaVaultContainer +-default: cn: shared +- +-dn: cn=users,cn=vaults,cn=kra,$SUFFIX +-default: objectClass: top +-default: objectClass: ipaVaultContainer +-default: cn: users +diff --git a/install/updates/40-vault.update b/install/updates/40-vault.update +new file mode 100644 +index 0000000000000000000000000000000000000000..3daea5b1988333d4d482463af0eec4163e4f0760 +--- /dev/null ++++ b/install/updates/40-vault.update +@@ -0,0 +1,23 @@ ++dn: cn=vaults,cn=kra,$SUFFIX ++remove: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(version 3.0; acl "Allow users to create private container"; allow (add) userdn = "ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX";) ++remove: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(version 3.0; acl "Allow services to create private container"; allow (add) userdn = "ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX";) ++remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#USERDN";) ++remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect container owners can manage vaults in the container"; allow(read, search, compare, add, delete) userattr="parent[1].owner#GROUPDN";) ++remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";) ++remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect vault members can access the vault"; allow(read, search, compare) userattr="member#GROUPDN";) ++remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault owners can manage the vault"; allow(read, search, compare, write) userattr="owner#USERDN";) ++remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect vault owners can manage the vault"; allow(read, search, compare, write) userattr="owner#GROUPDN";) ++addifexist: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow users to create private container"; allow(add) userdn="ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) ++addifexist: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow services to create private container"; allow(add) userdn="ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Container owners can access the container"; allow(read, search, compare) userattr="owner#USERDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Indirect container owners can access the container"; allow(read, search, compare) userattr="owner#GROUPDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Container owners can manage the container"; allow(write, delete) userattr="owner#USERDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Indirect container owners can manage the container"; allow(write, delete) userattr="owner#GROUPDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(version 3.0; acl "Container owners can add vaults in the container"; allow(add) userattr="parent[1].owner#USERDN" and userattr="owner#SELFDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(version 3.0; acl "Indirect container owners can add vaults in the container"; allow(add) userattr="parent[1].owner#GROUPDN" and userattr="owner#SELFDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Vault owners can access the vault"; allow(read, search, compare) userattr="owner#USERDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Indirect vault owners can access the vault"; allow(read, search, compare) userattr="owner#GROUPDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Vault members can access the vault"; allow(read, search, compare) userattr="member#USERDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || owner || member")(version 3.0; acl "Indirect vault members can access the vault"; allow(read, search, compare) userattr="member#GROUPDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || member")(version 3.0; acl "Vault owners can manage the vault"; allow(write, delete) userattr="owner#USERDN";) ++addifexist: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="objectClass || cn || description || ipaVaultType || ipaVaultSalt || ipaVaultPublicKey || member")(version 3.0; acl "Indirect vault owners can manage the vault"; allow(write, delete) userattr="owner#GROUPDN";) +diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am +index 1f4a91c9bb4222f99ad7a7ad16e376aeef7f525b..26e4c04ed66a4a2061a3bb3ca2f4a6cd84502598 100644 +--- a/install/updates/Makefile.am ++++ b/install/updates/Makefile.am +@@ -34,6 +34,7 @@ app_DATA = \ + 40-automember.update \ + 40-certprofile.update \ + 40-otp.update \ ++ 40-vault.update \ + 41-caacl.update \ + 45-roles.update \ + 50-7_bit_check.update \ +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index ff75e0d7a5a0250ce71e67b0302bbaab64c5e935..3930c93fcba06959dd34507ecc29f92e33637775 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -251,7 +251,6 @@ class BasePathNamespace(object): + SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/schema_compat.uldif" + IPA_JS_PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins" + UPDATES_DIR = "/usr/share/ipa/updates/" +- VAULT_UPDATE = "/usr/share/ipa/vault.update" + PKI_CONF_SERVER_XML_TEMPLATE = "/usr/share/pki/%s/conf/server.xml" + CACHE_IPA_SESSIONS = "/var/cache/ipa/sessions" + VAR_KERBEROS_KRB5KDC_DIR = "/var/kerberos/krb5kdc/" +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 958fe6fb095e69f83342ce8299d1586b8bbacd47..48268b0be5331cced1aee6b7f3358333b65de6dd 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -124,6 +124,7 @@ class KRAInstance(DogtagInstance): + self.step("configure HTTP to proxy connections", + self.http_proxy) + self.step("add vault container", self.__add_vault_container) ++ self.step("apply LDAP updates", self.__apply_updates) + + self.start_creation(runtime=126) + +@@ -313,13 +314,17 @@ class KRAInstance(DogtagInstance): + conn.disconnect() + + def __add_vault_container(self): ++ self._ldap_mod('vault.ldif', {'SUFFIX': self.suffix}) ++ self.ldap_disconnect() ++ ++ def __apply_updates(self): + sub_dict = { + 'SUFFIX': self.suffix, + } + + ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password, + sub_dict=sub_dict) +- ld.update([paths.VAULT_UPDATE]) ++ ld.update([os.path.join(paths.UPDATES_DIR, '40-vault.update')]) + + @staticmethod + def update_cert_config(nickname, cert, dogtag_constants=None): +-- +2.4.3 + diff --git a/SOURCES/0127-ipa-kdb-use-proper-memory-chunk-size-when-moving-sid.patch b/SOURCES/0127-ipa-kdb-use-proper-memory-chunk-size-when-moving-sid.patch deleted file mode 100644 index f1497b5..0000000 --- a/SOURCES/0127-ipa-kdb-use-proper-memory-chunk-size-when-moving-sid.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 3a4057a37254d6dbb0191da32cd110f7cd50d4e4 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 20 May 2015 18:24:52 +0300 -Subject: [PATCH] ipa-kdb: use proper memory chunk size when moving sids - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1222475 -Reviewed-By: Tomas Babej ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 20 +++++++++++++++++--- - 1 file changed, 17 insertions(+), 3 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index e3215db4ea11632dce8f039fc6b89c4a09acd87a..74ee2f3fd4b81bd3433c9ff9c77f7434b72e7f4d 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -1397,7 +1397,15 @@ static krb5_error_code filter_logon_info(krb5_context context, - if (result) { - filter_logon_info_log_message(info->info->info3.sids[i].sid); - } else { -+ /* Go over incoming SID blacklist */ - for(k = 0; k < domain->len_sid_blacklist_incoming; k++) { -+ /* if SID is an exact match, filter it out */ -+ result = dom_sid_check(&domain->sid_blacklist_incoming[k], info->info->info3.sids[i].sid, true); -+ if (result) { -+ filter_logon_info_log_message(info->info->info3.sids[i].sid); -+ break; -+ } -+ /* if SID is a suffix of the blacklist element, filter it out*/ - result = dom_sid_is_prefix(&domain->sid_blacklist_incoming[k], info->info->info3.sids[i].sid); - if (result) { - filter_logon_info_log_message(info->info->info3.sids[i].sid); -@@ -1406,11 +1414,17 @@ static krb5_error_code filter_logon_info(krb5_context context, - } - } - if (result) { -+ k = count - i - j - 1; -+ if (k != 0) { -+ memmove(info->info->info3.sids+i, -+ info->info->info3.sids+i+1, -+ sizeof(struct netr_SidAttr)*k); -+ } - j++; -- memmove(info->info->info3.sids+i, info->info->info3.sids+i+1, count-i-1); -+ } else { -+ i++; - } -- i++; -- } while (i < count); -+ } while ((i + j) < count); - - if (j != 0) { - count = count-j; --- -2.1.0 - diff --git a/SOURCES/0128-ipa-kdb-filter-out-group-membership-from-MS-PAC-for-.patch b/SOURCES/0128-ipa-kdb-filter-out-group-membership-from-MS-PAC-for-.patch deleted file mode 100644 index 18009ed..0000000 --- a/SOURCES/0128-ipa-kdb-filter-out-group-membership-from-MS-PAC-for-.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 32b7c1d012a0904420edc61bf94be66253a6c84a Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 28 May 2015 08:33:51 +0000 -Subject: [PATCH] ipa-kdb: filter out group membership from MS-PAC for exact - SID matches too - -When incoming SID blacklist contains exact SIDs of users and groups, -attempt to filter them out as well, according to [MS-PAC] 4.1.1.2. - -Note that we treat user's SID and primary group RID filtering as violation -of the KDC policy because the resulting MS-PAC will have no user SID or -primary group and thus will be invalid. - -For group RIDs we filter them out. According to [MS-KILE] 3.3.5.6.3.1 -it is OK to have empty group RIDs array as GroupCount SHOULD be -equal to Groups.MembershipCount returned by SamrGetGroupsForUser -[MS-SAMR] 3.1.5.9.1, not MUST, thus it may be empty. - -Part of fix for https://bugzilla.redhat.com/show_bug.cgi?id=1222475 - -Reviewed-By: Tomas Babej ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 100 +++++++++++++++++++++++++++++++++++++++- - 1 file changed, 99 insertions(+), 1 deletion(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 74ee2f3fd4b81bd3433c9ff9c77f7434b72e7f4d..3e6024f55071e95c6d40869e31d879baf627a3b9 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -1320,6 +1320,22 @@ static void filter_logon_info_log_message(struct dom_sid *sid) - } - } - -+static void filter_logon_info_log_message_rid(struct dom_sid *sid, uint32_t rid) -+{ -+ char *domstr = NULL; -+ -+ domstr = dom_sid_string(NULL, sid); -+ if (domstr) { -+ krb5_klog_syslog(LOG_ERR, "PAC filtering issue: SID [%s-%d] is not allowed " -+ "from a trusted source and will be excluded.", domstr, rid); -+ talloc_free(domstr); -+ } else { -+ krb5_klog_syslog(LOG_ERR, "PAC filtering issue: SID is not allowed " -+ "from a trusted source and will be excluded." -+ "Unable to allocate memory to display SID."); -+ } -+} -+ - static krb5_error_code filter_logon_info(krb5_context context, - TALLOC_CTX *memctx, - krb5_data realm, -@@ -1331,9 +1347,21 @@ static krb5_error_code filter_logon_info(krb5_context context, - * attempt at getting us to sign fake credentials with the help of a - * compromised trusted realm */ - -+ /* NOTE: there are two outcomes from filtering: -+ * REJECT TICKET -- ticket is rejected if domain SID of -+ * the principal with MS-PAC is filtered out or -+ * its primary group RID is filtered out -+ * -+ * REMOVE SID -- SIDs are removed from the list of SIDs associated -+ * with the principal if they are filtered out -+ * This applies also to secondary RIDs of the principal -+ * if domain_sid- is filtered out -+ */ -+ - struct ipadb_context *ipactx; - struct ipadb_adtrusts *domain; -- int i, j, k, count; -+ int i, j, k, l, count; -+ uint32_t rid; - bool result; - char *domstr = NULL; - -@@ -1380,6 +1408,76 @@ static krb5_error_code filter_logon_info(krb5_context context, - } - } - -+ /* Check if this user's SIDs membership is filtered too */ -+ for(k = 0; k < domain->len_sid_blacklist_incoming; k++) { -+ /* Short-circuit if there are no RIDs. This may happen if we filtered everything already. -+ * In normal situation there would be at least primary gid as RID in the RIDs array -+ * but if we filtered out the primary RID, this MS-PAC is invalid */ -+ count = info->info->info3.base.groups.count; -+ result = dom_sid_is_prefix(info->info->info3.base.domain_sid, -+ &domain->sid_blacklist_incoming[k]); -+ if (result) { -+ i = 0; -+ j = 0; -+ if (domain->sid_blacklist_incoming[k].num_auths - info->info->info3.base.domain_sid->num_auths != 1) { -+ krb5_klog_syslog(LOG_ERR, "Incoming SID blacklist element matching domain [%s with SID %s] " -+ "has more than one RID component. Invalid check skipped.", -+ domain->domain_name, domain->domain_sid); -+ break; -+ } -+ rid = domain->sid_blacklist_incoming[k].sub_auths[domain->sid_blacklist_incoming[k].num_auths - 1]; -+ if (rid == info->info->info3.base.rid) { -+ filter_logon_info_log_message_rid(info->info->info3.base.domain_sid, rid); -+ /* Actual user's SID is filtered out */ -+ return KRB5KDC_ERR_POLICY; -+ } -+ if (rid == info->info->info3.base.primary_gid) { -+ /* User's primary group SID is filtered out */ -+ return KRB5KDC_ERR_POLICY; -+ } -+ if (count == 0) { -+ /* Having checked actual user's SID and primary group SID, and having no other RIDs, -+ * skip checks below and continue to next blacklist element */ -+ continue; -+ } -+ -+ do { -+ if (rid == info->info->info3.base.groups.rids[i].rid) { -+ filter_logon_info_log_message_rid(info->info->info3.base.domain_sid, rid); -+ /* If this is just a non-primary RID, we simply remove it from the array of RIDs */ -+ l = count - i - j - 1; -+ if (l != 0) { -+ memmove(info->info->info3.base.groups.rids+i, -+ info->info->info3.base.groups.rids+i+1, -+ sizeof(struct samr_RidWithAttribute)*l); -+ } -+ j++; -+ } else { -+ i++; -+ } -+ } while ((i + j) < count); -+ -+ if (j != 0) { -+ count = count-j; -+ if (count == 0) { -+ /* All RIDs were filtered out. Unusual but MS-KILE 3.3.5.6.3.1 says SHOULD, not MUST for GroupCount */ -+ info->info->info3.base.groups.count = 0; -+ talloc_free(info->info->info3.base.groups.rids); -+ info->info->info3.base.groups.rids = NULL; -+ } else { -+ info->info->info3.base.groups.rids = talloc_realloc(memctx, -+ info->info->info3.base.groups.rids, -+ struct samr_RidWithAttribute, count); -+ if (!info->info->info3.base.groups.rids) { -+ info->info->info3.base.groups.count = 0; -+ return ENOMEM; -+ } -+ info->info->info3.base.groups.count = count; -+ } -+ } -+ } -+ } -+ - /* According to MS-KILE 25.0, info->info->info3.sids may be non zero, so check - * should include different possibilities into account - * */ --- -2.1.0 - diff --git a/SOURCES/0128-webui-use-manual-Firefox-configuration-for-Firefox-4.patch b/SOURCES/0128-webui-use-manual-Firefox-configuration-for-Firefox-4.patch new file mode 100644 index 0000000..d0ee5e0 --- /dev/null +++ b/SOURCES/0128-webui-use-manual-Firefox-configuration-for-Firefox-4.patch @@ -0,0 +1,130 @@ +From 27f97386a0259a8b12700e5d671a2de86c98661f Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Thu, 17 Sep 2015 17:41:06 +0200 +Subject: [PATCH] webui: use manual Firefox configuration for Firefox >= 40 + +The intended course of action is to show manual configuration in +browserconfig.html instead of configuration with the extension +for versions of Firefox >= 40. + +The reasoning is: +* plan for enterprise environments was not published yet which + forces as to use AMO (addons.mozilla.org) +* with AMO the user experience is worse than a manual configuration + +steps for AMO: +* go to AMO page +* installed the extension +* go back to IPA page +* probably refresh +* click configure +* confirm + +manual config: +* go to about:config +* set network.negotiate-auth.trusted-uris with *domain.name + +https://fedorahosted.org/freeipa/ticket/4906 + +Reviewed-By: Martin Basti +--- + install/html/browserconfig.html | 25 ++++++++++++++++++++++--- + install/html/ffconfig_page.js | 24 +++++++++++++++++++++--- + 2 files changed, 43 insertions(+), 6 deletions(-) + +diff --git a/install/html/browserconfig.html b/install/html/browserconfig.html +index d721a4ad2a3b684a4bf45602584fee78f4613360..9c5cf68211281723e12b518f346aac43c1541cdc 100644 +--- a/install/html/browserconfig.html ++++ b/install/html/browserconfig.html +@@ -69,7 +69,7 @@ +

+

+ +-
++ + +-
++ + ++
++

Step 2

++
    ++
  1. ++ In the address bar of Firefox, type about:config to display the list of current configuration options. ++
  2. ++
  3. ++ In the Filter field, type negotiate to restrict the list of options. ++
  4. ++
  5. ++ Double-click the network.negotiate-auth.trusted-uris entry to display the Enter string value dialog box. ++
  6. ++
  7. ++ Enter the name of the domain against which you want to authenticate, for example, .example.com. ++
  8. ++
++
++ +
+-

Step 4

++ ++

Step 3

+

Return to Web UI

+
+
+diff --git a/install/html/ffconfig_page.js b/install/html/ffconfig_page.js +index 4e59db0aa5424d3c664d3d651843b26b440d50a9..536332ee8358fb007da840b587df92e627dd7b58 100644 +--- a/install/html/ffconfig_page.js ++++ b/install/html/ffconfig_page.js +@@ -87,7 +87,7 @@ + + if (!browser.mozilla) { + $('#wrongbrowser').show(); +- set_enabled(['#step1', '#step2', '#step3'], false); ++ set_enabled(['#step2b'], false); + } else { + // Disable for all version of FF older than 15. Theoretically + // the extension is compatible with version 3.6, 10 and later +@@ -95,8 +95,26 @@ + // resource from chrome.manifest + if (compare_version(browser.version, '15') === -1) { + $('#step2a').show(); +- set_enabled(['#step2', '#step3'], false); +- }// else if (compare_version(version, '15') === -1) { ++ $('#step2').show(); ++ $('#step3').show(); ++ $('#step4header').show(); ++ $('#step3bheader').hide(); ++ set_enabled(['#step2', '#step3', '#step2b'], false); ++ } else if (compare_version(browser.version, '40') === -1) { ++ // FF is > 15 < 40 ++ // show krb extension method ++ $('#step2').show(); ++ $('#step3').show(); ++ $('#step4header').show(); ++ $('#step3bheader').hide(); ++ $('#step2b').hide(); ++ } ++ // else ++ // Firefox since version 40 has new extension signing policy ++ // this policy prevents to use self-signed FF extension and ++ // thus a manual config is needed - which is the default (step2b) ++ ++ // else if (compare_version(version, '15') === -1) { + // $('#step2a').show(); + // $('#older-compatible').show(); + // $('#older-required').hide(); +-- +2.4.3 + diff --git a/SOURCES/0129-ipa-backup-Add-mechanism-to-store-empty-directory-st.patch b/SOURCES/0129-ipa-backup-Add-mechanism-to-store-empty-directory-st.patch new file mode 100644 index 0000000..4425903 --- /dev/null +++ b/SOURCES/0129-ipa-backup-Add-mechanism-to-store-empty-directory-st.patch @@ -0,0 +1,130 @@ +From 9b2593e54f12e28a8f1dc502ddb44cf237f0ddec Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Thu, 17 Sep 2015 17:09:33 +0200 +Subject: [PATCH] ipa-backup: Add mechanism to store empty directory structure + +Certain subcomponents of IPA, such as Dogtag, cannot function if +non-critical directories (such as log directories) have not been +stored in the backup. + +This patch implements storage of selected empty directories, +while preserving attributes and SELinux context. + +https://fedorahosted.org/freeipa/ticket/5297 + +Reviewed-By: Martin Basti +--- + freeipa.spec.in | 1 + + ipaplatform/base/paths.py | 3 +++ + ipaserver/install/ipa_backup.py | 50 ++++++++++++++++++++++++++++++++++++++--- + 3 files changed, 51 insertions(+), 3 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index d8e24a5af47fbfca89ccb9c3d07dcfca5a8073d9..a8515487757556f337a4bbfc1cc14e8fb4707ccd 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -162,6 +162,7 @@ Requires: softhsm >= 2.0.0rc1-1 + Requires: p11-kit + Requires: systemd-python + Requires: %{etc_systemd_dir} ++Requires: gzip + + Conflicts: %{alt_name}-server + Obsoletes: %{alt_name}-server < %{version} +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 3930c93fcba06959dd34507ecc29f92e33637775..97c330c31844fcf19bec2e96bf2b23cba5f7f3f0 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -328,6 +328,9 @@ class BasePathNamespace(object): + TOMCAT_CA_DIR = "/var/log/pki/pki-tomcat/ca" + TOMCAT_CA_ARCHIVE_DIR = "/var/log/pki/pki-tomcat/ca/archive" + TOMCAT_SIGNEDAUDIT_DIR = "/var/log/pki/pki-tomcat/ca/signedAudit" ++ TOMCAT_KRA_DIR = "/var/log/pki/pki-tomcat/kra" ++ TOMCAT_KRA_ARCHIVE_DIR = "/var/log/pki/pki-tomcat/kra/archive" ++ TOMCAT_KRA_SIGNEDAUDIT_DIR = "/var/log/pki/pki-tomcat/kra/signedAudit" + LOG_SECURE = "/var/log/secure" + NAMED_RUN = "/var/named/data/named.run" + VAR_OPENDNSSEC_DIR = "/var/opendnssec" +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 8df1005a222220a0ece95a3691766ed3cd00a0d9..3bd2ef0203c1b5b596e092987acd894491ecae26 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -202,6 +202,16 @@ class Backup(admintool.AdminTool): + paths.NAMED_RUN, + ) + ++ required_dirs=( ++ paths.TOMCAT_TOPLEVEL_DIR, ++ paths.TOMCAT_CA_DIR, ++ paths.TOMCAT_SIGNEDAUDIT_DIR, ++ paths.TOMCAT_CA_ARCHIVE_DIR, ++ paths.TOMCAT_KRA_DIR, ++ paths.TOMCAT_KRA_SIGNEDAUDIT_DIR, ++ paths.TOMCAT_KRA_ARCHIVE_DIR, ++ ) ++ + def __init__(self, options, args): + super(Backup, self).__init__(options, args) + self._conn = None +@@ -486,13 +496,15 @@ class Backup(admintool.AdminTool): + def verify_directories(dirs): + return [s for s in dirs if os.path.exists(s)] + ++ tarfile = os.path.join(self.dir, 'files.tar') ++ + self.log.info("Backing up files") + args = ['tar', + '--exclude=/var/lib/ipa/backup', + '--xattrs', + '--selinux', +- '-czf', +- os.path.join(self.dir, 'files.tar') ++ '-cf', ++ tarfile + ] + + args.extend(verify_directories(self.dirs)) +@@ -503,7 +515,39 @@ class Backup(admintool.AdminTool): + + (stdout, stderr, rc) = run(args, raiseonerr=False) + if rc != 0: +- raise admintool.ScriptError('tar returned non-zero %d: %s' % (rc, stdout)) ++ raise admintool.ScriptError('tar returned non-zero code ' ++ '%d: %s' % (rc, stderr)) ++ ++ # Backup the necessary directory structure. This is a separate ++ # call since we are using the '--no-recursion' flag to store ++ # the directory structure only, no files. ++ missing_directories = verify_directories(self.required_dirs) ++ ++ if missing_directories: ++ args = ['tar', ++ '--exclude=/var/lib/ipa/backup', ++ '--xattrs', ++ '--selinux', ++ '--no-recursion', ++ '-rf', # -r appends to an existing archive ++ tarfile, ++ ] ++ args.extend(missing_directories) ++ ++ (stdout, stderr, rc) = run(args, raiseonerr=False) ++ if rc != 0: ++ raise admintool.ScriptError('tar returned non-zero %d when adding ' ++ 'directory structure: %s' % (rc, stderr)) ++ ++ # Compress the archive. This is done separately, since 'tar' cannot ++ # append to a compressed archive. ++ (stdout, stderr, rc) = run(['gzip', tarfile], raiseonerr=False) ++ if rc != 0: ++ raise admintool.ScriptError('gzip returned non-zero %d when ' ++ 'compressing the backup: %s' % (rc, stderr)) ++ ++ # Rename the archive back to files.tar to preserve compatibility ++ os.rename(os.path.join(self.dir, 'files.tar.gz'), tarfile) + + + def create_header(self, data_only): +-- +2.4.3 + diff --git a/SOURCES/0130-install-create-kdcproxy-user-during-server-install.patch b/SOURCES/0130-install-create-kdcproxy-user-during-server-install.patch new file mode 100644 index 0000000..53757d0 --- /dev/null +++ b/SOURCES/0130-install-create-kdcproxy-user-during-server-install.patch @@ -0,0 +1,131 @@ +From 99989ab3a9017ea9defc80c5a7047c119c29ff34 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 21 Sep 2015 10:09:50 +0200 +Subject: [PATCH] install: create kdcproxy user during server install + +This change makes kdcproxy user creation consistent with DS and CA user +creation. Before, the user was created in the spec file, in %pre scriptlet +of freeipa-server. + +https://fedorahosted.org/freeipa/ticket/5314 + +Reviewed-By: Martin Babinsky +--- + freeipa.spec.in | 11 ----------- + ipaserver/install/httpinstance.py | 14 ++++++++++++++ + ipaserver/install/ipa_restore.py | 4 +++- + ipaserver/install/server/upgrade.py | 1 + + 4 files changed, 18 insertions(+), 12 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index a8515487757556f337a4bbfc1cc14e8fb4707ccd..530f6141872804ab3801f2da6271fce0d9308a09 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -24,10 +24,6 @@ + + %define _hardened_build 1 + +-%define kdcproxy_user kdcproxy +-%define kdcproxy_group kdcproxy +-%define kdcproxy_home %{_sharedstatedir}/kdcproxy +- + Name: freeipa + Version: __VERSION__ + Release: __RELEASE__%{?dist} +@@ -568,13 +564,6 @@ if [ -e /usr/sbin/ipa_kpasswd ]; then + # END + fi + +-# create kdcproxy user +-getent group %{kdcproxy_group} >/dev/null || groupadd -r %{kdcproxy_group} +-getent passwd %{kdcproxy_user} >/dev/null || \ +- /usr/sbin/useradd -r -m -c "IPA KDC Proxy User" -s /sbin/nologin \ +- -g %{kdcproxy_group} -d %{kdcproxy_home} %{kdcproxy_user} +-exit 0 +- + %postun server-trust-ad + if [ "$1" -ge "1" ]; then + if [ "`readlink %{_sysconfdir}/alternatives/winbind_krb5_locator.so`" == "/dev/null" ]; then +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 792825621f68844a2b0b1265eeeb37e4247d66f8..4f2902e1b1ac03d9c6bd1949b66ede9abb5be28e 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -49,6 +49,8 @@ SELINUX_BOOLEAN_SETTINGS = dict( + httpd_run_ipa='on', + ) + ++KDCPROXY_USER = 'kdcproxy' ++ + + def httpd_443_configured(): + """ +@@ -75,6 +77,17 @@ def httpd_443_configured(): + + return False + ++ ++def create_kdcproxy_user(): ++ """Create KDC proxy user/group if it doesn't exist yet.""" ++ tasks.create_system_user( ++ name=KDCPROXY_USER, ++ group=KDCPROXY_USER, ++ homedir=paths.VAR_LIB, ++ shell=paths.NOLOGIN, ++ ) ++ ++ + class WebGuiInstance(service.SimpleServiceInstance): + def __init__(self): + service.SimpleServiceInstance.__init__(self, "ipa_webgui") +@@ -139,6 +152,7 @@ class HTTPInstance(service.Service): + self.step("clean up any existing httpd ccache", self.remove_httpd_ccache) + self.step("configuring SELinux for httpd", self.configure_selinux_for_httpd) + if not self.is_kdcproxy_configured(): ++ self.step("create KDC proxy user", create_kdcproxy_user) + self.step("create KDC proxy config", self.create_kdcproxy_conf) + self.step("enable KDC proxy", self.enable_kdcproxy) + self.step("restarting httpd", self.__start) +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index dc57a4937365ad1db960955cf21e1bf2d2eb3dda..57d5deb1e68af6e9ceb51f4dd751b8a59d9ac513 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -370,6 +370,7 @@ class Restore(admintool.AdminTool): + + self.restore_selinux_booleans() + ++ http = httpinstance.HTTPInstance() + + # We do either a full file restore or we restore data. + if restore_type == 'FULL': +@@ -381,6 +382,8 @@ class Restore(admintool.AdminTool): + self.cert_restore() + if 'CA' in self.backup_services: + self.__create_dogtag_log_dirs() ++ if http.is_kdcproxy_configured(): ++ httpinstance.create_kdcproxy_user() + + # Always restore the data from ldif + # If we are restoring PKI-IPA then we need to restore the +@@ -409,7 +412,6 @@ class Restore(admintool.AdminTool): + self.log.info('Restarting SSSD') + sssd = services.service('sssd') + sssd.restart() +- http = httpinstance.HTTPInstance() + http.remove_httpd_ccache() + finally: + try: +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 5288f8fcc5fb56b13773e3bb8ea6a5a6c8c0e8a9..0194f75477321a9e1660335ac8283d35aff8a0ec 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1439,6 +1439,7 @@ def upgrade_configuration(): + http.realm = api.env.realm + http.suffix = ipautil.realm_to_suffix(api.env.realm) + http.ldap_connect() ++ httpinstance.create_kdcproxy_user() + http.create_kdcproxy_conf() + http.enable_kdcproxy() + +-- +2.4.3 + diff --git a/SOURCES/0131-destroy-httpd-ccache-after-stopping-the-service.patch b/SOURCES/0131-destroy-httpd-ccache-after-stopping-the-service.patch new file mode 100644 index 0000000..ee9fba5 --- /dev/null +++ b/SOURCES/0131-destroy-httpd-ccache-after-stopping-the-service.patch @@ -0,0 +1,27 @@ +From be295102c07510a8136e016c0af0e67363d513c2 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 16 Sep 2015 18:35:21 +0200 +Subject: [PATCH] destroy httpd ccache after stopping the service + +This will force recreation of the file-based ccache after IPA restore and +prevent a mismatch between cached and restored Kerberos keys. + +https://fedorahosted.org/freeipa/ticket/5296 + +Reviewed-By: Martin Basti +--- + init/systemd/httpd.service | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/init/systemd/httpd.service b/init/systemd/httpd.service +index e68f39eca759db50ad18d8db1faa3b704cb15ede..7ce8f04d8b9bb3663e59d4fdc610af0eb4478178 100644 +--- a/init/systemd/httpd.service ++++ b/init/systemd/httpd.service +@@ -4,3 +4,4 @@ + Environment=KRB5CCNAME=/var/run/httpd/ipa/krbcache/krb5ccache + Environment=KDCPROXY_CONFIG=/etc/ipa/kdcproxy/kdcproxy.conf + ExecStartPre=/usr/libexec/ipa/ipa-httpd-kdcproxy ++ExecStopPost=-/usr/bin/kdestroy -A +-- +2.4.3 + diff --git a/SOURCES/0132-platform-add-option-to-create-home-directory-when-ad.patch b/SOURCES/0132-platform-add-option-to-create-home-directory-when-ad.patch new file mode 100644 index 0000000..5cb723f --- /dev/null +++ b/SOURCES/0132-platform-add-option-to-create-home-directory-when-ad.patch @@ -0,0 +1,70 @@ +From d17b314d405d2c127a3d51d2076e8982d43aa505 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 23 Sep 2015 13:09:44 +0200 +Subject: [PATCH] platform: add option to create home directory when adding + user + +https://fedorahosted.org/freeipa/ticket/5314 + +Reviewed-By: Martin Babinsky +--- + ipaplatform/base/tasks.py | 8 ++++++-- + ipaplatform/redhat/tasks.py | 4 ++-- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py +index 65715145af533c90038b3e8667da07fd28b7ec56..573287c6bf732991946a75c8817899ee6c1842e3 100644 +--- a/ipaplatform/base/tasks.py ++++ b/ipaplatform/base/tasks.py +@@ -184,7 +184,7 @@ class BaseTaskNamespace(object): + + return + +- def create_system_user(self, name, group, homedir, shell, uid = None, gid = None, comment = None): ++ def create_system_user(self, name, group, homedir, shell, uid=None, gid=None, comment=None, create_homedir=False): + """Create a system user with a corresponding group""" + try: + grp.getgrnam(group) +@@ -211,12 +211,16 @@ class BaseTaskNamespace(object): + '-g', group, + '-d', homedir, + '-s', shell, +- '-M', '-r', name, ++ '-r', name, + ] + if uid: + args += ['-u', str(uid)] + if comment: + args += ['-c', comment] ++ if create_homedir: ++ args += ['-m'] ++ else: ++ args += ['-M'] + try: + ipautil.run(args) + log.debug('Done adding user') +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index 1af99d318c6745b1e5285c7829c2b292f86c8390..db31cd04cb234fac8fee97f3579ba2ca919f3262 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -399,7 +399,7 @@ class RedHatTaskNamespace(BaseTaskNamespace): + + return True + +- def create_system_user(self, name, group, homedir, shell, uid = None, gid = None, comment = None): ++ def create_system_user(self, name, group, homedir, shell, uid=None, gid=None, comment=None, create_homedir=False): + """ + Create a system user with a corresponding group + +@@ -420,7 +420,7 @@ class RedHatTaskNamespace(BaseTaskNamespace): + comment = 'DS System User' + + super(RedHatTaskNamespace, self).create_system_user(name, group, +- homedir, shell, uid, gid, comment) ++ homedir, shell, uid, gid, comment, create_homedir) + + + tasks = RedHatTaskNamespace() +-- +2.4.3 + diff --git a/SOURCES/0133-install-fix-kdcproxy-user-home-directory.patch b/SOURCES/0133-install-fix-kdcproxy-user-home-directory.patch new file mode 100644 index 0000000..941b000 --- /dev/null +++ b/SOURCES/0133-install-fix-kdcproxy-user-home-directory.patch @@ -0,0 +1,57 @@ +From 8a866620f36356e570dcee332db6f487837435a6 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 23 Sep 2015 10:35:06 +0200 +Subject: [PATCH] install: fix kdcproxy user home directory + +https://fedorahosted.org/freeipa/ticket/5314 + +Reviewed-By: Martin Babinsky +--- + freeipa.spec.in | 1 + + ipaplatform/base/paths.py | 1 + + ipaserver/install/httpinstance.py | 4 +++- + 3 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 530f6141872804ab3801f2da6271fce0d9308a09..6527109b422a1e3065d5a540c3e2a3af670f2ebf 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -702,6 +702,7 @@ fi + %{_libexecdir}/ipa/ipa-dnskeysync-replica + %{_libexecdir}/ipa/ipa-ods-exporter + %{_libexecdir}/ipa/ipa-httpd-kdcproxy ++%ghost %verify(not owner group) %dir %{_sharedstatedir}/kdcproxy + %config(noreplace) %{_sysconfdir}/sysconfig/ipa_memcached + %config(noreplace) %{_sysconfdir}/sysconfig/ipa-dnskeysyncd + %config(noreplace) %{_sysconfdir}/sysconfig/ipa-ods-exporter +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 97c330c31844fcf19bec2e96bf2b23cba5f7f3f0..215caf90ea1ca4e5db8f43f8f09002ce5d5cd280 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -286,6 +286,7 @@ class BasePathNamespace(object): + REPLICA_INFO_GPG_TEMPLATE = "/var/lib/ipa/replica-info-%s.gpg" + SYSRESTORE = "/var/lib/ipa/sysrestore" + STATEFILE_DIR = "/var/lib/ipa/sysupgrade" ++ VAR_LIB_KDCPROXY = "/var/lib/kdcproxy" + VAR_LIB_PKI_DIR = "/var/lib/pki" + VAR_LIB_PKI_CA_DIR = "/var/lib/pki-ca" + PKI_ALIAS_CA_P12 = "/var/lib/pki-ca/alias/ca.p12" +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 4f2902e1b1ac03d9c6bd1949b66ede9abb5be28e..f55e698f7eb3d8f8aa603f99d750a009a806b70a 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -83,8 +83,10 @@ def create_kdcproxy_user(): + tasks.create_system_user( + name=KDCPROXY_USER, + group=KDCPROXY_USER, +- homedir=paths.VAR_LIB, ++ homedir=paths.VAR_LIB_KDCPROXY, + shell=paths.NOLOGIN, ++ comment="IPA KDC Proxy User", ++ create_homedir=True, + ) + + +-- +2.4.3 + diff --git a/SOURCES/0134-winsync-migrate-Convert-entity-names-to-posix-friend.patch b/SOURCES/0134-winsync-migrate-Convert-entity-names-to-posix-friend.patch new file mode 100644 index 0000000..ba75602 --- /dev/null +++ b/SOURCES/0134-winsync-migrate-Convert-entity-names-to-posix-friend.patch @@ -0,0 +1,104 @@ +From d8395581497150602dc11248ba6ce380a3394254 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 23 Sep 2015 13:27:35 +0200 +Subject: [PATCH] winsync-migrate: Convert entity names to posix friendly + strings + +During the migration from winsync replicated users to their +trusted identities, memberships are being preserved. However, +trusted users are external and as such cannot be added as +direct members to the IPA entities. External groups which +encapsulate the migrated users are added as members to those +entities instead. + +The name of the external group is generated from the type +of the entity and its name. However, the entity's name can +contain characters which are invalid for use in the group +name. + +Adds a helper function to convert a given string to a string +which would be valid for such use and leverages it in the +winsync-migrate tool. + +https://fedorahosted.org/freeipa/ticket/5319 + +Reviewed-By: Martin Babinsky +--- + ipapython/ipautil.py | 23 +++++++++++++++++++++++ + ipaserver/install/ipa_winsync_migrate.py | 15 ++++++++++++--- + 2 files changed, 35 insertions(+), 3 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 88e89706b8e2aa6dea80809510d88bceaa836e85..64fe9bc27e58c8ecfcfabe69690db0493a10c3b1 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -1318,6 +1318,29 @@ def restore_hostname(statestore): + except CalledProcessError, e: + print >>sys.stderr, "Failed to set this machine hostname back to %s: %s" % (old_hostname, str(e)) + ++def posixify(string): ++ """ ++ Convert a string to a more strict alpha-numeric representation. ++ ++ - Alpha-numeric, underscore, dot and dash characters are accepted ++ - Space is converted to underscore ++ - Other characters are omitted ++ - Leading dash is stripped ++ ++ Note: This mapping is not one-to-one and may map different input to the ++ same result. When using posixify, make sure the you do not map two different ++ entities to one unintentionally. ++ """ ++ ++ def valid_char(char): ++ return char.isalnum() or char in ('_', '.', '-') ++ ++ # First replace space characters ++ replaced = string.replace(' ','_') ++ omitted = ''.join(filter(valid_char, replaced)) ++ ++ # Leading dash is not allowed ++ return omitted.lstrip('-') + + @contextmanager + def private_ccache(path=None): +diff --git a/ipaserver/install/ipa_winsync_migrate.py b/ipaserver/install/ipa_winsync_migrate.py +index c327e502e6bfb6e402931e1962fe2410570b2bc2..4dacde3f27ead341fd4d7d2a744d28f74d5c5b95 100644 +--- a/ipaserver/install/ipa_winsync_migrate.py ++++ b/ipaserver/install/ipa_winsync_migrate.py +@@ -24,7 +24,7 @@ from ipalib import api + from ipalib import errors + from ipapython import admintool + from ipapython.dn import DN +-from ipapython.ipautil import realm_to_suffix ++from ipapython.ipautil import realm_to_suffix, posixify + from ipapython.ipa_log_manager import log_mgr + from ipaserver.plugins.ldap2 import ldap2 + from ipaserver.install import replication +@@ -214,12 +214,21 @@ class WinsyncMigrate(admintool.AdminTool): + + def winsync_group_name(object_entry): + """ +- Returns the generated name of group containing migrated external users ++ Returns the generated name of group containing migrated external ++ users. ++ ++ The group name is of the form: ++ "__winsync_external" ++ ++ Object name is converted to posix-friendly string by omitting ++ and/or replacing characters. This may lead to collisions, i.e. ++ if both 'trust_admins' and 'trust admin' groups have winsync ++ users being migrated. + """ + + return u"{0}_{1}_winsync_external".format( + winsync_group_prefix, +- object_entry['cn'][0] ++ posixify(object_entry['cn'][0]) + ) + + def create_winsync_group(object_entry): +-- +2.4.3 + diff --git a/SOURCES/0135-winsync-migrate-Properly-handle-collisions-in-the-na.patch b/SOURCES/0135-winsync-migrate-Properly-handle-collisions-in-the-na.patch new file mode 100644 index 0000000..10c42c1 --- /dev/null +++ b/SOURCES/0135-winsync-migrate-Properly-handle-collisions-in-the-na.patch @@ -0,0 +1,57 @@ +From 6f0660a342320ecec805bc158ba31f43394f5ab2 Mon Sep 17 00:00:00 2001 +From: Tomas Babej +Date: Wed, 23 Sep 2015 13:28:33 +0200 +Subject: [PATCH] winsync-migrate: Properly handle collisions in the names of + external groups + +Since the names of the external groups containing the migrated users +must be stripped of characters which are not valid for use in group names, +two different groups might be mapped to one during this process. + +Properly handle collisions in the names by adding an incremental +numeric suffix. + +https://fedorahosted.org/freeipa/ticket/5319 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/ipa_winsync_migrate.py | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/ipa_winsync_migrate.py b/ipaserver/install/ipa_winsync_migrate.py +index 4dacde3f27ead341fd4d7d2a744d28f74d5c5b95..13c5ddef383204451cbc4bb662c8a1befc1d5f93 100644 +--- a/ipaserver/install/ipa_winsync_migrate.py ++++ b/ipaserver/install/ipa_winsync_migrate.py +@@ -231,15 +231,26 @@ class WinsyncMigrate(admintool.AdminTool): + posixify(object_entry['cn'][0]) + ) + +- def create_winsync_group(object_entry): ++ def create_winsync_group(object_entry, suffix=0): + """ + Creates the group containing migrated external users that were + previously available via winsync. + """ + + name = winsync_group_name(object_entry) +- api.Command['group_add'](name, external=True) +- api.Command[object_membership_command](object_entry['cn'][0], group=[name]) ++ ++ # Only non-trivial suffix is appended at the end ++ if suffix != 0: ++ name += str(suffix) ++ ++ try: ++ api.Command['group_add'](name, external=True) ++ except errors.DuplicateEntry: ++ # If there is a collision, let's try again with a higher suffix ++ create_winsync_group(object_entry, suffix=suffix+1) ++ else: ++ # In case of no collision, add the membership ++ api.Command[object_membership_command](object_entry['cn'][0], group=[name]) + + # Search for all objects containing the given user as a direct member + member_filter = self.ldap.make_filter_from_attr(user_dn_attribute, +-- +2.4.3 + diff --git a/SOURCES/0136-Fix-an-integer-underflow-bug-in-libotp.patch b/SOURCES/0136-Fix-an-integer-underflow-bug-in-libotp.patch new file mode 100644 index 0000000..339958a --- /dev/null +++ b/SOURCES/0136-Fix-an-integer-underflow-bug-in-libotp.patch @@ -0,0 +1,37 @@ +From 0ee0de08a6b389a7593198c918dc894c87dcbe96 Mon Sep 17 00:00:00 2001 +From: Nathaniel McCallum +Date: Fri, 25 Sep 2015 11:35:03 -0400 +Subject: [PATCH] Fix an integer underflow bug in libotp + +Temporarily storing the offset time in an unsigned integer causes the +value of the offset to underflow when a (valid) negative offset value +is generated. Using a signed variable avoids this problem. + +https://fedorahosted.org/freeipa/ticket/5333 + +Reviewed-By: Tomas Babej +--- + daemons/ipa-slapi-plugins/libotp/otp_token.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c +index 9b90c6a1137b468103d73cd85fd7e0fcafcee616..a3cbfb0621c071f8addb29f7ce02f870a807c61d 100644 +--- a/daemons/ipa-slapi-plugins/libotp/otp_token.c ++++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c +@@ -199,10 +199,10 @@ static bool validate(struct otp_token *token, time_t now, ssize_t step, + case TYPE_TOTP: + /* Perform optional synchronization steps. */ + if (second != NULL) { +- tmp = (step - now / token->totp.step) * token->totp.step; +- if (!writeattr(token, T("clockOffset"), tmp)) ++ long long off = (step - now / token->totp.step) * token->totp.step; ++ if (!writeattr(token, T("clockOffset"), off)) + return false; +- token->totp.offset = tmp; ++ token->totp.offset = off; + } + token->totp.watermark = step; + break; +-- +2.4.3 + diff --git a/SOURCES/0137-do-not-overwrite-files-with-local-users-groups-when-.patch b/SOURCES/0137-do-not-overwrite-files-with-local-users-groups-when-.patch new file mode 100644 index 0000000..fb28b1f --- /dev/null +++ b/SOURCES/0137-do-not-overwrite-files-with-local-users-groups-when-.patch @@ -0,0 +1,50 @@ +From 54b62df055fda613aa985ccd971968123c0ad113 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 25 Sep 2015 18:00:30 +0200 +Subject: [PATCH] do not overwrite files with local users/groups when restoring + authconfig + +the patch fixes regression in ipa-restore caused by overwriting /etc/passwd, +/etc/shadow and fiends during restore of authconfig configuration files. These +files are now excluded from authconfig backup dir. + +https://fedorahosted.org/freeipa/ticket/5328 + +Reviewed-By: David Kupka +--- + ipaplatform/redhat/authconfig.py | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ipaplatform/redhat/authconfig.py b/ipaplatform/redhat/authconfig.py +index edefee8b2b4922ad67cdbac158615ef32c776bb4..7b06d583d8f8dba3df589edf73ec20f7b80c20a4 100644 +--- a/ipaplatform/redhat/authconfig.py ++++ b/ipaplatform/redhat/authconfig.py +@@ -19,7 +19,9 @@ + # along with this program. If not, see . + + from ipapython import ipautil ++import os + ++FILES_TO_NOT_BACKUP = ['passwd', 'group', 'shadow', 'gshadow'] + + class RedHatAuthConfig(object): + """ +@@ -88,5 +90,15 @@ class RedHatAuthConfig(object): + def backup(self, path): + ipautil.run(["/usr/sbin/authconfig", "--savebackup", path]) + ++ # do not backup these files since we don't want to mess with ++ # users/groups during restore. Authconfig doesn't seem to mind about ++ # having them deleted from backup dir ++ files_to_remove = [os.path.join(path, f) for f in FILES_TO_NOT_BACKUP] ++ for filename in files_to_remove: ++ try: ++ os.remove(filename) ++ except OSError: ++ pass ++ + def restore(self, path): + ipautil.run(["/usr/sbin/authconfig", "--restorebackup", path]) +-- +2.4.3 + diff --git a/SOURCES/0138-install-fix-KRA-agent-PEM-file-permissions.patch b/SOURCES/0138-install-fix-KRA-agent-PEM-file-permissions.patch new file mode 100644 index 0000000..fac95ef --- /dev/null +++ b/SOURCES/0138-install-fix-KRA-agent-PEM-file-permissions.patch @@ -0,0 +1,153 @@ +From 3b41a53830fc7d0fdb301437cdceb7fcddff25a5 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 21 Sep 2015 08:32:04 +0200 +Subject: [PATCH] install: fix KRA agent PEM file permissions + +This fixes CVE-2015-5284. + +https://fedorahosted.org/freeipa/ticket/5347 + +Reviewed-By: Martin Basti +--- + install/restart_scripts/renew_ra_cert | 8 +------- + ipaserver/install/dogtaginstance.py | 22 ++++++++++++++++++++++ + ipaserver/install/krainstance.py | 12 +++--------- + ipaserver/install/server/upgrade.py | 19 +++++++++++++++++++ + 4 files changed, 45 insertions(+), 16 deletions(-) + +diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert +index 93ffd4035723831f3955bcdf5a2082fd1ec5e22a..8a6bf3f7c1081db9710cf29e0f8e5f705d920b72 100644 +--- a/install/restart_scripts/renew_ra_cert ++++ b/install/restart_scripts/renew_ra_cert +@@ -63,13 +63,7 @@ def _main(): + + kra = krainstance.KRAInstance(api.env.realm) + if kra.is_installed(): +- # export ipaCert with private key for client authentication +- args = ["/usr/bin/pki", +- "-d", paths.HTTPD_ALIAS_DIR, +- "-C", paths.ALIAS_PWDFILE_TXT, +- "client-cert-show", "ipaCert", +- "--client-cert", paths.KRA_AGENT_PEM] +- ipautil.run(args) ++ krainstance.export_kra_agent_pem() + finally: + shutil.rmtree(tmpdir) + +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index 33f39f7930b4151200f2880d02a0bc2c152c0025..940b3ea9b13897d7e9e2878a47a8c66ce5ce9f0a 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -23,6 +23,7 @@ import shutil + import tempfile + import traceback + import dbus ++import pwd + + from pki.client import PKIConnection + import pki.system +@@ -88,6 +89,27 @@ def is_installing_replica(sys_type): + return False + + ++def export_kra_agent_pem(): ++ """ ++ Export ipaCert with private key for client authentication. ++ """ ++ fd, filename = tempfile.mkstemp(dir=paths.HTTPD_ALIAS_DIR) ++ os.close(fd) ++ ++ args = ["/usr/bin/pki", ++ "-d", paths.HTTPD_ALIAS_DIR, ++ "-C", paths.ALIAS_PWDFILE_TXT, ++ "client-cert-show", "ipaCert", ++ "--client-cert", filename] ++ ipautil.run(args) ++ ++ pent = pwd.getpwnam("apache") ++ os.chown(filename, 0, pent.pw_gid) ++ os.chmod(filename, 0o440) ++ ++ os.rename(filename, paths.KRA_AGENT_PEM) ++ ++ + class DogtagInstance(service.Service): + """ + This is the base class for a Dogtag 10+ instance, which uses a +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 48268b0be5331cced1aee6b7f3358333b65de6dd..0000192745b6d7f9f402267e435f7223f1bf8849 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -37,8 +37,8 @@ from ipaserver.install import cainstance + from ipaserver.install import installutils + from ipaserver.install import ldapupdate + from ipaserver.install import service +-from ipaserver.install.dogtaginstance import DogtagInstance +-from ipaserver.install.dogtaginstance import DEFAULT_DSPORT, PKI_USER ++from ipaserver.install.dogtaginstance import ( ++ DEFAULT_DSPORT, PKI_USER, export_kra_agent_pem, DogtagInstance) + from ipaserver.plugins import ldap2 + from ipapython.ipa_log_manager import log_mgr + +@@ -262,13 +262,7 @@ class KRAInstance(DogtagInstance): + + shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12) + +- # export ipaCert with private key for client authentication +- args = ["/usr/bin/pki", +- "-d", paths.HTTPD_ALIAS_DIR, +- "-C", paths.ALIAS_PWDFILE_TXT, +- "client-cert-show", "ipaCert", +- "--client-cert", paths.KRA_AGENT_PEM] +- ipautil.run(args) ++ export_kra_agent_pem() + + self.log.debug("completed creating KRA instance") + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 0194f75477321a9e1660335ac8283d35aff8a0ec..ab08c62352c0e5cf145f299e7727886b2f295037 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -35,6 +35,7 @@ from ipaserver.install import otpdinstance + from ipaserver.install import schemaupdate + from ipaserver.install import sysupgrade + from ipaserver.install import dnskeysyncinstance ++from ipaserver.install import krainstance + from ipaserver.install.upgradeinstance import IPAUpgrade + from ipaserver.install.ldapupdate import BadSyntax + +@@ -1244,6 +1245,23 @@ def fix_trust_flags(): + sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True) + + ++def export_kra_agent_pem(): ++ root_logger.info('[Exporting KRA agent PEM file]') ++ ++ if sysupgrade.get_upgrade_state('http', 'export_kra_agent_pem'): ++ root_logger.info("KRA agent PEM file already exported") ++ return ++ ++ kra = krainstance.KRAInstance(api.env.realm) ++ if not kra.is_installed(): ++ root_logger.info("KRA is not installed") ++ return ++ ++ krainstance.export_kra_agent_pem() ++ ++ sysupgrade.set_upgrade_state('http', 'export_kra_agent_pem', True) ++ ++ + def update_mod_nss_protocol(http): + root_logger.info('[Updating mod_nss protocol versions]') + +@@ -1446,6 +1464,7 @@ def upgrade_configuration(): + http.stop() + update_mod_nss_protocol(http) + fix_trust_flags() ++ export_kra_agent_pem() + http.start() + + uninstall_selfsign(ds, http) +-- +2.4.3 + diff --git a/SOURCES/0139-install-always-export-KRA-agent-PEM-file.patch b/SOURCES/0139-install-always-export-KRA-agent-PEM-file.patch new file mode 100644 index 0000000..9e590b0 --- /dev/null +++ b/SOURCES/0139-install-always-export-KRA-agent-PEM-file.patch @@ -0,0 +1,97 @@ +From d644d5533a7ccf61cc557f8fe8a5ee1d93bc19fd Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 16 Sep 2015 09:05:20 +0200 +Subject: [PATCH] install: always export KRA agent PEM file + +Export the file even when KRA is not installed locally so that vault commands +work on all IPA replicas. + +https://fedorahosted.org/freeipa/ticket/5302 + +Reviewed-By: Martin Basti +--- + install/restart_scripts/renew_ra_cert | 3 +-- + ipaserver/install/cainstance.py | 8 ++++++-- + ipaserver/install/krainstance.py | 2 -- + ipaserver/install/server/upgrade.py | 5 ++--- + 4 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert +index 8a6bf3f7c1081db9710cf29e0f8e5f705d920b72..3a36f739ae53391e502356f7b6b4fd96a536c3a6 100644 +--- a/install/restart_scripts/renew_ra_cert ++++ b/install/restart_scripts/renew_ra_cert +@@ -61,8 +61,7 @@ def _main(): + # Load it into dogtag + cainstance.update_people_entry(dercert) + +- kra = krainstance.KRAInstance(api.env.realm) +- if kra.is_installed(): ++ if api.Command.kra_is_enabled()['result']: + krainstance.export_kra_agent_pem() + finally: + shutil.rmtree(tmpdir) +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index a4504a35a42b8c8ea2a96738c82c546ebebf569f..dfe023c08c9b8d1b28f1659b7c5a6395f3afe879 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -62,8 +62,8 @@ from ipaserver.install import certs + from ipaserver.install import dsinstance + from ipaserver.install import installutils + from ipaserver.install import service +-from ipaserver.install.dogtaginstance import DogtagInstance +-from ipaserver.install.dogtaginstance import PKI_USER, DEFAULT_DSPORT ++from ipaserver.install.dogtaginstance import ( ++ DEFAULT_DSPORT, PKI_USER, export_kra_agent_pem, DogtagInstance) + from ipaserver.plugins import ldap2 + + +@@ -885,6 +885,8 @@ class CAInstance(DogtagInstance): + finally: + os.remove(agent_name) + ++ export_kra_agent_pem() ++ + def import_ra_cert(self, rafile): + """ + Cloned RAs will use the same RA agent cert as the master so we +@@ -903,6 +905,8 @@ class CAInstance(DogtagInstance): + + self.configure_agent_renewal() + ++ export_kra_agent_pem() ++ + def __create_ca_agent(self): + """ + Create CA agent, assign a certificate, and add the user to +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 0000192745b6d7f9f402267e435f7223f1bf8849..69fe636732e6d3a8c1e0c460b641f061e519df92 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -262,8 +262,6 @@ class KRAInstance(DogtagInstance): + + shutil.move(paths.KRA_BACKUP_KEYS_P12, paths.KRACERT_P12) + +- export_kra_agent_pem() +- + self.log.debug("completed creating KRA instance") + + def __create_kra_agent(self): +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index ab08c62352c0e5cf145f299e7727886b2f295037..51a2dd3d0e3693c12f11579a84175c7719651da9 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1252,9 +1252,8 @@ def export_kra_agent_pem(): + root_logger.info("KRA agent PEM file already exported") + return + +- kra = krainstance.KRAInstance(api.env.realm) +- if not kra.is_installed(): +- root_logger.info("KRA is not installed") ++ if not api.Command.kra_is_enabled()['result']: ++ root_logger.info("KRA is not enabled") + return + + krainstance.export_kra_agent_pem() +-- +2.4.3 + diff --git a/SOURCES/0140-vault-select-a-server-with-KRA-for-vault-operations.patch b/SOURCES/0140-vault-select-a-server-with-KRA-for-vault-operations.patch new file mode 100644 index 0000000..d7b8678 --- /dev/null +++ b/SOURCES/0140-vault-select-a-server-with-KRA-for-vault-operations.patch @@ -0,0 +1,72 @@ +From f81f6028428f232052fa372bf3b11fa1e7b3905e Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 30 Sep 2015 09:05:33 +0200 +Subject: [PATCH] vault: select a server with KRA for vault operations + +This uses the same mechanism which is used for the CA. + +https://fedorahosted.org/freeipa/ticket/5302 + +Reviewed-By: Martin Basti +--- + ipalib/constants.py | 3 --- + ipaserver/plugins/dogtag.py | 22 +++++++++++++++++++++- + 2 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/ipalib/constants.py b/ipalib/constants.py +index 1509151bac7e0abca081cbba033701db410fc54c..0c5fc49456307ed261acb057ce6612274da2c453 100644 +--- a/ipalib/constants.py ++++ b/ipalib/constants.py +@@ -167,9 +167,6 @@ DEFAULT_CONFIG = ( + ('ca_agent_install_port', None), + ('ca_ee_install_port', None), + +- # KRA plugin +- ('kra_host', FQDN), # Set in Env._finalize_core() +- + # Topology plugin + ('recommended_max_agmts', 4), # Recommended maximum number of replication + # agreements +diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py +index 47279921a5428f388f84967b7bbe05d758e475bd..f5f8eb67067c87f07c06e556fb9fc73792fbbc64 100644 +--- a/ipaserver/plugins/dogtag.py ++++ b/ipaserver/plugins/dogtag.py +@@ -1902,6 +1902,26 @@ class kra(Backend): + + super(kra, self).__init__(api) + ++ @property ++ def kra_host(self): ++ """ ++ :return: host ++ as str ++ ++ Select our KRA host. ++ """ ++ ldap2 = self.api.Backend.ldap2 ++ if host_has_service(api.env.ca_host, ldap2, "KRA"): ++ return api.env.ca_host ++ if api.env.host != api.env.ca_host: ++ if host_has_service(api.env.host, ldap2, "KRA"): ++ return api.env.host ++ host = select_any_master(ldap2, "KRA") ++ if host: ++ return host ++ else: ++ return api.env.ca_host ++ + def get_client(self): + """ + Returns an authenticated KRA client to access KRA services. +@@ -1921,7 +1941,7 @@ class kra(Backend): + # https://fedorahosted.org/freeipa/ticket/4557 + connection = PKIConnection( + 'https', +- api.env.kra_host, ++ self.kra_host, + str(self.kra_port), + 'kra') + +-- +2.4.3 + diff --git a/SOURCES/0141-schema-do-not-derive-ipaVaultPublicKey-from-ipaPubli.patch b/SOURCES/0141-schema-do-not-derive-ipaVaultPublicKey-from-ipaPubli.patch new file mode 100644 index 0000000..fde35d7 --- /dev/null +++ b/SOURCES/0141-schema-do-not-derive-ipaVaultPublicKey-from-ipaPubli.patch @@ -0,0 +1,32 @@ +From a60d3bb3c3ccaf9e3055fbfe855f931bd71cd8b0 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 12 Oct 2015 08:04:38 +0200 +Subject: [PATCH] schema: do not derive ipaVaultPublicKey from ipaPublicKey + +This is a workaround for DS bug: +https://bugzilla.redhat.com/show_bug.cgi?id=1267782 + +https://fedorahosted.org/freeipa/ticket/5359 + +Reviewed-By: Alexander Bokovoy +--- + install/share/60basev3.ldif | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif +index 16d7c21d9291d1cd1bdc70f7d908191a7939dd56..f04044cc43efff737a1016e5870e7a322908dad5 100644 +--- a/install/share/60basev3.ldif ++++ b/install/share/60basev3.ldif +@@ -58,7 +58,8 @@ attributeTypes: (2.16.840.1.113730.3.8.11.70 NAME 'ipaPermTargetTo' DESC 'Destin + attributeTypes: (2.16.840.1.113730.3.8.11.71 NAME 'ipaPermTargetFrom' DESC 'Source location from where moving an entry IPA permission ACI' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v4.0' ) + attributeTypes: (2.16.840.1.113730.3.8.18.2.1 NAME 'ipaVaultType' DESC 'IPA vault type' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v4.2') + attributeTypes: (2.16.840.1.113730.3.8.18.2.2 NAME 'ipaVaultSalt' DESC 'IPA vault salt' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v4.2' ) +-attributeTypes: (2.16.840.1.113730.3.8.18.2.3 NAME 'ipaVaultPublicKey' DESC 'IPA vault public key' SUP ipaPublicKey X-ORIGIN 'IPA v4.2' ) ++# FIXME: https://bugzilla.redhat.com/show_bug.cgi?id=1267782 ++attributeTypes: (2.16.840.1.113730.3.8.18.2.3 NAME 'ipaVaultPublicKey' DESC 'IPA vault public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v4.2' ) + objectClasses: (2.16.840.1.113730.3.8.12.1 NAME 'ipaExternalGroup' SUP top STRUCTURAL MUST ( cn ) MAY ( ipaExternalMember $ memberOf $ description $ owner) X-ORIGIN 'IPA v3' ) + objectClasses: (2.16.840.1.113730.3.8.12.2 NAME 'ipaNTUserAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) MAY ( ipaNTHash $ ipaNTLogonScript $ ipaNTProfilePath $ ipaNTHomeDirectory $ ipaNTHomeDirectoryDrive ) X-ORIGIN 'IPA v3' ) + objectClasses: (2.16.840.1.113730.3.8.12.3 NAME 'ipaNTGroupAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' ) +-- +2.4.3 + diff --git a/SOURCES/0142-upgrade-make-sure-ldap2-is-connected-in-export_kra_a.patch b/SOURCES/0142-upgrade-make-sure-ldap2-is-connected-in-export_kra_a.patch new file mode 100644 index 0000000..02ef3e2 --- /dev/null +++ b/SOURCES/0142-upgrade-make-sure-ldap2-is-connected-in-export_kra_a.patch @@ -0,0 +1,33 @@ +From 60cbb2471829504edb207c0914edd56a962593cf Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 12 Oct 2015 14:58:40 +0200 +Subject: [PATCH] upgrade: make sure ldap2 is connected in export_kra_agent_pem + +https://fedorahosted.org/freeipa/ticket/5360 + +Reviewed-By: Ales 'alich' Marecek +--- + ipaserver/install/server/upgrade.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 51a2dd3d0e3693c12f11579a84175c7719651da9..e0a45a097171613397db42e1c035f0d818a3ecf5 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1252,6 +1252,13 @@ def export_kra_agent_pem(): + root_logger.info("KRA agent PEM file already exported") + return + ++ if not api.Backend.ldap2.isconnected(): ++ try: ++ api.Backend.ldap2.connect(autobind=True) ++ except ipalib.errors.PublicError as e: ++ root_logger.error("Cannot connect to LDAP: %s", e) ++ return ++ + if not api.Command.kra_is_enabled()['result']: + root_logger.info("KRA is not enabled") + return +-- +2.4.3 + diff --git a/SOURCES/0143-vault-fix-private-service-vault-creation.patch b/SOURCES/0143-vault-fix-private-service-vault-creation.patch new file mode 100644 index 0000000..58d5fee --- /dev/null +++ b/SOURCES/0143-vault-fix-private-service-vault-creation.patch @@ -0,0 +1,53 @@ +From 997adec1729490ec9c3316862a4393002e708894 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 13 Oct 2015 10:10:48 +0200 +Subject: [PATCH] vault: fix private service vault creation + +https://fedorahosted.org/freeipa/ticket/5361 + +Reviewed-By: Petr Vobornik +--- + install/updates/40-vault.update | 3 ++- + ipalib/plugins/vault.py | 4 ++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/install/updates/40-vault.update b/install/updates/40-vault.update +index 3daea5b1988333d4d482463af0eec4163e4f0760..8d03f348c0ec9aded11f47bad5d1de6e013607cd 100644 +--- a/install/updates/40-vault.update ++++ b/install/updates/40-vault.update +@@ -7,8 +7,9 @@ remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0 + remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect vault members can access the vault"; allow(read, search, compare) userattr="member#GROUPDN";) + remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Vault owners can manage the vault"; allow(read, search, compare, write) userattr="owner#USERDN";) + remove: aci: (targetfilter="(objectClass=ipaVault)")(targetattr="*")(version 3.0; acl "Indirect vault owners can manage the vault"; allow(read, search, compare, write) userattr="owner#GROUPDN";) ++remove: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow services to create private container"; allow(add) userdn="ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) + addifexist: aci: (target="ldap:///cn=*,cn=users,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow users to create private container"; allow(add) userdn="ldap:///uid=($$attr.cn),cn=users,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) +-addifexist: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow services to create private container"; allow(add) userdn="ldap:///krbprincipalname=($$attr.cn)@$REALM,cn=services,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) ++addifexist: aci: (target="ldap:///cn=*,cn=services,cn=vaults,cn=kra,$SUFFIX")(targetfilter="(objectClass=ipaVaultContainer)")(version 3.0; acl "Allow services to create private container"; allow(add) userdn="ldap:///krbprincipalname=($$attr.cn),cn=services,cn=accounts,$SUFFIX" and userattr="owner#SELFDN";) + addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Container owners can access the container"; allow(read, search, compare) userattr="owner#USERDN";) + addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description || owner")(version 3.0; acl "Indirect container owners can access the container"; allow(read, search, compare) userattr="owner#GROUPDN";) + addifexist: aci: (targetfilter="(objectClass=ipaVaultContainer)")(targetattr="objectClass || cn || description")(version 3.0; acl "Container owners can manage the container"; allow(write, delete) userattr="owner#USERDN";) +diff --git a/ipalib/plugins/vault.py b/ipalib/plugins/vault.py +index 1159a84d58eb152cccdd791c96a1c876754bfa7d..d1d7f2a738999299bc9355a431e7adb6f514064e 100644 +--- a/ipalib/plugins/vault.py ++++ b/ipalib/plugins/vault.py +@@ -399,7 +399,7 @@ class vaultcontainer(LDAPObject): + + (name, realm) = split_principal(principal) + if '/' in name: +- service = name ++ service = principal + else: + user = name + +@@ -717,7 +717,7 @@ class vault(LDAPObject): + + (name, realm) = split_principal(principal) + if '/' in name: +- service = name ++ service = principal + else: + user = name + +-- +2.4.3 + diff --git a/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch b/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch index 644a02f..d61193c 100644 --- a/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch +++ b/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch @@ -1,4 +1,4 @@ -From e33a5c3b993e0111617e1c15bed374f6ce426b2d Mon Sep 17 00:00:00 2001 +From b8147e3295b16164f62d05a78dfd25bfa6f178e2 Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Fri, 5 Sep 2014 11:24:27 +0200 Subject: [PATCH] Hide pkinit functionality from production version @@ -7,97 +7,16 @@ Rebased from original patch from Jan Zeleny and Rob Crittenden. https://fedorahosted.org/freeipa/ticket/616 --- - install/tools/ipa-replica-install | 5 +++-- - install/tools/ipa-server-install | 20 ++++---------------- - ipaserver/install/ipa_replica_prepare.py | 20 +++----------------- - 3 files changed, 10 insertions(+), 35 deletions(-) + ipaserver/install/ipa_replica_prepare.py | 20 +++----------------- + ipaserver/install/server/install.py | 4 ++++ + ipaserver/install/server/replicainstall.py | 1 + + 3 files changed, 8 insertions(+), 17 deletions(-) -diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install -index 75bbe981b96cf17950fe73d92d39ca3030f548f9..d3b520abf635ccc324b74bca31f241960a33d950 100755 ---- a/install/tools/ipa-replica-install -+++ b/install/tools/ipa-replica-install -@@ -97,8 +97,6 @@ def parse_options(): - parser.add_option_group(basic_group) - - cert_group = OptionGroup(parser, "certificate system options") -- cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", -- default=True, help="disables pkinit setup steps") - cert_group.add_option("--skip-schema-check", dest="skip_schema_check", action="store_true", - default=False, help="skip check for updated CA DS schema on the remote master") - parser.add_option_group(cert_group) -@@ -126,6 +124,9 @@ def parse_options(): - options, args = parser.parse_args() - safe_options = parser.get_safe_opts(options) - -+ # pkinit is disabled in production version -+ options.setup_pkinit = False -+ - if len(args) != 1: - parser.error("you must provide a file generated by ipa-replica-prepare") - -diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index 0394314ee99817f221536136ae1432cc8e92220a..a5df3e9971a5ae128ebfa4c542dcad7cc3626276 100755 ---- a/install/tools/ipa-server-install -+++ b/install/tools/ipa-server-install -@@ -218,8 +218,6 @@ def parse_options(): - cert_group.add_option("--external_ca_file", dest="external_cert_files", - action="append", - help=SUPPRESS_HELP) -- cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", -- default=True, help="disables pkinit setup steps") - cert_group.add_option("--dirsrv-cert-file", dest="dirsrv_cert_files", - action="append", metavar="FILE", - help="File containing the Directory Server SSL certificate and private key") -@@ -232,12 +230,6 @@ def parse_options(): - cert_group.add_option("--http_pkcs12", dest="http_cert_files", - action="append", - help=SUPPRESS_HELP) -- cert_group.add_option("--pkinit-cert-file", dest="pkinit_cert_files", -- action="append", metavar="FILE", -- help="File containing the Kerberos KDC SSL certificate and private key") -- cert_group.add_option("--pkinit_pkcs12", dest="pkinit_cert_files", -- action="append", -- help=SUPPRESS_HELP) - cert_group.add_option("--dirsrv-pin", dest="dirsrv_pin", sensitive=True, - metavar="PIN", - help="The password to unlock the Directory Server private key") -@@ -248,20 +240,12 @@ def parse_options(): - help="The password to unlock the Apache Server private key") - cert_group.add_option("--http_pin", dest="http_pin", sensitive=True, - help=SUPPRESS_HELP) -- cert_group.add_option("--pkinit-pin", dest="pkinit_pin", sensitive=True, -- metavar="PIN", -- help="The password to unlock the Kerberos KDC private key") -- cert_group.add_option("--pkinit_pin", dest="pkinit_pin", sensitive=True, -- help=SUPPRESS_HELP) - cert_group.add_option("--dirsrv-cert-name", dest="dirsrv_cert_name", - metavar="NAME", - help="Name of the Directory Server SSL certificate to install") - cert_group.add_option("--http-cert-name", dest="http_cert_name", - metavar="NAME", - help="Name of the Apache Server SSL certificate to install") -- cert_group.add_option("--pkinit-cert-name", dest="pkinit_cert_name", -- metavar="NAME", -- help="Name of the Kerberos KDC SSL certificate to install") - cert_group.add_option("--ca-cert-file", dest="ca_cert_files", - action="append", metavar="FILE", - help="File containing CA certificates for the service certificate files") -@@ -309,6 +293,10 @@ def parse_options(): - options, args = parser.parse_args() - safe_options = parser.get_safe_opts(options) - -+ # pkinit is disabled in production version -+ options.pkinit_pin = False -+ options.pkinit_cert_files = False -+ - if options.dm_password is not None: - try: - validate_dm_password(options.dm_password) diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py -index 3762f32700aa899541883d3af72b160c4c42ba7c..1d34aa26b49be0c5df8e7d315a45cd6d180e6da9 100644 +index 5246f5f5469c85571d04c99d872f38018802abaa..3ecf44fffad22e11b5008dadc24c9933eac965cf 100644 --- a/ipaserver/install/ipa_replica_prepare.py +++ b/ipaserver/install/ipa_replica_prepare.py -@@ -63,9 +63,6 @@ class ReplicaPrepare(admintool.AdminTool): +@@ -65,9 +65,6 @@ class ReplicaPrepare(admintool.AdminTool): parser.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="do not create reverse DNS zone") @@ -107,7 +26,7 @@ index 3762f32700aa899541883d3af72b160c4c42ba7c..1d34aa26b49be0c5df8e7d315a45cd6d parser.add_option("--ca", dest="ca_file", default=paths.CACERT_P12, metavar="FILE", help="location of CA PKCS#12 file, default /root/cacert.p12") -@@ -87,12 +84,6 @@ class ReplicaPrepare(admintool.AdminTool): +@@ -89,12 +86,6 @@ class ReplicaPrepare(admintool.AdminTool): group.add_option("--http_pkcs12", dest="http_cert_files", action="append", help=SUPPRESS_HELP) @@ -120,7 +39,7 @@ index 3762f32700aa899541883d3af72b160c4c42ba7c..1d34aa26b49be0c5df8e7d315a45cd6d group.add_option("--dirsrv-pin", dest="dirsrv_pin", sensitive=True, metavar="PIN", help="The password to unlock the Directory Server private key") -@@ -103,20 +94,12 @@ class ReplicaPrepare(admintool.AdminTool): +@@ -105,20 +96,12 @@ class ReplicaPrepare(admintool.AdminTool): help="The password to unlock the Apache Server private key") group.add_option("--http_pin", dest="http_pin", sensitive=True, help=SUPPRESS_HELP) @@ -141,7 +60,7 @@ index 3762f32700aa899541883d3af72b160c4c42ba7c..1d34aa26b49be0c5df8e7d315a45cd6d parser.add_option_group(group) def validate_options(self): -@@ -136,7 +119,10 @@ class ReplicaPrepare(admintool.AdminTool): +@@ -138,7 +121,10 @@ class ReplicaPrepare(admintool.AdminTool): "option together with --no-reverse") #Automatically disable pkinit w/ dogtag until that is supported @@ -152,6 +71,54 @@ index 3762f32700aa899541883d3af72b160c4c42ba7c..1d34aa26b49be0c5df8e7d315a45cd6d # If any of the PKCS#12 options are selected, all are required. cert_file_req = (options.dirsrv_cert_files, options.http_cert_files) +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 9d7036a7786a35e6aa2429254d62c8afb30970db..95a9b560843cfea9b4f7b2718e4e943548cd9a30 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -1173,6 +1173,7 @@ class ServerCA(common.Installable, core.Group, core.Composite): + + no_pkinit = Knob( + bool, False, ++ initializable=False, + description="disables pkinit setup steps", + ) + +@@ -1196,6 +1197,7 @@ class ServerCA(common.Installable, core.Group, core.Composite): + + pkinit_cert_files = Knob( + (list, str), None, ++ initializable=False, + description=("File containing the Kerberos KDC SSL certificate and " + "private key"), + cli_name='pkinit-cert-file', +@@ -1221,6 +1223,7 @@ class ServerCA(common.Installable, core.Group, core.Composite): + + pkinit_pin = Knob( + str, None, ++ initializable=False, + sensitive=True, + description="The password to unlock the Kerberos KDC private key", + cli_aliases=['pkinit_pin'], +@@ -1241,6 +1244,7 @@ class ServerCA(common.Installable, core.Group, core.Composite): + + pkinit_cert_name = Knob( + str, None, ++ initializable=False, + description="Name of the Kerberos KDC SSL certificate to install", + cli_metavar='NAME', + ) +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 6f9a6141fe9af44806244ce52df59c191dc966b0..2d34fdd02b57eb962cdffba508e53cfea0c922e1 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -655,6 +655,7 @@ class ReplicaCA(common.Installable, core.Group, core.Composite): + + no_pkinit = Knob( + bool, False, ++ initializable=False, + description="disables pkinit setup steps", + ) + -- -1.9.3 +2.5.1 diff --git a/SOURCES/1002-Remove-pkinit-plugin.patch b/SOURCES/1002-Remove-pkinit-plugin.patch index d2fed0a..955364d 100644 --- a/SOURCES/1002-Remove-pkinit-plugin.patch +++ b/SOURCES/1002-Remove-pkinit-plugin.patch @@ -1,4 +1,4 @@ -From f7996d16d5a424f136d54a7dc190d4e6c5dad628 Mon Sep 17 00:00:00 2001 +From 414c1303d60e6e7ca46b29e0e2e066bca03c9e0b Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Fri, 5 Sep 2014 11:26:18 +0200 Subject: [PATCH] Remove pkinit plugin @@ -17,10 +17,10 @@ https://fedorahosted.org/freeipa/ticket/616 delete mode 100644 ipalib/plugins/pkinit.py diff --git a/API.txt b/API.txt -index 7949c49f9fb9e3cd7eceb64a05dd8e550eb48f8b..e573a2838777dc564fc8ef16f97b36fe17b67590 100644 +index 5253e1585e000f39d6e185a94548037dfe54d4d8..0b626cb0db44ec9adfb688bd5afddb4b17d950d6 100644 --- a/API.txt +++ b/API.txt -@@ -2895,11 +2895,6 @@ command: ping +@@ -3199,11 +3199,6 @@ command: ping args: 0,1,1 option: Str('version?', exclude='webui') output: Output('summary', (, ), None) @@ -144,5 +144,5 @@ index 5f00b2b46ff94cca7f98876c0171f455c210d778..00000000000000000000000000000000 - return dict(result=True) - -- -2.1.0 +2.5.1 diff --git a/SOURCES/1003-Remove-pkinit-references-from-tool-man-pages.patch b/SOURCES/1003-Remove-pkinit-references-from-tool-man-pages.patch index cddd2b8..32a27c7 100644 --- a/SOURCES/1003-Remove-pkinit-references-from-tool-man-pages.patch +++ b/SOURCES/1003-Remove-pkinit-references-from-tool-man-pages.patch @@ -1,4 +1,4 @@ -From c86d432ab449d86860ad6436684caa2af30da99f Mon Sep 17 00:00:00 2001 +From b3173293d8b580beb4ffd8c3e05561f670387c04 Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Wed, 22 May 2013 09:59:12 +0200 Subject: [PATCH] Remove pkinit references from tool man pages @@ -10,10 +10,10 @@ Subject: [PATCH] Remove pkinit references from tool man pages 3 files changed, 27 deletions(-) diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 -index b7a55cb748dfd5536d86e1b2634df34fd43f319b..993606d83c8117b47b73bb13ac1e7431ba03f369 100644 +index 780febf9d597d7d36b6104c0fc1be8f3d1f8fdee..ab8a428da4047db4655dbe8b3c5488f1292f8982 100644 --- a/install/tools/man/ipa-replica-install.1 +++ b/install/tools/man/ipa-replica-install.1 -@@ -76,9 +76,6 @@ An unattended installation that will never prompt for user input +@@ -77,9 +77,6 @@ An unattended installation that will never prompt for user input .SS "CERTIFICATE SYSTEM OPTIONS" .TP @@ -24,10 +24,10 @@ index b7a55cb748dfd5536d86e1b2634df34fd43f319b..993606d83c8117b47b73bb13ac1e7431 Skip check for updated CA DS schema on the remote master diff --git a/install/tools/man/ipa-replica-prepare.1 b/install/tools/man/ipa-replica-prepare.1 -index a0d47c9add145b8840065f64b79443ade504d9db..7931b71ed6fceab059a51496d9289ce25eb86b4e 100644 +index 2063657f8eb4e97fc11b1abb95a892e26b4344e6..afc5408ef87ec5cf967d00dd21aa848584c7eb1e 100644 --- a/install/tools/man/ipa-replica-prepare.1 +++ b/install/tools/man/ipa-replica-prepare.1 -@@ -41,27 +41,18 @@ File containing the Directory Server SSL certificate and private key. The files +@@ -43,27 +43,18 @@ File containing the Directory Server SSL certificate and private key. The files \fB\-\-http\-cert\-file\fR=\fIFILE\fR File containing the Apache Server SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times. .TP @@ -55,7 +55,7 @@ index a0d47c9add145b8840065f64b79443ade504d9db..7931b71ed6fceab059a51496d9289ce2 \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR Directory Manager (existing master) password .TP -@@ -77,9 +68,6 @@ Do not create reverse DNS zone +@@ -81,9 +72,6 @@ Do not create reverse DNS zone \fB\-\-ca\fR=\fICA_FILE\fR Location of CA PKCS#12 file, default /root/cacert.p12 .TP @@ -66,10 +66,10 @@ index a0d47c9add145b8840065f64b79443ade504d9db..7931b71ed6fceab059a51496d9289ce2 Prints info log messages to the output .SH "EXIT STATUS" diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 -index e5c9c319b95268af091287a7be14df6a2d06a6e0..7343f323e5447c028bba36564172524690059342 100644 +index 1eaed72119a9cd2f9876d3dc3c4a662782c18a36..3cea9fd66c133a25a611fa72a00d60a279da1b2a 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 -@@ -93,36 +93,24 @@ Type of the external CA. Possible values are "generic", "ms-cs". Default value i +@@ -91,36 +91,24 @@ Type of the external CA. Possible values are "generic", "ms-cs". Default value i \fB\-\-external\-cert\-file\fR=\fIFILE\fR File containing the IPA CA certificate and the external CA certificate chain. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. .TP @@ -107,5 +107,5 @@ index e5c9c319b95268af091287a7be14df6a2d06a6e0..7343f323e5447c028bba365641725246 File containing the CA certificate of the CA which issued the Directory Server, Apache Server and Kerberos KDC certificates. The file is accepted in PEM and DER certificate and PKCS#7 certificate chain formats. This option may be used multiple times. Use this option if the CA certificate is not present in the certificate files. .TP -- -1.9.3 +2.1.0 diff --git a/SOURCES/1004-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1004-Change-branding-to-IPA-and-Identity-Management.patch index a1e96b4..877f1c5 100644 --- a/SOURCES/1004-Change-branding-to-IPA-and-Identity-Management.patch +++ b/SOURCES/1004-Change-branding-to-IPA-and-Identity-Management.patch @@ -1,4 +1,4 @@ -From 7e7a531e1b503c6fe5e4ac0389591c546071411b Mon Sep 17 00:00:00 2001 +From b8aa1e36a06ec183709933e51ef105d7b4a96d6d Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Fri, 5 Sep 2014 11:46:59 +0200 Subject: [PATCH] Change branding to IPA and Identity Management @@ -10,17 +10,17 @@ Subject: [PATCH] Change branding to IPA and Identity Management install/migration/error.html | 4 ++-- install/migration/index.html | 2 +- install/migration/invalid.html | 2 +- - install/tools/ipa-adtrust-install | 6 +++--- - install/tools/ipa-dns-install | 2 +- + install/tools/ipa-adtrust-install | 4 ++-- install/tools/ipa-replica-conncheck | 2 +- - install/tools/ipa-server-install | 2 +- install/tools/man/ipa-adtrust-install.1 | 2 +- install/tools/man/ipa-advise.1 | 4 ++-- install/tools/man/ipa-backup.1 | 2 +- install/tools/man/ipa-ca-install.1 | 2 +- + install/tools/man/ipa-cacert-manage.1 | 2 +- install/tools/man/ipa-compat-manage.1 | 2 +- install/tools/man/ipa-csreplica-manage.1 | 2 +- install/tools/man/ipa-dns-install.1 | 2 +- + install/tools/man/ipa-kra-install.1 | 2 +- install/tools/man/ipa-ldap-updater.1 | 2 +- install/tools/man/ipa-managed-entries.1 | 2 +- install/tools/man/ipa-nis-manage.1 | 2 +- @@ -32,12 +32,14 @@ Subject: [PATCH] Change branding to IPA and Identity Management install/tools/man/ipa-restore.1 | 2 +- install/tools/man/ipa-server-certinstall.1 | 2 +- install/tools/man/ipa-server-install.1 | 2 +- + install/tools/man/ipa-server-upgrade.1 | 2 +- install/tools/man/ipactl.8 | 2 +- install/ui/index.html | 2 +- install/ui/reset_password.html | 2 +- install/ui/src/freeipa/widgets/App.js | 2 +- install/ui/sync_otp.html | 2 +- ipa-client/man/default.conf.5 | 2 +- + ipa-client/man/ipa-certupdate.1 | 2 +- ipa-client/man/ipa-client-automount.1 | 2 +- ipa-client/man/ipa-client-install.1 | 2 +- ipa-client/man/ipa-getkeytab.1 | 4 ++-- @@ -45,7 +47,11 @@ Subject: [PATCH] Change branding to IPA and Identity Management ipa-client/man/ipa-rmkeytab.1 | 2 +- ipa.1 | 2 +- ipaserver/advise/plugins/legacy_clients.py | 8 ++++---- - 41 files changed, 52 insertions(+), 52 deletions(-) + ipaserver/install/dns.py | 2 +- + ipaserver/install/ipa_kra_install.py | 2 +- + ipaserver/install/server/install.py | 2 +- + ipaserver/install/server/replicainstall.py | 2 +- + 47 files changed, 57 insertions(+), 57 deletions(-) diff --git a/install/html/browserconfig.html b/install/html/browserconfig.html index d721a4ad2a3b684a4bf45602584fee78f4613360..b0cd570403b1604449887302844c43b1e89b80e2 100644 @@ -70,7 +76,7 @@ index d721a4ad2a3b684a4bf45602584fee78f4613360..b0cd570403b1604449887302844c43b1 diff --git a/install/html/ssbrowser.html b/install/html/ssbrowser.html -index d90103228150a60bd49e91ea8c64891d53d75d7b..d066d9c26694d4f0637bccf5dd4e869db7f6da41 100644 +index 685800e16e6e77c70adf905acfca2996513d1e1d..8595f82ead70c8e6b2fcd38e2e290bd126d32e70 100644 --- a/install/html/ssbrowser.html +++ b/install/html/ssbrowser.html @@ -2,7 +2,7 @@ @@ -162,10 +168,10 @@ index f75b0bdc7d00d54d801ef66f373a09e89ead3251..16c455ca12e922ece1ea49813071fc2d diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install -index 6e55bbe3e57f1c609398dc571e90cb8677d91a33..2e235262ee1ed3aa084459a243c41a49f79b68fd 100755 +index 21e58dd9f25e82429ce8d0c776d1b512c2661809..45b75a36d855ad11a5ac8c0358127a6726ff6ef2 100755 --- a/install/tools/ipa-adtrust-install +++ b/install/tools/ipa-adtrust-install -@@ -227,11 +227,11 @@ def main(): +@@ -228,11 +228,11 @@ def main(): print "==============================================================================" print "This program will setup components needed to establish trust to AD domains for" @@ -179,28 +185,6 @@ index 6e55bbe3e57f1c609398dc571e90cb8677d91a33..2e235262ee1ed3aa084459a243c41a49 #TODO: #print " * Add a SID to all users and Posix groups" print "" -@@ -429,7 +429,7 @@ You must make sure these network ports are open: - \t * 389: (C)LDAP - \t * 445: microsoft-ds - --Additionally you have to make sure the FreeIPA LDAP server is not reachable -+Additionally you have to make sure the IPA LDAP server is not reachable - by any domain controller in the Active Directory domain by closing down - the following ports for these servers: - \tTCP Ports: -diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install -index 1d4db5f1fdff373bc0af725ee50f1210f3195b7d..cbf3faeef3644870b6978e02c95f67354cc7e61b 100755 ---- a/install/tools/ipa-dns-install -+++ b/install/tools/ipa-dns-install -@@ -97,7 +97,7 @@ def main(): - fstore = sysrestore.FileStore(paths.SYSRESTORE) - - print "==============================================================================" -- print "This program will setup DNS for the FreeIPA Server." -+ print "This program will setup DNS for the IPA Server." - print "" - print "This includes:" - print " * Configure DNS (bind)" diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck index 22348fc2158e59afc2e1aa51e3d3f51e90b99e39..e26e878c5b82b4e1e8a172a217b3225dcea642c4 100755 --- a/install/tools/ipa-replica-conncheck @@ -214,21 +198,8 @@ index 22348fc2158e59afc2e1aa51e3d3f51e90b99e39..e26e878c5b82b4e1e8a172a217b3225d except socket.timeout: pass except socket.error, e: -diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index 8f4cf457af54d47dbeda48f24a1b607e61106497..4fd4d8171ab89b805449a6625e9c5ea2d0921fa5 100755 ---- a/install/tools/ipa-server-install -+++ b/install/tools/ipa-server-install -@@ -830,7 +830,7 @@ def main(): - external = 0 - - print "==============================================================================" -- print "This program will set up the FreeIPA Server." -+ print "This program will set up the IPA Server." - print "" - print "This includes:" - if setup_ca: diff --git a/install/tools/man/ipa-adtrust-install.1 b/install/tools/man/ipa-adtrust-install.1 -index b0aa8ceefc34698329b2a13d3adbcb204f08b3a9..fe22b69ad7730b9c07c0e4cc8f8326b80738fe62 100644 +index 2658f1957d1161963bf6af75e5a086a01b95c52f..7639a0b8e94c64180a05777c1cb117c74c49806b 100644 --- a/install/tools/man/ipa-adtrust-install.1 +++ b/install/tools/man/ipa-adtrust-install.1 @@ -16,7 +16,7 @@ @@ -286,6 +257,19 @@ index aa186987a15b5203607ac76e63751f01811c4bd7..c110db03ff48fd80b4dc70cf9d1c32d5 .SH "NAME" ipa\-ca\-install \- Install a CA on a server .SH "SYNOPSIS" +diff --git a/install/tools/man/ipa-cacert-manage.1 b/install/tools/man/ipa-cacert-manage.1 +index 1f37788336048e412eee71757f236c9944860514..0b927716797068ab4f5632292615a43748eee35c 100644 +--- a/install/tools/man/ipa-cacert-manage.1 ++++ b/install/tools/man/ipa-cacert-manage.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Jan Cholasta + .\" +-.TH "ipa-cacert-manage" "1" "Aug 12 2013" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-cacert-manage" "1" "Aug 12 2013" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-cacert\-manage \- Manage CA certificates in IPA + .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-compat-manage.1 b/install/tools/man/ipa-compat-manage.1 index f22b1743e31c3b07132acfcfdd8600544f9ace6c..26470331a127af9445c4473525434c237e23dbcf 100644 --- a/install/tools/man/ipa-compat-manage.1 @@ -313,7 +297,7 @@ index 3164ea60d67db99445dac168fad967cb48be428e..bdf70302e1743d0d94c0acad7e83b5a1 ipa\-csreplica\-manage \- Manage an IPA CS replica .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-dns-install.1 b/install/tools/man/ipa-dns-install.1 -index bde30cadba9b8b461f5373b734c3edf2faf9d0af..0e12918e5d906f0606e7fb6e19f2da25c91e2a3c 100644 +index 23427b1b15ddf21ff1aba5617adab395d2f25112..b05c328e31b8672a22d060bd23d8e8d2a79353ba 100644 --- a/install/tools/man/ipa-dns-install.1 +++ b/install/tools/man/ipa-dns-install.1 @@ -16,7 +16,7 @@ @@ -325,8 +309,21 @@ index bde30cadba9b8b461f5373b734c3edf2faf9d0af..0e12918e5d906f0606e7fb6e19f2da25 .SH "NAME" ipa\-dns\-install \- Add DNS as a service to an IPA server .SH "SYNOPSIS" +diff --git a/install/tools/man/ipa-kra-install.1 b/install/tools/man/ipa-kra-install.1 +index e3133eee188af0b613fca76b51d2f5b4f8d1ba7d..4a34e46fa7e5c7bf65e7cb41c011dc19e751434d 100644 +--- a/install/tools/man/ipa-kra-install.1 ++++ b/install/tools/man/ipa-kra-install.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Ade Lee + .\" +-.TH "ipa-kra-install" "1" "Aug 24 2014" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-kra-install" "1" "Aug 24 2014" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-kra\-install \- Install a KRA on a server + .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-ldap-updater.1 b/install/tools/man/ipa-ldap-updater.1 -index 79cc316501512879fa39ba4c15fd898b976eb25e..6d819cb531372e58c81eeb7e01ebfb9bb574169b 100644 +index 4893802c2f73af177857e61135626753289ce35f..7ead55bd9708ed322083abd6c3cb9e7694850c27 100644 --- a/install/tools/man/ipa-ldap-updater.1 +++ b/install/tools/man/ipa-ldap-updater.1 @@ -16,7 +16,7 @@ @@ -391,7 +388,7 @@ index 566322cf035bbb51d1ba8b14166a1b61375015da..7f220de96cc03a1f883f585740a82bff ipa\-replica\-conncheck \- Check a replica\-master network connection before installation .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 -index 993606d83c8117b47b73bb13ac1e7431ba03f369..4452c807d963a4a501eeb802f1d96e5761e0c0f3 100644 +index ab8a428da4047db4655dbe8b3c5488f1292f8982..e00aae357ad3dc7a97a0b516bf5e005953824d1b 100644 --- a/install/tools/man/ipa-replica-install.1 +++ b/install/tools/man/ipa-replica-install.1 @@ -16,7 +16,7 @@ @@ -404,7 +401,7 @@ index 993606d83c8117b47b73bb13ac1e7431ba03f369..4452c807d963a4a501eeb802f1d96e57 ipa\-replica\-install \- Create an IPA replica .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1 -index 8a7c78f39eeb6c7902ed99e7bed37e32eb0e92dc..2c162928dc7fa1567703019e2722a1c63914876d 100644 +index c09ed362f3143e6e38716e1b3a96e90001a64674..2cdaf59984868c98e02321cf73eed016b4e478a6 100644 --- a/install/tools/man/ipa-replica-manage.1 +++ b/install/tools/man/ipa-replica-manage.1 @@ -16,7 +16,7 @@ @@ -417,7 +414,7 @@ index 8a7c78f39eeb6c7902ed99e7bed37e32eb0e92dc..2c162928dc7fa1567703019e2722a1c6 ipa\-replica\-manage \- Manage an IPA replica .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-replica-prepare.1 b/install/tools/man/ipa-replica-prepare.1 -index 7931b71ed6fceab059a51496d9289ce25eb86b4e..fd07aa55c3d107378733d0eb3c1a6f0467182d2a 100644 +index afc5408ef87ec5cf967d00dd21aa848584c7eb1e..fb68af5e1dc311ec7a6aa1e53b616bd3b4273e3f 100644 --- a/install/tools/man/ipa-replica-prepare.1 +++ b/install/tools/man/ipa-replica-prepare.1 @@ -16,7 +16,7 @@ @@ -430,7 +427,7 @@ index 7931b71ed6fceab059a51496d9289ce25eb86b4e..fd07aa55c3d107378733d0eb3c1a6f04 ipa\-replica\-prepare \- Create an IPA replica file .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-restore.1 b/install/tools/man/ipa-restore.1 -index 31734b259524e4b07312a4009184e725aafc3728..689dc133fc4f526bffac0458b0c5c25ff5a8f674 100644 +index 5f401818a47b64854c2f25fcab4ebb8f96cd3b9e..80a1e70bff1871678259c8436915420c70d475b1 100644 --- a/install/tools/man/ipa-restore.1 +++ b/install/tools/man/ipa-restore.1 @@ -16,7 +16,7 @@ @@ -456,7 +453,7 @@ index d23bbd490e2b0454b8fb908e22f33c7a611c8874..d87b6bc16cfbea8f260d2767bf20eaac ipa\-server\-certinstall \- Install new SSL server certificates .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 -index 7343f323e5447c028bba36564172524690059342..1389f80f2e13f382b08b5b718b2d7eb46d3ff58e 100644 +index 3cea9fd66c133a25a611fa72a00d60a279da1b2a..a1fd6ea76926cae8db9ebeb6c92b03b8087eb3a2 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -16,7 +16,7 @@ @@ -468,8 +465,21 @@ index 7343f323e5447c028bba36564172524690059342..1389f80f2e13f382b08b5b718b2d7eb4 .SH "NAME" ipa\-server\-install \- Configure an IPA server .SH "SYNOPSIS" +diff --git a/install/tools/man/ipa-server-upgrade.1 b/install/tools/man/ipa-server-upgrade.1 +index cbbdc590171bff0a88b67bcf1de961fd783ac35c..3db19b0f13da1f5a36bd6e8df23fc916d0401a6d 100644 +--- a/install/tools/man/ipa-server-upgrade.1 ++++ b/install/tools/man/ipa-server-upgrade.1 +@@ -2,7 +2,7 @@ + .\" Copyright (C) 2015 FreeIPA Contributors see COPYING for license + .\" + +-.TH "ipa-server-upgrade" "1" "April 02 2015" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-server-upgrade" "1" "April 02 2015" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-server\-upgrade \- upgrade IPA server + .SH "SYNOPSIS" diff --git a/install/tools/man/ipactl.8 b/install/tools/man/ipactl.8 -index 5a1fd27ad6cb88877589173709c6cf0afa357fe1..0e6e339cef0a97c27b9e992a5082b2e47f00e7bd 100644 +index 136fe9ac6fe7dbff5618543c1958565bab87502a..88dad986330c327a3f1c1f8be114f7d3e158ea9c 100644 --- a/install/tools/man/ipactl.8 +++ b/install/tools/man/ipactl.8 @@ -16,7 +16,7 @@ @@ -482,7 +492,7 @@ index 5a1fd27ad6cb88877589173709c6cf0afa357fe1..0e6e339cef0a97c27b9e992a5082b2e4 ipactl \- IPA Server Control Interface .SH "SYNOPSIS" diff --git a/install/ui/index.html b/install/ui/index.html -index ce9859074d52dd67a13afe823f2b0860eb9db8af..1ed43b0ca940d0ed8369e59cecac57cd236d8e58 100644 +index f4fe06d0bf25cad1f68e8450d4cc2787eaf0de4e..cbdf97aa59f7b9ed01ff11de17e1f9f2a868b65b 100644 --- a/install/ui/index.html +++ b/install/ui/index.html @@ -2,7 +2,7 @@ @@ -534,7 +544,7 @@ index 5814b6c578c250d253c8eabeff7a787f1b24f10b..36a51ca62899790da3b8788fcd8a32ff