diff --git a/.gitignore b/.gitignore index 24c01ff..7ac1e50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ -SOURCES/freeipa-3.3.3.tar.gz -SOURCES/rh-ipabanner.png +SOURCES/freeipa-4.1.0.tar.gz +SOURCES/header-logo.png +SOURCES/login-screen-background.jpg +SOURCES/login-screen-logo.png +SOURCES/product-name.png diff --git a/.ipa.metadata b/.ipa.metadata index 65afa93..04fe802 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1,2 +1,5 @@ -32702b534b3f82c141107820283833d54d8287f2 SOURCES/freeipa-3.3.3.tar.gz -7460c1ae34b05ea659275fe169c19f94a28db2f7 SOURCES/rh-ipabanner.png +40a07c0e64a696dccb5d377c635db136cbc7c2a5 SOURCES/freeipa-4.1.0.tar.gz +77c318cf1f4fc25cf847de0692a77859a767c0e3 SOURCES/header-logo.png +8727245558422bf966d60677568925f081b8e299 SOURCES/login-screen-background.jpg +24a29d79efbd0906777be4639957abda111fca4b SOURCES/login-screen-logo.png +af82b7b7d327bd683c7d062a6f15713ea91ebedf SOURCES/product-name.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 new file mode 100644 index 0000000..ae05dc9 --- /dev/null +++ b/SOURCES/0001-Do-not-check-if-port-8443-is-available-in-step-2-of-.patch @@ -0,0 +1,54 @@ +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-Guard-import-of-adtrustinstance-for-case-without-tru.patch b/SOURCES/0001-Guard-import-of-adtrustinstance-for-case-without-tru.patch deleted file mode 100644 index 4202105..0000000 --- a/SOURCES/0001-Guard-import-of-adtrustinstance-for-case-without-tru.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 90ac36c780d6e5d0bcb26f8c7f153d35af1db70f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 4 Nov 2013 17:15:23 +0200 -Subject: [PATCH] Guard import of adtrustinstance for case without trusts - -https://fedorahosted.org/freeipa/ticket/4011 ---- - install/tools/ipa-server-install | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index b3dcf6d93a70e2910a3d7fa62139efbf640d1cbe..458ebba550d0fe7675bd874e23c7d730c53297e6 100755 ---- a/install/tools/ipa-server-install -+++ b/install/tools/ipa-server-install -@@ -40,7 +40,12 @@ import pwd - import textwrap - from optparse import OptionGroup, OptionValueError - --from ipaserver.install import adtrustinstance -+try: -+ from ipaserver.install import adtrustinstance -+ _server_trust_ad_installed = True -+except ImportError: -+ _server_trust_ad_installed = False -+ - from ipaserver.install import dsinstance - from ipaserver.install import krbinstance - from ipaserver.install import bindinstance -@@ -493,7 +498,8 @@ def uninstall(): - httpinstance.HTTPInstance(fstore).uninstall() - krbinstance.KrbInstance(fstore).uninstall() - dsinstance.DsInstance(fstore=fstore).uninstall() -- adtrustinstance.ADTRUSTInstance(fstore).uninstall() -+ if _server_trust_ad_installed: -+ adtrustinstance.ADTRUSTInstance(fstore).uninstall() - memcacheinstance.MemcacheInstance().uninstall() - otpdinstance.OtpdInstance().uninstall() - ipaservices.restore_network_configuration(fstore, sstore) --- -1.8.3.1 - 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 new file mode 100644 index 0000000..cf1764e --- /dev/null +++ b/SOURCES/0002-Add-ipaSshPubkey-and-gidNumber-to-the-ACI-to-read-ID.patch @@ -0,0 +1,42 @@ +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-Server-does-not-detect-different-server-and-IPA-doma.patch b/SOURCES/0002-Server-does-not-detect-different-server-and-IPA-doma.patch deleted file mode 100644 index 9b81558..0000000 --- a/SOURCES/0002-Server-does-not-detect-different-server-and-IPA-doma.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 8955e9f236ea9ca3ccfd32cb17c6b4baf9d492a2 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Wed, 6 Nov 2013 10:14:40 +0100 -Subject: [PATCH] Server does not detect different server and IPA domain - -Server installer does not properly recognize a situation when server -fqdn is not in a subdomain of the IPA domain, but shares the same -suffix. - -For example, if server FQDN is ipa-idm.example.com and domain -is idm.example.com, server's FQDN is not in the main domain, but -installer does not recognize that. proper Kerberos realm-domain -mapping is not created in this case and server does not work -(httpd reports gssapi errors). - -https://fedorahosted.org/freeipa/ticket/4012 ---- - ipaserver/install/krbinstance.py | 18 +++++++++++------- - 1 file changed, 11 insertions(+), 7 deletions(-) - -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index a16e4d5f0cb3b70c6c69aac3251785ef3e8fa7f2..98687a4002cd7b19faea03acc552759e962d8832 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -24,6 +24,7 @@ - import os - import pwd - import socket -+import dns.name - - import service - import installutils -@@ -237,15 +238,18 @@ def __setup_sub_dict(self): - - # IPA server/KDC is not a subdomain of default domain - # Proper domain-realm mapping needs to be specified -- dr_map = '' -- if not self.fqdn.endswith(self.domain): -- root_logger.debug("IPA FQDN '%s' is not located in default domain '%s'" \ -- % (self.fqdn, self.domain)) -- server_host, dot, server_domain = self.fqdn.partition('.') -- root_logger.debug("Domain '%s' needs additional mapping in krb5.conf" \ -- % server_domain) -+ domain = dns.name.from_text(self.domain) -+ fqdn = dns.name.from_text(self.fqdn) -+ if not fqdn.is_subdomain(domain): -+ root_logger.debug("IPA FQDN '%s' is not located in default domain '%s'", -+ fqdn, domain) -+ server_domain = fqdn.parent().to_unicode(omit_final_dot=True) -+ root_logger.debug("Domain '%s' needs additional mapping in krb5.conf", -+ server_domain) - dr_map = " .%(domain)s = %(realm)s\n %(domain)s = %(realm)s\n" \ - % dict(domain=server_domain, realm=self.realm) -+ else: -+ dr_map = "" - self.sub_dict['OTHER_DOMAIN_REALM_MAPS'] = dr_map - - def __configure_sasl_mappings(self): --- -1.8.3.1 - diff --git a/SOURCES/0003-Allow-kernel-keyring-CCACHE-when-supported.patch b/SOURCES/0003-Allow-kernel-keyring-CCACHE-when-supported.patch deleted file mode 100644 index d205d06..0000000 --- a/SOURCES/0003-Allow-kernel-keyring-CCACHE-when-supported.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 7726ddeb7506b9b68720f55c410d7c53b7098d91 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Fri, 29 Nov 2013 13:29:20 +0100 -Subject: [PATCH 03/10] Allow kernel keyring CCACHE when supported - -Server and client installer should allow kernel keyring ccache when -supported. - -https://fedorahosted.org/freeipa/ticket/4013 ---- - install/share/krb5.conf.template | 2 +- - ipa-client/ipa-install/ipa-client-install | 7 +++++++ - ipapython/kernel_keyring.py | 17 +++++++++++++++++ - ipaserver/install/krbinstance.py | 10 ++++++++++ - 4 files changed, 35 insertions(+), 1 deletion(-) - -diff --git a/install/share/krb5.conf.template b/install/share/krb5.conf.template -index 01e66881b0a38e342886727ec205ea9b7c057ad2..7c82083e3331cfacccc1995cd9dfa6ddd88edd1f 100644 ---- a/install/share/krb5.conf.template -+++ b/install/share/krb5.conf.template -@@ -12,7 +12,7 @@ includedir /var/lib/sss/pubconf/krb5.include.d/ - rdns = false - ticket_lifetime = 24h - forwardable = yes -- -+$OTHER_LIBDEFAULTS - [realms] - $REALM = { - kdc = $FQDN:88 -diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install -index 8e4695b42e9178725353dee2a4797a8da9b635b3..a898d388ee039752044008f8525424370098580a 100755 ---- a/ipa-client/ipa-install/ipa-client-install -+++ b/ipa-client/ipa-install/ipa-client-install -@@ -43,6 +43,7 @@ try: - run, user_input, CalledProcessError, file_exists, realm_to_suffix) - import ipapython.services as ipaservices - from ipapython import ipautil, sysrestore, version, certmonger, ipaldap -+ from ipapython import kernel_keyring - from ipapython.config import IPAOptionParser - from ipalib import api, errors - from ipalib import x509 -@@ -926,6 +927,12 @@ def configure_krb5_conf(cli_realm, cli_domain, cli_server, cli_kdc, dnsok, - libopts.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'}) - libopts.append({'name':'forwardable', 'type':'option', 'value':'yes'}) - -+ # Configure KEYRING CCACHE if supported -+ if kernel_keyring.is_persistent_keyring_supported(): -+ root_logger.debug("Enabling persistent keyring CCACHE") -+ libopts.append({'name':'default_ccache_name', 'type':'option', -+ 'value':'KEYRING:persistent:%{uid}'}) -+ - opts.append({'name':'libdefaults', 'type':'section', 'value':libopts}) - opts.append({'name':'empty', 'type':'empty'}) - -diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py -index 547dd3de6b45295910b66982e99886135c06335b..d30531cabaee5c12376f0821a21a6f63cd60397c 100644 ---- a/ipapython/kernel_keyring.py -+++ b/ipapython/kernel_keyring.py -@@ -17,6 +17,8 @@ - # along with this program. If not, see . - # - -+import os -+ - from ipapython.ipautil import run - - # NOTE: Absolute path not required for keyctl since we reset the environment -@@ -47,6 +49,21 @@ def get_real_key(key): - raise ValueError('key %s not found' % key) - return stdout.rstrip() - -+def get_persistent_key(key): -+ (stdout, stderr, rc) = run(['keyctl', 'get_persistent', KEYRING, key], raiseonerr=False) -+ if rc: -+ raise ValueError('persistent key %s not found' % key) -+ return stdout.rstrip() -+ -+def is_persistent_keyring_supported(): -+ uid = os.geteuid() -+ try: -+ get_persistent_key(str(uid)) -+ except ValueError: -+ return False -+ -+ return True -+ - def has_key(key): - """ - Returns True/False whether the key exists in the keyring. -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index 98687a4002cd7b19faea03acc552759e962d8832..f1fa827d89a31f9d6d4cb7f7a78a2680f983565a 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -31,6 +31,7 @@ - from ipapython import sysrestore - from ipapython import ipautil - from ipapython import services as ipaservices -+from ipapython import kernel_keyring - from ipalib import errors - from ipapython.ipa_log_manager import * - from ipapython.dn import DN -@@ -252,6 +253,15 @@ def __setup_sub_dict(self): - dr_map = "" - self.sub_dict['OTHER_DOMAIN_REALM_MAPS'] = dr_map - -+ # Configure KEYRING CCACHE if supported -+ if kernel_keyring.is_persistent_keyring_supported(): -+ root_logger.debug("Enabling persistent keyring CCACHE") -+ self.sub_dict['OTHER_LIBDEFAULTS'] = \ -+ " default_ccache_name = KEYRING:persistent:%{uid}\n" -+ else: -+ root_logger.debug("Persistent keyring CCACHE is not enabled") -+ self.sub_dict['OTHER_LIBDEFAULTS'] = '' -+ - def __configure_sasl_mappings(self): - # we need to remove any existing SASL mappings in the directory as otherwise they - # they may conflict. --- -1.8.3.1 - diff --git a/SOURCES/0003-Fix-dns-zonemgr-validation-regression.patch b/SOURCES/0003-Fix-dns-zonemgr-validation-regression.patch new file mode 100644 index 0000000..1698d87 --- /dev/null +++ b/SOURCES/0003-Fix-dns-zonemgr-validation-regression.patch @@ -0,0 +1,27 @@ +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/0004-Fix-regression-which-prevents-creating-a-winsync-agr.patch b/SOURCES/0004-Fix-regression-which-prevents-creating-a-winsync-agr.patch deleted file mode 100644 index 5839449..0000000 --- a/SOURCES/0004-Fix-regression-which-prevents-creating-a-winsync-agr.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 2f3c2538595664796d673517eb1c91edf5712d80 Mon Sep 17 00:00:00 2001 -From: Ana Krivokapic -Date: Tue, 12 Nov 2013 14:50:57 +0100 -Subject: [PATCH] Fix regression which prevents creating a winsync agreement - -A regression, which prevented creation of a winsync agreement, -was introduced in the original fix for ticket #3989. - -https://fedorahosted.org/freeipa/ticket/3989 ---- - ipaserver/install/replication.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 4d8a4687e162155d7855e11ba5048bed2ff13fa5..c4e62fc91b4fb33c37b9f18ce167149ccd3bd54f 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -626,8 +626,9 @@ def setup_agreement(self, a_conn, b_hostname, port=389, - - if iswinsync: - self.setup_winsync_agmt(entry, win_subtree) -+ else: -+ entry['nsds5ReplicaStripAttrs'] = [" ".join(STRIP_ATTRS)] - -- entry['nsds5ReplicaStripAttrs'] = [" ".join(STRIP_ATTRS)] - a_conn.add_entry(entry) - - try: --- -1.8.3.1 - 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 new file mode 100644 index 0000000..6def83a --- /dev/null +++ b/SOURCES/0004-Handle-profile-changes-in-dogtag-ipa-ca-renew-agent.patch @@ -0,0 +1,181 @@ +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/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 new file mode 100644 index 0000000..07ade9e --- /dev/null +++ b/SOURCES/0005-Do-not-wait-for-new-CA-certificate-to-appear-in-LDAP.patch @@ -0,0 +1,170 @@ +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-trusts-Do-not-pass-base-id-to-the-subdomain-ranges.patch b/SOURCES/0005-trusts-Do-not-pass-base-id-to-the-subdomain-ranges.patch deleted file mode 100644 index 29e4c01..0000000 --- a/SOURCES/0005-trusts-Do-not-pass-base-id-to-the-subdomain-ranges.patch +++ /dev/null @@ -1,40 +0,0 @@ -From bcf89f59d86f4031f3b2ea39dc1dff9484d81e67 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Thu, 21 Nov 2013 14:44:42 +0100 -Subject: [PATCH 5/6] trusts: Do not pass base-id to the subdomain ranges - -For trusted domains base id is calculated using a murmur3 hash of the -domain Security Identifier (SID). During trust-add we create ranges for -forest root domain and other forest domains. Since --base-id explicitly -overrides generated base id for forest root domain, its value should not -be passed to other forest domains' ranges -- their base ids must be -calculated based on their SIDs. - -In case base id change for non-root forest domains is required, it can -be done manually through idrange-mod command after the trust is -established. - -https://fedorahosted.org/freeipa/ticket/4041 ---- - ipalib/plugins/trust.py | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 32a93834394273c9f896ff5fd17bfcc753fe7b8e..5ba0905030c700c7f63003eef25891c52330934b 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -375,6 +375,11 @@ def execute(self, *keys, **options): - passed_options = options - passed_options.update(range_type=created_range_type) - -+ # Do not pass the base id to the subdomains since it would -+ # clash with the root level domain -+ if 'base_id' in passed_options: -+ del passed_options['base_id'] -+ - # Try to add the range for each subdomain - try: - self.add_range(range_name, dom_sid, *keys, --- -1.8.3.1 - 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 new file mode 100644 index 0000000..cd83510 --- /dev/null +++ b/SOURCES/0006-Fail-if-certmonger-can-t-see-new-CA-certificate-in-L.patch @@ -0,0 +1,101 @@ +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-Map-NT_STATUS_INVALID_PARAMETER-to-most-likely-error.patch b/SOURCES/0006-Map-NT_STATUS_INVALID_PARAMETER-to-most-likely-error.patch deleted file mode 100644 index 52c1290..0000000 --- a/SOURCES/0006-Map-NT_STATUS_INVALID_PARAMETER-to-most-likely-error.patch +++ /dev/null @@ -1,32 +0,0 @@ -From f3292de4abee43c35c25d7ecd8b3638173fb24b8 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 12 Nov 2013 11:36:22 +0200 -Subject: [PATCH 6/6] Map NT_STATUS_INVALID_PARAMETER to most likely error - cause: clock skew - -When we get NT_STATUS_INVALID_PARAMETER in response to establish -DCE RPC pipe with Kerberos, the most likely reason is clock skew. -Suggest that it is so in the error message. - -https://fedorahosted.org/freeipa/ticket/4024 ---- - ipaserver/dcerpc.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 86bb42884067ec91477d8efb37a5e7729ad50315..0dde3473b12b857ff269a936ad9a07d098405c45 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -82,6 +82,9 @@ def is_sid_valid(sid): - -1073741614: access_denied_error, - -1073741603: - errors.ValidationError(name=_('AD domain controller'), error=_('unsupported functional level')), -+ -1073741811: # NT_STATUS_INVALID_PARAMETER -+ errors.RemoteRetrieveError( -+ reason=_('AD domain controller complains about communication sequence. It may mean unsynchronized time on both sides, for example')), - } - - dcerpc_error_messages = { --- -1.8.3.1 - diff --git a/SOURCES/0007-Fix-possible-NULL-dereference-in-ipa-kdb.patch b/SOURCES/0007-Fix-possible-NULL-dereference-in-ipa-kdb.patch new file mode 100644 index 0000000..01e8b44 --- /dev/null +++ b/SOURCES/0007-Fix-possible-NULL-dereference-in-ipa-kdb.patch @@ -0,0 +1,34 @@ +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-Remove-mod_ssl-port-workaround.patch b/SOURCES/0007-Remove-mod_ssl-port-workaround.patch deleted file mode 100644 index 020ca87..0000000 --- a/SOURCES/0007-Remove-mod_ssl-port-workaround.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 940afde411eb9ba52252ae80188f4fdbb87a9554 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 26 Nov 2013 08:53:34 +0000 -Subject: [PATCH 07/10] Remove mod_ssl port workaround. - -https://fedorahosted.org/freeipa/ticket/4021 ---- - freeipa.spec.in | 8 ++++++-- - install/tools/ipa-upgradeconfig | 2 +- - ipaserver/install/httpinstance.py | 17 ++++++++--------- - 3 files changed, 15 insertions(+), 12 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index a091164907735d659be61fe29221cbce6934c77d..69ec29d9ff58bf3a25e25b35d5f3ba1d43741124 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -114,14 +114,14 @@ Requires: krb5-server >= 1.10 - Requires: krb5-pkinit-openssl - Requires: cyrus-sasl-gssapi%{?_isa} - Requires: ntp --Requires: httpd -+Requires: httpd >= 2.4.6-6 - Requires: mod_wsgi - %if 0%{?fedora} >= 18 - Requires: mod_auth_kerb >= 5.4-16 - %else - Requires: mod_auth_kerb >= 5.4-8 - %endif --Requires: mod_nss >= 1.0.8-24 -+Requires: mod_nss >= 1.0.8-26 - Requires: python-ldap - Requires: python-krbV - Requires: acl -@@ -832,6 +832,10 @@ fi - %endif # ONLY_CLIENT - - %changelog -+* Tue Nov 26 2013 Jan Cholasta - 3.3.2-2 -+- Set minimum version of httpd to 2.4.6-6 -+- Set minimum version of mod_nss to 1.0.8-26 -+ - * Fri Oct 25 2013 Martin Kosek - 3.3.2-1 - - Remove mod_ssl conflict, it can now live with mod_nss installed - -diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig -index 41c51263d5fc8b3a0e2f28bab89fc9d2d184fdca..10526f226798c78ae75972b82a2f72b200a8aacf 100644 ---- a/install/tools/ipa-upgradeconfig -+++ b/install/tools/ipa-upgradeconfig -@@ -1047,7 +1047,7 @@ def main(): - http.remove_httpd_ccache() - http.configure_selinux_for_httpd() - http.configure_httpd_ccache() -- http.change_mod_nss_port_to_http() -+ http.change_mod_nss_port_from_http() - - ds = dsinstance.DsInstance() - ds.configure_dirsrv_ccache() -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 689e657e291b93d90038937a61f67915c0d582ec..e61a0c6d1526f29acb4647710e559a5bb32a58c0 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -253,25 +253,24 @@ def __configure_http(self): - http_fd.close() - os.chmod(target_fname, 0644) - -- def change_mod_nss_port_to_http(self): -+ def change_mod_nss_port_from_http(self): - # mod_ssl enforces SSLEngine on for vhost on 443 even though - # the listener is mod_nss. This then crashes the httpd as mod_nss - # listened port obviously does not match mod_ssl requirements. - # -- # Change port to http to workaround the mod_ssl check, the SSL is -- # enforced in the vhost later, so it is benign. -+ # The workaround for this was to change port to http. It is no longer -+ # necessary, as mod_nss now ships with default configuration which -+ # sets SSLEngine off when mod_ssl is installed. - # -- # Remove when https://bugzilla.redhat.com/show_bug.cgi?id=1023168 -- # is fixed. -- if not sysupgrade.get_upgrade_state('nss.conf', 'listen_port_updated'): -- installutils.set_directive(NSS_CONF, 'Listen', '443 http', quotes=False) -- sysupgrade.set_upgrade_state('nss.conf', 'listen_port_updated', True) -+ # Remove the workaround. -+ if sysupgrade.get_upgrade_state('nss.conf', 'listen_port_updated'): -+ installutils.set_directive(NSS_CONF, 'Listen', '443', quotes=False) -+ sysupgrade.set_upgrade_state('nss.conf', 'listen_port_updated', False) - - def __set_mod_nss_port(self): - self.fstore.backup_file(NSS_CONF) - if installutils.update_file(NSS_CONF, '8443', '443') != 0: - print "Updating port in %s failed." % NSS_CONF -- self.change_mod_nss_port_to_http() - - def __set_mod_nss_nickname(self, nickname): - installutils.set_directive(NSS_CONF, 'NSSNickname', nickname) --- -1.8.3.1 - diff --git a/SOURCES/0008-Fix-memory-leaks-in-ipa-extdom-extop.patch b/SOURCES/0008-Fix-memory-leaks-in-ipa-extdom-extop.patch new file mode 100644 index 0000000..39a260e --- /dev/null +++ b/SOURCES/0008-Fix-memory-leaks-in-ipa-extdom-extop.patch @@ -0,0 +1,57 @@ +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-subdomains-Use-AD-admin-credentials-when-trust-is-be.patch b/SOURCES/0008-subdomains-Use-AD-admin-credentials-when-trust-is-be.patch deleted file mode 100644 index f2f1a4e..0000000 --- a/SOURCES/0008-subdomains-Use-AD-admin-credentials-when-trust-is-be.patch +++ /dev/null @@ -1,147 +0,0 @@ -From 7c4828f3eb0e7b1f246f6263bdf22592d51824df Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 27 Nov 2013 12:17:43 +0200 -Subject: [PATCH 08/10] subdomains: Use AD admin credentials when trust is - being established - -When AD administrator credentials passed, they stored in realm_passwd, -not realm_password in the options. - -When passing credentials to ipaserver.dcerpc.fetch_domains(), make sure -to normalize them. - -Additionally, force Samba auth module to use NTLMSSP in case we have -credentials because at the point when trust is established, KDC is not -yet ready to issue tickets to a service in the other realm due to -MS-PAC information caching effects. The logic is a bit fuzzy because -credentials code makes decisions on what to use based on the smb.conf -parameters and Python bindings to set parameters to smb.conf make it so -that auth module believes these parameters were overidden by the user -through the command line and ignore some of options. We have to do calls -in the right order to force NTLMSSP use instead of Kerberos. - -Fixes https://fedorahosted.org/freeipa/ticket/4046 ---- - ipalib/plugins/trust.py | 13 ++++++++++--- - ipaserver/dcerpc.py | 42 ++++++++++++++++++++++++++++-------------- - 2 files changed, 38 insertions(+), 17 deletions(-) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 5ba0905030c700c7f63003eef25891c52330934b..3b1b2fc67ce333751556a5c3a59a7f89efc608f9 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -1231,10 +1231,17 @@ def execute(self, *keys, **options): - def fetch_domains_from_trust(self, trustinstance, trust_entry, **options): - trust_name = trust_entry['cn'][0] - creds = None -- password = options.get('realm_password', None) -+ password = options.get('realm_passwd', None) - if password: -- creds = u"%s%%%s" % (options.get('realm_admin'), password) -- domains = ipaserver.dcerpc.fetch_domains(self.api, trustinstance.local_flatname, trust_name, creds=creds) -+ admin_name = options.get('realm_admin') -+ sp = admin_name.split('\\') -+ if len(sp) == 1: -+ sp.insert(0, trustinstance.remote_domain.info['name']) -+ creds = u"{name}%{password}".format(name="\\".join(sp), -+ password=password) -+ domains = ipaserver.dcerpc.fetch_domains(self.api, -+ trustinstance.local_flatname, -+ trust_name, creds=creds) - result = [] - if not domains: - return None -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 0dde3473b12b857ff269a936ad9a07d098405c45..d809c416baac072a2489fbd3c167f08665b7a24e 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -655,7 +655,7 @@ def __gen_lsa_connection(self, binding): - except RuntimeError, (num, message): - raise assess_dcerpc_exception(num=num, message=message) - -- def __init_lsa_pipe(self, remote_host): -+ def init_lsa_pipe(self, remote_host): - """ - Try to initialize connection to the LSA pipe at remote host. - This method tries consequently all possible transport options -@@ -692,7 +692,7 @@ def __gen_lsa_bindings(self, remote_host): - """ - There are multiple transports to issue LSA calls. However, depending on a - system in use they may be blocked by local operating system policies. -- Generate all we can use. __init_lsa_pipe() will try them one by one until -+ Generate all we can use. init_lsa_pipe() will try them one by one until - there is one working. - - We try NCACN_NP before NCACN_IP_TCP and signed sessions before unsigned. -@@ -753,7 +753,7 @@ def parse_naming_context(self, context): - return naming_ref.match(context).group(1) - - def retrieve(self, remote_host): -- self.__init_lsa_pipe(remote_host) -+ self.init_lsa_pipe(remote_host) - - objectAttribute = lsa.ObjectAttribute() - objectAttribute.sec_qos = lsa.QosInfo() -@@ -964,34 +964,48 @@ def fetch_domains(api, mydomain, trustdomain, creds=None): - NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL = 0x00000040) - - def communicate(td): -- td.creds.guess(td.parm) -- netrc = net.Net(creds=td.creds, lp=td.parm) -- try: -- result = netrc.finddc(domain=trustdomain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) -- except RuntimeError, e: -- raise assess_dcerpc_exception(message=str(e)) -- if not result: -- return None -- td.retrieve(unicode(result.pdc_dns_name)) -- -+ td.init_lsa_pipe(td.info['dc']) - netr_pipe = netlogon.netlogon(td.binding, td.parm, td.creds) - domains = netr_pipe.netr_DsrEnumerateDomainTrusts(td.binding, 1) - return domains - - domains = None -+ domain_validator = DomainValidator(api) -+ configured = domain_validator.is_configured() -+ if not configured: -+ return None -+ - td = TrustDomainInstance('') - td.parm.set('workgroup', mydomain) -- td.creds = credentials.Credentials() -+ cr = credentials.Credentials() -+ cr.set_kerberos_state(credentials.DONT_USE_KERBEROS) -+ cr.guess(td.parm) -+ cr.set_anonymous() -+ cr.set_workstation(domain_validator.flatname) -+ netrc = net.Net(creds=cr, lp=td.parm) -+ try: -+ result = netrc.finddc(domain=trustdomain, -+ flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) -+ except RuntimeError, e: -+ raise assess_dcerpc_exception(message=str(e)) -+ -+ td.info['dc'] = unicode(result.pdc_dns_name) - if creds is None: - domval = DomainValidator(api) - (ccache_name, principal) = domval.kinit_as_http(trustdomain) -+ td.creds = credentials.Credentials() - td.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) - if ccache_name: - with installutils.private_ccache(path=ccache_name): -+ td.creds.guess(td.parm) -+ td.creds.set_workstation(domain_validator.flatname) - domains = communicate(td) - else: -+ td.creds = credentials.Credentials() - td.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS) -+ td.creds.guess(td.parm) - td.creds.parse_string(creds) -+ td.creds.set_workstation(domain_validator.flatname) - domains = communicate(td) - - if domains is None: --- -1.8.3.1 - 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 new file mode 100644 index 0000000..a9dd4a4 --- /dev/null +++ b/SOURCES/0009-Fix-various-bugs-in-ipa-opt-counter-and-ipa-otp-last.patch @@ -0,0 +1,102 @@ +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-trusts-Always-stop-and-disable-smb-service-on-uninst.patch b/SOURCES/0009-trusts-Always-stop-and-disable-smb-service-on-uninst.patch deleted file mode 100644 index d5a4486..0000000 --- a/SOURCES/0009-trusts-Always-stop-and-disable-smb-service-on-uninst.patch +++ /dev/null @@ -1,47 +0,0 @@ -From a7fffdc2685b82546c620c19fbbda545ba1b8e90 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Thu, 21 Nov 2013 15:25:27 +0100 -Subject: [PATCH 09/10] trusts: Always stop and disable smb service on - uninstall - -https://fedorahosted.org/freeipa/ticket/4042 ---- - ipaserver/install/adtrustinstance.py | 15 +++++++-------- - 1 file changed, 7 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index 6a1ede0d7eb46a824d6e9eaf7ad1226120d08809..4aa8322e3e2cfb6fbc07696097c3e6e21fc7f665 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -881,11 +881,16 @@ def uninstall(self): - if self.is_configured(): - self.print_msg("Unconfiguring %s" % self.service_name) - -- running = self.restore_state("running") -- enabled = self.restore_state("enabled") -+ # Call restore_state so that we do not leave mess in the statestore -+ # Otherwise this does nothing -+ self.restore_state("running") -+ self.restore_state("enabled") - -+ # Always try to stop and disable smb service, since we do not leave -+ # working configuration after uninstall - try: - self.stop() -+ self.disable() - except: - pass - -@@ -917,9 +922,3 @@ def uninstall(self): - - # Remove our keys from samba's keytab - self.clean_samba_keytab() -- -- if not enabled is None and not enabled: -- self.disable() -- -- if not running is None and running: -- self.start() --- -1.8.3.1 - diff --git a/SOURCES/0010-Fix-memory-leak-in-ipa-pwd-extop.patch b/SOURCES/0010-Fix-memory-leak-in-ipa-pwd-extop.patch new file mode 100644 index 0000000..a98caa9 --- /dev/null +++ b/SOURCES/0010-Fix-memory-leak-in-ipa-pwd-extop.patch @@ -0,0 +1,60 @@ +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-Use-hardening-flags-for-ipa-optd.patch b/SOURCES/0010-Use-hardening-flags-for-ipa-optd.patch deleted file mode 100644 index 68e1c3c..0000000 --- a/SOURCES/0010-Use-hardening-flags-for-ipa-optd.patch +++ /dev/null @@ -1,277 +0,0 @@ -From d55551c763d29ddd92156829fb2ae6b4f89b5184 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 27 Nov 2013 13:13:16 +0000 -Subject: [PATCH 10/11] Use hardening flags for ipa-optd. - -https://fedorahosted.org/freeipa/ticket/4010 - -Martin Kosek: note that this patch contains both Jan's original work -and squashed additional patches 206.2, 207.2, 208.2, 209.2, 212.2 -implemented to fix some of the problems introduced by the original -patch. ---- - Makefile | 3 +++ - daemons/ipa-otpd/Makefile.am | 4 ++-- - daemons/ipa-sam/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c | 4 +++- - daemons/ipa-slapi-plugins/ipa-dns/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am | 3 +-- - daemons/ipa-slapi-plugins/ipa-range-check/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-version/Makefile.am | 1 - - daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am | 1 - - freeipa.spec.in | 8 ++++++-- - ipa-client/Makefile.am | 1 - - 18 files changed, 15 insertions(+), 20 deletions(-) - -diff --git a/Makefile b/Makefile -index a21cf7e33275fd1a783e89baf237c8dcd8db6508..9ed3bb59a0f1d52e1b40430bb9516d9438b0fcb4 100644 ---- a/Makefile -+++ b/Makefile -@@ -52,6 +52,9 @@ endif - - PYTHON ?= $(shell rpm -E %__python) - -+CFLAGS := -g -O2 -Werror -Wall -Wextra -Wformat-security -Wno-unused-parameter -Wno-sign-compare -Wno-missing-field-initializers $(CFLAGS) -+export CFLAGS -+ - all: bootstrap-autogen server tests - @for subdir in $(SUBDIRS); do \ - (cd $$subdir && $(MAKE) $@) || exit 1; \ -diff --git a/daemons/ipa-otpd/Makefile.am b/daemons/ipa-otpd/Makefile.am -index ed99c3ecbdf6507d18243a665daa1418f978eea1..af82a5fe08856573d2d245608ba1dbaad171c7fe 100644 ---- a/daemons/ipa-otpd/Makefile.am -+++ b/daemons/ipa-otpd/Makefile.am -@@ -1,5 +1,5 @@ --AM_CFLAGS := $(CFLAGS) @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ --AM_LDFLAGS := $(LDFLAGS) @LDAP_LIBS@ @LIBVERTO_LIBS@ @KRAD_LIBS@ -+AM_CFLAGS := @LDAP_CFLAGS@ @LIBVERTO_CFLAGS@ -+AM_LDFLAGS := @LDAP_LIBS@ @LIBVERTO_LIBS@ @KRAD_LIBS@ - - noinst_HEADERS = internal.h - libexec_PROGRAMS = ipa-otpd -diff --git a/daemons/ipa-sam/Makefile.am b/daemons/ipa-sam/Makefile.am -index e8e22503a4d8e3821d6f455bac337feae8b34bfc..d55a187708eb5dda8ffc4c87abb2fcc854940ade 100644 ---- a/daemons/ipa-sam/Makefile.am -+++ b/daemons/ipa-sam/Makefile.am -@@ -20,7 +20,6 @@ AM_CPPFLAGS = \ - -DLDAPIDIR=\""$(localstatedir)/run"\" \ - -DHAVE_LDAP \ - -I $(KRB5_UTIL_DIR) \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(WARN_CFLAGS) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am -index f669d6b561482e165bedc1c1b2904b7f67a49a95..70b08835e5629026c80c21c83e0c749a387b73a4 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NDRNBT_CFLAGS) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c -index 54d44ebf64b1efa0dda06773736d3413a6b70977..64ec80665de5f5b0c5c1a8605e05e34e7199a23d 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.c -@@ -82,7 +82,9 @@ static int ipa_cldap_stop(Slapi_PBlock *pb) - } - - /* send stop signal to terminate worker thread */ -- write(ctx->stopfd[1], "", 1); -+ do { -+ ret = write(ctx->stopfd[1], "", 1); -+ } while (ret == -1 && errno == EINTR); - close(ctx->stopfd[1]); - - ret = pthread_join(ctx->tid, &retval); -diff --git a/daemons/ipa-slapi-plugins/ipa-dns/Makefile.am b/daemons/ipa-slapi-plugins/ipa-dns/Makefile.am -index 6d09c8d9c73755e89d91fea83ac66f088d9be553..31b7485e39af30224d97e4a759dbc5779bd61373 100644 ---- a/daemons/ipa-slapi-plugins/ipa-dns/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-dns/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am b/daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am -index 7ba754a48269f5c4ad9d2f08bc8cd7a0f8e6243c..3ce37ac10ad7d1ee077caa55a2f128f688388561 100644 ---- a/daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am -@@ -11,7 +11,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(WARN_CFLAGS) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -index df0c30562f09bf0e29464c9bb05f7befbd3997e1..7099a988878e2bc0cf840eab0b14fa9f40805a51 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am -@@ -13,7 +13,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(SSSIDMAP_CFLAGS) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am b/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am -index 0c69f4d7fd79a08d98c3b967e5ed35e3668cccc2..6e4c31aa591c37d3b7fdd7110f66303af3005605 100644 ---- a/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am b/daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am -index 9fbd03397cf36097e3c38280330cdeda1bf5950e..a3f8d4f7b0886fd7e03f425d27fb1ee98d868913 100644 ---- a/daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -index b53b2e1e445ccc9e756aa1ecb2656f19980cd001..8bd89653de51ab33e295fc6b1f1d6d93576d3c64 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am -@@ -18,13 +18,12 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(SSL_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -- -+ - AM_LDFLAGS = \ - $(KRB5_LIBS) \ - $(SSL_LIBS) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-range-check/Makefile.am b/daemons/ipa-slapi-plugins/ipa-range-check/Makefile.am -index f23a24ed8b2c8845e7bddbce86abe5a4a2fcd8cd..5aa9b5485211dc5ac699692d8c46cf59c53a9546 100644 ---- a/daemons/ipa-slapi-plugins/ipa-range-check/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-range-check/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am b/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am -index 4bfb0185ec589797125df747cc02dcf8a7ef30cd..642fdd599b9a3e8204232199e1cc4a5ee8b013ba 100644 ---- a/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am b/daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am -index 738290170da587b0bbee96d8abcda2762264ee0e..061d8483310b686db844059deb82b1465d498652 100644 ---- a/daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am -@@ -12,7 +12,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/daemons/ipa-slapi-plugins/ipa-version/Makefile.am b/daemons/ipa-slapi-plugins/ipa-version/Makefile.am -index 5396bda99c64e66428a15a17a520227f790bff00..afce915a0d76ff607c116e18ea98f959aed46d32 100644 ---- a/daemons/ipa-slapi-plugins/ipa-version/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-version/Makefile.am -@@ -13,7 +13,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(WARN_CFLAGS) \ -diff --git a/daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am b/daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am -index c41692864557e890d388e42c404c23e91ae8b1e9..3108f3c152c08d8b9883974a4c999f7bb89acc8e 100644 ---- a/daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am -+++ b/daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am -@@ -11,7 +11,6 @@ AM_CPPFLAGS = \ - -DLIBDIR=\""$(libdir)"\" \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ -- $(AM_CFLAGS) \ - $(LDAP_CFLAGS) \ - $(WARN_CFLAGS) \ - $(NULL) -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 69ec29d9ff58bf3a25e25b35d5f3ba1d43741124..ae8ee57f3ba2c0746bb0f7a1e65dab1da83cca22 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -5,6 +5,10 @@ - %global POLICYCOREUTILSVER 2.1.12-5 - %global gettext_domain ipa - -+%if (0%{?fedora} > 15 || 0%{?rhel} >= 7) -+%define _hardened_build 1 -+%endif -+ - Name: freeipa - Version: __VERSION__ - Release: __RELEASE__%{?dist} -@@ -316,8 +320,8 @@ This package contains tests that verify IPA functionality. - %setup -n freeipa-%{version} -q - - %build --export CFLAGS="$CFLAGS %{optflags}" --export CPPFLAGS="$CPPFLAGS %{optflags}" -+export CFLAGS="%{optflags} $CFLAGS" -+export LDFLAGS="%{__global_ldflags} $LDFLAGS" - %if 0%{?fedora} >= 18 - # use fedora18 platform which is based on fedora16 platform with systemd - # support + fedora18 changes -diff --git a/ipa-client/Makefile.am b/ipa-client/Makefile.am -index b7d70fd8d0d4383cac497b2978196e25893f9fe1..73076315d496d8f2be47ed18f726e5c9a6cb572f 100644 ---- a/ipa-client/Makefile.am -+++ b/ipa-client/Makefile.am -@@ -25,7 +25,6 @@ AM_CPPFLAGS = \ - -DLIBEXECDIR=\""$(libexecdir)"\" \ - -DDATADIR=\""$(datadir)"\" \ - -DLOCALEDIR=\""$(localedir)"\" \ -- $(AM_CFLAGS) \ - $(KRB5_CFLAGS) \ - $(OPENLDAP_CFLAGS) \ - $(SASL_CFLAGS) \ --- -1.8.3.1 - diff --git a/SOURCES/0011-Fix-memory-leaks-in-ipa-join.patch b/SOURCES/0011-Fix-memory-leaks-in-ipa-join.patch new file mode 100644 index 0000000..274c2d7 --- /dev/null +++ b/SOURCES/0011-Fix-memory-leaks-in-ipa-join.patch @@ -0,0 +1,107 @@ +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-test_integration-Support-external-names-for-hosts.patch b/SOURCES/0011-test_integration-Support-external-names-for-hosts.patch deleted file mode 100644 index 202b024..0000000 --- a/SOURCES/0011-test_integration-Support-external-names-for-hosts.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 36c14bf16eba793f37585b697bd1cb2750d68e36 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Thu, 24 Oct 2013 12:14:58 +0200 -Subject: [PATCH 11/11] test_integration: Support external names for hosts - -The framework had a concept of external hostnames, -which the controller uses to contact the test machines, -but they were not loaded from configuration. - -Load external names from configuration. - -This makes tests pass in setups where internal and external -hostnames are different, and the internal hostnames are not -initially resolvable from the controller. - -Martin Kosek: this patch also contains squashed patch -"test_integration: Log external hostname in Host.ldap_connect" from -Petr Viktorin aiming for better debugability of the beaker tests. ---- - ipatests/test_integration/config.py | 14 ++++++++++---- - ipatests/test_integration/host.py | 11 +++++++---- - 2 files changed, 17 insertions(+), 8 deletions(-) - -diff --git a/ipatests/test_integration/config.py b/ipatests/test_integration/config.py -index 3aa4d05d6cb5758cd0d6be64a1ac582adcc971b4..b8c5fdc7f9ce1877e34491964418a8d806168e73 100644 ---- a/ipatests/test_integration/config.py -+++ b/ipatests/test_integration/config.py -@@ -236,8 +236,10 @@ def env_normalize(env): - """Fill env variables from alternate variable names - - MASTER_env1 <- MASTER -- REPLICA_env1 <- REPLICA -- CLIENT_env1 <- CLIENT, SLAVE -+ REPLICA_env1 <- REPLICA, SLAVE -+ CLIENT_env1 <- CLIENT -+ similarly for BEAKER* variants: BEAKERMASTER1_env1 <- BEAKERMASTER, etc. -+ - CLIENT_env1 gets extended with CLIENT2 or CLIENT2_env1 - """ - def coalesce(name, *other_names): -@@ -253,8 +255,12 @@ def coalesce(name, *other_names): - else: - env[name] = '' - coalesce('MASTER_env1', 'MASTER') -- coalesce('REPLICA_env1', 'REPLICA') -- coalesce('CLIENT_env1', 'CLIENT', 'SLAVE') -+ coalesce('REPLICA_env1', 'REPLICA', 'SLAVE') -+ coalesce('CLIENT_env1', 'CLIENT') -+ -+ coalesce('BEAKERMASTER1_env1', 'BEAKERMASTER') -+ coalesce('BEAKERREPLICA1_env1', 'BEAKERREPLICA', 'BEAKERSLAVE') -+ coalesce('BEAKERCLIENT1_env1', 'BEAKERCLIENT') - - def extend(name, name2): - value = env.get(name2) -diff --git a/ipatests/test_integration/host.py b/ipatests/test_integration/host.py -index 02c82b372ce2805c0ca922319f5de1cd29b0ed82..507e19ed62b3d0a76e6e2ff6286fd83f17a68627 100644 ---- a/ipatests/test_integration/host.py -+++ b/ipatests/test_integration/host.py -@@ -32,7 +32,8 @@ class BaseHost(object): - """Representation of a remote IPA host""" - transport_class = None - -- def __init__(self, domain, hostname, role, index, ip=None): -+ def __init__(self, domain, hostname, role, index, ip=None, -+ external_hostname=None): - self.domain = domain - self.role = role - self.index = index -@@ -40,7 +41,7 @@ def __init__(self, domain, hostname, role, index, ip=None): - shortname, dot, ext_domain = hostname.partition('.') - self.shortname = shortname - self.hostname = shortname + '.' + self.domain.name -- self.external_hostname = hostname -+ self.external_hostname = external_hostname or hostname - - self.netbios = self.domain.name.split('.')[0].upper() - -@@ -96,6 +97,8 @@ def remove_log_collector(self, collector): - def from_env(cls, env, domain, hostname, role, index): - ip = env.get('BEAKER%s%s_IP_env%s' % - (role.upper(), index, domain.index), None) -+ external_hostname = env.get( -+ 'BEAKER%s%s_env%s' % (role.upper(), index, domain.index), None) - - # We need to determine the type of the host, this depends on the domain - # type, as we assume all Unix machines are in the Unix domain and -@@ -106,7 +109,7 @@ def from_env(cls, env, domain, hostname, role, index): - else: - cls = Host - -- self = cls(domain, hostname, role, index, ip) -+ self = cls(domain, hostname, role, index, ip, external_hostname) - return self - - @property -@@ -157,7 +160,7 @@ def put_file_contents(self, filename, contents): - def ldap_connect(self): - """Return an LDAPClient authenticated to this host as directory manager - """ -- self.log.info('Connecting to LDAP') -+ self.log.info('Connecting to LDAP at %s', self.external_hostname) - ldap = IPAdmin(self.external_hostname) - binddn = self.config.dirman_dn - self.log.info('LDAP bind as %s' % binddn) --- -1.8.3.1 - diff --git a/SOURCES/0012-Fix-various-bugs-in-ipap11helper.patch b/SOURCES/0012-Fix-various-bugs-in-ipap11helper.patch new file mode 100644 index 0000000..5e570e3 --- /dev/null +++ b/SOURCES/0012-Fix-various-bugs-in-ipap11helper.patch @@ -0,0 +1,108 @@ +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-ipa-client-install-Always-pass-hostname-to-the-ipa-j.patch b/SOURCES/0012-ipa-client-install-Always-pass-hostname-to-the-ipa-j.patch deleted file mode 100644 index cf4e3e1..0000000 --- a/SOURCES/0012-ipa-client-install-Always-pass-hostname-to-the-ipa-j.patch +++ /dev/null @@ -1,42 +0,0 @@ -From ab33d06556e607b4477500f77d97f6ec7ee536c3 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Tue, 26 Nov 2013 12:15:33 +0100 -Subject: [PATCH] ipa-client-install: Always pass hostname to the ipa-join - -The ipa-client-install script and ipa-join use different methods -of resolving the hostname, the former uses gethostbyaddr() call, -while the latter reads the "uinfo.nodename". - -This can result ipa-client-install failures in case of broken PTR -records. - -https://fedorahosted.org/freeipa/ticket/4027 ---- - ipa-client/ipa-install/ipa-client-install | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install -index a898d388ee039752044008f8525424370098580a..5e966a3ae9fb9d5881d0fd4e8c2509f92e665d44 100755 ---- a/ipa-client/ipa-install/ipa-client-install -+++ b/ipa-client/ipa-install/ipa-client-install -@@ -2119,13 +2119,13 @@ def install(options, env, fstore, statestore): - (ccache_fd, ccache_name) = tempfile.mkstemp() - os.close(ccache_fd) - env['KRB5CCNAME'] = os.environ['KRB5CCNAME'] = ccache_name -- join_args = ["/usr/sbin/ipa-join", "-s", cli_server[0], "-b", str(realm_to_suffix(cli_realm))] -+ join_args = ["/usr/sbin/ipa-join", -+ "-s", cli_server[0], -+ "-b", str(realm_to_suffix(cli_realm)), -+ "-h", hostname] - if options.debug: - join_args.append("-d") - env['XMLRPC_TRACE_CURL'] = 'yes' -- if options.hostname: -- join_args.append("-h") -- join_args.append(options.hostname) - if options.force_join: - join_args.append("-f") - if options.principal is not None: --- -1.8.3.1 - diff --git a/SOURCES/0013-Deadlock-in-schema-compat-plugin-between-automember_.patch b/SOURCES/0013-Deadlock-in-schema-compat-plugin-between-automember_.patch new file mode 100644 index 0000000..63ccb08 --- /dev/null +++ b/SOURCES/0013-Deadlock-in-schema-compat-plugin-between-automember_.patch @@ -0,0 +1,83 @@ +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-trust-fix-get_dn-to-distinguish-creating-and-re-addi.patch b/SOURCES/0013-trust-fix-get_dn-to-distinguish-creating-and-re-addi.patch deleted file mode 100644 index 434f2b5..0000000 --- a/SOURCES/0013-trust-fix-get_dn-to-distinguish-creating-and-re-addi.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 51f46b7acd00b324e66e5fffd8646a48dc70aa2d Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 5 Dec 2013 13:47:37 +0200 -Subject: [PATCH 13/14] trust: fix get_dn() to distinguish creating and - re-adding trusts - -Latest support for subdomains introduced regression that masked -difference between newly added trust and re-added one. - -Additionally, in case no new subdomains were found, the code was -returning None instead of an empty list which later could confuse -trustdomain-find command. - -https://fedorahosted.org/freeipa/ticket/4067 ---- - ipalib/plugins/trust.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 3b1b2fc67ce333751556a5c3a59a7f89efc608f9..76d609fd4de33edd96715deaaf7842c1de3ddaf4 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -262,7 +262,7 @@ def get_dn(self, *keys, **kwargs): - result = ldap.get_entries(DN(self.container_dn, self.env.basedn), - ldap.SCOPE_SUBTREE, filter, ['']) - except errors.NotFound: -- trust_type = u'ad' -+ return None - else: - if len(result) > 1: - raise errors.OnlyOneValueAllowed(attr='trust domain') -@@ -1244,7 +1244,7 @@ def fetch_domains_from_trust(self, trustinstance, trust_entry, **options): - trust_name, creds=creds) - result = [] - if not domains: -- return None -+ return result - - for dom in domains: - dom['trust_type'] = u'ad' --- -1.8.4.2 - diff --git a/SOURCES/0014-Stop-dirsrv-last-in-ipactl-stop.patch b/SOURCES/0014-Stop-dirsrv-last-in-ipactl-stop.patch new file mode 100644 index 0000000..b6b9e1f --- /dev/null +++ b/SOURCES/0014-Stop-dirsrv-last-in-ipactl-stop.patch @@ -0,0 +1,47 @@ +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-ipa-cldap-Cut-NetBIOS-name-after-15-characters.patch b/SOURCES/0014-ipa-cldap-Cut-NetBIOS-name-after-15-characters.patch deleted file mode 100644 index ad174dc..0000000 --- a/SOURCES/0014-ipa-cldap-Cut-NetBIOS-name-after-15-characters.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 03bfce26c944e2bf4d3073d959ed1e26d8f390a1 Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Tue, 26 Nov 2013 12:14:39 +0100 -Subject: [PATCH 14/14] ipa-cldap: Cut NetBIOS name after 15 characters - -The CLDAP DS plugin uses the uppercased first segment of the fully -qualified hostname as the NetBIOS name. We need to limit its size -to 15 characters. - -https://fedorahosted.org/freeipa/ticket/4028 ---- - daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h | 1 + - daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c | 6 +++++- - 2 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h -index 7b0c2aad1991f5f5958db62844f5777f71534794..3f420ff2c5acc7bd75bff7f042f76b9c61144461 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h -@@ -59,6 +59,7 @@ - #define IPA_PLUGIN_NAME IPA_CLDAP_PLUGIN_NAME - #define CLDAP_PORT 389 - #define MAX_DG_SIZE 4096 -+#define NETBIOS_NAME_MAX 15 - - #ifndef MAXHOSTNAMELEN - #define MAXHOSTNAMELEN 64 -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -index 7d29fe559be55607fcb6b83fa521372e5197b848..9ba05829418a0d1de46f2c7776cc15c54a9eab1c 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -@@ -161,8 +161,12 @@ static int ipa_cldap_encode_netlogon(char *fq_hostname, char *domain, - nlr->dns_domain = domain; - nlr->pdc_dns_name = fq_hostname; - nlr->domain_name = name; -- pdc_name = talloc_asprintf(nlr, "\\\\%s", fq_hostname); -+ -+ /* copy the first 15 characters of the fully qualified hostname*/ -+ pdc_name = talloc_asprintf(nlr, "\\\\%.*s", NETBIOS_NAME_MAX, fq_hostname); -+ - for (p = pdc_name; *p; p++) { -+ /* Create the NetBIOS name from the first segment of the hostname */ - if (*p == '.') { - *p = '\0'; - break; --- -1.8.4.2 - 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 new file mode 100644 index 0000000..334f889 --- /dev/null +++ b/SOURCES/0015-Fix-upgrade-do-not-use-invalid-ldap-connection.patch @@ -0,0 +1,43 @@ +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-Prevent-garbage-from-readline-on-standard-output-of-.patch b/SOURCES/0015-Prevent-garbage-from-readline-on-standard-output-of-.patch deleted file mode 100644 index f35e96a..0000000 --- a/SOURCES/0015-Prevent-garbage-from-readline-on-standard-output-of-.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 57bf3ea34f2b727ffe1977de1010fdf0f62c354a Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 10 Dec 2013 16:32:08 +0100 -Subject: [PATCH] Prevent garbage from readline on standard output of - dogtag-ipa-retrieve-agent. - -https://fedorahosted.org/freeipa/ticket/4064 ---- - install/certmonger/dogtag-ipa-retrieve-agent-submit | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/install/certmonger/dogtag-ipa-retrieve-agent-submit b/install/certmonger/dogtag-ipa-retrieve-agent-submit -index 3781fc5d01da12ce2dc01e17fc60143e82fbedc6..70cbd82d7d5cc392a2877e7478f459cc8b4a570f 100644 ---- a/install/certmonger/dogtag-ipa-retrieve-agent-submit -+++ b/install/certmonger/dogtag-ipa-retrieve-agent-submit -@@ -23,6 +23,10 @@ - # retrieve the updated certificate from IPA. - - 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 shutil - import tempfile --- -1.8.4.2 - diff --git a/SOURCES/0016-Do-not-build-tests.patch b/SOURCES/0016-Do-not-build-tests.patch deleted file mode 100644 index 3717767..0000000 --- a/SOURCES/0016-Do-not-build-tests.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0c1c338accaf23b993781535c68bdaf93ba05430 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Mon, 6 Jan 2014 10:47:19 +0100 -Subject: [PATCH] Do not build tests - -Tests have been moved to other SRPM. ---- - Makefile | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Makefile b/Makefile -index 9ed3bb59a0f1d52e1b40430bb9516d9438b0fcb4..7a1e7fd9dcf916d2a238c44ec34bd33fe8989c03 100644 ---- a/Makefile -+++ b/Makefile -@@ -55,7 +55,7 @@ PYTHON ?= $(shell rpm -E %__python) - CFLAGS := -g -O2 -Werror -Wall -Wextra -Wformat-security -Wno-unused-parameter -Wno-sign-compare -Wno-missing-field-initializers $(CFLAGS) - export CFLAGS - --all: bootstrap-autogen server tests -+all: bootstrap-autogen server - @for subdir in $(SUBDIRS); do \ - (cd $$subdir && $(MAKE) $@) || exit 1; \ - done -@@ -77,7 +77,7 @@ client-autogen: version-update - tests-man-autogen: version-update - cd ipatests/man; if [ ! -e Makefile ]; then ../../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi - --install: all server-install tests-install -+install: all server-install - @for subdir in $(SUBDIRS); do \ - (cd $$subdir && $(MAKE) $@) || exit 1; \ - done --- -1.8.4.2 - 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 new file mode 100644 index 0000000..f74ac1e --- /dev/null +++ b/SOURCES/0016-Ensure-that-a-password-exists-after-OTP-validation.patch @@ -0,0 +1,73 @@ +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-PKI-service-restart-after-CA-renewal-failed.patch b/SOURCES/0017-PKI-service-restart-after-CA-renewal-failed.patch deleted file mode 100644 index 947e53a..0000000 --- a/SOURCES/0017-PKI-service-restart-after-CA-renewal-failed.patch +++ /dev/null @@ -1,198 +0,0 @@ -From 34c054ea9203ffa804bafb20afa236af867ce572 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 15 Oct 2013 17:47:12 +0000 -Subject: [PATCH] PKI service restart after CA renewal failed - -Fix both the service restart procedure and registration of old -pki-cad well known service name. - -This patch was adapted from original patch of Jan Cholasta 178 to -fix ticket 4092. - -https://fedorahosted.org/freeipa/ticket/4092 ---- - install/restart_scripts/renew_ca_cert | 16 +++++++++------- - install/restart_scripts/restart_pkicad | 30 ++++++++++++++++++------------ - install/restart_scripts/stop_pkicad | 16 ++++++++-------- - ipapython/dogtag.py | 4 ++++ - ipapython/platform/base/__init__.py | 2 +- - ipaserver/install/cainstance.py | 4 ++-- - 6 files changed, 42 insertions(+), 30 deletions(-) - -diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert -index ab394b970eaee28bc386d4d1ba737643414e2680..b10e4b842f3b9a54962402cddce8710eae4538b8 100644 ---- a/install/restart_scripts/renew_ca_cert -+++ b/install/restart_scripts/renew_ca_cert -@@ -49,6 +49,7 @@ api.finalize() - - configured_constants = dogtag.configured_constants(api) - alias_dir = configured_constants.ALIAS_DIR -+dogtag_service = ipaservices.knownservices[configured_constants.SERVICE_NAME] - dogtag_instance = configured_constants.PKI_INSTANCE_NAME - - # Fetch the new certificate -@@ -106,12 +107,13 @@ if nickname == 'auditSigningCert cert-pki-ca': - # off the servlet to verify that the CA is actually up and responding so - # when this returns it should be good-to-go. The CA was stopped in the - # pre-save state. --syslog.syslog(syslog.LOG_NOTICE, 'Starting %sd' % dogtag_instance) -+syslog.syslog(syslog.LOG_NOTICE, 'Starting %s' % dogtag_service.service_name) - try: -- if configured_constants.DOGTAG_VERSION == 9: -- ipaservices.knownservices.pki_cad.start(dogtag_instance) -- else: -- ipaservices.knownservices.pki_tomcatd.start(dogtag_instance) -+ dogtag_service.start(dogtag_instance) - except Exception, e: -- syslog.syslog(syslog.LOG_ERR, "Cannot start %sd: %s" % -- (dogtag_instance, str(e))) -+ syslog.syslog( -+ syslog.LOG_ERR, -+ "Cannot start %s: %s" % (dogtag_service.service_name, e)) -+else: -+ syslog.syslog( -+ syslog.LOG_NOTICE, "Started %s" % dogtag_service.service_name) -diff --git a/install/restart_scripts/restart_pkicad b/install/restart_scripts/restart_pkicad -index a58c3f31e1bd288587842ba5fc4335c967b9405e..f840aeb1a228aee88b1c498700f733f1b90686f0 100644 ---- a/install/restart_scripts/restart_pkicad -+++ b/install/restart_scripts/restart_pkicad -@@ -33,18 +33,25 @@ api.finalize() - - configured_constants = dogtag.configured_constants(api) - alias_dir = configured_constants.ALIAS_DIR -+dogtag_service = ipaservices.knownservices[configured_constants.SERVICE_NAME] - dogtag_instance = configured_constants.PKI_INSTANCE_NAME - - # dogtag opens its NSS database in read/write mode so we need it - # shut down so certmonger can open it read/write mode. This avoids - # database corruption. It should already be stopped by the pre-command - # but lets be sure. --if ipaservices.knownservices.pki_cad.is_running(dogtag_instance): -+if dogtag_service.is_running(dogtag_instance): -+ syslog.syslog( -+ syslog.LOG_NOTICE, "Stopping %s" % dogtag_service.service_name) - try: -- ipaservices.knownservices.pki_cad.stop(dogtag_instance) -+ dogtag_service.stop(dogtag_instance) - except Exception, e: -- syslog.syslog(syslog.LOG_ERR, "Cannot stop %sd: %s" % -- (dogtag_instance, str(e))) -+ syslog.syslog( -+ syslog.LOG_ERR, -+ "Cannot stop %s: %s" % (dogtag_service.service_name, e)) -+ else: -+ syslog.syslog( -+ syslog.LOG_NOTICE, "Stopped %s" % dogtag_service.service_name) - - # Fix permissions on the audit cert if we're updating it - if nickname == 'auditSigningCert cert-pki-ca': -@@ -55,14 +62,13 @@ if nickname == 'auditSigningCert cert-pki-ca': - ] - db.run_certutil(args) - -+syslog.syslog(syslog.LOG_NOTICE, 'Starting %s' % dogtag_service.service_name) - try: -- if configured_constants.DOGTAG_VERSION == 9: -- ipaservices.knownservices.pki_cad.start(dogtag_instance) -- else: -- ipaservices.knownservices.pki_tomcatd.start(dogtag_instance) -+ dogtag_service.start(dogtag_instance) - except Exception, e: -- syslog.syslog(syslog.LOG_ERR, "Cannot start %sd: %s" % -- (dogtag_instance, str(e))) -+ syslog.syslog( -+ syslog.LOG_ERR, -+ "Cannot start %s: %s" % (dogtag_service.service_name, e)) - else: -- syslog.syslog(syslog.LOG_NOTICE, "certmonger started %sd, nickname '%s'" % -- (dogtag_instance, nickname)) -+ syslog.syslog( -+ syslog.LOG_NOTICE, "Started %s" % dogtag_service.service_name) -diff --git a/install/restart_scripts/stop_pkicad b/install/restart_scripts/stop_pkicad -index c8589b286eefbe1c3d79e2a6dab7adfd3ff56b2a..bbaf8895e3a86899ee5bd794eb595fd43316028b 100644 ---- a/install/restart_scripts/stop_pkicad -+++ b/install/restart_scripts/stop_pkicad -@@ -29,15 +29,15 @@ api.bootstrap(context='restart') - api.finalize() - - configured_constants = dogtag.configured_constants(api) -+dogtag_service = ipaservices.knownservices[configured_constants.SERVICE_NAME] - dogtag_instance = configured_constants.PKI_INSTANCE_NAME - --syslog.syslog(syslog.LOG_NOTICE, "certmonger stopping %sd" % dogtag_instance) -- -+syslog.syslog(syslog.LOG_NOTICE, "Stopping %s" % dogtag_service.service_name) - try: -- if configured_constants.DOGTAG_VERSION == 9: -- ipaservices.knownservices.pki_cad.stop(dogtag_instance) -- else: -- ipaservices.knownservices.pki_tomcatd.stop(dogtag_instance) -+ dogtag_service.stop(dogtag_instance) - except Exception, e: -- syslog.syslog(syslog.LOG_ERR, "Cannot stop %sd: %s" % -- (dogtag_instance, str(e))) -+ syslog.syslog( -+ syslog.LOG_ERR, "Cannot stop %s: %s" % (dogtag_service.service_name, e)) -+else: -+ syslog.syslog( -+ syslog.LOG_NOTICE, "Stopped %s" % dogtag_service.service_name) -diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py -index ea769b0275c4642d5da457996165e5a348cb7299..f829b9340d1ce55b2adae4817018de11b894c92d 100644 ---- a/ipapython/dogtag.py -+++ b/ipapython/dogtag.py -@@ -62,6 +62,8 @@ class Dogtag10Constants(object): - SERVICE_PROFILE_DIR = '%s/ca/profiles/ca' % PKI_ROOT - ALIAS_DIR = '/etc/pki/pki-tomcat/alias' - -+ SERVICE_NAME = 'pki_tomcatd' -+ - RACERT_LINE_SEP = '\n' - - IPA_SERVICE_PROFILE = '%s/caIPAserviceCert.cfg' % SERVICE_PROFILE_DIR -@@ -92,6 +94,8 @@ class Dogtag9Constants(object): - SERVICE_PROFILE_DIR = '%s/profiles/ca' % PKI_ROOT - ALIAS_DIR = '%s/alias' % PKI_ROOT - -+ SERVICE_NAME = 'pki-cad' -+ - RACERT_LINE_SEP = '\r\n' - - ADMIN_SECURE_PORT = 9445 -diff --git a/ipapython/platform/base/__init__.py b/ipapython/platform/base/__init__.py -index e2aa33faf9ccf182c778dfdbd8fd68d3686deae0..d76bc73a7d159c2dd43e281fa9916f245d88aaf3 100644 ---- a/ipapython/platform/base/__init__.py -+++ b/ipapython/platform/base/__init__.py -@@ -27,7 +27,7 @@ - wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc', - 'messagebus', 'nslcd', 'nscd', 'ntpd', 'portmap', - 'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd', -- 'rpcidmapd', 'pki_tomcatd', 'pki-cad', 'chronyd'] -+ 'rpcidmapd', 'pki_tomcatd', 'pki_cad', 'chronyd'] - - # System may support more time&date services. FreeIPA supports ntpd only, other - # services will be disabled during IPA installation -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index ac5c81de8c57194160cbfd2fa79c776bf2f39625..52c91b68c2d073a9b1c6aedc1811aa26db046e6b 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1283,7 +1283,7 @@ def enable_client_auth_to_db(self): - """ - caconfig = dogtag.install_constants.CS_CFG_PATH - -- with stopped_service('pki_tomcatd', -+ with stopped_service(self.dogtag_constants.SERVICE_NAME, - instance_name=self.dogtag_constants.PKI_INSTANCE_NAME): - - # Enable file publishing, disable LDAP -@@ -1723,7 +1723,7 @@ def update_cert_config(nickname, cert, dogtag_constants=None): - 'subsystemCert cert-pki-ca': 'ca.subsystem.cert', - 'Server-Cert cert-pki-ca': 'ca.sslserver.cert'} - -- with stopped_service('pki_tomcatd', -+ with stopped_service(dogtag_constants.SERVICE_NAME, - instance_name=dogtag_constants.PKI_INSTANCE_NAME): - - installutils.set_directive(dogtag.configured_constants().CS_CFG_PATH, --- -1.8.4.2 - 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 new file mode 100644 index 0000000..022c014 --- /dev/null +++ b/SOURCES/0017-ipa-restore-Don-t-crash-if-AD-trust-is-not-installed.patch @@ -0,0 +1,53 @@ +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/0018-hbactest-does-not-work-for-external-users.patch b/SOURCES/0018-hbactest-does-not-work-for-external-users.patch deleted file mode 100644 index 4961b8b..0000000 --- a/SOURCES/0018-hbactest-does-not-work-for-external-users.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 01e98be318caa921302726b48f05166b0ce00f21 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Fri, 10 Jan 2014 12:41:29 +0100 -Subject: [PATCH] hbactest does not work for external users - -Original patch for ticket #3803 implemented support to resolve SIDs -through SSSD. However, it also broke hbactest for external users. The -result of the updated external member group search must be local -non-external groups, not the external ones. Otherwise the rule is not -matched. - -https://fedorahosted.org/freeipa/ticket/3803 ---- - ipalib/plugins/hbactest.py | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/ipalib/plugins/hbactest.py b/ipalib/plugins/hbactest.py -index fed39b05d8ac75254575cf211d338ab85b093cb8..cc18890ce3ca589a0d086aa263795f9c4ff61cb6 100644 ---- a/ipalib/plugins/hbactest.py -+++ b/ipalib/plugins/hbactest.py -@@ -400,14 +400,16 @@ def execute(self, *args, **options): - ldap = self.api.Backend.ldap2 - group_container = DN(api.env.container_group, api.env.basedn) - try: -- entries, truncated = ldap.find_entries(filter_sids, ['cn'], group_container) -+ entries, truncated = ldap.find_entries(filter_sids, ['memberof'], group_container) - except errors.NotFound: - request.user.groups = [] - else: - groups = [] - for dn, entry in entries: -- if dn.endswith(group_container): -- groups.append(dn[0][0].value) -+ memberof_dns = entry.get('memberof', []) -+ for memberof_dn in memberof_dns: -+ if memberof_dn.endswith(group_container): -+ groups.append(memberof_dn[0][0].value) - request.user.groups = sorted(set(groups)) - else: - # try searching for a local user --- -1.8.4.2 - 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 new file mode 100644 index 0000000..c37297e --- /dev/null +++ b/SOURCES/0018-ranges-prohibit-setting-rid-base-with-ipa-trust-ad-p.patch @@ -0,0 +1,159 @@ +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-Change-the-way-we-determine-if-the-host-has-a-passwo.patch b/SOURCES/0019-Change-the-way-we-determine-if-the-host-has-a-passwo.patch deleted file mode 100644 index 118ee8a..0000000 --- a/SOURCES/0019-Change-the-way-we-determine-if-the-host-has-a-passwo.patch +++ /dev/null @@ -1,72 +0,0 @@ -From b574423a54dbff7dbca89c6cee49f0304f2393e1 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Tue, 14 Jan 2014 14:23:47 -0500 -Subject: [PATCH 19/25] Change the way we determine if the host has a password - set. - -When creating a host with a password we don't set a Kerberos -principal or add the Kerberos objectclasses. Those get added when the -host is enrolled. If one passed in --password= (so no password) then -we incorrectly thought the user was in fact setting a password, so the -principal and objectclasses weren't updated. - -https://fedorahosted.org/freeipa/ticket/4102 ---- - ipalib/plugins/host.py | 2 +- - ipatests/test_xmlrpc/test_host_plugin.py | 27 +++++++++++++++++++++++++++ - 2 files changed, 28 insertions(+), 1 deletion(-) - -diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py -index 7aa94aa95ba9be17c308546d5d2fe247f27a07b3..9d45e270ff8221e4b9380684cb56112db4af4f52 100644 ---- a/ipalib/plugins/host.py -+++ b/ipalib/plugins/host.py -@@ -425,7 +425,7 @@ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - entry_attrs['l'] = entry_attrs['locality'] - entry_attrs['cn'] = keys[-1] - entry_attrs['serverhostname'] = keys[-1].split('.', 1)[0] -- if 'userpassword' not in entry_attrs and not options.get('random', False): -+ if not entry_attrs.get('userpassword', False) and not options.get('random', False): - entry_attrs['krbprincipalname'] = 'host/%s@%s' % ( - keys[-1], self.api.env.realm - ) -diff --git a/ipatests/test_xmlrpc/test_host_plugin.py b/ipatests/test_xmlrpc/test_host_plugin.py -index a23a34112f5c041a8325d5090580b535d93c7a72..7b64398fadd236b9b06723ef561cb19d61bca6d5 100644 ---- a/ipatests/test_xmlrpc/test_host_plugin.py -+++ b/ipatests/test_xmlrpc/test_host_plugin.py -@@ -863,6 +863,33 @@ class test_host(Declarative): - ), - ), - -+ -+ dict( -+ desc='Create a host with a NULL password', -+ command=('host_add', [fqdn3], -+ dict( -+ description=u'Test host 3', -+ force=True, -+ userpassword=None, -+ ), -+ ), -+ expected=dict( -+ value=fqdn3, -+ summary=u'Added host "%s"' % fqdn3, -+ result=dict( -+ dn=dn3, -+ fqdn=[fqdn3], -+ description=[u'Test host 3'], -+ krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)], -+ objectclass=objectclasses.host, -+ ipauniqueid=[fuzzy_uuid], -+ managedby_host=[u'%s' % fqdn3], -+ has_keytab=False, -+ has_password=False, -+ ), -+ ), -+ ), -+ - ] - - class test_host_false_pwd_change(XMLRPC_test): --- -1.8.4.2 - 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 new file mode 100644 index 0000000..47342c5 --- /dev/null +++ b/SOURCES/0019-ldapupdater-set-baserid-to-0-for-ipa-ad-trust-posix-.patch @@ -0,0 +1,102 @@ +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 new file mode 100644 index 0000000..03e655f --- /dev/null +++ b/SOURCES/0020-idrange-include-raw-range-type-in-output.patch @@ -0,0 +1,29 @@ +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-sudoOrder-missing-in-sudoers.patch b/SOURCES/0020-sudoOrder-missing-in-sudoers.patch deleted file mode 100644 index 6f81e52..0000000 --- a/SOURCES/0020-sudoOrder-missing-in-sudoers.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 4e5f306c4a544d449a763b46baea0ebfdb0d5785 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Wed, 15 Jan 2014 08:58:16 +0100 -Subject: [PATCH 20/25] sudoOrder missing in sudoers - -sudoers compat plugin configuration missed the sudoOrder attribute -and it thus did not show up in ou=sudoers. Add the definion to update -file. - -https://fedorahosted.org/freeipa/ticket/4107 ---- - install/updates/10-schema_compat.update | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/install/updates/10-schema_compat.update b/install/updates/10-schema_compat.update -index e65e67afc40f10eee342afc12e2132d36e9c2a1a..1199ef3861fb60e204cd0cd6272a829b495cdde7 100644 ---- a/install/updates/10-schema_compat.update -+++ b/install/updates/10-schema_compat.update -@@ -21,3 +21,5 @@ dn: cn=computers, cn=Schema Compatibility, cn=plugins, - default:schema-compat-entry-attribute: cn=%{fqdn} - default:schema-compat-entry-attribute: macAddress=%{macAddress} - -+dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config -+add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} --- -1.8.4.2 - diff --git a/SOURCES/0021-Add-missing-example-to-sudorule.patch b/SOURCES/0021-Add-missing-example-to-sudorule.patch deleted file mode 100644 index 5bae186..0000000 --- a/SOURCES/0021-Add-missing-example-to-sudorule.patch +++ /dev/null @@ -1,45 +0,0 @@ -From f85b3ba942c0347c197cd738fab444fe9a697a62 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Wed, 15 Jan 2014 09:31:37 +0100 -Subject: [PATCH 21/25] Add missing example to sudorule - -https://fedorahosted.org/freeipa/ticket/4090 ---- - ipalib/plugins/sudorule.py | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py -index a89941cb6ab9b258de26bb7cf3632dc0acc7e20e..9644aafa263b4790c8123d177f0ccd10b572f0f0 100644 ---- a/ipalib/plugins/sudorule.py -+++ b/ipalib/plugins/sudorule.py -@@ -52,7 +52,26 @@ - -h ipa.example.com -ZZ -D "cn=Directory Manager" \ - uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com - --For more information, see the FreeIPA Documentation to Sudo. -+EXAMPLES: -+ -+ Create a new rule: -+ ipa sudorule-add readfiles -+ -+ Add sudo command object and add it as allowed command in the rule: -+ ipa sudocmd-add /usr/bin/less -+ ipa sudorule-add-allow-command readfiles --sudocmds /usr/bin/less -+ -+ Add a host to the rule: -+ ipa sudorule-add-host readfiles --hosts server.example.com -+ -+ Add a user to the rule: -+ ipa sudorule-add-user readfiles --users jsmith -+ -+ Add a special Sudo rule for default Sudo server configuration: -+ ipa sudorule-add defaults -+ -+ Set a default Sudo option: -+ ipa sudorule-add-option defaults --sudooption '!authenticate' - """) - - topic = ('sudo', _('Commands for controlling sudo configuration')) --- -1.8.4.2 - 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 new file mode 100644 index 0000000..ebcb9ab --- /dev/null +++ b/SOURCES/0021-webui-prohibit-setting-rid-base-with-ipa-trust-ad-po.patch @@ -0,0 +1,153 @@ +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 new file mode 100644 index 0000000..c41a1f3 --- /dev/null +++ b/SOURCES/0022-Fix-CA-certificate-backup-and-restore.patch @@ -0,0 +1,208 @@ +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-Fix-ipa-client-automount-uninstall-when-fstore-is-em.patch b/SOURCES/0022-Fix-ipa-client-automount-uninstall-when-fstore-is-em.patch deleted file mode 100644 index e478189..0000000 --- a/SOURCES/0022-Fix-ipa-client-automount-uninstall-when-fstore-is-em.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 8782235cff60229051c82880131fb11c82659a0b Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 15 Jan 2014 10:48:10 +0100 -Subject: [PATCH 22/25] Fix ipa-client-automount uninstall when fstore is - empty. - -https://fedorahosted.org/freeipa/ticket/4091 ---- - ipa-client/ipa-install/ipa-client-automount | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipa-client/ipa-install/ipa-client-automount b/ipa-client/ipa-install/ipa-client-automount -index 2ce31dcb9605941fa8734caad7ed5ba9b5ce1e01..62531bfe1d923b1705aed1187da6766b54c90a0c 100755 ---- a/ipa-client/ipa-install/ipa-client-automount -+++ b/ipa-client/ipa-install/ipa-client-automount -@@ -360,7 +360,7 @@ def main(): - - fstore = sysrestore.FileStore('/var/lib/ipa-client/sysrestore') - statestore = sysrestore.StateFile('/var/lib/ipa-client/sysrestore') -- if not fstore.has_files(): -+ if not fstore.has_files() and not os.path.exists('/etc/ipa/default.conf'): - sys.exit('IPA client is not configured on this system.\n') - - options, args = parse_options() --- -1.8.4.2 - diff --git a/SOURCES/0023-Fix-DNS-installer-adds-invalid-zonemgr-email.patch b/SOURCES/0023-Fix-DNS-installer-adds-invalid-zonemgr-email.patch new file mode 100644 index 0000000..0de6d63 --- /dev/null +++ b/SOURCES/0023-Fix-DNS-installer-adds-invalid-zonemgr-email.patch @@ -0,0 +1,43 @@ +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/0023-trust-fetch-domains-create-ranges-for-new-child-doma.patch b/SOURCES/0023-trust-fetch-domains-create-ranges-for-new-child-doma.patch deleted file mode 100644 index fca1bd3..0000000 --- a/SOURCES/0023-trust-fetch-domains-create-ranges-for-new-child-doma.patch +++ /dev/null @@ -1,346 +0,0 @@ -From f446cde6f626f5a4b086a542121486bde42d0dc7 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 14 Jan 2014 13:55:56 +0200 -Subject: [PATCH 23/25] trust-fetch-domains: create ranges for new child - domains - -When trust is added, we do create ranges for discovered child domains. -However, this functionality was not available through -'trust-fetch-domains' command. - -Additionally, make sure non-existing trust will report proper error in -trust-fetch-domains. - -https://fedorahosted.org/freeipa/ticket/4111 -https://fedorahosted.org/freeipa/ticket/4104 ---- - ipalib/plugins/trust.py | 256 +++++++++++++++++++++++++----------------------- - 1 file changed, 135 insertions(+), 121 deletions(-) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 76d609fd4de33edd96715deaaf7842c1de3ddaf4..a16c23083662fd674c45ba54b9dfb9f4837160df 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -188,6 +188,114 @@ def make_trust_dn(env, trust_type, dn): - return DN(dn, container_dn) - return dn - -+def add_range(self, range_name, dom_sid, *keys, **options): -+ """ -+ First, we try to derive the parameters of the ID range based on the -+ information contained in the Active Directory. -+ -+ If that was not successful, we go for our usual defaults (random base, -+ range size 200 000, ipa-ad-trust range type). -+ -+ Any of these can be overriden by passing appropriate CLI options -+ to the trust-add command. -+ """ -+ -+ range_size = None -+ range_type = None -+ base_id = None -+ -+ # First, get information about ID space from AD -+ # However, we skip this step if other than ipa-ad-trust-posix -+ # range type is enforced -+ -+ if options.get('range_type', None) in (None, u'ipa-ad-trust-posix'): -+ -+ # Get the base dn -+ domain = keys[-1] -+ basedn = realm_to_suffix(domain) -+ -+ # Search for information contained in -+ # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System -+ info_filter = '(objectClass=msSFU30DomainInfo)' -+ info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\ -+ + basedn -+ -+ # Get the domain validator -+ domain_validator = ipaserver.dcerpc.DomainValidator(self.api) -+ if not domain_validator.is_configured(): -+ raise errors.NotFound( -+ reason=_('Cannot search in trusted domains without own ' -+ 'domain configured. Make sure you have run ' -+ 'ipa-adtrust-install on the IPA server first')) -+ -+ # KDC might not get refreshed data at the first time, -+ # retry several times -+ for retry in range(10): -+ info_list = domain_validator.search_in_dc(domain, -+ info_filter, -+ None, -+ SCOPE_SUBTREE, -+ basedn=info_dn, -+ quiet=True) -+ -+ if info_list: -+ info = info_list[0] -+ break -+ else: -+ sleep(2) -+ -+ required_msSFU_attrs = ['msSFU30MaxUidNumber', 'msSFU30OrderNumber'] -+ -+ if not info_list: -+ # We were unable to gain UNIX specific info from the AD -+ self.log.debug("Unable to gain POSIX info from the AD") -+ else: -+ if all(attr in info for attr in required_msSFU_attrs): -+ self.log.debug("Able to gain POSIX info from the AD") -+ range_type = u'ipa-ad-trust-posix' -+ -+ max_uid = info.get('msSFU30MaxUidNumber') -+ max_gid = info.get('msSFU30MaxGidNumber', None) -+ max_id = int(max(max_uid, max_gid)[0]) -+ -+ base_id = int(info.get('msSFU30OrderNumber')[0]) -+ range_size = (1 + (max_id - base_id) / DEFAULT_RANGE_SIZE)\ -+ * DEFAULT_RANGE_SIZE -+ -+ # Second, options given via the CLI options take precedence to discovery -+ if options.get('range_type', None): -+ range_type = options.get('range_type', None) -+ elif not range_type: -+ range_type = u'ipa-ad-trust' -+ -+ if options.get('range_size', None): -+ range_size = options.get('range_size', None) -+ elif not range_size: -+ range_size = DEFAULT_RANGE_SIZE -+ -+ if options.get('base_id', None): -+ base_id = options.get('base_id', None) -+ elif not base_id: -+ # Generate random base_id if not discovered nor given via CLI -+ base_id = DEFAULT_RANGE_SIZE + ( -+ pysss_murmur.murmurhash3( -+ dom_sid, -+ len(dom_sid), 0xdeadbeefL -+ ) % 10000 -+ ) * DEFAULT_RANGE_SIZE -+ -+ # Finally, add new ID range -+ self.api.Command['idrange_add'](range_name, -+ ipabaseid=base_id, -+ ipaidrangesize=range_size, -+ ipabaserid=0, -+ iparangetype=range_type, -+ ipanttrusteddomainsid=dom_sid) -+ -+ # Return the values that were generated inside this function -+ return range_type, range_size, base_id -+ -+ - class trust(LDAPObject): - """ - Trust object. -@@ -258,15 +366,11 @@ def get_dn(self, *keys, **kwargs): - filter = ldap.make_filter({'objectclass': ['ipaNTTrustedDomain'], 'cn': [keys[-1]] }, - rules=ldap.MATCH_ALL) - filter = ldap.combine_filters((filter, "ipaNTSIDBlacklistIncoming=*"), rules=ldap.MATCH_ALL) -- try: -- result = ldap.get_entries(DN(self.container_dn, self.env.basedn), -- ldap.SCOPE_SUBTREE, filter, ['']) -- except errors.NotFound: -- return None -- else: -- if len(result) > 1: -- raise errors.OnlyOneValueAllowed(attr='trust domain') -- return result[0].dn -+ result = ldap.get_entries(DN(self.container_dn, self.env.basedn), -+ ldap.SCOPE_SUBTREE, filter, ['']) -+ if len(result) > 1: -+ raise errors.OnlyOneValueAllowed(attr='trust domain') -+ return result[0].dn - - dn=make_trust_dn(self.env, trust_type, DN(*sdn)) - return dn -@@ -341,8 +445,8 @@ def execute(self, *keys, **options): - # Store the created range type, since for POSIX trusts no - # ranges for the subdomains should be added, POSIX attributes - # provide a global mapping across all subdomains -- (created_range_type, _, _) = self.add_range(range_name, dom_sid, -- *keys, **options) -+ (created_range_type, _, _) = add_range(self, range_name, dom_sid, -+ *keys, **options) - else: - created_range_type = old_range['result']['iparangetype'][0] - -@@ -382,8 +486,8 @@ def execute(self, *keys, **options): - - # Try to add the range for each subdomain - try: -- self.add_range(range_name, dom_sid, *keys, -- **passed_options) -+ add_range(self, range_name, dom_sid, *keys, -+ **passed_options) - except errors.DuplicateEntry: - pass - -@@ -549,120 +653,17 @@ def validate_range(self, *keys, **options): - - return old_range, range_name, dom_sid - -- def add_range(self, range_name, dom_sid, *keys, **options): -- """ -- First, we try to derive the parameters of the ID range based on the -- information contained in the Active Directory. -- -- If that was not successful, we go for our usual defaults (random base, -- range size 200 000, ipa-ad-trust range type). -- -- Any of these can be overriden by passing appropriate CLI options -- to the trust-add command. -- """ -- -- range_size = None -- range_type = None -- base_id = None -- -- # First, get information about ID space from AD -- # However, we skip this step if other than ipa-ad-trust-posix -- # range type is enforced -- -- if options.get('range_type', None) in (None, u'ipa-ad-trust-posix'): -- -- # Get the base dn -- domain = keys[-1] -- basedn = realm_to_suffix(domain) -- -- # Search for information contained in -- # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System -- info_filter = '(objectClass=msSFU30DomainInfo)' -- info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\ -- + basedn -- -- # Get the domain validator -- domain_validator = ipaserver.dcerpc.DomainValidator(self.api) -- if not domain_validator.is_configured(): -- raise errors.NotFound( -- reason=_('Cannot search in trusted domains without own ' -- 'domain configured. Make sure you have run ' -- 'ipa-adtrust-install on the IPA server first')) -- -- # KDC might not get refreshed data at the first time, -- # retry several times -- for retry in range(10): -- info_list = domain_validator.search_in_dc(domain, -- info_filter, -- None, -- SCOPE_SUBTREE, -- basedn=info_dn, -- quiet=True) -- -- if info_list: -- info = info_list[0] -- break -- else: -- sleep(2) -- -- required_msSFU_attrs = ['msSFU30MaxUidNumber', 'msSFU30OrderNumber'] -- -- if not info_list: -- # We were unable to gain UNIX specific info from the AD -- self.log.debug("Unable to gain POSIX info from the AD") -- else: -- if all(attr in info for attr in required_msSFU_attrs): -- self.log.debug("Able to gain POSIX info from the AD") -- range_type = u'ipa-ad-trust-posix' -- -- max_uid = info.get('msSFU30MaxUidNumber') -- max_gid = info.get('msSFU30MaxGidNumber', None) -- max_id = int(max(max_uid, max_gid)[0]) -- -- base_id = int(info.get('msSFU30OrderNumber')[0]) -- range_size = (1 + (max_id - base_id) / DEFAULT_RANGE_SIZE)\ -- * DEFAULT_RANGE_SIZE -- -- # Second, options given via the CLI options take precedence to discovery -- if options.get('range_type', None): -- range_type = options.get('range_type', None) -- elif not range_type: -- range_type = u'ipa-ad-trust' -- -- if options.get('range_size', None): -- range_size = options.get('range_size', None) -- elif not range_size: -- range_size = DEFAULT_RANGE_SIZE -- -- if options.get('base_id', None): -- base_id = options.get('base_id', None) -- elif not base_id: -- # Generate random base_id if not discovered nor given via CLI -- base_id = DEFAULT_RANGE_SIZE + ( -- pysss_murmur.murmurhash3( -- dom_sid, -- len(dom_sid), 0xdeadbeefL -- ) % 10000 -- ) * DEFAULT_RANGE_SIZE -- -- # Finally, add new ID range -- api.Command['idrange_add'](range_name, -- ipabaseid=base_id, -- ipaidrangesize=range_size, -- ipabaserid=0, -- iparangetype=range_type, -- ipanttrusteddomainsid=dom_sid) -- -- # Return the values that were generated inside this function -- return range_type, range_size, base_id -- - def execute_ad(self, full_join, *keys, **options): - # Join domain using full credentials and with random trustdom - # secret (will be generated by the join method) - - # First see if the trust is already in place - # Force retrieval of the trust object by not passing trust_type -- dn = self.obj.get_dn(keys[-1]) -+ try: -+ dn = self.obj.get_dn(keys[-1]) -+ except errors.NotFound: -+ dn = None -+ - if dn: - summary = _('Re-established trust to domain "%(value)s"') - else: -@@ -794,6 +795,7 @@ class trust_show(LDAPRetrieve): - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - -+ assert isinstance(dn, DN) - # Translate ipanttrusttype to trusttype - # and ipanttrustdirection to trustdirection - # if --raw not used -@@ -1246,6 +1248,11 @@ def fetch_domains_from_trust(self, trustinstance, trust_entry, **options): - if not domains: - return result - -+ # trust range must exist by the time fetch_domains_from_trust is called -+ range_name = trust_name.upper() + '_id_range' -+ old_range = api.Command.idrange_show(range_name, raw=True)['result'] -+ idrange_type = old_range['iparangetype'] -+ - for dom in domains: - dom['trust_type'] = u'ad' - try: -@@ -1255,8 +1262,15 @@ def fetch_domains_from_trust(self, trustinstance, trust_entry, **options): - dom['all'] = options['all'] - if 'raw' in options: - dom['raw'] = options['raw'] -+ - res = self.api.Command.trustdomain_add(trust_name, name, **dom) - result.append(res['result']) -+ -+ if idrange_type != u'ipa-ad-trust-posix': -+ range_name = name.upper() + '_id_range' -+ dom['range_type'] = u'ipa-ad-trust' -+ add_range(self, range_name, dom['ipanttrusteddomainsid'], -+ trust_name, name, **dom) - except errors.DuplicateEntry: - # Ignore updating duplicate entries - pass --- -1.8.4.2 - diff --git a/SOURCES/0024-ipaplatform-Use-the-dirsrv-service-not-target.patch b/SOURCES/0024-ipaplatform-Use-the-dirsrv-service-not-target.patch new file mode 100644 index 0000000..fc46b34 --- /dev/null +++ b/SOURCES/0024-ipaplatform-Use-the-dirsrv-service-not-target.patch @@ -0,0 +1,37 @@ +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/0024-trustdomain-find-report-status-of-the-sub-domain.patch b/SOURCES/0024-trustdomain-find-report-status-of-the-sub-domain.patch deleted file mode 100644 index 7c94776..0000000 --- a/SOURCES/0024-trustdomain-find-report-status-of-the-sub-domain.patch +++ /dev/null @@ -1,57 +0,0 @@ -From c805cd76acc8fbc9c2cb689deaf6e5eae78700c5 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 15 Jan 2014 15:42:10 +0200 -Subject: [PATCH 24/25] trustdomain-find: report status of the (sub)domain - -Show status of each enumerated domain - -trustdomain-find shows list of domains associated with the trust. -Each domain except the trust forest root can be enabled or disabled -with the help of trustdomain-enable and trustdomain-disable commands. - -https://fedorahosted.org/freeipa/ticket/4096 ---- - ipalib/plugins/trust.py | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index a16c23083662fd674c45ba54b9dfb9f4837160df..3d412c9c9f518347769e88ddc9089d6d92ccc4be 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -21,7 +21,7 @@ - from ipalib.plugins.baseldap import * - from ipalib.plugins.dns import dns_container_exists - from ipapython.ipautil import realm_to_suffix --from ipalib import api, Str, StrEnum, Password, _, ngettext -+from ipalib import api, Str, StrEnum, Password, Bool, _, ngettext - from ipalib import Command - from ipalib import errors - from ldap import SCOPE_SUBTREE -@@ -1183,8 +1183,24 @@ def get_dn(self, *keys, **kwargs): - class trustdomain_find(LDAPSearch): - __doc__ = _('Search domains of the trust') - -+ has_output_params = LDAPSearch.has_output_params + ( -+ Flag('domain_enabled', label= _('Domain enabled')), -+ ) - def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): - return (filters, base_dn, ldap.SCOPE_SUBTREE) -+ -+ def post_callback(self, ldap, entries, truncated, *args, **options): -+ trust_dn = self.obj.get_dn(args[0], trust_type=u'ad') -+ trust_entry = ldap.get_entry(trust_dn) -+ for entry in entries: -+ sid = entry['ipanttrusteddomainsid'][0] -+ if sid in trust_entry['ipantsidblacklistincoming']: -+ entry['domain_enabled'] = [False] -+ else: -+ entry['domain_enabled'] = [True] -+ return truncated -+ -+ - api.register(trustdomain_find) - - class trustdomain_mod(LDAPUpdate): --- -1.8.4.2 - diff --git a/SOURCES/0025-CLDAP-do-not-prepend.patch b/SOURCES/0025-CLDAP-do-not-prepend.patch deleted file mode 100644 index fc97f15..0000000 --- a/SOURCES/0025-CLDAP-do-not-prepend.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 198f16c26e36bd8b4b7d55a74bb679a6daa85084 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 13 Jan 2014 10:43:33 +0100 -Subject: [PATCH 25/25] CLDAP: do not prepend \\ - -For NETLOGON_NT_VERSION_5EX requests the prepended \\ is not expected in -the PDC NetBIOS name. In general AD seems to be smart enough to handle -the two \ signs. But if the NetBIOS name reaches the maximum of 15 -character AD does not accept the responses anymore. - -Fixes https://fedorahosted.org/freeipa/ticket/4028 ---- - daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -index 9ba05829418a0d1de46f2c7776cc15c54a9eab1c..c03172d474589ddee84f1cfa5395c23fdba83bcb 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -@@ -163,7 +163,7 @@ static int ipa_cldap_encode_netlogon(char *fq_hostname, char *domain, - nlr->domain_name = name; - - /* copy the first 15 characters of the fully qualified hostname*/ -- pdc_name = talloc_asprintf(nlr, "\\\\%.*s", NETBIOS_NAME_MAX, fq_hostname); -+ pdc_name = talloc_asprintf(nlr, "%.*s", NETBIOS_NAME_MAX, fq_hostname); - - for (p = pdc_name; *p; p++) { - /* Create the NetBIOS name from the first segment of the hostname */ --- -1.8.4.2 - diff --git a/SOURCES/0025-Fix-DNS-policy-upgrade-raises-asertion-error.patch b/SOURCES/0025-Fix-DNS-policy-upgrade-raises-asertion-error.patch new file mode 100644 index 0000000..a56a044 --- /dev/null +++ b/SOURCES/0025-Fix-DNS-policy-upgrade-raises-asertion-error.patch @@ -0,0 +1,29 @@ +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/0026-Fix-upgrade-referint-plugin.patch b/SOURCES/0026-Fix-upgrade-referint-plugin.patch new file mode 100644 index 0000000..d72fba0 --- /dev/null +++ b/SOURCES/0026-Fix-upgrade-referint-plugin.patch @@ -0,0 +1,153 @@ +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-ipaserver-install-installutils-clean-up-properly-aft.patch b/SOURCES/0026-ipaserver-install-installutils-clean-up-properly-aft.patch deleted file mode 100644 index d80e27b..0000000 --- a/SOURCES/0026-ipaserver-install-installutils-clean-up-properly-aft.patch +++ /dev/null @@ -1,56 +0,0 @@ -From fcd4ec48c2515aff7c10f10653628631d832146b Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 15 Jan 2014 17:26:10 +0100 -Subject: [PATCH 26/27] ipaserver/install/installutils: clean up properly after - yield - -When a context to which we yield generates exception, the code in -private_ccache() and stopped_service() didn't get called for cleanup. ---- - ipaserver/install/installutils.py | 25 ++++++++++++++----------- - 1 file changed, 14 insertions(+), 11 deletions(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index c26f072f2f44149746d55b1160d09ebce8394fd5..3770432cae79f653fd57f726de43787dec8dd7d1 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -784,15 +784,16 @@ def private_ccache(path=None): - - os.environ['KRB5CCNAME'] = path - -- yield -+ try: -+ yield -+ finally: -+ if original_value is not None: -+ os.environ['KRB5CCNAME'] = original_value -+ else: -+ os.environ.pop('KRB5CCNAME') - -- if original_value is not None: -- os.environ['KRB5CCNAME'] = original_value -- else: -- os.environ.pop('KRB5CCNAME') -- -- if os.path.exists(path): -- os.remove(path) -+ if os.path.exists(path): -+ os.remove(path) - - - @contextmanager -@@ -825,6 +826,8 @@ def stopped_service(service, instance_name=""): - # Stop the service, do the required stuff and start it again - root_logger.debug('Stopping %s%s.', service, log_instance_name) - ipaservices.knownservices[service].stop(instance_name) -- yield -- root_logger.debug('Starting %s%s.', service, log_instance_name) -- ipaservices.knownservices[service].start(instance_name) -+ try: -+ yield -+ finally: -+ root_logger.debug('Starting %s%s.', service, log_instance_name) -+ ipaservices.knownservices[service].start(instance_name) --- -1.8.4.2 - diff --git a/SOURCES/0027-Do-not-start-the-service-in-stopped_service-if-it-wa.patch b/SOURCES/0027-Do-not-start-the-service-in-stopped_service-if-it-wa.patch deleted file mode 100644 index 28749e4..0000000 --- a/SOURCES/0027-Do-not-start-the-service-in-stopped_service-if-it-wa.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a923cedc1aedafe7f58d480a633257bd19809d72 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 15 Oct 2013 17:49:07 +0000 -Subject: [PATCH 27/27] Do not start the service in stopped_service if it was - not running before. - -This fixes a possible NSS database corruption in renew_ca_cert. ---- - ipaserver/install/installutils.py | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 3770432cae79f653fd57f726de43787dec8dd7d1..32671adc895b0cb2632729e8bdb44b5df02c1314 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -819,9 +819,6 @@ def stopped_service(service, instance_name=""): - root_logger.debug('Service %s%s is not running, continue.', service, - log_instance_name) - yield -- root_logger.debug('Starting %s%s.', service, log_instance_name) -- ipaservices.knownservices[service].start(instance_name) -- return - else: - # Stop the service, do the required stuff and start it again - root_logger.debug('Stopping %s%s.', service, log_instance_name) --- -1.8.4.2 - diff --git a/SOURCES/0027-Upgrade-fix-trusts-objectclass-violationi.patch b/SOURCES/0027-Upgrade-fix-trusts-objectclass-violationi.patch new file mode 100644 index 0000000..e107203 --- /dev/null +++ b/SOURCES/0027-Upgrade-fix-trusts-objectclass-violationi.patch @@ -0,0 +1,63 @@ +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/0028-Harmonize-policy-discovery-to-kdb-driver.patch b/SOURCES/0028-Harmonize-policy-discovery-to-kdb-driver.patch deleted file mode 100644 index 6e2a1f2..0000000 --- a/SOURCES/0028-Harmonize-policy-discovery-to-kdb-driver.patch +++ /dev/null @@ -1,180 +0,0 @@ -From 8ee0ea62d669f59246c8727d89a860bb6d6082f8 Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Tue, 14 Jan 2014 10:09:37 -0500 -Subject: [PATCH 28/34] Harmonize policy discovery to kdb driver - -The KDB driver does not walk the tree back like the original password plugin. -Also we do not store the default policy in the base DN as we used to do in the -past anymore. -So doing a full subtree search and walking back the tree is just a waste of -time. -Instead hardcode the default policy like we do in the kdb driver. - -Fixes: https://fedorahosted.org/freeipa/ticket/4085 ---- - daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c | 106 ++++------------------- - 1 file changed, 17 insertions(+), 89 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c -index 2538a4094bd9a166e61b0911e5ea93426092d88a..ef20c4c61bd764bffc426208ff8b99f5d0b782ec 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c -@@ -436,75 +436,44 @@ static void pwd_values_free(Slapi_ValueSet** results, - slapi_vattr_values_free(results, actual_type_name, buffer_flags); - } - --static int ipapwd_rdn_count(const char *dn) --{ -- int rdnc = 0; -- LDAPDN ldn; -- int ret; -- -- ret = ldap_str2dn(dn, &ldn, LDAP_DN_FORMAT_LDAPV3); -- if (ret != LDAP_SUCCESS) { -- LOG_TRACE("ldap_str2dn(dn) failed ?!"); -- return -1; -- } -- -- for (rdnc = 0; ldn != NULL && ldn[rdnc]; rdnc++) /* count */ ; -- ldap_dnfree(ldn); -- -- return rdnc; --} -- - int ipapwd_getPolicy(const char *dn, - Slapi_Entry *target, - struct ipapwd_policy *policy) - { - const char *krbPwdPolicyReference; -- const char *pdn; -- const Slapi_DN *psdn; -- Slapi_Backend *be; -+ char *pdn = NULL; - Slapi_PBlock *pb = NULL; - char *attrs[] = { "krbMaxPwdLife", "krbMinPwdLife", - "krbPwdMinDiffChars", "krbPwdMinLength", - "krbPwdHistoryLength", NULL}; - Slapi_Entry **es = NULL; - Slapi_Entry *pe = NULL; -- int ret, res, dist, rdnc, scope, i; -- Slapi_DN *sdn = NULL; -+ int ret, res, scope, i; - int buffer_flags=0; - Slapi_ValueSet* results = NULL; -- char* actual_type_name = NULL; -+ char *actual_type_name = NULL; - int tmpint; - - LOG_TRACE("Searching policy for [%s]\n", dn); - -- sdn = slapi_sdn_new_dn_byref(dn); -- if (sdn == NULL) { -- LOG_OOM(); -- ret = -1; -- goto done; -- } -- - pwd_get_values(target, "krbPwdPolicyReference", - &results, &actual_type_name, &buffer_flags); - if (results) { - Slapi_Value *sv; - slapi_valueset_first_value(results, &sv); - krbPwdPolicyReference = slapi_value_get_string(sv); -- pdn = krbPwdPolicyReference; -- scope = LDAP_SCOPE_BASE; -- LOG_TRACE("using policy reference: %s\n", pdn); -+ pdn = slapi_ch_strdup(krbPwdPolicyReference); - } else { -- /* Find ancestor base DN */ -- be = slapi_be_select(sdn); -- psdn = slapi_be_getsuffix(be, 0); -- if (psdn == NULL) { -- LOG_FATAL("Invalid DN [%s]\n", dn); -- ret = -1; -- goto done; -- } -- pdn = slapi_sdn_get_dn(psdn); -- scope = LDAP_SCOPE_SUBTREE; -+ /* Fallback to hardcoded value */ -+ pdn = slapi_ch_smprintf("cn=global_policy,%s", ipa_realm_dn); - } -+ if (pdn == NULL) { -+ LOG_OOM(); -+ ret = -1; -+ goto done; -+ } -+ LOG_TRACE("Using policy at [%s]\n", pdn); -+ scope = LDAP_SCOPE_BASE; - - pb = slapi_pblock_new(); - slapi_search_internal_set_pb(pb, -@@ -539,54 +508,13 @@ int ipapwd_getPolicy(const char *dn, - /* if there is only one, return that */ - if (i == 1) { - pe = es[0]; -- goto fill; -- } -- -- /* count number of RDNs in DN */ -- rdnc = ipapwd_rdn_count(dn); -- if (rdnc == -1) { -- LOG_TRACE("ipapwd_rdn_count(dn) failed"); -- ret = -1; -- goto done; -- } -- -- pe = NULL; -- dist = -1; -- -- /* find closest entry */ -- for (i = 0; es[i]; i++) { -- const Slapi_DN *esdn; -- -- esdn = slapi_entry_get_sdn_const(es[i]); -- if (esdn == NULL) continue; -- if (0 == slapi_sdn_compare(esdn, sdn)) { -- pe = es[i]; -- dist = 0; -- break; -- } -- if (slapi_sdn_issuffix(sdn, esdn)) { -- const char *dn1; -- int c1; -- -- dn1 = slapi_sdn_get_dn(esdn); -- if (!dn1) continue; -- c1 = ipapwd_rdn_count(dn1); -- if (c1 == -1) continue; -- if ((dist == -1) || -- ((rdnc - c1) < dist)) { -- dist = rdnc - c1; -- pe = es[i]; -- } -- } -- if (dist == 0) break; /* found closest */ -- } -- -- if (pe == NULL) { -+ } else { -+ LOG_TRACE("Multiple entries from a base search ?!"); - ret = -1; - goto done; - } - --fill: -+ /* read data out of policy object */ - policy->min_pwd_life = slapi_entry_attr_get_int(pe, "krbMinPwdLife"); - - tmpint = slapi_entry_attr_get_int(pe, "krbMaxPwdLife"); -@@ -615,7 +543,7 @@ done: - slapi_free_search_results_internal(pb); - slapi_pblock_destroy(pb); - } -- if (sdn) slapi_sdn_free(&sdn); -+ slapi_ch_free_string(&pdn); - return ret; - } - --- -1.8.4.2 - diff --git a/SOURCES/0028-Produce-better-error-in-group-add-command.patch b/SOURCES/0028-Produce-better-error-in-group-add-command.patch new file mode 100644 index 0000000..9cbe930 --- /dev/null +++ b/SOURCES/0028-Produce-better-error-in-group-add-command.patch @@ -0,0 +1,28 @@ +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/0029-Search-using-proper-scope-when-connecting-CA-instanc.patch b/SOURCES/0029-Search-using-proper-scope-when-connecting-CA-instanc.patch new file mode 100644 index 0000000..0a02cd2 --- /dev/null +++ b/SOURCES/0029-Search-using-proper-scope-when-connecting-CA-instanc.patch @@ -0,0 +1,32 @@ +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-Stop-adding-a-default-password-policy-reference.patch b/SOURCES/0029-Stop-adding-a-default-password-policy-reference.patch deleted file mode 100644 index 4e325d2..0000000 --- a/SOURCES/0029-Stop-adding-a-default-password-policy-reference.patch +++ /dev/null @@ -1,409 +0,0 @@ -From 46ad7d5e76929d5744355374c1e56c5004bf5281 Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Thu, 16 Jan 2014 09:06:18 +0100 -Subject: [PATCH 29/34] Stop adding a default password policy reference - -Both the password plugin and the kdb driver code automatically fall -back to the default password policy. -so stop adding an explicit reference to user objects and instead rely on the -fallback. -This way users created via the framework and users created via winsync plugin -behave the same way wrt password policies and no surprises will happen. - -Also in case we need to change the default password policy DN this will allow -just code changes instead of having to change each user entry created, and -distinguish between the default policy and explicit admin changes. - -Related: https://fedorahosted.org/freeipa/ticket/4085 - -Patch backported/updated by Martin Kosek to accomodate different ipatests -structure in ipa-3-3 branch. ---- - ipalib/plugins/user.py | 3 -- - ipatests/test_xmlrpc/test_attr.py | 2 -- - ipatests/test_xmlrpc/test_automember_plugin.py | 4 --- - ipatests/test_xmlrpc/test_group_plugin.py | 4 --- - ipatests/test_xmlrpc/test_krbtpolicy.py | 2 -- - ipatests/test_xmlrpc/test_nesting.py | 8 ----- - ipatests/test_xmlrpc/test_netgroup_plugin.py | 4 --- - ipatests/test_xmlrpc/test_range_plugin.py | 2 -- - ipatests/test_xmlrpc/test_replace.py | 2 -- - ipatests/test_xmlrpc/test_selinuxusermap_plugin.py | 5 --- - ipatests/test_xmlrpc/test_user_plugin.py | 40 ---------------------- - 11 files changed, 76 deletions(-) - -diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py -index 471981f48204209753eda2fb994d4c653dca0fa2..9b212005ef522920a86deacc8f9b3e658a088ec1 100644 ---- a/ipalib/plugins/user.py -+++ b/ipalib/plugins/user.py -@@ -498,9 +498,6 @@ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - homes_root = config.get('ipahomesrootdir', ['/home'])[0] - # build user's home directory based on his uid - entry_attrs['homedirectory'] = posixpath.join(homes_root, keys[-1]) -- entry_attrs.setdefault('krbpwdpolicyreference', -- DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'), -- api.env.basedn)) - entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm)) - - if entry_attrs.get('gidnumber') is None: -diff --git a/ipatests/test_xmlrpc/test_attr.py b/ipatests/test_xmlrpc/test_attr.py -index 118eabdeb5c8f6e86c0a9fc7dcdf9fc73a0a9ad2..a9e2956947109efcdcd132dff3807b7400d95a09 100644 ---- a/ipatests/test_xmlrpc/test_attr.py -+++ b/ipatests/test_xmlrpc/test_attr.py -@@ -71,8 +71,6 @@ class test_attr(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_automember_plugin.py b/ipatests/test_xmlrpc/test_automember_plugin.py -index 2c38b6463bfc684dbe23904f54b7107bb4ce3ff2..32fc59bac70d0f2e16d5d988835772f894bd78a9 100644 ---- a/ipatests/test_xmlrpc/test_automember_plugin.py -+++ b/ipatests/test_xmlrpc/test_automember_plugin.py -@@ -812,8 +812,6 @@ class test_automember(Declarative): - cn=[u'Michael Scott'], - initials=[u'MS'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'), -- api.env.basedn)], - mepmanagedentry=[DN(('cn', manager1), ('cn', 'groups'), ('cn', 'accounts'), - api.env.basedn)], - memberof_group=[u'defaultgroup1', u'ipausers'], -@@ -851,8 +849,6 @@ class test_automember(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'), -- api.env.basedn)], - mepmanagedentry=[DN(('cn', user1), ('cn', 'groups'), ('cn', 'accounts'), - api.env.basedn)], - memberof_group=[u'group1', u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_group_plugin.py b/ipatests/test_xmlrpc/test_group_plugin.py -index be31af453bbd28d420c5e9f301bef6eb56388f61..9cc337db2a5f80abc960f5bc8a226372bf16b980 100644 ---- a/ipatests/test_xmlrpc/test_group_plugin.py -+++ b/ipatests/test_xmlrpc/test_group_plugin.py -@@ -812,8 +812,6 @@ class test_group(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - dn=DN(('uid',user1),('cn','users'),('cn','accounts'), -@@ -932,8 +930,6 @@ class test_group(Declarative): - ipauniqueid=[fuzzy_uuid], - dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'), - api.env.basedn), -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - memberof_group=[u'ipausers'], - has_keytab=False, - has_password=False, -diff --git a/ipatests/test_xmlrpc/test_krbtpolicy.py b/ipatests/test_xmlrpc/test_krbtpolicy.py -index 2fac11f1854037aa197f2df42c72a9d7ae947ccd..fb66e8a6ca72bee7dcfc595f3b89badc2608ca09 100644 ---- a/ipatests/test_xmlrpc/test_krbtpolicy.py -+++ b/ipatests/test_xmlrpc/test_krbtpolicy.py -@@ -110,8 +110,6 @@ class test_krbtpolicy(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_nesting.py b/ipatests/test_xmlrpc/test_nesting.py -index 850010b8797734406aa81a911a64bb1d051b7196..5be05688973f9ee39425f1bfc9cdedaa1a193c25 100644 ---- a/ipatests/test_xmlrpc/test_nesting.py -+++ b/ipatests/test_xmlrpc/test_nesting.py -@@ -176,8 +176,6 @@ class test_nesting(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -@@ -214,8 +212,6 @@ class test_nesting(Declarative): - cn=[u'Test User2'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -@@ -252,8 +248,6 @@ class test_nesting(Declarative): - cn=[u'Test User3'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user3),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -@@ -290,8 +284,6 @@ class test_nesting(Declarative): - cn=[u'Test User4'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user4),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_netgroup_plugin.py b/ipatests/test_xmlrpc/test_netgroup_plugin.py -index 09241a7d691aeb7d967e549d14ff5d87a80b6a9b..15453bd3cfd45dce9be43cc5003b67a87a7915ac 100644 ---- a/ipatests/test_xmlrpc/test_netgroup_plugin.py -+++ b/ipatests/test_xmlrpc/test_netgroup_plugin.py -@@ -288,8 +288,6 @@ class test_netgroup(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -@@ -325,8 +323,6 @@ class test_netgroup(Declarative): - cn=[u'Test User2'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py -index df80e2fb72725c52d13be7a661364cbeafa3f84f..8c7b5f26e70283db62f18b152378d1b7d31bcc96 100644 ---- a/ipatests/test_xmlrpc/test_range_plugin.py -+++ b/ipatests/test_xmlrpc/test_range_plugin.py -@@ -248,8 +248,6 @@ def tearDownClass(cls): - initials=[u'TU'], - mail=[u'%s@%s' % (user1, api.env.domain)], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_replace.py b/ipatests/test_xmlrpc/test_replace.py -index 1b946b76cb9ecccc3452b3714d1647b0a09ec831..691918f5857827365323ed1d20835a15dd899a4f 100644 ---- a/ipatests/test_xmlrpc/test_replace.py -+++ b/ipatests/test_xmlrpc/test_replace.py -@@ -66,8 +66,6 @@ class test_replace(Declarative): - initials=[u'TU'], - mail=[u'test1@example.com', u'test2@example.com'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),('cn','kerberos'), -- api.env.basedn)], - mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_selinuxusermap_plugin.py b/ipatests/test_xmlrpc/test_selinuxusermap_plugin.py -index d1fedf1f0ff603a702089651db7f226ea58a98cd..9438bd01227c3ed0317976a38de8f67ec4ae425f 100644 ---- a/ipatests/test_xmlrpc/test_selinuxusermap_plugin.py -+++ b/ipatests/test_xmlrpc/test_selinuxusermap_plugin.py -@@ -216,11 +216,6 @@ class test_selinuxusermap(Declarative): - cn=[u'Test User1'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn', 'global_policy'), -- ('cn', api.env.realm), -- ('cn', 'kerberos'), -- api.env.basedn) -- ], - mepmanagedentry=[DN(('cn', user1), ('cn', 'groups'), - ('cn', 'accounts'), api.env.basedn)], - memberof_group=[u'ipausers'], -diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py -index 98e1965a4fbd3c2e77363495d0391be580bd0805..6a5ba50034fd2c9b63db63eeaa0061657574342d 100644 ---- a/ipatests/test_xmlrpc/test_user_plugin.py -+++ b/ipatests/test_xmlrpc/test_user_plugin.py -@@ -125,8 +125,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -199,8 +197,6 @@ class test_user(Declarative): - 'gidnumber': [fuzzy_digits], - 'ipauniqueid': [fuzzy_uuid], - 'mepmanagedentry': [get_group_dn(user1)], -- 'krbpwdpolicyreference': [DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - 'nsaccountlock': False, - 'has_keytab': False, - 'has_password': False, -@@ -594,8 +590,6 @@ class test_user(Declarative): - ipasshpubkey=[sshpubkey], - sshpubkeyfp=[sshpubkeyfp], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -650,8 +644,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -687,8 +679,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user2, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user2)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -908,8 +898,6 @@ class test_user(Declarative): - postalcode=[u'01234-5678'], - telephonenumber=[u'410-555-1212'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -954,8 +942,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=True, -@@ -1003,8 +989,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user2, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user2)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -1075,8 +1059,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -1148,8 +1130,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -1210,8 +1190,6 @@ class test_user(Declarative): - initials=[u'TU'], - mail=[u'%s@%s' % (user1, api.env.domain)], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -1273,8 +1251,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user2, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - memberof_group=[u'ipausers'], - has_keytab=False, - has_password=False, -@@ -1327,8 +1303,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - memberof_group=[group1], - has_keytab=False, - has_password=False, -@@ -1364,8 +1338,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user2, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - memberof_group=[group1], - has_keytab=False, - has_password=False, -@@ -1446,8 +1418,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user2, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - memberof_group=[group1], - nsaccountlock=False, - has_keytab=False, -@@ -1493,8 +1463,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user2, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - memberof_group=[group1], - nsaccountlock=False, - has_keytab=False, -@@ -1553,8 +1521,6 @@ class test_user(Declarative): - initials=[u'SA'], - mail=[u'%s@%s' % (admin2, api.env.domain)], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(admin2)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -1744,8 +1710,6 @@ class test_user(Declarative): - cn=[u'Test User2'], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'), -- api.env.basedn)], - mepmanagedentry=[DN(('cn', user2), ('cn', 'groups'), ('cn', 'accounts'), - api.env.basedn)], - memberof_group=[u'ipausers'], -@@ -1780,8 +1744,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, -@@ -1828,8 +1790,6 @@ class test_user(Declarative): - mail=[u'%s@%s' % (user1, api.env.domain)], - initials=[u'TU'], - ipauniqueid=[fuzzy_uuid], -- krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm), -- ('cn','kerberos'),api.env.basedn)], - mepmanagedentry=[get_group_dn(user1)], - memberof_group=[u'ipausers'], - has_keytab=False, --- -1.8.4.2 - diff --git a/SOURCES/0030-Fix-zonemgr-must-be-unicode-value.patch b/SOURCES/0030-Fix-zonemgr-must-be-unicode-value.patch new file mode 100644 index 0000000..adbf8bb --- /dev/null +++ b/SOURCES/0030-Fix-zonemgr-must-be-unicode-value.patch @@ -0,0 +1,30 @@ +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-Increase-service-startup-timeout-default.patch b/SOURCES/0030-Increase-service-startup-timeout-default.patch deleted file mode 100644 index e4790a7..0000000 --- a/SOURCES/0030-Increase-service-startup-timeout-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b3d3abfa3adcfc8b1f5ea09e52a0bd8a519571e6 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 15 Jan 2014 09:41:15 +0100 -Subject: [PATCH 30/34] Increase service startup timeout default. - -https://fedorahosted.org/freeipa/ticket/4078 ---- - ipalib/constants.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipalib/constants.py b/ipalib/constants.py -index 79885a33a3008bd83908fc34a7340e78ab25e31f..6d4088be9a958eb5cb3b2725f8696fb4a7926e57 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -116,7 +116,7 @@ - ('rpc_json_uri', 'http://localhost:8888/ipa/json'), - ('ldap_uri', 'ldap://localhost:389'), - # Time to wait for a service to start, in seconds -- ('startup_timeout', 120), -+ ('startup_timeout', 300), - - # Web Application mount points - ('mount_ipa', '/ipa/'), --- -1.8.4.2 - 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 new file mode 100644 index 0000000..38f504e --- /dev/null +++ b/SOURCES/0031-Fix-warning-message-should-not-contain-CLI-commands.patch @@ -0,0 +1,73 @@ +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-cli.print_attribute-Convert-values-to-strings.patch b/SOURCES/0031-cli.print_attribute-Convert-values-to-strings.patch deleted file mode 100644 index 343a418..0000000 --- a/SOURCES/0031-cli.print_attribute-Convert-values-to-strings.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 32d3d38edfd47f3cc5425d3c2e7d42a38ea4a95b Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Tue, 26 Nov 2013 23:31:05 +0100 -Subject: [PATCH 31/34] cli.print_attribute: Convert values to strings - -When output_for_cli was called directly, rather than for values -received through XML or JSON API, joining multiple values failed -on non-strings such as DN objects. - -Convert output to strings before printing it out. ---- - ipalib/cli.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipalib/cli.py b/ipalib/cli.py -index 5f02e929fe0df7051f4bb925a960678d780d4883..41e1b4752a2a549ea687632e60eb8003d0cad95f 100644 ---- a/ipalib/cli.py -+++ b/ipalib/cli.py -@@ -293,7 +293,7 @@ def print_attribute(self, attr, value, format='%s: %s', indent=1, one_value_per_ - return - else: - if len(value) > 0: -- text = ', '.join(value) -+ text = ', '.join(str(v) for v in value) - else: - return - line_len = self.get_tty_width() --- -1.8.4.2 - 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 new file mode 100644 index 0000000..c7805e0 --- /dev/null +++ b/SOURCES/0032-Fix-wrong-expiration-date-on-renewed-IPA-CA-certific.patch @@ -0,0 +1,54 @@ +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-group-show-resolve-external-members-of-the-groups.patch b/SOURCES/0032-group-show-resolve-external-members-of-the-groups.patch deleted file mode 100644 index 609d8ba..0000000 --- a/SOURCES/0032-group-show-resolve-external-members-of-the-groups.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 2d1a85606d61128611f49101854bb8efe4abd638 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 16 Jan 2014 20:31:37 +0200 -Subject: [PATCH 32/34] group-show: resolve external members of the groups - -Perform SID to name conversion for existing external members of the -groups if trust is configured. - -https://bugzilla.redhat.com/show_bug.cgi?id=1054391 -https://fedorahosted.org/freeipa/ticket/4123 ---- - ipalib/plugins/group.py | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py -index 02eeb10ca2ca2a5710e88d6e3c11f1d1cdaa4a7b..dac55003e5a4291e8a3b7db58ae9b3c9c76e271e 100644 ---- a/ipalib/plugins/group.py -+++ b/ipalib/plugins/group.py -@@ -387,6 +387,21 @@ def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **option - class group_show(LDAPRetrieve): - __doc__ = _('Display information about a named group.') - has_output_params = LDAPRetrieve.has_output_params + (ipaexternalmember_param,) -+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -+ assert isinstance(dn, DN) -+ if ('ipaexternalmember' in entry_attrs and -+ len(entry_attrs['ipaexternalmember']) > 0 and -+ 'trust_resolve' in self.Command and -+ not options.get('raw', False)): -+ sids = entry_attrs['ipaexternalmember'] -+ result = self.Command.trust_resolve(sids=sids) -+ for entry in result['result']: -+ try: -+ idx = sids.index(entry['sid'][0]) -+ sids[idx] = entry['name'][0] -+ except ValueError: -+ pass -+ return dn - api.register(group_show) - - --- -1.8.4.2 - 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 new file mode 100644 index 0000000..108f221 --- /dev/null +++ b/SOURCES/0033-Do-not-restore-SELinux-settings-that-were-not-backed.patch @@ -0,0 +1,43 @@ +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-SID-resolve-call-from-Web-UI.patch b/SOURCES/0033-Remove-SID-resolve-call-from-Web-UI.patch deleted file mode 100644 index 35fee47..0000000 --- a/SOURCES/0033-Remove-SID-resolve-call-from-Web-UI.patch +++ /dev/null @@ -1,87 +0,0 @@ -From ff15df8bd58bddd4c53644867f8ee340febdc198 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Mon, 20 Jan 2014 09:50:56 +0100 -Subject: [PATCH 33/34] Remove SID resolve call from Web UI - -- it's called in group-show - -https://bugzilla.redhat.com/show_bug.cgi?id=1054391 -https://fedorahosted.org/freeipa/ticket/4123 ---- - install/ui/src/freeipa/association.js | 47 ----------------------------------- - install/ui/src/freeipa/group.js | 1 - - 2 files changed, 48 deletions(-) - -diff --git a/install/ui/src/freeipa/association.js b/install/ui/src/freeipa/association.js -index ad427d66b6b98119b2eb577ae98e4b7c2f1a6932..8d81e495a153c06cdbcfa9917bdf04d70916f997 100644 ---- a/install/ui/src/freeipa/association.js -+++ b/install/ui/src/freeipa/association.js -@@ -1455,53 +1455,6 @@ exp.attribute_facet = IPA.attribute_facet = function(spec, no_init) { - return that; - }; - --IPA.sid_facet = function(spec, no_init) { -- -- spec.name = spec.name || 'sid_facet'; -- -- var that = IPA.attribute_facet(spec, no_init); -- -- that.load_records = function(value) { -- var xlate = {}; -- var sidxlate_command = IPA.command({ -- entity: 'trust', -- method: 'resolve', -- options: { -- sids: '' -- } -- }); -- sidxlate_command.on_success = function(data, text_status, xhr) { -- for (var i=0; i< data.result.result.length; i++) { -- var entry = data.result.result[i]; -- if (entry.sid[0] in xlate) { -- xlate[entry.sid[0]].resolve(entry.name[0]); -- } -- } -- }; -- that.table.empty(); -- -- if (value.length === 0) return; -- -- var sids = []; -- for (var i=0; i< value.length; i++) { -- var sid = value[i][that.attribute]; -- var deferred = new Deferred(); -- value[i][that.attribute] = { -- promise: deferred.promise, -- temp: sid -- }; -- xlate[sid] = deferred; -- sids.push(sid); -- that.add_record(value[i]); -- } -- sidxlate_command.options.sids = sids; -- sidxlate_command.execute(); -- }; -- -- return that; --}; -- -- - IPA.attr_read_only_evaluator = function(spec) { - - spec.name = spec.name || 'attr_read_only_evaluator'; -diff --git a/install/ui/src/freeipa/group.js b/install/ui/src/freeipa/group.js -index 5e8cdf991cdaf4f52e3f49dca431e999a72f2089..bb12d902fcba8228098b667aa6fbd3fa7daee34d 100644 ---- a/install/ui/src/freeipa/group.js -+++ b/install/ui/src/freeipa/group.js -@@ -112,7 +112,6 @@ return { - }, - { - $type: 'attribute', -- $factory: IPA.sid_facet, - name: 'member_external', - attribute: 'ipaexternalmember', - tab_label: 'External', --- -1.8.4.2 - diff --git a/SOURCES/0034-Improve-otptoken-help-messages.patch b/SOURCES/0034-Improve-otptoken-help-messages.patch new file mode 100644 index 0000000..3a6ca29 --- /dev/null +++ b/SOURCES/0034-Improve-otptoken-help-messages.patch @@ -0,0 +1,121 @@ +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/0034-ipa-adtrust-install-configure-host-netbios-name-by-d.patch b/SOURCES/0034-ipa-adtrust-install-configure-host-netbios-name-by-d.patch deleted file mode 100644 index f0ccd4a..0000000 --- a/SOURCES/0034-ipa-adtrust-install-configure-host-netbios-name-by-d.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 7358fdd85215b9ee9becb2e352480abd2789691f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 17 Jan 2014 14:09:34 +0200 -Subject: [PATCH 34/34] ipa-adtrust-install: configure host netbios name by - default - -Ensure we set host netbios name by default in smb.conf - -https://fedorahosted.org/freeipa/ticket/4116 ---- - install/share/smb.conf.template | 1 + - ipaserver/install/adtrustinstance.py | 3 +++ - 2 files changed, 4 insertions(+) - -diff --git a/install/share/smb.conf.template b/install/share/smb.conf.template -index 086b0fcfe5cff2bc3582f2a89962a99c9095b4bb..2908b998cc85fcb84f60847135aaa4b008e121f8 100644 ---- a/install/share/smb.conf.template -+++ b/install/share/smb.conf.template -@@ -1,5 +1,6 @@ - [global] - workgroup = $NETBIOS_NAME -+netbios name = $HOST_NETBIOS_NAME - realm = $REALM - kerberos method = dedicated keytab - dedicated keytab file = FILE:/etc/samba/samba.keytab -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index 4aa8322e3e2cfb6fbc07696097c3e6e21fc7f665..621e3fd46780beb15f3d642cb9e3eb1c5fa721ad 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -124,6 +124,7 @@ def __init__(self, fstore=None): - self.secondary_rid_base = None - - self.fqdn = None -+ self.host_netbios_name = None - self.realm = None - self.domain_name = None - -@@ -151,6 +152,7 @@ def __setup_default_attributes(self): - - # Values obtained from API.env - self.fqdn = self.fqdn or api.env.host -+ self.host_netbios_name = make_netbios_name(self.fqdn) - self.realm = self.realm or api.env.realm - self.domain_name = self.domain_name or api.env.domain - -@@ -769,6 +771,7 @@ def __setup_sub_dict(self): - self.sub_dict = dict(REALM = self.realm, - SUFFIX = self.suffix, - NETBIOS_NAME = self.netbios_name, -+ HOST_NETBIOS_NAME = self.host_netbios_name, - SMB_DN = self.smb_dn, - LDAPI_SOCKET = self.ldapi_socket, - FQDN = self.fqdn) --- -1.8.4.2 - 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 new file mode 100644 index 0000000..a19c17a --- /dev/null +++ b/SOURCES/0035-Ensure-users-exist-when-assigning-tokens-to-them.patch @@ -0,0 +1,34 @@ +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-Remove-missing-VERSION-warning-in-dnsrecord-mod.patch b/SOURCES/0035-Remove-missing-VERSION-warning-in-dnsrecord-mod.patch deleted file mode 100644 index 876fa45..0000000 --- a/SOURCES/0035-Remove-missing-VERSION-warning-in-dnsrecord-mod.patch +++ /dev/null @@ -1,30 +0,0 @@ -From a8cc1ff0dbf3de89b78c8d382779433658286750 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Fri, 17 Jan 2014 09:26:35 +0100 -Subject: [PATCH] Remove missing VERSION warning in dnsrecord-mod - -dnsrecord-mod may call dnsrecord-delentry command when all records -are deleted. However, the version was not passwd to delentry and -it resulted in a warning. - -https://fedorahosted.org/freeipa/ticket/4120 ---- - ipalib/plugins/dns.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py -index 07523dc72466892f0e7d5fdd9261024d0e898548..94ae92ba5d1ae42e31ebb6100c743a2334f29e70 100644 ---- a/ipalib/plugins/dns.py -+++ b/ipalib/plugins/dns.py -@@ -2636,7 +2636,7 @@ def execute(self, *keys, **options): - break - - if del_all: -- return self.obj.methods.delentry(*keys) -+ return self.obj.methods.delentry(*keys, version=options['version']) - return result - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): --- -1.8.4.2 - 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 new file mode 100644 index 0000000..7a89d30 --- /dev/null +++ b/SOURCES/0036-Enable-QR-code-display-by-default-in-otptoken-add.patch @@ -0,0 +1,104 @@ +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-Hide-trust-resolve-command.patch b/SOURCES/0036-Hide-trust-resolve-command.patch deleted file mode 100644 index 3e8c387..0000000 --- a/SOURCES/0036-Hide-trust-resolve-command.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 94888d83efbbd3b3ddf194e35d4d10f03bb47bb2 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Fri, 17 Jan 2014 16:13:17 +0100 -Subject: [PATCH] Hide trust-resolve command - -We do not need to expose a public FreeIPA specific interface to resolve -SIDs to names. The interface is only used internally to resolve SIDs -when external group members are listed. Additionally, the command interface -is not prepared for regular user and can give rather confusing results. - -Hide it from CLI. The API itself is still accessible and compatible with -older clients. - -https://fedorahosted.org/freeipa/ticket/4113 ---- - ipalib/plugins/trust.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 3d412c9c9f518347769e88ddc9089d6d92ccc4be..0b6db27c696cd169c8f4b33128520961c20e3015 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -978,6 +978,7 @@ def idmap_type_string(level): - return unicode(string) - - class trust_resolve(Command): -+ NO_CLI = True - __doc__ = _('Resolve security identifiers of users and groups in trusted domains') - - takes_options = ( --- -1.8.4.2 - 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 new file mode 100644 index 0000000..d70a544 --- /dev/null +++ b/SOURCES/0037-Show-warning-instead-of-error-if-CA-did-not-start.patch @@ -0,0 +1,32 @@ +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-Trust-domains-Web-UI.patch b/SOURCES/0037-Trust-domains-Web-UI.patch deleted file mode 100644 index a7b76fb..0000000 --- a/SOURCES/0037-Trust-domains-Web-UI.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 8dcaa8f17b94fd7056340622e49d8ab505694603 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Wed, 15 Jan 2014 18:01:02 +0100 -Subject: [PATCH] Trust domains Web UI - -Add Web UI counterpart of following CLI commands: - -* trust-fetch-domains Refresh list of the domains associated with the trust -* trustdomain-del Remove infromation about the domain associated with the trust. -* trustdomain-disable Disable use of IPA resources by the domain of the trust -* trustdomain-enable Allow use of IPA resources by the domain of the trust -* trustdomain-find Search domains of the trust - -https://fedorahosted.org/freeipa/ticket/4119 ---- - install/ui/src/freeipa/search.js | 11 +++--- - install/ui/src/freeipa/trust.js | 68 ++++++++++++++++++++++++++++++++++++++ - install/ui/test/data/ipa_init.json | 1 + - ipalib/plugins/internal.py | 1 + - 4 files changed, 77 insertions(+), 4 deletions(-) - -diff --git a/install/ui/src/freeipa/search.js b/install/ui/src/freeipa/search.js -index c2e678a35e7d7d5179c1b766eea88599710593c3..3f7fdf9b1e6716c73e0657dc678abe332f6fc8c0 100644 ---- a/install/ui/src/freeipa/search.js -+++ b/install/ui/src/freeipa/search.js -@@ -470,20 +470,23 @@ IPA.batch_items_action = function(spec) { - that.execute_action = function(facet, on_success, on_error) { - - var entity = facet.managed_entity; -- var pkeys = facet.get_selected_values(); -+ var selected_keys = facet.get_selected_values(); -+ var pkeys = facet.get_pkeys(); -+ if (!pkeys[0]) pkeys = []; // correction for search facet - - that.batch = IPA.batch_command({ - name: entity.name + '_batch_'+ that.method, - on_success: that.get_on_success(facet, on_success) - }); - -- for (var i=0; i -Date: Mon, 20 Jan 2014 16:42:48 +0200 -Subject: [PATCH] ipasam: delete trusted child domains before removing the - trust - -LDAP protocol doesn't allow deleting non-leaf entries. One needs to -remove all leaves first before removing the tree node. - -https://fedorahosted.org/freeipa/ticket/4126 ---- - daemons/ipa-sam/ipa_sam.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 44 insertions(+), 1 deletion(-) - -diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c -index 674085d2a14c67359df16458dbbb098414a24d8b..1ca504db4e442c834ebe44d7e3503abafd6f9602 100644 ---- a/daemons/ipa-sam/ipa_sam.c -+++ b/daemons/ipa-sam/ipa_sam.c -@@ -2437,6 +2437,44 @@ done: - return status; - } - -+static int delete_subtree(struct ldapsam_privates *ldap_state, char* dn) -+{ -+ LDAP *state = priv2ld(ldap_state); -+ int rc; -+ char *filter = NULL; -+ int scope = LDAP_SCOPE_SUBTREE; -+ LDAPMessage *result = NULL; -+ LDAPMessage *entry = NULL; -+ char *entry_dn = NULL; -+ -+ /* use 'dn' for a temporary talloc context */ -+ filter = talloc_asprintf(dn, "(objectClass=*)"); -+ if (filter == NULL) { -+ return LDAP_NO_MEMORY; -+ } -+ -+ rc = smbldap_search(ldap_state->smbldap_state, dn, scope, filter, NULL, 0, &result); -+ TALLOC_FREE(filter); -+ -+ if (result != NULL) { -+ smbldap_talloc_autofree_ldapmsg(dn, result); -+ } -+ -+ for (entry = ldap_first_entry(state, result); -+ entry != NULL; -+ entry = ldap_next_entry(state, entry)) { -+ entry_dn = get_dn(dn, state, entry); -+ /* remove child entries */ -+ if ((entry_dn != NULL) && (strcmp(entry_dn, dn) != 0)) { -+ rc = smbldap_delete(ldap_state->smbldap_state, entry_dn); -+ } -+ } -+ rc = smbldap_delete(ldap_state->smbldap_state, dn); -+ -+ /* caller will destroy dn */ -+ return rc; -+} -+ - static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods, - const char *domain) - { -@@ -2444,7 +2482,7 @@ static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods, - struct ldapsam_privates *ldap_state = - (struct ldapsam_privates *)methods->private_data; - LDAPMessage *entry = NULL; -- const char *dn; -+ char *dn; - const char *domain_name; - TALLOC_CTX *tmp_ctx; - NTSTATUS status; -@@ -2490,6 +2528,11 @@ static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods, - } - - ret = smbldap_delete(ldap_state->smbldap_state, dn); -+ if (ret == LDAP_NOT_ALLOWED_ON_NONLEAF) { -+ /* delete_subtree will use 'dn' as temporary context too */ -+ ret = delete_subtree(ldap_state, dn); -+ } -+ - if (ret != LDAP_SUCCESS) { - status = NT_STATUS_UNSUCCESSFUL; - goto done; --- -1.8.4.2 - diff --git a/SOURCES/0038-webui-fix-potential-XSS-vulnerabilities.patch b/SOURCES/0038-webui-fix-potential-XSS-vulnerabilities.patch new file mode 100644 index 0000000..f6c78d2 --- /dev/null +++ b/SOURCES/0038-webui-fix-potential-XSS-vulnerabilities.patch @@ -0,0 +1,131 @@ +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-CLDAP-generate-NetBIOS-name-like-ipa-adtrust-install.patch b/SOURCES/0039-CLDAP-generate-NetBIOS-name-like-ipa-adtrust-install.patch deleted file mode 100644 index 7bcceae..0000000 --- a/SOURCES/0039-CLDAP-generate-NetBIOS-name-like-ipa-adtrust-install.patch +++ /dev/null @@ -1,104 +0,0 @@ -From c57ff0a9aae8e51de1de8671dc6c8d91a1f1af66 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 23 Jan 2014 14:39:24 +0100 -Subject: [PATCH] CLDAP: generate NetBIOS name like ipa-adtrust-install does - -Fixes https://fedorahosted.org/freeipa/ticket/4116 ---- - daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h | 2 + - .../ipa-cldap/ipa_cldap_netlogon.c | 47 +++++++++++++++------- - 2 files changed, 35 insertions(+), 14 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h -index 3f420ff2c5acc7bd75bff7f042f76b9c61144461..5e963e3f8557d468d646e6343366921d17242e2d 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap.h -@@ -51,6 +51,7 @@ - #include - #include - #include -+#include - #include "util.h" - - #define IPA_CLDAP_PLUGIN_NAME "CLDAP Server" -@@ -106,4 +107,5 @@ int ipa_cldap_netlogon(struct ipa_cldap_ctx *ctx, - struct ipa_cldap_req *req, - struct berval *reply); - -+char *make_netbios_name(TALLOC_CTX *mem_ctx, const char *s); - #endif /* _IPA_CLDAP_H_ */ -diff --git a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -index c03172d474589ddee84f1cfa5395c23fdba83bcb..1d16de7be09cf9675c2ee1a602ddfb800cd6e7af 100644 ---- a/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -+++ b/daemons/ipa-slapi-plugins/ipa-cldap/ipa_cldap_netlogon.c -@@ -121,6 +121,38 @@ done: - return ret; - } - -+char *make_netbios_name(TALLOC_CTX *mem_ctx, const char *s) -+{ -+ char *nb_name; -+ const char *p; -+ size_t c = 0; -+ -+ if (s == NULL) { -+ return NULL; -+ } -+ -+ nb_name = talloc_zero_size(mem_ctx, NETBIOS_NAME_MAX + 1); -+ if (nb_name == NULL) { -+ return NULL; -+ } -+ -+ for (p = s; *p && c < NETBIOS_NAME_MAX; p++) { -+ /* Create the NetBIOS name from the first segment of the hostname */ -+ if (*p == '.') { -+ break; -+ } else if (isalnum(*p)) { -+ nb_name[c++] = toupper(*p); -+ } -+ } -+ -+ if (*nb_name == '\0') { -+ talloc_free(nb_name); -+ return NULL; -+ } -+ -+ return nb_name; -+} -+ - #define NETLOGON_SAM_LOGON_RESPONSE_EX_pusher \ - (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX - -@@ -131,8 +163,6 @@ static int ipa_cldap_encode_netlogon(char *fq_hostname, char *domain, - struct NETLOGON_SAM_LOGON_RESPONSE_EX *nlr; - enum ndr_err_code ndr_err; - DATA_BLOB blob; -- char *pdc_name; -- char *p; - int ret; - - nlr = talloc_zero(NULL, struct NETLOGON_SAM_LOGON_RESPONSE_EX); -@@ -162,18 +192,7 @@ static int ipa_cldap_encode_netlogon(char *fq_hostname, char *domain, - nlr->pdc_dns_name = fq_hostname; - nlr->domain_name = name; - -- /* copy the first 15 characters of the fully qualified hostname*/ -- pdc_name = talloc_asprintf(nlr, "%.*s", NETBIOS_NAME_MAX, fq_hostname); -- -- for (p = pdc_name; *p; p++) { -- /* Create the NetBIOS name from the first segment of the hostname */ -- if (*p == '.') { -- *p = '\0'; -- break; -- } -- *p = toupper(*p); -- } -- nlr->pdc_name = pdc_name; -+ nlr->pdc_name = make_netbios_name(nlr, fq_hostname); - nlr->user_name = ""; - nlr->server_site = "Default-First-Site-Name"; - nlr->client_site = "Default-First-Site-Name"; --- -1.8.3.1 - 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 new file mode 100644 index 0000000..2714868 --- /dev/null +++ b/SOURCES/0039-Raise-right-exception-if-domain-name-is-not-valid.patch @@ -0,0 +1,46 @@ +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/0040-Fallback-to-global-policy-in-ipa-lockout-plugin.patch b/SOURCES/0040-Fallback-to-global-policy-in-ipa-lockout-plugin.patch deleted file mode 100644 index 5483f37..0000000 --- a/SOURCES/0040-Fallback-to-global-policy-in-ipa-lockout-plugin.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 2392ccb4ff9f0310512a6313240749900567d831 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Thu, 30 Jan 2014 16:58:25 +0100 -Subject: [PATCH] Fallback to global policy in ipa-lockout plugin - -krbPwdPolicyReference is no longer filled default users. Instead, plugins -fallback to hardcoded global policy reference. - -Fix ipa-lockout plugin to fallback to it instead of failing to apply -the policy. - -https://fedorahosted.org/freeipa/ticket/4085 ---- - .../ipa-slapi-plugins/ipa-lockout/ipa_lockout.c | 34 ++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c -index fd6602fdee9b2fd95c154fd512fcba4f37e56bad..5a24359d319aaea28773daa01d268d2d46583270 100644 ---- a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c -+++ b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c -@@ -49,6 +49,7 @@ - #include - #include "slapi-plugin.h" - #include "nspr.h" -+#include - - #include "util.h" - -@@ -81,6 +82,8 @@ static int g_plugin_started = 0; - - static struct ipa_context *global_ipactx = NULL; - -+static char *ipa_global_policy = NULL; -+ - #define GENERALIZED_TIME_LENGTH 15 - - /** -@@ -142,8 +145,11 @@ ipalockout_get_global_config(struct ipa_context *ipactx) - Slapi_Attr *attr = NULL; - char *dn = NULL; - char *basedn = NULL; -+ char *realm = NULL; - Slapi_DN *sdn; - Slapi_Entry *config_entry; -+ krb5_context krbctx = NULL; -+ krb5_error_code krberr; - int ret; - - /* Get cn=config so we can get the default naming context */ -@@ -167,6 +173,28 @@ ipalockout_get_global_config(struct ipa_context *ipactx) - goto done; - } - -+ krberr = krb5_init_context(&krbctx); -+ if (krberr) { -+ LOG_FATAL("krb5_init_context failed (%d)\n", krberr); -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; -+ } -+ -+ krberr = krb5_get_default_realm(krbctx, &realm); -+ if (krberr) { -+ LOG_FATAL("Failed to get default realm (%d)\n", krberr); -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; -+ } -+ -+ ipa_global_policy = slapi_ch_smprintf("cn=global_policy,cn=%s,cn=kerberos,%s", -+ realm, basedn); -+ if (!ipa_global_policy) { -+ LOG_OOM(); -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; -+ } -+ - ret = asprintf(&dn, "cn=ipaConfig,cn=etc,%s", basedn); - if (ret == -1) { - LOG_OOM(); -@@ -221,6 +249,8 @@ ipalockout_get_global_config(struct ipa_context *ipactx) - done: - if (config_entry) - slapi_entry_free(config_entry); -+ free(realm); -+ krb5_free_context(krbctx); - free(dn); - free(basedn); - return ret; -@@ -248,6 +278,8 @@ int ipalockout_getpolicy(Slapi_Entry *target_entry, Slapi_Entry **policy_entry, - slapi_valueset_first_value(*values, &sv); - *policy_dn = slapi_value_get_string(sv); - } -+ } else { -+ *policy_dn = ipa_global_policy; - } - - if (*policy_dn == NULL) { -@@ -376,6 +408,8 @@ ipalockout_close(Slapi_PBlock * pb) - { - LOG_TRACE( "--in-->\n"); - -+ slapi_ch_free_string(&ipa_global_policy); -+ - LOG_TRACE("<--out--\n"); - - return EOK; --- -1.8.5.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 new file mode 100644 index 0000000..5d920ee --- /dev/null +++ b/SOURCES/0040-Restore-file-extended-attributes-and-SELinux-context.patch @@ -0,0 +1,38 @@ +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/0041-Migration-does-not-add-users-to-default-group.patch b/SOURCES/0041-Migration-does-not-add-users-to-default-group.patch deleted file mode 100644 index 10c292c..0000000 --- a/SOURCES/0041-Migration-does-not-add-users-to-default-group.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 8b7a17d19428fa13dcd76893d758863adb9f515e Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Mon, 27 Jan 2014 12:28:12 +0100 -Subject: [PATCH] Migration does not add users to default group - -When users with missing default group were searched, IPA suffix was -not passed so these users were searched in a wrong base DN. Thus, -no user was detected and added to default group. - -https://fedorahosted.org/freeipa/ticket/4141 ---- - ipalib/plugins/migration.py | 17 ++++++++++------- - 1 file changed, 10 insertions(+), 7 deletions(-) - -diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py -index 83bf40dbfa4cf2310b2501c28cf095299711331d..0ed65f7015f458aa1cf96efb0e36e28c5019cbd2 100644 ---- a/ipalib/plugins/migration.py -+++ b/ipalib/plugins/migration.py -@@ -286,19 +286,21 @@ def _update_default_group(ldap, pkey, config, ctx, force): - searchfilter = "(&(objectclass=posixAccount)(!(memberof=%s)))" % group_dn - try: - (result, truncated) = ldap.find_entries(searchfilter, -- [''], api.env.container_user, scope=ldap.SCOPE_SUBTREE, -- time_limit = -1) -+ [''], DN(api.env.container_user, api.env.basedn), -+ scope=ldap.SCOPE_SUBTREE, time_limit = -1) - except errors.NotFound: -+ api.log.debug('All users have default group set') - return - new_members = [] - (group_dn, group_entry_attrs) = ldap.get_entry(group_dn, ['member']) -+ existing_members = set(group_entry_attrs.get('member', [])) - for m in result: -- if m[0] not in group_entry_attrs.get('member', []): -+ if m[0] not in existing_members: - new_members.append(m[0]) -- if len(new_members) > 0: -- members = group_entry_attrs.get('member', []) -+ -+ if new_members: -+ members = group_entry_attrs.setdefault('member', []) - members.extend(new_members) -- group_entry_attrs['member'] = members - - try: - ldap.update_entry(group_dn, group_entry_attrs) -@@ -308,7 +310,8 @@ def _update_default_group(ldap, pkey, config, ctx, force): - e = datetime.datetime.now() - d = e - s - mode = " (forced)" if force else "" -- api.log.debug('Adding %d users to group%s duration %s' % (len(new_members), mode, d)) -+ api.log.debug('Adding %d users to group%s duration %s', -+ len(new_members), mode, d) - - # GROUP MIGRATION CALLBACKS AND VARS - --- -1.8.5.3 - diff --git a/SOURCES/0041-restore-clear-httpd-ccache-after-restore.patch b/SOURCES/0041-restore-clear-httpd-ccache-after-restore.patch new file mode 100644 index 0000000..ed2eb27 --- /dev/null +++ b/SOURCES/0041-restore-clear-httpd-ccache-after-restore.patch @@ -0,0 +1,32 @@ +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-user-group-ignore-attribute-in-migration-plugin.patch b/SOURCES/0042-Fix-user-group-ignore-attribute-in-migration-plugin.patch new file mode 100644 index 0000000..0b0939a --- /dev/null +++ b/SOURCES/0042-Fix-user-group-ignore-attribute-in-migration-plugin.patch @@ -0,0 +1,45 @@ +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/0042-ipa-lockout-do-not-fail-when-default-realm-cannot-be.patch b/SOURCES/0042-ipa-lockout-do-not-fail-when-default-realm-cannot-be.patch deleted file mode 100644 index 3020bec..0000000 --- a/SOURCES/0042-ipa-lockout-do-not-fail-when-default-realm-cannot-be.patch +++ /dev/null @@ -1,65 +0,0 @@ -From c41034f5ab587023d9941409618bdf5dc9046fae Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Tue, 4 Feb 2014 11:02:34 +0100 -Subject: [PATCH] ipa-lockout: do not fail when default realm cannot be read - -When ipa-lockout plugin is started during FreeIPA server installation, -the default realm may not be available and plugin should then not end -with failure. - -Similarly to other plugins, start in degraded mode in this situation. -Operation is fully restored during the final services restart. - -https://fedorahosted.org/freeipa/ticket/4085 ---- - .../ipa-slapi-plugins/ipa-lockout/ipa_lockout.c | 34 +++++++++++----------- - 1 file changed, 17 insertions(+), 17 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c -index 5a24359d319aaea28773daa01d268d2d46583270..265c2701c36fe78486a2bdd4a66366b0b05472a0 100644 ---- a/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c -+++ b/daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c -@@ -176,23 +176,23 @@ ipalockout_get_global_config(struct ipa_context *ipactx) - krberr = krb5_init_context(&krbctx); - if (krberr) { - LOG_FATAL("krb5_init_context failed (%d)\n", krberr); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- -- krberr = krb5_get_default_realm(krbctx, &realm); -- if (krberr) { -- LOG_FATAL("Failed to get default realm (%d)\n", krberr); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -- } -- -- ipa_global_policy = slapi_ch_smprintf("cn=global_policy,cn=%s,cn=kerberos,%s", -- realm, basedn); -- if (!ipa_global_policy) { -- LOG_OOM(); -- ret = LDAP_OPERATIONS_ERROR; -- goto done; -+ /* Yes, we failed, but it is because /etc/krb5.conf doesn't exist -+ * or is misconfigured. Start up in a degraded mode. -+ */ -+ } else { -+ krberr = krb5_get_default_realm(krbctx, &realm); -+ if (krberr) { -+ LOG_FATAL("Failed to get default realm (%d)\n", krberr); -+ } else { -+ ipa_global_policy = -+ slapi_ch_smprintf("cn=global_policy,cn=%s,cn=kerberos,%s", -+ realm, basedn); -+ if (!ipa_global_policy) { -+ LOG_OOM(); -+ ret = LDAP_OPERATIONS_ERROR; -+ goto done; -+ } -+ } - } - - ret = asprintf(&dn, "cn=ipaConfig,cn=etc,%s", basedn); --- -1.8.5.3 - diff --git a/SOURCES/0043-Fix-filtering-of-enctypes-in-server-code.patch b/SOURCES/0043-Fix-filtering-of-enctypes-in-server-code.patch new file mode 100644 index 0000000..27024cf --- /dev/null +++ b/SOURCES/0043-Fix-filtering-of-enctypes-in-server-code.patch @@ -0,0 +1,98 @@ +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-ipa-tool-Print-the-name-of-the-server-we-are-connect.patch b/SOURCES/0043-ipa-tool-Print-the-name-of-the-server-we-are-connect.patch deleted file mode 100644 index 9f66da8..0000000 --- a/SOURCES/0043-ipa-tool-Print-the-name-of-the-server-we-are-connect.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 09a2ae5368abce22e397fef29d3acf3c16b8b96c Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 5 Feb 2014 09:24:22 +0100 -Subject: [PATCH 43/46] ipa tool: Print the name of the server we are - connecting to with -v -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The logging level for these messages was decreaed so that they -do not show up in ipa-advise output. -Reset the log level to INFO and configure ipa-advise to not display -INFO messages from xmlclient by default. - -Partially reverts commit efe5a96725d3ddcd05b03a1ca9df5597eee693be - -https://fedorahosted.org/freeipa/ticket/4135 - -Reviewed-By: Tomáš Babej ---- - ipalib/rpc.py | 4 ++-- - ipaserver/advise/base.py | 5 +++++ - 2 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/ipalib/rpc.py b/ipalib/rpc.py -index 81e7aa35fdf780b3dcd850cfcc3ba5285d71e461..1eec1134617dd49395c2b36f11f304c473067a5d 100644 ---- a/ipalib/rpc.py -+++ b/ipalib/rpc.py -@@ -621,7 +621,7 @@ def create_connection(self, ccache=None, verbose=False, fallback=True, - kw['transport'] = KerbTransport() - else: - kw['transport'] = LanguageAwareTransport() -- self.log.debug('trying %s' % url) -+ self.log.info('trying %s' % url) - setattr(context, 'request_url', url) - serverproxy = ServerProxy(url, **kw) - if len(urls) == 1: -@@ -697,7 +697,7 @@ def forward(self, name, *args, **kw): - '%s.forward(): %r not in api.Command' % (self.name, name) - ) - server = getattr(context, 'request_url', None) -- self.debug("Forwarding '%s' to server '%s'", name, server) -+ self.log.info("Forwarding '%s' to server '%s'", name, server) - command = getattr(self.conn, name) - params = [args, kw] - try: -diff --git a/ipaserver/advise/base.py b/ipaserver/advise/base.py -index 92dbb4e9e30c6d624eca95609568ae62bd9ea7fe..056cb808d24805202f16b4afd60356163ca9006a 100644 ---- a/ipaserver/advise/base.py -+++ b/ipaserver/advise/base.py -@@ -22,6 +22,7 @@ - from ipalib.errors import ValidationError - from ipapython import admintool - from textwrap import wrap -+from ipapython.ipa_log_manager import log_mgr - - - """ -@@ -173,6 +174,10 @@ def run(self): - - api.bootstrap(in_server=False, context='advise') - api.finalize() -+ if not self.options.verbose: -+ # Do not print connection information by default -+ logger_name = r'ipa\.ipalib\.rpc\.xmlclient' -+ log_mgr.configure(dict(logger_regexps=[(logger_name, 'warning')])) - - # With no argument, print the list out and exit - if not self.args: --- -1.8.5.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 new file mode 100644 index 0000000..31aba71 --- /dev/null +++ b/SOURCES/0044-Add-asn1c-generated-code-for-keytab-controls.patch @@ -0,0 +1,13109 @@ +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-Remove-sourcehostcategory-from-the-default-HBAC-rule.patch b/SOURCES/0044-Remove-sourcehostcategory-from-the-default-HBAC-rule.patch deleted file mode 100644 index b2822e3..0000000 --- a/SOURCES/0044-Remove-sourcehostcategory-from-the-default-HBAC-rule.patch +++ /dev/null @@ -1,41 +0,0 @@ -From b3d761fb187f08d910df0bee420e9ed3b23d035f Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 6 Feb 2014 12:33:43 +0100 -Subject: [PATCH 44/46] Remove sourcehostcategory from the default HBAC rule. - -https://fedorahosted.org/freeipa/ticket/4158 - -Reviewed-By: Martin Kosek ---- - install/share/default-hbac.ldif | 1 - - ipalib/plugins/hbacrule.py | 2 +- - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/install/share/default-hbac.ldif b/install/share/default-hbac.ldif -index b7b6ba28453b867fa142d038b1e35e162dac800f..52fd30ec9ac4e01f68d9cc6a94fb4cc15177e10b 100644 ---- a/install/share/default-hbac.ldif -+++ b/install/share/default-hbac.ldif -@@ -7,7 +7,6 @@ dn: - accessruletype: allow - usercategory: all - hostcategory: all --sourcehostcategory: all - servicecategory: all - ipaenabledflag: TRUE - description: Allow all users to access any host from any host -diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py -index 5cc8bc1a34de38ce5c5f6faf8ea24ee6873bf0b7..daf165346ba67c6525f7ab2034519c7a03fd3394 100644 ---- a/ipalib/plugins/hbacrule.py -+++ b/ipalib/plugins/hbacrule.py -@@ -118,7 +118,7 @@ class hbacrule(LDAPObject): - default_attributes = [ - 'cn', 'ipaenabledflag', - 'description', 'usercategory', 'hostcategory', -- 'sourcehostcategory', 'servicecategory', 'ipaenabledflag', -+ 'servicecategory', 'ipaenabledflag', - 'memberuser', 'sourcehost', 'memberhost', 'memberservice', - 'memberhostgroup', 'externalhost', - ] --- -1.8.5.3 - diff --git a/SOURCES/0045-DNS-classless-support-for-reverse-domains.patch b/SOURCES/0045-DNS-classless-support-for-reverse-domains.patch deleted file mode 100644 index 3611dcc..0000000 --- a/SOURCES/0045-DNS-classless-support-for-reverse-domains.patch +++ /dev/null @@ -1,229 +0,0 @@ -From c884a56c2d9996fc54c054c78d56eae50f696997 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 31 Jan 2014 15:42:31 +0100 -Subject: [PATCH 45/46] DNS classless support for reverse domains - -Now users can add reverse zones in classless form: -0/25.1.168.192.in-addr.arpa. -0-25.1.168.192.in-addr.arpa. - -128/25 NS ns.example.com. -10 CNAME 10.128/25.1.168.192.in-addr.arpa. - -Ticket: https://fedorahosted.org/freeipa/ticket/4143 -Reviewed-By: Jan Cholasta ---- - ipalib/plugins/dns.py | 45 +++++++++++++++++++++++++++---------- - ipalib/util.py | 61 ++++++++++++++++++++++++++++++--------------------- - 2 files changed, 70 insertions(+), 36 deletions(-) - -diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py -index 94ae92ba5d1ae42e31ebb6100c743a2334f29e70..a78dc9e90a04a00a731541f8a04db5c0f0dd12bb 100644 ---- a/ipalib/plugins/dns.py -+++ b/ipalib/plugins/dns.py -@@ -368,25 +368,31 @@ def _normalize_bind_aci(bind_acis): - acis += u';' - return acis - --def _bind_hostname_validator(ugettext, value): -+def _bind_hostname_validator(ugettext, value, allow_slash=False): - if value == _dns_zone_record: - return - try: - # Allow domain name which is not fully qualified. These are supported - # in bind and then translated as .. -- validate_hostname(value, check_fqdn=False, allow_underscore=True) -+ validate_hostname(value, check_fqdn=False, allow_underscore=True, allow_slash=allow_slash) - except ValueError, e: - return _('invalid domain-name: %s') \ - % unicode(e) - - return None - -+def _bind_cname_hostname_validator(ugettext, value): -+ """ -+ Validator for CNAME allows classless domain names (25/0.0.10.in-addr.arpa.) -+ """ -+ return _bind_hostname_validator(ugettext, value, allow_slash=True) -+ - def _dns_record_name_validator(ugettext, value): - if value == _dns_zone_record: - return - - try: -- map(lambda label:validate_dns_label(label, allow_underscore=True), \ -+ map(lambda label:validate_dns_label(label, allow_underscore=True, allow_slash=True), \ - value.split(u'.')) - except ValueError, e: - return unicode(e) -@@ -411,7 +417,10 @@ def _validate_bind_forwarder(ugettext, forwarder): - - def _domain_name_validator(ugettext, value): - try: -- validate_domain_name(value) -+ #classless reverse zones can contain slash '/' -+ normalized_zone = normalize_zone(value) -+ validate_domain_name(value, allow_slash=zone_is_reverse(normalized_zone)) -+ - except ValueError, e: - return unicode(e) - -@@ -939,7 +948,7 @@ class CNAMERecord(DNSRecord): - rfc = 1035 - parts = ( - Str('hostname', -- _bind_hostname_validator, -+ _bind_cname_hostname_validator, - label=_('Hostname'), - doc=_('A hostname which this alias hostname points to'), - ), -@@ -960,7 +969,7 @@ class DNAMERecord(DNSRecord): - rfc = 2672 - parts = ( - Str('target', -- _bind_hostname_validator, -+ _bind_cname_hostname_validator, - label=_('Target'), - ), - ) -@@ -2119,6 +2128,14 @@ class dnsrecord(LDAPObject): - doc=_('Parse all raw DNS records and return them in a structured way'), - ) - -+ def _idnsname_pre_callback(self, ldap, dn, entry_attrs, *keys, **options): -+ if not self.is_pkey_zone_record(*keys): -+ zone, addr = normalize_zone(keys[-2]), keys[-1] -+ try: -+ validate_domain_name(addr, allow_underscore=True, allow_slash=zone_is_reverse(zone)) -+ except ValueError, e: -+ raise errors.ValidationError(name='idnsname', error=unicode(e)) -+ - def _nsrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) - nsrecords = entry_attrs.get('nsrecord') -@@ -2132,6 +2149,7 @@ def _ptrrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options): - ptrrecords = entry_attrs.get('ptrrecord') - if ptrrecords is None: - return -+ - zone = keys[-2] - if self.is_pkey_zone_record(*keys): - addr = u'' -@@ -2150,11 +2168,16 @@ def _ptrrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options): - error=unicode(_('Reverse zone for PTR record should be a sub-zone of one the following fully qualified domains: %s') % allowed_zones)) - - addr_len = len(addr.split('.')) if addr else 0 -- ip_addr_comp_count = addr_len + len(zone.split('.')) -- if ip_addr_comp_count != zone_len: -- raise errors.ValidationError(name='ptrrecord', -- error=unicode(_('Reverse zone %(name)s requires exactly %(count)d IP address components, %(user_count)d given') -- % dict(name=zone_name, count=zone_len, user_count=ip_addr_comp_count))) -+ -+ #Classless zones (0/25.0.0.10.in-addr.arpa.) -> skip check -+ #zone has to be checked without reverse domain suffix (in-addr.arpa.) -+ if ('/' not in addr and '/' not in zone and -+ '-' not in addr and '-' not in zone): -+ ip_addr_comp_count = addr_len + len(zone.split('.')) -+ if ip_addr_comp_count != zone_len: -+ raise errors.ValidationError(name='ptrrecord', -+ error=unicode(_('Reverse zone %(name)s requires exactly %(count)d IP address components, %(user_count)d given') -+ % dict(name=zone_name, count=zone_len, user_count=ip_addr_comp_count))) - - def run_precallback_validators(self, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) -diff --git a/ipalib/util.py b/ipalib/util.py -index 3c52e4fd9a3e08d160dd4ae7076590be8b869d2c..17851294a78507aba7035390c3695184b7d641b1 100644 ---- a/ipalib/util.py -+++ b/ipalib/util.py -@@ -215,34 +215,45 @@ def normalize_zone(zone): - else: - return zone - --def validate_dns_label(dns_label, allow_underscore=False): -- label_chars = r'a-z0-9' -- underscore_err_msg = '' -- if allow_underscore: -- label_chars += "_" -- underscore_err_msg = u' _,' -- label_regex = r'^[%(chars)s]([%(chars)s-]?[%(chars)s])*$' % dict(chars=label_chars) -- regex = re.compile(label_regex, re.IGNORECASE) -- -- if not dns_label: -- raise ValueError(_('empty DNS label')) -- -- if len(dns_label) > 63: -- raise ValueError(_('DNS label cannot be longer that 63 characters')) -- -- if not regex.match(dns_label): -- raise ValueError(_('only letters, numbers,%(underscore)s and - are allowed. ' \ -- 'DNS label may not start or end with -') \ -- % dict(underscore=underscore_err_msg)) -- --def validate_domain_name(domain_name, allow_underscore=False): -+ -+def validate_dns_label(dns_label, allow_underscore=False, allow_slash=False): -+ base_chars = 'a-z0-9' -+ extra_chars = '' -+ middle_chars = '' -+ -+ if allow_underscore: -+ extra_chars += '_' -+ if allow_slash: -+ middle_chars += '/' -+ -+ middle_chars = middle_chars + '-' #has to be always the last in the regex [....-] -+ -+ label_regex = r'^[%(base)s%(extra)s]([%(base)s%(extra)s%(middle)s]?[%(base)s%(extra)s])*$' \ -+ % dict(base=base_chars, extra=extra_chars, middle=middle_chars) -+ regex = re.compile(label_regex, re.IGNORECASE) -+ -+ if not dns_label: -+ raise ValueError(_('empty DNS label')) -+ -+ if len(dns_label) > 63: -+ raise ValueError(_('DNS label cannot be longer that 63 characters')) -+ -+ if not regex.match(dns_label): -+ chars = ', '.join("'%s'" % c for c in extra_chars + middle_chars) -+ chars2 = ', '.join("'%s'" % c for c in middle_chars) -+ raise ValueError(_("only letters, numbers, %(chars)s are allowed. " \ -+ "DNS label may not start or end with %(chars2)s") \ -+ % dict(chars=chars, chars2=chars2)) -+ -+ -+def validate_domain_name(domain_name, allow_underscore=False, allow_slash=False): - if domain_name.endswith('.'): - domain_name = domain_name[:-1] - - domain_name = domain_name.split(".") - - # apply DNS name validator to every name part -- map(lambda label:validate_dns_label(label,allow_underscore), domain_name) -+ map(lambda label:validate_dns_label(label, allow_underscore, allow_slash), domain_name) - - - def validate_zonemgr(zonemgr): -@@ -287,7 +298,7 @@ def validate_zonemgr(zonemgr): - local_part.split(local_part_sep)): - raise ValueError(local_part_errmsg) - --def validate_hostname(hostname, check_fqdn=True, allow_underscore=False): -+def validate_hostname(hostname, check_fqdn=True, allow_underscore=False, allow_slash=False): - """ See RFC 952, 1123 - - :param hostname Checked value -@@ -305,9 +316,9 @@ def validate_hostname(hostname, check_fqdn=True, allow_underscore=False): - if '.' not in hostname: - if check_fqdn: - raise ValueError(_('not fully qualified')) -- validate_dns_label(hostname,allow_underscore) -+ validate_dns_label(hostname, allow_underscore, allow_slash) - else: -- validate_domain_name(hostname,allow_underscore) -+ validate_domain_name(hostname, allow_underscore, allow_slash) - - def normalize_sshpubkey(value): - return SSHPublicKey(value).openssh() --- -1.8.5.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 new file mode 100644 index 0000000..e8c728e --- /dev/null +++ b/SOURCES/0045-Use-asn1c-helpers-to-encode-decode-the-getkeytab-con.patch @@ -0,0 +1,813 @@ +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/0046-Fix-read_ip_addresses-should-return-ipaddr-object.patch b/SOURCES/0046-Fix-read_ip_addresses-should-return-ipaddr-object.patch new file mode 100644 index 0000000..f8c56c9 --- /dev/null +++ b/SOURCES/0046-Fix-read_ip_addresses-should-return-ipaddr-object.patch @@ -0,0 +1,30 @@ +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-Move-ipa-otpd-socket-directory.patch b/SOURCES/0046-Move-ipa-otpd-socket-directory.patch deleted file mode 100644 index 87a59bf..0000000 --- a/SOURCES/0046-Move-ipa-otpd-socket-directory.patch +++ /dev/null @@ -1,84 +0,0 @@ -From e7d5a0c79e780fddb97bcbf2763a19a2c0b244c7 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Fri, 7 Feb 2014 11:56:33 -0500 -Subject: [PATCH 46/46] Move ipa-otpd socket directory - -https://fedorahosted.org/freeipa/ticket/4167 -Reviewed-By: Martin Kosek ---- - daemons/configure.ac | 6 +++--- - daemons/ipa-otpd/Makefile.am | 2 +- - daemons/ipa-otpd/ipa-otpd.socket.in | 4 ++-- - freeipa.spec.in | 2 +- - 4 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/daemons/configure.ac b/daemons/configure.ac -index e57dad27614f268d3e5bbafc99b739a5cfa2589b..5646c3873beee996999e4f1d87aea653f4b5dd1b 100644 ---- a/daemons/configure.ac -+++ b/daemons/configure.ac -@@ -60,10 +60,10 @@ AC_CHECK_LIB(k5crypto, main, [krb5crypto=k5crypto], [krb5crypto=crypto]) - AC_CHECK_LIB(krad, main, [], [AC_MSG_ERROR([libkrad not found])]) - KRB5_LIBS="-lkrb5 -l$krb5crypto -lcom_err" - KRAD_LIBS="-lkrad" --krb5kdcdir="${localstatedir}/kerberos/krb5kdc" -+krb5rundir="${localstatedir}/run/krb5kdc" - AC_SUBST(KRB5_LIBS) - AC_SUBST(KRAD_LIBS) --AC_SUBST(krb5kdcdir) -+AC_SUBST(krb5rundir) - - dnl --------------------------------------------------------------------------- - dnl - Check for Mozilla LDAP and OpenLDAP SDK -@@ -337,7 +337,7 @@ echo " - sysconfdir: ${sysconfdir} - localstatedir: ${localstatedir} - datadir: ${datadir} -- krb5kdcdir: ${krb5kdcdir} -+ krb5rundir: ${krb5rundir} - systemdsystemunitdir: ${systemdsystemunitdir} - source code location: ${srcdir} - compiler: ${CC} -diff --git a/daemons/ipa-otpd/Makefile.am b/daemons/ipa-otpd/Makefile.am -index af82a5fe08856573d2d245608ba1dbaad171c7fe..83921748426d801e1edeec23f956689be5fe98b5 100644 ---- a/daemons/ipa-otpd/Makefile.am -+++ b/daemons/ipa-otpd/Makefile.am -@@ -9,7 +9,7 @@ systemdsystemunit_DATA = ipa-otpd.socket ipa-otpd@.service - ipa_otpd_SOURCES = bind.c forward.c main.c parse.c query.c queue.c stdio.c - - %.socket: %.socket.in -- @sed -e 's|@krb5kdcdir[@]|$(krb5kdcdir)|g' \ -+ @sed -e 's|@krb5rundir[@]|$(krb5rundir)|g' \ - -e 's|@UNLINK[@]|@UNLINK@|g' \ - $< > $@ - -diff --git a/daemons/ipa-otpd/ipa-otpd.socket.in b/daemons/ipa-otpd/ipa-otpd.socket.in -index b968beaa7b9e68c43b2c5386b62c096fa8b97764..ce3596d9f01b26e3e8bd63f447f85a486c8e0dff 100644 ---- a/daemons/ipa-otpd/ipa-otpd.socket.in -+++ b/daemons/ipa-otpd/ipa-otpd.socket.in -@@ -2,8 +2,8 @@ - Description=ipa-otpd socket - - [Socket] --ListenStream=@krb5kdcdir@/DEFAULT.socket --ExecStopPre=@UNLINK@ @krb5kdcdir@/DEFAULT.socket -+ListenStream=@krb5rundir@/DEFAULT.socket -+ExecStopPre=@UNLINK@ @krb5rundir@/DEFAULT.socket - SocketMode=0600 - Accept=true - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index ae8ee57f3ba2c0746bb0f7a1e65dab1da83cca22..cff79843d76a7251ae6065dba7341465733bb7cc 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -105,7 +105,7 @@ Requires: nss >= 3.14.3-12.0 - Requires: nss-tools >= 3.14.3-12.0 - %endif - %if 0%{?krb5_dal_version} >= 4 --Requires: krb5-server >= 1.11.2-1 -+Requires: krb5-server >= 1.11.5-3 - %else - %if 0%{krb5_dal_version} == 3 - # krb5 1.11 bumped DAL interface major version, a rebuild is needed --- -1.8.5.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 new file mode 100644 index 0000000..8ba39fc --- /dev/null +++ b/SOURCES/0047-Use-correct-service-name-in-cainstance.backup_config.patch @@ -0,0 +1,29 @@ +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/0047-bindinstance-make-sure-zone-manager-is-initialized-i.patch b/SOURCES/0047-bindinstance-make-sure-zone-manager-is-initialized-i.patch deleted file mode 100644 index 7a023ac..0000000 --- a/SOURCES/0047-bindinstance-make-sure-zone-manager-is-initialized-i.patch +++ /dev/null @@ -1,31 +0,0 @@ -From ea96ad03312cecad4ff6853aafc30d3cf2c618a9 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 26 Feb 2014 11:06:29 +0200 -Subject: [PATCH 47/51] bindinstance: make sure zone manager is initialized in - add_master_dns_records - -Bind instance is configured using a short-circuited way when replica is set up. -Make sure required properties are in place for that. - -https://fedorahosted.org/freeipa/ticket/4186 - -Reviewed-By: Petr Viktorin ---- - ipaserver/install/bindinstance.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 6d5a1d44d30c89278c24fe7ab5278355cb65b0b4..4dc4103f7cb94877d0652f0094b41feec56cee94 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -828,6 +828,7 @@ def add_master_dns_records(self, fqdn, ip_address, realm_name, domain_name, - self.reverse_zone = reverse_zone - self.ca_configured = ca_configured - self.first_instance = False -+ self.zonemgr = 'hostmaster.%s' % self.domain - - self.__add_self() - self.__add_ipa_ca_record() --- -1.8.5.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 new file mode 100644 index 0000000..0568548 --- /dev/null +++ b/SOURCES/0048-ipa-restore-Check-if-directory-is-provided-better-er.patch @@ -0,0 +1,54 @@ +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/0048-trustdomain_find-make-sure-we-skip-short-entries-whe.patch b/SOURCES/0048-trustdomain_find-make-sure-we-skip-short-entries-whe.patch deleted file mode 100644 index b1718fb..0000000 --- a/SOURCES/0048-trustdomain_find-make-sure-we-skip-short-entries-whe.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a11cfd34e2f92c3c71a0b568d758f7d5221b4e94 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 26 Feb 2014 17:59:05 +0200 -Subject: [PATCH 48/51] trustdomain_find: make sure we skip short entries when - --pkey-only is specified - -With --pkey-only only primary key is returned. It makes no sense to check and -replace boolean values then. - -https://fedorahosted.org/freeipa/ticket/4196 - -Reviewed-By: Martin Kosek ---- - ipalib/plugins/trust.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index 0b6db27c696cd169c8f4b33128520961c20e3015..bd71253607d6009414ff8a24b042175f0cb08d66 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -1191,6 +1191,8 @@ def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **optio - return (filters, base_dn, ldap.SCOPE_SUBTREE) - - def post_callback(self, ldap, entries, truncated, *args, **options): -+ if options.get('pkey_only', False): -+ return truncated - trust_dn = self.obj.get_dn(args[0], trust_type=u'ad') - trust_entry = ldap.get_entry(trust_dn) - for entry in entries: --- -1.8.5.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 new file mode 100644 index 0000000..f8870c5 --- /dev/null +++ b/SOURCES/0049-Stop-tracking-certificates-before-restoring-them-in-.patch @@ -0,0 +1,57 @@ +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/0049-ipa-kdb-in-case-of-delegation-use-original-client-s-.patch b/SOURCES/0049-ipa-kdb-in-case-of-delegation-use-original-client-s-.patch deleted file mode 100644 index a3c7c45..0000000 --- a/SOURCES/0049-ipa-kdb-in-case-of-delegation-use-original-client-s-.patch +++ /dev/null @@ -1,67 +0,0 @@ -From ede01c14e58a98af728152635e5d75be0deb389d Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 25 Feb 2014 17:50:55 +0200 -Subject: [PATCH 49/51] ipa-kdb: in case of delegation use original client's - database entry, not the proxy -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -https://fedorahosted.org/freeipa/ticket/4195 - -Reviewed-By: Tomáš Babej -Reviewed-By: Simo Sorce ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index ff67391538234e2272ea1ec886ec96fa88ea579b..2a0480fff029d29fb56286d85108936f6c579901 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -1983,12 +1983,14 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - bool with_pac; - bool with_pad; - int result; -+ krb5_db_entry *client_entry = NULL; - - /* When using s4u2proxy client_princ actually refers to the proxied user - * while client->princ to the proxy service asking for the TGS on behalf - * of the proxied user. So always use client_princ in preference */ - if (client_princ != NULL) { - ks_client_princ = client_princ; -+ kerr = ipadb_get_principal(context, client_princ, flags, &client_entry); - } else { - ks_client_princ = client->princ; - } -@@ -2025,7 +2027,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - } - } - -- kerr = ipadb_get_pac(context, client, &pac); -+ kerr = ipadb_get_pac(context, client_entry ? client_entry : client, &pac); - if (kerr != 0 && kerr != ENOENT) { - goto done; - } -@@ -2041,7 +2043,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - /* check or generate pac data */ - if ((pac_auth_data == NULL) || (pac_auth_data[0] == NULL)) { - if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) { -- kerr = ipadb_get_pac(context, client, &pac); -+ kerr = ipadb_get_pac(context, client_entry ? client_entry : client, &pac); - if (kerr != 0 && kerr != ENOENT) { - goto done; - } -@@ -2094,6 +2096,9 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - kerr = 0; - - done: -+ if (client_entry != NULL) { -+ ipadb_free_principal(context, client_entry); -+ } - krb5_pac_free(context, pac); - return kerr; - } --- -1.8.5.3 - diff --git a/SOURCES/0050-Fix-detection-of-encoding-in-zonemgr-option.patch b/SOURCES/0050-Fix-detection-of-encoding-in-zonemgr-option.patch new file mode 100644 index 0000000..2a526dd --- /dev/null +++ b/SOURCES/0050-Fix-detection-of-encoding-in-zonemgr-option.patch @@ -0,0 +1,40 @@ +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-ipa-kdb-make-sure-we-don-t-produce-MS-PAC-in-case-of.patch b/SOURCES/0050-ipa-kdb-make-sure-we-don-t-produce-MS-PAC-in-case-of.patch deleted file mode 100644 index a4909d1..0000000 --- a/SOURCES/0050-ipa-kdb-make-sure-we-don-t-produce-MS-PAC-in-case-of.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 817e83837d249a63395d90ac47dc975a23f00c6c Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 25 Feb 2014 20:53:49 +0200 -Subject: [PATCH 50/51] ipa-kdb: make sure we don't produce MS-PAC in case of - authdata flag cleared by admin -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When admin clears authdata flag for the service principal, KDC will pass -NULL client pointer (service proxy) to the DAL driver. - -Make sure we bail out correctly. - -Reviewed-By: Tomáš Babej -Reviewed-By: Simo Sorce ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 2a0480fff029d29fb56286d85108936f6c579901..9137cd5ad1e6166fd5d6e765fab2c8178ca0587c 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -1985,6 +1985,14 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - int result; - krb5_db_entry *client_entry = NULL; - -+ -+ /* When client is NULL, authdata flag on the service principal was cleared -+ * by an admin. We don't generate MS-PAC in this case */ -+ if (client == NULL) { -+ *signed_auth_data = NULL; -+ return 0; -+ } -+ - /* When using s4u2proxy client_princ actually refers to the proxied user - * while client->princ to the proxy service asking for the TGS on behalf - * of the proxied user. So always use client_princ in preference */ --- -1.8.5.3 - diff --git a/SOURCES/0051-Too-big-font-in-input-fields.patch b/SOURCES/0051-Too-big-font-in-input-fields.patch deleted file mode 100644 index 89a369c..0000000 --- a/SOURCES/0051-Too-big-font-in-input-fields.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 92cb7c52b3a6241c9a0e5bc4e0c91705723d118f Mon Sep 17 00:00:00 2001 -From: Adam Misnyovszki -Date: Wed, 26 Feb 2014 18:16:45 +0100 -Subject: [PATCH 51/51] Too big font in input fields - -In Firefox 27, default font size has bigger priority than body css, -text input font size is therefore explicitly set to 1em. Also -checkbox/radiobutton styling fixed. - -https://fedorahosted.org/freeipa/ticket/4180 - -Reviewed-By: Petr Vobornik ---- - install/ui/ipa.css | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/install/ui/ipa.css b/install/ui/ipa.css -index ad3d1aa1f8f8898ad8dff8f8ecc175238fad1181..29dfe80aacfa1e508f59d3008b2aa57f9477a448 100644 ---- a/install/ui/ipa.css -+++ b/install/ui/ipa.css -@@ -1243,6 +1243,18 @@ table.scrollable tbody { - width: 250px; - } - -+input, select, textarea { -+ font-size: 1em; -+ font-family: "Liberation Sans",Arial,Sans; -+} -+ -+input[type=radio], input[type=checkbox], -+.ui-widget input[type=radio], .ui-widget input[type=checkbox]{ -+ margin-right: 5px; -+ position: relative; -+ top: 3px; -+} -+ - .multivalued-widget [name=value] { - margin-bottom: 1em; - } --- -1.8.5.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 new file mode 100644 index 0000000..63d5bae --- /dev/null +++ b/SOURCES/0051-webui-use-domain-name-instead-of-domain-SID-in-idran.patch @@ -0,0 +1,149 @@ +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-trust-make-sure-we-always-discover-topology-of-the-f.patch b/SOURCES/0052-trust-make-sure-we-always-discover-topology-of-the-f.patch deleted file mode 100644 index 93b27ce..0000000 --- a/SOURCES/0052-trust-make-sure-we-always-discover-topology-of-the-f.patch +++ /dev/null @@ -1,75 +0,0 @@ -From bbba8c95ed2f5e551b4e468b394f5e0839be9f6f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 27 Feb 2014 13:43:17 +0200 -Subject: [PATCH 52/53] trust: make sure we always discover topology of the - forest trust - -Even though we are creating idranges for subdomains only in case -there is algorithmic ID mapping in use, we still need to fetch -list of subdomains for all other cases. - -https://fedorahosted.org/freeipa/ticket/4205 ---- - ipalib/plugins/trust.py | 37 ++++++------------------------------- - 1 file changed, 6 insertions(+), 31 deletions(-) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index bd71253607d6009414ff8a24b042175f0cb08d66..f2b00a6f58f5890e37aaa033a35dcf9bc39ccbc4 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -458,38 +458,13 @@ def execute(self, *keys, **options): - - result['result'] = entry_to_dict(trusts[0][1], **options) - -- # For AD trusts with algorithmic mapping, we need to add a separate -- # range for each subdomain. -- if (options.get('trust_type') == u'ad' and -- created_range_type != u'ipa-ad-trust-posix'): -- -+ # Fetch topology of the trust forest -- we need always to do it -+ # for AD trusts, regardless of the type of idranges associated with it -+ # Note that fetch_domains_from_trust will add needed ranges for -+ # the algorithmic ID mapping case. -+ if options.get('trust_type') == u'ad': - domains = fetch_domains_from_trust(self, self.trustinstance, - result['result'], **options) -- if domains and len(domains) > 0: -- for dom in domains: -- range_name = dom['cn'][0].upper() + '_id_range' -- dom_sid = dom['ipanttrusteddomainsid'][0] -- -- # Enforce the same range type as the range for the root -- # level domain. -- -- # This will skip the detection of the POSIX attributes if -- # they are not available, since it has been already -- # detected when creating the range for the root level domain -- passed_options = options -- passed_options.update(range_type=created_range_type) -- -- # Do not pass the base id to the subdomains since it would -- # clash with the root level domain -- if 'base_id' in passed_options: -- del passed_options['base_id'] -- -- # Try to add the range for each subdomain -- try: -- add_range(self, range_name, dom_sid, *keys, -- **passed_options) -- except errors.DuplicateEntry: -- pass - - # Format the output into human-readable values - result['result']['trusttype'] = [trust_type_string( -@@ -1270,7 +1245,7 @@ def fetch_domains_from_trust(self, trustinstance, trust_entry, **options): - # trust range must exist by the time fetch_domains_from_trust is called - range_name = trust_name.upper() + '_id_range' - old_range = api.Command.idrange_show(range_name, raw=True)['result'] -- idrange_type = old_range['iparangetype'] -+ idrange_type = old_range['iparangetype'][0] - - for dom in domains: - dom['trust_type'] = u'ad' --- -1.8.5.3 - diff --git a/SOURCES/0052-webui-normalize-idview-tab-labels.patch b/SOURCES/0052-webui-normalize-idview-tab-labels.patch new file mode 100644 index 0000000..e00a15e --- /dev/null +++ b/SOURCES/0052-webui-normalize-idview-tab-labels.patch @@ -0,0 +1,48 @@ +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-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 new file mode 100644 index 0000000..080350d --- /dev/null +++ b/SOURCES/0053-copy_schema_to_ca-Fallback-to-old-import-location-fo.patch @@ -0,0 +1,43 @@ +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/0053-ipaserver-dcerpc-catch-the-case-of-insuffient-permis.patch b/SOURCES/0053-ipaserver-dcerpc-catch-the-case-of-insuffient-permis.patch deleted file mode 100644 index eeccfc1..0000000 --- a/SOURCES/0053-ipaserver-dcerpc-catch-the-case-of-insuffient-permis.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 504e8701fd7870b18febe9b544244d5d2744bb16 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 26 Feb 2014 17:43:34 +0200 -Subject: [PATCH 53/53] ipaserver/dcerpc: catch the case of insuffient - permissions when establishing trust - -We attempt to delete the trust that might exist already. If there are not enough -privileges to do so, we wouldn't be able to create trust at the next step and it will fail. -However, failure to create trust will be due to the name collision as we already had -the trust with the same name before. Thus, raise access denied exception here -to properly indicate wrong access level instead of returning NT_STATUS_OBJECT_NAME_COLLISION. - -https://fedorahosted.org/freeipa/ticket/4202 - -Reviewed-By: Martin Kosek ---- - ipaserver/dcerpc.py | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index d809c416baac072a2489fbd3c167f08665b7a24e..5972e622292a033d4fc979cbf5401fa02151f35c 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -892,8 +892,11 @@ def establish_trust(self, another_domain, trustdom_secret): - dname.string = another_domain.info['dns_domain'] - res = self._pipe.QueryTrustedDomainInfoByName(self._policy_handle, dname, lsa.LSA_TRUSTED_DOMAIN_INFO_FULL_INFO) - self._pipe.DeleteTrustedDomain(self._policy_handle, res.info_ex.sid) -- except RuntimeError, e: -- pass -+ except RuntimeError, (num, message): -+ # Ignore anything but access denied (NT_STATUS_ACCESS_DENIED) -+ if num == -1073741790: -+ raise access_denied_error -+ - try: - trustdom_handle = self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE) - except RuntimeError, (num, message): --- -1.8.5.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 new file mode 100644 index 0000000..bb2d6ec --- /dev/null +++ b/SOURCES/0054-Remove-redefinition-of-LOG-from-ipa-otp-lasttoken.patch @@ -0,0 +1,29 @@ +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/0054-fix-filtering-of-subdomain-based-trust-users.patch b/SOURCES/0054-fix-filtering-of-subdomain-based-trust-users.patch deleted file mode 100644 index 4b094ce..0000000 --- a/SOURCES/0054-fix-filtering-of-subdomain-based-trust-users.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 4b7059b4f29832d98b4ff4f266007d007ca07a19 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 28 Feb 2014 22:03:29 +0200 -Subject: [PATCH] fix filtering of subdomain-based trust users - -https://fedorahosted.org/freeipa/ticket/4207 ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 41 ++++++++++++++++++++++++++++++++--------- - 1 file changed, 32 insertions(+), 9 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 9137cd5ad1e6166fd5d6e765fab2c8178ca0587c..68f27f0e2d9028cdaece80c4bd3440d0438d20db 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -806,6 +806,12 @@ static krb5_error_code ipadb_get_pac(krb5_context kcontext, - krb5_error_code kerr; - enum ndr_err_code ndr_err; - -+ /* When no client entry is there, we cannot generate MS-PAC */ -+ if (!client) { -+ *pac = NULL; -+ return 0; -+ } -+ - ipactx = ipadb_get_context(kcontext); - if (!ipactx) { - return KRB5_KDB_DBNOTINITED; -@@ -1534,6 +1540,12 @@ static krb5_error_code ipadb_add_transited_service(krb5_context context, - uint32_t i; - char *tmpstr; - -+ /* When proxy is NULL, authdata flag on the service principal was cleared -+ * by an admin. We don't generate MS-PAC in this case */ -+ if (proxy == NULL) { -+ return 0; -+ } -+ - tmpctx = talloc_new(NULL); - if (!tmpctx) { - kerr = ENOMEM; -@@ -1731,6 +1743,12 @@ static krb5_error_code ipadb_verify_pac(krb5_context context, - } - - if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) { -+ if (proxy == NULL) { -+ *pac = NULL; -+ kerr = 0; -+ goto done; -+ } -+ - kerr = ipadb_add_transited_service(context, proxy, server, - old_pac, new_pac); - if (kerr) { -@@ -1986,20 +2004,27 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - krb5_db_entry *client_entry = NULL; - - -- /* When client is NULL, authdata flag on the service principal was cleared -- * by an admin. We don't generate MS-PAC in this case */ -- if (client == NULL) { -- *signed_auth_data = NULL; -- return 0; -- } -+ is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); - - /* When using s4u2proxy client_princ actually refers to the proxied user - * while client->princ to the proxy service asking for the TGS on behalf - * of the proxied user. So always use client_princ in preference */ - if (client_princ != NULL) { - ks_client_princ = client_princ; -- kerr = ipadb_get_principal(context, client_princ, flags, &client_entry); -+ if (!is_as_req) { -+ kerr = ipadb_get_principal(context, client_princ, flags, &client_entry); -+ /* If we didn't find client_princ in our database, it might be: -+ * - a principal from another realm, handle it down in ipadb_get/verify_pac() -+ */ -+ if (!kerr) { -+ client_entry = NULL; -+ } -+ } - } else { -+ if (client == NULL) { -+ *signed_auth_data = NULL; -+ return 0; -+ } - ks_client_princ = client->princ; - } - -@@ -2014,8 +2039,6 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - "currently not supported."); - } - -- is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); -- - if (is_as_req && with_pac && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) { - /* Be aggressive here: special case for discovering range type - * immediately after establishing the trust by IPA framework */ --- -1.8.5.3 - 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 new file mode 100644 index 0000000..2a2309d --- /dev/null +++ b/SOURCES/0055-Unload-P11_Helper-object-s-library-when-it-is-finali.patch @@ -0,0 +1,81 @@ +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-ipa-kdb-do-not-fetch-client-principal-if-it-is-the-s.patch b/SOURCES/0055-ipa-kdb-do-not-fetch-client-principal-if-it-is-the-s.patch deleted file mode 100644 index a736514..0000000 --- a/SOURCES/0055-ipa-kdb-do-not-fetch-client-principal-if-it-is-the-s.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 278b347c6f84140b4fc58d7c11749bbf6c44a50c Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 6 Mar 2014 10:26:29 +0200 -Subject: [PATCH] ipa-kdb: do not fetch client principal if it is the same as - existing entry - -When client principal is the same as supplied client entry, don't fetch it -again. - -Note that when client principal is not NULL, client entry might be NULL for -cross-realm case, so we need to make sure to not dereference NULL pointer here. - -Also fix reverted condition for case when we didn't find the client principal -in the database, preventing a memory leak. - -https://fedorahosted.org/freeipa/ticket/4223 - -Reviewed-By: Sumit Bose ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 19 +++++++++++++------ - 1 file changed, 13 insertions(+), 6 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 68f27f0e2d9028cdaece80c4bd3440d0438d20db..8481278760aba2d5dec5c337813f394633d67e46 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -2002,6 +2002,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - bool with_pad; - int result; - krb5_db_entry *client_entry = NULL; -+ krb5_boolean is_equal; - - - is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0); -@@ -2012,12 +2013,18 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, - if (client_princ != NULL) { - ks_client_princ = client_princ; - if (!is_as_req) { -- kerr = ipadb_get_principal(context, client_princ, flags, &client_entry); -- /* If we didn't find client_princ in our database, it might be: -- * - a principal from another realm, handle it down in ipadb_get/verify_pac() -- */ -- if (!kerr) { -- client_entry = NULL; -+ is_equal = false; -+ if ((client != NULL) && (client->princ != NULL)) { -+ is_equal = krb5_principal_compare(context, client_princ, client->princ); -+ } -+ if (!is_equal) { -+ kerr = ipadb_get_principal(context, client_princ, flags, &client_entry); -+ /* If we didn't find client_princ in our database, it might be: -+ * - a principal from another realm, handle it down in ipadb_get/verify_pac() -+ */ -+ if (kerr != 0) { -+ client_entry = NULL; -+ } - } - } - } else { --- -1.8.5.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 new file mode 100644 index 0000000..7e6107e --- /dev/null +++ b/SOURCES/0056-Fix-Kerberos-error-handling-in-ipa-sam.patch @@ -0,0 +1,28 @@ +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-ipa-replica-install-never-checks-for-7389-port.patch b/SOURCES/0056-ipa-replica-install-never-checks-for-7389-port.patch deleted file mode 100644 index e00e968..0000000 --- a/SOURCES/0056-ipa-replica-install-never-checks-for-7389-port.patch +++ /dev/null @@ -1,220 +0,0 @@ -From c088cccb0b27e0defd5457f756a2d4c68e8eff55 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Tue, 11 Mar 2014 16:28:19 +0100 -Subject: [PATCH 56/58] ipa-replica-install never checks for 7389 port - -When creating replica from a Dogtag 9 based IPA server, the port 7389 -which is required for the installation is never checked by -ipa-replica-conncheck even though it knows that it is being installed -from the Dogtag 9 based FreeIPA. If the 7389 port would be blocked by -firewall, installation would stuck with no hint to user. - -Make sure that the port configuration parsed from replica info file -is used consistently in the installers. - -https://fedorahosted.org/freeipa/ticket/4240 - -Reviewed-By: Petr Viktorin ---- - install/tools/ipa-ca-install | 17 +++++------------ - install/tools/ipa-replica-install | 18 ++++++------------ - ipaserver/install/cainstance.py | 12 +++++------- - ipaserver/install/installutils.py | 16 ++++++++++++++++ - 4 files changed, 32 insertions(+), 31 deletions(-) - -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index 4edd26d337a50eebe686daae539c257f706e0158..bb3e595a3df47f00b3929f546db7b04dd7eda32a 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -30,7 +30,7 @@ from ipaserver.install import installutils, service - from ipaserver.install import certs - from ipaserver.install.installutils import (HostnameLocalhost, ReplicaConfig, - expand_replica_info, read_replica_info, get_host_name, BadHostError, -- private_ccache) -+ private_ccache, read_replica_info_dogtag_port) - from ipaserver.install import dsinstance, cainstance, bindinstance - from ipaserver.install.replication import replica_conn_check - from ipapython import version -@@ -159,31 +159,24 @@ def main(): - sys.exit(0) - config.dir = dir - config.setup_ca = True -+ config.ca_ds_port = read_replica_info_dogtag_port(config.dir) - - if not ipautil.file_exists(config.dir + "/cacert.p12"): - print 'CA cannot be installed in CA-less setup.' - sys.exit(1) - -- portfile = config.dir + "/dogtag_directory_port.txt" -- if not ipautil.file_exists(portfile): -- dogtag_master_ds_port = str(dogtag.Dogtag9Constants.DS_PORT) -- else: -- with open(portfile) as fd: -- dogtag_master_ds_port = fd.read() -- - if not options.skip_conncheck: - replica_conn_check( - config.master_host_name, config.host_name, config.realm_name, True, -- dogtag_master_ds_port, options.admin_password) -+ config.ca_ds_port, options.admin_password) - - if options.skip_schema_check: - root_logger.info("Skipping CA DS schema check") - else: -- cainstance.replica_ca_install_check(config, dogtag_master_ds_port) -+ cainstance.replica_ca_install_check(config) - - # Configure the CA if necessary -- CA = cainstance.install_replica_ca( -- config, dogtag_master_ds_port, postinstall=True) -+ CA = cainstance.install_replica_ca(config, postinstall=True) - - # We need to ldap_enable the CA now that DS is up and running - CA.ldap_enable('CA', config.host_name, config.dirman_password, -diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install -index 0e7aefef48d47fefa290607e0604c014d9469fdd..e039fd1e7cb213b3269d0a5d2305a96f68e36e29 100755 ---- a/install/tools/ipa-replica-install -+++ b/install/tools/ipa-replica-install -@@ -37,8 +37,8 @@ from ipaserver.install import memcacheinstance - from ipaserver.install import otpdinstance - from ipaserver.install.replication import replica_conn_check, ReplicationManager - from ipaserver.install.installutils import (ReplicaConfig, expand_replica_info, -- read_replica_info ,get_host_name, -- BadHostError, private_ccache) -+ read_replica_info, get_host_name, BadHostError, private_ccache, -+ read_replica_info_dogtag_port) - from ipaserver.plugins.ldap2 import ldap2 - from ipaserver.install import cainstance - from ipalib import api, errors, util -@@ -534,6 +534,7 @@ def main(): - sys.exit(0) - config.dir = dir - config.setup_ca = options.setup_ca -+ config.ca_ds_port = read_replica_info_dogtag_port(config.dir) - - if config.setup_ca and not ipautil.file_exists(config.dir + "/cacert.p12"): - print 'CA cannot be installed in CA-less setup.' -@@ -541,18 +542,11 @@ def main(): - - installutils.verify_fqdn(config.master_host_name, options.no_host_dns) - -- portfile = config.dir + "/dogtag_directory_port.txt" -- if not ipautil.file_exists(portfile): -- dogtag_master_ds_port = str(dogtag.Dogtag9Constants.DS_PORT) -- else: -- with open(portfile) as fd: -- dogtag_master_ds_port = fd.read() -- - # check connection - if not options.skip_conncheck: - replica_conn_check( - config.master_host_name, config.host_name, config.realm_name, -- options.setup_ca, dogtag_master_ds_port, options.admin_password) -+ options.setup_ca, config.ca_ds_port, options.admin_password) - - - # check replica host IP resolution -@@ -657,7 +651,7 @@ def main(): - if options.skip_schema_check: - root_logger.info("Skipping CA DS schema check") - else: -- cainstance.replica_ca_install_check(config, dogtag_master_ds_port) -+ cainstance.replica_ca_install_check(config) - - # Configure ntpd - if options.conf_ntp: -@@ -669,7 +663,7 @@ def main(): - ds = install_replica_ds(config) - - # Configure the CA if necessary -- CA = cainstance.install_replica_ca(config, dogtag_master_ds_port) -+ CA = cainstance.install_replica_ca(config) - - # Always try to install DNS records - install_dns_records(config, options) -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 52c91b68c2d073a9b1c6aedc1811aa26db046e6b..126bbae66e8a9ae8d9cc6e624745ab1cc37bf4c1 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1574,7 +1574,7 @@ def is_master(self): - return master == 'New' - - --def replica_ca_install_check(config, master_ds_port): -+def replica_ca_install_check(config): - if not config.setup_ca: - return - -@@ -1583,8 +1583,6 @@ def replica_ca_install_check(config, master_ds_port): - # Replica of old "self-signed" master - CA won't be installed - return - -- master_ds_port = int(master_ds_port) -- - # Exit if we have an old-style (Dogtag 9) CA already installed - ca = CAInstance(config.realm_name, certs.NSS_DIR, - dogtag_constants=dogtag.Dogtag9Constants) -@@ -1592,13 +1590,13 @@ def replica_ca_install_check(config, master_ds_port): - root_logger.info('Dogtag 9 style CA instance found') - sys.exit("A CA is already configured on this system.") - -- if master_ds_port != dogtag.Dogtag9Constants.DS_PORT: -+ if config.ca_ds_port != dogtag.Dogtag9Constants.DS_PORT: - root_logger.debug( - 'Installing CA Replica from master with a merged database') - return - - # Check if the master has the necessary schema in its CA instance -- ca_ldap_url = 'ldap://%s:%s' % (config.master_host_name, master_ds_port) -+ ca_ldap_url = 'ldap://%s:%s' % (config.master_host_name, config.ca_ds_port) - objectclass = 'ipaObject' - root_logger.debug('Checking if IPA schema is present in %s', ca_ldap_url) - try: -@@ -1627,7 +1625,7 @@ def replica_ca_install_check(config, master_ds_port): - exit('IPA schema missing on master CA directory server') - - --def install_replica_ca(config, master_ds_port, postinstall=False): -+def install_replica_ca(config, postinstall=False): - """ - Install a CA on a replica. - -@@ -1676,7 +1674,7 @@ def install_replica_ca(config, master_ds_port, postinstall=False): - config.dirman_password, config.dirman_password, - pkcs12_info=(cafile,), - master_host=config.master_host_name, -- master_replication_port=master_ds_port, -+ master_replication_port=config.ca_ds_port, - subject_base=config.subject_base) - - # Restart httpd since we changed it's config and added ipa-pki-proxy.conf -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 32671adc895b0cb2632729e8bdb44b5df02c1314..8be8cd3ffa86256c096ddc99227210f2daeb3185 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -538,6 +538,22 @@ def read_replica_info(dir, rconfig): - except NoOptionError: - pass - -+def read_replica_info_dogtag_port(config_dir): -+ portfile = config_dir + "/dogtag_directory_port.txt" -+ default_port = dogtag.Dogtag9Constants.DS_PORT -+ if not ipautil.file_exists(portfile): -+ dogtag_master_ds_port = default_port -+ else: -+ with open(portfile) as fd: -+ try: -+ dogtag_master_ds_port = int(fd.read()) -+ except (ValueError, IOError), e: -+ root_logger.debug('Cannot parse dogtag DS port: %s', e) -+ root_logger.debug('Default to %d', default_port) -+ dogtag_master_ds_port = default_port -+ -+ return dogtag_master_ds_port -+ - def check_server_configuration(): - """ - Check if IPA server is configured on the system. --- -1.8.5.3 - diff --git a/SOURCES/0057-Avoid-passing-non-terminated-string-to-is_master_hos.patch b/SOURCES/0057-Avoid-passing-non-terminated-string-to-is_master_hos.patch deleted file mode 100644 index 006eb6a..0000000 --- a/SOURCES/0057-Avoid-passing-non-terminated-string-to-is_master_hos.patch +++ /dev/null @@ -1,40 +0,0 @@ -From a8fde83022360a02e53b70fd7bd4d61de1ccc7cb Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Fri, 7 Mar 2014 10:06:52 +0100 -Subject: [PATCH 57/58] Avoid passing non-terminated string to is_master_host - -When string is not terminated, queries with corrupted base may be sent -to LDAP: - -... cn=ipa1.example.com,cn=masters... - -https://fedorahosted.org/freeipa/ticket/4214 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 8481278760aba2d5dec5c337813f394633d67e46..a73a3cb46e104b43493177e333deb2b0d6226c2a 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -488,13 +488,14 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx, - } - - data = krb5_princ_component(ipactx->context, princ, 1); -- strres = malloc(data->length); -+ strres = malloc(data->length+1); - if (strres == NULL) { - krb5_free_principal(ipactx->kcontext, princ); - return ENOENT; - } - - memcpy(strres, data->data, data->length); -+ strres[data->length] = '\0'; - krb5_free_principal(ipactx->kcontext, princ); - - /* Only add PAC to TGT to services on IPA masters to allow querying --- -1.8.5.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 new file mode 100644 index 0000000..7cff879 --- /dev/null +++ b/SOURCES/0057-Fix-unchecked-return-value-in-ipa-kdb.patch @@ -0,0 +1,28 @@ +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/0058-Fix-unchecked-return-values-in-ipa-winsync.patch b/SOURCES/0058-Fix-unchecked-return-values-in-ipa-winsync.patch new file mode 100644 index 0000000..f333fd8 --- /dev/null +++ b/SOURCES/0058-Fix-unchecked-return-values-in-ipa-winsync.patch @@ -0,0 +1,108 @@ +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-ipa-sam-cache-gid-to-sid-and-uid-to-sid-requests-in-.patch b/SOURCES/0058-ipa-sam-cache-gid-to-sid-and-uid-to-sid-requests-in-.patch deleted file mode 100644 index cd202e4..0000000 --- a/SOURCES/0058-ipa-sam-cache-gid-to-sid-and-uid-to-sid-requests-in-.patch +++ /dev/null @@ -1,303 +0,0 @@ -From e5bd495a9a7d71f5dde5661d960e372bb2609965 Mon Sep 17 00:00:00 2001 -From: Jason Woods -Date: Fri, 7 Mar 2014 16:38:24 +0000 -Subject: [PATCH 58/58] ipa-sam: cache gid to sid and uid to sid requests in - idmap cache - -Add idmap_cache calls to ipa-sam to prevent huge numbers of LDAP calls to the -directory service for gid/uid<->sid resolution. - -Additionally, this patch further reduces number of queries by: - - fast fail on uidNumber=0 which doesn't exist in FreeIPA, - - return fallback group correctly when looking up user primary group as is - done during init, - - checking for group objectclass in case insensitive way - -Patch by Jason Woods - -Reviewed-by: Alexander Bokovoy - -https://fedorahosted.org/freeipa/ticket/4234 -and -https://bugzilla.redhat.com/show_bug.cgi?id=1073829 -https://bugzilla.redhat.com/show_bug.cgi?id=1074314 - -Reviewed-By: Sumit Bose ---- - daemons/ipa-sam/ipa_sam.c | 128 +++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 114 insertions(+), 14 deletions(-) - -diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c -index 1ca504db4e442c834ebe44d7e3503abafd6f9602..3b69f9e8255490aac17d08033e2a3584c6bf9e24 100644 ---- a/daemons/ipa-sam/ipa_sam.c -+++ b/daemons/ipa-sam/ipa_sam.c -@@ -82,6 +82,18 @@ struct trustAuthInOutBlob { - struct AuthenticationInformationArray previous;/* [subcontext(0),flag(LIBNDR_FLAG_REMAINING)] */ - }/* [gensize,public,nopush] */; - -+/* from generated idmap.h - hopefully OK */ -+enum id_type { -+ ID_TYPE_NOT_SPECIFIED, -+ ID_TYPE_UID, -+ ID_TYPE_GID, -+ ID_TYPE_BOTH -+}; -+ -+struct unixid { -+ uint32_t id; -+ enum id_type type; -+}/* [public] */; - - enum ndr_err_code ndr_pull_trustAuthInOutBlob(struct ndr_pull *ndr, int ndr_flags, struct trustAuthInOutBlob *r); /*available in libndr-samba.so */ - bool sid_check_is_builtin(const struct dom_sid *sid); /* available in libpdb.so */ -@@ -91,6 +103,7 @@ char *sid_string_talloc(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); /* avai - char *sid_string_dbg(const struct dom_sid *sid); /* available in libsmbconf.so */ - char *escape_ldap_string(TALLOC_CTX *mem_ctx, const char *s); /* available in libsmbconf.so */ - bool secrets_store(const char *key, const void *data, size_t size); /* available in libpdb.so */ -+void idmap_cache_set_sid2unixid(const struct dom_sid *sid, struct unixid *unix_id); /* available in libsmbconf.so */ - - #define LDAP_PAGE_SIZE 1024 - #define LDAP_OBJ_SAMBASAMACCOUNT "ipaNTUserAttrs" -@@ -750,8 +763,8 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods, - } - - for (c = 0; values[c] != NULL; c++) { -- if (strncmp(LDAP_OBJ_GROUPMAP, values[c]->bv_val, -- values[c]->bv_len) == 0) { -+ if (strncasecmp(LDAP_OBJ_GROUPMAP, values[c]->bv_val, -+ values[c]->bv_len) == 0) { - break; - } - } -@@ -769,6 +782,9 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods, - } - - unixid_from_gid(id, strtoul(gid_str, NULL, 10)); -+ -+ idmap_cache_set_sid2unixid(sid, id); -+ - ret = true; - goto done; - } -@@ -785,8 +801,11 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods, - - unixid_from_uid(id, strtoul(value, NULL, 10)); - -+ idmap_cache_set_sid2unixid(sid, id); -+ - ret = true; - done: -+ - TALLOC_FREE(mem_ctx); - return ret; - } -@@ -806,6 +825,18 @@ static bool ldapsam_uid_to_sid(struct pdb_methods *methods, uid_t uid, - int rc; - enum idmap_error_code err; - TALLOC_CTX *tmp_ctx = talloc_stackframe(); -+ struct unixid id; -+ -+ /* Fast fail if we get a request for uidNumber=0 because it currently -+ * will never exist in the directory -+ * Saves an expensive LDAP call of which failure will never be cached -+ */ -+ if (uid == 0) { -+ DEBUG(3, ("ERROR: Received request for uid %u, " -+ "fast failing as it will never exist\n", -+ (unsigned int)uid)); -+ goto done; -+ } - - filter = talloc_asprintf(tmp_ctx, - "(&(uidNumber=%u)" -@@ -852,6 +883,10 @@ static bool ldapsam_uid_to_sid(struct pdb_methods *methods, uid_t uid, - - sid_copy(sid, user_sid); - -+ unixid_from_uid(&id, uid); -+ -+ idmap_cache_set_sid2unixid(sid, &id); -+ - ret = true; - - done: -@@ -866,21 +901,30 @@ static bool ldapsam_gid_to_sid(struct pdb_methods *methods, gid_t gid, - struct ldapsam_privates *priv = - (struct ldapsam_privates *)methods->private_data; - char *filter; -- const char *attrs[] = { LDAP_ATTRIBUTE_SID, NULL }; -+ const char *attrs[] = { LDAP_ATTRIBUTE_SID, LDAP_ATTRIBUTE_OBJECTCLASS, NULL }; - LDAPMessage *result = NULL; - LDAPMessage *entry = NULL; - bool ret = false; -- char *group_sid_string; -+ char *group_sid_string = NULL; - struct dom_sid *group_sid = NULL; -+ struct berval **values; -+ size_t c; - int rc; - enum idmap_error_code err; - TALLOC_CTX *tmp_ctx = talloc_stackframe(); -+ struct unixid id; - - filter = talloc_asprintf(tmp_ctx, -- "(&(gidNumber=%u)" -- "(objectClass=%s))", -+ "(|(&(gidNumber=%u)" -+ "(objectClass=%s))" -+ "(&(uidNumber=%u)" -+ "(objectClass=%s)" -+ "(objectClass=%s)))", - (unsigned int)gid, -- LDAP_OBJ_GROUPMAP); -+ LDAP_OBJ_GROUPMAP, -+ (unsigned int)gid, -+ LDAP_OBJ_POSIXACCOUNT, -+ LDAP_OBJ_SAMBASAMACCOUNT); - if (filter == NULL) { - DEBUG(3, ("talloc_asprintf failed\n")); - goto done; -@@ -892,14 +936,46 @@ static bool ldapsam_gid_to_sid(struct pdb_methods *methods, gid_t gid, - } - smbldap_talloc_autofree_ldapmsg(tmp_ctx, result); - -- if (ldap_count_entries(priv2ld(priv), result) != 1) { -- DEBUG(3, ("ERROR: Got %d entries for gid %u, expected one\n", -+ if (ldap_count_entries(priv2ld(priv), result) == 0) { -+ DEBUG(3, ("ERROR: Got %d entries for gid %u, expected at least one\n", - ldap_count_entries(priv2ld(priv), result), - (unsigned int)gid)); - goto done; - } - -- entry = ldap_first_entry(priv2ld(priv), result); -+ for (entry = ldap_first_entry(priv2ld(priv), result); -+ entry != NULL; -+ entry = ldap_next_entry(priv2ld(priv), entry)) { -+ -+ values = ldap_get_values_len(priv2ld(priv), entry, "objectClass"); -+ if (values == NULL) { -+ DEBUG(10, ("Cannot find any objectclasses.\n")); -+ goto done; -+ } -+ -+ for (c = 0; values[c] != NULL; c++) { -+ if (strncasecmp(LDAP_OBJ_GROUPMAP, values[c]->bv_val, -+ values[c]->bv_len) == 0) { -+ goto found; -+ } -+ } -+ -+ } -+ -+found: -+ /* If we didn't find a group we found a user - so this is a primary group -+ * For user private group, use fallback group */ -+ if (entry == NULL) { -+ -+ DEBUG(10, ("Did not find user private group %u, " -+ "returning fallback group.\n", (unsigned int)gid)); -+ -+ sid_copy(sid, -+ &priv->ipasam_privates->fallback_primary_group); -+ ret = true; -+ goto done; -+ -+ } - - group_sid_string = get_single_attribute(tmp_ctx, priv2ld(priv), entry, - LDAP_ATTRIBUTE_SID); -@@ -910,7 +986,7 @@ static bool ldapsam_gid_to_sid(struct pdb_methods *methods, gid_t gid, - } - - err = sss_idmap_sid_to_smb_sid(priv->ipasam_privates->idmap_ctx, -- group_sid_string, &group_sid); -+ group_sid_string, &group_sid); - if (err != IDMAP_SUCCESS) { - DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n", - group_sid_string)); -@@ -919,6 +995,10 @@ static bool ldapsam_gid_to_sid(struct pdb_methods *methods, gid_t gid, - - sid_copy(sid, group_sid); - -+ unixid_from_gid(&id, gid); -+ -+ idmap_cache_set_sid2unixid(sid, &id); -+ - ret = true; - - done: -@@ -2456,10 +2536,16 @@ static int delete_subtree(struct ldapsam_privates *ldap_state, char* dn) - rc = smbldap_search(ldap_state->smbldap_state, dn, scope, filter, NULL, 0, &result); - TALLOC_FREE(filter); - -- if (result != NULL) { -- smbldap_talloc_autofree_ldapmsg(dn, result); -+ if (rc != LDAP_SUCCESS) { -+ return rc; - } - -+ if (result == NULL) { -+ return LDAP_NO_MEMORY; -+ } -+ -+ smbldap_talloc_autofree_ldapmsg(dn, result); -+ - for (entry = ldap_first_entry(state, result); - entry != NULL; - entry = ldap_next_entry(state, entry)) { -@@ -2467,6 +2553,9 @@ static int delete_subtree(struct ldapsam_privates *ldap_state, char* dn) - /* remove child entries */ - if ((entry_dn != NULL) && (strcmp(entry_dn, dn) != 0)) { - rc = smbldap_delete(ldap_state->smbldap_state, entry_dn); -+ if (rc != LDAP_SUCCESS) { -+ return rc; -+ } - } - } - rc = smbldap_delete(ldap_state->smbldap_state, dn); -@@ -2856,6 +2945,7 @@ static int ipasam_get_sid_by_gid(struct ldapsam_privates *ldap_state, - struct dom_sid *sid = NULL; - int count; - enum idmap_error_code err; -+ struct unixid id; - - tmp_ctx = talloc_new("ipasam_get_sid_by_gid"); - if (tmp_ctx == NULL) { -@@ -2910,6 +3000,10 @@ static int ipasam_get_sid_by_gid(struct ldapsam_privates *ldap_state, - } - sid_copy(_sid, sid); - -+ unixid_from_gid(&id, gid); -+ -+ idmap_cache_set_sid2unixid(sid, &id); -+ - ret = 0; - - done: -@@ -2929,6 +3023,7 @@ static int ipasam_get_primary_group_sid(TALLOC_CTX *mem_ctx, - uint32_t uid; - uint32_t gid; - struct dom_sid *group_sid; -+ struct unixid id; - - TALLOC_CTX *tmp_ctx = talloc_init("ipasam_get_primary_group_sid"); - if (tmp_ctx == NULL) { -@@ -2967,8 +3062,13 @@ static int ipasam_get_primary_group_sid(TALLOC_CTX *mem_ctx, - } - } - -- ret = 0; -+ unixid_from_gid(&id, gid); -+ -+ idmap_cache_set_sid2unixid(group_sid, &id); -+ -+ ret = 0; - done: -+ - if (ret == 0) { - *_group_sid = talloc_steal(mem_ctx, group_sid); - } --- -1.8.5.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 new file mode 100644 index 0000000..f78a191 --- /dev/null +++ b/SOURCES/0059-Fix-unchecked-return-value-in-ipa-join.patch @@ -0,0 +1,32 @@ +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-ipaserver-dcerpc-make-sure-to-always-return-unicode-.patch b/SOURCES/0059-ipaserver-dcerpc-make-sure-to-always-return-unicode-.patch deleted file mode 100644 index 0289984..0000000 --- a/SOURCES/0059-ipaserver-dcerpc-make-sure-to-always-return-unicode-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 1a5cf5b28ca3143c72abaa85db59cf827d25a379 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 12 Mar 2014 17:51:43 +0200 -Subject: [PATCH 59/60] ipaserver/dcerpc: make sure to always return unicode - SID of the trust domain - -Trusted domain SID could be obtained through different means. When it is -fetched from the AD DC via LDAP, it needs to be extracted from a default -context and explicitly converted to unicode. - -https://fedorahosted.org/freeipa/ticket/4246 - -Reviewed-By: Martin Kosek ---- - ipaserver/dcerpc.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 5972e622292a033d4fc979cbf5401fa02151f35c..f1c75089b875787debcee22316a4898b424d923f 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -750,7 +750,7 @@ def retrieve_anonymously(self, remote_host, discover_srv=False): - - def parse_naming_context(self, context): - naming_ref = re.compile('.*.*') -- return naming_ref.match(context).group(1) -+ return unicode(naming_ref.match(context).group(1)) - - def retrieve(self, remote_host): - self.init_lsa_pipe(remote_host) --- -1.8.5.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 new file mode 100644 index 0000000..2a04221 --- /dev/null +++ b/SOURCES/0060-Fix-unchecked-return-value-in-krb5-common-utils.patch @@ -0,0 +1,30 @@ +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-trust-do-not-fetch-subdomains-in-case-shared-secret-.patch b/SOURCES/0060-trust-do-not-fetch-subdomains-in-case-shared-secret-.patch deleted file mode 100644 index f2d8e65..0000000 --- a/SOURCES/0060-trust-do-not-fetch-subdomains-in-case-shared-secret-.patch +++ /dev/null @@ -1,44 +0,0 @@ -From f06e746602f34a1c60580fe3bbb105a8a1cab8a2 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Wed, 12 Mar 2014 19:01:00 +0200 -Subject: [PATCH 60/60] trust: do not fetch subdomains in case shared secret - was used to set up the trust - -Until incoming trust is validated from AD side, we cannot run any operations -against AD using the trust. Also, Samba currently does not suport verifying -trust against the other party (returns WERR_NOT_SUPPORTED). - -This needs to be added to the documentation: - - When using 'ipa trust-add ad.domain --trust-secret', one has to manually - validate incoming trust using forest trust properties in AD Domains and - Trusts tool. - - Once incoming trust is validated at AD side, use IPA command - 'ipa trust-fetch-domains ad.domain' to retrieve topology of the AD forest. - From this point on the trust should be usable. - -https://fedorahosted.org/freeipa/ticket/4246 - -Reviewed-By: Martin Kosek ---- - ipalib/plugins/trust.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py -index f2b00a6f58f5890e37aaa033a35dcf9bc39ccbc4..fe2795cad86e173a150f35db6301119930463a10 100644 ---- a/ipalib/plugins/trust.py -+++ b/ipalib/plugins/trust.py -@@ -462,7 +462,8 @@ def execute(self, *keys, **options): - # for AD trusts, regardless of the type of idranges associated with it - # Note that fetch_domains_from_trust will add needed ranges for - # the algorithmic ID mapping case. -- if options.get('trust_type') == u'ad': -+ if (options.get('trust_type') == u'ad' and -+ options.get('trust_secret') is None): - domains = fetch_domains_from_trust(self, self.trustinstance, - result['result'], **options) - --- -1.8.5.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 new file mode 100644 index 0000000..79d12ca --- /dev/null +++ b/SOURCES/0061-Fix-memory-leak-in-GetKeytabControl-asn1-code.patch @@ -0,0 +1,52 @@ +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/0061-Update-Dogtag-9-database-during-replica-installation.patch b/SOURCES/0061-Update-Dogtag-9-database-during-replica-installation.patch deleted file mode 100644 index fc97678..0000000 --- a/SOURCES/0061-Update-Dogtag-9-database-during-replica-installation.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 2e031c9469f0313014dbe8c47d0be3fee370f287 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Thu, 13 Mar 2014 08:25:11 +0100 -Subject: [PATCH] Update Dogtag 9 database during replica installation - -When Dogtag 10 based FreeIPA replica is being installed for a Dogtag 9 -based master, the PKI database is not updated and miss several ACLs -which prevent some of the PKI functions, e.g. an ability to create -other clones. - -Add an update file to do the database update. Content is based on -recommendation from PKI team: - * https://bugzilla.redhat.com/show_bug.cgi?id=1075118#c9 - -This update file can be removed when Dogtag database upgrades are done -in PKI component. Upstream tickets: - * https://fedorahosted.org/pki/ticket/710 (database upgrade framework) - * https://fedorahosted.org/pki/ticket/906 (checking database version) - -Also make sure that PKI service is restarted in the end of the installation -as the other services to make sure it picks changes done during LDAP -updates. - -https://fedorahosted.org/freeipa/ticket/4243 ---- - install/tools/ipa-replica-install | 4 ++++ - install/tools/ipa-server-install | 4 ++++ - install/updates/50-dogtag10-migration.update | 18 ++++++++++++++++++ - install/updates/Makefile.am | 1 + - 4 files changed, 27 insertions(+) - create mode 100644 install/updates/50-dogtag10-migration.update - -diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install -index e039fd1e7cb213b3269d0a5d2305a96f68e36e29..4418b41784313121e73b560ee84715ddeba8bc54 100755 ---- a/install/tools/ipa-replica-install -+++ b/install/tools/ipa-replica-install -@@ -704,6 +704,10 @@ def main(): - service.print_msg("Restarting the KDC") - krb.restart() - -+ if CA and config.setup_ca: -+ service.print_msg("Restarting the certificate server") -+ CA.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) -+ - if options.setup_dns: - install_bind(config, options) - -diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index 458ebba550d0fe7675bd874e23c7d730c53297e6..dfbbb91bf3bb8461333193b5a3e72c3ec06d4582 100755 ---- a/install/tools/ipa-server-install -+++ b/install/tools/ipa-server-install -@@ -1186,6 +1186,10 @@ def main(): - service.print_msg("Restarting the KDC") - krb.restart() - -+ if setup_ca: -+ service.print_msg("Restarting the certificate server") -+ ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) -+ - # Create a BIND instance - bind = bindinstance.BindInstance(fstore, dm_password) - bind.setup(host_name, ip_address, realm_name, domain_name, dns_forwarders, -diff --git a/install/updates/50-dogtag10-migration.update b/install/updates/50-dogtag10-migration.update -new file mode 100644 -index 0000000000000000000000000000000000000000..d718923544f0cb00f61b7b56940695e3891c4780 ---- /dev/null -+++ b/install/updates/50-dogtag10-migration.update -@@ -0,0 +1,18 @@ -+# PKI/Dogtag does not automatically upgrade it's database. When Dogtag 10 -+# based replica is being installed from a Dogtag 9 based replica, -+# the database will miss ACLs added in Dogtag 10 resulting in limited -+# functionality. -+# -+# This update file can be removed when Dogtag database upgrades are done -+# in PKI component. Upstream tickets: -+# * https://fedorahosted.org/pki/ticket/710 (database upgrade framework) -+# * https://fedorahosted.org/pki/ticket/906 (checking database version) -+ -+dn: cn=aclResources,o=ipaca -+addifexist:resourceACLS:'certServer.ca.account:login,logout:allow (login,logout) user="anybody":Anybody can login and logout' -+addifexist:resourceACLS:'certServer.ca.certrequests:execute:allow (execute) group="Certificate Manager Agents":Agents may execute cert request operations' -+addifexist:resourceACLS:'certServer.ca.certs:execute:allow (execute) group="Certificate Manager Agents":Agents may execute cert operations' -+addifexist:resourceACLS:'certServer.ca.groups:execute:allow (execute) group="Administrators":Admins may execute group operations' -+addifexist:resourceACLS:'certServer.ca.users:execute:allow (execute) group="Administrators":Admins may execute user operations' -+replace:resourceACLS:'certServer.securitydomain.domainxml:read,modify:allow (read) user="anybody";allow (modify) group="Subsystem Group":Anybody is allowed to read domain.xml but only Subsystem group is allowed to modify the domain.xml::certServer.securitydomain.domainxml:read,modify:allow (read) user="anybody";allow (modify) group="Subsystem Group" || group="Enterprise CA Administrators" || group="Enterprise KRA Administrators" || group="Enterprise RA Administrators" || group="Enterprise OCSP Administrators" || group="Enterprise TKS Administrators" || group="Enterprise TPS Administrators":Anybody is allowed to read domain.xml but only Subsystem group and Enterprise Administrators are allowed to modify the domain.xml' -+replace:resourceACLS:'certServer.ca.connectorInfo:read,modify:allow (modify,read) group="Enterprise KRA Administrators":Only Enterprise Administrators are allowed to update the connector information::certServer.ca.connectorInfo:read,modify:allow (read) group="Enterprise KRA Administrators";allow (modify) group="Enterprise KRA Administrators" || group="Subsystem Group":Only Enterprise Administrators and Subsystem Group are allowed to update the connector information' -diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am -index 40c3b3c8916faa267254a29d0f458ca53201950c..fb73c410dbcd1978c3a5deeb184dc10cdba866ae 100644 ---- a/install/updates/Makefile.am -+++ b/install/updates/Makefile.am -@@ -36,6 +36,7 @@ app_DATA = \ - 40-otp.update \ - 45-roles.update \ - 50-7_bit_check.update \ -+ 50-dogtag10-migration.update \ - 50-lockout-policy.update \ - 50-groupuuid.update \ - 50-hbacservice.update \ --- -1.8.5.3 - diff --git a/SOURCES/0062-AD-trust-improve-trust-validation.patch b/SOURCES/0062-AD-trust-improve-trust-validation.patch new file mode 100644 index 0000000..2bd259d --- /dev/null +++ b/SOURCES/0062-AD-trust-improve-trust-validation.patch @@ -0,0 +1,75 @@ +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-Prohibit-deletion-of-active-subdomain-range.patch b/SOURCES/0062-Prohibit-deletion-of-active-subdomain-range.patch deleted file mode 100644 index 3820074..0000000 --- a/SOURCES/0062-Prohibit-deletion-of-active-subdomain-range.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 35916294df8acc87e70c6b6796c644824caed64a Mon Sep 17 00:00:00 2001 -From: Tomas Babej -Date: Thu, 13 Mar 2014 12:36:17 +0100 -Subject: [PATCH] Prohibit deletion of active subdomain range - -Changes the code in the idrange_del method to not only check for -the root domains that match the SID in the IDRange, but for the -SIDs of subdomains of trusts as well. - -https://fedorahosted.org/freeipa/ticket/4247 - -Reviewed-By: Alexander Bokovoy ---- - ipalib/plugins/idrange.py | 20 ++++++++++++++++---- - 1 file changed, 16 insertions(+), 4 deletions(-) - -diff --git a/ipalib/plugins/idrange.py b/ipalib/plugins/idrange.py -index cf74a75ffda42b2d2e40d2ab35c79ed069dd0f52..56ef4bba3ad0203d7d2462db6c4de90e1cb555cd 100644 ---- a/ipalib/plugins/idrange.py -+++ b/ipalib/plugins/idrange.py -@@ -567,14 +567,26 @@ class idrange_del(LDAPDelete): - range_sid = old_attrs.get('ipanttrusteddomainsid') - - if range_sid is not None: -+ # Search for trusted domain with SID specified in the ID range entry - range_sid = range_sid[0] -- result = api.Command['trust_find'](ipanttrusteddomainsid=range_sid) -+ domain_filter=('(&(objectclass=ipaNTTrustedDomain)' -+ '(ipanttrusteddomainsid=%s))' % range_sid) - -- if result['count'] > 0: -+ try: -+ (trust_domains, truncated) = ldap.find_entries( -+ base_dn=DN(api.env.container_trusts, api.env.basedn), -+ filter=domain_filter) -+ except errors.NotFound: -+ pass -+ else: -+ # If there's an entry, it means that there's active domain -+ # of a trust that this range belongs to, so raise a -+ # DependentEntry error - raise errors.DependentEntry( -- label='Active Trust', -+ label='Active Trust domain', - key=keys[0], -- dependent=result['result'][0]['cn'][0]) -+ dependent=trust_domains[0].dn[0].value) -+ - - return dn - --- -1.8.5.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 new file mode 100644 index 0000000..647bde3 --- /dev/null +++ b/SOURCES/0063-Add-TLS-1.2-to-the-protocol-list-in-mod_nss-config.patch @@ -0,0 +1,72 @@ +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-extdom-do-not-return-results-from-the-wrong-domain.patch b/SOURCES/0063-extdom-do-not-return-results-from-the-wrong-domain.patch deleted file mode 100644 index fdaa145..0000000 --- a/SOURCES/0063-extdom-do-not-return-results-from-the-wrong-domain.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 8d8cbc740af171a24e768fd6e4af17013d1fa261 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 25 Mar 2014 11:29:58 +0100 -Subject: [PATCH] extdom: do not return results from the wrong domain - -Resolves: https://fedorahosted.org/freeipa/ticket/4264 -Reviewed-By: Tomas Babej ---- - .../ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -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 675fc368042373314e9416dcf7d5866cb8c9871e..025d37dc5eda05c8db43d4e8176fd7898ed32fe7 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 -@@ -359,6 +359,9 @@ int create_response(struct extdom_req *req, struct pwd_grp *pg_data, - if ((locat = strchr(pg_data->data.pwd.pw_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { - if (strcasecmp(locat+1, domain_name) == 0 ) { - locat[0] = 0; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ goto done; - } - } - res->data.name.object_name = -@@ -368,6 +371,9 @@ int create_response(struct extdom_req *req, struct pwd_grp *pg_data, - if ((locat = strchr(pg_data->data.grp.gr_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { - if (strcasecmp(locat+1, domain_name) == 0) { - locat[0] = 0; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ goto done; - } - } - res->data.name.object_name = -@@ -408,6 +414,9 @@ int create_response(struct extdom_req *req, struct pwd_grp *pg_data, - if ((locat = strchr(pg_data->data.pwd.pw_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { - if (strcasecmp(locat+1, domain_name) == 0) { - locat[0] = 0; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ goto done; - } - } - res->data.user.user_name = -@@ -428,6 +437,9 @@ int create_response(struct extdom_req *req, struct pwd_grp *pg_data, - if ((locat = strchr(pg_data->data.grp.gr_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { - if (strcasecmp(locat+1, domain_name) == 0) { - locat[0] = 0; -+ } else { -+ ret = LDAP_NO_SUCH_OBJECT; -+ goto done; - } - } - res->data.group.group_name = --- -1.8.5.3 - diff --git a/SOURCES/0064-Proxy-PKI-clone-ca-ee-ca-profileSubmit-URI.patch b/SOURCES/0064-Proxy-PKI-clone-ca-ee-ca-profileSubmit-URI.patch deleted file mode 100644 index ab22fb9..0000000 --- a/SOURCES/0064-Proxy-PKI-clone-ca-ee-ca-profileSubmit-URI.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8e8a020f8d2476cca321349fa24db4bee95270d8 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Thu, 20 Mar 2014 09:34:53 +0100 -Subject: [PATCH] Proxy PKI clone /ca/ee/ca/profileSubmit URI - -PKI change done in ticket https://fedorahosted.org/pki/ticket/816 -requires the PKI Clone's SSL Server certificate to be issued by -it's associated PKI master. - -Allow this call on IPA master. - -https://fedorahosted.org/freeipa/ticket/4265 - -Reviewed-By: Jan Cholasta ---- - install/conf/ipa-pki-proxy.conf | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/install/conf/ipa-pki-proxy.conf b/install/conf/ipa-pki-proxy.conf -index 6f0463242b75a58cf63a38e62c23fa372aeacf64..224cdd45b5b5f72671a179570fd15772fe8cfaab 100644 ---- a/install/conf/ipa-pki-proxy.conf -+++ b/install/conf/ipa-pki-proxy.conf -@@ -1,9 +1,9 @@ --# VERSION 3 - DO NOT REMOVE THIS LINE -+# VERSION 4 - DO NOT REMOVE THIS LINE - - ProxyRequests Off - - # matches for ee port -- -+ - NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate - NSSVerifyClient none - ProxyPassMatch ajp://localhost:$DOGTAG_PORT --- -1.8.5.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 new file mode 100644 index 0000000..57e905c --- /dev/null +++ b/SOURCES/0064-webui-add-radius-fields-to-user-page.patch @@ -0,0 +1,39 @@ +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 new file mode 100644 index 0000000..e4698df --- /dev/null +++ b/SOURCES/0065-Fix-zonemgr-option-encoding-detection.patch @@ -0,0 +1,30 @@ +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-Make-ipa-client-automount-backwards-compatible.patch b/SOURCES/0065-Make-ipa-client-automount-backwards-compatible.patch deleted file mode 100644 index dd62f62..0000000 --- a/SOURCES/0065-Make-ipa-client-automount-backwards-compatible.patch +++ /dev/null @@ -1,39 +0,0 @@ -From cebfd91869bdc22fa8f72c4e47d32cac73487e45 Mon Sep 17 00:00:00 2001 -From: Martin Kosek -Date: Tue, 1 Apr 2014 16:23:14 +0200 -Subject: [PATCH] Make ipa-client-automount backwards compatible - -ipa-client-automount calls automountlocation-show command during the -process. Unfortunately, FreeIPA commands are forward compatible only -and thus fail the installer. - -Similarly to ipa-client-install, call XML-RPC interface directly -with version fixed to 2.0 (command was already available at that -version) to fix the failure. - -https://fedorahosted.org/freeipa/ticket/4290 ---- - ipa-client/ipa-install/ipa-client-automount | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/ipa-client/ipa-install/ipa-client-automount b/ipa-client/ipa-install/ipa-client-automount -index 62531bfe1d923b1705aed1187da6766b54c90a0c..77829b927e8c1772598d1a4e590c3f99977aa8eb 100755 ---- a/ipa-client/ipa-install/ipa-client-automount -+++ b/ipa-client/ipa-install/ipa-client-automount -@@ -440,7 +440,12 @@ def main(): - except errors.KerberosError, e: - sys.exit('Cannot connect to the server due to ' + str(e)) - try: -- api.Command['automountlocation_show'](unicode(options.location)) -+ # Use the RPC directly so older servers are supported -+ result = api.Backend.xmlclient.forward( -+ 'automountlocation_show', -+ unicode(options.location), -+ version=u'2.0', -+ ) - except errors.VersionError, e: - sys.exit('This client is incompatible: ' + str(e)) - except errors.NotFound: --- -1.8.5.3 - diff --git a/SOURCES/0066-Catch-USBError-during-YubiKey-location.patch b/SOURCES/0066-Catch-USBError-during-YubiKey-location.patch new file mode 100644 index 0000000..157f4c8 --- /dev/null +++ b/SOURCES/0066-Catch-USBError-during-YubiKey-location.patch @@ -0,0 +1,40 @@ +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-Convert-external-CA-chain-to-PKCS-7-before-passing-i.patch b/SOURCES/0066-Convert-external-CA-chain-to-PKCS-7-before-passing-i.patch deleted file mode 100644 index 09ecea3..0000000 --- a/SOURCES/0066-Convert-external-CA-chain-to-PKCS-7-before-passing-i.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 15c68b5ab6441a443f0a135da2b553ee1f9cbcf9 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Fri, 8 Aug 2014 10:15:26 +0200 -Subject: [PATCH] Convert external CA chain to PKCS#7 before passing it to - pkispawn. - -https://fedorahosted.org/freeipa/ticket/4397 ---- - install/tools/ipa-server-install | 6 +++--- - install/tools/man/ipa-server-install.1 | 10 +++++++--- - ipaserver/install/cainstance.py | 13 ++++++++++++- - 3 files changed, 22 insertions(+), 7 deletions(-) - -diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index dfbbb91bf3bb8461333193b5a3e72c3ec06d4582..feea616b089261bf46392d5514e6e3cc9e12fcac 100755 ---- a/install/tools/ipa-server-install -+++ b/install/tools/ipa-server-install -@@ -174,11 +174,11 @@ def parse_options(): - - cert_group = OptionGroup(parser, "certificate system options") - cert_group.add_option("", "--external-ca", dest="external_ca", action="store_true", -- default=False, help="Generate a CSR to be signed by an external CA") -+ default=False, help="Generate a CSR for the IPA CA certificate to be signed by an external CA") - cert_group.add_option("", "--external_cert_file", dest="external_cert_file", -- help="PEM file containing a certificate signed by the external CA") -+ help="File containing the IPA CA certificate signed by the external CA in PEM format") - cert_group.add_option("", "--external_ca_file", dest="external_ca_file", -- help="PEM file containing the external CA chain") -+ help="File containing the external CA certificate chain in PEM format") - cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", - default=True, help="disables pkinit setup steps") - cert_group.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12", -diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 -index 4adf1d037517bb211bd4c5e5e915380777e8f337..d713d2db4cb863dff77e451b22c5a9b1fbbfeecd 100644 ---- a/install/tools/man/ipa-server-install.1 -+++ b/install/tools/man/ipa-server-install.1 -@@ -85,13 +85,17 @@ An unattended installation that will never prompt for user input - .SS "CERTIFICATE SYSTEM OPTIONS" - .TP - \fB\-\-external\-ca\fR --Generate a CSR to be signed by an external CA -+Generate a CSR for the IPA CA certificate to be signed by an external CA. - .TP - \fB\-\-external_cert_file\fR=\fIFILE\fR --PEM file containing a certificate signed by the external CA. Must be given with \-\-external_ca_file. -+File containing the IPA CA certificate signed by the external CA in PEM format. Must be given with \-\-external_ca_file. - .TP - \fB\-\-external_ca_file\fR=\fIFILE\fR --PEM file containing the external CA chain -+File containing the external CA certificate chain in PEM format. Must be given with \-\-external_cert_file. -+ -+If the CA certificate chain is in PKCS#7 format you can convert it to PEM using: -+ -+ openssl pkcs7 -in PKCS7_FILE -print_certs -out PEM_FILE - .TP - \fB\-\-no\-pkinit\fR - Disables pkinit setup steps -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 126bbae66e8a9ae8d9cc6e624745ab1cc37bf4c1..233fa5d95fb7068b22a1c3daaed89176ff14a380 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -578,9 +578,20 @@ def __spawn_instance(self): - config.set("CA", "pki_external_csr_path", self.csr_file) - - elif self.external == 2: -+ cert_chain, stderr, rc = ipautil.run( -+ ['/usr/bin/openssl', 'crl2pkcs7', -+ '-certfile', self.cert_chain_file, -+ '-nocrl']) -+ # Dogtag chokes on the header and footer, remove them -+ # https://bugzilla.redhat.com/show_bug.cgi?id=1127838 -+ cert_chain = re.search( -+ r'(?<=-----BEGIN PKCS7-----).*?(?=-----END PKCS7-----)', -+ cert_chain, re.DOTALL).group(0) -+ cert_chain_file = ipautil.write_tmp_file(cert_chain) -+ - config.set("CA", "pki_external", "True") - config.set("CA", "pki_external_ca_cert_path", self.cert_file) -- config.set("CA", "pki_external_ca_cert_chain_path", self.cert_chain_file) -+ config.set("CA", "pki_external_ca_cert_chain_path", cert_chain_file.name) - config.set("CA", "pki_external_step_two", "True") - - # Generate configuration file --- -1.9.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 new file mode 100644 index 0000000..0fc2801 --- /dev/null +++ b/SOURCES/0067-Use-NSS-protocol-range-API-to-set-available-TLS-prot.patch @@ -0,0 +1,149 @@ +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-ipaserver-dcerpc.py-if-search-of-a-closest-GC-failed.patch b/SOURCES/0067-ipaserver-dcerpc.py-if-search-of-a-closest-GC-failed.patch deleted file mode 100644 index 8a6db38..0000000 --- a/SOURCES/0067-ipaserver-dcerpc.py-if-search-of-a-closest-GC-failed.patch +++ /dev/null @@ -1,33 +0,0 @@ -From f2acf0d67bab3f3797c387705f93c3a3d0164134 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 19 Aug 2014 16:19:45 +0300 -Subject: [PATCH] ipaserver/dcerpc.py: if search of a closest GC failed, try to - find any GC - -https://fedorahosted.org/freeipa/ticket/4458 - -Reviewed-By: Sumit Bose ---- - ipaserver/dcerpc.py | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index f1c75089b875787debcee22316a4898b424d923f..b11476a262ccce4315131b9ffbd93b625de940e7 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -588,7 +588,11 @@ class DomainValidator(object): - try: - result = netrc.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC | nbt.NBT_SERVER_CLOSEST) - except RuntimeError, e: -- finddc_error = e -+ try: -+ # If search of closest GC failed, attempt to find any one -+ result = netrc.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC) -+ except RuntimeError, e: -+ finddc_error = e - - if not self._domains: - self._domains = self.get_trusted_domains() --- -1.9.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 new file mode 100644 index 0000000..d753f55 --- /dev/null +++ b/SOURCES/0068-Throw-zonemgr-error-message-before-installation-proc.patch @@ -0,0 +1,136 @@ +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-ipaserver-dcerpc.py-make-PDC-discovery-more-robust.patch b/SOURCES/0068-ipaserver-dcerpc.py-make-PDC-discovery-more-robust.patch deleted file mode 100644 index a1ba8b9..0000000 --- a/SOURCES/0068-ipaserver-dcerpc.py-make-PDC-discovery-more-robust.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 41b252a5b47f57919bf98c41947d5927ed0d5aaf Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 19 Aug 2014 16:21:21 +0300 -Subject: [PATCH] ipaserver/dcerpc.py: make PDC discovery more robust - -Certain operations against AD domain controller can only be done if its -FSMO role is primary domain controller. We need to use writable DC and -PDC when creating trust and updating name suffix routing information. - -https://fedorahosted.org/freeipa/ticket/4479 - -Reviewed-By: Sumit Bose ---- - ipaserver/dcerpc.py | 21 ++++++++++++++++----- - 1 file changed, 16 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index b11476a262ccce4315131b9ffbd93b625de940e7..78bfc5dbefc778519c5db0ac12d6551710257ba9 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -706,16 +706,19 @@ class TrustDomainInstance(object): - 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): -+ def retrieve_anonymously(self, remote_host, discover_srv=False, search_pdc=False): - """ - When retrieving DC information anonymously, we can't get SID of the domain - """ - netrc = net.Net(creds=self.creds, lp=self.parm) -+ flags = nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE -+ if search_pdc: -+ flags = flags | nbt.NBT_SERVER_PDC - try: - if discover_srv: -- result = netrc.finddc(domain=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) -+ result = netrc.finddc(domain=remote_host, flags=flags) - else: -- result = netrc.finddc(address=remote_host, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) -+ result = netrc.finddc(address=remote_host, flags=flags) - except RuntimeError, e: - raise assess_dcerpc_exception(message=str(e)) - -@@ -726,6 +729,7 @@ class TrustDomainInstance(object): - self.info['dns_forest'] = unicode(result.forest) - self.info['guid'] = unicode(result.domain_uuid) - self.info['dc'] = unicode(result.pdc_dns_name) -+ self.info['is_pdc'] = (result.server_type & nbt.NBT_SERVER_PDC) != 0 - - # Netlogon response doesn't contain SID of the domain. - # We need to do rootDSE search with LDAP_SERVER_EXTENDED_DN_OID control to reveal the SID -@@ -774,6 +778,13 @@ class TrustDomainInstance(object): - self.info['sid'] = unicode(result.sid) - self.info['dc'] = remote_host - -+ try: -+ result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_ROLE) -+ except RuntimeError, (num, message): -+ raise assess_dcerpc_exception(num=num, message=message) -+ -+ self.info['is_pdc'] = (result.role == lsa.LSA_ROLE_PRIMARY) -+ - def generate_auth(self, trustdom_secret): - def arcfour_encrypt(key, data): - c = RC4.RC4(key) -@@ -1069,9 +1080,9 @@ class TrustDomainJoins(object): - rd.creds.set_anonymous() - rd.creds.set_workstation(self.local_domain.hostname) - if realm_server is None: -- rd.retrieve_anonymously(realm, discover_srv=True) -+ rd.retrieve_anonymously(realm, discover_srv=True, search_pdc=True) - else: -- rd.retrieve_anonymously(realm_server, discover_srv=False) -+ rd.retrieve_anonymously(realm_server, discover_srv=False, search_pdc=True) - rd.read_only = True - if realm_admin and realm_passwd: - if 'name' in rd.info: --- -1.9.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 new file mode 100644 index 0000000..e8e73d1 --- /dev/null +++ b/SOURCES/0069-certs-Fix-incorrect-flag-handling-in-load_cacert.patch @@ -0,0 +1,62 @@ +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-ipaserver-dcerpc.py-be-more-open-to-what-domains-can.patch b/SOURCES/0069-ipaserver-dcerpc.py-be-more-open-to-what-domains-can.patch deleted file mode 100644 index 595950a..0000000 --- a/SOURCES/0069-ipaserver-dcerpc.py-be-more-open-to-what-domains-can.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 027f61099c63c91aaac95a6c2b9d9a75e7b1f83e Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 19 Aug 2014 16:23:58 +0300 -Subject: [PATCH] ipaserver/dcerpc.py: be more open to what domains can be seen - through the forest trust - -https://fedorahosted.org/freeipa/ticket/4463 - -Reviewed-By: Sumit Bose ---- - ipaserver/dcerpc.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 78bfc5dbefc778519c5db0ac12d6551710257ba9..fcf1e4e775868f17220cac3c0203cc67dba2f839 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -1031,7 +1031,7 @@ def fetch_domains(api, mydomain, trustdomain, creds=None): - - result = [] - for t in domains.array: -- if ((t.trust_attributes & trust_attributes['NETR_TRUST_ATTRIBUTE_WITHIN_FOREST']) and -+ if (not (t.trust_flags & trust_flags['NETR_TRUST_FLAG_PRIMARY']) and - (t.trust_flags & trust_flags['NETR_TRUST_FLAG_IN_FOREST'])): - res = dict() - res['cn'] = unicode(t.dns_name) --- -1.9.3 - diff --git a/SOURCES/0070-Preliminary-refactoring-of-libotp-files.patch b/SOURCES/0070-Preliminary-refactoring-of-libotp-files.patch new file mode 100644 index 0000000..95100d4 --- /dev/null +++ b/SOURCES/0070-Preliminary-refactoring-of-libotp-files.patch @@ -0,0 +1,2309 @@ +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-ipaserver-dcerpc.py-Make-sure-trust-is-established-o.patch b/SOURCES/0070-ipaserver-dcerpc.py-Make-sure-trust-is-established-o.patch deleted file mode 100644 index 29ca7e5..0000000 --- a/SOURCES/0070-ipaserver-dcerpc.py-Make-sure-trust-is-established-o.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 079fdf41592559de96465080e81aa91252c01a3d Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 19 Aug 2014 16:24:27 +0300 -Subject: [PATCH] ipaserver/dcerpc.py: Make sure trust is established only to - forest root domain - -Part of https://fedorahosted.org/freeipa/ticket/4463 - -Reviewed-By: Sumit Bose ---- - ipalib/errors.py | 16 ++++++++++++++++ - ipaserver/dcerpc.py | 6 ++++++ - 2 files changed, 22 insertions(+) - -diff --git a/ipalib/errors.py b/ipalib/errors.py -index 716decb2b41baf5470a1dc23c0cfb5d1c995e5ff..405c5c3bfc25d9b024189be9fcf582052dd10dd3 100644 ---- a/ipalib/errors.py -+++ b/ipalib/errors.py -@@ -810,6 +810,22 @@ class DeprecationError(InvocationError): - errno = 3015 - format = _("Command '%(name)s' has been deprecated") - -+class NotAForestRootError(InvocationError): -+ """ -+ **3016** Raised when an attempt to establish trust is done against non-root domain -+ Forest root domain has the same name as the forest itself -+ -+ For example: -+ -+ >>> raise NotAForestRootError(forest='example.test', domain='jointops.test') -+ Traceback (most recent call last): -+ ... -+ NotAForestRootError: Domain 'jointops.test' is not a root domain for forest 'example.test' -+ """ -+ -+ errno = 3016 -+ format = _("Domain '%(domain)s' is not a root domain for forest '%(forest)s'") -+ - - ############################################################################## - # 4000 - 4999: Execution errors -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index fcf1e4e775868f17220cac3c0203cc67dba2f839..41f373df3cc4365727200f3ca4667faac2f9e19c 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -1143,6 +1143,9 @@ class TrustDomainJoins(object): - realm_passwd - ) - -+ if self.remote_domain.info['dns_domain'] != self.remote_domain.info['dns_forest']: -+ raise errors.NotAForestRootError(forest=self.remote_domain.info['dns_forest'], domain=self.remote_domain.info['dns_domain']) -+ - if not self.remote_domain.read_only: - trustdom_pass = samba.generate_random_password(128, 128) - self.get_realmdomains() -@@ -1159,5 +1162,8 @@ class TrustDomainJoins(object): - if not(isinstance(self.remote_domain, TrustDomainInstance)): - self.populate_remote_domain(realm, realm_server, realm_passwd=None) - -+ if self.remote_domain.info['dns_domain'] != self.remote_domain.info['dns_forest']: -+ raise errors.NotAForestRootError(forest=self.remote_domain.info['dns_forest'], domain=self.remote_domain.info['dns_domain']) -+ - self.local_domain.establish_trust(self.remote_domain, trustdom_passwd) - return dict(local=self.local_domain, remote=self.remote_domain, verified=False) --- -1.9.3 - diff --git a/SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch b/SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch new file mode 100644 index 0000000..0372953 --- /dev/null +++ b/SOURCES/0071-Move-authentication-configuration-cache-into-libotp.patch @@ -0,0 +1,1207 @@ +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-ipaserver-dcerpc.py-Avoid-hitting-issue-with-transit.patch b/SOURCES/0071-ipaserver-dcerpc.py-Avoid-hitting-issue-with-transit.patch deleted file mode 100644 index 565c6ec..0000000 --- a/SOURCES/0071-ipaserver-dcerpc.py-Avoid-hitting-issue-with-transit.patch +++ /dev/null @@ -1,54 +0,0 @@ -From ba2a63da8bada8af988d8fb8931c0cdba2c7ceee Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 19 Aug 2014 16:22:54 +0300 -Subject: [PATCH] ipaserver/dcerpc.py: Avoid hitting issue with transitive - trusts on Windows Server prior to 2012 - -http://msdn.microsoft.com/en-us/library/2a769a08-e023-459f-aebe-4fb3f595c0b7#id83 - -Reviewed-By: Sumit Bose ---- - ipaserver/dcerpc.py | 13 ++++++++++--- - 1 file changed, 10 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 41f373df3cc4365727200f3ca4667faac2f9e19c..e779a12bae52ec8dac52e4a43854a8a3c601a043 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -900,7 +900,7 @@ class TrustDomainInstance(object): - info.sid = security.dom_sid(another_domain.info['sid']) - info.trust_direction = lsa.LSA_TRUST_DIRECTION_INBOUND | lsa.LSA_TRUST_DIRECTION_OUTBOUND - info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL -- info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE -+ info.trust_attributes = 0 - - try: - dname = lsa.String() -@@ -917,8 +917,6 @@ class TrustDomainInstance(object): - except RuntimeError, (num, message): - raise assess_dcerpc_exception(num=num, message=message) - -- self.update_ftinfo(another_domain) -- - # We should use proper trustdom handle in order to modify the - # trust settings. Samba insists this has to be done with LSA - # OpenTrustedDomain* calls, it is not enough to have a handle -@@ -937,6 +935,15 @@ class TrustDomainInstance(object): - # server as that one doesn't support AES encryption types - pass - -+ try: -+ info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE -+ self._pipe.SetInformationTrustedDomain(trustdom_handle, lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX, info) -+ except RuntimeError, e: -+ root_logger.error('unable to set trust to transitive: %s' % (str(e))) -+ pass -+ if self.info['is_pdc']: -+ self.update_ftinfo(another_domain) -+ - def verify_trust(self, another_domain): - def retrieve_netlogon_info_2(domain, function_code, data): - try: --- -1.9.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 new file mode 100644 index 0000000..ab58dd6 --- /dev/null +++ b/SOURCES/0072-Enable-last-token-deletion-when-password-auth-type-i.patch @@ -0,0 +1,327 @@ +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/0073-add-hosts-and-hostgroup-options-to-allow-retrieve-ke.patch b/SOURCES/0073-add-hosts-and-hostgroup-options-to-allow-retrieve-ke.patch new file mode 100644 index 0000000..0e544cf --- /dev/null +++ b/SOURCES/0073-add-hosts-and-hostgroup-options-to-allow-retrieve-ke.patch @@ -0,0 +1,878 @@ +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/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 new file mode 100644 index 0000000..906a2dc --- /dev/null +++ b/SOURCES/0074-hosts-Display-assigned-ID-view-by-default-in-host-fi.patch @@ -0,0 +1,152 @@ +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/0075-Prefer-TCP-connections-to-UDP-in-krb5-clients.patch b/SOURCES/0075-Prefer-TCP-connections-to-UDP-in-krb5-clients.patch new file mode 100644 index 0000000..42e9d66 --- /dev/null +++ b/SOURCES/0075-Prefer-TCP-connections-to-UDP-in-krb5-clients.patch @@ -0,0 +1,61 @@ +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/0076-webui-fix-service-unprovisioning.patch b/SOURCES/0076-webui-fix-service-unprovisioning.patch new file mode 100644 index 0000000..89d44ef --- /dev/null +++ b/SOURCES/0076-webui-fix-service-unprovisioning.patch @@ -0,0 +1,30 @@ +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-webui-increase-duration-of-notification-messages.patch b/SOURCES/0077-webui-increase-duration-of-notification-messages.patch new file mode 100644 index 0000000..7c49e9f --- /dev/null +++ b/SOURCES/0077-webui-increase-duration-of-notification-messages.patch @@ -0,0 +1,30 @@ +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 new file mode 100644 index 0000000..797a2fa --- /dev/null +++ b/SOURCES/0078-Fix-automatic-CA-cert-renewal-endless-loop-in-dogtag.patch @@ -0,0 +1,34 @@ +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/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 new file mode 100644 index 0000000..c7adb92 --- /dev/null +++ b/SOURCES/0079-Do-not-renew-the-IPA-CA-cert-by-serial-number-in-dog.patch @@ -0,0 +1,34 @@ +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/0080-Improve-validation-of-instance-and-backend-options-i.patch b/SOURCES/0080-Improve-validation-of-instance-and-backend-options-i.patch new file mode 100644 index 0000000..f8e9fd5 --- /dev/null +++ b/SOURCES/0080-Improve-validation-of-instance-and-backend-options-i.patch @@ -0,0 +1,169 @@ +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/0081-revert-removal-of-cn-attribute-from-idnsRecord.patch b/SOURCES/0081-revert-removal-of-cn-attribute-from-idnsRecord.patch new file mode 100644 index 0000000..d619512 --- /dev/null +++ b/SOURCES/0081-revert-removal-of-cn-attribute-from-idnsRecord.patch @@ -0,0 +1,31 @@ +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/0082-Check-subject-name-encoding-in-ipa-cacert-manage-ren.patch b/SOURCES/0082-Check-subject-name-encoding-in-ipa-cacert-manage-ren.patch new file mode 100644 index 0000000..efe906b --- /dev/null +++ b/SOURCES/0082-Check-subject-name-encoding-in-ipa-cacert-manage-ren.patch @@ -0,0 +1,51 @@ +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/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 new file mode 100644 index 0000000..7c26966 --- /dev/null +++ b/SOURCES/0083-Refer-the-user-to-freeipa.org-when-something-goes-wr.patch @@ -0,0 +1,68 @@ +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/0084-Show-SSHFP-record-containing-space-in-fingerprint.patch b/SOURCES/0084-Show-SSHFP-record-containing-space-in-fingerprint.patch new file mode 100644 index 0000000..9379cb0 --- /dev/null +++ b/SOURCES/0084-Show-SSHFP-record-containing-space-in-fingerprint.patch @@ -0,0 +1,37 @@ +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/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 new file mode 100644 index 0000000..fced922 --- /dev/null +++ b/SOURCES/0085-Always-add-etc-hosts-record-when-DNS-is-being-config.patch @@ -0,0 +1,31 @@ +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/0086-Avoid-calling-ldap-functions-without-a-context.patch b/SOURCES/0086-Avoid-calling-ldap-functions-without-a-context.patch new file mode 100644 index 0000000..103cc3d --- /dev/null +++ b/SOURCES/0086-Avoid-calling-ldap-functions-without-a-context.patch @@ -0,0 +1,61 @@ +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/0087-Remove-the-removal-of-the-ccache.patch b/SOURCES/0087-Remove-the-removal-of-the-ccache.patch new file mode 100644 index 0000000..0a025b1 --- /dev/null +++ b/SOURCES/0087-Remove-the-removal-of-the-ccache.patch @@ -0,0 +1,38 @@ +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-Fix-Upgrade-forwardzones-zones-after-adding-newer-re.patch b/SOURCES/0088-Fix-Upgrade-forwardzones-zones-after-adding-newer-re.patch new file mode 100644 index 0000000..0c36e4f --- /dev/null +++ b/SOURCES/0088-Fix-Upgrade-forwardzones-zones-after-adding-newer-re.patch @@ -0,0 +1,145 @@ +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 new file mode 100644 index 0000000..327daa9 --- /dev/null +++ b/SOURCES/0089-Fix-zone-find-during-forwardzone-upgrade.patch @@ -0,0 +1,36 @@ +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/0090-migrate-ds-fix-compat-plugin-check.patch b/SOURCES/0090-migrate-ds-fix-compat-plugin-check.patch new file mode 100644 index 0000000..79e57f9 --- /dev/null +++ b/SOURCES/0090-migrate-ds-fix-compat-plugin-check.patch @@ -0,0 +1,44 @@ +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-rpcclient-use-json_encode_binary-for-verbose-output.patch b/SOURCES/0091-rpcclient-use-json_encode_binary-for-verbose-output.patch new file mode 100644 index 0000000..d9a2916 --- /dev/null +++ b/SOURCES/0091-rpcclient-use-json_encode_binary-for-verbose-output.patch @@ -0,0 +1,52 @@ +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-Remove-ipanttrustauthincoming-ipanttrustauthoutgoing.patch b/SOURCES/0092-Remove-ipanttrustauthincoming-ipanttrustauthoutgoing.patch new file mode 100644 index 0000000..f06b63a --- /dev/null +++ b/SOURCES/0092-Remove-ipanttrustauthincoming-ipanttrustauthoutgoing.patch @@ -0,0 +1,29 @@ +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 new file mode 100644 index 0000000..e479b01 --- /dev/null +++ b/SOURCES/0093-Abort-backup-restoration-on-not-matching-host.patch @@ -0,0 +1,36 @@ +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/0094-Fix-ipa-restore-on-systems-without-IPA-installed.patch b/SOURCES/0094-Fix-ipa-restore-on-systems-without-IPA-installed.patch new file mode 100644 index 0000000..a95caa7 --- /dev/null +++ b/SOURCES/0094-Fix-ipa-restore-on-systems-without-IPA-installed.patch @@ -0,0 +1,34 @@ +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/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 new file mode 100644 index 0000000..28976ce --- /dev/null +++ b/SOURCES/0095-Remove-RUV-from-LDIF-files-before-using-them-in-ipa-.patch @@ -0,0 +1,76 @@ +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/0096-Fix-CA-certificate-renewal-syslog-alert.patch b/SOURCES/0096-Fix-CA-certificate-renewal-syslog-alert.patch new file mode 100644 index 0000000..b1e3792 --- /dev/null +++ b/SOURCES/0096-Fix-CA-certificate-renewal-syslog-alert.patch @@ -0,0 +1,28 @@ +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/0097-Do-not-crash-on-unknown-services-in-installutils.sto.patch b/SOURCES/0097-Do-not-crash-on-unknown-services-in-installutils.sto.patch new file mode 100644 index 0000000..f876241 --- /dev/null +++ b/SOURCES/0097-Do-not-crash-on-unknown-services-in-installutils.sto.patch @@ -0,0 +1,46 @@ +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/0098-Restart-dogtag-when-its-server-certificate-is-renewe.patch b/SOURCES/0098-Restart-dogtag-when-its-server-certificate-is-renewe.patch new file mode 100644 index 0000000..e8be4da --- /dev/null +++ b/SOURCES/0098-Restart-dogtag-when-its-server-certificate-is-renewe.patch @@ -0,0 +1,65 @@ +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/0099-Make-certificate-renewal-process-synchronized.patch b/SOURCES/0099-Make-certificate-renewal-process-synchronized.patch new file mode 100644 index 0000000..3275e64 --- /dev/null +++ b/SOURCES/0099-Make-certificate-renewal-process-synchronized.patch @@ -0,0 +1,581 @@ +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/0100-Fix-validation-of-ipa-restore-options.patch b/SOURCES/0100-Fix-validation-of-ipa-restore-options.patch new file mode 100644 index 0000000..c0ee533 --- /dev/null +++ b/SOURCES/0100-Fix-validation-of-ipa-restore-options.patch @@ -0,0 +1,313 @@ +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/0101-Allow-PassSync-user-to-locate-and-update-NT-users.patch b/SOURCES/0101-Allow-PassSync-user-to-locate-and-update-NT-users.patch new file mode 100644 index 0000000..bddc767 --- /dev/null +++ b/SOURCES/0101-Allow-PassSync-user-to-locate-and-update-NT-users.patch @@ -0,0 +1,284 @@ +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/0102-Allow-Replication-Administrators-manipulate-Winsync-.patch b/SOURCES/0102-Allow-Replication-Administrators-manipulate-Winsync-.patch new file mode 100644 index 0000000..627f6e6 --- /dev/null +++ b/SOURCES/0102-Allow-Replication-Administrators-manipulate-Winsync-.patch @@ -0,0 +1,68 @@ +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/0103-Do-not-assume-certmonger-is-running-in-httpinstance.patch b/SOURCES/0103-Do-not-assume-certmonger-is-running-in-httpinstance.patch new file mode 100644 index 0000000..af80ec4 --- /dev/null +++ b/SOURCES/0103-Do-not-assume-certmonger-is-running-in-httpinstance.patch @@ -0,0 +1,81 @@ +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-Replication-Administrators-cannot-remove-replication.patch b/SOURCES/0104-Replication-Administrators-cannot-remove-replication.patch new file mode 100644 index 0000000..c6b0bc8 --- /dev/null +++ b/SOURCES/0104-Replication-Administrators-cannot-remove-replication.patch @@ -0,0 +1,41 @@ +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 new file mode 100644 index 0000000..1eca1dc --- /dev/null +++ b/SOURCES/0105-Put-LDIF-files-to-their-original-location-in-ipa-res.patch @@ -0,0 +1,40 @@ +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/0106-Add-anonymous-read-ACI-for-DUA-profile.patch b/SOURCES/0106-Add-anonymous-read-ACI-for-DUA-profile.patch new file mode 100644 index 0000000..dd94dc2 --- /dev/null +++ b/SOURCES/0106-Add-anonymous-read-ACI-for-DUA-profile.patch @@ -0,0 +1,62 @@ +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/0107-Revert-Make-all-ipatokenTOTP-attributes-mandatory.patch b/SOURCES/0107-Revert-Make-all-ipatokenTOTP-attributes-mandatory.patch new file mode 100644 index 0000000..da907c4 --- /dev/null +++ b/SOURCES/0107-Revert-Make-all-ipatokenTOTP-attributes-mandatory.patch @@ -0,0 +1,34 @@ +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 new file mode 100644 index 0000000..5b916f5 --- /dev/null +++ b/SOURCES/0108-Create-correct-log-directories-during-full-restore-i.patch @@ -0,0 +1,57 @@ +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/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 new file mode 100644 index 0000000..d770803 --- /dev/null +++ b/SOURCES/0109-Do-not-crash-when-replica-is-unreachable-in-ipa-rest.patch @@ -0,0 +1,35 @@ +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-idviews-Allow-setting-ssh-public-key-on-ipauseroverr.patch b/SOURCES/0110-idviews-Allow-setting-ssh-public-key-on-ipauseroverr.patch new file mode 100644 index 0000000..fb67ee0 --- /dev/null +++ b/SOURCES/0110-idviews-Allow-setting-ssh-public-key-on-ipauseroverr.patch @@ -0,0 +1,36 @@ +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-Fix-ipa-pwd-extop-global-configuration-caching.patch b/SOURCES/0111-Fix-ipa-pwd-extop-global-configuration-caching.patch new file mode 100644 index 0000000..5758f5f --- /dev/null +++ b/SOURCES/0111-Fix-ipa-pwd-extop-global-configuration-caching.patch @@ -0,0 +1,39 @@ +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-group-detach-does-not-add-correct-objectclasses.patch b/SOURCES/0112-group-detach-does-not-add-correct-objectclasses.patch new file mode 100644 index 0000000..e6f1196 --- /dev/null +++ b/SOURCES/0112-group-detach-does-not-add-correct-objectclasses.patch @@ -0,0 +1,25 @@ +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/1001-Hide-pkinit-functionality-from-production-version.patch b/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch index c650b25..644a02f 100644 --- a/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch +++ b/SOURCES/1001-Hide-pkinit-functionality-from-production-version.patch @@ -1,6 +1,6 @@ -From ebaad372cdeb941af1a390f81c8a4d90ea128f9f Mon Sep 17 00:00:00 2001 +From e33a5c3b993e0111617e1c15bed374f6ce426b2d Mon Sep 17 00:00:00 2001 From: Martin Kosek -Date: Thu, 14 Aug 2014 13:34:13 +0200 +Date: Fri, 5 Sep 2014 11:24:27 +0200 Subject: [PATCH] Hide pkinit functionality from production version Rebased from original patch from Jan Zeleny and Rob Crittenden. @@ -8,15 +8,15 @@ 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 | 10 ++++------ - ipaserver/install/ipa_replica_prepare.py | 11 +++-------- - 3 files changed, 10 insertions(+), 16 deletions(-) + install/tools/ipa-server-install | 20 ++++---------------- + ipaserver/install/ipa_replica_prepare.py | 20 +++----------------- + 3 files changed, 10 insertions(+), 35 deletions(-) diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install -index 4418b41784313121e73b560ee84715ddeba8bc54..ff4cd70147abb2dc6e0486155fb179d4fb1b29e9 100755 +index 75bbe981b96cf17950fe73d92d39ca3030f548f9..d3b520abf635ccc324b74bca31f241960a33d950 100755 --- a/install/tools/ipa-replica-install +++ b/install/tools/ipa-replica-install -@@ -95,8 +95,6 @@ def parse_options(): +@@ -97,8 +97,6 @@ def parse_options(): parser.add_option_group(basic_group) cert_group = OptionGroup(parser, "certificate system options") @@ -25,7 +25,7 @@ index 4418b41784313121e73b560ee84715ddeba8bc54..ff4cd70147abb2dc6e0486155fb179d4 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) -@@ -121,6 +119,9 @@ def parse_options(): +@@ -126,6 +124,9 @@ def parse_options(): options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) @@ -36,82 +36,122 @@ index 4418b41784313121e73b560ee84715ddeba8bc54..ff4cd70147abb2dc6e0486155fb179d4 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 feea616b089261bf46392d5514e6e3cc9e12fcac..5bd22bf18f2b00e26d674b6cbbf81989b4a030cb 100755 +index 0394314ee99817f221536136ae1432cc8e92220a..a5df3e9971a5ae128ebfa4c542dcad7cc3626276 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install -@@ -179,20 +179,14 @@ def parse_options(): - help="File containing the IPA CA certificate signed by the external CA in PEM format") - cert_group.add_option("", "--external_ca_file", dest="external_ca_file", - help="File containing the external CA certificate chain in PEM format") +@@ -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_pkcs12", dest="dirsrv_pkcs12", - help="PKCS#12 file containing the Directory Server SSL certificate") - cert_group.add_option("--http_pkcs12", dest="http_pkcs12", - help="PKCS#12 file containing the Apache Server SSL certificate") -- cert_group.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12", -- help="PKCS#12 file containing the Kerberos KDC SSL certificate") - cert_group.add_option("--dirsrv_pin", dest="dirsrv_pin", sensitive=True, - help="The password of the Directory Server PKCS#12 file") + 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="The password of the Apache Server PKCS#12 file") -- cert_group.add_option("--pkinit_pin", dest="pkinit_pin", -- help="The password of the Kerberos KDC PKCS#12 file") - cert_group.add_option("--root-ca-file", dest="root_ca_file", - help="PEM file with root CA certificate(s) to trust") - cert_group.add_option("--subject", action="callback", callback=subject_callback, -@@ -229,6 +223,10 @@ def parse_options(): + 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_pkcs12 = 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 36d078a6b73562cb0047154f4bb7666ab25687b8..a3b89a8a739c6082aa7117cea470e2a9d8dba7f9 100644 +index 3762f32700aa899541883d3af72b160c4c42ba7c..1d34aa26b49be0c5df8e7d315a45cd6d180e6da9 100644 --- a/ipaserver/install/ipa_replica_prepare.py +++ b/ipaserver/install/ipa_replica_prepare.py -@@ -56,9 +56,6 @@ def add_options(cls, parser): +@@ -63,9 +63,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") - parser.add_option("--no-pkinit", dest="setup_pkinit", - action="store_false", default=True, - help="disables pkinit setup steps") - parser.add_option("--ca", dest="ca_file", default="/root/cacert.p12", + parser.add_option("--ca", dest="ca_file", default=paths.CACERT_P12, metavar="FILE", help="location of CA PKCS#12 file, default /root/cacert.p12") -@@ -71,15 +68,10 @@ def add_options(cls, parser): - group.add_option("--http_pkcs12", dest="http_pkcs12", - metavar="FILE", - help="install certificate for the http server") -- group.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12", -- metavar="FILE", -- help="install certificate for the KDC") - group.add_option("--dirsrv_pin", dest="dirsrv_pin", metavar="PIN", - help="PIN for the Directory Server PKCS#12 file") - group.add_option("--http_pin", dest="http_pin", metavar="PIN", - help="PIN for the Apache Server PKCS#12 file") -- group.add_option("--pkinit_pin", dest="pkinit_pin", metavar="PIN", -- help="PIN for the KDC pkinit PKCS#12 file") +@@ -87,12 +84,6 @@ class ReplicaPrepare(admintool.AdminTool): + group.add_option("--http_pkcs12", dest="http_cert_files", + action="append", + help=SUPPRESS_HELP) +- 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") +- group.add_option("--pkinit_pkcs12", dest="pkinit_cert_files", +- action="append", +- help=SUPPRESS_HELP) + 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): + help="The password to unlock the Apache Server private key") + group.add_option("--http_pin", dest="http_pin", sensitive=True, + help=SUPPRESS_HELP) +- group.add_option("--pkinit-pin", dest="pkinit_pin", sensitive=True, +- metavar="PIN", +- help="The password to unlock the Kerberos KDC private key") +- group.add_option("--pkinit_pin", dest="pkinit_pin", sensitive=True, +- help=SUPPRESS_HELP) + group.add_option("--dirsrv-cert-name", dest="dirsrv_cert_name", + metavar="NAME", + help="Name of the Directory Server SSL certificate to install") + group.add_option("--http-cert-name", dest="http_cert_name", + metavar="NAME", + help="Name of the Apache Server SSL certificate to install") +- group.add_option("--pkinit-cert-name", dest="pkinit_cert_name", +- metavar="NAME", +- help="Name of the Kerberos KDC SSL certificate to install") parser.add_option_group(group) def validate_options(self): -@@ -99,7 +91,10 @@ def validate_options(self): +@@ -136,7 +119,10 @@ class ReplicaPrepare(admintool.AdminTool): "option together with --no-reverse") #Automatically disable pkinit w/ dogtag until that is supported + # pkinit is disabled in production version options.setup_pkinit = False + options.pkinit_pin = False -+ options.pkinit_pkcs12 = False ++ options.pkinit_cert_files = False # If any of the PKCS#12 options are selected, all are required. - pkcs12_req = (options.dirsrv_pkcs12, options.http_pkcs12) + cert_file_req = (options.dirsrv_cert_files, options.http_cert_files) -- 1.9.3 diff --git a/SOURCES/1002-Remove-pkinit-plugin.patch b/SOURCES/1002-Remove-pkinit-plugin.patch index 6c53550..d2fed0a 100644 --- a/SOURCES/1002-Remove-pkinit-plugin.patch +++ b/SOURCES/1002-Remove-pkinit-plugin.patch @@ -1,7 +1,7 @@ -From 62b7d72f65ab8ac90a62486bb170133755764bc7 Mon Sep 17 00:00:00 2001 +From f7996d16d5a424f136d54a7dc190d4e6c5dad628 Mon Sep 17 00:00:00 2001 From: Martin Kosek -Date: Wed, 22 May 2013 09:40:39 +0200 -Subject: [PATCH 1002/1006] Remove pkinit plugin +Date: Fri, 5 Sep 2014 11:26:18 +0200 +Subject: [PATCH] Remove pkinit plugin This patch completely removes any signs of pkinit in the IPA package. It should be used only as addition to the first patch attached to the @@ -12,15 +12,15 @@ Rebased patch by Jan Zeleny and Rob Crittenden. https://fedorahosted.org/freeipa/ticket/616 --- API.txt | 5 --- - ipalib/plugins/pkinit.py | 101 ----------------------------------------------- - 2 files changed, 106 deletions(-) + ipalib/plugins/pkinit.py | 105 ----------------------------------------------- + 2 files changed, 110 deletions(-) delete mode 100644 ipalib/plugins/pkinit.py diff --git a/API.txt b/API.txt -index 5418f31dc8d936ee629155aff08c05577cf9c4ee..ec5b3c9f6459e048c516a64dbab2396306fa6a72 100644 +index 7949c49f9fb9e3cd7eceb64a05dd8e550eb48f8b..e573a2838777dc564fc8ef16f97b36fe17b67590 100644 --- a/API.txt +++ b/API.txt -@@ -2336,11 +2336,6 @@ command: ping +@@ -2895,11 +2895,6 @@ command: ping args: 0,1,1 option: Str('version?', exclude='webui') output: Output('summary', (, ), None) @@ -34,10 +34,10 @@ index 5418f31dc8d936ee629155aff08c05577cf9c4ee..ec5b3c9f6459e048c516a64dbab23963 option: Flag('all', autofill=True, cli_name='all', default=True, exclude='webui') diff --git a/ipalib/plugins/pkinit.py b/ipalib/plugins/pkinit.py deleted file mode 100644 -index 981e411df520e175fa88f1de02a4eae36d687ede..0000000000000000000000000000000000000000 +index 5f00b2b46ff94cca7f98876c0171f455c210d778..0000000000000000000000000000000000000000 --- a/ipalib/plugins/pkinit.py +++ /dev/null -@@ -1,101 +0,0 @@ +@@ -1,105 +0,0 @@ -# Authors: -# Simo Sorce -# @@ -61,6 +61,7 @@ index 981e411df520e175fa88f1de02a4eae36d687ede..00000000000000000000000000000000 -from ipalib import Int, Str -from ipalib import Object, Command -from ipalib import _ +-from ipalib.plugable import Registry -from ipapython.dn import DN - -__doc__ = _(""" @@ -83,6 +84,9 @@ index 981e411df520e175fa88f1de02a4eae36d687ede..00000000000000000000000000000000 -http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit -""") - +-register = Registry() +- +-@register() -class pkinit(Object): - """ - PKINIT Options @@ -91,7 +95,6 @@ index 981e411df520e175fa88f1de02a4eae36d687ede..00000000000000000000000000000000 - - label=_('PKINIT') - --api.register(pkinit) - -def valid_arg(ugettext, action): - """ @@ -104,6 +107,7 @@ index 981e411df520e175fa88f1de02a4eae36d687ede..00000000000000000000000000000000 - error=_('Unknown command %s') % action - ) - +-@register() -class pkinit_anonymous(Command): - __doc__ = _('Enable or Disable Anonymous PKINIT.') - @@ -119,7 +123,7 @@ index 981e411df520e175fa88f1de02a4eae36d687ede..00000000000000000000000000000000 - set_lock = False - lock = None - -- (dn, entry_attrs) = ldap.get_entry(self.default_dn, ['nsaccountlock']) +- entry_attrs = ldap.get_entry(self.default_dn, ['nsaccountlock']) - - if 'nsaccountlock' in entry_attrs: - lock = entry_attrs['nsaccountlock'][0].lower() @@ -134,11 +138,11 @@ index 981e411df520e175fa88f1de02a4eae36d687ede..00000000000000000000000000000000 - lock = 'TRUE' - - if set_lock: -- ldap.update_entry(dn, {'nsaccountlock':lock}) +- entry_attrs['nsaccountlock'] = lock +- ldap.update_entry(entry_attrs) - - return dict(result=True) - --api.register(pkinit_anonymous) -- -1.8.3.1 +2.1.0 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 d4a0099..cddd2b8 100644 --- a/SOURCES/1003-Remove-pkinit-references-from-tool-man-pages.patch +++ b/SOURCES/1003-Remove-pkinit-references-from-tool-man-pages.patch @@ -1,13 +1,13 @@ -From e7dcef627095e38ce29a5f446c08a55ee88fc893 Mon Sep 17 00:00:00 2001 +From c86d432ab449d86860ad6436684caa2af30da99f Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Wed, 22 May 2013 09:59:12 +0200 -Subject: [PATCH 1003/1006] Remove pkinit references from tool man pages +Subject: [PATCH] Remove pkinit references from tool man pages --- - install/tools/man/ipa-replica-install.1 | 3 --- - install/tools/man/ipa-replica-prepare.1 | 9 --------- - install/tools/man/ipa-server-install.1 | 9 --------- - 3 files changed, 21 deletions(-) + install/tools/man/ipa-replica-install.1 | 3 --- + install/tools/man/ipa-replica-prepare.1 | 12 ------------ + install/tools/man/ipa-server-install.1 | 12 ------------ + 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 @@ -24,29 +24,38 @@ 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 8e1e60a25628432bf380e7af1d2d2dac9abf8c8a..88c30757b38cfdfec36dce85e995d419dd05c17b 100644 +index a0d47c9add145b8840065f64b79443ade504d9db..7931b71ed6fceab059a51496d9289ce25eb86b4e 100644 --- a/install/tools/man/ipa-replica-prepare.1 +++ b/install/tools/man/ipa-replica-prepare.1 -@@ -41,18 +41,12 @@ PKCS#12 file containing the Directory Server SSL Certificate and Private Key - \fB\-\-http_pkcs12\fR=\fIFILE\fR - PKCS#12 file containing the Apache Server SSL Certificate and Private Key +@@ -41,27 +41,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 --\fB\-\-pkinit_pkcs12\fR=\fIFILE\fR --PKCS#12 file containing the Kerberos KDC Certificate and Private Key +-\fB\-\-pkinit\-cert\-file\fR=\fIFILE\fR +-File containing the Kerberos KDC 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 - \fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR - The password of the Directory Server PKCS#12 file + \fB\-\-dirsrv\-pin\fR=\fIPIN\fR + The password to unlock the Directory Server private key .TP - \fB\-\-http_pin\fR=\fIHTTP_PIN\fR - The password of the Apache Server PKCS#12 file + \fB\-\-http\-pin\fR=\fIPIN\fR + The password to unlock the Apache Server private key .TP --\fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR --The password of the Kerberos KDC PKCS#12 file +-\fB\-\-pkinit\-pin\fR=\fIPIN\fR +-The password to unlock the Kerberos KDC private key +-.TP + \fB\-\-dirsrv\-cert\-name\fR=\fINAME\fR + Name of the Directory Server SSL certificate to install + .TP + \fB\-\-http\-cert\-name\fR=\fINAME\fR + Name of the Apache Server SSL certificate to install + .TP +-\fB\-\-pkinit\-cert\-name\fR=\fINAME\fR +-Name of the Kerberos KDC SSL certificate to install -.TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR Directory Manager (existing master) password .TP -@@ -68,9 +62,6 @@ Do not create reverse DNS zone +@@ -77,9 +68,6 @@ Do not create reverse DNS zone \fB\-\-ca\fR=\fICA_FILE\fR Location of CA PKCS#12 file, default /root/cacert.p12 .TP @@ -57,37 +66,46 @@ index 8e1e60a25628432bf380e7af1d2d2dac9abf8c8a..88c30757b38cfdfec36dce85e995d419 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 59219c14727c5a3062d06d5ef02eb0eebdc9c4f2..409dcf24beb6c53a9908437738fbbe3c90078367 100644 +index e5c9c319b95268af091287a7be14df6a2d06a6e0..7343f323e5447c028bba36564172524690059342 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 -@@ -93,27 +93,18 @@ PEM file containing a certificate signed by the external CA. Must be given with - \fB\-\-external_ca_file\fR=\fIFILE\fR - PEM file containing the external CA chain +@@ -93,36 +93,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 -\fB\-\-no\-pkinit\fR -Disables pkinit setup steps -.TP - \fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR - PKCS#12 file containing the Directory Server SSL Certificate + \fB\-\-dirsrv\-cert\-file\fR=\fIFILE\fR + File containing the Directory 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 - \fB\-\-http_pkcs12\fR=\fIFILE\fR - PKCS#12 file containing the Apache Server SSL Certificate + \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 --\fB\-\-pkinit_pkcs12\fR=\fIFILE\fR --PKCS#12 file containing the Kerberos KDC SSL certificate +-\fB\-\-pkinit\-cert\-file\fR=\fIFILE\fR +-File containing the Kerberos KDC 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 - \fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR - The password of the Directory Server PKCS#12 file + \fB\-\-dirsrv\-pin\fR=\fIPIN\fR + The password to unlock the Directory Server private key .TP - \fB\-\-http_pin\fR=\fIHTTP_PIN\fR - The password of the Apache Server PKCS#12 file + \fB\-\-http\-pin\fR=\fIPIN\fR + The password to unlock the Apache Server private key .TP --\fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR --The password of the Kerberos KDC PKCS#12 file +-\fB\-\-pkinit\-pin\fR=\fIPIN\fR +-The password to unlock the Kerberos KDC private key -.TP - \fB\-\-subject\fR=\fISUBJECT\fR - The certificate subject base (default O=REALM.NAME) - + \fB\-\-dirsrv\-cert\-name\fR=\fINAME\fR + Name of the Directory Server SSL certificate to install + .TP + \fB\-\-http\-cert\-name\fR=\fINAME\fR + Name of the Apache Server SSL certificate to install + .TP +-\fB\-\-pkinit\-cert\-name\fR=\fINAME\fR +-Name of the Kerberos KDC SSL certificate to install +-.TP + \fB\-\-ca\-cert\-file\fR=\fIFILE\fR + 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.8.3.1 +1.9.3 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 3f300c0..a1e96b4 100644 --- a/SOURCES/1004-Change-branding-to-IPA-and-Identity-Management.patch +++ b/SOURCES/1004-Change-branding-to-IPA-and-Identity-Management.patch @@ -1,13 +1,13 @@ -From 8f1aaebb76015f92601d012a4ce1d8da27a1c90c Mon Sep 17 00:00:00 2001 +From 7e7a531e1b503c6fe5e4ac0389591c546071411b Mon Sep 17 00:00:00 2001 From: Martin Kosek -Date: Thu, 18 Jul 2013 08:48:29 +0200 -Subject: [PATCH 1004/1006] Change branding to IPA and Identity Management +Date: Fri, 5 Sep 2014 11:46:59 +0200 +Subject: [PATCH] Change branding to IPA and Identity Management --- - install/html/browserconfig.html | 2 +- - install/html/ssbrowser.html | 2 +- - install/html/unauthorized.html | 2 +- - install/migration/error.html | 2 +- + install/html/browserconfig.html | 4 ++-- + install/html/ssbrowser.html | 4 ++-- + install/html/unauthorized.html | 4 ++-- + install/migration/error.html | 4 ++-- install/migration/index.html | 2 +- install/migration/invalid.html | 2 +- install/tools/ipa-adtrust-install | 6 +++--- @@ -24,6 +24,7 @@ Subject: [PATCH 1004/1006] Change branding to IPA and Identity Management install/tools/man/ipa-ldap-updater.1 | 2 +- install/tools/man/ipa-managed-entries.1 | 2 +- install/tools/man/ipa-nis-manage.1 | 2 +- + install/tools/man/ipa-otptoken-import.1 | 2 +- install/tools/man/ipa-replica-conncheck.1 | 2 +- install/tools/man/ipa-replica-install.1 | 2 +- install/tools/man/ipa-replica-manage.1 | 2 +- @@ -33,19 +34,21 @@ Subject: [PATCH 1004/1006] Change branding to IPA and Identity Management install/tools/man/ipa-server-install.1 | 2 +- install/tools/man/ipactl.8 | 2 +- install/ui/index.html | 2 +- - install/ui/login.html | 2 +- - install/ui/logout.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-client-automount.1 | 2 +- ipa-client/man/ipa-client-install.1 | 2 +- - ipa-client/man/ipa-getkeytab.1 | 2 +- + ipa-client/man/ipa-getkeytab.1 | 4 ++-- ipa-client/man/ipa-join.1 | 2 +- ipa-client/man/ipa-rmkeytab.1 | 2 +- - 38 files changed, 41 insertions(+), 41 deletions(-) + ipa.1 | 2 +- + ipaserver/advise/plugins/legacy_clients.py | 8 ++++---- + 41 files changed, 52 insertions(+), 52 deletions(-) diff --git a/install/html/browserconfig.html b/install/html/browserconfig.html -index a7784f75b8dabb19a5658b06a008bc3f4660823d..31508e95521b9c196c102cfda0be94bb25e43cf3 100644 +index d721a4ad2a3b684a4bf45602584fee78f4613360..b0cd570403b1604449887302844c43b1e89b80e2 100644 --- a/install/html/browserconfig.html +++ b/install/html/browserconfig.html @@ -2,7 +2,7 @@ @@ -54,11 +57,20 @@ index a7784f75b8dabb19a5658b06a008bc3f4660823d..31508e95521b9c196c102cfda0be94bb - IPA: Identity Policy Audit + Identity Management + + + + +

diff --git a/install/migration/error.html b/install/migration/error.html -index 9e1e3bd0b27f264534d013e8e526c3cded448c77..333ee1e5030596917a15a5b864719cc2abb374b4 100644 +index 896e56ec63c6eee62cb0b93f4e7fe97d668e703d..c7a4cb41961e181633ddd4f0d41064d8b696782f 100644 --- a/install/migration/error.html +++ b/install/migration/error.html @@ -2,7 +2,7 @@ @@ -94,39 +124,48 @@ index 9e1e3bd0b27f264534d013e8e526c3cded448c77..333ee1e5030596917a15a5b864719cc2 - IPA: Identity Policy Audit + Identity Management - - + + +@@ -11,7 +11,7 @@ + + + diff --git a/install/migration/index.html b/install/migration/index.html -index eb816b35d9f420f8f64ee8a63c443818793e5e59..78c5165f076f77de59f5554bedfe59f4a580a133 100644 +index 302eca263fa62c92d39ad9ccc678cf251a0afc8c..189aa71943ae1a5acfae977c0f74400d7ac4d23b 100644 --- a/install/migration/index.html +++ b/install/migration/index.html @@ -2,7 +2,7 @@ - + - IPA: Identity Policy Audit + Identity Management - - + + diff --git a/install/migration/invalid.html b/install/migration/invalid.html -index 4f46934066602b5bc52c62ad7006fe4b85ae2a6d..4f4e87a7d9490cab4ac97ed623d1f364d87be909 100644 +index f75b0bdc7d00d54d801ef66f373a09e89ead3251..16c455ca12e922ece1ea49813071fc2db0a22970 100644 --- a/install/migration/invalid.html +++ b/install/migration/invalid.html @@ -2,7 +2,7 @@ - + - IPA: Identity Policy Audit + Identity Management - - + + diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install -index 838f7226bca66f4980c1144d7907bc42fcd31a22..bcf90a621ff052715951ed494d29c4d89742a458 100755 +index 6e55bbe3e57f1c609398dc571e90cb8677d91a33..2e235262ee1ed3aa084459a243c41a49f79b68fd 100755 --- a/install/tools/ipa-adtrust-install +++ b/install/tools/ipa-adtrust-install -@@ -225,11 +225,11 @@ def main(): +@@ -227,11 +227,11 @@ def main(): print "==============================================================================" print "This program will setup components needed to establish trust to AD domains for" @@ -140,7 +179,7 @@ index 838f7226bca66f4980c1144d7907bc42fcd31a22..bcf90a621ff052715951ed494d29c4d8 #TODO: #print " * Add a SID to all users and Posix groups" print "" -@@ -398,7 +398,7 @@ You must make sure these network ports are open: +@@ -429,7 +429,7 @@ You must make sure these network ports are open: \t * 389: (C)LDAP \t * 445: microsoft-ds @@ -150,11 +189,11 @@ index 838f7226bca66f4980c1144d7907bc42fcd31a22..bcf90a621ff052715951ed494d29c4d8 the following ports for these servers: \tTCP Ports: diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install -index 275e699ebc824e0eb454ac80089105c5e9ac2146..505f3d5b651c75df4f592f880bf29657c2f6b650 100755 +index 1d4db5f1fdff373bc0af725ee50f1210f3195b7d..cbf3faeef3644870b6978e02c95f67354cc7e61b 100755 --- a/install/tools/ipa-dns-install +++ b/install/tools/ipa-dns-install -@@ -112,7 +112,7 @@ def main(): - fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') +@@ -97,7 +97,7 @@ def main(): + fstore = sysrestore.FileStore(paths.SYSRESTORE) print "==============================================================================" - print "This program will setup DNS for the FreeIPA Server." @@ -163,10 +202,10 @@ index 275e699ebc824e0eb454ac80089105c5e9ac2146..505f3d5b651c75df4f592f880bf29657 print "This includes:" print " * Configure DNS (bind)" diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck -index 583b5d5e75090483ddd9549862de04ea30fe820f..b2d4bc253e334ccce742489b376e29af649bd2e0 100755 +index 22348fc2158e59afc2e1aa51e3d3f51e90b99e39..e26e878c5b82b4e1e8a172a217b3225dcea642c4 100755 --- a/install/tools/ipa-replica-conncheck +++ b/install/tools/ipa-replica-conncheck -@@ -223,7 +223,7 @@ class PortResponder(threading.Thread): +@@ -252,7 +252,7 @@ class PortResponder(threading.Thread): ipautil.bind_port_responder(self.port, self.port_type, socket_timeout=self.socket_timeout, @@ -176,10 +215,10 @@ index 583b5d5e75090483ddd9549862de04ea30fe820f..b2d4bc253e334ccce742489b376e29af pass except socket.error, e: diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install -index 00aed1953f58c7f7c6a3c9bae8dcab8b8a669b62..fa9e4c47fe961c2296c5491ca19c61cc7869af0b 100755 +index 8f4cf457af54d47dbeda48f24a1b607e61106497..4fd4d8171ab89b805449a6625e9c5ea2d0921fa5 100755 --- a/install/tools/ipa-server-install +++ b/install/tools/ipa-server-install -@@ -730,7 +730,7 @@ def main(): +@@ -830,7 +830,7 @@ def main(): external = 0 print "==============================================================================" @@ -189,7 +228,7 @@ index 00aed1953f58c7f7c6a3c9bae8dcab8b8a669b62..fa9e4c47fe961c2296c5491ca19c61cc 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 7f0566e135ce1eec049987ff99e922f76c53177b..3b591a033ee4639b951e15b937249c7890fbf3b6 100644 +index b0aa8ceefc34698329b2a13d3adbcb204f08b3a9..fe22b69ad7730b9c07c0e4cc8f8326b80738fe62 100644 --- a/install/tools/man/ipa-adtrust-install.1 +++ b/install/tools/man/ipa-adtrust-install.1 @@ -16,7 +16,7 @@ @@ -235,7 +274,7 @@ index ff9759ec77d54f32532c4ececfa5081daab9ec15..476f9b534d514b03200369212807fc6d ipa\-backup \- Back up an IPA master .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-ca-install.1 b/install/tools/man/ipa-ca-install.1 -index 13ef43a80aa16afad8b7432ef2bce361e45d1fb8..0a6977dbf9780182f0d86564575433002ab50b71 100644 +index aa186987a15b5203607ac76e63751f01811c4bd7..c110db03ff48fd80b4dc70cf9d1c32d53d58b57b 100644 --- a/install/tools/man/ipa-ca-install.1 +++ b/install/tools/man/ipa-ca-install.1 @@ -16,7 +16,7 @@ @@ -245,7 +284,7 @@ index 13ef43a80aa16afad8b7432ef2bce361e45d1fb8..0a6977dbf9780182f0d8656457543300 -.TH "ipa-ca-install" "1" "Jun 17 2011" "FreeIPA" "FreeIPA Manual Pages" +.TH "ipa-ca-install" "1" "Jun 17 2011" "IPA" "IPA Manual Pages" .SH "NAME" - ipa\-ca\-install \- Install a CA on a replica + ipa\-ca\-install \- Install a CA on a server .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-compat-manage.1 b/install/tools/man/ipa-compat-manage.1 index f22b1743e31c3b07132acfcfdd8600544f9ace6c..26470331a127af9445c4473525434c237e23dbcf 100644 @@ -261,7 +300,7 @@ index f22b1743e31c3b07132acfcfdd8600544f9ace6c..26470331a127af9445c4473525434c23 ipa\-compat\-manage \- Enables or disables the schema compatibility plugin .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-csreplica-manage.1 b/install/tools/man/ipa-csreplica-manage.1 -index ddb28da414ee12f4a8d09032b8b7346b2d3a06ea..ee1a030ace8dce345e66f42b37d2621d954083d9 100644 +index 3164ea60d67db99445dac168fad967cb48be428e..bdf70302e1743d0d94c0acad7e83b5a16026c643 100644 --- a/install/tools/man/ipa-csreplica-manage.1 +++ b/install/tools/man/ipa-csreplica-manage.1 @@ -16,7 +16,7 @@ @@ -274,7 +313,7 @@ index ddb28da414ee12f4a8d09032b8b7346b2d3a06ea..ee1a030ace8dce345e66f42b37d2621d 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 b0bdca94f4aea4a17fecc3362a92a9885bbafed0..68789506c11857190273d2ea67ce299517e3d338 100644 +index bde30cadba9b8b461f5373b734c3edf2faf9d0af..0e12918e5d906f0606e7fb6e19f2da25c91e2a3c 100644 --- a/install/tools/man/ipa-dns-install.1 +++ b/install/tools/man/ipa-dns-install.1 @@ -16,7 +16,7 @@ @@ -287,7 +326,7 @@ index b0bdca94f4aea4a17fecc3362a92a9885bbafed0..68789506c11857190273d2ea67ce2995 ipa\-dns\-install \- Add DNS as a service to an IPA server .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-ldap-updater.1 b/install/tools/man/ipa-ldap-updater.1 -index 37e200f520218150af4e1be63fc442131f908e27..23b8dc8177c85e351eae30a27e6001780ad267bb 100644 +index 79cc316501512879fa39ba4c15fd898b976eb25e..6d819cb531372e58c81eeb7e01ebfb9bb574169b 100644 --- a/install/tools/man/ipa-ldap-updater.1 +++ b/install/tools/man/ipa-ldap-updater.1 @@ -16,7 +16,7 @@ @@ -325,6 +364,19 @@ index fa02cfc76fa6bd076ebddde702036fa0b36f1413..e25f53eddca6cf1da1b631c1bf4ae275 .SH "NAME" ipa\-nis\-manage \- Enables or disables the NIS listener plugin .SH "SYNOPSIS" +diff --git a/install/tools/man/ipa-otptoken-import.1 b/install/tools/man/ipa-otptoken-import.1 +index 920a08ca2c2f996d6281483f5c65bac6b412d6d5..fe91040fabd1cad7c395aafd6afc68ed816a1951 100644 +--- a/install/tools/man/ipa-otptoken-import.1 ++++ b/install/tools/man/ipa-otptoken-import.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Nathaniel McCallum + .\" +-.TH "ipa-otptoken-import" "1" "Jun 12 2014" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-otptoken-import" "1" "Jun 12 2014" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-otptoken\-import \- Imports OTP tokens from RFC 6030 XML file + .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-replica-conncheck.1 b/install/tools/man/ipa-replica-conncheck.1 index 566322cf035bbb51d1ba8b14166a1b61375015da..7f220de96cc03a1f883f585740a82bff062f0ce9 100644 --- a/install/tools/man/ipa-replica-conncheck.1 @@ -352,7 +404,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 a981c72f59e23024110e0d9e8331cd50cbb22130..8703caa2baaf83211a5e64e4cd724c42a78a835f 100644 +index 8a7c78f39eeb6c7902ed99e7bed37e32eb0e92dc..2c162928dc7fa1567703019e2722a1c63914876d 100644 --- a/install/tools/man/ipa-replica-manage.1 +++ b/install/tools/man/ipa-replica-manage.1 @@ -16,7 +16,7 @@ @@ -365,7 +417,7 @@ index a981c72f59e23024110e0d9e8331cd50cbb22130..8703caa2baaf83211a5e64e4cd724c42 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 88c30757b38cfdfec36dce85e995d419dd05c17b..24b6464d1683f23c1a95c952a27b8a92adfbf385 100644 +index 7931b71ed6fceab059a51496d9289ce25eb86b4e..fd07aa55c3d107378733d0eb3c1a6f0467182d2a 100644 --- a/install/tools/man/ipa-replica-prepare.1 +++ b/install/tools/man/ipa-replica-prepare.1 @@ -16,7 +16,7 @@ @@ -391,7 +443,7 @@ index 31734b259524e4b07312a4009184e725aafc3728..689dc133fc4f526bffac0458b0c5c25f ipa\-restore \- Restore an IPA master .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-server-certinstall.1 b/install/tools/man/ipa-server-certinstall.1 -index ab293cf0fdcb2fb231c39f2a32eaa62842a94a94..023971db661d4c0bee495d14bd226534b50559c2 100644 +index d23bbd490e2b0454b8fb908e22f33c7a611c8874..d87b6bc16cfbea8f260d2767bf20eaac3562b050 100644 --- a/install/tools/man/ipa-server-certinstall.1 +++ b/install/tools/man/ipa-server-certinstall.1 @@ -16,7 +16,7 @@ @@ -404,7 +456,7 @@ index ab293cf0fdcb2fb231c39f2a32eaa62842a94a94..023971db661d4c0bee495d14bd226534 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 409dcf24beb6c53a9908437738fbbe3c90078367..807e1b38201c504b601a21751798a332d257e819 100644 +index 7343f323e5447c028bba36564172524690059342..1389f80f2e13f382b08b5b718b2d7eb46d3ff58e 100644 --- a/install/tools/man/ipa-server-install.1 +++ b/install/tools/man/ipa-server-install.1 @@ -16,7 +16,7 @@ @@ -417,7 +469,7 @@ index 409dcf24beb6c53a9908437738fbbe3c90078367..807e1b38201c504b601a21751798a332 ipa\-server\-install \- Configure an IPA server .SH "SYNOPSIS" diff --git a/install/tools/man/ipactl.8 b/install/tools/man/ipactl.8 -index 05be8e0e29f792ad2a2159ca3f8f38624a42ffa4..b9e4700858c7490298bac58c092fe97d2c6d3a19 100644 +index 5a1fd27ad6cb88877589173709c6cf0afa357fe1..0e6e339cef0a97c27b9e992a5082b2e47f00e7bd 100644 --- a/install/tools/man/ipactl.8 +++ b/install/tools/man/ipactl.8 @@ -16,7 +16,7 @@ @@ -430,48 +482,48 @@ index 05be8e0e29f792ad2a2159ca3f8f38624a42ffa4..b9e4700858c7490298bac58c092fe97d ipactl \- IPA Server Control Interface .SH "SYNOPSIS" diff --git a/install/ui/index.html b/install/ui/index.html -index 75ff829970a42c6efa0f62a61bf922d07fb779a5..7a71f815496a6651850d7076015f30c6df281fed 100644 +index ce9859074d52dd67a13afe823f2b0860eb9db8af..1ed43b0ca940d0ed8369e59cecac57cd236d8e58 100644 --- a/install/ui/index.html +++ b/install/ui/index.html @@ -2,7 +2,7 @@ - -- IPA: Identity Policy Audit -+ Identity Management - - - -diff --git a/install/ui/login.html b/install/ui/login.html -index 5545e8834a38fd24a6f0debf263a56402be42dbc..7b4d13962790e6b9457727424c37b41879a3404a 100644 ---- a/install/ui/login.html -+++ b/install/ui/login.html -@@ -2,7 +2,7 @@ - - - IPA: Identity Policy Audit + Identity Management - - -diff --git a/install/ui/logout.html b/install/ui/logout.html -index e356d2a5f9b59f0b516825fb039eaa4210dc5d98..80740069c9c3b3fa1b5ccbcf64487b4f1ab4a2cd 100644 ---- a/install/ui/logout.html -+++ b/install/ui/logout.html +