From ac7d03c67af81669700da761908f3f0de3d23372 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 01 2017 03:52:15 +0000 Subject: import ipa-4.5.0-20.el7 --- diff --git a/.gitignore b/.gitignore index e66632a..a43c0f8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -SOURCES/freeipa-4.4.0.tar.gz +SOURCES/freeipa-4.5.0.tar.gz SOURCES/header-logo.png SOURCES/login-screen-background.jpg SOURCES/login-screen-logo.png diff --git a/.ipa.metadata b/.ipa.metadata index 97596a6..61ded07 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1,4 +1,4 @@ -441ef8cb2b0ac103723d03b0478da641d697e104 SOURCES/freeipa-4.4.0.tar.gz +686e9b1375659524de83e1b78df66b355715438e SOURCES/freeipa-4.5.0.tar.gz 77c318cf1f4fc25cf847de0692a77859a767c0e3 SOURCES/header-logo.png 8727245558422bf966d60677568925f081b8e299 SOURCES/login-screen-background.jpg 24a29d79efbd0906777be4639957abda111fca4b SOURCES/login-screen-logo.png diff --git a/SOURCES/0001-Add-options-to-allow-ticket-caching.patch b/SOURCES/0001-Add-options-to-allow-ticket-caching.patch new file mode 100644 index 0000000..1c3b8e0 --- /dev/null +++ b/SOURCES/0001-Add-options-to-allow-ticket-caching.patch @@ -0,0 +1,39 @@ +From 6c4d53f843575d5e69a0c310cdb2e5026751faa4 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 6 Mar 2017 13:46:44 -0500 +Subject: [PATCH] Add options to allow ticket caching + +This new option (planned to land in gssproxy 0.7) we cache the ldap +ticket properly and avoid a ticket lookup to the KDC on each and every +ldap connection. (Also requires krb5 libs 1.15.1 to benefit from caching). + +Ticket: https://pagure.io/freeipa/issue/6771 + +Signed-off-by: Simo Sorce +Reviewed-By: Martin Babinsky +--- + install/share/gssproxy.conf.template | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/install/share/gssproxy.conf.template b/install/share/gssproxy.conf.template +index fbb158a689a430168ea9841d59cb558755371968..9d111009f5a5ba24dd474be336bf0cb27ab59aab 100644 +--- a/install/share/gssproxy.conf.template ++++ b/install/share/gssproxy.conf.template +@@ -4,6 +4,7 @@ + cred_store = keytab:$HTTP_KEYTAB + cred_store = client_keytab:$HTTP_KEYTAB + allow_protocol_transition = true ++ allow_client_ccache_sync = true + cred_usage = both + euid = $HTTPD_USER + +@@ -12,5 +13,6 @@ + cred_store = keytab:$HTTP_KEYTAB + cred_store = client_keytab:$HTTP_KEYTAB + allow_constrained_delegation = true ++ allow_client_ccache_sync = true + cred_usage = initiate + euid = $IPAAPI_USER +-- +2.12.0 + diff --git a/SOURCES/0001-Fix-incorrect-check-for-principal-type-when-evaluati.patch b/SOURCES/0001-Fix-incorrect-check-for-principal-type-when-evaluati.patch deleted file mode 100644 index 46921fd..0000000 --- a/SOURCES/0001-Fix-incorrect-check-for-principal-type-when-evaluati.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 808772d7426dae6924c62ca327116c3152729a8e Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Fri, 1 Jul 2016 11:55:47 +0200 -Subject: [PATCH] Fix incorrect check for principal type when evaluating CA - ACLs - -This error prevented hosts to request certificates for themselves. - -https://fedorahosted.org/freeipa/ticket/3864 - -Reviewed-By: Petr Spacek ---- - ipaserver/plugins/caacl.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/caacl.py b/ipaserver/plugins/caacl.py -index 3f813a7efb9e554abcb8dd2946eea73065c93414..9a60f7e27809c4f41b160647efafde94dbe90bf0 100644 ---- a/ipaserver/plugins/caacl.py -+++ b/ipaserver/plugins/caacl.py -@@ -64,8 +64,10 @@ def _acl_make_request(principal_type, principal, ca_id, profile_id): - req = pyhbac.HbacRequest() - req.targethost.name = ca_id - req.service.name = profile_id -- if principal_type == 'user' or principal_type == 'host': -+ if principal_type == 'user': - req.user.name = principal.username -+ elif principal_type == 'host': -+ req.user.name = principal.hostname - elif principal_type == 'service': - req.user.name = unicode(principal) - groups = [] --- -2.9.0 - diff --git a/SOURCES/0002-Use-connection-keep-alive.patch b/SOURCES/0002-Use-connection-keep-alive.patch new file mode 100644 index 0000000..c7320ea --- /dev/null +++ b/SOURCES/0002-Use-connection-keep-alive.patch @@ -0,0 +1,35 @@ +From 1216aaa3c5f5e3dc3a81de81633eaade15df1129 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Mon, 20 Mar 2017 08:47:41 +0100 +Subject: [PATCH] Use connection keep-alive + +Do not forcefully close the connection after every request. This enables +HTTP connection keep-alive, also known as persistent TCP and TLS/SSL +connection. Keep-alive speed up consecutive HTTP requests by 15% (for +local, low-latency network connections to a fast server) to multiple +times (high latency connections or remote peers). + +https://pagure.io/freeipa/issue/6641 + +Signed-off-by: Christian Heimes +Reviewed-By: Tomas Krizek +--- + ipalib/rpc.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index 16ffb8b541107e3ce1a84d143db007a1105b49b5..8d587180a65bd06b644c6df23ac9fb26eb7e97dd 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -686,7 +686,7 @@ class KerbTransport(SSLTransport): + return self.parse_response(response) + except gssapi.exceptions.GSSError as e: + self._handle_exception(e) +- finally: ++ except BaseException: + self.close() + + if six.PY3: +-- +2.12.1 + diff --git a/SOURCES/0002-uninstall-untrack-lightweight-CA-certs.patch b/SOURCES/0002-uninstall-untrack-lightweight-CA-certs.patch deleted file mode 100644 index 21fa9ec..0000000 --- a/SOURCES/0002-uninstall-untrack-lightweight-CA-certs.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 8235b85d6960356fd49affca40b1b609f3cae827 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Mon, 4 Jul 2016 13:05:28 +1000 -Subject: [PATCH] uninstall: untrack lightweight CA certs - -Fixes: https://fedorahosted.org/freeipa/ticket/6020 -Reviewed-By: Martin Babinsky ---- - ipaserver/install/cainstance.py | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 5e3e8c7f9a1845b82d23de589f804aa065387b38..070498fe8a394802ea55f848a268e2b6563ec472 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1127,6 +1127,12 @@ class CAInstance(DogtagInstance): - """ - super(CAInstance, self).stop_tracking_certificates(False) - -+ # stop tracking lightweight CA signing certs -+ for request_id in certmonger.get_requests_for_dir(self.nss_db): -+ nickname = certmonger.get_request_value(request_id, 'key-nickname') -+ if nickname.startswith('caSigningCert cert-pki-ca '): -+ certmonger.stop_tracking(self.nss_db, nickname=nickname) -+ - try: - certmonger.stop_tracking(paths.HTTPD_ALIAS_DIR, nickname='ipaCert') - except RuntimeError as e: --- -2.4.3 - diff --git a/SOURCES/0003-Add-debug-logging-for-keep-alive.patch b/SOURCES/0003-Add-debug-logging-for-keep-alive.patch new file mode 100644 index 0000000..4fc4f1d --- /dev/null +++ b/SOURCES/0003-Add-debug-logging-for-keep-alive.patch @@ -0,0 +1,68 @@ +From bdaf584ef5ebcae08e86142ceb80ebe56ac11fa3 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Mon, 20 Mar 2017 08:47:51 +0100 +Subject: [PATCH] Add debug logging for keep-alive + +Signed-off-by: Christian Heimes +Reviewed-By: Tomas Krizek +--- + ipalib/rpc.py | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index 8d587180a65bd06b644c6df23ac9fb26eb7e97dd..38321d17cf2c9529738aa45cc44bbd38b08b032b 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -79,6 +79,13 @@ except ImportError: + from xmlrpc.client import (Binary, Fault, DateTime, dumps, loads, ServerProxy, + Transport, ProtocolError, MININT, MAXINT) + ++# pylint: disable=import-error ++if six.PY3: ++ from http.client import RemoteDisconnected ++else: ++ from httplib import BadStatusLine as RemoteDisconnected ++# pylint: enable=import-error ++ + + if six.PY3: + unicode = str +@@ -531,6 +538,7 @@ class SSLTransport(LanguageAwareTransport): + host, self._extra_headers, _x509 = self.get_host_info(host) + + if self._connection and host == self._connection[0]: ++ root_logger.debug("HTTP connection keep-alive (%s)", host) + return self._connection[1] + + conn = create_https_connection( +@@ -540,6 +548,7 @@ class SSLTransport(LanguageAwareTransport): + tls_version_max=api.env.tls_version_max) + + conn.connect() ++ root_logger.debug("New HTTP connection (%s)", host) + + self._connection = host, conn + return self._connection[1] +@@ -686,8 +695,18 @@ class KerbTransport(SSLTransport): + return self.parse_response(response) + except gssapi.exceptions.GSSError as e: + self._handle_exception(e) +- except BaseException: ++ except RemoteDisconnected: ++ # keep-alive connection was terminated by remote peer, close ++ # connection and let transport handle reconnect for us. ++ self.close() ++ root_logger.debug("HTTP server has closed connection (%s)", host) ++ raise ++ except BaseException as e: ++ # Unexpected exception may leave connections in a bad state. + self.close() ++ root_logger.debug("HTTP connection destroyed (%s)", ++ host, exc_info=True) ++ raise + + if six.PY3: + def __send_request(self, connection, host, handler, request_body, debug): +-- +2.12.1 + diff --git a/SOURCES/0003-ipa-nis-manage-Use-server-API-to-retrieve-plugin-sta.patch b/SOURCES/0003-ipa-nis-manage-Use-server-API-to-retrieve-plugin-sta.patch deleted file mode 100644 index b0e8ae3..0000000 --- a/SOURCES/0003-ipa-nis-manage-Use-server-API-to-retrieve-plugin-sta.patch +++ /dev/null @@ -1,28 +0,0 @@ -From db7950c119f71df018ae1759933c0a8dca1072df Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Mon, 4 Jul 2016 13:33:10 +0200 -Subject: [PATCH] ipa-nis-manage: Use server API to retrieve plugin status - -https://fedorahosted.org/freeipa/ticket/6027 - -Reviewed-By: Florence Blanc-Renaud ---- - install/tools/ipa-nis-manage | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/tools/ipa-nis-manage b/install/tools/ipa-nis-manage -index f70961309c34e48ea1b4c1b144c9c0df5860f667..64de9e848ff7c382ddaea0729352da2584be6031 100755 ---- a/install/tools/ipa-nis-manage -+++ b/install/tools/ipa-nis-manage -@@ -116,7 +116,7 @@ def main(): - if not dirman_password: - sys.exit("No password supplied") - -- api.bootstrap(context='cli', debug=options.debug) -+ api.bootstrap(context='cli', debug=options.debug, in_server=True) - api.finalize() - - conn = None --- -2.4.3 - diff --git a/SOURCES/0004-Increase-Apache-HTTPD-s-default-keep-alive-timeout.patch b/SOURCES/0004-Increase-Apache-HTTPD-s-default-keep-alive-timeout.patch new file mode 100644 index 0000000..4750bad --- /dev/null +++ b/SOURCES/0004-Increase-Apache-HTTPD-s-default-keep-alive-timeout.patch @@ -0,0 +1,41 @@ +From 2905ebdb1a6c668da1a12d79824c6710e3f0eb94 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Mon, 20 Mar 2017 08:47:56 +0100 +Subject: [PATCH] Increase Apache HTTPD's default keep alive timeout + +Apache has a default keep alive timeout of 5 seconds. That's too low for +interactive commands, e.g. password prompts. 30 seconds sounds like a +good compromise. + +Signed-off-by: Christian Heimes +Reviewed-By: Tomas Krizek +--- + install/conf/ipa.conf | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf +index 164231c729a8b3d64982ea0d9592e949635d7418..e1f1a581b4e8a91b899bcf165ca81f266fa9e516 100644 +--- a/install/conf/ipa.conf ++++ b/install/conf/ipa.conf +@@ -1,5 +1,5 @@ + # +-# VERSION 24 - DO NOT REMOVE THIS LINE ++# VERSION 25 - DO NOT REMOVE THIS LINE + # + # This file may be overwritten on upgrades. + # +@@ -20,6 +20,11 @@ DirectoryIndex index.html + # requests, ticket #2767. This should easily support a 64KiB PAC. + LimitRequestFieldSize 100000 + ++# Increase connection keep alive time. Default value is 5 seconds, which is too ++# short for interactive ipa commands. 30 seconds is a good compromise. ++KeepAlive On ++KeepAliveTimeout 30 ++ + # ipa-rewrite.conf is loaded separately + + # This is required so the auto-configuration works with Firefox 2+ +-- +2.12.1 + diff --git a/SOURCES/0004-ipa-compat-manage-use-server-API-to-retrieve-plugin-.patch b/SOURCES/0004-ipa-compat-manage-use-server-API-to-retrieve-plugin-.patch deleted file mode 100644 index a74f4d0..0000000 --- a/SOURCES/0004-ipa-compat-manage-use-server-API-to-retrieve-plugin-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5d699a0bff0c42220d68fac54d08fbcdd2daae67 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Mon, 11 Jul 2016 10:46:34 +0200 -Subject: [PATCH] ipa-compat-manage: use server API to retrieve plugin status - -https://fedorahosted.org/freeipa/ticket/6033 - -Reviewed-By: Stanislav Laznicka ---- - install/tools/ipa-compat-manage | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage -index 2b13c4a68531c7b6261465399b59225db094aba2..178cef9792c703f868fa3639a3a570b963dc7ed6 100755 ---- a/install/tools/ipa-compat-manage -+++ b/install/tools/ipa-compat-manage -@@ -103,7 +103,7 @@ def main(): - if dirman_password is None: - sys.exit("Directory Manager password required") - -- api.bootstrap(context='cli', debug=options.debug) -+ api.bootstrap(context='cli', in_server=True, debug=options.debug) - api.finalize() - - conn = None --- -2.4.3 - diff --git a/SOURCES/0005-ipa-advise-correct-handling-of-plugin-namespace-iter.patch b/SOURCES/0005-ipa-advise-correct-handling-of-plugin-namespace-iter.patch deleted file mode 100644 index e55904e..0000000 --- a/SOURCES/0005-ipa-advise-correct-handling-of-plugin-namespace-iter.patch +++ /dev/null @@ -1,40 +0,0 @@ -From c4d5331ec5361a5f607eca7bb576d5d387bf3824 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Mon, 11 Jul 2016 14:03:36 +0200 -Subject: [PATCH] ipa-advise: correct handling of plugin namespace iteration - -The API object namespace iterators now yield plugin classes themselves -instead of their names as strings. The method enumerating through available -plugins needs to be made aware of this change. - -https://fedorahosted.org/freeipa/ticket/6044 - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/advise/base.py | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/advise/base.py b/ipaserver/advise/base.py -index d083a3c506074f0adbb49e7a6d9935b8d338e941..a2dc9ccee93811da415c1e1eb0b57f47ac817a3f 100644 ---- a/ipaserver/advise/base.py -+++ b/ipaserver/advise/base.py -@@ -167,12 +167,12 @@ class IpaAdvise(admintool.AdminTool): - def print_config_list(self): - self.print_header('List of available advices') - -- max_keyword_len = max((len(keyword) for keyword in advise_api.Advice)) -+ max_keyword_len = max( -+ (len(advice.__name__) for advice in advise_api.Advice)) - -- for keyword in advise_api.Advice: -- advice = getattr(advise_api.Advice, keyword, '') -+ for advice in advise_api.Advice: - description = getattr(advice, 'description', '') -- keyword = keyword.replace('_', '-') -+ keyword = advice.__name__.replace('_', '-') - - # Compute the number of spaces needed for the table to be aligned - offset = max_keyword_len - len(keyword) --- -2.4.3 - diff --git a/SOURCES/0005-ipapython.ipautil.nolog_replace-Do-not-replace-empty.patch b/SOURCES/0005-ipapython.ipautil.nolog_replace-Do-not-replace-empty.patch new file mode 100644 index 0000000..188c635 --- /dev/null +++ b/SOURCES/0005-ipapython.ipautil.nolog_replace-Do-not-replace-empty.patch @@ -0,0 +1,32 @@ +From fef78a011c148f63a08014bbe7ed2d63fe3380bd Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Mon, 20 Mar 2017 12:48:14 +0100 +Subject: [PATCH] ipapython.ipautil.nolog_replace: Do not replace empty value + +When provided empty value in nolog parameter nolog_replace added 'XXXXXXXX' +three (once for plain value, once for http quoted value and last time for shell +quoted value) times before every character (including terminating '\0') in the string. + +https://pagure.io/freeipa/issue/6738 + +Reviewed-By: Pavel Vomacka +--- + ipapython/ipautil.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 60b4a37fe247624e826d0f6516cb9a25d30ae75d..cd66328e6c9a0f69e6f83582a9d288ac239c5be3 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -505,7 +505,7 @@ def run(args, stdin=None, raiseonerr=True, nolog=(), env=None, + def nolog_replace(string, nolog): + """Replace occurences of strings given in `nolog` with XXXXXXXX""" + for value in nolog: +- if not isinstance(value, six.string_types): ++ if not value or not isinstance(value, six.string_types): + continue + + quoted = urllib.parse.quote(value) +-- +2.12.1 + diff --git a/SOURCES/0006-kdb-check-for-local-realm-in-enterprise-principals.patch b/SOURCES/0006-kdb-check-for-local-realm-in-enterprise-principals.patch deleted file mode 100644 index fd02aa9..0000000 --- a/SOURCES/0006-kdb-check-for-local-realm-in-enterprise-principals.patch +++ /dev/null @@ -1,89 +0,0 @@ -From ed178aad6751ea7673d8e730bd5a6709921a1ff0 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 6 Jul 2016 17:29:37 +0200 -Subject: [PATCH] kdb: check for local realm in enterprise principals - -Reviewed-By: Martin Babinsky -Reviewed-By: Jakub Hrozek ---- - daemons/ipa-kdb/ipa_kdb_principals.c | 52 +++++++++++++++++++++++++++--------- - 1 file changed, 40 insertions(+), 12 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c -index 6cdfa909452a4b55912b2a5a74648abd2053482a..5b80909475565d6bb4fa8cba67629094daf51eb3 100644 ---- a/daemons/ipa-kdb/ipa_kdb_principals.c -+++ b/daemons/ipa-kdb/ipa_kdb_principals.c -@@ -1198,30 +1198,58 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext, - /* skip '@' and use part after '@' as an enterprise realm for comparison */ - realm++; - -- kerr = ipadb_is_princ_from_trusted_realm(kcontext, -- realm, -- upn->length - (realm - upn->data), -- &trusted_realm); -- if (kerr == 0) { -- kentry = calloc(1, sizeof(krb5_db_entry)); -- if (!kentry) { -+ /* check for our realm */ -+ if (strncasecmp(ipactx->realm, realm, -+ upn->length - (realm - upn->data)) == 0) { -+ /* it looks like it is ok to use malloc'ed strings as principal */ -+ krb5_free_unparsed_name(kcontext, principal); -+ principal = strndup((const char *) upn->data, upn->length); -+ if (principal == NULL) { - kerr = ENOMEM; - goto done; - } -- kerr = krb5_parse_name(kcontext, principal, -- &kentry->princ); -+ -+ ldap_msgfree(res); -+ res = NULL; -+ kerr = ipadb_fetch_principals(ipactx, flags, principal, &res); - if (kerr != 0) { - goto done; - } - -- kerr = krb5_set_principal_realm(kcontext, kentry->princ, trusted_realm); -+ kerr = ipadb_find_principal(kcontext, flags, res, &principal, -+ &lentry); - if (kerr != 0) { - goto done; - } -- *entry = kentry; -+ } else { -+ -+ kerr = ipadb_is_princ_from_trusted_realm(kcontext, -+ realm, -+ upn->length - (realm - upn->data), -+ &trusted_realm); -+ if (kerr == 0) { -+ kentry = calloc(1, sizeof(krb5_db_entry)); -+ if (!kentry) { -+ kerr = ENOMEM; -+ goto done; -+ } -+ kerr = krb5_parse_name(kcontext, principal, -+ &kentry->princ); -+ if (kerr != 0) { -+ goto done; -+ } -+ -+ kerr = krb5_set_principal_realm(kcontext, kentry->princ, trusted_realm); -+ if (kerr != 0) { -+ goto done; -+ } -+ *entry = kentry; -+ } -+ goto done; - } -+ } else { -+ goto done; - } -- goto done; - } - - kerr = ipadb_parse_ldap_entry(kcontext, principal, lentry, entry, &pol); --- -2.4.3 - diff --git a/SOURCES/0006-tasks-run-systemctl-daemon-reload-after-httpd.servic.patch b/SOURCES/0006-tasks-run-systemctl-daemon-reload-after-httpd.servic.patch new file mode 100644 index 0000000..15450ff --- /dev/null +++ b/SOURCES/0006-tasks-run-systemctl-daemon-reload-after-httpd.servic.patch @@ -0,0 +1,49 @@ +From d8a9ed4e2fc164962d76773b57277f97bca84270 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 16 Mar 2017 12:51:29 +0000 +Subject: [PATCH] tasks: run `systemctl daemon-reload` after httpd.service.d + updates + +Run `systemctl daemon-reload` after +`/etc/systemd/system/httpd.service.d/ipa.conf` is created or deleted, +otherwise systemd will not merge the file into httpd.service and therefore +required environment variables will not be set for httpd. + +This fixes authentication failures ("No valid Negotiate header in server +response") due to missing `GSS_USE_PROXY=yes` in httpd environment. + +https://pagure.io/freeipa/issue/6773 + +Reviewed-By: Martin Babinsky +--- + ipaplatform/redhat/tasks.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index c1b574e06fc52839b684cbe96587365fa107b2eb..d0ef5fbd1ceb8110dd417dda44a74dc63898456a 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -483,6 +483,9 @@ class RedHatTaskNamespace(BaseTaskNamespace): + os.chmod(paths.SYSTEMD_SYSTEM_HTTPD_IPA_CONF, 0o644) + self.restore_context(paths.SYSTEMD_SYSTEM_HTTPD_IPA_CONF) + ++ ipautil.run([paths.SYSTEMCTL, "--system", "daemon-reload"], ++ raiseonerr=False) ++ + def configure_http_gssproxy_conf(self): + ipautil.copy_template_file( + os.path.join(paths.USR_SHARE_IPA_DIR, 'gssproxy.conf.template'), +@@ -513,6 +516,10 @@ class RedHatTaskNamespace(BaseTaskNamespace): + 'Error removing %s: %s', + paths.SYSTEMD_SYSTEM_HTTPD_IPA_CONF, e + ) ++ return ++ ++ ipautil.run([paths.SYSTEMCTL, "--system", "daemon-reload"], ++ raiseonerr=False) + + def set_hostname(self, hostname): + ipautil.run([paths.BIN_HOSTNAMECTL, 'set-hostname', hostname]) +-- +2.12.1 + diff --git a/SOURCES/0007-Enable-vault-commands-on-client.patch b/SOURCES/0007-Enable-vault-commands-on-client.patch deleted file mode 100644 index 59fd755..0000000 --- a/SOURCES/0007-Enable-vault-commands-on-client.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 0d3f6f147382625fc326a6f84bb6a950dd4386b1 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 8 Jul 2016 15:53:25 +0200 -Subject: [PATCH] Enable vault-* commands on client - -Client plugins fot vault commands were disabled by NO_CLI=True, -inherited from vault_add_interal, that is always NO_CLI=True. -Introduced by this commit 8278da6967dbe425b4e0c6cf37dc1c53052525b2 - -Removed NO_CLI=True from client side plugins for vault. - -https://fedorahosted.org/freeipa/ticket/6035 - -Reviewed-By: Martin Babinsky -Reviewed-By: Alexander Bokovoy ---- - ipaclient/plugins/vault.py | 16 ---------------- - 1 file changed, 16 deletions(-) - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index 11210d6e1339f42598b39bcf599d3e6eacb5b9d8..bf0242fc4290bb94f29faf9c787dd7454a8921bf 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -202,10 +202,6 @@ class vault_add(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return self.api.Command.vault_add_internal.NO_CLI -- - def get_args(self): - for arg in self.api.Command.vault_add_internal.args(): - yield arg -@@ -394,10 +390,6 @@ class vault_mod(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return self.api.Command.vault_mod_internal.NO_CLI -- - def get_args(self): - for arg in self.api.Command.vault_mod_internal.args(): - yield arg -@@ -572,10 +564,6 @@ class vault_archive(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return self.api.Command.vault_archive_internal.NO_CLI -- - def get_args(self): - for arg in self.api.Command.vault_archive_internal.args(): - yield arg -@@ -820,10 +808,6 @@ class vault_retrieve(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return self.api.Command.vault_retrieve_internal.NO_CLI -- - def get_args(self): - for arg in self.api.Command.vault_retrieve_internal.args(): - yield arg --- -2.4.3 - diff --git a/SOURCES/0007-man-ipa-cacert-manage-install-needs-clarification.patch b/SOURCES/0007-man-ipa-cacert-manage-install-needs-clarification.patch new file mode 100644 index 0000000..def7c31 --- /dev/null +++ b/SOURCES/0007-man-ipa-cacert-manage-install-needs-clarification.patch @@ -0,0 +1,31 @@ +From 9d5e8f44210f661850ec67f92909534dd52c2ee8 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 22 Mar 2017 08:49:39 +0100 +Subject: [PATCH] man ipa-cacert-manage install needs clarification + +The customers are often confused by ipa-cacert-manage install. The man page +should make it clear that IPA CA is not modified in any way by this command. + +https://pagure.io/freeipa/issue/6795 + +Reviewed-By: Tomas Krizek +--- + install/tools/man/ipa-cacert-manage.1 | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/install/tools/man/ipa-cacert-manage.1 b/install/tools/man/ipa-cacert-manage.1 +index 4515d7c404054139725fd47f366706cb1e222be5..128edd8bd2500a09f406da8dc01a53b269007ab0 100644 +--- a/install/tools/man/ipa-cacert-manage.1 ++++ b/install/tools/man/ipa-cacert-manage.1 +@@ -46,6 +46,8 @@ When the IPA CA is not configured, this command is not available. + .RS + This command can be used to install the certificate contained in \fICERTFILE\fR as an additional CA certificate to IPA. + .sp ++Important: this does not replace IPA CA but adds the provided certificate as a known CA. This is useful for instance when using ipa-server-certinstall to replace HTTP/LDAP certificates with third-party certificates signed by this additional CA. ++.sp + Please do not forget to run ipa-certupdate on the master, all the replicas and all the clients after this command in order to update IPA certificates databases. + .RE + .SH "COMMON OPTIONS" +-- +2.12.1 + diff --git a/SOURCES/0008-certs-do-not-implicitly-create-DS-pin.txt.patch b/SOURCES/0008-certs-do-not-implicitly-create-DS-pin.txt.patch new file mode 100644 index 0000000..caea419 --- /dev/null +++ b/SOURCES/0008-certs-do-not-implicitly-create-DS-pin.txt.patch @@ -0,0 +1,48 @@ +From 846b1c9b72f539cbe4b8d6e23de81e03b1afec9e Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 14 Mar 2017 09:32:17 +0100 +Subject: [PATCH] certs: do not implicitly create DS pin.txt + +Do not implicitly create DS pin.txt in `CertDB.init_from_pkcs12()`, create +it explicitly in `DSInstance.__enable_ssl()`. + +This stops the file from being created in /etc/httpd/alias during classic +replica install. + +https://pagure.io/freeipa/issue/4639 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/certs.py | 1 - + ipaserver/install/dsinstance.py | 3 ++- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 63e7887c4e73a8346d4eb5d865ddc89c07247573..9f340b8678c55cffe2872df97c643c34857cfaa9 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -635,7 +635,6 @@ class CertDB(object): + self.cacert_name = ca_names[-1] + self.trust_root_cert(self.cacert_name, trust_flags) + +- self.create_pin_file() + self.export_ca_cert(nickname, False) + + def publish_ca_cert(self, location): +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 91cc180e62b9532e716c07c493b359567b20c749..79dc90e92cac49a2b64ff6645f75dc3a8cbcc104 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -838,7 +838,8 @@ class DsInstance(service.Service): + certmonger.modify_ca_helper('IPA', prev_helper) + + self.dercert = dsdb.get_cert_from_db(self.nickname, pem=False) +- dsdb.create_pin_file() ++ ++ dsdb.create_pin_file() + + self.cacert_name = dsdb.cacert_name + +-- +2.12.1 + diff --git a/SOURCES/0008-vault-add-set-the-default-vault-type-on-the-client-s.patch b/SOURCES/0008-vault-add-set-the-default-vault-type-on-the-client-s.patch deleted file mode 100644 index 5045dea..0000000 --- a/SOURCES/0008-vault-add-set-the-default-vault-type-on-the-client-s.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 5754f00a924bd74079fbf8dc386437ef671547b0 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Tue, 12 Jul 2016 13:44:49 +0200 -Subject: [PATCH] vault-add: set the default vault type on the client side if - none was given - -`vault-add` commands does much processing depending on the vault type even -before the request is forwarded to remote server. Since default values for -parameters are now filled only on server side, the client-side logic would -fail if the vault type was not explicitly given. In this case we have to -retrieve and use the default vault type from schema. - -https://fedorahosted.org/freeipa/ticket/6047 - -Reviewed-By: Stanislav Laznicka ---- - ipaclient/plugins/vault.py | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index bf0242fc4290bb94f29faf9c787dd7454a8921bf..a3ce6fecbfd38b342f826d8d27940d991d821e90 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -221,6 +221,11 @@ class vault_add(Local): - def forward(self, *args, **options): - - vault_type = options.get('ipavaulttype') -+ -+ if vault_type is None: -+ internal_cmd = self.api.Command.vault_add_internal -+ vault_type = internal_cmd.params.ipavaulttype.default -+ - password = options.get('password') - password_file = options.get('password_file') - public_key = options.get('ipavaultpublickey') --- -2.4.3 - diff --git a/SOURCES/0009-caacl-expand-plugin-documentation.patch b/SOURCES/0009-caacl-expand-plugin-documentation.patch deleted file mode 100644 index 3b5a6c2..0000000 --- a/SOURCES/0009-caacl-expand-plugin-documentation.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 39fdccd9216c7a58ba48ed2226a5588a4f19da51 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Tue, 12 Jul 2016 15:11:11 +1000 -Subject: [PATCH] caacl: expand plugin documentation - -Expand the 'caacl' plugin documentation to explain some common -confusions including the fact that CA ACLs apply to the target -subject principal (not necessarily the principal requesting the -cert), and the fact that CA-less CA ACL implies the 'ipa' CA. - -Fixes: https://fedorahosted.org/freeipa/ticket/6002 -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/caacl.py | 34 ++++++++++++++++++++++++++++------ - 1 file changed, 28 insertions(+), 6 deletions(-) - -diff --git a/ipaserver/plugins/caacl.py b/ipaserver/plugins/caacl.py -index 3f813a7efb9e554abcb8dd2946eea73065c93414..1461c4814727e5774219ac206bab3d078f2daa7d 100644 ---- a/ipaserver/plugins/caacl.py -+++ b/ipaserver/plugins/caacl.py -@@ -23,14 +23,36 @@ if six.PY3: - __doc__ = _(""" - Manage CA ACL rules. - --This plugin is used to define rules governing which principals are --permitted to have certificates issued using a given certificate --profile. -+This plugin is used to define rules governing which CAs and profiles -+may be used to issue certificates to particular principals or groups -+of principals. - --PROFILE ID SYNTAX: -+SUBJECT PRINCIPAL SCOPE: - --A Profile ID is a string without spaces or punctuation starting with a letter --and followed by a sequence of letters, digits or underscore ("_"). -+For a certificate request to be allowed, the principal(s) that are -+the subject of a certificate request (not necessarily the principal -+actually requesting the certificate) must be included in the scope -+of a CA ACL that also includes the target CA and profile. -+ -+Users can be included by name, group or the "all users" category. -+Hosts can be included by name, hostgroup or the "all hosts" -+category. Services can be included by service name or the "all -+services" category. CA ACLs may be associated with a single type of -+principal, or multiple types. -+ -+CERTIFICATE AUTHORITY SCOPE: -+ -+A CA ACL can be associated with one or more CAs by name, or by the -+"all CAs" category. For compatibility reasons, a CA ACL with no CA -+association implies an association with the 'ipa' CA (and only this -+CA). -+ -+PROFILE SCOPE: -+ -+A CA ACL can be associated with one or more profiles by Profile ID. -+The Profile ID is a string without spaces or punctuation starting -+with a letter and followed by a sequence of letters, digits or -+underscore ("_"). - - EXAMPLES: - --- -2.4.3 - diff --git a/SOURCES/0009-httpinstance-clean-up-etc-httpd-alias-on-uninstall.patch b/SOURCES/0009-httpinstance-clean-up-etc-httpd-alias-on-uninstall.patch new file mode 100644 index 0000000..c26e495 --- /dev/null +++ b/SOURCES/0009-httpinstance-clean-up-etc-httpd-alias-on-uninstall.patch @@ -0,0 +1,74 @@ +From 10e74165a827377ed3318d4d2b974fdbf0fab9db Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 8 Mar 2017 14:24:15 +0000 +Subject: [PATCH] httpinstance: clean up /etc/httpd/alias on uninstall + +Restore cert8.db, key3.db, pwdfile.txt and secmod.db in /etc/httpd/alias +from backup on uninstall. + +Files modified by IPA are kept with .ipasave suffix. + +https://pagure.io/freeipa/issue/4639 + +Reviewed-By: Martin Babinsky +--- + ipapython/certdb.py | 13 +++++++++++++ + ipaserver/install/certs.py | 3 +++ + ipaserver/install/httpinstance.py | 3 +++ + 3 files changed, 19 insertions(+) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index 6c89e778068d9ed1e9939077f7114463776e3516..f1410e5ae4290263573e9554ab4e66873d4344a1 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -169,6 +169,19 @@ class NSSDatabase(object): + new_mode = filemode + os.chmod(path, new_mode) + ++ def restore(self): ++ for filename in NSS_FILES: ++ path = os.path.join(self.secdir, filename) ++ backup_path = path + '.orig' ++ save_path = path + '.ipasave' ++ try: ++ if os.path.exists(path): ++ os.rename(path, save_path) ++ if os.path.exists(backup_path): ++ os.rename(backup_path, path) ++ except OSError as e: ++ root_logger.debug(e) ++ + def list_certs(self): + """Return nicknames and cert flags for all certs in the database + +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 9f340b8678c55cffe2872df97c643c34857cfaa9..0ca971358030db6a6e7e410e58a984675bcf53ac 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -234,6 +234,9 @@ class CertDB(object): + backup=True) + self.set_perms(self.passwd_fname, write=True) + ++ def restore(self): ++ self.nssdb.restore() ++ + def list_certs(self): + """ + Return a tuple of tuples containing (nickname, trust) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index ca3bcc87eec2c93a664db517df3eddecaaf565c2..f6f0b0c4f6acd648aa9f6f5d7400617613245473 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -555,6 +555,9 @@ class HTTPInstance(service.Service): + ca_iface.Set('org.fedorahosted.certmonger.ca', + 'external-helper', helper) + ++ db = certs.CertDB(self.realm, paths.HTTPD_ALIAS_DIR) ++ db.restore() ++ + for f in [paths.HTTPD_IPA_CONF, paths.HTTPD_SSL_CONF, paths.HTTPD_NSS_CONF]: + try: + self.fstore.restore_file(f) +-- +2.12.1 + diff --git a/SOURCES/0010-Fixing-replica-install-fix-ldap-connection-in-domlvl.patch b/SOURCES/0010-Fixing-replica-install-fix-ldap-connection-in-domlvl.patch new file mode 100644 index 0000000..0664301 --- /dev/null +++ b/SOURCES/0010-Fixing-replica-install-fix-ldap-connection-in-domlvl.patch @@ -0,0 +1,43 @@ +From 175c29c7b57a0ab48d1371c199e70f3435a0ead7 Mon Sep 17 00:00:00 2001 +From: felipe +Date: Tue, 21 Mar 2017 09:05:56 -0300 +Subject: [PATCH] Fixing replica install: fix ldap connection in domlvl 0 + +Now, at the domain level 0, the replica install always uses +Directory Manager credentials to create the LDAP connection. +Since ACIs permitting hosts to manage their own services were +added in 4.2 release, the old master denies this operations. + +https://pagure.io/freeipa/issue/6549 + +Reviewed-By: Martin Basti +Reviewed-By: Jan Cholasta +--- + ipaserver/install/server/replicainstall.py | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index b4463fd4066efbc68f22e4f8f3175b59cb20b103..f489e691999fd9d6e82879341922510e56eac47d 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1391,7 +1391,16 @@ def install(installer): + dsinstance.create_ds_user() + + try: +- conn.connect(ccache=ccache) ++ if promote: ++ conn.connect(ccache=ccache) ++ else: ++ # dmlvl 0 replica install should always use DM credentials ++ # to create remote LDAP connection. Since ACIs permitting hosts ++ # to manage their own services were added in 4.2 release, ++ # the master denies this operations. ++ conn.connect(bind_dn=ipaldap.DIRMAN_DN, cacert=cafile, ++ bind_pw=config.dirman_password) ++ + # Update and istall updated CA file + cafile = install_ca_cert(conn, api.env.basedn, api.env.realm, cafile) + +-- +2.12.1 + diff --git a/SOURCES/0010-host-find-do-not-show-SSH-key-by-default.patch b/SOURCES/0010-host-find-do-not-show-SSH-key-by-default.patch deleted file mode 100644 index 387dc4d..0000000 --- a/SOURCES/0010-host-find-do-not-show-SSH-key-by-default.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 058e260ac530f09f5fb5566a14a87614c4bdff63 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 8 Jul 2016 13:40:02 +0200 -Subject: [PATCH] host-find: do not show SSH key by default - -Only function 'remove_sshpubkey_from_output_list_post' should be used in -postcallbacks of *-find, otherwise only one entry will be cleaned up - -https://fedorahosted.org/freeipa/ticket/6043 - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/plugins/host.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py -index 2c5cf48cb80c6a49b6577836231a19cd13d824e2..f342b05c87b936ab7b99009cfb0f6d3acde4ef93 100644 ---- a/ipaserver/plugins/host.py -+++ b/ipaserver/plugins/host.py -@@ -1077,7 +1077,6 @@ class host_find(LDAPSearch): - entry_attrs['managing'] = self.obj.get_managed_hosts(entry_attrs.dn) - - convert_sshpubkey_post(entry_attrs) -- remove_sshpubkey_from_output_post(self.context, entry_attrs) - convert_ipaassignedidview_post(entry_attrs, options) - - remove_sshpubkey_from_output_list_post(self.context, entries) --- -2.4.3 - diff --git a/SOURCES/0011-Removed-unused-method-parameter-from-migrate-ds.patch b/SOURCES/0011-Removed-unused-method-parameter-from-migrate-ds.patch deleted file mode 100644 index 97510ab..0000000 --- a/SOURCES/0011-Removed-unused-method-parameter-from-migrate-ds.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 4132b63a5e02b019826053a07b2be79c879c1f6e Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka -Date: Mon, 11 Jul 2016 12:31:39 +0200 -Subject: [PATCH] Removed unused method parameter from migrate-ds - -An extra parameter on client side command override of migrate-ds output -was causing errors. - -https://fedorahosted.org/freeipa/ticket/6034 - -Reviewed-By: Martin Babinsky ---- - ipaclient/plugins/migration.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaclient/plugins/migration.py b/ipaclient/plugins/migration.py -index 8ac5f66bf1440b245c1268cd97d5a3e0dc2e6226..cf8d461bfa144f1287ef36a231f553fd9cd102b3 100644 ---- a/ipaclient/plugins/migration.py -+++ b/ipaclient/plugins/migration.py -@@ -50,7 +50,7 @@ can use their Kerberos accounts.''') - option = option.clone_retype(option.name, File) - yield option - -- def output_for_cli(self, textui, result, ldapuri, bindpw, **options): -+ def output_for_cli(self, textui, result, ldapuri, **options): - textui.print_name(self.name) - if not result['enabled']: - textui.print_plain(self.migration_disabled_msg) --- -2.4.3 - diff --git a/SOURCES/0011-replica-prepare-fix-wrong-IPA-CA-nickname-in-replica.patch b/SOURCES/0011-replica-prepare-fix-wrong-IPA-CA-nickname-in-replica.patch new file mode 100644 index 0000000..7b96d06 --- /dev/null +++ b/SOURCES/0011-replica-prepare-fix-wrong-IPA-CA-nickname-in-replica.patch @@ -0,0 +1,51 @@ +From c34fa1891b774e98de6a1787001f2215ea85c0f3 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Fri, 17 Mar 2017 09:34:08 +0000 +Subject: [PATCH] replica prepare: fix wrong IPA CA nickname in replica file + +Lookup IPA CA subject and pass it to CertDB when creating dscert.p12 and +httpcert.p12, otherwise a generic nickname will be used for the IPA CA +certificate instead of "$REALM IPA CA". + +This fixes replica install on domain level 0 from a replica file created +using ipa-replica-install on IPA 4.5. + +https://pagure.io/freeipa/issue/6777 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/ipa_replica_prepare.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py +index f4925a6c46b6714362545ee5e8194b7b02de5091..95c3818a9fc34c937f8b418e91a1bfc28352b02e 100644 +--- a/ipaserver/install/ipa_replica_prepare.py ++++ b/ipaserver/install/ipa_replica_prepare.py +@@ -34,7 +34,7 @@ import dns.resolver + from six.moves.configparser import SafeConfigParser + # pylint: enable=import-error + +-from ipaserver.install import certs, installutils, bindinstance, dsinstance ++from ipaserver.install import certs, installutils, bindinstance, dsinstance, ca + from ipaserver.install.replication import enable_replication_version_checking + from ipaserver.install.server.replicainstall import install_ca_cert + from ipaserver.install.bindinstance import ( +@@ -537,12 +537,13 @@ class ReplicaPrepare(admintool.AdminTool): + """ + hostname = self.replica_fqdn + subject_base = self.subject_base ++ ca_subject = ca.lookup_ca_subject(api, subject_base) + nickname = "Server-Cert" + + try: + db = certs.CertDB( +- api.env.realm, nssdir=self.dir, subject_base=subject_base, +- host_name=api.env.host) ++ api.env.realm, nssdir=self.dir, host_name=api.env.host, ++ subject_base=subject_base, ca_subject=ca_subject) + db.create_passwd_file() + db.create_from_cacert() + db.create_server_cert(nickname, hostname) +-- +2.12.1 + diff --git a/SOURCES/0012-Preserve-user-principal-aliases-during-rename-operat.patch b/SOURCES/0012-Preserve-user-principal-aliases-during-rename-operat.patch deleted file mode 100644 index b897bc3..0000000 --- a/SOURCES/0012-Preserve-user-principal-aliases-during-rename-operat.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 07ff43d198055bc5b95a0acdf516216d00a85cc3 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Fri, 1 Jul 2016 18:09:04 +0200 -Subject: [PATCH] Preserve user principal aliases during rename operation - -When a MODRDN is performed on the user entry, the MODRDN plugin resets both -krbPrincipalName and krbCanonicalName to the value constructed from uid. In -doing so, hovewer, any principal aliases added to the krbPrincipalName are -wiped clean. In this patch old aliases are fetched before the MODRDN operation -takes place and inserted back after it is performed. - -This also preserves previous user logins which can be used further for -authentication as aliases. - -https://fedorahosted.org/freeipa/ticket/6028 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Simo Sorce ---- - ipaserver/plugins/baseuser.py | 46 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 46 insertions(+) - -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index 0052e718afe639bcc1c0a698ded39ea8407a0551..e4288a5a131157815ffb2452692a7edb342f6ac3 100644 ---- a/ipaserver/plugins/baseuser.py -+++ b/ipaserver/plugins/baseuser.py -@@ -498,6 +498,50 @@ class baseuser_mod(LDAPUpdate): - len = int(config.get('ipamaxusernamelength')[0]) - ) - ) -+ -+ def preserve_krbprincipalname_pre(self, ldap, entry_attrs, *keys, **options): -+ """ -+ preserve user principal aliases during rename operation. This is the -+ pre-callback part of this. Another method called during post-callback -+ shall insert the principals back -+ """ -+ if options.get('rename', None) is None: -+ return -+ -+ try: -+ old_entry = ldap.get_entry( -+ entry_attrs.dn, attrs_list=( -+ 'krbprincipalname', 'krbcanonicalname')) -+ -+ if 'krbcanonicalname' not in old_entry: -+ return -+ except errors.NotFound: -+ self.obj.handle_not_found(*keys) -+ -+ self.context.krbprincipalname = old_entry.get( -+ 'krbprincipalname', []) -+ -+ def preserve_krbprincipalname_post(self, ldap, entry_attrs, **options): -+ """ -+ Insert the preserved aliases back to the user entry during rename -+ operation -+ """ -+ if options.get('rename', None) is None or not hasattr( -+ self.context, 'krbprincipalname'): -+ return -+ -+ obj_pkey = self.obj.get_primary_key_from_dn(entry_attrs.dn) -+ canonical_name = entry_attrs['krbcanonicalname'][0] -+ -+ principals_to_add = tuple(p for p in self.context.krbprincipalname if -+ p != canonical_name) -+ -+ if principals_to_add: -+ result = self.api.Command.user_add_principal( -+ obj_pkey, principals_to_add)['result'] -+ -+ entry_attrs['krbprincipalname'] = result.get('krbprincipalname', []) -+ - def check_mail(self, entry_attrs): - if 'mail' in entry_attrs: - entry_attrs['mail'] = self.obj.normalize_and_validate_email(entry_attrs['mail']) -@@ -557,9 +601,11 @@ class baseuser_mod(LDAPUpdate): - - self.check_objectclass(ldap, dn, entry_attrs) - self.obj.convert_usercertificate_pre(entry_attrs) -+ self.preserve_krbprincipalname_pre(ldap, entry_attrs, *keys, **options) - - def post_common_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) -+ self.preserve_krbprincipalname_post(ldap, entry_attrs, **options) - if options.get('random', False): - try: - entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword')) --- -2.7.4 - diff --git a/SOURCES/0012-ldap2-use-LDAP-whoami-operation-to-retrieve-bind-DN-.patch b/SOURCES/0012-ldap2-use-LDAP-whoami-operation-to-retrieve-bind-DN-.patch new file mode 100644 index 0000000..2b4be55 --- /dev/null +++ b/SOURCES/0012-ldap2-use-LDAP-whoami-operation-to-retrieve-bind-DN-.patch @@ -0,0 +1,43 @@ +From 1288763da61ba9e0c9bd345487a3e645c58284df Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 22 Mar 2017 13:00:22 +0200 +Subject: [PATCH] ldap2: use LDAP whoami operation to retrieve bind DN for + current connection + +For external users which are mapped to some DN in LDAP server, we +wouldn't neccesary be able to find a kerberos data in their LDAP entry. +Instead of searching for Kerberos principal use actual DN we are bound +to because for get_effective_rights LDAP control we only need the DN +itself. + +Fixes https://pagure.io/freeipa/issue/6797 + +Reviewed-By: Martin Babinsky +Reviewed-By: Pavel Vomacka +--- + ipaserver/plugins/ldap2.py | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py +index def124530cc863e6924c7b6f1f48c236323019a9..3b1e4da57a8e16e3d9b27eea24025de2caa53216 100644 +--- a/ipaserver/plugins/ldap2.py ++++ b/ipaserver/plugins/ldap2.py +@@ -286,12 +286,11 @@ class ldap2(CrudBackend, LDAPClient): + + assert isinstance(dn, DN) + +- principal = getattr(context, 'principal') +- entry = self.find_entry_by_attr("krbprincipalname", principal, +- "krbPrincipalAux", base_dn=self.api.env.basedn) ++ bind_dn = self.conn.whoami_s()[4:] ++ + sctrl = [ + GetEffectiveRightsControl( +- True, "dn: {0}".format(entry.dn).encode('utf-8')) ++ True, "dn: {0}".format(bind_dn).encode('utf-8')) + ] + self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, sctrl) + try: +-- +2.12.1 + diff --git a/SOURCES/0013-Backup-ipa-specific-httpd-unit-file.patch b/SOURCES/0013-Backup-ipa-specific-httpd-unit-file.patch new file mode 100644 index 0000000..bf500ae --- /dev/null +++ b/SOURCES/0013-Backup-ipa-specific-httpd-unit-file.patch @@ -0,0 +1,47 @@ +From 7b57dd770bbb4861f46805adaa9597445dff142c Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Thu, 16 Mar 2017 10:22:59 +0100 +Subject: [PATCH] Backup ipa-specific httpd unit-file + +On backup-restore, the ipa unit file for httpd was not backed up. +This file however contains setting for httpd to communicate with +gssproxy so not backing it up will result in httpd not knowing +how to get credentials. + +https://pagure.io/freeipa/issue/6748 + +Reviewed-By: Martin Basti +Reviewed-By: Christian Heimes +--- + ipaserver/install/ipa_backup.py | 1 + + ipaserver/install/ipa_restore.py | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 07c50c8364c313b9aeb6d73540b541f55d98a44d..56583c01b1677a48c103d79123e3fbe106222f38 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -166,6 +166,7 @@ class Backup(admintool.AdminTool): + paths.KDC_CERT, + paths.KDC_KEY, + paths.SYSTEMD_IPA_SERVICE, ++ paths.SYSTEMD_SYSTEM_HTTPD_IPA_CONF, + paths.SYSTEMD_SSSD_SERVICE, + paths.SYSTEMD_CERTMONGER_SERVICE, + paths.SYSTEMD_PKI_TOMCAT_SERVICE, +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index d798654ea7464f66e461936e41e3747a16acb21d..2552bbdef36f653f1c377ea096ca227d09e5f3e6 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -414,6 +414,8 @@ class Restore(admintool.AdminTool): + sssd = services.service('sssd', api) + sssd.restart() + http.remove_httpd_ccaches() ++ # have the daemons pick up their restored configs ++ run([paths.SYSTEMCTL, "--system", "daemon-reload"]) + finally: + try: + os.chdir(cwd) +-- +2.12.1 + diff --git a/SOURCES/0013-messages-specify-message-type-for-ResultFormattingEr.patch b/SOURCES/0013-messages-specify-message-type-for-ResultFormattingEr.patch deleted file mode 100644 index 3f77ffa..0000000 --- a/SOURCES/0013-messages-specify-message-type-for-ResultFormattingEr.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0d5962e52aa9418ec0285f202aa786083aec67c3 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Wed, 13 Jul 2016 18:22:04 +0200 -Subject: [PATCH] messages: specify message type for ResultFormattingError - -the ResultFormattingError message class was missing a `type` member which -could cause `otptoken-add` command to crash during QR image rendering using -suboptimal TTY settings - -https://fedorahosted.org/freeipa/ticket/6081 - -Reviewed-By: Alexander Bokovoy ---- - ipalib/messages.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipalib/messages.py b/ipalib/messages.py -index 7288606f6ac923c2c87fadba5f2a6a2d9dadb7f5..6abad64a8259a8e164db60f63e75bbb9c230e7bf 100644 ---- a/ipalib/messages.py -+++ b/ipalib/messages.py -@@ -363,6 +363,7 @@ class ResultFormattingError(PublicMessage): - """ - **13019** Unable to correctly format some part of the result - """ -+ type = "warning" - errno = 13019 - - --- -2.7.4 - diff --git a/SOURCES/0014-WebUI-check-principals-in-lowercase.patch b/SOURCES/0014-WebUI-check-principals-in-lowercase.patch new file mode 100644 index 0000000..ebaff11 --- /dev/null +++ b/SOURCES/0014-WebUI-check-principals-in-lowercase.patch @@ -0,0 +1,36 @@ +From 4ffc29d45ff1121f76b39ac7acaee824b4d04aaf Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Wed, 22 Mar 2017 16:39:21 +0100 +Subject: [PATCH] WebUI: check principals in lowercase + +WebUI checks whether principal name of logged user and principal name +in each command is equal. As KDC for our principals is case insensitive +- it does make sense to switch this check also into case insensitive. +So both principals are reformated to lower case and then +compared. + +Part of: https://pagure.io/freeipa/issue/3242 + +Reviewed-By: Petr Vobornik +Reviewed-By: Alexander Bokovoy +--- + install/ui/src/freeipa/rpc.js | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/install/ui/src/freeipa/rpc.js b/install/ui/src/freeipa/rpc.js +index 7ae1b64291a4530137e0fb8d72ff5a8491cb10b4..1880f8d5732f982c25924b787b273c9e56636b20 100644 +--- a/install/ui/src/freeipa/rpc.js ++++ b/install/ui/src/freeipa/rpc.js +@@ -389,7 +389,8 @@ rpc.command = function(spec) { + } else if (IPA.version && data.version && IPA.version !== data.version) { + window.location.reload(); + +- } else if (IPA.principal && data.principal && IPA.principal !== data.principal) { ++ } else if (IPA.principal && data.principal && ++ IPA.principal.toLowerCase() !== data.principal.toLowerCase()) { + window.location.reload(); + + } else if (data.error) { +-- +2.12.1 + diff --git a/SOURCES/0014-schema-Fix-subtopic-topic-mapping.patch b/SOURCES/0014-schema-Fix-subtopic-topic-mapping.patch deleted file mode 100644 index 2f95e8a..0000000 --- a/SOURCES/0014-schema-Fix-subtopic-topic-mapping.patch +++ /dev/null @@ -1,29 +0,0 @@ -From a48b8aa5e4d45b238551c122f88dfc8151314c93 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 14 Jul 2016 10:15:59 +0200 -Subject: [PATCH] schema: Fix subtopic -> topic mapping - -https://fedorahosted.org/freeipa/ticket/6069 - -Reviewed-By: Martin Babinsky ---- - ipaserver/plugins/schema.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/schema.py b/ipaserver/plugins/schema.py -index a82b357899a483fd3b3dc9f7407bd26a4c03aada..8fd7c6ba1c4ed8cd6e27cb8b1b04f48694a4f1ff 100644 ---- a/ipaserver/plugins/schema.py -+++ b/ipaserver/plugins/schema.py -@@ -399,7 +399,8 @@ class topic_(MetaObject): - continue - if topic_value is not None: - topic_name = unicode(topic_value) -- topic['topic_topic'] = topic_full_name -+ topic['topic_topic'] = '{}/{}'.format(topic_name, -+ topic_version) - else: - topic.pop('topic_topic', None) - --- -2.7.4 - diff --git a/SOURCES/0015-DNS-install-Ensure-that-DNS-servers-container-exists.patch b/SOURCES/0015-DNS-install-Ensure-that-DNS-servers-container-exists.patch deleted file mode 100644 index b0dd7fc..0000000 --- a/SOURCES/0015-DNS-install-Ensure-that-DNS-servers-container-exists.patch +++ /dev/null @@ -1,93 +0,0 @@ -From caceb3a08644dae0ecae05a5b1f18b91a522356d Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 14 Jul 2016 17:14:59 +0200 -Subject: [PATCH] DNS install: Ensure that DNS servers container exists - -during DNS installation it is assumed that the cn=servers,cn=dns container is -always present in LDAP backend when migrating DNS server info to LDAP. - -This may not always be the case (e.g. when a new replica is set up against -older master) so the code must take additional steps to ensure this container -is present. - -https://fedorahosted.org/freeipa/ticket/6083 - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/install/bindinstance.py | 21 +++++++++++++++++++++ - ipaserver/install/plugins/dns.py | 13 ++----------- - 2 files changed, 23 insertions(+), 11 deletions(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index f4ed63141cf25dfcfdc72d37d6ff4563e4acccf1..844fb04a9d9feca936211964b75a0b3468ba663b 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -546,6 +546,26 @@ def remove_master_dns_records(hostname, realm): - bind.remove_server_ns_records(hostname) - - -+def ensure_dnsserver_container_exists(ldap, api_instance, logger=None): -+ """ -+ Create cn=servers,cn=dns,$SUFFIX container. If logger is not None, emit a -+ message that the container already exists when DuplicateEntry is raised -+ """ -+ -+ entry = ldap.make_entry( -+ DN(api_instance.env.container_dnsservers, api_instance.env.basedn), -+ { -+ u'objectclass': [u'top', u'nsContainer'], -+ u'cn': [u'servers'] -+ } -+ ) -+ try: -+ ldap.add_entry(entry) -+ except errors.DuplicateEntry: -+ if logger is not None: -+ logger.debug('cn=servers,cn=dns container already exists') -+ -+ - class DnsBackup(object): - def __init__(self, service): - self.service = service -@@ -942,6 +962,7 @@ class BindInstance(service.Service): - ) - - def __setup_server_configuration(self): -+ ensure_dnsserver_container_exists(self.admin_conn, self.api) - try: - self.api.Command.dnsserver_add( - self.fqdn, idnssoamname=DNSName(self.fqdn).make_absolute(), -diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py -index 4fa30661e40748cd32cb25c232168191db20c461..32247eedbac7fc7e00c7277ef0bc593a74cd22e4 100644 ---- a/ipaserver/install/plugins/dns.py -+++ b/ipaserver/install/plugins/dns.py -@@ -29,6 +29,7 @@ from ipapython.dn import DN - from ipapython import dnsutil - from ipapython.ipa_log_manager import root_logger - from ipaserver.install import sysupgrade -+from ipaserver.install.bindinstance import ensure_dnsserver_container_exists - from ipaserver.plugins.dns import dns_container_exists - - register = Registry() -@@ -521,17 +522,7 @@ class update_dnsserver_configuration_into_ldap(DNSUpdater): - return False, [] - - # create container first, if doesn't exist -- entry = ldap.make_entry( -- DN(self.api.env.container_dnsservers, self.api.env.basedn), -- { -- u'objectclass': [u'top', u'nsContainer'], -- u'cn': [u'servers'] -- } -- ) -- try: -- ldap.add_entry(entry) -- except errors.DuplicateEntry: -- self.log.debug('cn=dnsservers container already exists') -+ ensure_dnsserver_container_exists(ldap, self.api, logger=self.log) - - try: - self.api.Command.dnsserver_add(self.api.env.host) --- -2.7.4 - diff --git a/SOURCES/0015-WebUI-add-method-for-disabling-item-in-user-dropdown.patch b/SOURCES/0015-WebUI-add-method-for-disabling-item-in-user-dropdown.patch new file mode 100644 index 0000000..e8389c4 --- /dev/null +++ b/SOURCES/0015-WebUI-add-method-for-disabling-item-in-user-dropdown.patch @@ -0,0 +1,105 @@ +From 894fdd8c10552ef0b90363db985bb25e398d99e1 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Wed, 22 Mar 2017 16:48:36 +0100 +Subject: [PATCH] WebUI: add method for disabling item in user dropdown menu + +AD user can do only several things. One of those which are not +allowed is to reset password to itself. Therefore we need to be +able to turn of a item in dropdown menu. In our case +'Password reset' item. Function which disable menu item and detach +the listener on click from the item specified by its name was added. + +Part of: https://pagure.io/freeipa/issue/3242 + +Reviewed-By: Petr Vobornik +Reviewed-By: Alexander Bokovoy +--- + install/ui/src/freeipa/Application_controller.js | 42 ++++++++++++++++++++---- + install/ui/src/freeipa/widgets/App.js | 4 +++ + 2 files changed, 40 insertions(+), 6 deletions(-) + +diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js +index 32add5f8f3d6874c1c555bf28d2b70cd54af5956..d809c1f2662609e390609270ef3ddc42f0727936 100644 +--- a/install/ui/src/freeipa/Application_controller.js ++++ b/install/ui/src/freeipa/Application_controller.js +@@ -69,6 +69,16 @@ define([ + facet_changing: false, + + /** ++ * Listeners for user menu items ++ */ ++ on_profile_listener: null, ++ on_passwd_reset_listener: null, ++ on_logout_listener: null, ++ on_item_select_listener: null, ++ on_configuration_listerer: null, ++ on_about_listener: null, ++ ++ /** + * Currently displayed facet + * + */ +@@ -109,12 +119,7 @@ define([ + } + }; + +- on(this.app_widget.menu_widget, 'item-select', this.on_menu_click.bind(this)); +- on(this.app_widget, 'profile-click', this.on_profile.bind(this)); +- on(this.app_widget, 'logout-click', this.on_logout.bind(this)); +- on(this.app_widget, 'password-reset-click', this.on_password_reset.bind(this)); +- on(this.app_widget, 'configuration-click', this.on_configuration.bind(this)); +- on(this.app_widget, 'about-click', this.on_about.bind(this)); ++ this.register_user_menu_listeners(); + + on(this.router, 'facet-show', this.on_facet_show.bind(this)); + on(this.router, 'facet-change', this.on_facet_change.bind(this)); +@@ -133,6 +138,31 @@ define([ + IPA.opened_dialogs.start_handling(this); + }, + ++ register_user_menu_listeners: function() { ++ this.on_profile_listener = on(this.app_widget, 'profile-click', ++ this.on_profile.bind(this)); ++ this.on_passwd_reset_listener = on(this.app_widget, ++ 'password-reset-click', this.on_password_reset.bind(this)); ++ this.on_logout_listener = on(this.app_widget, 'logout-click', ++ this.on_logout.bind(this)); ++ this.on_item_select_listener = on(this.app_widget.menu_widget, ++ 'item-select', this.on_menu_click.bind(this)); ++ this.on_configuration_listerer = on(this.app_widget, ++ 'configuration-click', this.on_configuration.bind(this)); ++ this.on_about_listener = on(this.app_widget, ++ 'about-click', this.on_about.bind(this)); ++ }, ++ ++ /** ++ * Turns off one item in user dropdown menu and remove its listener. ++ * @param {string} name of the user menu item which should be disabled ++ * @param {Object} listener disable this listener ++ */ ++ disable_user_menu_item: function(name, listener) { ++ this.app_widget.disable_user_menu_item(name); ++ listener.remove(); ++ }, ++ + /** + * Gets: + * * metadata +diff --git a/install/ui/src/freeipa/widgets/App.js b/install/ui/src/freeipa/widgets/App.js +index 68b78c7c4be44f5a1f658fed6b6b75d1beda22c5..95bc9b2cf3bcf40cd3a4cab47e9043e05331e019 100644 +--- a/install/ui/src/freeipa/widgets/App.js ++++ b/install/ui/src/freeipa/widgets/App.js +@@ -222,6 +222,10 @@ define(['dojo/_base/declare', + } + }, + ++ disable_user_menu_item: function(name) { ++ this.user_menu.disable_item(name); ++ }, ++ + on_menu_item_click: function(item) { + this.collapse_menu(); + }, +-- +2.12.1 + diff --git a/SOURCES/0016-Heap-corruption-in-ipapwd-plugin.patch b/SOURCES/0016-Heap-corruption-in-ipapwd-plugin.patch deleted file mode 100644 index 59d2c6e..0000000 --- a/SOURCES/0016-Heap-corruption-in-ipapwd-plugin.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 98bdf4755d5c0256d26ba6a6aed6b9e649adf941 Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Mon, 18 Jul 2016 15:00:02 +0200 -Subject: [PATCH] Heap corruption in ipapwd plugin - -ipapwd_encrypt_encode_key allocates 'kset' on the heap but -with num_keys and keys not being initialized. -Then ipa_krb5_generate_key_data initializes them with the -generated keys. -If ipa_krb5_generate_key_data fails (here EINVAL meaning no -principal->realm.data), num_keys and keys are left uninitialized. -Upon failure, ipapwd_keyset_free is called to free 'kset' -that contains random num_keys and keys. - -allocates kset with calloc so that kset->num_keys==0 and -kset->keys==NULL - -https://fedorahosted.org/freeipa/ticket/6030 - -Reviewed-By: Simo Sorce -Reviewed-By: Lukas Slebodnik ---- - daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c -index 9c62f0560aa999b2179a7767040047dfa89288e0..7b2f341229b4f3bf48105c3856c0d6778da154a5 100644 ---- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c -+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/encoding.c -@@ -157,7 +157,7 @@ Slapi_Value **ipapwd_encrypt_encode_key(struct ipapwd_krbcfg *krbcfg, - pwd.length = strlen(data->password); - } - -- kset = malloc(sizeof(struct ipapwd_keyset)); -+ kset = (struct ipapwd_keyset *) calloc(1, sizeof(struct ipapwd_keyset)); - if (!kset) { - LOG_OOM(); - goto enc_error; --- -2.7.4 - diff --git a/SOURCES/0016-WebUI-Add-support-for-login-for-AD-users.patch b/SOURCES/0016-WebUI-Add-support-for-login-for-AD-users.patch new file mode 100644 index 0000000..4912fd1 --- /dev/null +++ b/SOURCES/0016-WebUI-Add-support-for-login-for-AD-users.patch @@ -0,0 +1,341 @@ +From 18e9bc2399af788399e66c3f4b28e6a7f0378b78 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Wed, 22 Mar 2017 16:54:33 +0100 +Subject: [PATCH] WebUI: Add support for login for AD users + +After login, method user-find --whoami was called which cannot be +called for AD users. That method was replaced by ipa whoami command +and sequential command according to result of ipa whoami. AD user +can now be logged in. + +AD users have new menu definition which contains only list of IPA +users and profile page of AD user - "User ID Override". + +This commit also fixes several places where IPA.whoami object was +used, because its structure was also changed. It now contains two +objects. First one is stored in 'metadata' property and stores +result from ipa whoami (type of object, command which should be +called for showing detailed data about currently logged entity, etc). +The second one is stored in 'data' property which stores result of +_show command for currently logged entity. + +https://pagure.io/freeipa/issue/3242 + +Reviewed-By: Petr Vobornik +Reviewed-By: Alexander Bokovoy +--- + install/ui/src/freeipa/Application_controller.js | 52 +++++++++++++++++++----- + install/ui/src/freeipa/idviews.js | 21 +++++++++- + install/ui/src/freeipa/ipa.js | 47 +++++++++++++-------- + install/ui/src/freeipa/navigation/menu_spec.js | 10 +++++ + install/ui/src/freeipa/otptoken.js | 2 +- + install/ui/src/freeipa/user.js | 5 ++- + ipaserver/plugins/internal.py | 1 + + 7 files changed, 108 insertions(+), 30 deletions(-) + +diff --git a/install/ui/src/freeipa/Application_controller.js b/install/ui/src/freeipa/Application_controller.js +index d809c1f2662609e390609270ef3ddc42f0727936..5eb4e7a5104b780761b9a5179dbfd1501a8d1478 100644 +--- a/install/ui/src/freeipa/Application_controller.js ++++ b/install/ui/src/freeipa/Application_controller.js +@@ -31,6 +31,7 @@ define([ + './widgets/App', + './widgets/FacetContainer', + './ipa', ++ './rpc', + './reg', + './config', + './widget', +@@ -41,7 +42,7 @@ define([ + './plugins/load_page' + ], + function(declare, array, Deferred, on, topic, query, dom_class, auth, +- JSON, App_widget, FacetContainer, IPA, reg, config, widget_mod, ++ JSON, App_widget, FacetContainer, IPA, rpc, reg, config, widget_mod, + Menu, Router, routing, menu_spec) { + + /** +@@ -156,7 +157,7 @@ define([ + /** + * Turns off one item in user dropdown menu and remove its listener. + * @param {string} name of the user menu item which should be disabled +- * @param {Object} listener disable this listener ++ * @param {Object} listener disable di + */ + disable_user_menu_item: function(name, listener) { + this.app_widget.disable_user_menu_item(name); +@@ -179,16 +180,22 @@ define([ + */ + choose_profile: function() { + +- // TODO: change IPA.whoami.cn[0] to something readable +- this.update_logged_in(true, IPA.whoami.cn[0]); ++ this.update_logged_in(true); + var selfservice = this.is_selfservice(); + + + this.app_widget.menu_widget.ignore_changes = true; + + if (selfservice) { +- this.menu.name = menu_spec.self_service.name; +- this.menu.add_items(menu_spec.self_service.items); ++ if (this.is_aduser_selfservice()) { ++ this.menu.name = menu_spec.ad_self_service.name; ++ this.menu.add_items(menu_spec.ad_self_service.items); ++ this.disable_user_menu_item('password_reset', ++ this.on_passwd_reset_listener); ++ } else { ++ this.menu.name = menu_spec.self_service.name; ++ this.menu.add_items(menu_spec.self_service.items); ++ } + } else { + this.menu.name = menu_spec.admin.name; + this.menu.add_items(menu_spec.admin.items); +@@ -232,10 +239,9 @@ define([ + }, + + is_selfservice: function() { +- var whoami = IPA.whoami; ++ var whoami = IPA.whoami.data; + var self_service = true; + +- + if (whoami.hasOwnProperty('memberof_group') && + whoami.memberof_group.indexOf('admins') !== -1) { + self_service = false; +@@ -255,13 +261,39 @@ define([ + return self_service; + }, + +- update_logged_in: function(logged_in, fullname) { ++ is_aduser_selfservice: function() { ++ var selfservice = IPA.whoami.metadata.object === 'idoverrideuser'; ++ // quite ugly, needed for users and iduseroverride to hide breadcrumb ++ IPA.is_aduser_selfservice = selfservice; ++ ++ return selfservice; ++ }, ++ ++ update_logged_in: function(logged_in) { + this.app_widget.set('logged', logged_in); ++ ++ var whoami = IPA.whoami; ++ var fullname = ''; ++ var entity = whoami.metadata.object; ++ ++ if (whoami.data.cn) { ++ fullname = whoami.data.cn[0]; ++ } else if (whoami.data.displayname) { ++ fullname = whoami.data.displayname[0]; ++ } else if (whoami.data.gecos) { ++ fullname = whoami.data.gecos[0]; ++ } else if (whoami.data.krbprincipalname) { ++ fullname = whoami.data.krbprincipalname[0]; ++ } else if (whoami.data.ipaoriginaluid) { ++ fullname = whoami.data.ipaoriginaluid[0]; ++ } ++ + this.app_widget.set('fullname', fullname); + }, + + on_profile: function() { +- routing.navigate(['entity', 'user', 'details', [IPA.whoami.uid[0]]]); ++ routing.navigate(['entity', IPA.whoami.metadata.object, 'details', ++ IPA.whoami.metadata.arguments]); + }, + + on_logout: function(event) { +diff --git a/install/ui/src/freeipa/idviews.js b/install/ui/src/freeipa/idviews.js +index f383ab3be4c4ed997fb209da2da4d04835236d8a..d9133a13c2ed8970e7919bb28d06f818d832170a 100644 +--- a/install/ui/src/freeipa/idviews.js ++++ b/install/ui/src/freeipa/idviews.js +@@ -452,6 +452,21 @@ idviews.id_override_user_details_facet = function(spec) { + return that; + }; + ++ ++idviews.aduser_idoverrideuser_pre_op = function(spec, context) { ++ spec = spec || []; ++ ++ if (!IPA.is_aduser_selfservice) return spec; ++ ++ var facet = spec.facets[0]; ++ facet.label = '@i18n:objects.idoverrideuser.profile'; ++ facet.actions = []; ++ facet.header_actions = []; ++ facet.disable_breadcrumb = true; ++ ++ return spec; ++}; ++ + /** + * @extends IPA.cert.certs_widget + */ +@@ -948,7 +963,11 @@ idviews.register = function() { + var w = reg.widget; + + e.register({type: 'idview', spec: idviews.spec}); +- e.register({type: 'idoverrideuser', spec: idviews.idoverrideuser_spec}); ++ e.register({ ++ type: 'idoverrideuser', ++ spec: idviews.idoverrideuser_spec, ++ pre_ops: [idviews.aduser_idoverrideuser_pre_op] ++ }); + e.register({type: 'idoverridegroup', spec: idviews.idoverridegroup_spec}); + f.copy('attribute', 'idview_appliedtohosts', { + factory: idviews.appliedtohosts_facet +diff --git a/install/ui/src/freeipa/ipa.js b/install/ui/src/freeipa/ipa.js +index 0ddbd0744d699cacddb3970e5ec7cb72b9dbf4f4..2538001c94141b823d634ca63327a66fd148129f 100644 +--- a/install/ui/src/freeipa/ipa.js ++++ b/install/ui/src/freeipa/ipa.js +@@ -86,7 +86,8 @@ var IPA = function () { + /** + * User information + * +- * - output of ipa user-find --whoami ++ * - output of ipa whoami in that.whoami.metadata and then object_show method ++ * in that.whoami.data + */ + that.whoami = {}; + +@@ -263,19 +264,33 @@ var IPA = function () { + */ + that.get_whoami_command = function(batch) { + return rpc.command({ +- entity: 'user', +- method: 'find', +- options: { +- whoami: true, +- all: true +- }, ++ method: 'whoami', + on_success: function(data, text_status, xhr) { +- that.whoami = batch ? data.result[0] : data.result.result[0]; +- var cn = that.whoami.krbcanonicalname; +- if (cn) that.principal = cn[0]; +- if (!that.principal) { +- that.principal = that.whoami.krbprincipalname[0]; +- } ++ that.whoami.metadata = data; ++ ++ rpc.command({ ++ method: data.details || data.command, ++ args: data.arguments, ++ options: function() { ++ var options = data.options || []; ++ $.extend(options, {all: true}); ++ return options; ++ }(), ++ on_success: function(data, text_status, xhr) { ++ that.whoami.data = false ? data.result[0] : data.result.result; ++ var entity = that.whoami.metadata.object; ++ ++ if (entity === 'user') { ++ var cn = that.whoami.data.krbcanonicalname; ++ if (cn) that.principal = cn[0]; ++ if (!that.principal) { ++ that.principal = that.whoami.data.krbprincipalname[0]; ++ } ++ } else if (entity === 'idoverrideuser') { ++ that.principal = that.whoami.data.ipaoriginaluid[0]; ++ } ++ } ++ }).execute(); + } + }); + }; +@@ -616,7 +631,7 @@ IPA.update_password_expiration = function() { + + var now, expires, notify_days, diff, message, container, notify; + +- expires = rpc.extract_objects(IPA.whoami.krbpasswordexpiration); ++ expires = rpc.extract_objects(IPA.whoami.data.krbpasswordexpiration); + expires = expires ? datetime.parse(expires[0]) : null; + + notify_days = IPA.server_config.ipapwdexpadvnotify; +@@ -650,13 +665,13 @@ IPA.update_password_expiration = function() { + IPA.password_selfservice = function() { + var reset_dialog = builder.build('dialog', { + $type: 'user_password', +- args: [IPA.whoami.uid[0]] ++ args: [IPA.whoami.data.uid[0]] + }); + reset_dialog.succeeded.attach(function() { + var command = IPA.get_whoami_command(); + var orig_on_success = command.on_success; + command.on_success = function(data, text_status, xhr) { +- orig_on_success.call(this, data, text_status, xhr); ++ orig_on_success.call(this, data.result, text_status, xhr); + IPA.update_password_expiration(); + }; + command.execute(); +diff --git a/install/ui/src/freeipa/navigation/menu_spec.js b/install/ui/src/freeipa/navigation/menu_spec.js +index 4f78e4bf9ba25bf2f7585e38086b1cbc6db34026..9329694c14a47cbe1ec244554327b40743044d7b 100644 +--- a/install/ui/src/freeipa/navigation/menu_spec.js ++++ b/install/ui/src/freeipa/navigation/menu_spec.js +@@ -353,5 +353,15 @@ nav.self_service = { + ] + }; + ++nav.ad_self_service = { ++ name: 'ad_self_service', ++ items: [ ++ { ++ entity: 'idoverrideuser', ++ label: 'Profile' ++ } ++ ] ++}; ++ + return nav; + }); +diff --git a/install/ui/src/freeipa/otptoken.js b/install/ui/src/freeipa/otptoken.js +index caa7a85523d6e63db629a3a518e8611d511f7952..1f6f20d801042a5424ecf5894658df9411723bcc 100644 +--- a/install/ui/src/freeipa/otptoken.js ++++ b/install/ui/src/freeipa/otptoken.js +@@ -361,7 +361,7 @@ otptoken.adder_dialog = function(spec) { + + var command = that.entity_adder_dialog_create_add_command(record); + if (that.self_service) { +- command.set_option('ipatokenowner', IPA.whoami.uid[0]); ++ command.set_option('ipatokenowner', IPA.whoami.data.uid[0]); + } + return command; + }; +diff --git a/install/ui/src/freeipa/user.js b/install/ui/src/freeipa/user.js +index 4bb04488b51dd43a437ab3759eb3f530afe62550..6b2bf196c31e7891d3389eb2e2774f56d88ac2ba 100644 +--- a/install/ui/src/freeipa/user.js ++++ b/install/ui/src/freeipa/user.js +@@ -735,7 +735,7 @@ IPA.user.password_dialog = function(spec) { + var that = dialogs.command_dialog(spec); + + that.is_self_service = function() { +- var self_service = that.args[0] === IPA.whoami.uid[0]; ++ var self_service = that.args[0] === IPA.whoami.data.uid[0]; + return self_service; + }; + +@@ -895,7 +895,8 @@ IPA.user.self_service_other_user_evaluator = function(spec) { + that.state = []; + + var value = that.adapter.load(data); +- if (IPA.is_selfservice && IPA.whoami.uid[0] !== value[0]) { ++ if (IPA.is_aduser_selfservice || ++ (IPA.is_selfservice && IPA.whoami.data.uid[0] !== value[0])) { + that.state.push('self-service-other'); + } + +diff --git a/ipaserver/plugins/internal.py b/ipaserver/plugins/internal.py +index 9fa1b6de857cf7e21210f557befabff32da0d4ff..6feefa5941506f38f01b8016a22cad14a831e3fc 100644 +--- a/ipaserver/plugins/internal.py ++++ b/ipaserver/plugins/internal.py +@@ -625,6 +625,7 @@ class i18n_messages(Command): + "anchor_label": _("User to override"), + "anchor_tooltip": _("Enter trusted or IPA user login. Note: search doesn't list users from trusted domains."), + "anchor_tooltip_ad": _("Enter trusted user login."), ++ "profile": _("Profile"), + }, + "idoverridegroup": { + "anchor_label": _("Group to override"), +-- +2.12.1 + diff --git a/SOURCES/0017-Use-server-API-in-com.redhat.idm.trust-fetch-domains.patch b/SOURCES/0017-Use-server-API-in-com.redhat.idm.trust-fetch-domains.patch deleted file mode 100644 index 52f2eae..0000000 --- a/SOURCES/0017-Use-server-API-in-com.redhat.idm.trust-fetch-domains.patch +++ /dev/null @@ -1,29 +0,0 @@ -From c5f48cd10b9aa3f0dd226aacab8abd8af996c861 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 14 Jul 2016 09:31:22 +0200 -Subject: [PATCH] Use server API in com.redhat.idm.trust-fetch-domains oddjob - helper - -https://fedorahosted.org/freeipa/ticket/6082 - -Reviewed-By: Alexander Bokovoy ---- - install/oddjob/com.redhat.idm.trust-fetch-domains | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains -index a6b87cde917cfa5bfedf28442a6d1b2b512706f9..7c948fd53bd54bf3638ef3cc4407576b9011f4fb 100755 ---- a/install/oddjob/com.redhat.idm.trust-fetch-domains -+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains -@@ -76,7 +76,7 @@ env._bootstrap(debug=options.debug, log=None) - env._finalize_core(**dict(DEFAULT_CONFIG)) - - # Initialize the API with the proper debug level --api.bootstrap(debug=env.debug, log=None) -+api.bootstrap(in_server=True, debug=env.debug, log=None) - api.finalize() - - # Only import trust plugin after api is initialized or internal imports --- -2.7.4 - diff --git a/SOURCES/0017-cert-do-not-limit-internal-searches-in-cert-find.patch b/SOURCES/0017-cert-do-not-limit-internal-searches-in-cert-find.patch new file mode 100644 index 0000000..7166516 --- /dev/null +++ b/SOURCES/0017-cert-do-not-limit-internal-searches-in-cert-find.patch @@ -0,0 +1,105 @@ +From ca26e32beb77fbd8fcc66e6eea07c6eeeb9261c9 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 22 Mar 2017 06:58:25 +0000 +Subject: [PATCH] cert: do not limit internal searches in cert-find + +Instead, apply the limits on the combined result. + +This fixes (absence of) `--sizelimit` leading to strange behavior, such as +`cert-find --users user` returning a non-empty result only with +`--sizelimit 0`. + +https://pagure.io/freeipa/issue/6716 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/plugins/cert.py | 28 ++++++++++------------------ + 1 file changed, 10 insertions(+), 18 deletions(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index 9f901076075809592ad5ddeec8d71c273d4853c9..1a6d04533cebb2eb00022981dae9ffe5b785ba8b 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -1324,7 +1324,7 @@ class cert_find(Search, CertMethod): + + return result, False, True + +- def _ca_search(self, all, raw, pkey_only, sizelimit, exactly, **options): ++ def _ca_search(self, all, raw, pkey_only, exactly, **options): + ra_options = {} + for name in ('revocation_reason', + 'issuer', +@@ -1343,10 +1343,6 @@ class cert_find(Search, CertMethod): + elif isinstance(value, DN): + value = unicode(value) + ra_options[name] = value +- if sizelimit > 0: +- # Dogtag doesn't tell that the size limit was exceeded +- # search for one more entry so that we can tell ourselves +- ra_options['sizelimit'] = sizelimit + 1 + if exactly: + ra_options['exactly'] = True + +@@ -1369,11 +1365,6 @@ class cert_find(Search, CertMethod): + + ra = self.api.Backend.ra + for ra_obj in ra.find(ra_options): +- if sizelimit > 0 and len(result) >= sizelimit: +- self.add_message(messages.SearchResultTruncated( +- reason=errors.SizeLimitExceeded())) +- break +- + issuer = DN(ra_obj['issuer']) + serial_number = ra_obj['serial_number'] + +@@ -1411,8 +1402,7 @@ class cert_find(Search, CertMethod): + + return result, False, complete + +- def _ldap_search(self, all, raw, pkey_only, no_members, timelimit, +- sizelimit, **options): ++ def _ldap_search(self, all, raw, pkey_only, no_members, **options): + ldap = self.api.Backend.ldap2 + + filters = [] +@@ -1453,8 +1443,8 @@ class cert_find(Search, CertMethod): + base_dn=self.api.env.basedn, + filter=filter, + attrs_list=['usercertificate'], +- time_limit=timelimit, +- size_limit=sizelimit, ++ time_limit=0, ++ size_limit=0, + ) + except errors.EmptyResult: + entries = [] +@@ -1527,13 +1517,9 @@ class cert_find(Search, CertMethod): + raw=raw, + pkey_only=pkey_only, + no_members=no_members, +- timelimit=timelimit, +- sizelimit=sizelimit, + **options) + + if sub_complete: +- sizelimit = 0 +- + for key in tuple(result): + if key not in sub_result: + del result[key] +@@ -1552,6 +1538,12 @@ class cert_find(Search, CertMethod): + complete = complete or sub_complete + + result = list(six.itervalues(result)) ++ if sizelimit > 0 and len(result) > sizelimit: ++ if not truncated: ++ self.add_message(messages.SearchResultTruncated( ++ reason=errors.SizeLimitExceeded())) ++ result = result[:sizelimit] ++ truncated = True + + ret = dict( + result=result +-- +2.12.1 + diff --git a/SOURCES/0018-frontend-copy-command-arguments-to-output-params-on-.patch b/SOURCES/0018-frontend-copy-command-arguments-to-output-params-on-.patch deleted file mode 100644 index 64f030e..0000000 --- a/SOURCES/0018-frontend-copy-command-arguments-to-output-params-on-.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 1297d5f1ba731e81b03a2fca997487813a2e962a Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 18 Jul 2016 07:37:31 +0200 -Subject: [PATCH] frontend: copy command arguments to output params on client - -In commit f554078291d682d59956998af97f7d3066fbe7e7 we stopped copying -command arguments to output params in order to remove redundancies and -reduce API schema in size. Since then, output params were removed from -API schema completely and are reconstructed on the client. - -Not including arguments in output params hides failed members from member -commands' CLI output. To fix this, copy arguments to output params again, -but only on the client side. - -https://fedorahosted.org/freeipa/ticket/6026 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaclient/frontend.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaclient/frontend.py b/ipaclient/frontend.py -index e8eacc068f4bec5ccdb21228b32a88aea24424df..1525c88b3dfeadccd8115cb4b6ba149caef22103 100644 ---- a/ipaclient/frontend.py -+++ b/ipaclient/frontend.py -@@ -95,6 +95,10 @@ class ClientMethod(ClientCommand, Method): - - def get_output_params(self): - seen = set() -+ for param in self.params(): -+ if param.name not in self.obj.params: -+ seen.add(param.name) -+ yield param - for output_param in super(ClientMethod, self).get_output_params(): - seen.add(output_param.name) - yield output_param --- -2.7.4 - diff --git a/SOURCES/0018-ipa-kdb-add-ipadb_fetch_principals_with_extra_filter.patch b/SOURCES/0018-ipa-kdb-add-ipadb_fetch_principals_with_extra_filter.patch new file mode 100644 index 0000000..3a5a47a --- /dev/null +++ b/SOURCES/0018-ipa-kdb-add-ipadb_fetch_principals_with_extra_filter.patch @@ -0,0 +1,132 @@ +From 7a115884d370d8e9b2c7b110a0565fe5b78446a9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 15 Feb 2017 12:09:20 +0100 +Subject: [PATCH] ipa-kdb: add ipadb_fetch_principals_with_extra_filter() + +Additionally make ipadb_find_principal public. + +Related to https://pagure.io/freeipa/issue/4905 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: David Kupka +--- + daemons/ipa-kdb/ipa_kdb.h | 11 +++++++ + daemons/ipa-kdb/ipa_kdb_principals.c | 58 ++++++++++++++++++++++++++++-------- + 2 files changed, 56 insertions(+), 13 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 8a3f7d3c012186fd73b27abef09602b0d0e96e8d..72f2675809a3267cce30bc06c77335697c7287ad 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -198,6 +198,17 @@ krb5_error_code ipadb_put_principal(krb5_context kcontext, + char **db_args); + krb5_error_code ipadb_delete_principal(krb5_context kcontext, + krb5_const_principal search_for); ++krb5_error_code ++ipadb_fetch_principals_with_extra_filter(struct ipadb_context *ipactx, ++ unsigned int flags, ++ const char *principal, ++ const char *filter, ++ LDAPMessage **result); ++krb5_error_code ipadb_find_principal(krb5_context kcontext, ++ unsigned int flags, ++ LDAPMessage *res, ++ char **principal, ++ LDAPMessage **entry); + #if KRB5_KDB_API_VERSION < 8 + krb5_error_code ipadb_iterate(krb5_context kcontext, + char *match_entry, +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index 3bd8fb8c70c61b056a714bc0a8149bd8524beb1d..82c857430b11279b4029fa72a6d430610524ba43 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -37,6 +37,17 @@ + "(objectclass=krbprincipal))" \ + "(krbprincipalname=%s))" + ++#define PRINC_TGS_SEARCH_FILTER_EXTRA "(&(|(objectclass=krbprincipalaux)" \ ++ "(objectclass=krbprincipal)" \ ++ "(objectclass=ipakrbprincipal))" \ ++ "(|(ipakrbprincipalalias=%s)" \ ++ "(krbprincipalname:caseIgnoreIA5Match:=%s))" \ ++ "%s)" ++ ++#define PRINC_SEARCH_FILTER_EXTRA "(&(|(objectclass=krbprincipalaux)" \ ++ "(objectclass=krbprincipal))" \ ++ "(krbprincipalname=%s)" \ ++ "%s)" + static char *std_principal_attrs[] = { + "krbPrincipalName", + "krbCanonicalName", +@@ -864,10 +875,12 @@ done: + return kerr; + } + +-static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, +- unsigned int flags, +- char *principal, +- LDAPMessage **result) ++krb5_error_code ++ipadb_fetch_principals_with_extra_filter(struct ipadb_context *ipactx, ++ unsigned int flags, ++ const char *principal, ++ const char *filter, ++ LDAPMessage **result) + { + krb5_error_code kerr; + char *src_filter = NULL; +@@ -890,11 +903,21 @@ static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, + goto done; + } + +- if (flags & KRB5_KDB_FLAG_ALIAS_OK) { +- ret = asprintf(&src_filter, PRINC_TGS_SEARCH_FILTER, +- esc_original_princ, esc_original_princ); ++ if (filter == NULL) { ++ if (flags & KRB5_KDB_FLAG_ALIAS_OK) { ++ ret = asprintf(&src_filter, PRINC_TGS_SEARCH_FILTER, ++ esc_original_princ, esc_original_princ); ++ } else { ++ ret = asprintf(&src_filter, PRINC_SEARCH_FILTER, esc_original_princ); ++ } + } else { +- ret = asprintf(&src_filter, PRINC_SEARCH_FILTER, esc_original_princ); ++ if (flags & KRB5_KDB_FLAG_ALIAS_OK) { ++ ret = asprintf(&src_filter, PRINC_TGS_SEARCH_FILTER_EXTRA, ++ esc_original_princ, esc_original_princ, filter); ++ } else { ++ ret = asprintf(&src_filter, PRINC_SEARCH_FILTER_EXTRA, ++ esc_original_princ, filter); ++ } + } + + if (ret == -1) { +@@ -913,11 +936,20 @@ done: + return kerr; + } + +-static krb5_error_code ipadb_find_principal(krb5_context kcontext, +- unsigned int flags, +- LDAPMessage *res, +- char **principal, +- LDAPMessage **entry) ++static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx, ++ unsigned int flags, ++ char *principal, ++ LDAPMessage **result) ++{ ++ return ipadb_fetch_principals_with_extra_filter(ipactx, flags, principal, ++ NULL, result); ++} ++ ++krb5_error_code ipadb_find_principal(krb5_context kcontext, ++ unsigned int flags, ++ LDAPMessage *res, ++ char **principal, ++ LDAPMessage **entry) + { + struct ipadb_context *ipactx; + bool found = false; +-- +2.12.1 + diff --git a/SOURCES/0019-IPA-certauth-plugin.patch b/SOURCES/0019-IPA-certauth-plugin.patch new file mode 100644 index 0000000..b600531 --- /dev/null +++ b/SOURCES/0019-IPA-certauth-plugin.patch @@ -0,0 +1,609 @@ +From 0956c8149f11921ed427d67b10bb9b6c4b97df48 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 2 Feb 2017 12:32:13 +0100 +Subject: [PATCH] IPA certauth plugin + +This patch add a certauth plugin which allows the IPA server to support +PKINIT for certificates which do not include a special SAN extension +which contains a Kerberos principal but allow other mappings with the +help of SSSD's certmap library. + +Related to https://pagure.io/freeipa/issue/4905 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: David Kupka +--- + daemons/ipa-kdb/Makefile.am | 24 ++- + daemons/ipa-kdb/ipa-certauth.in | 5 + + daemons/ipa-kdb/ipa_kdb.c | 2 + + daemons/ipa-kdb/ipa_kdb.exports | 1 + + daemons/ipa-kdb/ipa_kdb.h | 5 + + daemons/ipa-kdb/ipa_kdb_certauth.c | 398 +++++++++++++++++++++++++++++++++++++ + freeipa.spec.in | 2 + + server.m4 | 13 ++ + 8 files changed, 449 insertions(+), 1 deletion(-) + create mode 100644 daemons/ipa-kdb/ipa-certauth.in + create mode 100644 daemons/ipa-kdb/ipa_kdb_certauth.c + +diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am +index 6a2caa0637bf076c796b50efc92412062524f35f..715666e779a4fa64c2c0f71767f09efb19b5f908 100644 +--- a/daemons/ipa-kdb/Makefile.am ++++ b/daemons/ipa-kdb/Makefile.am +@@ -18,6 +18,7 @@ AM_CPPFLAGS = \ + $(WARN_CFLAGS) \ + $(NDRPAC_CFLAGS) \ + $(NSS_CFLAGS) \ ++ $(SSSCERTMAP_CFLAGS) \ + $(NULL) + + plugindir = $(libdir)/krb5/plugins/kdb +@@ -39,6 +40,20 @@ ipadb_la_SOURCES = \ + ipa_kdb_audit_as.c \ + $(NULL) + ++if BUILD_IPA_CERTAUTH_PLUGIN ++ipadb_la_SOURCES += ipa_kdb_certauth.c ++ ++ ++%: %.in ++ sed \ ++ -e 's|@plugindir@|$(plugindir)|g' \ ++ '$(srcdir)/$@.in' >$@ ++ ++krb5confdir = $(sysconfdir)/krb5.conf.d ++krb5conf_DATA = ipa-certauth ++CLEANFILES = $(krb5conf_DATA) ++endif ++ + ipadb_la_LDFLAGS = \ + -avoid-version \ + -module \ +@@ -50,6 +65,7 @@ ipadb_la_LIBADD = \ + $(NDRPAC_LIBS) \ + $(UNISTRING_LIBS) \ + $(NSS_LIBS) \ ++ $(SSSCERTMAP_LIBS) \ + $(top_builddir)/util/libutil.la \ + $(NULL) + +@@ -70,6 +86,11 @@ ipa_kdb_tests_SOURCES = \ + ipa_kdb_delegation.c \ + ipa_kdb_audit_as.c \ + $(NULL) ++ ++if BUILD_IPA_CERTAUTH_PLUGIN ++ipa_kdb_tests_SOURCES += ipa_kdb_certauth.c ++endif ++ + ipa_kdb_tests_CFLAGS = $(CMOCKA_CFLAGS) + ipa_kdb_tests_LDADD = \ + $(CMOCKA_LIBS) \ +@@ -78,12 +99,13 @@ ipa_kdb_tests_LDADD = \ + $(NDRPAC_LIBS) \ + $(UNISTRING_LIBS) \ + $(NSS_LIBS) \ ++ $(SSSCERTMAP_LIBS) \ + $(top_builddir)/util/libutil.la \ + -lkdb5 \ + -lsss_idmap \ + $(NULL) + +-dist_noinst_DATA = ipa_kdb.exports ++dist_noinst_DATA = ipa_kdb.exports ipa-certauth.in + + clean-local: + rm -f tests/.dirstamp +diff --git a/daemons/ipa-kdb/ipa-certauth.in b/daemons/ipa-kdb/ipa-certauth.in +new file mode 100644 +index 0000000000000000000000000000000000000000..eda89a26f02fbea449eb754b232b8115904acd21 +--- /dev/null ++++ b/daemons/ipa-kdb/ipa-certauth.in +@@ -0,0 +1,5 @@ ++[plugins] ++ certauth = { ++ module = ipakdb:@plugindir@/ipadb.so ++ enable_only = ipakdb ++ } +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index c19b7c40e2e88173ab8367a3ef1d7f46245fd174..a961e4e57cf5379eb237551d56e3bc8dc82d952d 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -67,6 +67,8 @@ static void ipadb_context_free(krb5_context kcontext, + } + free(cfg->authz_data); + ++ ipa_certauth_free_moddata(&((*ctx)->certauth_moddata)); ++ + free(*ctx); + *ctx = NULL; + } +diff --git a/daemons/ipa-kdb/ipa_kdb.exports b/daemons/ipa-kdb/ipa_kdb.exports +index d2c3f30246cc7ebcba02a9ec5d134e604fa0dbb9..27ce92d2edd741245061a5f4ee9275169440c932 100644 +--- a/daemons/ipa-kdb/ipa_kdb.exports ++++ b/daemons/ipa-kdb/ipa_kdb.exports +@@ -3,6 +3,7 @@ EXPORTED { + # public symbols + global: + kdb_function_table; ++ certauth_ipakdb_initvt; + + # everything else is local + local: +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 72f2675809a3267cce30bc06c77335697c7287ad..632c1979d15e88aec86d5e408ed6c7017d8362b8 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + + #include "ipa_krb5.h" + #include "ipa_pwd.h" +@@ -111,6 +112,7 @@ struct ipadb_context { + krb5_key_salt_tuple *def_encs; + int n_def_encs; + struct ipadb_mspac *mspac; ++ krb5_certauth_moddata certauth_moddata; + + /* Don't access this directly, use ipadb_get_global_config(). */ + struct ipadb_global_config config; +@@ -331,3 +333,6 @@ ipadb_get_global_config(struct ipadb_context *ipactx); + int ipadb_get_enc_salt_types(struct ipadb_context *ipactx, LDAPMessage *entry, + char *attr, krb5_key_salt_tuple **enc_salt_types, + int *n_enc_salt_types); ++ ++/* CERTAUTH PLUGIN */ ++void ipa_certauth_free_moddata(krb5_certauth_moddata *moddata); +diff --git a/daemons/ipa-kdb/ipa_kdb_certauth.c b/daemons/ipa-kdb/ipa_kdb_certauth.c +new file mode 100644 +index 0000000000000000000000000000000000000000..a53a2ce4e7ceb06ec8de117cdbca2666fdb5a97a +--- /dev/null ++++ b/daemons/ipa-kdb/ipa_kdb_certauth.c +@@ -0,0 +1,398 @@ ++/** 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: ++ * Sumit Bose ++ * ++ * Copyright (C) 2017 Red Hat, Inc. ++ * All rights reserved. ++ * END COPYRIGHT BLOCK **/ ++ ++#include ++//#include ++#include ++#include ++ ++#include "util/ipa_krb5.h" ++#include "ipa_kdb.h" ++ ++#define IPA_OC_CERTMAP_RULE "ipaCertMapRule" ++#define IPA_CERTMAP_MAPRULE "ipaCertMapMapRule" ++#define IPA_CERTMAP_MATCHRULE "ipaCertMapMatchRule" ++#define IPA_CERTMAP_PRIORITY "ipaCertMapPriority" ++#define IPA_ENABLED_FLAG "ipaEnabledFlag" ++#define IPA_TRUE_VALUE "TRUE" ++#define IPA_ASSOCIATED_DOMAIN "associatedDomain" ++ ++#define OBJECTCLASS "objectClass" ++ ++#define CERTMAP_FILTER "(&("OBJECTCLASS"="IPA_OC_CERTMAP_RULE")" \ ++ "("IPA_ENABLED_FLAG"="IPA_TRUE_VALUE"))" ++ ++#ifndef discard_const ++#define discard_const(ptr) ((void *)((uintptr_t)(ptr))) ++#endif ++ ++ ++struct krb5_certauth_moddata_st { ++ char *local_domain; ++ struct sss_certmap_ctx *sss_certmap_ctx; ++ struct ipadb_context *ipactx; ++}; ++ ++void ipa_certmap_debug(void *private, ++ const char *file, long line, ++ const char *function, ++ const char *format, ...) ++{ ++ va_list ap; ++ char str[255] = { 0 }; ++ ++ va_start(ap, format); ++ vsnprintf(str, sizeof(str)-1, format, ap); ++ va_end(ap); ++ krb5_klog_syslog(LOG_INFO, str); ++} ++ ++void ipa_certauth_free_moddata(krb5_certauth_moddata *moddata) ++{ ++ if (moddata == NULL || *moddata == NULL) { ++ return; ++ } ++ ++ free((*moddata)->local_domain); ++ (*moddata)->local_domain = NULL; ++ sss_certmap_free_ctx((*moddata)->sss_certmap_ctx); ++ (*moddata)->sss_certmap_ctx = NULL; ++ ++ free(*moddata); ++ ++ return; ++} ++ ++static krb5_error_code ipa_get_init_data(krb5_context kcontext, ++ krb5_certauth_moddata moddata_out) ++{ ++ int ret; ++ struct sss_certmap_ctx *ctx = NULL; ++ struct ipadb_context *ipactx; ++ krb5_error_code kerr; ++ char *basedn = NULL; ++ LDAPMessage *result = NULL; ++ LDAPMessage *le; ++ LDAP *lc; ++ size_t c; ++ uint32_t prio; ++ char *map_rule = NULL; ++ char *match_rule = NULL; ++ char **domains = NULL; ++ ++ const char *certmap_attrs[] = { OBJECTCLASS, ++ IPA_CERTMAP_PRIORITY, ++ IPA_CERTMAP_MATCHRULE, ++ IPA_CERTMAP_MAPRULE, ++ IPA_ASSOCIATED_DOMAIN, ++ IPA_ENABLED_FLAG, ++ NULL}; ++ ++ ++ krb5_klog_syslog(LOG_INFO, "Initializing IPA certauth plugin."); ++ ++ ipactx = ipadb_get_context(kcontext); ++ if (ipactx == NULL) { ++ return KRB5_KDB_DBNOTINITED; ++ } ++ ++ if (ipactx->certauth_moddata == NULL) { ++ ret = asprintf(&basedn, "cn=certmap,%s", ipactx->base); ++ if (ret == -1) { ++ return ENOMEM; ++ } ++ ++ kerr = ipadb_simple_search(ipactx,basedn, LDAP_SCOPE_SUBTREE, ++ CERTMAP_FILTER, discard_const(certmap_attrs), ++ &result); ++ if (kerr != 0 && kerr != KRB5_KDB_NOENTRY) { ++ goto done; ++ } ++ ++ ret = sss_certmap_init(NULL, ipa_certmap_debug, NULL, &ctx); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (kerr == KRB5_KDB_NOENTRY) { ++ ret = sss_certmap_add_rule(ctx, SSS_CERTMAP_MIN_PRIO, ++ NULL, NULL, NULL); ++ if (ret != 0) { ++ goto done; ++ } ++ } else { ++ lc = ipactx->lcontext; ++ ++ for (le = ldap_first_entry(lc, result); le; ++ le = ldap_next_entry(lc, le)) { ++ prio = SSS_CERTMAP_MIN_PRIO; ++ ret = ipadb_ldap_attr_to_uint32(lc, le, IPA_CERTMAP_PRIORITY, ++ &prio); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; ++ } ++ ++ free(map_rule); ++ map_rule = NULL; ++ ret = ipadb_ldap_attr_to_str(lc, le, IPA_CERTMAP_MAPRULE, ++ &map_rule); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; ++ } ++ ++ free(match_rule); ++ match_rule = NULL; ++ ret = ipadb_ldap_attr_to_str(lc, le, IPA_CERTMAP_MATCHRULE, ++ &match_rule); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; ++ } ++ ++ if (domains != NULL) { ++ for (c = 0; domains[c] != NULL; c++) { ++ free(domains[c]); ++ } ++ free(domains); ++ domains = NULL; ++ } ++ ret = ipadb_ldap_attr_to_strlist(lc, le, IPA_ASSOCIATED_DOMAIN, ++ &domains); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; ++ } ++ ++ ret = sss_certmap_add_rule(ctx, prio, match_rule, map_rule, ++ (const char **) domains); ++ if (ret != 0) { ++ goto done; ++ } ++ } ++ } ++ ++ ipactx->certauth_moddata = moddata_out; ++ ++ if (ipactx->realm != NULL) { ++ ipactx->certauth_moddata->local_domain = strdup(ipactx->realm); ++ if (ipactx->certauth_moddata->local_domain == NULL) { ++ free(ipactx->certauth_moddata); ++ ipactx->certauth_moddata = NULL; ++ ret = ENOMEM; ++ goto done; ++ } ++ } ++ ++ ipactx->certauth_moddata->sss_certmap_ctx = ctx; ++ ipactx->certauth_moddata->ipactx = ipactx; ++ ++ } ++ ++ ret = 0; ++ ++done: ++ ldap_msgfree(result); ++ free(basedn); ++ free(map_rule); ++ free(match_rule); ++ if (domains != NULL) { ++ for (c = 0; domains[c] != NULL; c++) { ++ free(domains[c]); ++ } ++ free(domains); ++ domains = NULL; ++ } ++ ++ if (ret != 0) { ++ sss_certmap_free_ctx(ctx); ++ } ++ ++ return ret; ++} ++ ++static krb5_error_code ipa_certauth_authorize(krb5_context context, ++ krb5_certauth_moddata moddata, ++ const uint8_t *cert, ++ size_t cert_len, ++ krb5_const_principal princ, ++ const void *opts, ++ const krb5_db_entry *db_entry, ++ char ***authinds_out) ++{ ++ char *cert_filter = NULL; ++ char **domains = NULL; ++ int ret; ++ size_t c; ++ char *principal = NULL; ++ LDAPMessage *res = NULL; ++ krb5_error_code kerr; ++ LDAPMessage *lentry; ++ ++ if (moddata == NULL) { ++ return KRB5_PLUGIN_NO_HANDLE; ++ } ++ ++ if (moddata->sss_certmap_ctx == NULL) { ++ kerr = ipa_get_init_data(context, moddata); ++ if (kerr != 0) { ++ krb5_klog_syslog(LOG_ERR, "Failed to init certmapping data"); ++ return KRB5_PLUGIN_NO_HANDLE; ++ } ++ } ++ ++ ret = krb5_unparse_name(context, princ, &principal); ++ if (ret != 0) { ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto done; ++ } ++ krb5_klog_syslog(LOG_INFO, "Doing certauth authorize for [%s]", principal); ++ ++ ret = sss_certmap_get_search_filter(moddata->sss_certmap_ctx, ++ cert, cert_len, ++ &cert_filter, &domains); ++ if (ret != 0) { ++ if (ret == ENOENT) { ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ } ++ goto done; ++ } ++ krb5_klog_syslog(LOG_INFO, "Got cert filter [%s]", cert_filter); ++ ++ /* If there are no domains assigned the rule will apply to the local ++ * domain only. */ ++ if (domains != NULL) { ++ ++ if (moddata->local_domain == NULL) { ++ /* We don't know our own domain name, in general this should not ++ * happen. But to be fault tolerant we allow matching rule which ++ * do not have a domain assigned. */ ++ ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto done; ++ } ++ ++ for (c = 0; domains[c] != NULL; c++) { ++ if (strcasecmp(domains[c], moddata->local_domain) == 0) { ++ break; ++ } ++ } ++ ++ /* Our domain was not in the list */ ++ if (domains[c] == NULL) { ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto done; ++ } ++ } ++ ++ kerr = ipadb_fetch_principals_with_extra_filter(moddata->ipactx, ++ KRB5_KDB_FLAG_ALIAS_OK, ++ principal, ++ cert_filter, ++ &res); ++ if (kerr != 0) { ++ krb5_klog_syslog(LOG_ERR, "Search failed [%d]", kerr); ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto done; ++ } ++ ++ kerr = ipadb_find_principal(context, KRB5_KDB_FLAG_ALIAS_OK, res, ++ &principal, &lentry); ++ if (kerr == KRB5_KDB_NOENTRY) { ++ krb5_klog_syslog(LOG_INFO, "No matching entry found"); ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto done; ++ } else if (kerr != 0) { ++ krb5_klog_syslog(LOG_ERR, "ipadb_find_principal failed [%d]", kerr); ++ ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; ++ goto done; ++ } ++ ++ /* TODO: add more tests ? */ ++ ++ ret = 0; ++ ++done: ++ sss_certmap_free_filter_and_domains(cert_filter, domains); ++ krb5_free_unparsed_name(context, principal); ++ ldap_msgfree(res); ++ ++ return ret; ++} ++ ++static krb5_error_code ipa_certauth_init(krb5_context kcontext, ++ krb5_certauth_moddata *moddata_out) ++{ ++ struct krb5_certauth_moddata_st *certauth_moddata; ++ ++ certauth_moddata = calloc(1, sizeof(struct krb5_certauth_moddata_st)); ++ if (certauth_moddata == NULL) { ++ return ENOMEM; ++ } ++ ++ *moddata_out = certauth_moddata; ++ ++ return 0; ++} ++ ++static void ipa_certauth_fini(krb5_context context, ++ krb5_certauth_moddata moddata_out) ++{ ++ krb5_klog_syslog(LOG_INFO, "IPA certauth plugin un-loaded."); ++ return; ++} ++ ++ ++krb5_error_code certauth_ipakdb_initvt(krb5_context context, ++ int maj_ver, int min_ver, ++ krb5_plugin_vtable vtable) ++{ ++ krb5_certauth_vtable vt; ++ ++ if (maj_ver != 1) { ++ return KRB5_PLUGIN_VER_NOTSUPP; ++ } ++ ++ vt = (krb5_certauth_vtable) vtable; ++ ++ vt->name = "ipakdb"; ++ vt->authorize = ipa_certauth_authorize; ++ vt->init = ipa_certauth_init; ++ vt->fini = ipa_certauth_fini; ++ /* currently we do not return authentication indicators */ ++ vt->free_ind = NULL; ++ return 0; ++} +diff --git a/freeipa.spec.in b/freeipa.spec.in +index f776b34af88cc8ccd02da0713cb6eaca161c99f5..18291a5793a6b69dcd719f42e80e1652169e5e1d 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -120,6 +120,7 @@ BuildRequires: libtalloc-devel + BuildRequires: libtevent-devel + BuildRequires: libuuid-devel + BuildRequires: libsss_idmap-devel ++BuildRequires: libsss_certmap-devel + # 1.14.0: sss_nss_getnamebycert (https://fedorahosted.org/sssd/ticket/2897) + BuildRequires: libsss_nss_idmap-devel >= 1.14.0 + BuildRequires: rhino +@@ -1164,6 +1165,7 @@ fi + %attr(0755,root,root) %{_libexecdir}/ipa/oddjob/org.freeipa.server.conncheck + %config(noreplace) %{_sysconfdir}/dbus-1/system.d/org.freeipa.server.conf + %config(noreplace) %{_sysconfdir}/oddjobd.conf.d/ipa-server.conf ++%config(noreplace) %{_sysconfdir}/krb5.conf.d/ipa-certauth + %dir %{_libexecdir}/ipa/certmonger + %attr(755,root,root) %{_libexecdir}/ipa/certmonger/* + # NOTE: systemd specific section +diff --git a/server.m4 b/server.m4 +index 92b5cdd3a6ff90b70a9002360ff3d3aec5053392..7b2e94df91a4803849e496142788a4ed87ef487d 100644 +--- a/server.m4 ++++ b/server.m4 +@@ -30,6 +30,19 @@ dnl -- sss_idmap is needed by the extdom exop -- + PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap]) + PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.13.90]) + ++dnl -- sss_certmap and certauth.h are needed by the IPA KDB certauth plugin -- ++PKG_CHECK_EXISTS([sss_certmap], ++ [PKG_CHECK_MODULES([SSSCERTMAP], [sss_certmap])], ++ [AC_MSG_NOTICE([sss_certmap not found])]) ++AC_CHECK_HEADER([krb5/certauth_plugin.h], ++ [have_certauth_plugin=yes], ++ [have_certauth_plugin=no]) ++AM_CONDITIONAL([BUILD_IPA_CERTAUTH_PLUGIN], ++ [test x$have_certauth_plugin = xyes -a x"$SSSCERTMAP_LIBS" != x]) ++AM_COND_IF([BUILD_IPA_CERTAUTH_PLUGIN], ++ [AC_MSG_NOTICE([Build IPA KDB certauth plugin])], ++ [AC_MSG_WARN([Cannot build IPA KDB certauth plugin])]) ++ + dnl --------------------------------------------------------------------------- + dnl - Check for KRB5 krad + dnl --------------------------------------------------------------------------- +-- +2.12.1 + diff --git a/SOURCES/0019-Show-full-error-message-for-selinuxusermap-add-hostg.patch b/SOURCES/0019-Show-full-error-message-for-selinuxusermap-add-hostg.patch deleted file mode 100644 index ea161af..0000000 --- a/SOURCES/0019-Show-full-error-message-for-selinuxusermap-add-hostg.patch +++ /dev/null @@ -1,152 +0,0 @@ -From b79d70c9977a9b5026f8976e172122bf78885dd8 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Wed, 20 Jul 2016 11:02:30 +0200 -Subject: [PATCH] Show full error message for selinuxusermap-add-hostgroup - -While investigating the issue for selinuxusermap-add-hostgroup, -we discovered that other commands were missing output. -A first patch fixes most of the issues: -freeipa-jcholast-677-frontend-copy-command-arguments-to-output-params-on-.patch - -This patch fixes servicedelegation CLI, where -servicedelegation.takes_params was missing -ipaallowedtarget_servicedelegationtarget, ipaallowedtoimpersonate and -memberprincipal - -https://fedorahosted.org/freeipa/ticket/6026 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/servicedelegation.py | 53 ++++++++++------------------------ - 1 file changed, 15 insertions(+), 38 deletions(-) - -diff --git a/ipaserver/plugins/servicedelegation.py b/ipaserver/plugins/servicedelegation.py -index 958c3b739a2dd465c2b685672c3deb1af8c36e4e..6f38c36a30363755c80081d02bf4c86d829eae34 100644 ---- a/ipaserver/plugins/servicedelegation.py -+++ b/ipaserver/plugins/servicedelegation.py -@@ -96,30 +96,6 @@ PROTECTED_CONSTRAINT_TARGETS = ( - ) - - --output_params = ( -- Str( -- 'ipaallowedtarget_servicedelegationtarget', -- label=_('Allowed Target'), -- ), -- Str( -- 'ipaallowedtoimpersonate', -- label=_('Allowed to Impersonate'), -- ), -- Str( -- 'memberprincipal', -- label=_('Member principals'), -- ), -- Str( -- 'failed_memberprincipal', -- label=_('Failed members'), -- ), -- Str( -- 'ipaallowedtarget', -- label=_('Failed targets'), -- ), --) -- -- - class servicedelegation(LDAPObject): - """ - Service Constrained Delegation base object. -@@ -175,6 +151,21 @@ class servicedelegation(LDAPObject): - label=_('Delegation name'), - primary_key=True, - ), -+ Str( -+ 'ipaallowedtarget_servicedelegationtarget', -+ label=_('Allowed Target'), -+ flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, -+ ), -+ Str( -+ 'ipaallowedtoimpersonate', -+ label=_('Allowed to Impersonate'), -+ flags={'no_create', 'no_update', 'no_search'}, -+ ), -+ Str( -+ 'memberprincipal', -+ label=_('Member principals'), -+ flags={'no_create', 'no_update', 'no_search'}, -+ ), - ) - - -@@ -186,8 +177,6 @@ class servicedelegation_add_member(LDAPAddMember): - principal_attr = 'memberprincipal' - principal_failedattr = 'failed_memberprincipal' - -- has_output_params = LDAPAddMember.has_output_params + output_params -- - def get_options(self): - for option in super(servicedelegation_add_member, self).get_options(): - yield option -@@ -268,8 +257,6 @@ class servicedelegation_remove_member(LDAPRemoveMember): - principal_attr = 'memberprincipal' - principal_failedattr = 'failed_memberprincipal' - -- has_output_params = LDAPRemoveMember.has_output_params + output_params -- - def get_options(self): - for option in super( - servicedelegation_remove_member, self).get_options(): -@@ -397,8 +384,6 @@ class servicedelegationrule_del(LDAPDelete): - class servicedelegationrule_find(LDAPSearch): - __doc__ = _('Search for service delegations rule.') - -- has_output_params = LDAPSearch.has_output_params + output_params -- - msg_summary = ngettext( - '%(count)d service delegation rule matched', - '%(count)d service delegation rules matched', 0 -@@ -409,8 +394,6 @@ class servicedelegationrule_find(LDAPSearch): - class servicedelegationrule_show(LDAPRetrieve): - __doc__ = _('Display information about a named service delegation rule.') - -- has_output_params = LDAPRetrieve.has_output_params + output_params -- - - @register() - class servicedelegationrule_add_member(servicedelegation_add_member): -@@ -437,7 +420,6 @@ class servicedelegationrule_add_target(LDAPAddMember): - attribute_members = { - 'ipaallowedtarget': ['servicedelegationtarget'], - } -- has_output_params = LDAPAddMember.has_output_params + output_params - - - @register() -@@ -447,7 +429,6 @@ class servicedelegationrule_remove_target(LDAPRemoveMember): - attribute_members = { - 'ipaallowedtarget': ['servicedelegationtarget'], - } -- has_output_params = LDAPRemoveMember.has_output_params + output_params - - - @register() -@@ -492,8 +473,6 @@ class servicedelegationtarget_del(LDAPDelete): - class servicedelegationtarget_find(LDAPSearch): - __doc__ = _('Search for service delegation target.') - -- has_output_params = LDAPSearch.has_output_params + output_params -- - msg_summary = ngettext( - '%(count)d service delegation target matched', - '%(count)d service delegation targets matched', 0 -@@ -530,8 +509,6 @@ class servicedelegationtarget_find(LDAPSearch): - class servicedelegationtarget_show(LDAPRetrieve): - __doc__ = _('Display information about a named service delegation target.') - -- has_output_params = LDAPRetrieve.has_output_params + output_params -- - - @register() - class servicedelegationtarget_add_member(servicedelegation_add_member): --- -2.7.4 - diff --git a/SOURCES/0020-allow-value-output-param-in-commands-without-primary.patch b/SOURCES/0020-allow-value-output-param-in-commands-without-primary.patch deleted file mode 100644 index 6c91a7f..0000000 --- a/SOURCES/0020-allow-value-output-param-in-commands-without-primary.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 829e708bf22e80373f1af167fbfb3e6b6bf8655e Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Mon, 18 Jul 2016 13:18:44 +0200 -Subject: [PATCH] allow 'value' output param in commands without primary key - -`PrimaryKey` output param works only for API objects that have primary keys, -otherwise it expects None (nothing is associated with this param). Since the -validation of command output was tightened durng thin client effort, some -commands not honoring this contract began to fail output validation. - -A custom output was implemented for them to restore their functionality. It -should however be considered as a fix for broken commands and not used -further. - -https://fedorahosted.org/freeipa/ticket/6037 -https://fedorahosted.org/freeipa/ticket/6061 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Jan Cholasta ---- - API.txt | 10 +++++----- - VERSION | 4 ++-- - ipalib/output.py | 10 ++++++++++ - ipaserver/plugins/automember.py | 3 +++ - ipaserver/plugins/trust.py | 2 ++ - 5 files changed, 22 insertions(+), 7 deletions(-) - -diff --git a/API.txt b/API.txt -index eb33c1fb7f94f5af45ec0b38fc7e45e484a1044e..535d8ec9a4990395207e2455a09a8c1bdef5529a 100644 ---- a/API.txt -+++ b/API.txt -@@ -144,7 +144,7 @@ option: StrEnum('type', values=[u'group', u'hostgroup']) - option: Str('version?') - output: Entry('result') - output: Output('summary', type=[, ]) --output: PrimaryKey('value') -+output: Output('value', type=[]) - command: automember_default_group_set/1 - args: 0,6,3 - option: Flag('all', autofill=True, cli_name='all', default=False) -@@ -155,7 +155,7 @@ option: StrEnum('type', values=[u'group', u'hostgroup']) - option: Str('version?') - output: Entry('result') - output: Output('summary', type=[, ]) --output: PrimaryKey('value') -+output: Output('value', type=[]) - command: automember_default_group_show/1 - args: 0,4,3 - option: Flag('all', autofill=True, cli_name='all', default=False) -@@ -164,7 +164,7 @@ option: StrEnum('type', values=[u'group', u'hostgroup']) - option: Str('version?') - output: Entry('result') - output: Output('summary', type=[, ]) --output: PrimaryKey('value') -+output: Output('value', type=[]) - command: automember_del/1 - args: 1,2,3 - arg: Str('cn+', cli_name='automember_rule') -@@ -5574,7 +5574,7 @@ option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', val - option: Str('version?') - output: Entry('result') - output: Output('summary', type=[, ]) --output: PrimaryKey('value') -+output: Output('value', type=[]) - command: trustconfig_show/1 - args: 0,5,3 - option: Flag('all', autofill=True, cli_name='all', default=False) -@@ -5584,7 +5584,7 @@ option: StrEnum('trust_type', autofill=True, cli_name='type', default=u'ad', val - option: Str('version?') - output: Entry('result') - output: Output('summary', type=[, ]) --output: PrimaryKey('value') -+output: Output('value', type=[]) - command: trustdomain_add/1 - args: 2,8,3 - arg: Str('trustcn', cli_name='trust') -diff --git a/VERSION b/VERSION -index 0559741451a858dd0adfa99a8bf653261d771601..ca489965050f32d2d8987dfd251ec2b2a0ba1768 100644 ---- a/VERSION -+++ b/VERSION -@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 - # # - ######################################################## - IPA_API_VERSION_MAJOR=2 --IPA_API_VERSION_MINOR=210 --# Last change: Add --ca option to cert-status -+IPA_API_VERSION_MINOR=211 -+# Last change: mbabinsk: allow 'value' output param in commands without primary key -diff --git a/ipalib/output.py b/ipalib/output.py -index 19dd9adadeb8521caf9f0dc52981ce57a7f0c8b6..b104584631629f33280164dd1d23922d21ddea49 100644 ---- a/ipalib/output.py -+++ b/ipalib/output.py -@@ -217,3 +217,13 @@ simple_value = ( - Output('result', bool, _('True means the operation was successful')), - Output('value', unicode, flags=['no_display']), - ) -+ -+# custom shim for commands like `trustconfig-show`, -+# `automember-default-group-*` which put stuff into output['value'] despite not -+# having primary key themselves. Designing commands like this is not a very -+# good practice, so please do not use this for new code. -+simple_entry = ( -+ summary, -+ Entry('result'), -+ Output('value', unicode, flags=['no_display']), -+) -diff --git a/ipaserver/plugins/automember.py b/ipaserver/plugins/automember.py -index dfa8498a6bd44352d854bff7f8eedaba8f731eef..8e9356a9d30c98b7c72735ffb9ac05c672546a0d 100644 ---- a/ipaserver/plugins/automember.py -+++ b/ipaserver/plugins/automember.py -@@ -586,6 +586,7 @@ class automember_default_group_set(LDAPUpdate): - ), - ) + group_type - msg_summary = _('Set default (fallback) group for automember "%(value)s"') -+ has_output = output.simple_entry - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - dn = DN(('cn', options['type']), api.env.container_automember, -@@ -609,6 +610,7 @@ class automember_default_group_remove(LDAPUpdate): - - takes_options = group_type - msg_summary = _('Removed default (fallback) group for automember "%(value)s"') -+ has_output = output.simple_entry - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - dn = DN(('cn', options['type']), api.env.container_automember, -@@ -644,6 +646,7 @@ class automember_default_group_show(LDAPRetrieve): - obj_name = 'automember_default_group' - - takes_options = group_type -+ has_output = output.simple_entry - - def pre_callback(self, ldap, dn, attrs_list, *keys, **options): - dn = DN(('cn', options['type']), api.env.container_automember, -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index 8536202b9b785507bd27b3c7b1896b721f8c5927..d4676bd57054043edd07da5ec3321d755babf35c 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -1288,6 +1288,7 @@ class trustconfig_mod(LDAPUpdate): - - takes_options = LDAPUpdate.takes_options + (_trust_type_option,) - msg_summary = _('Modified "%(value)s" trust configuration') -+ has_output = output.simple_entry - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): - self.obj._normalize_groupdn(entry_attrs) -@@ -1310,6 +1311,7 @@ class trustconfig_show(LDAPRetrieve): - __doc__ = _('Show global trust configuration.') - - takes_options = LDAPRetrieve.takes_options + (_trust_type_option,) -+ has_output = output.simple_entry - - def execute(self, *keys, **options): - result = super(trustconfig_show, self).execute(*keys, **options) --- -2.7.4 - diff --git a/SOURCES/0020-configure-fix-disable-server-with-certauth-plugin.patch b/SOURCES/0020-configure-fix-disable-server-with-certauth-plugin.patch new file mode 100644 index 0000000..67fec06 --- /dev/null +++ b/SOURCES/0020-configure-fix-disable-server-with-certauth-plugin.patch @@ -0,0 +1,55 @@ +From 1dca2667b1e43540c377a45b0f653b0e9bc8840d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 27 Mar 2017 12:18:53 +0200 +Subject: [PATCH] configure: fix --disable-server with certauth plugin + +Resolves https://pagure.io/freeipa/issue/6816 + +Reviewed-By: Christian Heimes +--- + configure.ac | 12 ++++++++++++ + server.m4 | 5 ----- + 2 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 2d84426d1039e822fa3ee53410c819274e763e32..8d4b82e4590e9e122f7aa5684fd78834c4b6a204 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -225,6 +225,18 @@ AM_COND_IF([ENABLE_SERVER], [ + ]) + + dnl --------------------------------------------------------------------------- ++dnl - Check if IPA certauth plugin can be build ++dnl --------------------------------------------------------------------------- ++ ++AM_CONDITIONAL([BUILD_IPA_CERTAUTH_PLUGIN], ++ [test x$have_certauth_plugin = xyes -a x"$SSSCERTMAP_LIBS" != x]) ++AM_COND_IF([BUILD_IPA_CERTAUTH_PLUGIN], [ ++ AM_COND_IF([ENABLE_SERVER], ++ [AC_MSG_NOTICE([Build IPA KDB certauth plugin])], ++ [AC_MSG_WARN([Cannot build IPA KDB certauth plugin])]) ++]) ++ ++dnl --------------------------------------------------------------------------- + dnl - Check for program paths + dnl --------------------------------------------------------------------------- + AC_PATH_PROG(UNLINK, unlink, [AC_MSG_ERROR([unlink not found])]) +diff --git a/server.m4 b/server.m4 +index 7b2e94df91a4803849e496142788a4ed87ef487d..a4c99195ae535e586445cf5bbe9fef457d224531 100644 +--- a/server.m4 ++++ b/server.m4 +@@ -37,11 +37,6 @@ PKG_CHECK_EXISTS([sss_certmap], + AC_CHECK_HEADER([krb5/certauth_plugin.h], + [have_certauth_plugin=yes], + [have_certauth_plugin=no]) +-AM_CONDITIONAL([BUILD_IPA_CERTAUTH_PLUGIN], +- [test x$have_certauth_plugin = xyes -a x"$SSSCERTMAP_LIBS" != x]) +-AM_COND_IF([BUILD_IPA_CERTAUTH_PLUGIN], +- [AC_MSG_NOTICE([Build IPA KDB certauth plugin])], +- [AC_MSG_WARN([Cannot build IPA KDB certauth plugin])]) + + dnl --------------------------------------------------------------------------- + dnl - Check for KRB5 krad +-- +2.12.1 + diff --git a/SOURCES/0021-ipa-kdb-do-not-depend-on-certauth_plugin.h.patch b/SOURCES/0021-ipa-kdb-do-not-depend-on-certauth_plugin.h.patch new file mode 100644 index 0000000..fcbc083 --- /dev/null +++ b/SOURCES/0021-ipa-kdb-do-not-depend-on-certauth_plugin.h.patch @@ -0,0 +1,85 @@ +From 1c421b3874488c0021a5e0d344be31c84c2b4bd0 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 27 Mar 2017 13:19:57 +0200 +Subject: [PATCH] ipa-kdb: do not depend on certauth_plugin.h + +Related to https://pagure.io/freeipa/issue/4905 + +Reviewed-By: Christian Heimes +--- + configure.ac | 2 ++ + daemons/ipa-kdb/ipa_kdb.c | 2 ++ + daemons/ipa-kdb/ipa_kdb.h | 8 ++++++++ + 3 files changed, 12 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 8d4b82e4590e9e122f7aa5684fd78834c4b6a204..ded1d71fd079a5f6947ef0627fb699783c8cc109 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -231,6 +231,8 @@ dnl --------------------------------------------------------------------------- + AM_CONDITIONAL([BUILD_IPA_CERTAUTH_PLUGIN], + [test x$have_certauth_plugin = xyes -a x"$SSSCERTMAP_LIBS" != x]) + AM_COND_IF([BUILD_IPA_CERTAUTH_PLUGIN], [ ++ AC_DEFINE([HAVE_KRB5_CERTAUTH_PLUGIN], [1], ++ [MIT Kerberos version supports certauth plugin]) + AM_COND_IF([ENABLE_SERVER], + [AC_MSG_NOTICE([Build IPA KDB certauth plugin])], + [AC_MSG_WARN([Cannot build IPA KDB certauth plugin])]) +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index a961e4e57cf5379eb237551d56e3bc8dc82d952d..050bfc90cef1bce4c932f54bb6050438c60ca79f 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -67,7 +67,9 @@ static void ipadb_context_free(krb5_context kcontext, + } + free(cfg->authz_data); + ++#ifdef HAVE_KRB5_CERTAUTH_PLUGIN + ipa_certauth_free_moddata(&((*ctx)->certauth_moddata)); ++#endif + + free(*ctx); + *ctx = NULL; +diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h +index 632c1979d15e88aec86d5e408ed6c7017d8362b8..72573a61adecfae152796d61b88b6c43b3a975a3 100644 +--- a/daemons/ipa-kdb/ipa_kdb.h ++++ b/daemons/ipa-kdb/ipa_kdb.h +@@ -30,6 +30,8 @@ + * filtering purposes */ + #define SECURID 1 + ++#include "config.h" ++ + #include + #include + #include +@@ -40,7 +42,9 @@ + #include + #include + #include ++#ifdef HAVE_KRB5_CERTAUTH_PLUGIN + #include ++#endif + + #include "ipa_krb5.h" + #include "ipa_pwd.h" +@@ -112,7 +116,9 @@ struct ipadb_context { + krb5_key_salt_tuple *def_encs; + int n_def_encs; + struct ipadb_mspac *mspac; ++#ifdef HAVE_KRB5_CERTAUTH_PLUGIN + krb5_certauth_moddata certauth_moddata; ++#endif + + /* Don't access this directly, use ipadb_get_global_config(). */ + struct ipadb_global_config config; +@@ -334,5 +340,7 @@ int ipadb_get_enc_salt_types(struct ipadb_context *ipactx, LDAPMessage *entry, + char *attr, krb5_key_salt_tuple **enc_salt_types, + int *n_enc_salt_types); + ++#ifdef HAVE_KRB5_CERTAUTH_PLUGIN + /* CERTAUTH PLUGIN */ + void ipa_certauth_free_moddata(krb5_certauth_moddata *moddata); ++#endif +-- +2.12.1 + diff --git a/SOURCES/0021-server-uninstall-fails-to-remove-krb-principals.patch b/SOURCES/0021-server-uninstall-fails-to-remove-krb-principals.patch deleted file mode 100644 index cdcb725..0000000 --- a/SOURCES/0021-server-uninstall-fails-to-remove-krb-principals.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 028ae66827085960cdfa9861c413a7aeccea5221 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 11 Jul 2016 09:00:44 +0200 -Subject: [PATCH] server uninstall fails to remove krb principals - -This patch fixes the 3rd issue of ticket 6012: -ipa-server-install --uninstall -U -complains while removing Kerberos service principals from /etc/krb5.keytab ----- -Failed to remove Kerberos service principals: Command '/usr/sbin/ipa-rmkeytab -k /etc/krb5.keytab -r DOM-221.ABC.IDM.LAB.ENG.BRQ.REDHAT.COM' returned non-zero exit status 5 ----- - -This happens because the uninstaller performs the following sequence: -1/ restore pre-install files, including /etc/krb5.keytab -At this point /etc/krb5.keytab does not contain any principal for -IPA domain -2/ call ipa-client-install --uninstall, which in turns runs -ipa-rmkeytab -k /etc/krb5.keytab -r -to remove the principals. - -The fix ignores ipa-rmkeytab's exit code 5 (Principal name or realm not -found in keytab) - -https://fedorahosted.org/freeipa/ticket/6012 - -Reviewed-By: Martin Basti ---- - client/ipa-client-install | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/client/ipa-client-install b/client/ipa-client-install -index cee202f89e0f40f4b7ee77e5c38a2c7d50e0dee9..45185d44feb43a8b8d30e412a26dd63121be4ad1 100755 ---- a/client/ipa-client-install -+++ b/client/ipa-client-install -@@ -614,6 +614,13 @@ def uninstall(options, env): - fp.close() - realm = parser.get('global', 'realm') - run([paths.IPA_RMKEYTAB, "-k", paths.KRB5_KEYTAB, "-r", realm]) -+ except CalledProcessError as err: -+ if err.returncode != 5: -+ # 5 means Principal name or realm not found in keytab -+ # and can be ignored -+ root_logger.error( -+ "Failed to remove Kerberos service principals: %s", -+ str(err)) - except Exception as e: - root_logger.error( - "Failed to remove Kerberos service principals: %s", str(e)) --- -2.7.4 - diff --git a/SOURCES/0022-WebUI-Add-support-for-suppressing-warnings.patch b/SOURCES/0022-WebUI-Add-support-for-suppressing-warnings.patch new file mode 100644 index 0000000..8a4d26c --- /dev/null +++ b/SOURCES/0022-WebUI-Add-support-for-suppressing-warnings.patch @@ -0,0 +1,46 @@ +From 3d8b42ac1e532168c2dae96ab0de3d83df0268d0 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Fri, 17 Mar 2017 15:10:42 +0100 +Subject: [PATCH] WebUI: Add support for suppressing warnings + +Each command can have specified an array of warning codes which will +be suppressed and won't be shown. + +For specifying this it is necessary to set command property +'supressed_warnings: [codes_of_warning]' + +Part of: https://pagure.io/freeipa/issue/6618 + +Reviewed-By: Petr Vobornik +--- + install/ui/src/freeipa/rpc.js | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/install/ui/src/freeipa/rpc.js b/install/ui/src/freeipa/rpc.js +index 1880f8d5732f982c25924b787b273c9e56636b20..84282f78d940ac2d18d00df92a7430ca51bbf389 100644 +--- a/install/ui/src/freeipa/rpc.js ++++ b/install/ui/src/freeipa/rpc.js +@@ -72,6 +72,12 @@ rpc.command = function(spec) { + that.options = $.extend({}, spec.options || {}); + + /** ++ * @property {Array} suppress_warnings array of message codes which ++ * are suppressed ++ */ ++ that.suppress_warnings = spec.suppress_warnings || []; ++ ++ /** + * Success handler + * @property {Function} + * @param {Object} data +@@ -219,6 +225,7 @@ rpc.command = function(spec) { + + for (var i=0,l=msgs.length; i -1) continue; + // escape and reformat message + msg.message = util.beautify_message(msg.message); + IPA.notify(msg.message, msg.type); +-- +2.12.1 + diff --git a/SOURCES/0022-expose-secret-option-in-radiusproxy-commands.patch b/SOURCES/0022-expose-secret-option-in-radiusproxy-commands.patch deleted file mode 100644 index dd10fc1..0000000 --- a/SOURCES/0022-expose-secret-option-in-radiusproxy-commands.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a9914cc13e0b04fbe8637214970c99b2328a2dfa Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Mon, 18 Jul 2016 10:45:48 +0200 -Subject: [PATCH] expose `--secret` option in radiusproxy-* commands - -Option `--secret` was hidden from radiusproxy CLI preventing setting a secret -on existing server or searching by secret. Since thin client implementation it -was also not recognized by the interactive prompt code in CLI frontend since -it never got there. - -https://fedorahosted.org/freeipa/ticket/6078 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/radiusproxy.py | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/ipaserver/plugins/radiusproxy.py b/ipaserver/plugins/radiusproxy.py -index 44d87b9ae1337278bb6237d471f64693b0eac3db..5657e002c1ce66335b7697b98f95a49207c61d87 100644 ---- a/ipaserver/plugins/radiusproxy.py -+++ b/ipaserver/plugins/radiusproxy.py -@@ -126,7 +126,6 @@ class radiusproxy(LDAPObject): - label=_('Secret'), - doc=_('The secret used to encrypt data'), - confirm=True, -- flags=['no_option'], - ), - Int('ipatokenradiustimeout?', - cli_name='timeout', --- -2.7.4 - diff --git a/SOURCES/0023-WebUI-suppress-truncation-warning-in-select-widget.patch b/SOURCES/0023-WebUI-suppress-truncation-warning-in-select-widget.patch new file mode 100644 index 0000000..b36a576 --- /dev/null +++ b/SOURCES/0023-WebUI-suppress-truncation-warning-in-select-widget.patch @@ -0,0 +1,37 @@ +From 66ea6269d7ad401e5f89b1ab33f8e827efb25dd8 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Fri, 17 Mar 2017 15:10:49 +0100 +Subject: [PATCH] WebUI: suppress truncation warning in select widget + +This widget is used on details pages and dialogs. When the size limit +is set to lower number the warning about truncation was shown every time +the details page was open. + +Now, with support for suppressing warning messages from server according +to its code, we are able to disable warning with 13017 code (truncation +warning) + +https://pagure.io/freeipa/issue/6618 + +Reviewed-By: Petr Vobornik +--- + install/ui/src/freeipa/widget.js | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js +index 223b449962fabb47cf72b0443e39c295c783ab7f..b7a6504cf4af942c99ee217a2b47718af9e40f86 100644 +--- a/install/ui/src/freeipa/widget.js ++++ b/install/ui/src/freeipa/widget.js +@@ -5012,7 +5012,8 @@ IPA.entity_select_widget = function(spec) { + entity: that.other_entity.name, + method: 'find', + args: [filter], +- options: that.filter_options ++ options: that.filter_options, ++ suppress_warnings: [13017] + }); + var no_members = metadata.get('@mc-opt:' + cmd.get_command() + ':no_members'); + if (no_members) { +-- +2.12.1 + diff --git a/SOURCES/0023-prevent-search-for-RADIUS-proxy-servers-by-secret.patch b/SOURCES/0023-prevent-search-for-RADIUS-proxy-servers-by-secret.patch deleted file mode 100644 index 915e307..0000000 --- a/SOURCES/0023-prevent-search-for-RADIUS-proxy-servers-by-secret.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 57e8d1c6ff58bc58d50d0b1d501820f55a6f2837 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 21 Jul 2016 09:42:01 +0200 -Subject: [PATCH] prevent search for RADIUS proxy servers by secret - -radiusproxy-find should not allow search by proxy secret even for privileged -users so we should hide it from CLI. - -https://fedorahosted.org/freeipa/ticket/6078 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/radiusproxy.py | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/ipaserver/plugins/radiusproxy.py b/ipaserver/plugins/radiusproxy.py -index 5657e002c1ce66335b7697b98f95a49207c61d87..3391b8aed77205fb1a586d5472d8cfdbc9fd1cd5 100644 ---- a/ipaserver/plugins/radiusproxy.py -+++ b/ipaserver/plugins/radiusproxy.py -@@ -169,6 +169,14 @@ class radiusproxy_find(LDAPSearch): - '%(count)d RADIUS proxy server matched', '%(count)d RADIUS proxy servers matched', 0 - ) - -+ def get_options(self): -+ for option in super(radiusproxy_find, self).get_options(): -+ if option.name == 'ipatokenradiussecret': -+ option = option.clone(flags={'no_option'}) -+ -+ yield option -+ -+ - @register() - class radiusproxy_show(LDAPRetrieve): - __doc__ = _('Display information about a RADIUS proxy server.') --- -2.7.4 - diff --git a/SOURCES/0024-WebUI-Fix-showing-vault-in-selfservice-view.patch b/SOURCES/0024-WebUI-Fix-showing-vault-in-selfservice-view.patch new file mode 100644 index 0000000..d729a24 --- /dev/null +++ b/SOURCES/0024-WebUI-Fix-showing-vault-in-selfservice-view.patch @@ -0,0 +1,54 @@ +From 5ccffb9ca109d820c5535140713a5b6672aa4f71 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Fri, 24 Mar 2017 10:19:21 +0100 +Subject: [PATCH] WebUI: Fix showing vault in selfservice view + +Vaults menu item was shown even when the KRA service was not installed. +That was caused by different path to the menu item in admin's view +and in selfservice view. + +The path is now set correctly for both situations. 'network_service/vault' +for admin's view and 'vault' for selfservice view. + +https://pagure.io/freeipa/issue/6812 + +Reviewed-By: Petr Vobornik +--- + install/ui/src/freeipa/navigation/menu_spec.js | 1 + + install/ui/src/freeipa/vault.js | 8 +++++--- + 2 files changed, 6 insertions(+), 3 deletions(-) + +diff --git a/install/ui/src/freeipa/navigation/menu_spec.js b/install/ui/src/freeipa/navigation/menu_spec.js +index 9329694c14a47cbe1ec244554327b40743044d7b..0c30459691d8f652dc35ccf74ed27fae7654020d 100644 +--- a/install/ui/src/freeipa/navigation/menu_spec.js ++++ b/install/ui/src/freeipa/navigation/menu_spec.js +@@ -326,6 +326,7 @@ nav.self_service = { + { entity: 'user' }, + { entity: 'otptoken' }, + { ++ name: 'vault', + entity: 'vault', + facet: 'search', + children: [ +diff --git a/install/ui/src/freeipa/vault.js b/install/ui/src/freeipa/vault.js +index b5cdc810adea9b521df77eb328b55475a707580a..36a4838ee108020cf6ad7a20c59e4ab5403f3528 100644 +--- a/install/ui/src/freeipa/vault.js ++++ b/install/ui/src/freeipa/vault.js +@@ -809,9 +809,11 @@ vault.config_sidebar_policy = function(spec) { + + + vault.remove_vault_menu_item = function() { +- if (!IPA.vault_enabled) { +- menu.remove_item('network_services/vault'); +- } ++ if (IPA.vault_enabled) return; ++ ++ var menu_location = IPA.is_selfservice ? 'vault' : 'network_services/vault'; ++ ++ menu.remove_item(menu_location); + }; + + vault.my_vault_spec = make_my_vault_spec(); +-- +2.12.1 + diff --git a/SOURCES/0024-trust-add-handle-all-raw-options-properly.patch b/SOURCES/0024-trust-add-handle-all-raw-options-properly.patch deleted file mode 100644 index dd90e03..0000000 --- a/SOURCES/0024-trust-add-handle-all-raw-options-properly.patch +++ /dev/null @@ -1,89 +0,0 @@ -From b18c50fb6f596896b35b80178368762d8b9d4a56 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Fri, 15 Jul 2016 12:38:00 +0200 -Subject: [PATCH] trust-add: handle `--all/--raw` options properly - -`trust-add` command did not handle these options correctly often resulting in -internal errors or mangled output. This patch implements a behavior which is -more in-line with the rest of the API commands. - -https://fedorahosted.org/freeipa/ticket/6059 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/trust.py | 41 +++++++++++++++++++++++++++-------------- - 1 file changed, 27 insertions(+), 14 deletions(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index d4676bd57054043edd07da5ec3321d755babf35c..f2e0b1ee4b261ddc4f29477f46b7f4027af18892 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -710,6 +710,25 @@ sides. - msg_summary = _('Added Active Directory trust for realm "%(value)s"') - msg_summary_existing = _('Re-established trust to domain "%(value)s"') - -+ def _format_trust_attrs(self, result, **options): -+ -+ # Format the output into human-readable values -+ attributes = int(result['result'].get('ipanttrustattributes', [0])[0]) -+ -+ if not options.get('raw', False): -+ result['result']['trusttype'] = [trust_type_string( -+ result['result']['ipanttrusttype'][0], attributes)] -+ result['result']['trustdirection'] = [trust_direction_string( -+ result['result']['ipanttrustdirection'][0])] -+ result['result']['truststatus'] = [trust_status_string( -+ result['verified'])] -+ -+ if attributes: -+ result['result'].pop('ipanttrustattributes', None) -+ -+ result['result'].pop('ipanttrustauthoutgoing', None) -+ result['result'].pop('ipanttrustauthincoming', None) -+ - def execute(self, *keys, **options): - ldap = self.obj.backend - -@@ -729,10 +748,15 @@ sides. - else: - created_range_type = old_range['result']['iparangetype'][0] - -+ attrs_list = self.obj.default_attributes -+ if options.get('all', False): -+ attrs_list.append('*') -+ - trust_filter = "cn=%s" % result['value'] - (trusts, truncated) = ldap.find_entries( - base_dn=DN(self.api.env.container_trusts, self.api.env.basedn), -- filter=trust_filter) -+ filter=trust_filter, -+ attrs_list=attrs_list) - - result['result'] = entry_to_dict(trusts[0], **options) - -@@ -761,20 +785,9 @@ sides. - # add_new_domains_from_trust() on its own. - fetch_trusted_domains_over_dbus(self.api, self.log, result['value']) - -- # Format the output into human-readable values -- attributes = int(result['result'].get('ipanttrustattributes', [0])[0]) -- result['result']['trusttype'] = [trust_type_string( -- result['result']['ipanttrusttype'][0], attributes)] -- result['result']['trustdirection'] = [trust_direction_string( -- result['result']['ipanttrustdirection'][0])] -- result['result']['truststatus'] = [trust_status_string( -- result['verified'])] -- if attributes: -- result['result'].pop('ipanttrustattributes', None) -- -+ # Format the output into human-readable values unless `--raw` is given -+ self._format_trust_attrs(result, **options) - del result['verified'] -- result['result'].pop('ipanttrustauthoutgoing', None) -- result['result'].pop('ipanttrustauthincoming', None) - - return result - --- -2.7.4 - diff --git a/SOURCES/0025-Set-KDC-Disable-Last-Success-by-default.patch b/SOURCES/0025-Set-KDC-Disable-Last-Success-by-default.patch new file mode 100644 index 0000000..f5abe43 --- /dev/null +++ b/SOURCES/0025-Set-KDC-Disable-Last-Success-by-default.patch @@ -0,0 +1,35 @@ +From ac3c0d46d947c59aa25f4c9268ef17023c87b4b2 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 22 Mar 2017 17:47:04 +0100 +Subject: [PATCH] Set "KDC:Disable Last Success" by default + +In big deployments enabled recording of the last sucesfull login +this creates a huge changelog on DS side and cause performance +issues even if this is excluded from replication. + +Actually this is not used directly by FreeIPA so it is safe to remove +in new installations. User who need this must manually remove +"KDC:Disable Last Success" using `ipa config-mod` command or WebUI. + +https://pagure.io/freeipa/issue/5313 + +Reviewed-By: Stanislav Laznicka +--- + install/share/bootstrap-template.ldif | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif +index da12ddf0ca887e8305402048ceed5d5b28816164..ea1e5b222e7af5ed7c5d80bbaf9282735e425e18 100644 +--- a/install/share/bootstrap-template.ldif ++++ b/install/share/bootstrap-template.ldif +@@ -410,6 +410,7 @@ ipaUserObjectClasses: ipasshuser + ipaDefaultEmailDomain: $DOMAIN + ipaMigrationEnabled: FALSE + ipaConfigString: AllowNThash ++ipaConfigString: KDC:Disable Last Success + ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 + ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023 + +-- +2.12.1 + diff --git a/SOURCES/0025-unite-log-file-name-of-ipa-ca-install.patch b/SOURCES/0025-unite-log-file-name-of-ipa-ca-install.patch deleted file mode 100644 index 0e10ba9..0000000 --- a/SOURCES/0025-unite-log-file-name-of-ipa-ca-install.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 41b85da8629e69efcc9acf65ba81ab79d38dc609 Mon Sep 17 00:00:00 2001 -From: Petr Vobornik -Date: Fri, 15 Jul 2016 16:25:36 +0200 -Subject: [PATCH] unite log file name of ipa-ca-install - -ipa-ca-install said that it used - /var/log/ipareplica-ca-install.log -but in fact it used - /var/log/ipaserver-ca-install.log - -This patch unites it to ipareplica-ca-install.log - -It was chosen because of backwards compatibility - ipareplica-ca-install -was more commonly used. ipaserver-ca-install.log was used only in rare -CA less -> CA installation. - -https://fedorahosted.org/freeipa/ticket/6086 - -Reviewed-By: Martin Babinsky -Reviewed-By: Jan Cholasta -Reviewed-By: Florence Blanc-Renaud ---- - install/tools/ipa-ca-install | 2 +- - ipaplatform/base/paths.py | 1 - - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index ed685920cbadb9cd3fc80865afb1610ca42f8b13..985e7413aa06900976934c329757ce45da5ff12d 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -285,7 +285,7 @@ def main(): - cainstance.is_ca_installed_locally()): - sys.exit("CA is already installed on this host.") - -- standard_logging_setup(paths.IPASERVER_CA_INSTALL_LOG, debug=options.debug) -+ standard_logging_setup(log_file_name, debug=options.debug) - root_logger.debug("%s was invoked with options: %s,%s", - sys.argv[0], safe_options, filename) - root_logger.debug("IPA version %s", version.VENDOR_VERSION) -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index d6fbe32f6839a5db40148777132ba1454cbc3382..1507ac36da5b40447c951ee608053a09b2db2fc3 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -307,7 +307,6 @@ class BasePathNamespace(object): - IPAREPLICA_CONNCHECK_LOG = "/var/log/ipareplica-conncheck.log" - IPAREPLICA_INSTALL_LOG = "/var/log/ipareplica-install.log" - IPARESTORE_LOG = "/var/log/iparestore.log" -- IPASERVER_CA_INSTALL_LOG = "/var/log/ipaserver-ca-install.log" - IPASERVER_INSTALL_LOG = "/var/log/ipaserver-install.log" - IPASERVER_KRA_INSTALL_LOG = "/var/log/ipaserver-kra-install.log" - IPASERVER_KRA_UNINSTALL_LOG = "/var/log/ipaserver-kra-uninstall.log" --- -2.7.4 - diff --git a/SOURCES/0026-Host-del-fix-behavior-of-updatedns-and-PTR-records.patch b/SOURCES/0026-Host-del-fix-behavior-of-updatedns-and-PTR-records.patch deleted file mode 100644 index 0f2f5ff..0000000 --- a/SOURCES/0026-Host-del-fix-behavior-of-updatedns-and-PTR-records.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 57b757807a53400b8addb19d323f5691122c3ebb Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 21 Jul 2016 13:18:34 +0200 -Subject: [PATCH] Host-del: fix behavior of --updatedns and PTR records - -* target for ptr record must be absolute domain name -* zone is detected using DNS system instead of random splitting of -hostname - -https://fedorahosted.org/freeipa/ticket/6060 - -Reviewed-By: Petr Spacek ---- - ipaserver/plugins/host.py | 26 +++++++++++++++----------- - 1 file changed, 15 insertions(+), 11 deletions(-) - -diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py -index f342b05c87b936ab7b99009cfb0f6d3acde4ef93..413dcf15e0423170d8334902b9dcf8fb5aa14de6 100644 ---- a/ipaserver/plugins/host.py -+++ b/ipaserver/plugins/host.py -@@ -18,6 +18,9 @@ - # You should have received a copy of the GNU General Public License - # along with this program. If not, see . - -+from __future__ import absolute_import -+ -+import dns.resolver - import string - - import six -@@ -134,7 +137,7 @@ register = Registry() - host_pwd_chars = string.digits + string.ascii_letters + '_,.@+-=' - - --def remove_ptr_rec(ipaddr, host, domain): -+def remove_ptr_rec(ipaddr, fqdn): - """ - Remove PTR record of IP address (ipaddr) - :return: True if PTR record was removed, False if record was not found -@@ -143,13 +146,12 @@ def remove_ptr_rec(ipaddr, host, domain): - try: - revzone, revname = get_reverse_zone(ipaddr) - -- # in case domain is in FQDN form with a trailing dot, we needn't add -- # another one, in case it has no trailing dot, dnsrecord-del will -- # normalize the entry -- delkw = {'ptrrecord': "%s.%s" % (host, domain)} -+ # assume that target in PTR record is absolute name (otherwise it is -+ # non-standard configuration) -+ delkw = {'ptrrecord': u"%s" % fqdn.make_absolute()} - - api.Command['dnsrecord_del'](revzone, revname, **delkw) -- except errors.NotFound: -+ except (errors.NotFound, errors.AttrValueNotFound): - api.log.debug('PTR record of ipaddr %s not found', ipaddr) - return False - -@@ -794,13 +796,15 @@ class host_del(LDAPDelete): - - if updatedns: - # Remove A, AAAA, SSHFP and PTR records of the host -- parts = fqdn.split('.') -- domain = unicode('.'.join(parts[1:])) -+ fqdn_dnsname = DNSName(fqdn).make_absolute() -+ zone = DNSName(dns.resolver.zone_for_name(fqdn_dnsname)) -+ relative_hostname = fqdn_dnsname.relativize(zone) -+ - # Get all resources for this host - rec_removed = False - try: - record = api.Command['dnsrecord_show']( -- domain, parts[0])['result'] -+ zone, relative_hostname)['result'] - except errors.NotFound: - pass - else: -@@ -808,13 +812,13 @@ class host_del(LDAPDelete): - for attr in ('arecord', 'aaaarecord'): - for val in record.get(attr, []): - rec_removed = ( -- remove_ptr_rec(val, parts[0], domain) or -+ remove_ptr_rec(val, fqdn_dnsname) or - rec_removed - ) - try: - # remove all A, AAAA, SSHFP records of the host - api.Command['dnsrecord_mod']( -- domain, -+ zone, - record['idnsname'][0], - arecord=[], - aaaarecord=[], --- -2.7.4 - diff --git a/SOURCES/0026-WebUI-Allow-to-add-certs-to-certmapping-with-CERT-LI.patch b/SOURCES/0026-WebUI-Allow-to-add-certs-to-certmapping-with-CERT-LI.patch new file mode 100644 index 0000000..eb02c8d --- /dev/null +++ b/SOURCES/0026-WebUI-Allow-to-add-certs-to-certmapping-with-CERT-LI.patch @@ -0,0 +1,69 @@ +From be6eedde5a5aaf7ad1b527c0cfb9699ccb98a6b5 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Mon, 27 Mar 2017 14:14:32 +0200 +Subject: [PATCH] WebUI: Allow to add certs to certmapping with CERT LINES + around + +The certificate to the certmapping might be inserted as +base64 encoded blob. This patch allows to also insert the certificate +blob with surrounding "-----BEGIN CERTIFICATE-----" and +"-----END CERTIFICATE-----" lines. This behavior is the same in +widget for assigning certificates to users, so the change helps +WebUI to be more consistent. + +https://pagure.io/freeipa/issue/6772 + +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Petr Vobornik +--- + install/ui/src/freeipa/plugins/certmap.js | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/install/ui/src/freeipa/plugins/certmap.js b/install/ui/src/freeipa/plugins/certmap.js +index ecbe095b9ead5c3dad70380202836608d564cd58..c613601e989f065a3d6289b02b60563020acf978 100644 +--- a/install/ui/src/freeipa/plugins/certmap.js ++++ b/install/ui/src/freeipa/plugins/certmap.js +@@ -8,6 +8,7 @@ define([ + 'dojo/_base/declare', + 'dojo/Evented', + 'dojo/on', ++ '../certificate', + '../navigation', + '../field', + '../ipa', +@@ -19,8 +20,8 @@ define([ + // plain imports + '../search', + '../entity'], +- function(lang, declare, Evented, on, navigation, mod_field, IPA, +- phases, reg, widget_mod, text, util) { ++ function(lang, declare, Evented, on, certificate, navigation, ++ mod_field, IPA, phases, reg, widget_mod, text, util) { + /** + * Certificate map module + * @class +@@ -312,6 +313,12 @@ certmap.certmap_multivalued_widget = function (spec) { + var widget = widgets[0]; + var inner_widgets = widget.widgets.get_widgets(); + ++ var normalize_certs = function(certs) { ++ for (var k = 0, l = certs.length; k +Date: Fri, 24 Mar 2017 14:47:38 +0100 +Subject: [PATCH] Bump samba version for FIPS and priv. separation + +With the latest Samba, adding trusts to AD under FIPS should now work +as well as adding trusts as a whole after the privilege separation +rework. + +https://pagure.io/freeipa/issue/6671 +https://pagure.io/freeipa/issue/6697 + +Reviewed-By: Martin Basti +--- + freeipa.spec.in | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 18291a5793a6b69dcd719f42e80e1652169e5e1d..5419ed10723fc7aa3ecc1b3f66b3ef1c8b38b12f 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -36,11 +36,13 @@ + + %global alt_name ipa + %if 0%{?rhel} +-%global samba_version 4.0.5-1 ++# Require 4.6.0-4 which brings RC4 for FIPS + trust fixes to priv. separation ++%global samba_version 4.6.0-4 + %global selinux_policy_version 3.12.1-153 + %global slapi_nis_version 0.56.0-4 + %else +-%global samba_version 2:4.0.5-1 ++# Require 4.6.0-4 which brings RC4 for FIPS + trust fixes to priv. separation ++%global samba_version 2:4.6.0-4 + %global selinux_policy_version 3.13.1-158.4 + %global slapi_nis_version 0.56.1 + %endif +-- +2.12.1 + diff --git a/SOURCES/0027-help-Add-dnsserver-commands-to-help-topic-dns.patch b/SOURCES/0027-help-Add-dnsserver-commands-to-help-topic-dns.patch deleted file mode 100644 index a0b00c8..0000000 --- a/SOURCES/0027-help-Add-dnsserver-commands-to-help-topic-dns.patch +++ /dev/null @@ -1,67 +0,0 @@ -From a7c1e25d3d1c065d0a56e63741c8e5b05ee880a6 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Fri, 15 Jul 2016 11:55:19 +0200 -Subject: [PATCH] help: Add dnsserver commands to help topic 'dns' - -https://fedorahosted.org/freeipa/ticket/6069 - -Reviewed-By: Petr Spacek ---- - ipaserver/plugins/dnsserver.py | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/ipaserver/plugins/dnsserver.py b/ipaserver/plugins/dnsserver.py -index beddec04230d810479fff9612721cf12260bbb3a..d635722a6b6aaea942d49456a04f5d0480d344c9 100644 ---- a/ipaserver/plugins/dnsserver.py -+++ b/ipaserver/plugins/dnsserver.py -@@ -48,6 +48,8 @@ EXAMPLES: - - register = Registry() - -+topic = None -+ - dnsserver_object_class = ['top', 'idnsServerConfigObject'] - - @register() -@@ -149,6 +151,7 @@ class dnsserver(LDAPObject): - @register() - class dnsserver_mod(LDAPUpdate): - __doc__ = _('Modify DNS server configuration') -+ topic = 'dns' - - msg_summary = _('Modified DNS server "%(value)s"') - -@@ -156,6 +159,7 @@ class dnsserver_mod(LDAPUpdate): - @register() - class dnsserver_find(LDAPSearch): - __doc__ = _('Search for DNS servers.') -+ topic = 'dns' - - msg_summary = ngettext( - '%(count)d DNS server matched', -@@ -166,6 +170,7 @@ class dnsserver_find(LDAPSearch): - @register() - class dnsserver_show(LDAPRetrieve): - __doc__=_('Display configuration of a DNS server.') -+ topic = 'dns' - - - @register() -@@ -175,6 +180,7 @@ class dnsserver_add(LDAPCreate, Local): - Be careful in future this will be transformed to public API call - """ - __doc__ = _('Add a new DNS server.') -+ topic = 'dns' - - msg_summary = _('Added new DNS server "%(value)s"') - -@@ -186,5 +192,6 @@ class dnsserver_del(LDAPDelete, Local): - Be careful in future this will be transformed to public API call - """ - __doc__ = _('Delete a DNS server') -+ topic = 'dns' - - msg_summary = _('Deleted DNS server "%(value)s"') --- -2.7.4 - diff --git a/SOURCES/0028-DNS-Locations-fix-update-system-records-unpacking-er.patch b/SOURCES/0028-DNS-Locations-fix-update-system-records-unpacking-er.patch deleted file mode 100644 index dc26a25..0000000 --- a/SOURCES/0028-DNS-Locations-fix-update-system-records-unpacking-er.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0f655b619eae8320757cd6d18f9f1dda6ab2c6ed Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 22 Jul 2016 13:32:31 +0200 -Subject: [PATCH] DNS Locations: fix update-system-records unpacking error - -Method IPASystemRecords.records_list_from_node returns only list -consists only from record names not tuple, which caused unpacking error - -https://fedorahosted.org/freeipa/ticket/6117 - -Reviewed-By: Nikhil Dehadrai ---- - ipaserver/install/bindinstance.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 844fb04a9d9feca936211964b75a0b3468ba663b..7538e145cbe37dfc21963d97dea0e835e3bd5072 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -1139,10 +1139,10 @@ class BindInstance(service.Service): - root_logger.error("Update of following records failed:") - for attr in (failed_ipa_rec, failed_loc_rec): - for rname, node, error in attr: -- for record, e in IPASystemRecords.records_list_from_node( -+ for record in IPASystemRecords.records_list_from_node( - rname, node - ): -- root_logger.error("%s (%s)", record, e) -+ root_logger.error("%s (%s)", record, error) - - def check_global_configuration(self): - """ --- -2.7.4 - diff --git a/SOURCES/0028-Reworked-the-renaming-mechanism.patch b/SOURCES/0028-Reworked-the-renaming-mechanism.patch new file mode 100644 index 0000000..36f0a8d --- /dev/null +++ b/SOURCES/0028-Reworked-the-renaming-mechanism.patch @@ -0,0 +1,296 @@ +From bd2a0a8d363af6c8b1491314d5da5f3c146e4ce6 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Mon, 27 Mar 2017 08:18:29 +0200 +Subject: [PATCH] Reworked the renaming mechanism + +The rename operation on *_mod commands was only allowed when +the primary key of an entry was also its RDN. With these changes, +it should be possible to rename the rest of the entries as well. + +An attribute to the base LDAPObject was added to whitelist the +objects we want to allow to be renamed. It replaced an old +attribute rdn_is_primary_key which was used for the very same +purpose but the name was confusing because it was not set +correctly for certain objects. + +https://pagure.io/freeipa/issue/2466 +https://pagure.io/freeipa/issue/6784 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +--- + ipaserver/plugins/automount.py | 2 +- + ipaserver/plugins/baseldap.py | 32 ++++++++++++++++++++------------ + ipaserver/plugins/baseuser.py | 2 +- + ipaserver/plugins/ca.py | 2 +- + ipaserver/plugins/dns.py | 2 +- + ipaserver/plugins/group.py | 2 +- + ipaserver/plugins/idviews.py | 6 +++--- + ipaserver/plugins/otptoken.py | 2 +- + ipaserver/plugins/permission.py | 2 +- + ipaserver/plugins/privilege.py | 2 +- + ipaserver/plugins/radiusproxy.py | 2 +- + ipaserver/plugins/role.py | 2 +- + ipaserver/plugins/servicedelegation.py | 2 +- + 13 files changed, 34 insertions(+), 26 deletions(-) + +diff --git a/ipaserver/plugins/automount.py b/ipaserver/plugins/automount.py +index c4cf2d6db876e13c78ecd73fc53bb356bf190e17..03f994c65832e7b6099739e951105c4b5a897391 100644 +--- a/ipaserver/plugins/automount.py ++++ b/ipaserver/plugins/automount.py +@@ -456,7 +456,7 @@ class automountkey(LDAPObject): + default_attributes = [ + 'automountkey', 'automountinformation', 'description' + ] +- rdn_is_primary_key = True ++ allow_rename = True + rdn_separator = ' ' + + takes_params = ( +diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py +index 79ba7fc4a14f8105cda481e1599b2acbd8394e45..dbe3cbd28c85ebc3d9254e24e14c5701adc673ab 100644 +--- a/ipaserver/plugins/baseldap.py ++++ b/ipaserver/plugins/baseldap.py +@@ -36,7 +36,7 @@ from ipalib.text import _ + from ipalib.util import json_serialize, validate_hostname + from ipalib.capabilities import client_has_capability + from ipalib.messages import add_message, SearchResultTruncated +-from ipapython.dn import DN ++from ipapython.dn import DN, RDN + from ipapython.version import API_VERSION + + if six.PY3: +@@ -549,7 +549,7 @@ class LDAPObject(Object): + rdn_attribute = '' + uuid_attribute = '' + attribute_members = {} +- rdn_is_primary_key = False # Do we need RDN change to do a rename? ++ allow_rename = False + password_attributes = [] + # Can bind as this entry (has userPassword or krbPrincipalKey) + bindable = False +@@ -1384,7 +1384,7 @@ class LDAPUpdate(LDAPQuery, crud.Update): + def get_options(self): + for option in super(LDAPUpdate, self).get_options(): + yield option +- if self.obj.rdn_is_primary_key: ++ if self.obj.allow_rename: + yield self._get_rename_option() + + def execute(self, *keys, **options): +@@ -1419,15 +1419,19 @@ class LDAPUpdate(LDAPQuery, crud.Update): + _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), list(entry_attrs), allow_only=False) + + rdnupdate = False +- try: +- if self.obj.rdn_is_primary_key and 'rename' in options: +- if not options['rename']: +- raise errors.ValidationError(name='rename', error=u'can\'t be empty') +- entry_attrs[self.obj.primary_key.name] = options['rename'] +- +- if self.obj.rdn_is_primary_key and self.obj.primary_key.name in entry_attrs: ++ if 'rename' in options: ++ if not options['rename']: ++ raise errors.ValidationError( ++ name='rename', error=u'can\'t be empty') ++ entry_attrs[self.obj.primary_key.name] = options['rename'] ++ ++ # if setattr was used to change the RDN, the primary_key.name is ++ # already in entry_attrs ++ if self.obj.allow_rename and self.obj.primary_key.name in entry_attrs: ++ # perform RDN change if the primary key is also RDN ++ if (RDN((self.obj.primary_key.name, keys[-1])) == ++ entry_attrs.dn[0]): + try: +- # RDN change + new_dn = DN((self.obj.primary_key.name, + entry_attrs[self.obj.primary_key.name]), + *entry_attrs.dn[1:]) +@@ -1435,17 +1439,21 @@ class LDAPUpdate(LDAPQuery, crud.Update): + entry_attrs.dn, + new_dn) + +- rdnkeys = keys[:-1] + (entry_attrs[self.obj.primary_key.name], ) ++ rdnkeys = (keys[:-1] + ++ (entry_attrs[self.obj.primary_key.name], )) + entry_attrs.dn = self.obj.get_dn(*rdnkeys) + options['rdnupdate'] = True + rdnupdate = True + except errors.EmptyModlist: + # Attempt to rename to the current name, ignore + pass ++ except errors.NotFound: ++ self.obj.handle_not_found(*keys) + finally: + # Delete the primary_key from entry_attrs either way + del entry_attrs[self.obj.primary_key.name] + ++ try: + # Exception callbacks will need to test for options['rdnupdate'] + # to decide what to do. An EmptyModlist in this context doesn't + # mean an error occurred, just that there were no other updates to +diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py +index 44adc76ec854dadbe0d8a4e8ca03e71c30df526c..bf24dbf542d3b481671dfe4e8cee14a2edcc26e0 100644 +--- a/ipaserver/plugins/baseuser.py ++++ b/ipaserver/plugins/baseuser.py +@@ -164,7 +164,7 @@ class baseuser(LDAPObject): + 'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], + 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], + } +- rdn_is_primary_key = True ++ allow_rename = True + bindable = True + password_attributes = [('userpassword', 'has_password'), + ('krbprincipalkey', 'has_keytab')] +diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py +index f774f78bd6d4ad236b37d06b8b267e8dd78f93b7..9bb163dffa645c1cbb10976e62cbd4a714139319 100644 +--- a/ipaserver/plugins/ca.py ++++ b/ipaserver/plugins/ca.py +@@ -68,7 +68,7 @@ class ca(LDAPObject): + 'cn', 'description', 'ipacaid', 'ipacaissuerdn', 'ipacasubjectdn', + ] + rdn_attribute = 'cn' +- rdn_is_primary_key = True ++ allow_rename = True + label = _('Certificate Authorities') + label_singular = _('Certificate Authority') + +diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py +index 7007928f3b4b2fd863077193671a03ae46119dc5..47ac963a0ae26fcaa81e70a8143bd7d0c172d20e 100644 +--- a/ipaserver/plugins/dns.py ++++ b/ipaserver/plugins/dns.py +@@ -3000,7 +3000,7 @@ class dnsrecord(LDAPObject): + possible_objectclasses = ['idnsTemplateObject'] + permission_filter_objectclasses = ['idnsrecord'] + default_attributes = ['idnsname'] + _record_attributes +- rdn_is_primary_key = True ++ allow_rename = True + + label = _('DNS Resource Records') + label_singular = _('DNS Resource Record') +diff --git a/ipaserver/plugins/group.py b/ipaserver/plugins/group.py +index 218da3c94d95bb399761acf9414182eff566c63b..1fb092d5f049e86f12681e5eb2397f98f1001697 100644 +--- a/ipaserver/plugins/group.py ++++ b/ipaserver/plugins/group.py +@@ -173,7 +173,7 @@ class group(LDAPObject): + 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', + 'sudorule'], + } +- rdn_is_primary_key = True ++ allow_rename = True + managed_permissions = { + 'System: Read Groups': { + 'replaces_global_anonymous_aci': True, +diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py +index 6d4ac75209ea08e3c2969d53e1ae5372c3a535ac..b5ee32cf138677874497e2f345c932c352e20054 100644 +--- a/ipaserver/plugins/idviews.py ++++ b/ipaserver/plugins/idviews.py +@@ -97,7 +97,7 @@ class idview(LDAPObject): + object_class = ['ipaIDView', 'top'] + possible_objectclasses = ['ipaNameResolutionData'] + default_attributes = ['cn', 'description', 'ipadomainresolutionorder'] +- rdn_is_primary_key = True ++ allow_rename = True + + label = _('ID Views') + label_singular = _('ID View') +@@ -848,7 +848,7 @@ class idoverrideuser(baseidoverride): + + label = _('User ID overrides') + label_singular = _('User ID override') +- rdn_is_primary_key = True ++ allow_rename = True + + # ID user overrides are bindable because we map SASL GSSAPI + # authentication of trusted users to ID user overrides in the +@@ -964,7 +964,7 @@ class idoverridegroup(baseidoverride): + + label = _('Group ID overrides') + label_singular = _('Group ID override') +- rdn_is_primary_key = True ++ allow_rename = True + + permission_filter_objectclasses = ['ipaGroupOverride'] + managed_permissions = { +diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py +index 98ecbe58b84622d7937a7e6eff77c5e41624bf4f..c66f0980f0fc2ed49b4224be40a18ce528a6da7b 100644 +--- a/ipaserver/plugins/otptoken.py ++++ b/ipaserver/plugins/otptoken.py +@@ -143,7 +143,7 @@ class otptoken(LDAPObject): + relationships = { + 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), + } +- rdn_is_primary_key = True ++ allow_rename = True + + label = _('OTP Tokens') + label_singular = _('OTP Token') +diff --git a/ipaserver/plugins/permission.py b/ipaserver/plugins/permission.py +index dd2a0183e90ed6da9e55fb0590ea0bd81bf0bd67..977c6fe363c501f820aa82ae5b2ea00d8c78c7ae 100644 +--- a/ipaserver/plugins/permission.py ++++ b/ipaserver/plugins/permission.py +@@ -188,7 +188,7 @@ class permission(baseldap.LDAPObject): + 'member': ['privilege'], + 'memberindirect': ['role'], + } +- rdn_is_primary_key = True ++ allow_rename = True + managed_permissions = { + 'System: Read Permissions': { + 'replaces_global_anonymous_aci': True, +diff --git a/ipaserver/plugins/privilege.py b/ipaserver/plugins/privilege.py +index b3afbd289ac2e82d5569b5d5306be398a560413e..01d5396902d482eb5a9f21e7ece730a0a35157d6 100644 +--- a/ipaserver/plugins/privilege.py ++++ b/ipaserver/plugins/privilege.py +@@ -101,7 +101,7 @@ class privilege(LDAPObject): + reverse_members = { + 'member': ['permission'], + } +- rdn_is_primary_key = True ++ allow_rename = True + managed_permissions = { + 'System: Read Privileges': { + 'replaces_global_anonymous_aci': True, +diff --git a/ipaserver/plugins/radiusproxy.py b/ipaserver/plugins/radiusproxy.py +index 3391b8aed77205fb1a586d5472d8cfdbc9fd1cd5..be77c62432066beec951e5f50afe689e1d6debce 100644 +--- a/ipaserver/plugins/radiusproxy.py ++++ b/ipaserver/plugins/radiusproxy.py +@@ -101,7 +101,7 @@ class radiusproxy(LDAPObject): + 'ipatokenradiustimeout', 'ipatokenradiusretries', 'ipatokenusermapattribute' + ] + search_attributes = ['cn', 'description', 'ipatokenradiusserver'] +- rdn_is_primary_key = True ++ allow_rename = True + label = _('RADIUS Servers') + label_singular = _('RADIUS Server') + +diff --git a/ipaserver/plugins/role.py b/ipaserver/plugins/role.py +index 5d0d1f8c657b8d840762135f5ff16db90fb4893f..e7f115c461a6a0421f9c43d0410daaf9d4307e76 100644 +--- a/ipaserver/plugins/role.py ++++ b/ipaserver/plugins/role.py +@@ -92,7 +92,7 @@ class role(LDAPObject): + reverse_members = { + 'member': ['privilege'], + } +- rdn_is_primary_key = True ++ allow_rename = True + managed_permissions = { + 'System: Read Roles': { + 'replaces_global_anonymous_aci': True, +diff --git a/ipaserver/plugins/servicedelegation.py b/ipaserver/plugins/servicedelegation.py +index c8052e957cc5f8d24f6a8d0621ca93422052e35b..4f94924fa76691bcd6c6fc2cef9eb7fb30fce48c 100644 +--- a/ipaserver/plugins/servicedelegation.py ++++ b/ipaserver/plugins/servicedelegation.py +@@ -138,7 +138,7 @@ class servicedelegation(LDAPObject): + }, + } + +- rdn_is_primary_key = True ++ allow_rename = True + + takes_params = ( + Str( +-- +2.12.1 + diff --git a/SOURCES/0029-Allow-renaming-of-the-HBAC-rule-objects.patch b/SOURCES/0029-Allow-renaming-of-the-HBAC-rule-objects.patch new file mode 100644 index 0000000..2247186 --- /dev/null +++ b/SOURCES/0029-Allow-renaming-of-the-HBAC-rule-objects.patch @@ -0,0 +1,103 @@ +From 496255286bdf83c11deeba08755de56e639de000 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Mon, 27 Mar 2017 08:25:04 +0200 +Subject: [PATCH] Allow renaming of the HBAC rule objects + +The recent changes allow HBAC rule objects to be renamed. + +https://pagure.io/freeipa/issue/6784 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +--- + API.txt | 3 ++- + VERSION.m4 | 4 ++-- + ipaserver/plugins/hbacrule.py | 1 + + ipatests/test_xmlrpc/test_hbac_plugin.py | 15 +++++++++++++++ + 4 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/API.txt b/API.txt +index f0bd1b6495854decf4470efdcf1f2d915ce71c52..2a63c983a343b07ec7928bc774c6443a84b7c64c 100644 +--- a/API.txt ++++ b/API.txt +@@ -2163,7 +2163,7 @@ output: ListOfEntries('result') + output: Output('summary', type=[, ]) + output: Output('truncated', type=[]) + command: hbacrule_mod/1 +-args: 1,16,3 ++args: 1,17,3 + arg: Str('cn', cli_name='name') + option: StrEnum('accessruletype?', autofill=False, cli_name='type', default=u'allow', values=[u'allow', u'deny']) + option: Str('addattr*', cli_name='addattr') +@@ -2175,6 +2175,7 @@ option: StrEnum('hostcategory?', autofill=False, cli_name='hostcat', values=[u'a + option: Bool('ipaenabledflag?', autofill=False) + option: Flag('no_members', autofill=True, default=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False) ++option: Str('rename?', cli_name='rename') + option: Flag('rights', autofill=True, default=False) + option: StrEnum('servicecategory?', autofill=False, cli_name='servicecat', values=[u'all']) + option: Str('setattr*', cli_name='setattr') +diff --git a/VERSION.m4 b/VERSION.m4 +index 743f2dbe0d05126f11c67574c5a9b712cb1f112d..bbb5212e5b8cd9604b6ec90d4a0bd4c3276b1856 100644 +--- a/VERSION.m4 ++++ b/VERSION.m4 +@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000) + # # + ######################################################## + define(IPA_API_VERSION_MAJOR, 2) +-define(IPA_API_VERSION_MINOR, 223) +-# Last change: Add domain resolution order to ID views ++define(IPA_API_VERSION_MINOR, 224) ++# Last change: Add rename option to HBAC rule objects + + + ######################################################## +diff --git a/ipaserver/plugins/hbacrule.py b/ipaserver/plugins/hbacrule.py +index 60e5e606fff6d2ffb93db608328c5987b91d1fa8..2495702e87accaf60eb38dae0fb122ac0764452f 100644 +--- a/ipaserver/plugins/hbacrule.py ++++ b/ipaserver/plugins/hbacrule.py +@@ -141,6 +141,7 @@ class hbacrule(LDAPObject): + ] + uuid_attribute = 'ipauniqueid' + rdn_attribute = 'ipauniqueid' ++ allow_rename = True + attribute_members = { + 'memberuser': ['user', 'group'], + 'memberhost': ['host', 'hostgroup'], +diff --git a/ipatests/test_xmlrpc/test_hbac_plugin.py b/ipatests/test_xmlrpc/test_hbac_plugin.py +index 75c15c5abe472d975f0c2bc78eb9dd5fda8af45e..b495fe3341f8d0682f65b4fc1d408734d130a7cd 100644 +--- a/ipatests/test_xmlrpc/test_hbac_plugin.py ++++ b/ipatests/test_xmlrpc/test_hbac_plugin.py +@@ -34,6 +34,7 @@ class test_hbac(XMLRPC_test): + Test the `hbacrule` plugin. + """ + rule_name = u'testing_rule1234' ++ rule_renamed = u'mega_testing_rule' + rule_type = u'allow' + rule_type_fail = u'value not allowed' + rule_service = u'ssh' +@@ -459,6 +460,20 @@ class test_hbac(XMLRPC_test): + assert_attr_equal(entry, 'cn', self.rule_name) + assert_attr_equal(entry, 'memberservice_hbacsvc', self.test_service) + ++ def test_o_hbacrule_rename(self): ++ """ ++ Test renaming an HBAC rule, rename it back afterwards ++ """ ++ api.Command['hbacrule_mod']( ++ self.rule_name, rename=self.rule_renamed ++ ) ++ entry = api.Command['hbacrule_show'](self.rule_renamed)['result'] ++ assert_attr_equal(entry, 'cn', self.rule_renamed) ++ # clean up by renaming the rule back ++ api.Command['hbacrule_mod']( ++ self.rule_renamed, rename=self.rule_name ++ ) ++ + def test_y_hbacrule_zap_testing_data(self): + """ + Clear data for HBAC plugin testing. +-- +2.12.1 + diff --git a/SOURCES/0029-Fix-session-cookies.patch b/SOURCES/0029-Fix-session-cookies.patch deleted file mode 100644 index dc2dd2c..0000000 --- a/SOURCES/0029-Fix-session-cookies.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 059ced75270c681144462dba3772812901495054 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 21 Jul 2016 16:54:43 +0200 -Subject: [PATCH] Fix session cookies - -The CLI was not using session cookies for communication with IPA API. -The kernel_keyring code was expecting the keyname to be a string, but -in python 2 a unicode was supplied (the key is built using -ipa_session_cookie:%principal and principal is a unicode). - -The patch fixes the assertions, allowing to store and retrieve the cookie. -It also adds a test with unicode key name. - -https://fedorahosted.org/freeipa/ticket/5984 - -Reviewed-By: Petr Spacek ---- - ipapython/kernel_keyring.py | 15 ++++++++------- - ipatests/test_ipapython/test_keyring.py | 15 +++++++++++++++ - 2 files changed, 23 insertions(+), 7 deletions(-) - -diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py -index ed4868a9d8eaffdae6f717928663296bd20c762e..651fd708667420d1769e3601a8fa0b6c52604a10 100644 ---- a/ipapython/kernel_keyring.py -+++ b/ipapython/kernel_keyring.py -@@ -18,6 +18,7 @@ - # - - import os -+import six - - from ipapython.ipautil import run - -@@ -45,7 +46,7 @@ def get_real_key(key): - One cannot request a key based on the description it was created with - so find the one we're looking for. - """ -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - result = run(['keyctl', 'search', KEYRING, KEYTYPE, key], - raiseonerr=False, capture_output=True) - if result.returncode: -@@ -53,7 +54,7 @@ def get_real_key(key): - return result.raw_output.rstrip() - - def get_persistent_key(key): -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - result = run(['keyctl', 'get_persistent', KEYRING, key], - raiseonerr=False, capture_output=True) - if result.returncode: -@@ -73,7 +74,7 @@ def has_key(key): - """ - Returns True/False whether the key exists in the keyring. - """ -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - try: - get_real_key(key) - return True -@@ -86,7 +87,7 @@ def read_key(key): - - Use pipe instead of print here to ensure we always get the raw data. - """ -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - real_key = get_real_key(key) - result = run(['keyctl', 'pipe', real_key], raiseonerr=False, - capture_output=True) -@@ -99,7 +100,7 @@ def update_key(key, value): - """ - Update the keyring data. If they key doesn't exist it is created. - """ -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - assert isinstance(value, bytes) - if has_key(key): - real_key = get_real_key(key) -@@ -114,7 +115,7 @@ def add_key(key, value): - """ - Add a key to the kernel keyring. - """ -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - assert isinstance(value, bytes) - if has_key(key): - raise ValueError('key %s already exists' % key) -@@ -127,7 +128,7 @@ def del_key(key): - """ - Remove a key from the keyring - """ -- assert isinstance(key, str) -+ assert isinstance(key, six.string_types) - real_key = get_real_key(key) - result = run(['keyctl', 'unlink', real_key, KEYRING], - raiseonerr=False) -diff --git a/ipatests/test_ipapython/test_keyring.py b/ipatests/test_ipapython/test_keyring.py -index e22841c8f5d229d17cdd05ab9c4248eeffaab249..c81e6d95f7ebdf585ee37ecf71151c01e0001912 100644 ---- a/ipatests/test_ipapython/test_keyring.py -+++ b/ipatests/test_ipapython/test_keyring.py -@@ -28,6 +28,7 @@ import pytest - pytestmark = pytest.mark.tier0 - - TEST_KEY = 'ipa_test' -+TEST_UNICODEKEY = u'ipa_unicode' - TEST_VALUE = b'abc123' - UPDATE_VALUE = b'123abc' - -@@ -49,6 +50,10 @@ class test_keyring(object): - kernel_keyring.del_key(SIZE_256) - except ValueError: - pass -+ try: -+ kernel_keyring.del_key(TEST_UNICODEKEY) -+ except ValueError: -+ pass - - def test_01(self): - """ -@@ -150,3 +155,13 @@ class test_keyring(object): - assert(result == SIZE_1024.encode('ascii')) - - kernel_keyring.del_key(TEST_KEY) -+ -+ def test_10(self): -+ """ -+ Test a unicode key -+ """ -+ kernel_keyring.add_key(TEST_UNICODEKEY, TEST_VALUE) -+ result = kernel_keyring.read_key(TEST_UNICODEKEY) -+ assert(result == TEST_VALUE) -+ -+ kernel_keyring.del_key(TEST_UNICODEKEY) --- -2.7.4 - diff --git a/SOURCES/0030-Allow-renaming-of-the-sudorule-objects.patch b/SOURCES/0030-Allow-renaming-of-the-sudorule-objects.patch new file mode 100644 index 0000000..7198e0f --- /dev/null +++ b/SOURCES/0030-Allow-renaming-of-the-sudorule-objects.patch @@ -0,0 +1,100 @@ +From f868a2016bdad996fac9cc9d3b3e9b4228ab1dd4 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Mon, 27 Mar 2017 08:26:03 +0200 +Subject: [PATCH] Allow renaming of the sudorule objects + +The recent changes allow the sudorule objects to be renamed. + +https://pagure.io/freeipa/issue/2466 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +--- + API.txt | 3 ++- + VERSION.m4 | 2 +- + ipaserver/plugins/sudorule.py | 1 + + ipatests/test_xmlrpc/test_sudorule_plugin.py | 14 ++++++++++++++ + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/API.txt b/API.txt +index 2a63c983a343b07ec7928bc774c6443a84b7c64c..7594157384511c1317738dafb41361676a2a0fd7 100644 +--- a/API.txt ++++ b/API.txt +@@ -5403,7 +5403,7 @@ output: ListOfEntries('result') + output: Output('summary', type=[, ]) + output: Output('truncated', type=[]) + command: sudorule_mod/1 +-args: 1,20,3 ++args: 1,21,3 + arg: Str('cn', cli_name='sudorule_name') + option: Str('addattr*', cli_name='addattr') + option: Flag('all', autofill=True, cli_name='all', default=False) +@@ -5420,6 +5420,7 @@ option: StrEnum('ipasudorunasgroupcategory?', autofill=False, cli_name='runasgro + option: StrEnum('ipasudorunasusercategory?', autofill=False, cli_name='runasusercat', values=[u'all']) + option: Flag('no_members', autofill=True, default=False) + option: Flag('raw', autofill=True, cli_name='raw', default=False) ++option: Str('rename?', cli_name='rename') + option: Flag('rights', autofill=True, default=False) + option: Str('setattr*', cli_name='setattr') + option: Int('sudoorder?', autofill=False, cli_name='order', default=0) +diff --git a/VERSION.m4 b/VERSION.m4 +index bbb5212e5b8cd9604b6ec90d4a0bd4c3276b1856..31e7c1d6e7054d3b4ef1d9dfaf349d2959f8330a 100644 +--- a/VERSION.m4 ++++ b/VERSION.m4 +@@ -74,7 +74,7 @@ define(IPA_DATA_VERSION, 20100614120000) + ######################################################## + define(IPA_API_VERSION_MAJOR, 2) + define(IPA_API_VERSION_MINOR, 224) +-# Last change: Add rename option to HBAC rule objects ++# Last change: Add rename option to sudorule objects + + + ######################################################## +diff --git a/ipaserver/plugins/sudorule.py b/ipaserver/plugins/sudorule.py +index 90771072ac8645863e77e88b2500c47c0bb2c8df..28c3f21f113fd14160abd518663f2d582f8653fd 100644 +--- a/ipaserver/plugins/sudorule.py ++++ b/ipaserver/plugins/sudorule.py +@@ -145,6 +145,7 @@ class sudorule(LDAPObject): + ] + uuid_attribute = 'ipauniqueid' + rdn_attribute = 'ipauniqueid' ++ allow_rename = True + attribute_members = { + 'memberuser': ['user', 'group'], + 'memberhost': ['host', 'hostgroup'], +diff --git a/ipatests/test_xmlrpc/test_sudorule_plugin.py b/ipatests/test_xmlrpc/test_sudorule_plugin.py +index c37262a43cc3805913688be4bda0318d67b364c4..75dbfbe67202a57299330d21200fe7ca1bb3f77e 100644 +--- a/ipatests/test_xmlrpc/test_sudorule_plugin.py ++++ b/ipatests/test_xmlrpc/test_sudorule_plugin.py +@@ -42,6 +42,7 @@ class test_sudorule(XMLRPC_test): + """ + rule_name = u'testing_sudorule1' + rule_name2 = u'testing_sudorule2' ++ rule_renamed = u'testing_mega_sudorule' + rule_command = u'/usr/bin/testsudocmd1' + rule_desc = u'description' + rule_desc_mod = u'description modified' +@@ -782,6 +783,19 @@ class test_sudorule(XMLRPC_test): + api.Command['sudorule_mod'](self.rule_name, sudoorder=None) + api.Command['sudorule_mod'](self.rule_name2, sudoorder=None) + ++ def test_l_1_sudorule_rename(self): ++ """ ++ Test renaming an HBAC rule, rename it back afterwards ++ """ ++ api.Command['sudorule_mod']( ++ self.rule_name, rename=self.rule_renamed ++ ) ++ entry = api.Command['sudorule_show'](self.rule_renamed)['result'] ++ assert_attr_equal(entry, 'cn', self.rule_renamed) ++ # clean up by renaming the rule back ++ api.Command['sudorule_mod']( ++ self.rule_renamed, rename=self.rule_name ++ ) + + def test_m_sudorule_del(self): + """ +-- +2.12.1 + diff --git a/SOURCES/0030-Use-copy-when-replacing-files-to-keep-SELinux-contex.patch b/SOURCES/0030-Use-copy-when-replacing-files-to-keep-SELinux-contex.patch deleted file mode 100644 index ac00108..0000000 --- a/SOURCES/0030-Use-copy-when-replacing-files-to-keep-SELinux-contex.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 602d1c5190cfb879f81ced19e60d1eb08bd559f0 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 21 Jul 2016 18:49:57 +0200 -Subject: [PATCH] Use copy when replacing files to keep SELinux context - -When installer replaces any file with newer, it must use 'copy' instead of -'mv' to keep SELinux context valid. - -https://fedorahosted.org/freeipa/ticket/6111 - -Reviewed-By: Petr Spacek ---- - ipapython/ipautil.py | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py -index 763a99c117e22a4ac49d8d34b38230f3da7c8435..9964fba4f694b57242b3bd3065a418917d977533 100644 ---- a/ipapython/ipautil.py -+++ b/ipapython/ipautil.py -@@ -528,10 +528,14 @@ def dir_exists(filename): - except Exception: - return False - -+ - def install_file(fname, dest): -+ # SELinux: use copy to keep the right context - if file_exists(dest): - os.rename(dest, dest + ".orig") -- shutil.move(fname, dest) -+ shutil.copy(fname, dest) -+ os.remove(fname) -+ - - def backup_file(fname): - if file_exists(fname): --- -2.7.4 - diff --git a/SOURCES/0031-Create-temporaty-directories-at-the-begining-of-unin.patch b/SOURCES/0031-Create-temporaty-directories-at-the-begining-of-unin.patch new file mode 100644 index 0000000..3c73e87 --- /dev/null +++ b/SOURCES/0031-Create-temporaty-directories-at-the-begining-of-unin.patch @@ -0,0 +1,36 @@ +From e344a42bfff8c9d124b13ae43baec72c5329e29f Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Thu, 23 Mar 2017 12:48:06 +0100 +Subject: [PATCH] Create temporaty directories at the begining of uninstall + +Since commit 38c6689 temporary directories are no longer created at package +install time. Instead they're created at server install time. +Some steps in uninstall also assume that temporary direcories exist. Creating +the directories in the begining of server uninstall ensure that the uninstall +will go through. + +https://pagure.io/freeipa/issue/6715 + +Reviewed-By: Martin Basti +--- + ipaserver/install/server/install.py | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index de6b5b31274c87ceca5d98bcf8e80230ec6ae1f7..d7eb0bfacd0815026c82f59d76962f527e2b7dad 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -1042,6 +1042,10 @@ def uninstall(installer): + + rv = 0 + ++ # further steps assumes that temporary directories exists so rather ++ # ensure they are created ++ tasks.create_tmpfiles_dirs() ++ + print("Shutting down all IPA services") + try: + services.knownservices.ipa.stop() +-- +2.12.1 + diff --git a/SOURCES/0031-baseldap-Fix-MidairCollision-instantiation-during-en.patch b/SOURCES/0031-baseldap-Fix-MidairCollision-instantiation-during-en.patch deleted file mode 100644 index 9b87f51..0000000 --- a/SOURCES/0031-baseldap-Fix-MidairCollision-instantiation-during-en.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 25b1fb956cc8029d5030d93cf48faed823778c5e Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Mon, 25 Jul 2016 14:05:08 +0200 -Subject: [PATCH] baseldap: Fix MidairCollision instantiation during entry - modification - -https://fedorahosted.org/freeipa/ticket/6097 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/baseldap.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py -index 6107e43a6ee17d9b9a63d9dc109664d8b232069f..f7844e3e7c59c259b9c8367d135b2dbefc3f0016 100644 ---- a/ipaserver/plugins/baseldap.py -+++ b/ipaserver/plugins/baseldap.py -@@ -1466,7 +1466,7 @@ class LDAPUpdate(LDAPQuery, crud.Update): - entry_attrs.dn, attrs_list) - except errors.NotFound: - raise errors.MidairCollision( -- format=_('the entry was deleted while being modified') -+ message=_('the entry was deleted while being modified') - ) - - self.obj.get_indirect_members(entry_attrs, attrs_list) -@@ -2344,7 +2344,7 @@ class BaseLDAPModAttribute(LDAPQuery): - entry_attrs.dn, attrs_list) - except errors.NotFound: - raise errors.MidairCollision( -- format=_('the entry was deleted while being modified') -+ message=_('the entry was deleted while being modified') - ) - - for callback in self.get_callbacks('post'): --- -2.7.4 - diff --git a/SOURCES/0032-Create-indexes-for-krbCanonicalName-attribute.patch b/SOURCES/0032-Create-indexes-for-krbCanonicalName-attribute.patch deleted file mode 100644 index 7a008f3..0000000 --- a/SOURCES/0032-Create-indexes-for-krbCanonicalName-attribute.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 1eed28c173336da828ac60b64b09a8b01d79fab4 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Fri, 22 Jul 2016 13:02:38 +0200 -Subject: [PATCH] Create indexes for krbCanonicalName attribute - -krbCanonicalName is for a long time among the attributes guarded by uniqueness -plugins, but there was never an index for it. Now that the attribute is really -used to store canonical principal names we need to add index for it to avoid -performance regressions. - -https://fedorahosted.org/freeipa/ticket/6100 - -Reviewed-By: Thierry Bordaz ---- - install/share/indices.ldif | 9 +++++++++ - install/updates/20-indices.update | 8 ++++++++ - 2 files changed, 17 insertions(+) - -diff --git a/install/share/indices.ldif b/install/share/indices.ldif -index 642c2f7aee78b684b3e451c2595e4f18950e449e..d853266025ae350dd7de83e11e463c6bb1ab9429 100644 ---- a/install/share/indices.ldif -+++ b/install/share/indices.ldif -@@ -269,3 +269,12 @@ ObjectClass: nsIndex - nsSystemIndex: false - nsIndexType: eq - nsIndexType: pres -+ -+dn: cn=krbCanonicalName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config -+changetype: add -+cn: krbCanonicalName -+objectClass: top -+objectClass: nsIndex -+nsSystemIndex: false -+nsIndexType: eq -+nsIndexType: sub -diff --git a/install/updates/20-indices.update b/install/updates/20-indices.update -index 445eda5ab6939f21654335ea4dd50d7b2cab008f..74961d77875515d680f34af739c984a6533eb252 100644 ---- a/install/updates/20-indices.update -+++ b/install/updates/20-indices.update -@@ -251,3 +251,11 @@ only: nsMatchingRule: caseIgnoreIA5Match - only: nsMatchingRule: caseExactIA5Match - only:nsIndexType: eq - only:nsIndexType: sub -+ -+dn: cn=krbCanonicalName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config -+default: cn: krbCanonicalName -+default: objectClass: top -+default: objectClass: nsIndex -+only: nsSystemIndex: false -+only: nsIndexType: eq -+only: nsIndexType: sub --- -2.7.4 - diff --git a/SOURCES/0032-dogtag-ipa-ca-renew-agent-submit-fix-the-is_replicat.patch b/SOURCES/0032-dogtag-ipa-ca-renew-agent-submit-fix-the-is_replicat.patch new file mode 100644 index 0000000..cd3f5ba --- /dev/null +++ b/SOURCES/0032-dogtag-ipa-ca-renew-agent-submit-fix-the-is_replicat.patch @@ -0,0 +1,38 @@ +From c7d19fca09f7398af63ceffb915afc9b5d507e1e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 24 Mar 2017 11:02:33 +0100 +Subject: [PATCH] dogtag-ipa-ca-renew-agent-submit: fix the is_replicated() + function + +dogtag-ipa-ca-renew-agent-submit behaves differently depending on the +certificate it needs to renew. For instance, some certificates (such as IPA RA) +are the same on all the hosts and the renewal is actually done only on +the renewal master. On other nodes, the new cert is downloaded from LDAP. + +The function is_replicated() is returning the opposite as what it should. If +the cert nickname is IPA RA, it should return that the cert is replicated but +it doesn't, and this leads to a wrong code path to renew the cert. + +https://pagure.io/freeipa/issue/6813 + +Reviewed-By: Jan Cholasta +--- + 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 cc690b8fa26854a5ab683915a5ba6a8d3c0d4ae4..5782db703c49d7c2e92c806e24e9925e8e7d710a 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -119,7 +119,7 @@ def is_renewable(): + + + def is_replicated(): +- return not get_nickname() ++ return bool(get_nickname()) + + + def is_renewal_master(): +-- +2.12.1 + diff --git a/SOURCES/0033-Simplify-KRA-transport-cert-cache.patch b/SOURCES/0033-Simplify-KRA-transport-cert-cache.patch new file mode 100644 index 0000000..2e3441a --- /dev/null +++ b/SOURCES/0033-Simplify-KRA-transport-cert-cache.patch @@ -0,0 +1,195 @@ +From 1190a1b41d436de4dab7a622d78217baba44a9ef Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Fri, 17 Mar 2017 10:44:38 +0100 +Subject: [PATCH] Simplify KRA transport cert cache + +In-memory cache causes problem in forking servers. A file based cache is +good enough. It's easier to understand and avoids performance regression +and synchronization issues when cert becomes out-of-date. + +https://pagure.io/freeipa/issue/6787 +Signed-off-by: Christian Heimes +Reviewed-By: Jan Cholasta +--- + ipaclient/plugins/vault.py | 103 ++++++++++++++++++++++++--------------------- + 1 file changed, 55 insertions(+), 48 deletions(-) + +diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py +index d677ec0287d6b37cfd63820a919c0726d3a4ae9f..3fb4900d9cf90e6902c40e1c3d8cfdafec2e28b8 100644 +--- a/ipaclient/plugins/vault.py ++++ b/ipaclient/plugins/vault.py +@@ -20,7 +20,6 @@ + from __future__ import print_function + + import base64 +-import collections + import errno + import getpass + import io +@@ -558,74 +557,79 @@ class vault_mod(Local): + return response + + +-class _TransportCertCache(collections.MutableMapping): ++class _TransportCertCache(object): + def __init__(self): + self._dirname = os.path.join( +- USER_CACHE_PATH, 'ipa', 'kra-transport-certs') +- self._transport_certs = {} ++ USER_CACHE_PATH, 'ipa', 'kra-transport-certs' ++ ) + + def _get_filename(self, domain): + basename = DNSName(domain).ToASCII() + '.pem' + return os.path.join(self._dirname, basename) + +- def __getitem__(self, domain): +- try: +- transport_cert = self._transport_certs[domain] +- except KeyError: +- transport_cert = None ++ def load_cert(self, domain): ++ """Load cert from cache + +- filename = self._get_filename(domain) ++ :param domain: IPA domain ++ :return: cryptography.x509.Certificate or None ++ """ ++ filename = self._get_filename(domain) ++ try: + try: +- try: +- transport_cert = x509.load_certificate_from_file(filename) +- except EnvironmentError as e: +- if e.errno != errno.ENOENT: +- raise +- except Exception: +- logger.warning("Failed to load %s: %s", filename, +- exc_info=True) +- +- if transport_cert is None: +- raise KeyError(domain) +- +- self._transport_certs[domain] = transport_cert ++ return x509.load_certificate_from_file(filename) ++ except EnvironmentError as e: ++ if e.errno != errno.ENOENT: ++ raise ++ except Exception: ++ logger.warning("Failed to load %s", filename, exc_info=True) + +- return transport_cert ++ def store_cert(self, domain, transport_cert): ++ """Store a new cert or override existing cert + +- def __setitem__(self, domain, transport_cert): ++ :param domain: IPA domain ++ :param transport_cert: cryptography.x509.Certificate ++ :return: True if cert was stored successfully ++ """ + filename = self._get_filename(domain) +- transport_cert_der = ( +- transport_cert.public_bytes(serialization.Encoding.DER)) ++ pem = transport_cert.public_bytes(serialization.Encoding.PEM) + try: + try: + os.makedirs(self._dirname) + except EnvironmentError as e: + if e.errno != errno.EEXIST: + raise +- fd, tmpfilename = tempfile.mkstemp(dir=self._dirname) +- os.close(fd) +- x509.write_certificate(transport_cert_der, tmpfilename) +- os.rename(tmpfilename, filename) ++ with tempfile.NamedTemporaryFile(dir=self._dirname, delete=False, ++ mode='wb') as f: ++ try: ++ f.write(pem) ++ f.flush() ++ os.fdatasync(f.fileno()) ++ f.close() ++ os.rename(f.name, filename) ++ except Exception: ++ os.unlink(f.name) ++ raise + except Exception: + logger.warning("Failed to save %s", filename, exc_info=True) ++ return False ++ else: ++ return True + +- self._transport_certs[domain] = transport_cert ++ def remove_cert(self, domain): ++ """Remove a cert from cache, ignores errors + +- def __delitem__(self, domain): ++ :param domain: IPA domain ++ :return: True if cert was found and removed ++ """ + filename = self._get_filename(domain) + try: + os.unlink(filename) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + logger.warning("Failed to remove %s", filename, exc_info=True) +- +- del self._transport_certs[domain] +- +- def __len__(self): +- return len(self._transport_certs) +- +- def __iter__(self): +- return iter(self._transport_certs) ++ return False ++ else: ++ return True + + + _transport_cert_cache = _TransportCertCache() +@@ -646,7 +650,10 @@ class vaultconfig_show(MethodOverride): + # cache transport certificate + transport_cert = x509.load_certificate( + response['result']['transport_cert'], x509.DER) +- _transport_cert_cache[self.api.env.domain] = transport_cert ++ ++ _transport_cert_cache.store_cert( ++ self.api.env.domain, transport_cert ++ ) + + if file: + with open(file, 'w') as f: +@@ -680,7 +687,7 @@ class ModVaultData(Local): + except (errors.InternalError, + errors.ExecutionError, + errors.GenericError): +- _transport_cert_cache.pop(self.api.env.domain, None) ++ _transport_cert_cache.remove_cert(self.api.env.domain) + if raise_unexpected: + raise + +@@ -691,17 +698,17 @@ class ModVaultData(Local): + domain = self.api.env.domain + + # try call with cached transport certificate +- transport_cert = _transport_cert_cache.get(domain) ++ transport_cert = _transport_cert_cache.load_cert(domain) + if transport_cert is not None: + result = self._do_internal(algo, transport_cert, False, + *args, **options) + if result is not None: + return result + +- # retrieve and cache transport certificate +- self.api.Command.vaultconfig_show() +- transport_cert = _transport_cert_cache[domain] +- ++ # retrieve transport certificate (cached by vaultconfig_show) ++ response = self.api.Command.vaultconfig_show() ++ transport_cert = x509.load_certificate( ++ response['result']['transport_cert'], x509.DER) + # call with the retrieved transport certificate + return self._do_internal(algo, transport_cert, True, + *args, **options) +-- +2.12.1 + diff --git a/SOURCES/0033-harden-the-check-for-trust-namespace-overlap-in-new-.patch b/SOURCES/0033-harden-the-check-for-trust-namespace-overlap-in-new-.patch deleted file mode 100644 index 8bf5ee6..0000000 --- a/SOURCES/0033-harden-the-check-for-trust-namespace-overlap-in-new-.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 843d21620c118f283f53db77b1114d15d26dc176 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Wed, 20 Jul 2016 15:46:22 +0200 -Subject: [PATCH] harden the check for trust namespace overlap in new - principals - -This check must handle the possibility of optional attributes -(ipantadditionalsuffixes and ipantflatname) missing in the trusted domain -entry. - -https://fedorahosted.org/freeipa/ticket/6099 - -Reviewed-By: David Kupka ---- - ipalib/util.py | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/ipalib/util.py b/ipalib/util.py -index d101514cad4f35fd9a09d84b549ffa86de432f70..e0fc178c4af2056d04ad88a3923daa7d127fe307 100644 ---- a/ipalib/util.py -+++ b/ipalib/util.py -@@ -968,11 +968,15 @@ def check_principal_realm_in_trust_namespace(api_instance, *keys): - trust_suffix_namespace = set() - - for obj in trust_objects: -- trust_suffix_namespace.update( -- set(upn.lower() for upn in obj['ipantadditionalsuffixes'])) -+ nt_suffixes = obj.get('ipantadditionalsuffixes', []) - - trust_suffix_namespace.update( -- set((obj['cn'][0].lower(), obj['ipantflatname'][0].lower()))) -+ set(upn.lower() for upn in nt_suffixes)) -+ -+ if 'ipantflatname' in obj: -+ trust_suffix_namespace.add(obj['ipantflatname'][0].lower()) -+ -+ trust_suffix_namespace.add(obj['cn'][0].lower()) - - for principal in keys[-1]: - realm = principal.realm --- -2.7.4 - diff --git a/SOURCES/0034-Revert-Enable-vault-commands-on-client.patch b/SOURCES/0034-Revert-Enable-vault-commands-on-client.patch deleted file mode 100644 index 9b74d02..0000000 --- a/SOURCES/0034-Revert-Enable-vault-commands-on-client.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 872e67c0121250dd41e2d6953810582f1e5dda27 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 25 Jul 2016 14:00:08 +0200 -Subject: [PATCH] Revert "Enable vault-* commands on client" - -This reverts commit 9feeaca9fb552229638ce98086aa75905a45b48d. - -https://fedorahosted.org/freeipa/ticket/6089 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaclient/plugins/vault.py | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index a3ce6fecbfd38b342f826d8d27940d991d821e90..b7e0cfffb2fff62fdbbf438964d124fc2dd8ac36 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -202,6 +202,10 @@ class vault_add(Local): - ), - ) - -+ @property -+ def NO_CLI(self): -+ return self.api.Command.vault_add_internal.NO_CLI -+ - def get_args(self): - for arg in self.api.Command.vault_add_internal.args(): - yield arg -@@ -395,6 +399,10 @@ class vault_mod(Local): - ), - ) - -+ @property -+ def NO_CLI(self): -+ return self.api.Command.vault_mod_internal.NO_CLI -+ - def get_args(self): - for arg in self.api.Command.vault_mod_internal.args(): - yield arg -@@ -569,6 +577,10 @@ class vault_archive(Local): - ), - ) - -+ @property -+ def NO_CLI(self): -+ return self.api.Command.vault_archive_internal.NO_CLI -+ - def get_args(self): - for arg in self.api.Command.vault_archive_internal.args(): - yield arg -@@ -813,6 +825,10 @@ class vault_retrieve(Local): - ), - ) - -+ @property -+ def NO_CLI(self): -+ return self.api.Command.vault_retrieve_internal.NO_CLI -+ - def get_args(self): - for arg in self.api.Command.vault_retrieve_internal.args(): - yield arg --- -2.7.4 - diff --git a/SOURCES/0034-rpcserver.login_x509-Actually-return-reply-from-__ca.patch b/SOURCES/0034-rpcserver.login_x509-Actually-return-reply-from-__ca.patch new file mode 100644 index 0000000..7a5c3b4 --- /dev/null +++ b/SOURCES/0034-rpcserver.login_x509-Actually-return-reply-from-__ca.patch @@ -0,0 +1,33 @@ +From c9eefa180576e7218d6aef063ea52915c0ce18a6 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Mon, 27 Mar 2017 16:09:09 +0200 +Subject: [PATCH] rpcserver.login_x509: Actually return reply from __call__ + method + +__call__ didn't return causing internal error in wsgi application. Previously +this bug was hidden by some other error and the code worked even though it +shouldn't. + +https://pagure.io/freeipa/issue/6819 + +Reviewed-By: Pavel Vomacka +--- + ipaserver/rpcserver.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index be4e3916b6011dd2b6c90a0267990bf1e370dfb9..77ed7e124c2ca3dcb49d3a68269d6fa9875d4da0 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -842,7 +842,7 @@ class login_x509(KerberosLogin): + environ, start_response, 'KRB5CCNAME not set', + 'Authentication failed') + +- super(login_x509, self).__call__(environ, start_response) ++ return super(login_x509, self).__call__(environ, start_response) + + + class login_password(Backend, KerberosSession): +-- +2.12.1 + diff --git a/SOURCES/0035-Backup-CA-cert-from-kerberos-folder.patch b/SOURCES/0035-Backup-CA-cert-from-kerberos-folder.patch new file mode 100644 index 0000000..1aebce7 --- /dev/null +++ b/SOURCES/0035-Backup-CA-cert-from-kerberos-folder.patch @@ -0,0 +1,27 @@ +From 32b4dac59052bb48ba4862573d617c35e137e4b7 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Mon, 27 Mar 2017 10:44:56 +0200 +Subject: [PATCH] Backup CA cert from kerberos folder + +https://pagure.io/freeipa/issue/6748 + +Reviewed-By: Martin Basti +--- + ipaserver/install/ipa_backup.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 56583c01b1677a48c103d79123e3fbe106222f38..f71a40bb06545c8d89d1e3fdbc37d5e6e1fe8d58 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -165,6 +165,7 @@ class Backup(admintool.AdminTool): + paths.KRB5KDC_KDC_CONF, + paths.KDC_CERT, + paths.KDC_KEY, ++ paths.CACERT_PEM, + paths.SYSTEMD_IPA_SERVICE, + paths.SYSTEMD_SYSTEM_HTTPD_IPA_CONF, + paths.SYSTEMD_SSSD_SERVICE, +-- +2.12.1 + diff --git a/SOURCES/0035-client-fix-hiding-of-commands-which-lack-server-supp.patch b/SOURCES/0035-client-fix-hiding-of-commands-which-lack-server-supp.patch deleted file mode 100644 index 6b2b1cd..0000000 --- a/SOURCES/0035-client-fix-hiding-of-commands-which-lack-server-supp.patch +++ /dev/null @@ -1,93 +0,0 @@ -From a23b8fd488ca33f3e6ffa42530debd6d5d3430ac Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 18 Jul 2016 09:37:24 +0200 -Subject: [PATCH] client: fix hiding of commands which lack server support - -Rather than checking the server counterpart's NO_CLI, which may be False -even for commands supported on the server, check wheter the server -counterpart is a command defined on the server or a local placeholder. - -https://fedorahosted.org/freeipa/ticket/6089 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaclient/plugins/automount.py | 3 ++- - ipaclient/plugins/otptoken_yubikey.py | 3 ++- - ipaclient/plugins/vault.py | 12 ++++++++---- - 3 files changed, 12 insertions(+), 6 deletions(-) - -diff --git a/ipaclient/plugins/automount.py b/ipaclient/plugins/automount.py -index 8405f9f4fe283d9c068d51e10717fb1396fa44bf..c6537bc6c24b905a8e1f7fb6a7e2c931b95374c7 100644 ---- a/ipaclient/plugins/automount.py -+++ b/ipaclient/plugins/automount.py -@@ -54,7 +54,8 @@ class _fake_automountlocation_show(Method): - class automountlocation_tofiles(MethodOverride): - @property - def NO_CLI(self): -- return self.api.Command.automountlocation_show.NO_CLI -+ return isinstance(self.api.Command.automountlocation_show, -+ _fake_automountlocation_show) - - def output_for_cli(self, textui, result, *keys, **options): - maps = result['result']['maps'] -diff --git a/ipaclient/plugins/otptoken_yubikey.py b/ipaclient/plugins/otptoken_yubikey.py -index 5e0d994628ab997853a80d1f1118ba8ada9993d9..423b670de15dd7f803db1dcbb759bd0254827072 100644 ---- a/ipaclient/plugins/otptoken_yubikey.py -+++ b/ipaclient/plugins/otptoken_yubikey.py -@@ -76,7 +76,8 @@ class otptoken_add_yubikey(Command): - - @property - def NO_CLI(self): -- return self.api.Command.otptoken_add.NO_CLI -+ return isinstance(self.api.Command.otptoken_add, -+ _fake_otptoken_add) - - def get_args(self): - for arg in self.api.Command.otptoken_add.args(): -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index b7e0cfffb2fff62fdbbf438964d124fc2dd8ac36..e3a1ae3a0ad767bcee843b7fa3743a934e02d18b 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -204,7 +204,8 @@ class vault_add(Local): - - @property - def NO_CLI(self): -- return self.api.Command.vault_add_internal.NO_CLI -+ return isinstance(self.api.Command.vault_add_internal, -+ _fake_vault_add_internal) - - def get_args(self): - for arg in self.api.Command.vault_add_internal.args(): -@@ -401,7 +402,8 @@ class vault_mod(Local): - - @property - def NO_CLI(self): -- return self.api.Command.vault_mod_internal.NO_CLI -+ return isinstance(self.api.Command.vault_mod_internal, -+ _fake_vault_mod_internal) - - def get_args(self): - for arg in self.api.Command.vault_mod_internal.args(): -@@ -579,7 +581,8 @@ class vault_archive(Local): - - @property - def NO_CLI(self): -- return self.api.Command.vault_archive_internal.NO_CLI -+ return isinstance(self.api.Command.vault_archive_internal, -+ _fake_vault_archive_internal) - - def get_args(self): - for arg in self.api.Command.vault_archive_internal.args(): -@@ -827,7 +830,8 @@ class vault_retrieve(Local): - - @property - def NO_CLI(self): -- return self.api.Command.vault_retrieve_internal.NO_CLI -+ return isinstance(self.api.Command.vault_retrieve_internal, -+ _fake_vault_retrieve_internal) - - def get_args(self): - for arg in self.api.Command.vault_retrieve_internal.args(): --- -2.7.4 - diff --git a/SOURCES/0036-Minor-fix-in-ipa-replica-manage-MAN-page.patch b/SOURCES/0036-Minor-fix-in-ipa-replica-manage-MAN-page.patch deleted file mode 100644 index 76b1fca..0000000 --- a/SOURCES/0036-Minor-fix-in-ipa-replica-manage-MAN-page.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 1087492c74ed4f823c49314454b9db8bddf29ed2 Mon Sep 17 00:00:00 2001 -From: Abhijeet Kasurde -Date: Tue, 12 Jul 2016 17:08:06 +0530 -Subject: [PATCH] Minor fix in ipa-replica-manage MAN page - -Fixes: https://fedorahosted.org/freeipa/ticket/6058 - -Signed-off-by: Abhijeet Kasurde -Reviewed-By: Florence Blanc-Renaud ---- - install/tools/man/ipa-replica-manage.1 | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - -diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1 -index 68be0232fae9309b108e69f9144501be3277f503..34cd314a517ae2f74da7bc87d6336e62d7b57118 100644 ---- a/install/tools/man/ipa-replica-manage.1 -+++ b/install/tools/man/ipa-replica-manage.1 -@@ -16,7 +16,7 @@ - .\" - .\" Author: Rob Crittenden - .\" --.TH "ipa-replica-manage" "1" "Mar 1 2013" "FreeIPA" "FreeIPA Manual Pages" -+.TH "ipa-replica-manage" "1" "Jul 12 2016" "FreeIPA" "FreeIPA Manual Pages" - .SH "NAME" - ipa\-replica\-manage \- Manage an IPA replica - .SH "SYNOPSIS" -@@ -163,15 +163,15 @@ Performing range changes as a delegated administrator (e.g. not using the Direct - .TP - List all masters: - # ipa\-replica\-manage list -- srv1.example.com -- srv2.example.com -- srv3.example.com -- srv4.example.com -+ srv1.example.com: master -+ srv2.example.com: master -+ srv3.example.com: master -+ srv4.example.com: master - .TP - List a server's replication agreements. - # ipa\-replica\-manage list srv1.example.com -- srv2.example.com -- srv3.example.com -+ srv2.example.com: replica -+ srv3.example.com: replica - .TP - Re\-initialize a replica: - # ipa\-replica\-manage re\-initialize \-\-from srv2.example.com --- -2.7.4 - diff --git a/SOURCES/0036-spec-file-Bump-requires-to-make-Certificate-Login-in.patch b/SOURCES/0036-spec-file-Bump-requires-to-make-Certificate-Login-in.patch new file mode 100644 index 0000000..1869391 --- /dev/null +++ b/SOURCES/0036-spec-file-Bump-requires-to-make-Certificate-Login-in.patch @@ -0,0 +1,54 @@ +From 03d0b25c585e9202ff0fa7fba96df5c9f0a1a337 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Thu, 23 Mar 2017 08:43:51 +0100 +Subject: [PATCH] spec file: Bump requires to make Certificate Login in WebUI + work + +gssproxy >= 0.7.0-2 - fixes impersonator checking +mod_lookup_identity >= 0.9.9 - adds support for single certificate assigned to multiple users +mod_nss >= 1.0.14-3 - no longer sets remote user in fixup hook +sssd-dbus >= 1.15.2 - adds FindByNameAndCertificate DBus method + +https://pagure.io/freeipa/issue/6823 + +Reviewed-By: Pavel Vomacka +Reviewed-By: Jan Cholasta +--- + freeipa.spec.in | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 5419ed10723fc7aa3ecc1b3f66b3ef1c8b38b12f..9c8a14a580ad80ed10e797bef9661e7b1feb81b3 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -270,9 +270,11 @@ Requires: ntp + Requires: httpd >= 2.4.6-31 + Requires: mod_wsgi + Requires: mod_auth_gssapi >= 1.5.0 +-Requires: mod_nss >= 1.0.8-26 ++# 1.0.14-3: https://bugzilla.redhat.com/show_bug.cgi?id=1431206 ++Requires: mod_nss >= 1.0.14-3 + Requires: mod_session +-Requires: mod_lookup_identity ++# 0.9.9: https://github.com/adelton/mod_lookup_identity/pull/3 ++Requires: mod_lookup_identity >= 0.9.9 + Requires: python-ldap >= 2.4.15 + Requires: python-gssapi >= 1.2.0 + Requires: acl +@@ -300,9 +302,10 @@ Requires: systemd-python + Requires: %{etc_systemd_dir} + Requires: gzip + Requires: oddjob +-Requires: gssproxy >= 0.7.0 +-# Require 1.15.1 for the certificate identity mapping feature +-Requires: sssd-dbus >= 1.15.1 ++# 0.7.0-2: https://pagure.io/gssproxy/pull-request/172 ++Requires: gssproxy >= 0.7.0-2 ++# 1.15.2: FindByNameAndCertificate (https://pagure.io/SSSD/sssd/issue/3050) ++Requires: sssd-dbus >= 1.15.2 + + Provides: %{alt_name}-server = %{version} + Conflicts: %{alt_name}-server +-- +2.12.1 + diff --git a/SOURCES/0037-Use-Custodia-0.3.1-features.patch b/SOURCES/0037-Use-Custodia-0.3.1-features.patch new file mode 100644 index 0000000..44b805d --- /dev/null +++ b/SOURCES/0037-Use-Custodia-0.3.1-features.patch @@ -0,0 +1,236 @@ +From a93e6040fdadd41dc7d1c46c09110b7321ed333c Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Tue, 28 Feb 2017 12:07:19 +0100 +Subject: [PATCH] Use Custodia 0.3.1 features + +* Use sd-notify in ipa-custodia.service +* Introduce libexec/ipa/ipa-custodia script. It comes with correct + default setting for IPA's config file. The new file also makes it + simpler to run IPA's custodia instance with its own SELinux context. +* ipapython no longer depends on custodia + +The patch addresses three issues: + +* https://bugzilla.redhat.com/show_bug.cgi?id=1430247 + Forward compatibility with Custodia 0.3 in Fedora rawhide +* https://pagure.io/freeipa/issue/5825 + Use sd-notify +* https://pagure.io/freeipa/issue/6788 + Prepare for separate SELinux context + +Signed-off-by: Christian Heimes +Reviewed-By: Martin Basti +Reviewed-By: Jan Cholasta +--- + freeipa.spec.in | 13 ++++++++----- + init/systemd/Makefile.am | 1 + + init/systemd/ipa-custodia.service.in | 5 ++--- + install/tools/Makefile.am | 1 + + install/tools/ipa-custodia | 6 ++++++ + ipapython/setup.py | 1 - + ipaserver/secrets/service.py | 30 ++++++++++++++++++++++++++++++ + ipaserver/setup.py | 1 + + ipasetup.py.in | 1 + + 9 files changed, 50 insertions(+), 9 deletions(-) + create mode 100755 install/tools/ipa-custodia + create mode 100644 ipaserver/secrets/service.py + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 9c8a14a580ad80ed10e797bef9661e7b1feb81b3..91fca6ea974bd70847feb1e3b6db8ae3cbda061c 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -181,7 +181,8 @@ BuildRequires: pki-base-python2 + BuildRequires: python-pytest-multihost + BuildRequires: python-pytest-sourceorder + BuildRequires: python-jwcrypto +-BuildRequires: python-custodia ++# 0.3: sd_notify (https://pagure.io/freeipa/issue/5825) ++BuildRequires: python-custodia >= 0.3.1 + BuildRequires: dbus-python + BuildRequires: python-dateutil + BuildRequires: python-enum34 +@@ -216,7 +217,8 @@ BuildRequires: pki-base-python3 + BuildRequires: python3-pytest-multihost + BuildRequires: python3-pytest-sourceorder + BuildRequires: python3-jwcrypto +-BuildRequires: python3-custodia ++# 0.3: sd_notify (https://pagure.io/freeipa/issue/5825) ++BuildRequires: python3-custodia >= 0.3.1 + BuildRequires: python3-dbus + BuildRequires: python3-dateutil + BuildRequires: python3-enum34 +@@ -340,6 +342,7 @@ BuildArch: noarch + Requires: %{name}-server-common = %{version}-%{release} + Requires: %{name}-common = %{version}-%{release} + Requires: python2-ipaclient = %{version}-%{release} ++Requires: python-custodia >= 0.3.1 + Requires: python-ldap >= 2.4.15 + Requires: python-lxml + Requires: python-gssapi >= 1.2.0 +@@ -370,6 +373,7 @@ BuildArch: noarch + Requires: %{name}-server-common = %{version}-%{release} + Requires: %{name}-common = %{version}-%{release} + Requires: python3-ipaclient = %{version}-%{release} ++Requires: python3-custodia >= 0.3.1 + Requires: python3-pyldap >= 2.4.15 + Requires: python3-lxml + Requires: python3-gssapi >= 1.2.0 +@@ -399,7 +403,7 @@ BuildArch: noarch + Requires: %{name}-client-common = %{version}-%{release} + Requires: httpd >= 2.4.6-31 + Requires: systemd-units >= 38 +-Requires: custodia ++Requires: custodia >= 0.3.1 + + Provides: %{alt_name}-server-common = %{version} + Conflicts: %{alt_name}-server-common +@@ -650,7 +654,6 @@ Requires: python-jwcrypto + Requires: python-cffi + Requires: python-ldap >= 2.4.15 + Requires: python-requests +-Requires: python-custodia + Requires: python-dns >= 1.15 + Requires: python-enum34 + Requires: python-netifaces >= 0.10.4 +@@ -699,7 +702,6 @@ Requires: python3-six + Requires: python3-jwcrypto + Requires: python3-cffi + Requires: python3-pyldap >= 2.4.15 +-Requires: python3-custodia + Requires: python3-requests + Requires: python3-dns >= 1.15 + Requires: python3-netifaces >= 0.10.4 +@@ -1160,6 +1162,7 @@ fi + %{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit + %{_libexecdir}/certmonger/ipa-server-guard + %dir %{_libexecdir}/ipa ++%{_libexecdir}/ipa/ipa-custodia + %{_libexecdir}/ipa/ipa-dnskeysyncd + %{_libexecdir}/ipa/ipa-dnskeysync-replica + %{_libexecdir}/ipa/ipa-ods-exporter +diff --git a/init/systemd/Makefile.am b/init/systemd/Makefile.am +index 325e8574812a2ec507911128dbac0315070d2897..945f6ac22a050f393990cad27156e092ce4f7a29 100644 +--- a/init/systemd/Makefile.am ++++ b/init/systemd/Makefile.am +@@ -18,5 +18,6 @@ CLEANFILES = $(systemdsystemunit_DATA) + -e 's|@IPA_SYSCONF_DIR[@]|$(IPA_SYSCONF_DIR)|g' \ + -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@sbindir[@]|$(sbindir)|g' \ ++ -e 's|@libexecdir[@]|$(libexecdir)|g' \ + -e 's|@sysconfenvdir[@]|$(sysconfenvdir)|g' \ + '$(srcdir)/$@.in' >$@ +diff --git a/init/systemd/ipa-custodia.service.in b/init/systemd/ipa-custodia.service.in +index 3f9b128aa1b7ee373c52e1e3566048ec6028c826..0247bd8826529d638c692d827ae31393db292b4a 100644 +--- a/init/systemd/ipa-custodia.service.in ++++ b/init/systemd/ipa-custodia.service.in +@@ -2,9 +2,8 @@ + Description=IPA Custodia Service + + [Service] +-Type=simple +- +-ExecStart=@sbindir@/custodia @IPA_SYSCONF_DIR@/custodia/custodia.conf ++Type=notify ++ExecStart=@libexecdir@/ipa/ipa-custodia @IPA_SYSCONF_DIR@/custodia/custodia.conf + PrivateTmp=yes + Restart=on-failure + RestartSec=60s +diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am +index f2c2ce2953c3ac146a80f7e4515769683a01f843..493e5ff4a8290be8ef076135104a85f8315b7842 100644 +--- a/install/tools/Makefile.am ++++ b/install/tools/Makefile.am +@@ -32,6 +32,7 @@ dist_sbin_SCRIPTS = \ + + appdir = $(libexecdir)/ipa/ + dist_app_SCRIPTS = \ ++ ipa-custodia \ + ipa-httpd-kdcproxy \ + ipa-pki-retrieve-key \ + $(NULL) +diff --git a/install/tools/ipa-custodia b/install/tools/ipa-custodia +new file mode 100755 +index 0000000000000000000000000000000000000000..5deeeffdd78db323b6534934065772bb0ae67438 +--- /dev/null ++++ b/install/tools/ipa-custodia +@@ -0,0 +1,6 @@ ++#!/usr/bin/python2 ++# Copyright (C) 2017 IPA Project Contributors, see COPYING for license ++from ipaserver.secrets.service import main ++ ++if __name__ == '__main__': ++ main() +diff --git a/ipapython/setup.py b/ipapython/setup.py +index 86e4131e5f9cfc106393875018d6ac2645a38be1..2fc039fe7bb673add17404d13bf477c5b8bb0606 100755 +--- a/ipapython/setup.py ++++ b/ipapython/setup.py +@@ -38,7 +38,6 @@ if __name__ == '__main__': + ], + install_requires=[ + "cffi", +- "custodia", + "cryptography", + "dnspython", + "gssapi", +diff --git a/ipaserver/secrets/service.py b/ipaserver/secrets/service.py +new file mode 100644 +index 0000000000000000000000000000000000000000..f51c46a30e4caf76e38659c2f0a6a2c645376978 +--- /dev/null ++++ b/ipaserver/secrets/service.py +@@ -0,0 +1,30 @@ ++# Copyright (C) 2017 IPA Project Contributors, see COPYING for license ++import argparse ++ ++import custodia.server ++ ++ ++argparser = argparse.ArgumentParser( ++ prog='ipa-custodia', ++ description='IPA Custodia service' ++) ++argparser.add_argument( ++ '--debug', ++ action='store_true', ++ help='Debug mode' ++) ++argparser.add_argument( ++ 'configfile', ++ nargs='?', ++ type=argparse.FileType('r'), ++ help="Path to IPA's custodia server config", ++ default='/etc/ipa/custodia/custodia.conf' ++) ++ ++ ++def main(): ++ return custodia.server.main(argparser) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/ipaserver/setup.py b/ipaserver/setup.py +index d3c735c0f9e604512d6ccd14dcd16a186c6ecad4..42b0c1b0618ef9867acb1fe2add5702a756cf2d2 100755 +--- a/ipaserver/setup.py ++++ b/ipaserver/setup.py +@@ -47,6 +47,7 @@ if __name__ == '__main__': + ], + install_requires=[ + "cryptography", ++ "custodia", + "dbus-python", + "dnspython", + "dogtag-pki", +diff --git a/ipasetup.py.in b/ipasetup.py.in +index 915f0edee7ca291cc4921f6b8e4d38498253b372..7f9b2c918c0cd582706edee087ed5944451aaf2e 100644 +--- a/ipasetup.py.in ++++ b/ipasetup.py.in +@@ -64,6 +64,7 @@ if SETUPTOOLS_VERSION < (8, 0, 0): + + PACKAGE_VERSION = { + 'cryptography': 'cryptography >= 1.4', ++ 'custodia': 'custodia >= 0.3.1', + 'dnspython': 'dnspython >= 1.15', + 'gssapi': 'gssapi >= 1.2.0', + 'ipaclient': 'ipaclient == {}'.format(VERSION), +-- +2.12.1 + diff --git a/SOURCES/0037-compat-fix-ping-call.patch b/SOURCES/0037-compat-fix-ping-call.patch deleted file mode 100644 index ce000c1..0000000 --- a/SOURCES/0037-compat-fix-ping-call.patch +++ /dev/null @@ -1,31 +0,0 @@ -From f557f7487d9aae0c901a740b9a446568677b8bb3 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 25 Jul 2016 15:58:20 +0200 -Subject: [PATCH] compat: fix ping call - -Copy & paste accident caused the ping command to be called with an unwanted -argument, which results in an exception. - -Remove the argument to fix it. - -https://fedorahosted.org/freeipa/ticket/6129 ---- - ipaclient/remote_plugins/compat.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaclient/remote_plugins/compat.py b/ipaclient/remote_plugins/compat.py -index 40521af450aafca83f33d1723b4fd9e27ef8d96f..aef5718fcaade157487c0e65562c3bc8a11ad7de 100644 ---- a/ipaclient/remote_plugins/compat.py -+++ b/ipaclient/remote_plugins/compat.py -@@ -39,7 +39,7 @@ def get_package(api, client): - try: - server_version = env['result']['api_version'] - except KeyError: -- ping = client.forward(u'ping', u'api_version', version=u'2.0') -+ ping = client.forward(u'ping', version=u'2.0') - try: - match = re.search(u'API version (2\.[0-9]+)', ping['summary']) - except KeyError: --- -2.7.4 - diff --git a/SOURCES/0038-replica-install-Fix-domain.patch b/SOURCES/0038-replica-install-Fix-domain.patch deleted file mode 100644 index 20d2325..0000000 --- a/SOURCES/0038-replica-install-Fix-domain.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 42c09751aedf6289f983d4238ae1ff3b44b5f572 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 25 Jul 2016 15:54:43 +0200 -Subject: [PATCH] replica-install: Fix --domain - -Replica installation must not check existence of --domain - the domain -must (logically) exist. - -https://fedorahosted.org/freeipa/ticket/6130 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/server/common.py | 5 ----- - ipaserver/install/server/install.py | 14 +++++++++++--- - 2 files changed, 11 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/install/server/common.py b/ipaserver/install/server/common.py -index 45fb2dc17976a08acab16783584524721411fb4e..e6093d15cd1067a83ed89945c4a9c983c66ec06f 100644 ---- a/ipaserver/install/server/common.py -+++ b/ipaserver/install/server/common.py -@@ -284,11 +284,6 @@ class BaseServer(common.Installable, common.Interactive, core.Composite): - @domain_name.validator - def domain_name(self, value): - validate_domain_name(value) -- if (self.setup_dns and -- not self.dns.allow_zone_overlap): # pylint: disable=no-member -- print("Checking DNS domain %s, please wait ..." % value) -- check_zone_overlap(value, False) -- - - dm_password = Knob( - str, None, -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index c0c676b870b481696ae75742c7bf88074b0ecf9c..65f9318201e648b30a3c13626e807ac6f3a9416d 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -17,6 +17,7 @@ import six - - from ipapython import certmonger, ipaldap, ipautil, sysrestore - from ipapython.dn import DN -+from ipapython.dnsutil import check_zone_overlap - from ipapython.install import core - from ipapython.install.common import step - from ipapython.install.core import Knob -@@ -1199,13 +1200,20 @@ class ServerCA(BaseServerCA): - - - class Server(BaseServer): -- realm_name = Knob(BaseServer.realm_name) -- domain_name = Knob(BaseServer.domain_name) -- - setup_ca = None - setup_kra = None - setup_dns = Knob(BaseServer.setup_dns) - -+ realm_name = Knob(BaseServer.realm_name) -+ domain_name = Knob(BaseServer.domain_name) -+ -+ @domain_name.validator -+ def domain_name(self, value): -+ if (self.setup_dns and -+ not self.dns.allow_zone_overlap): # pylint: disable=no-member -+ print("Checking DNS domain %s, please wait ..." % value) -+ check_zone_overlap(value, False) -+ - dm_password = Knob( - BaseServer.dm_password, - description="Directory Manager password", --- -2.7.4 - diff --git a/SOURCES/0038-spec-file-bump-krb5-devel-BuildRequires-for-certauth.patch b/SOURCES/0038-spec-file-bump-krb5-devel-BuildRequires-for-certauth.patch new file mode 100644 index 0000000..06d302d --- /dev/null +++ b/SOURCES/0038-spec-file-bump-krb5-devel-BuildRequires-for-certauth.patch @@ -0,0 +1,40 @@ +From 93e0cc4aaf84e7a988a11d13674c294294b8498a Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 28 Mar 2017 10:43:31 +0000 +Subject: [PATCH] spec file: bump krb5-devel BuildRequires for certauth + +Bump BuildRequires on krb5-devel to the version which introduces the +certauth pluggable interface. + +This fixes RPM build failure when an older version of krb5-devel was +installed. + +https://pagure.io/freeipa/issue/4905 + +Reviewed-By: David Kupka +--- + freeipa.spec.in | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 91fca6ea974bd70847feb1e3b6db8ae3cbda061c..e7e39e87bef39653d660a345793750f59c8dd715 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -80,12 +80,10 @@ BuildRequires: openldap-devel + # will cause the build to fail due to unsatisfied dependencies. + # DAL version change may cause code crash or memory leaks, it is better to fail early. + %if 0%{?fedora} > 25 +-BuildRequires: krb5-devel >= 1.15-5 + BuildRequires: krb5-kdb-version = 6.1 +-%else +-# 1.12: libkrad (http://krbdev.mit.edu/rt/Ticket/Display.html?id=7678) +-BuildRequires: krb5-devel >= 1.12 + %endif ++# 1.15.1-3: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561) ++BuildRequires: krb5-devel >= 1.15.1-3 + # 1.27.4: xmlrpc_curl_xportparms.gssapi_delegation + BuildRequires: xmlrpc-c-devel >= 1.27.4 + BuildRequires: popt-devel +-- +2.12.1 + diff --git a/SOURCES/0039-Avoid-growing-FILE-ccaches-unnecessarily.patch b/SOURCES/0039-Avoid-growing-FILE-ccaches-unnecessarily.patch new file mode 100644 index 0000000..25803da --- /dev/null +++ b/SOURCES/0039-Avoid-growing-FILE-ccaches-unnecessarily.patch @@ -0,0 +1,34 @@ +From 5c84f945e0fe5e41d706fd7f700392214178b6aa Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Wed, 22 Mar 2017 18:25:38 -0400 +Subject: [PATCH] Avoid growing FILE ccaches unnecessarily + +Related https://pagure.io/freeipa/issue/6775 + +Signed-off-by: Simo Sorce +Reviewed-By: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + ipapython/session_storage.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index 7fe17fb235614e687a88c090336d3c59a7a24aac..a88f9f7a75c73d4dc753183a100350d197d02199 100644 +--- a/ipapython/session_storage.py ++++ b/ipapython/session_storage.py +@@ -104,6 +104,12 @@ def store_data(princ_name, key, value): + """ + Stores the session cookie in a hidden ccache entry. + """ ++ # FILE ccaches grow every time an entry is stored, so we need ++ # to avoid storing the same entry multiple times. ++ oldvalue = get_data(princ_name, key) ++ if oldvalue == value: ++ return ++ + context = krb5_context() + principal = krb5_principal() + ccache = krb5_ccache() +-- +2.12.1 + diff --git a/SOURCES/0039-idrange-fix-unassigned-global-variable.patch b/SOURCES/0039-idrange-fix-unassigned-global-variable.patch deleted file mode 100644 index 731295d..0000000 --- a/SOURCES/0039-idrange-fix-unassigned-global-variable.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 89bfc7c0a4b08c873e5c8b8dfad54cf895b742cd Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 29 Jul 2016 16:46:09 +0200 -Subject: [PATCH] idrange: fix unassigned global variable - -Global variable '_dcerpc_bindings_installed' is in some cases used -before assigment. This patch ensures that _dcerpc_bindings_installed is -always initialized. - -https://fedorahosted.org/freeipa/ticket/6082 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/idrange.py | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py -index ccd67995e5b42634387e1064e7c819b711f3ef99..3e9db0b6b734513547423901a8b3212b3cee9147 100644 ---- a/ipaserver/plugins/idrange.py -+++ b/ipaserver/plugins/idrange.py -@@ -35,6 +35,9 @@ if api.env.in_server and api.env.context in ['lite', 'server']: - _dcerpc_bindings_installed = True - except ImportError: - _dcerpc_bindings_installed = False -+else: -+ _dcerpc_bindings_installed = False -+ - - ID_RANGE_VS_DNA_WARNING = """======= - WARNING: --- -2.7.4 - diff --git a/SOURCES/0040-Handle-failed-authentication-via-cookie.patch b/SOURCES/0040-Handle-failed-authentication-via-cookie.patch new file mode 100644 index 0000000..7d32ccc --- /dev/null +++ b/SOURCES/0040-Handle-failed-authentication-via-cookie.patch @@ -0,0 +1,120 @@ +From d1a482316296d32551470de698a1bdd6a7efed1a Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Wed, 22 Mar 2017 18:38:22 -0400 +Subject: [PATCH] Handle failed authentication via cookie + +If cookie authentication fails and we get back a 401 see if we +tried a SPNEGO auth by checking if we had a GSSAPI context. If not +it means our session cookie was invalid or expired or some other +error happened on the server that requires us to try a full SPNEGO +handshake, so go ahead and try it. + +Fixes https://pagure.io/freeipa/issue/6775 + +Signed-off-by: Simo Sorce +Reviewed-By: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + ipalib/rpc.py | 52 ++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 32 insertions(+), 20 deletions(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index 38321d17cf2c9529738aa45cc44bbd38b08b032b..c1ceeec197c4a9c55f303f0fd431e86adb389598 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -586,22 +586,33 @@ class KerbTransport(SSLTransport): + else: + raise errors.KerberosError(message=unicode(e)) + +- def get_host_info(self, host): ++ def _get_host(self): ++ return self._connection[0] ++ ++ def _remove_extra_header(self, name): ++ for (h, v) in self._extra_headers: ++ if h == name: ++ self._extra_headers.remove((h, v)) ++ break ++ ++ def get_auth_info(self, use_cookie=True): + """ + Two things can happen here. If we have a session we will add + a cookie for that. If not we will set an Authorization header. + """ +- (host, extra_headers, x509) = SSLTransport.get_host_info(self, host) +- +- if not isinstance(extra_headers, list): +- extra_headers = [] ++ if not isinstance(self._extra_headers, list): ++ self._extra_headers = [] + +- session_cookie = getattr(context, 'session_cookie', None) +- if session_cookie: +- extra_headers.append(('Cookie', session_cookie)) +- return (host, extra_headers, x509) ++ # Remove any existing Cookie first ++ self._remove_extra_header('Cookie') ++ if use_cookie: ++ session_cookie = getattr(context, 'session_cookie', None) ++ if session_cookie: ++ self._extra_headers.append(('Cookie', session_cookie)) ++ return + + # Set the remote host principal ++ host = self._get_host() + service = self.service + "@" + host.split(':')[0] + + try: +@@ -616,18 +627,14 @@ class KerbTransport(SSLTransport): + except gssapi.exceptions.GSSError as e: + self._handle_exception(e, service=service) + +- self._set_auth_header(extra_headers, response) +- +- return (host, extra_headers, x509) ++ self._set_auth_header(response) + +- def _set_auth_header(self, extra_headers, token): +- for (h, v) in extra_headers: +- if h == 'Authorization': +- extra_headers.remove((h, v)) +- break ++ def _set_auth_header(self, token): ++ # Remove any existing authorization header first ++ self._remove_extra_header('Authorization') + + if token: +- extra_headers.append( ++ self._extra_headers.append( + ('Authorization', 'negotiate %s' % base64.b64encode(token).decode('ascii')) + ) + +@@ -651,18 +658,23 @@ class KerbTransport(SSLTransport): + if self._sec_context.complete: + self._sec_context = None + return True +- self._set_auth_header(self._extra_headers, token) ++ self._set_auth_header(token) ++ return False ++ elif response.status == 401: ++ self.get_auth_info(use_cookie=False) + return False + return True + + def single_request(self, host, handler, request_body, verbose=0): + # Based on Python 2.7's xmllib.Transport.single_request + try: +- h = SSLTransport.make_connection(self, host) ++ h = self.make_connection(host) + + if verbose: + h.set_debuglevel(1) + ++ self.get_auth_info() ++ + while True: + if six.PY2: + # pylint: disable=no-value-for-parameter +-- +2.12.1 + diff --git a/SOURCES/0040-re-set-canonical-principal-name-on-migrated-users.patch b/SOURCES/0040-re-set-canonical-principal-name-on-migrated-users.patch deleted file mode 100644 index bc6f486..0000000 --- a/SOURCES/0040-re-set-canonical-principal-name-on-migrated-users.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 1dfba16f6d46a2811d0230f28abf0ea4621bfde2 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 28 Jul 2016 10:42:58 +0200 -Subject: [PATCH] re-set canonical principal name on migrated users - -The migration procedure has been updated to re-set `krbcanonicalname` -attribute on migrated users as well as `krbprincipalname` so that migration -from FreeIPA versions supporting principal aliases does not break subsequent -authentication of migrated users. - -https://fedorahosted.org/freeipa/ticket/6101 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/plugins/migration.py | 41 ++++++++++++++++++++++++++++------------- - 1 file changed, 28 insertions(+), 13 deletions(-) - -diff --git a/ipaserver/plugins/migration.py b/ipaserver/plugins/migration.py -index 7f634a7ccf8c49a4c8e0cc3fe2b2dce84b5cadff..404c4aeb08ff2ee018799af3a9224bec93c26f82 100644 ---- a/ipaserver/plugins/migration.py -+++ b/ipaserver/plugins/migration.py -@@ -36,6 +36,7 @@ if api.env.in_server and api.env.context in ['lite', 'server']: - from ipalib import _ - from ipapython.dn import DN - from ipapython.ipautil import write_tmp_file -+from ipapython.kerberos import Principal - import datetime - from ipaplatform.paths import paths - -@@ -152,6 +153,32 @@ _supported_scopes = {u'base': SCOPE_BASE, u'onelevel': SCOPE_ONELEVEL, u'subtree - _default_scope = u'onelevel' - - -+def _create_kerberos_principals(ldap, pkey, entry_attrs, failed): -+ """ -+ Create 'krbprincipalname' and 'krbcanonicalname' attributes for incoming -+ user entry or skip it if there already is a user with such principal name. -+ The code does not search for `krbcanonicalname` since we assume that the -+ canonical principal name is always contained among values of -+ `krbprincipalname` attribute.Both `krbprincipalname` and `krbcanonicalname` -+ are set to default value generated from uid and realm. -+ -+ Note: the migration does not currently preserve principal aliases -+ """ -+ principal = Principal((pkey,), realm=api.env.realm) -+ try: -+ ldap.find_entry_by_attr( -+ 'krbprincipalname', principal, 'krbprincipalaux', [''], -+ DN(api.env.container_user, api.env.basedn) -+ ) -+ except errors.NotFound: -+ entry_attrs['krbprincipalname'] = principal -+ entry_attrs['krbcanonicalname'] = principal -+ except errors.LimitsExceeded: -+ failed[pkey] = unicode(_krb_failed_msg % unicode(principal)) -+ else: -+ failed[pkey] = unicode(_krb_err_msg % unicode(principal)) -+ -+ - def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs): - assert isinstance(dn, DN) - attr_blacklist = ['krbprincipalkey','memberofindirect','memberindirect'] -@@ -217,19 +244,7 @@ def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs - except ValueError: # object class not present - pass - -- # generate a principal name and check if it isn't already taken -- principal = u'%s@%s' % (pkey, api.env.realm) -- try: -- ldap.find_entry_by_attr( -- 'krbprincipalname', principal, 'krbprincipalaux', [''], -- DN(api.env.container_user, api.env.basedn) -- ) -- except errors.NotFound: -- entry_attrs['krbprincipalname'] = principal -- except errors.LimitsExceeded: -- failed[pkey] = unicode(_krb_failed_msg % principal) -- else: -- failed[pkey] = unicode(_krb_err_msg % principal) -+ _create_kerberos_principals(ldap, pkey, entry_attrs, failed) - - # Fix any attributes with DN syntax that point to entries in the old - # tree --- -2.7.4 - diff --git a/SOURCES/0041-Do-not-initialize-API-in-ipa-client-automount-uninst.patch b/SOURCES/0041-Do-not-initialize-API-in-ipa-client-automount-uninst.patch deleted file mode 100644 index 8d2cb7f..0000000 --- a/SOURCES/0041-Do-not-initialize-API-in-ipa-client-automount-uninst.patch +++ /dev/null @@ -1,41 +0,0 @@ -From c92d242a215c7fb312aaeb07dd02f5783aec1817 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 28 Jul 2016 09:47:39 +0200 -Subject: [PATCH] Do not initialize API in ipa-client-automount uninstall - -API is not needed in uninstallation, it may only produce errors. - -https://fedorahosted.org/freeipa/ticket/6072 - -Reviewed-By: Florence Blanc-Renaud ---- - client/ipa-client-automount | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/client/ipa-client-automount b/client/ipa-client-automount -index f06aa7f8d53ba2528bc2c023792771d5fd341e7c..08209c849f155a8394acddc6bb961be8fa68073c 100755 ---- a/client/ipa-client-automount -+++ b/client/ipa-client-automount -@@ -378,6 +378,9 @@ def main(): - paths.IPACLIENT_INSTALL_LOG, verbose=False, debug=options.debug, - filemode='a', console_format='%(message)s') - -+ if options.uninstall: -+ return uninstall(fstore, statestore) -+ - cfg = dict( - context='cli_installer', - in_server=False, -@@ -392,9 +395,6 @@ def main(): - if os.path.exists(paths.IPA_CA_CRT): - ca_cert_path = paths.IPA_CA_CRT - -- if options.uninstall: -- return uninstall(fstore, statestore) -- - if statestore.has_state('autofs'): - sys.exit('automount is already configured on this system.\n') - --- -2.7.4 - diff --git a/SOURCES/0041-Work-around-issues-fetching-session-data.patch b/SOURCES/0041-Work-around-issues-fetching-session-data.patch new file mode 100644 index 0000000..5be8812 --- /dev/null +++ b/SOURCES/0041-Work-around-issues-fetching-session-data.patch @@ -0,0 +1,331 @@ +From 2f8033174775f55cb2377baf524fc36914aa38fa Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Thu, 23 Mar 2017 13:02:00 -0400 +Subject: [PATCH] Work around issues fetching session data + +Unfortunately the MIT krb5 library has a severe limitation with FILE +ccaches when retrieving config data. It will always only search until +the first entry is found and return that one. + +For FILE caches MIT krb5 does not support removing old entries when a +new one is stored, and storage happens only in append mode, so the end +result is that even if an update is stored it is never returned with the +standard krb5_cc_get_config() call. + +To work around this issue we simply implement what krb5_cc_get_config() +does under the hood with the difference that we do not stop at the first +match but keep going until all ccache entries have been checked. + +Related https://pagure.io/freeipa/issue/6775 + +Signed-off-by: Simo Sorce +Reviewed-By: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + ipapython/session_storage.py | 213 ++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 190 insertions(+), 23 deletions(-) + +diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py +index a88f9f7a75c73d4dc753183a100350d197d02199..f3094f60000aa6e3f4b27fe91092c4214936f651 100644 +--- a/ipapython/session_storage.py ++++ b/ipapython/session_storage.py +@@ -13,6 +13,12 @@ try: + except OSError as e: # pragma: no cover + raise ImportError(str(e)) + ++krb5_int32 = ctypes.c_int32 ++krb5_error_code = krb5_int32 ++krb5_magic = krb5_error_code ++krb5_enctype = krb5_int32 ++krb5_octet = ctypes.c_uint8 ++krb5_timestamp = krb5_int32 + + class _krb5_context(ctypes.Structure): # noqa + """krb5/krb5.h struct _krb5_context""" +@@ -27,7 +33,7 @@ class _krb5_ccache(ctypes.Structure): # noqa + class _krb5_data(ctypes.Structure): # noqa + """krb5/krb5.h struct _krb5_data""" + _fields_ = [ +- ("magic", ctypes.c_int32), ++ ("magic", krb5_magic), + ("length", ctypes.c_uint), + ("data", ctypes.c_char_p), + ] +@@ -38,6 +44,63 @@ class krb5_principal_data(ctypes.Structure): # noqa + _fields_ = [] + + ++class _krb5_keyblock(ctypes.Structure): # noqa ++ """krb5/krb5.h struct _krb5_keyblock""" ++ _fields_ = [ ++ ("magic", krb5_magic), ++ ("enctype", krb5_enctype), ++ ("length", ctypes.c_uint), ++ ("contents", ctypes.POINTER(krb5_octet)) ++ ] ++ ++ ++class _krb5_ticket_times(ctypes.Structure): # noqa ++ """krb5/krb5.h struct _krb5_ticket_times""" ++ _fields_ = [ ++ ("authtime", krb5_timestamp), ++ ("starttime", krb5_timestamp), ++ ("endtime", krb5_timestamp), ++ ("renew_till", krb5_timestamp), ++ ] ++ ++ ++class _krb5_address(ctypes.Structure): # noqa ++ """krb5/krb5.h struct _krb5_address""" ++ _fields_ = [] ++ ++ ++class _krb5_authdata(ctypes.Structure): # noqa ++ """krb5/krb5.h struct _krb5_authdata""" ++ _fields_ = [] ++ ++ ++krb5_principal = ctypes.POINTER(krb5_principal_data) ++krb5_keyblock = _krb5_keyblock ++krb5_ticket_times = _krb5_ticket_times ++krb5_boolean = ctypes.c_uint ++krb5_flags = krb5_int32 ++krb5_data = _krb5_data ++krb5_address_p = ctypes.POINTER(_krb5_address) ++krb5_authdata_p = ctypes.POINTER(_krb5_authdata) ++ ++ ++class _krb5_creds(ctypes.Structure): # noqa ++ """krb5/krb5.h struct _krb5_creds""" ++ _fields_ = [ ++ ("magic", krb5_magic), ++ ("client", krb5_principal), ++ ("server", krb5_principal), ++ ("keyblock", krb5_keyblock), ++ ("times", krb5_ticket_times), ++ ("is_skey", krb5_boolean), ++ ("ticket_flags", krb5_flags), ++ ("addresses", ctypes.POINTER(krb5_address_p)), ++ ("ticket", krb5_data), ++ ("second_ticket", krb5_data), ++ ("authdata", ctypes.POINTER(krb5_authdata_p)) ++ ] ++ ++ + class KRB5Error(Exception): + pass + +@@ -48,11 +111,13 @@ def krb5_errcheck(result, func, arguments): + raise KRB5Error(result, func.__name__, arguments) + + +-krb5_principal = ctypes.POINTER(krb5_principal_data) + krb5_context = ctypes.POINTER(_krb5_context) + krb5_ccache = ctypes.POINTER(_krb5_ccache) + krb5_data_p = ctypes.POINTER(_krb5_data) + krb5_error = ctypes.c_int32 ++krb5_creds = _krb5_creds ++krb5_pointer = ctypes.c_void_p ++krb5_cc_cursor = krb5_pointer + + krb5_init_context = LIBKRB5.krb5_init_context + krb5_init_context.argtypes = (ctypes.POINTER(krb5_context), ) +@@ -61,15 +126,15 @@ krb5_init_context.errcheck = krb5_errcheck + + krb5_free_context = LIBKRB5.krb5_free_context + krb5_free_context.argtypes = (krb5_context, ) +-krb5_free_context.retval = None ++krb5_free_context.restype = None + + krb5_free_principal = LIBKRB5.krb5_free_principal + krb5_free_principal.argtypes = (krb5_context, krb5_principal) +-krb5_free_principal.retval = None ++krb5_free_principal.restype = None + + krb5_free_data_contents = LIBKRB5.krb5_free_data_contents + krb5_free_data_contents.argtypes = (krb5_context, krb5_data_p) +-krb5_free_data_contents.retval = None ++krb5_free_data_contents.restype = None + + krb5_cc_default = LIBKRB5.krb5_cc_default + krb5_cc_default.argtypes = (krb5_context, ctypes.POINTER(krb5_ccache), ) +@@ -78,26 +143,79 @@ krb5_cc_default.errcheck = krb5_errcheck + + krb5_cc_close = LIBKRB5.krb5_cc_close + krb5_cc_close.argtypes = (krb5_context, krb5_ccache, ) +-krb5_cc_close.retval = krb5_error ++krb5_cc_close.restype = krb5_error + krb5_cc_close.errcheck = krb5_errcheck + + krb5_parse_name = LIBKRB5.krb5_parse_name + krb5_parse_name.argtypes = (krb5_context, ctypes.c_char_p, + ctypes.POINTER(krb5_principal), ) +-krb5_parse_name.retval = krb5_error ++krb5_parse_name.restype = krb5_error + krb5_parse_name.errcheck = krb5_errcheck + + krb5_cc_set_config = LIBKRB5.krb5_cc_set_config + krb5_cc_set_config.argtypes = (krb5_context, krb5_ccache, krb5_principal, + ctypes.c_char_p, krb5_data_p, ) +-krb5_cc_set_config.retval = krb5_error ++krb5_cc_set_config.restype = krb5_error + krb5_cc_set_config.errcheck = krb5_errcheck + +-krb5_cc_get_config = LIBKRB5.krb5_cc_get_config +-krb5_cc_get_config.argtypes = (krb5_context, krb5_ccache, krb5_principal, +- ctypes.c_char_p, krb5_data_p, ) +-krb5_cc_get_config.retval = krb5_error +-krb5_cc_get_config.errcheck = krb5_errcheck ++krb5_cc_get_principal = LIBKRB5.krb5_cc_get_principal ++krb5_cc_get_principal.argtypes = (krb5_context, krb5_ccache, ++ ctypes.POINTER(krb5_principal), ) ++krb5_cc_get_principal.restype = krb5_error ++krb5_cc_get_principal.errcheck = krb5_errcheck ++ ++# krb5_build_principal is a variadic function but that can't be expressed ++# in a ctypes argtypes definition, so I explicitly listed the number of ++# arguments we actually use through the code for type checking purposes ++krb5_build_principal = LIBKRB5.krb5_build_principal ++krb5_build_principal.argtypes = (krb5_context, ctypes.POINTER(krb5_principal), ++ ctypes.c_uint, ctypes.c_char_p, ++ ctypes.c_char_p, ctypes.c_char_p, ++ ctypes.c_char_p, ctypes.c_char_p, ) ++krb5_build_principal.restype = krb5_error ++krb5_build_principal.errcheck = krb5_errcheck ++ ++krb5_cc_start_seq_get = LIBKRB5.krb5_cc_start_seq_get ++krb5_cc_start_seq_get.argtypes = (krb5_context, krb5_ccache, ++ ctypes.POINTER(krb5_cc_cursor), ) ++krb5_cc_start_seq_get.restype = krb5_error ++krb5_cc_start_seq_get.errcheck = krb5_errcheck ++ ++krb5_cc_next_cred = LIBKRB5.krb5_cc_next_cred ++krb5_cc_next_cred.argtypes = (krb5_context, krb5_ccache, ++ ctypes.POINTER(krb5_cc_cursor), ++ ctypes.POINTER(krb5_creds), ) ++krb5_cc_next_cred.restype = krb5_error ++krb5_cc_next_cred.errcheck = krb5_errcheck ++ ++krb5_cc_end_seq_get = LIBKRB5.krb5_cc_end_seq_get ++krb5_cc_end_seq_get.argtypes = (krb5_context, krb5_ccache, ++ ctypes.POINTER(krb5_cc_cursor), ) ++krb5_cc_end_seq_get.restype = krb5_error ++krb5_cc_end_seq_get.errcheck = krb5_errcheck ++ ++krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents ++krb5_free_cred_contents.argtypes = (krb5_context, ctypes.POINTER(krb5_creds)) ++krb5_free_cred_contents.restype = krb5_error ++krb5_free_cred_contents.errcheck = krb5_errcheck ++ ++krb5_principal_compare = LIBKRB5.krb5_principal_compare ++krb5_principal_compare.argtypes = (krb5_context, krb5_principal, ++ krb5_principal, ) ++krb5_principal_compare.restype = krb5_boolean ++ ++krb5_unparse_name = LIBKRB5.krb5_unparse_name ++krb5_unparse_name.argtypes = (krb5_context, krb5_principal, ++ ctypes.POINTER(ctypes.c_char_p), ) ++krb5_unparse_name.restype = krb5_error ++krb5_unparse_name.errcheck = krb5_errcheck ++ ++krb5_free_unparsed_name = LIBKRB5.krb5_free_unparsed_name ++krb5_free_unparsed_name.argtypes = (krb5_context, ctypes.c_char_p, ) ++krb5_free_unparsed_name.restype = None ++ ++CONF_REALM = "X-CACHECONF:" ++CONF_NAME = "krb5_ccache_conf_data" + + + def store_data(princ_name, key, value): +@@ -144,29 +262,78 @@ def get_data(princ_name, key): + """ + context = krb5_context() + principal = krb5_principal() ++ srv_princ = krb5_principal() + ccache = krb5_ccache() +- data = _krb5_data() ++ pname_princ = krb5_principal() ++ pname = ctypes.c_char_p() + + try: + krb5_init_context(ctypes.byref(context)) + +- krb5_parse_name(context, ctypes.c_char_p(princ_name), +- ctypes.byref(principal)) +- + krb5_cc_default(context, ctypes.byref(ccache)) ++ krb5_cc_get_principal(context, ccache, ctypes.byref(principal)) + +- krb5_cc_get_config(context, ccache, principal, key, +- ctypes.byref(data)) +- +- return str(data.data) ++ # We need to parse and then unparse the name in case the pric_name ++ # passed in comes w/o a realm attached ++ krb5_parse_name(context, ctypes.c_char_p(princ_name), ++ ctypes.byref(pname_princ)) ++ krb5_unparse_name(context, pname_princ, ctypes.byref(pname)) ++ ++ krb5_build_principal(context, ctypes.byref(srv_princ), ++ len(CONF_REALM), ctypes.c_char_p(CONF_REALM), ++ ctypes.c_char_p(CONF_NAME), ctypes.c_char_p(key), ++ pname, ctypes.c_char_p(None)) ++ ++ # Unfortunately we can't just use krb5_cc_get_config() ++ # because of bugs in some ccache handling code in krb5 ++ # libraries that would always return the first entry ++ # stored and not the last one, which is the one we want. ++ cursor = krb5_cc_cursor() ++ creds = krb5_creds() ++ got_creds = False ++ krb5_cc_start_seq_get(context, ccache, ctypes.byref(cursor)) ++ try: ++ while True: ++ checkcreds = krb5_creds() ++ # the next function will throw an error and break out of the ++ # while loop when we try to access past the last cred ++ krb5_cc_next_cred(context, ccache, ctypes.byref(cursor), ++ ctypes.byref(checkcreds)) ++ if (krb5_principal_compare(context, principal, ++ checkcreds.client) == 1 and ++ krb5_principal_compare(context, srv_princ, ++ checkcreds.server) == 1): ++ if got_creds: ++ krb5_free_cred_contents(context, ctypes.byref(creds)) ++ creds = checkcreds ++ got_creds = True ++ # We do not stop here, as we want the LAST entry ++ # in the ccache for those ccaches that cannot delete ++ # but only always append, like FILE ++ else: ++ krb5_free_cred_contents(context, ++ ctypes.byref(checkcreds)) ++ except KRB5Error: ++ pass ++ finally: ++ krb5_cc_end_seq_get(context, ccache, ctypes.byref(cursor)) ++ ++ if got_creds: ++ data = creds.ticket.data.decode('utf-8') ++ krb5_free_cred_contents(context, ctypes.byref(creds)) ++ return data + + finally: + if principal: + krb5_free_principal(context, principal) ++ if srv_princ: ++ krb5_free_principal(context, srv_princ) ++ if pname_princ: ++ krb5_free_principal(context, pname_princ) ++ if pname: ++ krb5_free_unparsed_name(context, pname) + if ccache: + krb5_cc_close(context, ccache) +- if data: +- krb5_free_data_contents(context, data) + if context: + krb5_free_context(context) + +-- +2.12.1 + diff --git a/SOURCES/0042-Correct-path-to-HTTPD-s-systemd-service-directory.patch b/SOURCES/0042-Correct-path-to-HTTPD-s-systemd-service-directory.patch deleted file mode 100644 index 1f2a798..0000000 --- a/SOURCES/0042-Correct-path-to-HTTPD-s-systemd-service-directory.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0a0f32622b06234deb64a01376b0706a03650681 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Tue, 2 Aug 2016 16:58:07 +0200 -Subject: [PATCH] Correct path to HTTPD's systemd service directory - -Ticket #5681 and commit 586fee293f42388510fa5436af19460bbe1fdec5 changed -the location of the ipa.conf for Apache HTTPD. The variables -SYSTEMD_SYSTEM_HTTPD_D_DIR and SYSTEMD_SYSTEM_HTTPD_IPA_CONF point to -the wrong directory /etc/systemd/system/httpd.d/. The path is corrected -to /etc/systemd/system/httpd.service.d/. - -https://fedorahosted.org/freeipa/ticket/6158 -https://bugzilla.redhat.com/show_bug.cgi?id=1362537 -Signed-off-by: Christian Heimes -Reviewed-By: Abhijeet Kasurde ---- - ipaplatform/base/paths.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index 1507ac36da5b40447c951ee608053a09b2db2fc3..9c8eaf951df89d373796be3f354bd3c51a329902 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -126,8 +126,8 @@ class BasePathNamespace(object): - SYSCONFIG_PKI_TOMCAT = "/etc/sysconfig/pki-tomcat" - SYSCONFIG_PKI_TOMCAT_PKI_TOMCAT_DIR = "/etc/sysconfig/pki/tomcat/pki-tomcat" - ETC_SYSTEMD_SYSTEM_DIR = "/etc/systemd/system/" -- SYSTEMD_SYSTEM_HTTPD_D_DIR = "/etc/systemd/system/httpd.d/" -- SYSTEMD_SYSTEM_HTTPD_IPA_CONF = "/etc/systemd/system/httpd.d/ipa.conf" -+ SYSTEMD_SYSTEM_HTTPD_D_DIR = "/etc/systemd/system/httpd.service.d/" -+ SYSTEMD_SYSTEM_HTTPD_IPA_CONF = "/etc/systemd/system/httpd.service.d/ipa.conf" - SYSTEMD_CERTMONGER_SERVICE = "/etc/systemd/system/multi-user.target.wants/certmonger.service" - SYSTEMD_IPA_SERVICE = "/etc/systemd/system/multi-user.target.wants/ipa.service" - SYSTEMD_SSSD_SERVICE = "/etc/systemd/system/multi-user.target.wants/sssd.service" --- -2.7.4 - diff --git a/SOURCES/0042-Prevent-churn-on-ccaches.patch b/SOURCES/0042-Prevent-churn-on-ccaches.patch new file mode 100644 index 0000000..1912a24 --- /dev/null +++ b/SOURCES/0042-Prevent-churn-on-ccaches.patch @@ -0,0 +1,71 @@ +From df5600dc012465f2f18a54aa451353f0fd9d5453 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Thu, 23 Mar 2017 17:49:27 -0400 +Subject: [PATCH] Prevent churn on ccaches + +We slice down the received cookie so that just the content that matter +is preserved. Thi is ok because servers can't trust anything else anyway +and will accept a cookie with the ancillary data missing. + +By removing variable parts like the expiry component added by +mod_session or the Expiration or Max-Age metadata we keep only the part +of the cookie that changes only when a new session is generated. + +This way when storing the cookie we actually add a new entry in the +ccache only when the session actually changes, and this prevents churn +on FILE based ccaches. + +Related https://pagure.io/freeipa/issue/6775 + +Signed-off-by: Simo Sorce +Reviewed-By: Christian Heimes +Reviewed-By: Alexander Bokovoy +--- + ipalib/rpc.py | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index c1ceeec197c4a9c55f303f0fd431e86adb389598..5c49bd2456b7e564043a886c840fa2678060f9e3 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -38,6 +38,7 @@ import os + import locale + import base64 + import json ++import re + import socket + import gzip + +@@ -737,6 +738,20 @@ class KerbTransport(SSLTransport): + self.send_content(connection, request_body) + return connection + ++ # Find all occurrences of the expiry component ++ expiry_re = re.compile(r'.*?(&expiry=\d+).*?') ++ ++ def _slice_session_cookie(self, session_cookie): ++ # Keep only the cookie value and strip away all other info. ++ # This is to reduce the churn on FILE ccaches which grow every time we ++ # set new data. The expiration time for the cookie is set in the ++ # encrypted data anyway and will be enforced by the server ++ http_cookie = session_cookie.http_cookie() ++ # We also remove the "expiry" part from the data which is not required ++ for exp in self.expiry_re.findall(http_cookie): ++ http_cookie = http_cookie.replace(exp, '') ++ return http_cookie ++ + def store_session_cookie(self, cookie_header): + ''' + Given the contents of a Set-Cookie header scan the header and +@@ -787,7 +802,7 @@ class KerbTransport(SSLTransport): + if session_cookie is None: + return + +- cookie_string = str(session_cookie) ++ cookie_string = self._slice_session_cookie(session_cookie) + root_logger.debug("storing cookie '%s' for principal %s", cookie_string, principal) + try: + update_persistent_client_session_data(principal, cookie_string) +-- +2.12.1 + diff --git a/SOURCES/0043-Generate-PIN-for-PKI-to-help-Dogtag-in-FIPS.patch b/SOURCES/0043-Generate-PIN-for-PKI-to-help-Dogtag-in-FIPS.patch new file mode 100644 index 0000000..4d1370c --- /dev/null +++ b/SOURCES/0043-Generate-PIN-for-PKI-to-help-Dogtag-in-FIPS.patch @@ -0,0 +1,68 @@ +From 036605789d6b34f5592d2ef38723eeb87e6ae21a Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 28 Mar 2017 13:54:16 +0200 +Subject: [PATCH] Generate PIN for PKI to help Dogtag in FIPS + +Dogtag is currently unable to generate a PIN it could use for +an NSS database creation in FIPS. Generate it for them so that +we don't fail. + +https://pagure.io/freeipa/issue/6824 + +Reviewed-By: Tomas Krizek +--- + ipaserver/install/cainstance.py | 6 +++++- + ipaserver/install/krainstance.py | 6 +++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index f0d3c236810d01f08192b239c0edb362ed78e071..92bb760d39d23fedb40b7e3c5bea53381f1c87ad 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -541,6 +541,10 @@ class CAInstance(DogtagInstance): + # CA key algorithm + config.set("CA", "pki_ca_signing_key_algorithm", self.ca_signing_algorithm) + ++ # generate pin which we know can be used for FIPS NSS database ++ pki_pin = ipautil.ipa_generate_password() ++ config.set("CA", "pki_pin", pki_pin) ++ + if self.clone: + + if self.no_db_setup: +@@ -613,7 +617,7 @@ class CAInstance(DogtagInstance): + try: + DogtagInstance.spawn_instance( + self, cfg_file, +- nolog_list=(self.dm_password, self.admin_password) ++ nolog_list=(self.dm_password, self.admin_password, pki_pin) + ) + finally: + os.remove(cfg_file) +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index b41ccb6fa6517f53ad1f83389b45795f0cd135bc..34d667857a8055752e258a591af983190f33daa5 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -235,6 +235,10 @@ class KRAInstance(DogtagInstance): + "KRA", "pki_share_dbuser_dn", + str(DN(('uid', 'pkidbuser'), ('ou', 'people'), ('o', 'ipaca')))) + ++ # generate pin which we know can be used for FIPS NSS database ++ pki_pin = ipautil.ipa_generate_password() ++ config.set("KRA", "pki_pin", pki_pin) ++ + _p12_tmpfile_handle, p12_tmpfile_name = tempfile.mkstemp(dir=paths.TMP) + + if self.clone: +@@ -275,7 +279,7 @@ class KRAInstance(DogtagInstance): + try: + DogtagInstance.spawn_instance( + self, cfg_file, +- nolog_list=(self.dm_password, self.admin_password) ++ nolog_list=(self.dm_password, self.admin_password, pki_pin) + ) + finally: + os.remove(p12_tmpfile_name) +-- +2.12.1 + diff --git a/SOURCES/0043-vault-Catch-correct-exception-in-decrypt.patch b/SOURCES/0043-vault-Catch-correct-exception-in-decrypt.patch deleted file mode 100644 index 25eb903..0000000 --- a/SOURCES/0043-vault-Catch-correct-exception-in-decrypt.patch +++ /dev/null @@ -1,30 +0,0 @@ -From cc92fe8badfe32f4c55abfa8b249dc1f94936d7c Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 3 Aug 2016 10:35:40 +0200 -Subject: [PATCH] vault: Catch correct exception in decrypt - -ValueError is raised when decryption fails. - -https://fedorahosted.org/freeipa/ticket/6160 - -Reviewed-By: David Kupka ---- - ipaclient/plugins/vault.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index e3a1ae3a0ad767bcee843b7fa3743a934e02d18b..73ad09b38316d55b466b7973dbeffefc1b7bb528 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -164,7 +164,7 @@ def decrypt(data, symmetric_key=None, private_key=None): - label=None - ) - ) -- except AssertionError: -+ except ValueError: - raise errors.AuthenticationError( - message=_('Invalid credentials')) - --- -2.7.4 - diff --git a/SOURCES/0044-Increase-default-length-of-auto-generated-passwords.patch b/SOURCES/0044-Increase-default-length-of-auto-generated-passwords.patch deleted file mode 100644 index 1814e3c..0000000 --- a/SOURCES/0044-Increase-default-length-of-auto-generated-passwords.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 0d2e4dae80eb4140ea605ca88d9130b8bf3ec269 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 22 Jul 2016 16:41:29 +0200 -Subject: [PATCH] Increase default length of auto generated passwords - -Installer/IPA generates passwords for warious purpose: -* KRA -* kerberos master key -* NSSDB password -* temporary passwords during installation - -Length of passwords should be increased to 22, ~128bits of entropy, to -be safe nowadays. - -https://fedorahosted.org/freeipa/ticket/6116 - -Reviewed-By: Alexander Bokovoy ---- - ipapython/ipautil.py | 3 ++- - ipaserver/plugins/baseuser.py | 5 +++-- - ipaserver/plugins/host.py | 9 +++++++-- - ipaserver/plugins/stageuser.py | 5 +++-- - ipaserver/plugins/user.py | 5 +++-- - 5 files changed, 18 insertions(+), 9 deletions(-) - -diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py -index 9964fba4f694b57242b3bd3065a418917d977533..fdfebb65ecb8b62108852f6517b5ffb22fd7eedc 100644 ---- a/ipapython/ipautil.py -+++ b/ipapython/ipautil.py -@@ -57,7 +57,8 @@ from ipapython.dn import DN - SHARE_DIR = paths.USR_SHARE_IPA_DIR - PLUGINS_SHARE_DIR = paths.IPA_PLUGINS - --GEN_PWD_LEN = 12 -+GEN_PWD_LEN = 22 -+GEN_TMP_PWD_LEN = 12 # only for OTP password that is manually retyped by user - - # Having this in krb_utils would cause circular import - KRB5_KDC_UNREACH = 2529639068 # Cannot contact any KDC for requested realm -diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py -index e4288a5a131157815ffb2452692a7edb342f6ac3..5e36a6620295351d4745bfc035f24349f8fb8295 100644 ---- a/ipaserver/plugins/baseuser.py -+++ b/ipaserver/plugins/baseuser.py -@@ -34,7 +34,7 @@ from ipaserver.plugins.service import ( - from ipalib.request import context - from ipalib import _ - from ipapython import kerberos --from ipapython.ipautil import ipa_generate_password -+from ipapython.ipautil import ipa_generate_password, GEN_TMP_PWD_LEN - from ipapython.ipavalidate import Email - from ipalib.util import ( - normalize_sshpubkey, -@@ -552,7 +552,8 @@ class baseuser_mod(LDAPUpdate): - - def check_userpassword(self, entry_attrs, **options): - if 'userpassword' not in entry_attrs and options.get('random'): -- entry_attrs['userpassword'] = ipa_generate_password(baseuser_pwdchars) -+ entry_attrs['userpassword'] = ipa_generate_password( -+ baseuser_pwdchars, pwd_len=GEN_TMP_PWD_LEN) - # save the password so it can be displayed in post_callback - setattr(context, 'randompassword', entry_attrs['userpassword']) - -diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py -index 413dcf15e0423170d8334902b9dcf8fb5aa14de6..03c64c637cbba0aee1b6569f3b5dbe200953bff8 100644 ---- a/ipaserver/plugins/host.py -+++ b/ipaserver/plugins/host.py -@@ -59,7 +59,11 @@ from ipalib.util import (normalize_sshpubkey, validate_sshpubkey_no_options, - hostname_validator, - set_krbcanonicalname - ) --from ipapython.ipautil import ipa_generate_password, CheckedIPAddress -+from ipapython.ipautil import ( -+ ipa_generate_password, -+ CheckedIPAddress, -+ GEN_TMP_PWD_LEN -+) - from ipapython.dnsutil import DNSName - from ipapython.ssh import SSHPublicKey - from ipapython.dn import DN -@@ -683,7 +687,8 @@ class host_add(LDAPCreate): - if 'krbprincipal' in entry_attrs['objectclass']: - entry_attrs['objectclass'].remove('krbprincipal') - if options.get('random'): -- entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars) -+ entry_attrs['userpassword'] = ipa_generate_password( -+ characters=host_pwd_chars, pwd_len=GEN_TMP_PWD_LEN) - # save the password so it can be displayed in post_callback - setattr(context, 'randompassword', entry_attrs['userpassword']) - certs = options.get('usercertificate', []) -diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py -index 3b9388f6020b9a6c40caedd36f3640a05a13da65..a219e3dace6da5e9c036122e9710b2acaaa42ebf 100644 ---- a/ipaserver/plugins/stageuser.py -+++ b/ipaserver/plugins/stageuser.py -@@ -47,7 +47,7 @@ from ipalib.util import set_krbcanonicalname - from ipalib import _, ngettext - from ipalib import output - from ipaplatform.paths import paths --from ipapython.ipautil import ipa_generate_password -+from ipapython.ipautil import ipa_generate_password, GEN_TMP_PWD_LEN - from ipalib.capabilities import client_has_capability - - if six.PY3: -@@ -339,7 +339,8 @@ class stageuser_add(baseuser_add): - - # If requested, generate a userpassword - if 'userpassword' not in entry_attrs and options.get('random'): -- entry_attrs['userpassword'] = ipa_generate_password(baseuser_pwdchars) -+ entry_attrs['userpassword'] = ipa_generate_password( -+ baseuser_pwdchars, pwd_len=GEN_TMP_PWD_LEN) - # save the password so it can be displayed in post_callback - setattr(context, 'randompassword', entry_attrs['userpassword']) - -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index b3ae7646fdcfa1dce10d90063dae2a24c091e8ee..935ea892cde9e2cb5b21f4714fd93e73c3fa53d5 100644 ---- a/ipaserver/plugins/user.py -+++ b/ipaserver/plugins/user.py -@@ -63,7 +63,7 @@ from ipalib import _, ngettext - from ipalib import output - from ipaplatform.paths import paths - from ipapython.dn import DN --from ipapython.ipautil import ipa_generate_password -+from ipapython.ipautil import ipa_generate_password, GEN_TMP_PWD_LEN - from ipalib.capabilities import client_has_capability - - if api.env.in_server: -@@ -517,7 +517,8 @@ class user_add(baseuser_add): - entry_attrs['gidnumber'] = group_attrs['gidnumber'] - - if 'userpassword' not in entry_attrs and options.get('random'): -- entry_attrs['userpassword'] = ipa_generate_password(baseuser_pwdchars) -+ entry_attrs['userpassword'] = ipa_generate_password( -+ baseuser_pwdchars, pwd_len=GEN_TMP_PWD_LEN) - # save the password so it can be displayed in post_callback - setattr(context, 'randompassword', entry_attrs['userpassword']) - --- -2.7.4 - diff --git a/SOURCES/0044-httpinstance.disable_system_trust-Don-t-fail-if-modu.patch b/SOURCES/0044-httpinstance.disable_system_trust-Don-t-fail-if-modu.patch new file mode 100644 index 0000000..f8356de --- /dev/null +++ b/SOURCES/0044-httpinstance.disable_system_trust-Don-t-fail-if-modu.patch @@ -0,0 +1,47 @@ +From 9cacddeb763c3e07ee31ac5bc2528cfb274b57b1 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Mon, 27 Mar 2017 09:30:53 +0200 +Subject: [PATCH] httpinstance.disable_system_trust: Don't fail if module 'Root + Certs' is not available + +Server installation failed when attmpting to disable module 'Root Certs' and +the module was not available in HTTP_ALIAS_DIR. When the module is not +available there's no need to disable it and the error may be treated as +success. + +https://pagure.io/freeipa/issue/6803 + +Reviewed-By: Christian Heimes +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/httpinstance.py | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index f6f0b0c4f6acd648aa9f6f5d7400617613245473..01b55e7a7b00d020b7745c419267ad4f0ba86804 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -355,9 +355,17 @@ class HTTPInstance(service.Service): + name = 'Root Certs' + args = [paths.MODUTIL, '-dbdir', paths.HTTPD_ALIAS_DIR, '-force'] + +- result = ipautil.run(args + ['-list', name], +- env={}, +- capture_output=True) ++ try: ++ result = ipautil.run(args + ['-list', name], ++ env={}, ++ capture_output=True) ++ except ipautil.CalledProcessError as e: ++ if e.returncode == 29: # ERROR: Module not found in database. ++ root_logger.debug( ++ 'Module %s not available, treating as disabled', name) ++ return False ++ raise ++ + if 'Status: Enabled' in result.output: + ipautil.run(args + ['-disable', name], env={}) + return True +-- +2.12.1 + diff --git a/SOURCES/0045-extdom-do-reverse-search-for-domain-separator.patch b/SOURCES/0045-extdom-do-reverse-search-for-domain-separator.patch new file mode 100644 index 0000000..c422b4d --- /dev/null +++ b/SOURCES/0045-extdom-do-reverse-search-for-domain-separator.patch @@ -0,0 +1,49 @@ +From e795c094ac6ccc8a33e247ba56b93c35ed9cf57d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 17 Mar 2017 14:10:52 +0100 +Subject: [PATCH] extdom: do reverse search for domain separator + +To avoid issues which @-signs in the short user or group names it is +better to search for the domain separator starting at the end of the +fully-qualified name. + +Reviewed-By: Alexander Bokovoy +Reviewed-By: David Kupka +--- + daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 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 e629247fd771e374d50486d836cd3b0d8d32a78a..aa1ff10dfbf51b87a367261202b39d1346bd337a 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 +@@ -515,7 +515,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, + char *short_user_name = NULL; + + short_user_name = strdup(user_name); +- if ((locat = strchr(short_user_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { ++ if ((locat = strrchr(short_user_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { + if (strcasecmp(locat+1, domain_name) == 0 ) { + locat[0] = '\0'; + } else { +@@ -626,7 +626,7 @@ int pack_ber_group(enum response_types response_type, + char *short_group_name = NULL; + + short_group_name = strdup(group_name); +- if ((locat = strchr(short_group_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { ++ if ((locat = strrchr(short_group_name, SSSD_DOMAIN_SEPARATOR)) != NULL) { + if (strcasecmp(locat+1, domain_name) == 0 ) { + locat[0] = '\0'; + } else { +@@ -901,7 +901,7 @@ static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx, + goto done; + } + +- sep = strchr(fq_name, SSSD_DOMAIN_SEPARATOR); ++ sep = strrchr(fq_name, SSSD_DOMAIN_SEPARATOR); + if (sep == NULL) { + set_err_msg(req, "Failed to split fully qualified name"); + ret = LDAP_OPERATIONS_ERROR; +-- +2.12.1 + diff --git a/SOURCES/0045-vault-add-missing-salt-option-to-vault_mod.patch b/SOURCES/0045-vault-add-missing-salt-option-to-vault_mod.patch deleted file mode 100644 index 802353a..0000000 --- a/SOURCES/0045-vault-add-missing-salt-option-to-vault_mod.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 001abcdca2026d0e1f51ca4e4e9d2cff052eadd7 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 4 Aug 2016 14:14:15 +0200 -Subject: [PATCH] vault: add missing salt option to vault_mod - -The option was accidentally removed in commit -4b119e21a2f93ca16c5edf3d1058552b44feeaf8. - -https://fedorahosted.org/freeipa/ticket/6154 - -Reviewed-By: Jan Cholasta ---- - ipaclient/plugins/vault.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index 73ad09b38316d55b466b7973dbeffefc1b7bb528..9026cbb0829a7557584df27a4262dfde640b4f28 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -413,7 +413,7 @@ class vault_mod(Local): - - def get_options(self): - for option in self.api.Command.vault_mod_internal.options(): -- if option.name not in ('ipavaultsalt', 'version'): -+ if option.name != 'version': - yield option - for option in super(vault_mod, self).get_options(): - yield option --- -2.7.4 - diff --git a/SOURCES/0046-Fix-ipa-hbactest-output.patch b/SOURCES/0046-Fix-ipa-hbactest-output.patch deleted file mode 100644 index 252279e..0000000 --- a/SOURCES/0046-Fix-ipa-hbactest-output.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 56f6fe1df44bc9d3f434b0bccd44bc11cda89999 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Tue, 2 Aug 2016 10:40:54 +0200 -Subject: [PATCH] Fix ipa hbactest output - -ipa hbactest command produces a Traceback (TypeError: cannot concatenate -'str' and 'bool' objects) -This happens because hbactest overrides output_for_cli but does not -properly handle the output for 'value' field. 'value' contains a boolean -but it should not be displayed (refer to ipalib/frontend.py, -Command.output_for_cli()). - -Note that the issue did not appear before because the 'value' field -had a flag no_display. - -https://fedorahosted.org/freeipa/ticket/6157 - -Reviewed-By: Martin Basti ---- - ipaclient/plugins/hbactest.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/ipaclient/plugins/hbactest.py b/ipaclient/plugins/hbactest.py -index 2518719522c4eddff2e6bc341ee9a7c34b431938..1b54530b236cf654bc8ece7ab4e329850f5a6815 100644 ---- a/ipaclient/plugins/hbactest.py -+++ b/ipaclient/plugins/hbactest.py -@@ -39,13 +39,15 @@ class hbactest(CommandOverride): - # to be printed as our execute() method will return None for corresponding - # entries and None entries will be skipped. - for o in self.output: -+ if o == 'value': -+ continue - outp = self.output[o] - if 'no_display' in outp.flags: - continue - result = output[o] - if isinstance(result, (list, tuple)): - textui.print_attribute(unicode(outp.doc), result, '%s: %s', 1, True) -- elif isinstance(result, (unicode, bool)): -+ elif isinstance(result, unicode): - if o == 'summary': - textui.print_summary(result) - else: --- -2.7.4 - diff --git a/SOURCES/0046-extdom-improve-cert-request.patch b/SOURCES/0046-extdom-improve-cert-request.patch new file mode 100644 index 0000000..bbdf685 --- /dev/null +++ b/SOURCES/0046-extdom-improve-cert-request.patch @@ -0,0 +1,243 @@ +From b2af54f9e327763783f482b3d5b7b3819ce75f82 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 17 Mar 2017 14:48:50 +0100 +Subject: [PATCH] extdom: improve cert request + +Certificates can be assigned to multiple user so the extdom plugin must +use sss_nss_getlistbycert() instead of sss_nss_getnamebycert() and +return a list of fully-qualified user names. + +Due to issues on the SSSD side the current version of lookups by +certificates didn't work at all and the changes here won't break +existing clients. + +Related to https://pagure.io/freeipa/issue/6826 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: David Kupka +--- + .../ipa-extdom-extop/ipa_extdom.h | 3 +- + .../ipa-extdom-extop/ipa_extdom_common.c | 157 ++++++++++++++++++--- + server.m4 | 2 +- + 3 files changed, 143 insertions(+), 19 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h +index 34e2d3c795e33bbeb9552910d80ddcc828751b93..bc29f069816b0ce13578c9ae14c61edb832d44e4 100644 +--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h ++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h +@@ -95,7 +95,8 @@ enum response_types { + RESP_USER, + RESP_GROUP, + RESP_USER_GROUPLIST, +- RESP_GROUP_MEMBERS ++ RESP_GROUP_MEMBERS, ++ RESP_NAME_LIST + }; + + struct extdom_req { +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 aa1ff10dfbf51b87a367261202b39d1346bd337a..fe225fa86669a6728bec5014be41d80275f10717 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 +@@ -698,6 +698,90 @@ done: + return ret; + } + ++int pack_ber_name_list(struct extdom_req *req, char **fq_name_list, ++ struct berval **berval) ++{ ++ BerElement *ber = NULL; ++ int ret; ++ char *sep; ++ size_t c; ++ size_t len; ++ size_t name_len; ++ ++ /* count the names */ ++ for (c = 0; fq_name_list[c] != NULL; c++); ++ if (c == 0) { ++ set_err_msg(req, "Empty name list"); ++ return LDAP_NO_SUCH_OBJECT; ++ } ++ ++ ber = ber_alloc_t( LBER_USE_DER ); ++ if (ber == NULL) { ++ set_err_msg(req, "BER alloc failed"); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ ++ ret = ber_printf(ber,"{e{", RESP_NAME_LIST); ++ if (ret == -1) { ++ set_err_msg(req, "BER start failed"); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ for (c = 0; fq_name_list[c] != NULL; c++) { ++ len = strlen(fq_name_list[c]); ++ if (len < 3) { ++ set_err_msg(req, "Fully qualified name too short"); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ sep = strrchr(fq_name_list[c], SSSD_DOMAIN_SEPARATOR); ++ if (sep == NULL) { ++ set_err_msg(req, "Failed to split fully qualified name"); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ name_len = sep - fq_name_list[c]; ++ if (name_len == 0) { ++ set_err_msg(req, "Missing name."); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ if (name_len + 1 == len) { ++ set_err_msg(req, "Missing domain."); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ ret = ber_printf(ber,"{oo}", (sep + 1), len - name_len -1, ++ fq_name_list[c], name_len); ++ if (ret == -1) { ++ set_err_msg(req, "BER list item failed"); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ } ++ ++ ret = ber_printf(ber,"}}"); ++ if (ret == -1) { ++ set_err_msg(req, "BER end failed"); ++ ber_free(ber, 1); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ ret = ber_flatten(ber, berval); ++ ber_free(ber, 1); ++ if (ret == -1) { ++ set_err_msg(req, "BER flatten failed"); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ ++ return LDAP_SUCCESS; ++} ++ + int pack_ber_name(const char *domain_name, const char *name, + struct berval **berval) + { +@@ -867,12 +951,56 @@ done: + return ret; + } + +-static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx, +- struct extdom_req *req, +- enum request_types request_type, +- enum input_types input_type, +- const char *input, +- struct berval **berval) ++static int handle_cert_request(struct ipa_extdom_ctx *ctx, ++ struct extdom_req *req, ++ enum request_types request_type, ++ enum input_types input_type, ++ const char *input, ++ struct berval **berval) ++{ ++ int ret; ++ char **fq_names = NULL; ++ enum sss_id_type *id_types = NULL; ++ size_t c; ++ ++ if (request_type != REQ_SIMPLE) { ++ set_err_msg(req, "Only simple request type allowed " ++ "for lookups by certificate"); ++ ret = LDAP_PROTOCOL_ERROR; ++ goto done; ++ } ++ ++ ret = sss_nss_getlistbycert(input, &fq_names, &id_types); ++ if (ret != 0) { ++ if (ret == ENOENT) { ++ ret = LDAP_NO_SUCH_OBJECT; ++ } else { ++ set_err_msg(req, "Failed to lookup name by certificate"); ++ ret = LDAP_OPERATIONS_ERROR; ++ } ++ goto done; ++ } ++ ++ ret = pack_ber_name_list(req, fq_names, berval); ++ ++done: ++ if (fq_names != NULL) { ++ for (c = 0; fq_names[c] != NULL; c++) { ++ free(fq_names[c]); ++ } ++ free(fq_names); ++ } ++ free(id_types); ++ ++ return ret; ++} ++ ++static int handle_sid_request(struct ipa_extdom_ctx *ctx, ++ struct extdom_req *req, ++ enum request_types request_type, ++ enum input_types input_type, ++ const char *input, ++ struct berval **berval) + { + int ret; + struct passwd pwd; +@@ -886,11 +1014,7 @@ static int handle_sid_or_cert_request(struct ipa_extdom_ctx *ctx, + enum sss_id_type id_type; + struct sss_nss_kv *kv_list = NULL; + +- if (input_type == INP_SID) { +- ret = sss_nss_getnamebysid(input, &fq_name, &id_type); +- } else { +- ret = sss_nss_getnamebycert(input, &fq_name, &id_type); +- } ++ ret = sss_nss_getnamebysid(input, &fq_name, &id_type); + if (ret != 0) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; +@@ -1147,13 +1271,12 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req, + + break; + case INP_SID: ++ ret = handle_sid_request(ctx, req, req->request_type, ++ req->input_type, req->data.sid, berval); ++ break; + case INP_CERT: +- ret = handle_sid_or_cert_request(ctx, req, req->request_type, +- req->input_type, +- req->input_type == INP_SID ? +- req->data.sid : +- req->data.cert, +- berval); ++ ret = handle_cert_request(ctx, req, req->request_type, ++ req->input_type, req->data.cert, berval); + break; + case INP_NAME: + ret = handle_name_request(ctx, req, req->request_type, +diff --git a/server.m4 b/server.m4 +index a4c99195ae535e586445cf5bbe9fef457d224531..5d5333e194cb339d31576f54a70d96becadf9a87 100644 +--- a/server.m4 ++++ b/server.m4 +@@ -28,7 +28,7 @@ DIRSRV_CFLAGS="$DIRSRV_CFLAGS $NSPR_CFLAGS" + + dnl -- sss_idmap is needed by the extdom exop -- + PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap]) +-PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.13.90]) ++PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.15.2]) + + dnl -- sss_certmap and certauth.h are needed by the IPA KDB certauth plugin -- + PKG_CHECK_EXISTS([sss_certmap], +-- +2.12.1 + diff --git a/SOURCES/0047-install-fix-external-CA-cert-validation.patch b/SOURCES/0047-install-fix-external-CA-cert-validation.patch deleted file mode 100644 index 0e6980c..0000000 --- a/SOURCES/0047-install-fix-external-CA-cert-validation.patch +++ /dev/null @@ -1,31 +0,0 @@ -From fdcaf9f8437fcd12220af125a4fe0871c6d33f47 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 4 Aug 2016 09:58:38 +0200 -Subject: [PATCH] install: fix external CA cert validation - -The code which loads the external CA cert chain was never executed because -of an incorrect usage of an iterator (iterating over it twice). - -https://fedorahosted.org/freeipa/ticket/6166 - -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 25f48aed1eeaa03353465bc40abf3484ec19bf3b..66ba33326adcdb47c2ba77c573ba9b66a82b365e 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -1038,7 +1038,7 @@ def load_external_cert(files, subject_base): - raise ScriptError( - "IPA CA certificate not found in %s" % (", ".join(files))) - -- trust_chain = reversed(nssdb.get_trust_chain(ca_nickname)) -+ trust_chain = list(reversed(nssdb.get_trust_chain(ca_nickname))) - ca_cert_chain = [] - for nickname in trust_chain: - cert, subject, issuer = cache[nickname] --- -2.7.4 - diff --git a/SOURCES/0047-spec-file-bump-libsss_nss_idmap-devel-BuildRequires.patch b/SOURCES/0047-spec-file-bump-libsss_nss_idmap-devel-BuildRequires.patch new file mode 100644 index 0000000..a7fd0f5 --- /dev/null +++ b/SOURCES/0047-spec-file-bump-libsss_nss_idmap-devel-BuildRequires.patch @@ -0,0 +1,37 @@ +From e7091fc939b7b7a1c23f4e95220e343ca21958ad Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 29 Mar 2017 07:14:24 +0000 +Subject: [PATCH] spec file: bump libsss_nss_idmap-devel BuildRequires + +Bump BuildRequires on libsss_nss_idmap-devel to the version which +introduces the sss_nss_getlistbycert function. + +This fixes RPM build failure when an older version of +libsss_nss_idmap-devel was installed. + +https://pagure.io/freeipa/issue/6828 + +Reviewed-By: Tomas Krizek +Reviewed-By: Alexander Bokovoy +--- + freeipa.spec.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index e7e39e87bef39653d660a345793750f59c8dd715..829c3f0b2898de1ecbf0cfb769fde5cd978c241c 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -121,8 +121,8 @@ BuildRequires: libtevent-devel + BuildRequires: libuuid-devel + BuildRequires: libsss_idmap-devel + BuildRequires: libsss_certmap-devel +-# 1.14.0: sss_nss_getnamebycert (https://fedorahosted.org/sssd/ticket/2897) +-BuildRequires: libsss_nss_idmap-devel >= 1.14.0 ++# 1.15.3: sss_nss_getlistbycert (https://pagure.io/SSSD/sssd/issue/3050) ++BuildRequires: libsss_nss_idmap-devel >= 1.15.3 + BuildRequires: rhino + BuildRequires: libverto-devel + BuildRequires: libunistring-devel +-- +2.12.2 + diff --git a/SOURCES/0048-caacl-fix-regression-in-rule-instantiation.patch b/SOURCES/0048-caacl-fix-regression-in-rule-instantiation.patch deleted file mode 100644 index beeb795..0000000 --- a/SOURCES/0048-caacl-fix-regression-in-rule-instantiation.patch +++ /dev/null @@ -1,52 +0,0 @@ -From c27595371bfe1f4fe12125e053cb7ec3ad08ebf6 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 28 Jul 2016 10:55:45 +1000 -Subject: [PATCH] caacl: fix regression in rule instantiation - -The Principal refactor causes service collections -('memberservice_service' attribute) to return Principal objects -where previously it returned strings, but the HBAC machinery used -for CA ACL enforcement only handles strings. Update the code to -stringify service Principal objects when adding them to HBAC rules. - -Fixes: https://fedorahosted.org/freeipa/ticket/6146 -Reviewed-By: Martin Basti ---- - ipaserver/plugins/caacl.py | 17 +++++++++++------ - 1 file changed, 11 insertions(+), 6 deletions(-) - -diff --git a/ipaserver/plugins/caacl.py b/ipaserver/plugins/caacl.py -index d316cc7c48cf2997d6be6b052dc1efa6d6fcdb6a..a7817c4cf64f070c74557f52e9f26c9013a4963c 100644 ---- a/ipaserver/plugins/caacl.py -+++ b/ipaserver/plugins/caacl.py -@@ -132,16 +132,21 @@ def _acl_make_rule(principal_type, obj): - rule.services.names = obj.get(attr, []) - - # add principals and principal's groups -- m = {'user': 'group', 'host': 'hostgroup', 'service': None} - category_attr = '{}category'.format(principal_type) - if category_attr in obj and obj[category_attr][0].lower() == 'all': - rule.users.category = {pyhbac.HBAC_CATEGORY_ALL} - else: -- principal_attr = 'member{}_{}'.format(principal_type, principal_type) -- rule.users.names = obj.get(principal_attr, []) -- if m[principal_type] is not None: -- group_attr = 'member{}_{}'.format(principal_type, m[principal_type]) -- rule.users.groups = obj.get(group_attr, []) -+ if principal_type == 'user': -+ rule.users.names = obj.get('memberuser_user', []) -+ rule.users.groups = obj.get('memberuser_group', []) -+ elif principal_type == 'host': -+ rule.users.names = obj.get('memberhost_host', []) -+ rule.users.groups = obj.get('memberhost_hostgroup', []) -+ elif principal_type == 'service': -+ rule.users.names = [ -+ unicode(principal) -+ for principal in obj.get('memberservice_service', []) -+ ] - - return rule - --- -2.7.4 - diff --git a/SOURCES/0048-server-make-sure-we-test-for-sss_nss_getlistbycert.patch b/SOURCES/0048-server-make-sure-we-test-for-sss_nss_getlistbycert.patch new file mode 100644 index 0000000..1da5471 --- /dev/null +++ b/SOURCES/0048-server-make-sure-we-test-for-sss_nss_getlistbycert.patch @@ -0,0 +1,32 @@ +From 6c76be7f9d5c25d940b026310e2efec3d46b5d23 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 29 Mar 2017 10:43:11 +0300 +Subject: [PATCH] server: make sure we test for sss_nss_getlistbycert + +Fixes https://pagure.io/freeipa/issue/6828 + +Reviewed-By: Christian Heimes +Reviewed-By: Tomas Krizek +--- + server.m4 | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/server.m4 b/server.m4 +index 5d5333e194cb339d31576f54a70d96becadf9a87..346d73e906c5d0499e46fcc4da070007b2ff5973 100644 +--- a/server.m4 ++++ b/server.m4 +@@ -29,6 +29,11 @@ DIRSRV_CFLAGS="$DIRSRV_CFLAGS $NSPR_CFLAGS" + dnl -- sss_idmap is needed by the extdom exop -- + PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap]) + PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.15.2]) ++AC_CHECK_LIB([sss_nss_idmap], ++ [sss_nss_getlistbycert], ++ [], ++ [AC_MSG_ERROR([Required sss_nss_getlistbycert symbol in sss_nss_idmap not found])], ++ []) + + dnl -- sss_certmap and certauth.h are needed by the IPA KDB certauth plugin -- + PKG_CHECK_EXISTS([sss_certmap], +-- +2.12.2 + diff --git a/SOURCES/0049-Update-ipa-replica-install-documentation.patch b/SOURCES/0049-Update-ipa-replica-install-documentation.patch deleted file mode 100644 index eb68a96..0000000 --- a/SOURCES/0049-Update-ipa-replica-install-documentation.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 2c82ea7bd562c34fd6ea9476b3b9b25f399bb0f1 Mon Sep 17 00:00:00 2001 -From: Tomas Krizek -Date: Fri, 5 Aug 2016 09:25:05 +0200 -Subject: [PATCH] Update ipa-replica-install documentation - -Update the ipa-replica-install man page and help to reflect that replica_file -is optional instead of mandatory. - -https://fedorahosted.org/freeipa/ticket/6164 - -Reviewed-By: Martin Basti ---- - install/tools/ipa-replica-install | 2 +- - install/tools/man/ipa-replica-install.1 | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install -index 17fc957a583739bbda386676f44209e196282a9a..b3f0361c6577cb693dcc0d81d8ca95b0c220679e 100755 ---- a/install/tools/ipa-replica-install -+++ b/install/tools/ipa-replica-install -@@ -27,7 +27,7 @@ ReplicaInstall = cli.install_tool( - Replica, - command_name='ipa-replica-install', - positional_arguments=['replica_file'], -- usage='%prog [options] REPLICA_FILE', -+ usage='%prog [options] [REPLICA_FILE]', - log_file_name=paths.IPAREPLICA_INSTALL_LOG, - debug_option=True, - ) -diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 -index 55bae2cb77e1a1c520e0598983b8939a919a9ee9..af37b07956691aeb676bb8e41e90f6ce783a5270 100644 ---- a/install/tools/man/ipa-replica-install.1 -+++ b/install/tools/man/ipa-replica-install.1 -@@ -22,7 +22,7 @@ ipa\-replica\-install \- Create an IPA replica - .SH "SYNOPSIS" - .SS "DOMAIN LEVEL 0" - .TP --ipa\-replica\-install [\fIOPTION\fR]... replica_file -+ipa\-replica\-install [\fIOPTION\fR]... [replica_file] - .SS "DOMAIN LEVEL 1" - .TP - ipa\-replica\-install [\fIOPTION\fR]... --- -2.7.4 - diff --git a/SOURCES/0049-Upgrade-configure-PKINIT-after-adding-anonymous-prin.patch b/SOURCES/0049-Upgrade-configure-PKINIT-after-adding-anonymous-prin.patch new file mode 100644 index 0000000..9ce9eec --- /dev/null +++ b/SOURCES/0049-Upgrade-configure-PKINIT-after-adding-anonymous-prin.patch @@ -0,0 +1,34 @@ +From a4140595a3fcb42d9666aea823d3d8cd9ae0c7c3 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Tue, 21 Mar 2017 17:03:35 +0100 +Subject: [PATCH] Upgrade: configure PKINIT after adding anonymous principal + +In order to set up PKINIT, the anonymous principal must already be +created, otherwise the upgrade with fail when trying out anonymous +PKINIT. Switch the order of steps so that this issue does not occur. + +https://pagure.io/freeipa/issue/6792 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/server/upgrade.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 1706079da86d9ba9066f71f02b170c161c1f2963..be07d78585d4772eb6dd0aaa8fb4ccb588c42c65 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1809,9 +1809,9 @@ def upgrade_configuration(): + KDC_CERT=paths.KDC_CERT, + KDC_KEY=paths.KDC_KEY, + CACERT_PEM=paths.CACERT_PEM) +- setup_pkinit(krb) + enable_anonymous_principal(krb) + http.request_anon_keytab() ++ setup_pkinit(krb) + + if not ds_running: + ds.stop(ds_serverid) +-- +2.12.2 + diff --git a/SOURCES/0050-Remove-unused-variable-from-failed-anonymous-PKINIT-.patch b/SOURCES/0050-Remove-unused-variable-from-failed-anonymous-PKINIT-.patch new file mode 100644 index 0000000..bdc94ba --- /dev/null +++ b/SOURCES/0050-Remove-unused-variable-from-failed-anonymous-PKINIT-.patch @@ -0,0 +1,28 @@ +From 7b4ef6d23fb335d99b38347f1c4516a21222231e Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 22 Mar 2017 10:01:34 +0100 +Subject: [PATCH] Remove unused variable from failed anonymous PKINIT handling + +https://pagure.io/freeipa/issue/6792 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/krbinstance.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index d936cc5f4f47e0e641a2d9ba4f943aab0301045c..c817076249a224347421b1bf18088eecb8eb345f 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -413,7 +413,7 @@ class KrbInstance(service.Service): + with ipautil.private_ccache() as anon_ccache: + try: + ipautil.run([paths.KINIT, '-n', '-c', anon_ccache]) +- except ipautil.CalledProcessError as e: ++ except ipautil.CalledProcessError: + raise RuntimeError("Failed to configure anonymous PKINIT") + + def enable_ssl(self): +-- +2.12.2 + diff --git a/SOURCES/0050-ipa-kdb-Fix-unit-test-after-packaging-changes-in-krb.patch b/SOURCES/0050-ipa-kdb-Fix-unit-test-after-packaging-changes-in-krb.patch deleted file mode 100644 index 28a3b5d..0000000 --- a/SOURCES/0050-ipa-kdb-Fix-unit-test-after-packaging-changes-in-krb.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 92c1f960cd31417d898230f9cb538dc2336ba590 Mon Sep 17 00:00:00 2001 -From: Lukas Slebodnik -Date: Fri, 5 Aug 2016 08:34:23 +0200 -Subject: [PATCH] ipa-kdb: Fix unit test after packaging changes in krb5 - -Resolves: -https://fedorahosted.org/freeipa/ticket/6173 - -Reviewed-By: Alexander Bokovoy ---- - freeipa.spec.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index ff27a32eebcc640cdbc8895f47732f06a90c4a1b..e1d98a44d04804a6bb2d4b17206aa7c280d64eb9 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -108,6 +108,8 @@ BuildRequires: python-netifaces >= 0.10.4 - # Build dependencies for unit tests - BuildRequires: libcmocka-devel - BuildRequires: nss_wrapper -+# Required by ipa_kdb_tests -+BuildRequires: %{_libdir}/krb5/plugins/kdb/db2.so - - %if 0%{?with_python3} - BuildRequires: python3-devel --- -2.7.4 - diff --git a/SOURCES/0051-Improvements-for-the-ipa-cacert-manage-man-and-help.patch b/SOURCES/0051-Improvements-for-the-ipa-cacert-manage-man-and-help.patch deleted file mode 100644 index 9945b12..0000000 --- a/SOURCES/0051-Improvements-for-the-ipa-cacert-manage-man-and-help.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 57f643fa5ba0382bbe8a35bd3cc6fe7bec721064 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka -Date: Fri, 15 Jul 2016 14:04:59 +0200 -Subject: [PATCH] Improvements for the ipa-cacert-manage man and help - -The man page for ipa-cacert-manage didn't mention that some -options are only applicable to the install some to the renew -subcommand. - -Also fixed a few missing articles. - -https://fedorahosted.org/freeipa/ticket/6013 - -Reviewed-By: Florence Blanc-Renaud ---- - install/tools/man/ipa-cacert-manage.1 | 38 ++++++++++++++++++++++------------ - ipaserver/install/ipa_cacert_manage.py | 2 +- - 2 files changed, 26 insertions(+), 14 deletions(-) - -diff --git a/install/tools/man/ipa-cacert-manage.1 b/install/tools/man/ipa-cacert-manage.1 -index 1f37788336048e412eee71757f236c9944860514..f0a1033ab372c2f923a883b385c0e3304b98f56f 100644 ---- a/install/tools/man/ipa-cacert-manage.1 -+++ b/install/tools/man/ipa-cacert-manage.1 -@@ -20,7 +20,9 @@ - .SH "NAME" - ipa\-cacert\-manage \- Manage CA certificates in IPA - .SH "SYNOPSIS" --\fBipa\-cacert\-manage\fR [\fIOPTIONS\fR...] \fICOMMAND\fR -+\fBipa\-cacert\-manage\fR [\fIOPTIONS\fR...] renew -+.RE -+\fBipa\-cacert\-manage\fR [\fIOPTIONS\fR...] install \fICERTFILE\fR - .SH "DESCRIPTION" - \fBipa\-cacert\-manage\fR can be used to manage CA certificates in IPA. - .SH "COMMANDS" -@@ -29,7 +31,7 @@ ipa\-cacert\-manage \- Manage CA certificates in IPA - \- Renew the IPA CA certificate - .sp - .RS --This command can be used to manually renew CA certificate of the IPA CA. -+This command can be used to manually renew the CA certificate of the IPA CA. - .sp - When the IPA CA is the root CA (the default), it is not usually necessary to manually renew the CA certificate, as it will be renewed automatically when it is about to expire, but you can do so if you wish. - .sp -@@ -42,13 +44,30 @@ When the IPA CA is not configured, this command is not available. - \- Install a CA certificate - .sp - .RS --This command can be used to install new CA certificate to IPA. -+This command can be used to install the certificate contained in \fICERTFILE\fR as a new CA certificate to IPA. - .RE --.SH "OPTIONS" -+.SH "COMMON OPTIONS" -+.TP -+\fB\-\-version\fR -+Show the program's version and exit. -+.TP -+\fB\-h\fR, \fB\-\-help\fR -+Show the help for this program. - .TP - \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR - The Directory Manager password to use for authentication. - .TP -+\fB\-v\fR, \fB\-\-verbose\fR -+Print debugging information. -+.TP -+\fB\-q\fR, \fB\-\-quiet\fR -+Output only errors. -+.TP -+\fB\-\-log\-file\fR=\fIFILE\fR -+Log to the given file. -+.RE -+.SH "RENEW OPTIONS" -+.TP - \fB\-\-self\-signed\fR - Sign the renewed certificate by itself. - .TP -@@ -57,6 +76,8 @@ Sign the renewed certificate by external CA. - .TP - \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. -+.RE -+.SH "INSTALL OPTIONS" - .TP - \fB\-n\fR \fINICKNAME\fR, \fB\-\-nickname\fR=\fINICKNAME\fR - Nickname for the certificate. -@@ -73,15 +94,6 @@ T \- CA trusted to issue client certificates - .IP - p \- not trusted - .RE --.TP --\fB\-v\fR, \fB\-\-verbose\fR --Print debugging information. --.TP --\fB\-q\fR, \fB\-\-quiet\fR --Output only errors. --.TP --\fB\-\-log\-file\fR=\fIFILE\fR --Log to the given file. - .SH "EXIT STATUS" - 0 if the command was successful - -diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py -index de13ad39397ae5e9b924b0621521e5fc6016c8e6..32ef25c7aac3e57d27955b6a2608adb6a1626019 100644 ---- a/ipaserver/install/ipa_cacert_manage.py -+++ b/ipaserver/install/ipa_cacert_manage.py -@@ -35,7 +35,7 @@ from ipaserver.install import certs, cainstance, installutils - class CACertManage(admintool.AdminTool): - command_name = 'ipa-cacert-manage' - -- usage = "%prog {renew|install} [options]" -+ usage = "%prog renew [options]\n%prog install [options] CERTFILE" - - description = "Manage CA certificates." - --- -2.7.4 - diff --git a/SOURCES/0051-Split-out-anonymous-PKINIT-test-to-a-separate-method.patch b/SOURCES/0051-Split-out-anonymous-PKINIT-test-to-a-separate-method.patch new file mode 100644 index 0000000..f509598 --- /dev/null +++ b/SOURCES/0051-Split-out-anonymous-PKINIT-test-to-a-separate-method.patch @@ -0,0 +1,37 @@ +From b12c465ae8b8ffb1e34741daf8c0dea6525e5fcf Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 22 Mar 2017 10:04:52 +0100 +Subject: [PATCH] Split out anonymous PKINIT test to a separate method + +This allows for more flexibility in the whole PKINIT setup process. + +https://pagure.io/freeipa/issue/6792 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/krbinstance.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index c817076249a224347421b1bf18088eecb8eb345f..5f4b5282f54234c15b1a8d8273eff69e134e665b 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -410,6 +410,7 @@ class KrbInstance(service.Service): + root_logger.critical("krb5kdc service failed to restart") + raise + ++ def test_anonymous_pkinit(self): + with ipautil.private_ccache() as anon_ccache: + try: + ipautil.run([paths.KINIT, '-n', '-c', anon_ccache]) +@@ -421,6 +422,7 @@ class KrbInstance(service.Service): + self.steps = [] + self.step("installing X509 Certificate for PKINIT", + self.setup_pkinit) ++ self.step("testing anonymous PKINIT", self.test_anonymous_pkinit) + + self.start_creation() + +-- +2.12.2 + diff --git a/SOURCES/0052-Ensure-KDC-is-propery-configured-after-upgrade.patch b/SOURCES/0052-Ensure-KDC-is-propery-configured-after-upgrade.patch new file mode 100644 index 0000000..4be94d5 --- /dev/null +++ b/SOURCES/0052-Ensure-KDC-is-propery-configured-after-upgrade.patch @@ -0,0 +1,47 @@ +From 73ed5d59d0777329450cb8d6dce78f8ee862068b Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 22 Mar 2017 11:56:18 +0100 +Subject: [PATCH] Ensure KDC is propery configured after upgrade + +https://pagure.io/freeipa/issue/6792 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/server/upgrade.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index be07d78585d4772eb6dd0aaa8fb4ccb588c42c65..0db764cb80f6d0fb22f00719dadf1f921f97bf62 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1499,15 +1499,14 @@ def enable_anonymous_principal(krb): + def setup_pkinit(krb): + root_logger.info("[Setup PKINIT]") + +- if os.path.exists(paths.KDC_CERT): +- root_logger.info("PKINIT already set up") +- return +- + if not api.Command.ca_is_enabled()['result']: + root_logger.info("CA is not enabled") + return + +- krb.setup_pkinit() ++ if not os.path.exists(paths.KDC_CERT): ++ root_logger.info("Requesting PKINIT certificate") ++ krb.setup_pkinit() ++ + replacevars = dict() + replacevars['pkinit_identity'] = 'FILE:{},{}'.format( + paths.KDC_CERT,paths.KDC_KEY) +@@ -1519,6 +1518,7 @@ def setup_pkinit(krb): + if krb.is_running(): + krb.stop() + krb.start() ++ krb.test_anonymous_pkinit() + + + def disable_httpd_system_trust(http): +-- +2.12.2 + diff --git a/SOURCES/0052-Revert-spec-add-conflict-with-bind-chroot-to-freeipa.patch b/SOURCES/0052-Revert-spec-add-conflict-with-bind-chroot-to-freeipa.patch deleted file mode 100644 index 98c97b7..0000000 --- a/SOURCES/0052-Revert-spec-add-conflict-with-bind-chroot-to-freeipa.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 61746b75a7b10115633df2f9dce075c0bbdf161e Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 9 Aug 2016 14:12:50 +0200 -Subject: [PATCH] Revert "spec: add conflict with bind-chroot to - freeipa-server-dns" - -Remove the conflict, as bind-chroot caused issue only on systems with older -bind and bind-chroot - e.g. RHEL 6. - -This reverts commit 3ab63fa6ba60947b1452c2108c4cf7637f4aacdb. - -https://fedorahosted.org/freeipa/ticket/5696 - -Reviewed-By: Petr Spacek ---- - freeipa.spec.in | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index e1d98a44d04804a6bb2d4b17206aa7c280d64eb9..77fca24ef0e1e244e53d203a228931b4a444fb5a 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -274,9 +274,6 @@ Obsoletes: %{alt_name}-server-dns < %{version} - # upgrade path from monolithic -server to -server + -server-dns - Obsoletes: %{name}-server <= 4.2.0 - --# FreeIPA does not support running integrated BIND in chroot jail --Conflicts: bind-chroot -- - %description server-dns - IPA integrated DNS server with support for automatic DNSSEC signing. - Integrated DNS server is BIND 9. OpenDNSSEC provides key management. --- -2.7.4 - diff --git a/SOURCES/0053-Fix-unicode-characters-in-ca-and-domain-adders.patch b/SOURCES/0053-Fix-unicode-characters-in-ca-and-domain-adders.patch deleted file mode 100644 index f32cb64..0000000 --- a/SOURCES/0053-Fix-unicode-characters-in-ca-and-domain-adders.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 8163981ec3296c6768cacad2ac7382ae2c706853 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Fri, 5 Aug 2016 14:04:03 +0200 -Subject: [PATCH] Fix unicode characters in ca and domain adders - -Topology graph didn't show plus icons correctly. - -There is a problem with uglifying of javascript code. It does not leave unicode character -written in hexadecimal format unchanged. Therefore this workaround which inserts -needed character using Javascript function and uglifiyng does not affect it. - -https://fedorahosted.org/freeipa/ticket/6175 - -Reviewed-By: Martin Basti ---- - install/ui/src/freeipa/topology_graph.js | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/topology_graph.js b/install/ui/src/freeipa/topology_graph.js -index ce2ebeaff611987ae27f2655b5da80bdcd1b4f8a..4bc3668647979c77719efa78b7a663d0e899216e 100644 ---- a/install/ui/src/freeipa/topology_graph.js -+++ b/install/ui/src/freeipa/topology_graph.js -@@ -530,12 +530,14 @@ topology_graph.TopoGraph = declare([Evented], { - - function add_labels(type, color, adder_group) { - var label_radius = 3; -+ var decimal_plus = parseInt('f067', 16); // Converts hexadecimal -+ // code of plus icon to decimal. - - var plus = adder_group - .append('text') - .classed('plus', true) - .classed(type + '_plus', true) -- .text('\uf067'); -+ .text(String.fromCharCode(decimal_plus)); - - var label = adder_group.append('path') - .attr('id', type + '_label'); --- -2.7.4 - diff --git a/SOURCES/0053-adtrust-make-sure-that-runtime-hostname-result-is-co.patch b/SOURCES/0053-adtrust-make-sure-that-runtime-hostname-result-is-co.patch new file mode 100644 index 0000000..d1feda9 --- /dev/null +++ b/SOURCES/0053-adtrust-make-sure-that-runtime-hostname-result-is-co.patch @@ -0,0 +1,77 @@ +From dd4ae3da2d341a25b63936b689e53fdbc8e93f65 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 20 Mar 2017 13:23:44 +0200 +Subject: [PATCH] adtrust: make sure that runtime hostname result is consistent + with the configuration + +FreeIPA's `ipasam` module to Samba uses gethostname() call to identify +own server's host name. This value is then used in multiple places, +including construction of cifs/host.name principal. `ipasam` module +always uses GSSAPI authentication when talking to LDAP, so Kerberos +keys must be available in the /etc/samba/samba.keytab. However, if +the principal was created using non-FQDN name but system reports +FQDN name, `ipasam` will fail to acquire Kerberos credentials. +Same with FQDN principal and non-FQDN hostname. + +Also host name and principal name must have the same case. + +Report an error when configuring ADTrust instance with inconsistent +runtime hostname and configuration. This prevents errors like this: + + [20/21]: starting CIFS services + ipa : CRITICAL CIFS services failed to start + + where samba logs have this: + + [2017/03/20 06:34:27.385307, 0] ipa_sam.c:4193(bind_callback_cleanup) + kerberos error: code=-1765328203, message=Keytab contains no suitable keys for cifs/ipatrust@EXAMPLE.COM + [2017/03/20 06:34:27.385476, 1] ../source3/lib/smbldap.c:1206(get_cached_ldap_connect) + Connection to LDAP server failed for the 16 try! + +Fixes https://pagure.io/freeipa/issue/6786 + +Reviewed-By: Martin Basti +--- + ipaserver/install/adtrustinstance.py | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index 0b189854f568ea5d8c0e68077255939887ff0cc3..b4db055045823ce8ae7e3b264e1442a085f81b2d 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -27,6 +27,7 @@ import uuid + import string + import struct + import re ++import socket + + import six + +@@ -689,6 +690,15 @@ class ADTRUSTInstance(service.Service): + except Exception as e: + root_logger.critical("Enabling nsswitch support in slapi-nis failed with error '%s'" % e) + ++ def __validate_server_hostname(self): ++ hostname = socket.gethostname() ++ if hostname != self.fqdn: ++ raise ValueError("Host reports different name than configured: " ++ "'%s' versus '%s'. Samba requires to have " ++ "the same hostname or Kerberos principal " ++ "'cifs/%s' will not be found in Samba keytab." % ++ (hostname, self.fqdn, self.fqdn)) ++ + def __start(self): + try: + self.start() +@@ -804,6 +814,8 @@ class ADTRUSTInstance(service.Service): + api.Backend.ldap2.add_entry(entry) + + def create_instance(self): ++ self.step("validate server hostname", ++ self.__validate_server_hostname) + self.step("stopping smbd", self.__stop) + self.step("creating samba domain object", \ + self.__create_samba_domain_object) +-- +2.12.2 + diff --git a/SOURCES/0054-Allow-erasing-ipaDomainResolutionOrder-attribute.patch b/SOURCES/0054-Allow-erasing-ipaDomainResolutionOrder-attribute.patch new file mode 100644 index 0000000..2fe04fe --- /dev/null +++ b/SOURCES/0054-Allow-erasing-ipaDomainResolutionOrder-attribute.patch @@ -0,0 +1,42 @@ +From 5b9fe9df34d0eff697adefa171d35a57e561c17e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 28 Mar 2017 16:15:21 +0200 +Subject: [PATCH] Allow erasing ipaDomainResolutionOrder attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently when trying to erase the ipaDomainResolutionOrder attribute we +hit an internal error as the split() method is called on a None object. + +By returning early in case of empty string we now allow removing the +ipaDomainResolutionOrder attribute by both calling delattr or setting +its value to an empty string. + +https://pagure.io/freeipa/issue/6825 + +Signed-off-by: Fabiano Fidêncio +Reviewed-By: Martin Basti +--- + ipaserver/plugins/config.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py +index 232c88121fd2c938f77a1e76e1d7c9f0ad8e7550..b50e7a4691bd76bfaf7c332cd89b0f1bf55bac46 100644 +--- a/ipaserver/plugins/config.py ++++ b/ipaserver/plugins/config.py +@@ -359,6 +359,11 @@ class config(LDAPObject): + + domain_resolution_order = entry_attrs[attr_name] + ++ # setting up an empty string means that the previous configuration has ++ # to be cleaned up/removed. So, do nothing and let it pass ++ if not domain_resolution_order: ++ return ++ + # empty resolution order is signalized by single separator, do nothing + # and let it pass + if domain_resolution_order == DOMAIN_RESOLUTION_ORDER_SEPARATOR: +-- +2.12.2 + diff --git a/SOURCES/0054-ipa-backup-backup-etc-tmpfiles.d-dirsrv-instance-.co.patch b/SOURCES/0054-ipa-backup-backup-etc-tmpfiles.d-dirsrv-instance-.co.patch deleted file mode 100644 index f54e563..0000000 --- a/SOURCES/0054-ipa-backup-backup-etc-tmpfiles.d-dirsrv-instance-.co.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 7422ad189f90d596fcda93da97ae1cd152df4df3 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 5 Aug 2016 17:35:49 +0200 -Subject: [PATCH] ipa-backup: backup /etc/tmpfiles.d/dirsrv-.conf - -This file allows daemon tmpfiles.d to re-create the dirs in volatile -directories like /var/run or /var/lock. Without this file Dirsrv will -not start. - -https://fedorahosted.org/freeipa/ticket/6165 - -Reviewed-By: Petr Spacek ---- - ipaplatform/base/paths.py | 1 + - ipaserver/install/ipa_backup.py | 9 ++++++--- - 2 files changed, 7 insertions(+), 3 deletions(-) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index 9c8eaf951df89d373796be3f354bd3c51a329902..5ffe689950792a40c179533c8baf2794c2388696 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -132,6 +132,7 @@ class BasePathNamespace(object): - SYSTEMD_IPA_SERVICE = "/etc/systemd/system/multi-user.target.wants/ipa.service" - SYSTEMD_SSSD_SERVICE = "/etc/systemd/system/multi-user.target.wants/sssd.service" - SYSTEMD_PKI_TOMCAT_SERVICE = "/etc/systemd/system/pki-tomcatd.target.wants/pki-tomcatd@pki-tomcat.service" -+ ETC_TMPFILESD_DIRSRV = "/etc/tmpfiles.d/dirsrv-%s.conf" - DNSSEC_TRUSTED_KEY = "/etc/trusted-key.key" - HOME_DIR = "/home" - PROC_FIPS_ENABLED = "/proc/sys/crypto/fips_enabled" -diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py -index 18a60ecd13c7e7f5381b61ec70ea308a1931b7ec..9b09f4293028c3e560337ba082164b528cf76d80 100644 ---- a/ipaserver/install/ipa_backup.py -+++ b/ipaserver/install/ipa_backup.py -@@ -337,9 +337,12 @@ class Backup(admintool.AdminTool): - if os.path.exists(dir): - self.dirs.append(dir) - -- file = paths.SYSCONFIG_DIRSRV_INSTANCE % serverid -- if os.path.exists(file): -- self.files.append(file) -+ for file in ( -+ paths.SYSCONFIG_DIRSRV_INSTANCE % serverid, -+ paths.ETC_TMPFILESD_DIRSRV % serverid, -+ ): -+ if os.path.exists(file): -+ self.files.append(file) - - self.logs.append(paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % serverid) - --- -2.7.4 - diff --git a/SOURCES/0055-Always-check-and-create-anonymous-principal-during-K.patch b/SOURCES/0055-Always-check-and-create-anonymous-principal-during-K.patch new file mode 100644 index 0000000..4a67768 --- /dev/null +++ b/SOURCES/0055-Always-check-and-create-anonymous-principal-during-K.patch @@ -0,0 +1,70 @@ +From 6602dffc7ab8e9bdc7fefd02f9ed11e5575f5f7b Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 22 Mar 2017 16:41:59 +0100 +Subject: [PATCH] Always check and create anonymous principal during KDC + install + +The anonymous principal will now be checked for presence and created on +both server and replica install. This fixes errors caused during replica +installation against older master that do not have anonymous principal +present. + +https://pagure.io/freeipa/issue/6799 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/krbinstance.py | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 5f4b5282f54234c15b1a8d8273eff69e134e665b..6c105f74c8da2bfd34ace607b13170bc96a8ff1d 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -33,7 +33,7 @@ from ipaserver.install import installutils + from ipapython import ipaldap + from ipapython import ipautil + from ipapython import kernel_keyring +-from ipalib import api ++from ipalib import api, errors + from ipalib.constants import ANON_USER + from ipalib.install import certmonger + from ipapython.ipa_log_manager import root_logger +@@ -142,6 +142,7 @@ class KrbInstance(service.Service): + pass + + def __common_post_setup(self): ++ self.step("creating anonymous principal", self.add_anonymous_principal) + self.step("starting the KDC", self.__start_instance) + self.step("configuring KDC to start on boot", self.__enable) + +@@ -160,7 +161,6 @@ class KrbInstance(service.Service): + self.step("creating a keytab for the directory", self.__create_ds_keytab) + self.step("creating a keytab for the machine", self.__create_host_keytab) + self.step("adding the password extension to the directory", self.__add_pwd_extop_module) +- self.step("creating anonymous principal", self.add_anonymous_principal) + + self.__common_post_setup() + +@@ -432,8 +432,17 @@ class KrbInstance(service.Service): + def add_anonymous_principal(self): + # Create the special anonymous principal + princ_realm = self.get_anonymous_principal_name() +- installutils.kadmin_addprinc(princ_realm) +- self._ldap_mod("anon-princ-aci.ldif", self.sub_dict) ++ dn = DN(('krbprincipalname', princ_realm), self.get_realm_suffix()) ++ try: ++ self.api.Backend.ldap2.get_entry(dn) ++ except errors.NotFound: ++ installutils.kadmin_addprinc(princ_realm) ++ self._ldap_mod("anon-princ-aci.ldif", self.sub_dict) ++ ++ try: ++ self.api.Backend.ldap2.set_entry_active(dn, True) ++ except errors.AlreadyActive: ++ pass + + def __convert_to_gssapi_replication(self): + repl = replication.ReplicationManager(self.realm, +-- +2.12.2 + diff --git a/SOURCES/0055-client-RPM-require-initscripts-to-get-domainname.ser.patch b/SOURCES/0055-client-RPM-require-initscripts-to-get-domainname.ser.patch deleted file mode 100644 index a60ff94..0000000 --- a/SOURCES/0055-client-RPM-require-initscripts-to-get-domainname.ser.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 99105177385dbed1082db8676a1ff052e99e1eda Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 8 Aug 2016 13:13:18 +0200 -Subject: [PATCH] client: RPM require initscripts to get *-domainname.service - -https://fedorahosted.org/freeipa/ticket/4831 - -Reviewed-By: Jan Cholasta ---- - freeipa.spec.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 77fca24ef0e1e244e53d203a228931b4a444fb5a..29b63c9300b73d82aea88dbcf50f2f6ab5f9e9bd 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -324,6 +324,8 @@ Requires: krb5-workstation - Requires: authconfig - Requires: pam_krb5 - Requires: curl -+# NIS domain name config: /usr/lib/systemd/system/*-domainname.service -+Requires: initscripts - Requires: libcurl >= 7.21.7-2 - Requires: xmlrpc-c >= 1.27.4 - Requires: sssd >= 1.14.0 --- -2.7.4 - diff --git a/SOURCES/0056-Remove-duplicate-functionality-in-upgrade.patch b/SOURCES/0056-Remove-duplicate-functionality-in-upgrade.patch new file mode 100644 index 0000000..2b9d354 --- /dev/null +++ b/SOURCES/0056-Remove-duplicate-functionality-in-upgrade.patch @@ -0,0 +1,53 @@ +From dd300d7db884db2d0aa228c08d2447539ce14c1c Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 22 Mar 2017 16:52:14 +0100 +Subject: [PATCH] Remove duplicate functionality in upgrade + +Since krbinstance code can now handle all operations of the +`enabled_anonymous_principal` function from upgrade we can remove +extraneous function altogether. + +https://pagure.io/freeipa/issue/6799 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/server/upgrade.py | 16 +--------------- + 1 file changed, 1 insertion(+), 15 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 0db764cb80f6d0fb22f00719dadf1f921f97bf62..25b86297af3ae9d5f21cebb93f493b90670dcfc3 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1482,20 +1482,6 @@ def add_default_caacl(ca): + sysupgrade.set_upgrade_state('caacl', 'add_default_caacl', True) + + +-def enable_anonymous_principal(krb): +- princ_realm = krb.get_anonymous_principal_name() +- dn = DN(('krbprincipalname', princ_realm), krb.get_realm_suffix()) +- try: +- _ = api.Backend.ldap2.get_entry(dn) # pylint: disable=unused-variable +- except ipalib.errors.NotFound: +- krb.add_anonymous_principal() +- +- try: +- api.Backend.ldap2.set_entry_active(dn, True) +- except ipalib.errors.AlreadyActive: +- pass +- +- + def setup_pkinit(krb): + root_logger.info("[Setup PKINIT]") + +@@ -1809,7 +1795,7 @@ def upgrade_configuration(): + KDC_CERT=paths.KDC_CERT, + KDC_KEY=paths.KDC_KEY, + CACERT_PEM=paths.CACERT_PEM) +- enable_anonymous_principal(krb) ++ krb.add_anonymous_principal() + http.request_anon_keytab() + setup_pkinit(krb) + +-- +2.12.2 + diff --git a/SOURCES/0056-parameters-move-the-confirm-kwarg-to-Param.patch b/SOURCES/0056-parameters-move-the-confirm-kwarg-to-Param.patch deleted file mode 100644 index bc1a5cc..0000000 --- a/SOURCES/0056-parameters-move-the-confirm-kwarg-to-Param.patch +++ /dev/null @@ -1,89 +0,0 @@ -From c7b4c108ddd76d5ac02e2242a7eccb3acf3efce5 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 8 Aug 2016 13:09:39 +0200 -Subject: [PATCH] parameters: move the `confirm` kwarg to Param - -Whether a parameter is treated like password is determined by the -`password` class attribute defined in the Param class. Whether the CLI will -asks for confirmation of a password parameter depends on the value of the -`confirm` kwarg of the Password class. - -Move the `confirm` kwarg from the Password class to the Param class, so -that it can be used by any Param subclass which has the `password` class -attribute set to True. - -This fixes confirmation of the --key option of otptoken-add, which is a -Bytes subclass with `password` set to True. - -https://fedorahosted.org/freeipa/ticket/6174 - -Reviewed-By: Martin Basti -Reviewed-By: David Kupka ---- - ipaclient/remote_plugins/schema.py | 2 +- - ipalib/parameters.py | 6 ++---- - ipaserver/plugins/otptoken.py | 4 ---- - 3 files changed, 3 insertions(+), 9 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index cd1d5d607978899254325f634ccec91d2c92f59b..0301e54127dc236ebc14e1409484626f1427800d 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -155,7 +155,7 @@ class _SchemaPlugin(object): - elif key in ('cli_metavar', - 'cli_name'): - kwargs[key] = str(value) -- elif key == 'confirm' and issubclass(cls, Password): -+ elif key == 'confirm': - kwargs[key] = value - elif key == 'default': - default = value -diff --git a/ipalib/parameters.py b/ipalib/parameters.py -index 1581b7dcac5259e5c4a127e2a38e13335002b204..6917c8d4fc117b47bddc11fbf3ea379e3c537ea4 100644 ---- a/ipalib/parameters.py -+++ b/ipalib/parameters.py -@@ -377,6 +377,7 @@ class Param(ReadOnly): - parameter is not `required` - - sortorder: used to sort a list of parameters for Command. See - `Command.finalize()` for further information -+ - confirm: if password, ask for confirmation - """ - - # This is a dummy type so that most of the functionality of Param can be -@@ -418,6 +419,7 @@ class Param(ReadOnly): - ('cli_metavar', str, None), - ('no_convert', bool, False), - ('deprecated', bool, False), -+ ('confirm', bool, True), - - # The 'default' kwarg gets appended in Param.__init__(): - # ('default', self.type, None), -@@ -1511,10 +1513,6 @@ class Password(Str): - - password = True - -- kwargs = Str.kwargs + ( -- ('confirm', bool, True), -- ) -- - def _convert_scalar(self, value, index=None): - if isinstance(value, (tuple, list)) and len(value) == 2: - (p1, p2) = value -diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py -index 56b8c911b3492de9342946cd3e47681e99a5abef..39012e2f9106c33c520e19f14331fc440333015a 100644 ---- a/ipaserver/plugins/otptoken.py -+++ b/ipaserver/plugins/otptoken.py -@@ -79,10 +79,6 @@ class OTPTokenKey(Bytes): - - password = True - -- kwargs = Bytes.kwargs + ( -- ('confirm', bool, True), -- ) -- - def _convert_scalar(self, value, index=None): - if isinstance(value, (tuple, list)) and len(value) == 2: - (p1, p2) = value --- -2.7.4 - diff --git a/SOURCES/0057-Fix-the-order-of-cert-files-check.patch b/SOURCES/0057-Fix-the-order-of-cert-files-check.patch new file mode 100644 index 0000000..d1c9c42 --- /dev/null +++ b/SOURCES/0057-Fix-the-order-of-cert-files-check.patch @@ -0,0 +1,47 @@ +From 9bc2481d6669906e105e1035a10cd81374464e5b Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 22 Mar 2017 17:10:56 +0100 +Subject: [PATCH] Fix the order of cert-files check + +Without this patch, if either of dirsrv_cert_files, http_cert_files +or pkinit_cert_files is set along with no-pkinit, the user is first +requested to add the remaining options and when they do that, +they are told that they are using 'no-pkinit' along with +'pkinit-cert-file'. + +https://pagure.io/freeipa/issue/6801 + +Reviewed-By: Martin Basti +--- + ipaserver/install/server/__init__.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py +index 14f1ec48a1b8c7a520db69ffad378d488efa29cc..117f51c4ebfaeba51d3c85625cda0d0eee305696 100644 +--- a/ipaserver/install/server/__init__.py ++++ b/ipaserver/install/server/__init__.py +@@ -340,16 +340,16 @@ class ServerInstallInterface(ServerCertificateInstallInterface, + cert_file_opt = (self.pkinit_cert_files,) + if not self.no_pkinit: + cert_file_req += cert_file_opt +- if any(cert_file_req + cert_file_opt) and not all(cert_file_req): +- raise RuntimeError( +- "--dirsrv-cert-file, --http-cert-file, and --pkinit-cert-file " +- "or --no-pkinit are required if any key file options are used." +- ) + if self.no_pkinit and self.pkinit_cert_files: + raise RuntimeError( + "--no-pkinit and --pkinit-cert-file cannot be specified " + "together" + ) ++ if any(cert_file_req + cert_file_opt) and not all(cert_file_req): ++ raise RuntimeError( ++ "--dirsrv-cert-file, --http-cert-file, and --pkinit-cert-file " ++ "or --no-pkinit are required if any key file options are used." ++ ) + + if not self.interactive: + if self.dirsrv_cert_files and self.dirsrv_pin is None: +-- +2.12.2 + diff --git a/SOURCES/0057-client-add-missing-output-params-to-client-side-comm.patch b/SOURCES/0057-client-add-missing-output-params-to-client-side-comm.patch deleted file mode 100644 index c1bd136..0000000 --- a/SOURCES/0057-client-add-missing-output-params-to-client-side-comm.patch +++ /dev/null @@ -1,95 +0,0 @@ -From b654999d25de81e2c63b0765b6f16df2ff880144 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 10 Aug 2016 09:02:47 +0200 -Subject: [PATCH] client: add missing output params to client-side commands - -Add output params for the otptoken-add-yubikey, vault-add, vault-mod, -vault-archive and vault-retrieve commands. - -This fixes the commands not having any output in CLI. - -https://fedorahosted.org/freeipa/ticket/6182 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: David Kupka ---- - ipaclient/plugins/otptoken_yubikey.py | 6 ++++++ - ipaclient/plugins/vault.py | 24 ++++++++++++++++++++++++ - 2 files changed, 30 insertions(+) - -diff --git a/ipaclient/plugins/otptoken_yubikey.py b/ipaclient/plugins/otptoken_yubikey.py -index 423b670de15dd7f803db1dcbb759bd0254827072..3c310eacbaeef654e43049db78437c8c29f52279 100644 ---- a/ipaclient/plugins/otptoken_yubikey.py -+++ b/ipaclient/plugins/otptoken_yubikey.py -@@ -103,6 +103,12 @@ class otptoken_add_yubikey(Command): - for option in super(otptoken_add_yubikey, self).get_options(): - yield option - -+ def get_output_params(self): -+ for param in self.api.Command.otptoken_add.output_params(): -+ yield param -+ for param in super(otptoken_add_yubikey, self).get_output_params(): -+ yield param -+ - def _iter_output(self): - return self.api.Command.otptoken_add.output() - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index 9026cbb0829a7557584df27a4262dfde640b4f28..3e116bbad54fea419b571d1f09c1b00280e94991 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -220,6 +220,12 @@ class vault_add(Local): - for option in super(vault_add, self).get_options(): - yield option - -+ def get_output_params(self): -+ for param in self.api.Command.vault_add_internal.output_params(): -+ yield param -+ for param in super(vault_add, self).get_output_params(): -+ yield param -+ - def _iter_output(self): - return self.api.Command.vault_add_internal.output() - -@@ -418,6 +424,12 @@ class vault_mod(Local): - for option in super(vault_mod, self).get_options(): - yield option - -+ def get_output_params(self): -+ for param in self.api.Command.vault_mod_internal.output_params(): -+ yield param -+ for param in super(vault_mod, self).get_output_params(): -+ yield param -+ - def _iter_output(self): - return self.api.Command.vault_mod_internal.output() - -@@ -600,6 +612,12 @@ class vault_archive(Local): - for option in super(vault_archive, self).get_options(): - yield option - -+ def get_output_params(self): -+ for param in self.api.Command.vault_archive_internal.output_params(): -+ yield param -+ for param in super(vault_archive, self).get_output_params(): -+ yield param -+ - def _iter_output(self): - return self.api.Command.vault_archive_internal.output() - -@@ -846,6 +864,12 @@ class vault_retrieve(Local): - for option in super(vault_retrieve, self).get_options(): - yield option - -+ def get_output_params(self): -+ for param in self.api.Command.vault_retrieve_internal.output_params(): -+ yield param -+ for param in super(vault_retrieve, self).get_output_params(): -+ yield param -+ - def _iter_output(self): - return self.api.Command.vault_retrieve_internal.output() - --- -2.7.4 - diff --git a/SOURCES/0058-Don-t-allow-setting-pkinit-related-options-on-DL0.patch b/SOURCES/0058-Don-t-allow-setting-pkinit-related-options-on-DL0.patch new file mode 100644 index 0000000..1675a78 --- /dev/null +++ b/SOURCES/0058-Don-t-allow-setting-pkinit-related-options-on-DL0.patch @@ -0,0 +1,95 @@ +From 60b57639295ab94949986ec59de3c8e6c92bee7d Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 22 Mar 2017 17:26:51 +0100 +Subject: [PATCH] Don't allow setting pkinit-related options on DL0 + +pkinit is not supported on DL0, remove options that allow to set it +from ipa-{server,replica}-install. + +https://pagure.io/freeipa/issue/6801 + +Reviewed-By: Martin Basti +--- + install/tools/man/ipa-replica-install.1 | 2 +- + install/tools/man/ipa-server-install.1 | 2 +- + ipaserver/install/server/__init__.py | 21 +++++++++++++++++++++ + 3 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 +index d63912c7018bd09a8567688a1f8d4db0c698ac3f..7d241324818dd3a5294da5e84b67a19d0d9a31b6 100644 +--- a/install/tools/man/ipa-replica-install.1 ++++ b/install/tools/man/ipa-replica-install.1 +@@ -114,7 +114,7 @@ Install and configure a CA on this replica. If a CA is not configured then + certificate operations will be forwarded to a master with a CA installed. + .TP + \fB\-\-no\-pkinit\fR +-Disables pkinit setup steps ++Disables pkinit setup steps. This is the default and only allowed behavior on domain level 0. + .TP + \fB\-\-dirsrv\-cert\-file\fR=FILE + File containing the Directory Server SSL certificate and private key +diff --git a/install/tools/man/ipa-server-install.1 b/install/tools/man/ipa-server-install.1 +index c48bdae7485a34d72381188191d6423ca2d16044..d5d28df8e72295296a9ac321623ead49fe4692a3 100644 +--- a/install/tools/man/ipa-server-install.1 ++++ b/install/tools/man/ipa-server-install.1 +@@ -93,7 +93,7 @@ Type of the external CA. Possible values are "generic", "ms-cs". Default value i + 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 ++Disables pkinit setup steps. This is the default and only allowed behavior on domain level 0. + .TP + \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. +diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py +index 117f51c4ebfaeba51d3c85625cda0d0eee305696..096cb0142fc7fe70fdc3d2ad1e5caedf0f65b643 100644 +--- a/ipaserver/install/server/__init__.py ++++ b/ipaserver/install/server/__init__.py +@@ -332,9 +332,24 @@ class ServerInstallInterface(ServerCertificateInstallInterface, + if not os.path.exists(value): + raise ValueError("File %s does not exist." % value) + ++ def _is_promote(self): ++ """ ++ :returns: True if domain level options correspond to domain level > 0 ++ """ ++ raise NotImplementedError() ++ + def __init__(self, **kwargs): + super(ServerInstallInterface, self).__init__(**kwargs) + ++ # pkinit is not supported on DL0, don't allow related options ++ if not self._is_promote(): ++ if (self.no_pkinit or self.pkinit_cert_files is not None or ++ self.pkinit_pin is not None): ++ raise RuntimeError( ++ "pkinit on domain level 0 is not supported. Please " ++ "don't use any pkinit-related options.") ++ self.no_pkinit = True ++ + # If any of the key file options are selected, all are required. + cert_file_req = (self.dirsrv_cert_files, self.http_cert_files) + cert_file_opt = (self.pkinit_cert_files,) +@@ -557,6 +572,9 @@ class ServerMasterInstall(ServerMasterInstallInterface): + add_sids = True + add_agents = False + ++ def _is_promote(self): ++ return self.domain_level > constants.DOMAIN_LEVEL_0 ++ + def __init__(self, **kwargs): + super(ServerMasterInstall, self).__init__(**kwargs) + master_init(self) +@@ -590,6 +608,9 @@ class ServerReplicaInstall(ServerReplicaInstallInterface): + description="Kerberos password for the specified admin principal", + ) + ++ def _is_promote(self): ++ return self.replica_file is None ++ + def __init__(self, **kwargs): + super(ServerReplicaInstall, self).__init__(**kwargs) + replica_init(self) +-- +2.12.2 + diff --git a/SOURCES/0058-server-install-Fix-hostname-option-to-always-overrid.patch b/SOURCES/0058-server-install-Fix-hostname-option-to-always-overrid.patch deleted file mode 100644 index 4267f9f..0000000 --- a/SOURCES/0058-server-install-Fix-hostname-option-to-always-overrid.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 09b5f9fc0e75886917aae014c2bb0c5bd67d3c4c Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Tue, 12 Jul 2016 17:42:40 +0200 -Subject: [PATCH] server-install: Fix --hostname option to always override - api.env values - -Attempts to compare local hostname with user-provided values are error -prone as we found out in #5794. This patch removes comparison and makes -the env values deterministic. - -https://fedorahosted.org/freeipa/ticket/6071 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/server/install.py | 13 +++++-------- - 1 file changed, 5 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 65f9318201e648b30a3c13626e807ac6f3a9416d..1e925595b93ff95a98b3e6c3d0c357b1766dc1dc 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -560,7 +560,12 @@ def install_check(installer): - cfg = dict( - context='installer', - in_server=True, -+ # make sure host name specified by user is used instead of default -+ host=host_name, - ) -+ if setup_ca: -+ # we have an IPA-integrated CA -+ cfg['ca_host'] = host_name - - # Create the management framework config file and finalize api - target_fname = paths.IPA_DEFAULT_CONF -@@ -586,14 +591,6 @@ def install_check(installer): - # Must be readable for everyone - os.chmod(target_fname, 0o644) - -- system_hostname = get_fqdn() -- if host_name != system_hostname: -- root_logger.debug("Chosen hostname (%s) differs from system hostname " -- "(%s) - change it" % (host_name, system_hostname)) -- # update `api.env.ca_host` to correct hostname -- # https://fedorahosted.org/freeipa/ticket/4936 -- api.env.ca_host = host_name -- - api.bootstrap(**cfg) - api.finalize() - --- -2.7.4 - diff --git a/SOURCES/0059-install-Call-hostnamectl-set-hostname-only-if-hostna.patch b/SOURCES/0059-install-Call-hostnamectl-set-hostname-only-if-hostna.patch deleted file mode 100644 index 2154c99..0000000 --- a/SOURCES/0059-install-Call-hostnamectl-set-hostname-only-if-hostna.patch +++ /dev/null @@ -1,148 +0,0 @@ -From fa252eac5db87020c7f4ecd3646a25bb7cafd27c Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 28 Jul 2016 16:13:55 +0200 -Subject: [PATCH] install: Call hostnamectl set-hostname only if --hostname - option is used - -This commit also splits hostname backup and configuration into two separate -functions. This allows us to backup hostname without setting it at the -same time. - -https://fedorahosted.org/freeipa/ticket/6071 - -Reviewed-By: Jan Cholasta ---- - client/ipa-client-install | 3 ++- - doc/guide/guide.org | 10 +++++----- - ipaplatform/base/tasks.py | 7 ++----- - ipaplatform/redhat/tasks.py | 13 ++----------- - ipaserver/install/server/install.py | 10 +++++----- - 5 files changed, 16 insertions(+), 27 deletions(-) - -diff --git a/client/ipa-client-install b/client/ipa-client-install -index 45185d44feb43a8b8d30e412a26dd63121be4ad1..db2037b8372644f997de498dcf3b99edcf3abb56 100755 ---- a/client/ipa-client-install -+++ b/client/ipa-client-install -@@ -2525,7 +2525,8 @@ def install(options, env, fstore, statestore): - if options.hostname and not options.on_master: - # skip this step when run by ipa-server-install as it always configures - # hostname -- tasks.backup_and_replace_hostname(fstore, statestore, options.hostname) -+ tasks.backup_hostname(fstore, statestore) -+ tasks.set_hostname(options.hostname) - - ntp_srv_servers = [] - if not options.on_master and options.conf_ntp: -diff --git a/doc/guide/guide.org b/doc/guide/guide.org -index 6d181559f0af90e7be7089aa94ab4900fa4e90b5..2e852a964991781ef5dd7b93ac481891897e1ed0 100644 ---- a/doc/guide/guide.org -+++ b/doc/guide/guide.org -@@ -1039,14 +1039,14 @@ def restore_context_default(filepath): - # version in platform services - restore_context = restore_context_default - --# Default implementation of backup and replace hostname that does nothing --def backup_and_replace_hostname_default(fstore, statestore, hostname): -+# Default implementation of backup hostname that does nothing -+def backup_hostname_default(fstore, statestore): - return - --# Backup and replace system's hostname --# Since many platforms have their own way how to store system's hostname, this method must be -+# Backup system's hostname -+# Since many platforms have their own way of handling system's hostname, this method must be - # implemented in platform services --backup_and_replace_hostname = backup_and_replace_hostname_default -+backup_hostname = backup_hostname_default - - from ipapython.platform.SUPPORTED_PLATFORM import * - #+END_SRC -diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py -index c6860ce47ad3d043f1561a690c401537f5e2fdb7..1e687b6181fcff20303b50ac18bfde66280f8bfd 100644 ---- a/ipaplatform/base/tasks.py -+++ b/ipaplatform/base/tasks.py -@@ -45,14 +45,11 @@ class BaseTaskNamespace(object): - - raise NotImplementedError() - -- def backup_and_replace_hostname(self, fstore, statestore, hostname): -+ def backup_hostname(self, fstore, statestore): - """ - Backs up the current hostname in the statestore (so that it can be - restored by the restore_hostname platform task). - -- Makes sure that new hostname (passed via hostname argument) is set -- as a new pemanent hostname for this host. -- - No return value expected. - """ - -@@ -109,7 +106,7 @@ class BaseTaskNamespace(object): - def restore_hostname(self, fstore, statestore): - """ - Restores the original hostname as backed up in the -- backup_and_replace_hostname platform task. -+ backup_hostname platform task. - """ - - raise NotImplementedError() -diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py -index 8ac88511e94d640f077c7a0e202bc545ec8bcbbe..dbe005abb0ecbcb398368789fee52895c6d6e980 100644 ---- a/ipaplatform/redhat/tasks.py -+++ b/ipaplatform/redhat/tasks.py -@@ -332,22 +332,13 @@ class RedHatTaskNamespace(BaseTaskNamespace): - - return result - -- def backup_and_replace_hostname(self, fstore, statestore, hostname): -- old_hostname = socket.gethostname() -- try: -- self.set_hostname(hostname) -- except ipautil.CalledProcessError as e: -- root_logger.debug(traceback.format_exc()) -- root_logger.error( -- "Failed to set this machine hostname to %s (%s).", -- old_hostname, e -- ) -- -+ def backup_hostname(self, fstore, statestore): - filepath = paths.ETC_HOSTNAME - if os.path.exists(filepath): - fstore.backup_file(filepath) - - # store old hostname -+ old_hostname = socket.gethostname() - statestore.backup_state('network', 'hostname', old_hostname) - - def restore_hostname(self, fstore, statestore): -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 1e925595b93ff95a98b3e6c3d0c357b1766dc1dc..94698898934844350488d5fc52d6e1e567624502 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -651,6 +651,7 @@ def install_check(installer): - options.dm_password = dm_password - options.master_password = master_password - options.admin_password = admin_password -+ options._host_name_overridden = bool(options.host_name) - options.host_name = host_name - options.ip_addresses = ip_addresses - -@@ -702,11 +703,10 @@ def install(installer): - print("Please wait until the prompt is returned.") - print("") - -- # configure /etc/sysconfig/network to contain the custom hostname -- tasks.backup_and_replace_hostname(fstore, sstore, host_name) -- -- # set hostname (we need both transient and static) -- tasks.set_hostname(host_name) -+ # set hostname (transient and static) if user instructed us to do so -+ if options._host_name_overridden: -+ tasks.backup_hostname(fstore, sstore) -+ tasks.set_hostname(host_name) - - if installer._update_hosts_file: - update_hosts_file(ip_addresses, host_name, fstore) --- -2.7.4 - diff --git a/SOURCES/0059-replica-prepare-man-remove-pkinit-option-refs.patch b/SOURCES/0059-replica-prepare-man-remove-pkinit-option-refs.patch new file mode 100644 index 0000000..ac24ad6 --- /dev/null +++ b/SOURCES/0059-replica-prepare-man-remove-pkinit-option-refs.patch @@ -0,0 +1,60 @@ +From a0b479ef9f9be97cc170734c0af5330d9fd702ce Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 24 Mar 2017 12:29:53 +0100 +Subject: [PATCH] replica-prepare man: remove pkinit option refs + +Remove the references to the pkinit options which was forgotten +about in 46d4d534c0 + +https://pagure.io/freeipa/issue/6801 + +Reviewed-By: Martin Basti +--- + install/tools/man/ipa-replica-prepare.1 | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/install/tools/man/ipa-replica-prepare.1 b/install/tools/man/ipa-replica-prepare.1 +index 2063657f8eb4e97fc11b1abb95a892e26b4344e6..afc5408ef87ec5cf967d00dd21aa848584c7eb1e 100644 +--- a/install/tools/man/ipa-replica-prepare.1 ++++ b/install/tools/man/ipa-replica-prepare.1 +@@ -43,27 +43,18 @@ File containing the Directory Server SSL certificate and private key. The files + \fB\-\-http\-cert\-file\fR=\fIFILE\fR + File containing the Apache Server SSL certificate and private key. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. This option may be used multiple times. + .TP +-\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=\fIPIN\fR + The password to unlock the Directory Server private key + .TP + \fB\-\-http\-pin\fR=\fIPIN\fR + The password to unlock the Apache Server private key + .TP +-\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 +@@ -81,9 +72,6 @@ Do not create reverse DNS zone + \fB\-\-ca\fR=\fICA_FILE\fR + Location of CA PKCS#12 file, default /root/cacert.p12 + .TP +-\fB\-\-no\-pkinit\fR +-Disables pkinit setup steps +-.TP + \fB\-\-debug\fR + Prints info log messages to the output + .SH "EXIT STATUS" +-- +2.12.2 + diff --git a/SOURCES/0060-Remove-redundant-option-check-for-cert-files.patch b/SOURCES/0060-Remove-redundant-option-check-for-cert-files.patch new file mode 100644 index 0000000..09e8115 --- /dev/null +++ b/SOURCES/0060-Remove-redundant-option-check-for-cert-files.patch @@ -0,0 +1,41 @@ +From abb400e3fbb7c607b6ec40cfd155aa14175d35d7 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 29 Mar 2017 09:00:09 +0200 +Subject: [PATCH] Remove redundant option check for cert files + +There was a redundant check for CA-less install certificate files +for replicas but the same check is done for all installers before +that. + +https://pagure.io/freeipa/issue/6801 + +Reviewed-By: Martin Basti +--- + ipaserver/install/server/__init__.py | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py +index 096cb0142fc7fe70fdc3d2ad1e5caedf0f65b643..89444f21fefc902931b7ecfaba861a18ecc28dbe 100644 +--- a/ipaserver/install/server/__init__.py ++++ b/ipaserver/install/server/__init__.py +@@ -470,16 +470,8 @@ class ServerInstallInterface(ServerCertificateInstallInterface, + "idmax (%s) cannot be smaller than idstart (%s)" % + (self.idmax, self.idstart)) + else: +- cert_file_req = (self.dirsrv_cert_files, self.http_cert_files) +- cert_file_opt = (self.pkinit_cert_files,) +- ++ # replica installers + if self.replica_file is None: +- # If any of the PKCS#12 options are selected, all are required. +- if any(cert_file_req + cert_file_opt) and not all(cert_file_req): +- raise RuntimeError( +- "--dirsrv-cert-file and --http-cert-file are required " +- "if any PKCS#12 options are used") +- + if self.servers and not self.domain_name: + raise RuntimeError( + "The --server option cannot be used without providing " +-- +2.12.2 + diff --git a/SOURCES/0060-schema-Speed-up-schema-cache.patch b/SOURCES/0060-schema-Speed-up-schema-cache.patch deleted file mode 100644 index 7c7d189..0000000 --- a/SOURCES/0060-schema-Speed-up-schema-cache.patch +++ /dev/null @@ -1,415 +0,0 @@ -From beff42632d1db674802c817afd49a3ac8bcd8fb6 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 27 Jul 2016 10:46:40 +0200 -Subject: [PATCH] schema: Speed up schema cache - -Check presence of schema in cache (and download it if necessary) on -__init__ instead of with each __getitem__ call. Prefill internal -dictionary with empty record for each command to be able to quickly -determine if requested command exist in schema or not. Rest of schema -data are read from cache on first attempt to retrive them. - -https://fedorahosted.org/freeipa/ticket/6048 -https://fedorahosted.org/freeipa/ticket/6069 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 301 ++++++++++++++++++++++--------------- - 1 file changed, 177 insertions(+), 124 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index 0301e54127dc236ebc14e1409484626f1427800d..d039fb41991c26a9c7b7f76f6959668efb677586 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -5,10 +5,8 @@ - import collections - import errno - import fcntl --import glob - import json - import os --import re - import sys - import time - import types -@@ -65,8 +63,6 @@ USER_CACHE_PATH = ( - '.cache' - ) - ) --SCHEMA_DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema') --SERVERS_DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'servers') - - logger = log_mgr.get_logger(__name__) - -@@ -274,15 +270,6 @@ class _SchemaObjectPlugin(_SchemaPlugin): - schema_key = 'classes' - - --def _ensure_dir_created(d): -- try: -- os.makedirs(d) -- except OSError as e: -- if e.errno != errno.EEXIST: -- raise RuntimeError("Unable to create cache directory: {}" -- "".format(e)) -- -- - class _LockedZipFile(zipfile.ZipFile): - """ Add locking to zipfile.ZipFile - Shared lock is used with read mode, exclusive with write mode. -@@ -308,7 +295,10 @@ class _SchemaNameSpace(collections.Mapping): - self._schema = schema - - def __getitem__(self, key): -- return self._schema.read_namespace_member(self.name, key) -+ try: -+ return self._schema.read_namespace_member(self.name, key) -+ except KeyError: -+ raise KeyError(key) - - def __iter__(self): - for key in self._schema.iter_namespace(self.name): -@@ -322,6 +312,62 @@ class NotAvailable(Exception): - pass - - -+class ServerInfo(collections.MutableMapping): -+ _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'servers') -+ -+ def __init__(self, api): -+ hostname = DNSName(api.env.server).ToASCII() -+ self._path = os.path.join(self._DIR, hostname) -+ self._dict = {} -+ self._dirty = False -+ -+ self._read() -+ -+ def __enter__(self): -+ return self -+ -+ def __exit__(self, *_exc_info): -+ if self._dirty: -+ self._write() -+ -+ def _read(self): -+ try: -+ with open(self._path, 'r') as sc: -+ self._dict = json.load(sc) -+ except EnvironmentError as e: -+ if e.errno != errno.ENOENT: -+ logger.warning('Failed to read server info: {}'.format(e)) -+ -+ def _write(self): -+ try: -+ try: -+ os.makedirs(self._DIR) -+ except EnvironmentError as e: -+ if e.errno != errno.EEXIST: -+ raise -+ with open(self._path, 'w') as sc: -+ json.dump(self._dict, sc) -+ except EnvironmentError as e: -+ logger.warning('Failed to write server info: {}'.format(e)) -+ -+ def __getitem__(self, key): -+ return self._dict[key] -+ -+ def __setitem__(self, key, value): -+ self._dirty = key not in self._dict or self._dict[key] != value -+ self._dict[key] = value -+ -+ def __delitem__(self, key): -+ del self._dict[key] -+ self._dirty = True -+ -+ def __iter__(self): -+ return iter(self._dict) -+ -+ def __len__(self): -+ return len(self._dict) -+ -+ - class Schema(object): - """ - Store and provide schema for commands and topics -@@ -342,38 +388,76 @@ class Schema(object): - u'Ping the remote IPA server to ...' - - """ -- schema_path_template = os.path.join(SCHEMA_DIR, '{}') -- servers_path_template = os.path.join(SERVERS_DIR, '{}') -- ns_member_pattern_template = '^{}/(?P.+)$' -- ns_member_path_template = '{}/{}' - namespaces = {'classes', 'commands', 'topics'} - schema_info_path = 'schema' -+ _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema') - -- @classmethod -- def _list(cls): -- for f in glob.glob(cls.schema_path_template.format('*')): -- yield os.path.splitext(os.path.basename(f))[0] -+ def __init__(self, api, server_info, client): -+ self._dict = {} -+ self._namespaces = {} -+ self._help = None - -- @classmethod -- def _in_cache(cls, fingeprint): -- return os.path.exists(cls.schema_path_template.format(fingeprint)) -+ for ns in self.namespaces: -+ self._dict[ns] = {} -+ self._namespaces[ns] = _SchemaNameSpace(self, ns) - -- def __init__(self, api, client): -- self._api = api -- self._client = client -- self._dict = {} -+ is_known = False -+ if not api.env.force_schema_check: -+ try: -+ self._fingerprint = server_info['fingerprint'] -+ self._expiration = server_info['expiration'] -+ except KeyError: -+ pass -+ else: -+ is_known = True -+ -+ if is_known: -+ try: -+ self._read_schema() -+ except Exception: -+ pass -+ else: -+ return - -- def _open_server_info(self, hostname, mode): -- encoded_hostname = DNSName(hostname).ToASCII() -- path = self.servers_path_template.format(encoded_hostname) -- return open(path, mode) -+ try: -+ self._fetch(client) -+ except NotAvailable: -+ raise -+ else: -+ self._write_schema() -+ finally: -+ try: -+ server_info['fingerprint'] = self._fingerprint -+ server_info['expiration'] = self._expiration -+ except AttributeError: -+ pass - -- def _get_schema(self): -- client = self._client -+ def _open_schema(self, filename, mode): -+ path = os.path.join(self._DIR, filename) -+ return _LockedZipFile(path, mode) -+ -+ def _get_schema_fingerprint(self, schema): -+ schema_info = json.loads(schema.read(self.schema_info_path)) -+ return schema_info['fingerprint'] -+ -+ def _fetch(self, client): - if not client.isconnected(): - client.connect(verbose=False) - -- fps = [unicode(f) for f in Schema._list()] -+ fps = [] -+ try: -+ files = os.listdir(self._DIR) -+ except EnvironmentError: -+ pass -+ else: -+ for filename in files: -+ try: -+ with self._open_schema(filename, 'r') as schema: -+ fps.append( -+ unicode(self._get_schema_fingerprint(schema))) -+ except Exception: -+ continue -+ - kwargs = {u'version': u'2.170'} - if fps: - kwargs[u'known_fingerprints'] = fps -@@ -386,110 +470,80 @@ class Schema(object): - ttl = e.ttl - else: - fp = schema['fingerprint'] -- ttl = schema['ttl'] -- self._store(fp, schema) -- finally: -- client.disconnect() -+ ttl = schema.pop('ttl', 0) - -- exp = ttl + time.time() -- return (fp, exp) -+ for key, value in schema.items(): -+ if key in self.namespaces: -+ value = {m['full_name']: m for m in value} -+ self._dict[key] = value - -- def _ensure_cached(self): -- no_info = False -- try: -- # pylint: disable=access-member-before-definition -- fp = self._server_schema_fingerprint -- exp = self._server_schema_expiration -- except AttributeError: -- try: -- with self._open_server_info(self._api.env.server, 'r') as sc: -- si = json.load(sc) -- -- fp = si['fingerprint'] -- exp = si['expiration'] -- except Exception as e: -- no_info = True -- if not (isinstance(e, EnvironmentError) and -- e.errno == errno.ENOENT): # pylint: disable=no-member -- logger.warning('Failed to load server properties: {}' -- ''.format(e)) -- -- force_check = ((not getattr(self, '_schema_checked', False)) and -- self._api.env.force_schema_check) -- -- if (force_check or -- no_info or exp < time.time() or not Schema._in_cache(fp)): -- (fp, exp) = self._get_schema() -- self._schema_checked = True -- _ensure_dir_created(SERVERS_DIR) -- try: -- with self._open_server_info(self._api.env.server, 'w') as sc: -- json.dump(dict(fingerprint=fp, expiration=exp), sc) -- except Exception as e: -- logger.warning('Failed to store server properties: {}' -- ''.format(e)) -- -- if not self._dict: -- self._dict['fingerprint'] = fp -- schema_info = self._read(self.schema_info_path) -+ self._fingerprint = fp -+ self._expiration = ttl + time.time() -+ -+ def _read_schema(self): -+ with self._open_schema(self._fingerprint, 'r') as schema: -+ self._dict['fingerprint'] = self._get_schema_fingerprint(schema) -+ schema_info = json.loads(schema.read(self.schema_info_path)) - self._dict['version'] = schema_info['version'] -- for ns in self.namespaces: -- self._dict[ns] = _SchemaNameSpace(self, ns) - -- self._server_schema_fingerprintr = fp -- self._server_schema_expiration = exp -+ for name in schema.namelist(): -+ ns, _slash, key = name.partition('/') -+ if ns in self.namespaces: -+ self._dict[ns][key] = {} - - def __getitem__(self, key): -- self._ensure_cached() -- return self._dict[key] -+ try: -+ return self._namespaces[key] -+ except KeyError: -+ return self._dict[key] - -- def _open_archive(self, mode, fp=None): -- if not fp: -- fp = self['fingerprint'] -- arch_path = self.schema_path_template.format(fp) -- return _LockedZipFile(arch_path, mode) -- -- def _store(self, fingerprint, schema={}): -- _ensure_dir_created(SCHEMA_DIR) -- -- schema_info = dict(version=schema['version'], -- fingerprint=schema['fingerprint']) -- -- with self._open_archive('w', fingerprint) as zf: -- # store schema information -- zf.writestr(self.schema_info_path, json.dumps(schema_info)) -- # store namespaces -- for namespace in self.namespaces: -- for member in schema[namespace]: -- path = self.ns_member_path_template.format( -- namespace, -- member['full_name'] -- ) -- zf.writestr(path, json.dumps(member)) -+ def _write_schema(self): -+ try: -+ os.makedirs(self._DIR) -+ except EnvironmentError as e: -+ if e.errno != errno.EEXIST: -+ logger.warning("Failed ti write schema: {}".format(e)) -+ return -+ -+ with self._open_schema(self._fingerprint, 'w') as schema: -+ schema_info = {} -+ for key, value in self._dict.items(): -+ if key in self.namespaces: -+ ns = value -+ for member in ns: -+ path = '{}/{}'.format(key, member) -+ schema.writestr(path, json.dumps(ns[member])) -+ else: -+ schema_info[key] = value -+ -+ schema.writestr(self.schema_info_path, json.dumps(schema_info)) - - def _read(self, path): -- with self._open_archive('r') as zf: -+ with self._open_schema(self._fingerprint, 'r') as zf: - return json.loads(zf.read(path)) - - def read_namespace_member(self, namespace, member): -- path = self.ns_member_path_template.format(namespace, member) -- return self._read(path) -+ value = self._dict[namespace][member] -+ -+ if (not value) or ('full_name' not in value): -+ path = '{}/{}'.format(namespace, member) -+ value = self._dict[namespace].setdefault( -+ member, {} -+ ).update(self._read(path)) -+ -+ return value - - def iter_namespace(self, namespace): -- pattern = self.ns_member_pattern_template.format(namespace) -- with self._open_archive('r') as zf: -- for name in zf.namelist(): -- r = re.match(pattern, name) -- if r: -- yield r.groups('name')[0] -+ return iter(self._dict[namespace]) - - - def get_package(api, client): - try: - schema = api._schema - except AttributeError: -- schema = Schema(api, client) -- object.__setattr__(api, '_schema', schema) -+ with ServerInfo(api.env.hostname) as server_info: -+ schema = Schema(api, server_info, client) -+ object.__setattr__(api, '_schema', schema) - - fingerprint = str(schema['fingerprint']) - package_name = '{}${}'.format(__name__, fingerprint) -@@ -509,10 +563,9 @@ def get_package(api, client): - module = types.ModuleType(module_name) - module.__file__ = os.path.join(package_dir, 'plugins.py') - module.register = plugable.Registry() -- for key, plugin_cls in (('commands', _SchemaCommandPlugin), -- ('classes', _SchemaObjectPlugin)): -- for full_name in schema[key]: -- plugin = plugin_cls(full_name) -+ for plugin_cls in (_SchemaCommandPlugin, _SchemaObjectPlugin): -+ for full_name in schema[plugin_cls.schema_key]: -+ plugin = plugin_cls(str(full_name)) - plugin = module.register()(plugin) - sys.modules[module_name] = module - --- -2.7.4 - diff --git a/SOURCES/0061-Hide-request_type-doc-string-in-cert-request-help.patch b/SOURCES/0061-Hide-request_type-doc-string-in-cert-request-help.patch new file mode 100644 index 0000000..75c7a38 --- /dev/null +++ b/SOURCES/0061-Hide-request_type-doc-string-in-cert-request-help.patch @@ -0,0 +1,34 @@ +From 9a6731643f1b0e3c47df13866109323ddd4c5db0 Mon Sep 17 00:00:00 2001 +From: Abhijeet Kasurde +Date: Sat, 18 Feb 2017 16:31:07 +0530 +Subject: [PATCH] Hide request_type doc string in cert-request help + +Fix hides description of request_type argument in cert-request +command help + +Fixes https://pagure.io/freeipa/issue/6494 +Fixes https://pagure.io/freeipa/issue/5734 + +Signed-off-by: Abhijeet Kasurde +Reviewed-By: Martin Basti +Reviewed-By: Fraser Tweedale +--- + ipaserver/plugins/cert.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index 1a6d04533cebb2eb00022981dae9ffe5b785ba8b..dfc7444ddbf31ac3c194e050af28220fc2a87a92 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -491,7 +491,7 @@ class certreq(BaseCertObject): + 'request_type', + default=u'pkcs10', + autofill=True, +- flags={'no_update', 'no_update', 'no_search'}, ++ flags={'no_option', 'no_update', 'no_update', 'no_search'}, + ), + Str( + 'profile_id?', validate_profile_id, +-- +2.12.2 + diff --git a/SOURCES/0061-frontend-Change-doc-summary-topic-and-NO_CLI-to-clas.patch b/SOURCES/0061-frontend-Change-doc-summary-topic-and-NO_CLI-to-clas.patch deleted file mode 100644 index f27bd62..0000000 --- a/SOURCES/0061-frontend-Change-doc-summary-topic-and-NO_CLI-to-clas.patch +++ /dev/null @@ -1,378 +0,0 @@ -From 8293d36c504b59a6dac46187baf51719ab355fd2 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 20 Jul 2016 13:23:33 +0200 -Subject: [PATCH] frontend: Change doc, summary, topic and NO_CLI to class - properties - -Avoid need to instantiate all commands just to get information for -displaying help. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/frontend.py | 32 ++++++++++++++------- - ipaclient/plugins/automount.py | 9 ++++-- - ipaclient/plugins/otptoken_yubikey.py | 11 +++++--- - ipaclient/plugins/vault.py | 35 ++++++++++++++--------- - ipaclient/remote_plugins/schema.py | 53 +++++++++++++++++++++++++++++++---- - ipalib/frontend.py | 10 ++++--- - ipalib/plugable.py | 17 ++++++----- - 7 files changed, 120 insertions(+), 47 deletions(-) - -diff --git a/ipaclient/frontend.py b/ipaclient/frontend.py -index 1525c88b3dfeadccd8115cb4b6ba149caef22103..aeaed550771d3c6af04a9b34fcae414faacb47d7 100644 ---- a/ipaclient/frontend.py -+++ b/ipaclient/frontend.py -@@ -2,9 +2,11 @@ - # Copyright (C) 2016 FreeIPA Contributors see COPYING for license - # - -+from ipalib import api - from ipalib.frontend import Command, Method - from ipalib.parameters import Str - from ipalib.text import _ -+from ipalib.util import classproperty - - - class ClientCommand(Command): -@@ -111,20 +113,30 @@ class CommandOverride(Command): - def __init__(self, api): - super(CommandOverride, self).__init__(api) - -- next_class = api.get_plugin_next(type(self)) -+ next_class = self.__get_next() - self.next = next_class(api) - -- @property -- def doc(self): -- return self.next.doc -+ @classmethod -+ def __get_next(cls): -+ return api.get_plugin_next(cls) - -- @property -- def NO_CLI(self): -- return self.next.NO_CLI -+ @classmethod -+ def __doc_getter(cls): -+ return cls.__get_next().doc - -- @property -- def topic(self): -- return self.next.topic -+ doc = classproperty(__doc_getter) -+ -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return cls.__get_next().NO_CLI -+ -+ NO_CLI = classproperty(__NO_CLI_getter) -+ -+ @classmethod -+ def __topic_getter(cls): -+ return cls.__get_next().topic -+ -+ topic = classproperty(__topic_getter) - - @property - def forwarded_name(self): -diff --git a/ipaclient/plugins/automount.py b/ipaclient/plugins/automount.py -index c6537bc6c24b905a8e1f7fb6a7e2c931b95374c7..925b635ff27411fc7e2f8c3dae17c747216d7fb6 100644 ---- a/ipaclient/plugins/automount.py -+++ b/ipaclient/plugins/automount.py -@@ -27,6 +27,7 @@ from ipalib import api, errors - from ipalib import Flag, Str - from ipalib.frontend import Command, Method, Object - from ipalib.plugable import Registry -+from ipalib.util import classproperty - from ipalib import _ - from ipapython.dn import DN - -@@ -52,11 +53,13 @@ class _fake_automountlocation_show(Method): - - @register(override=True, no_fail=True) - class automountlocation_tofiles(MethodOverride): -- @property -- def NO_CLI(self): -- return isinstance(self.api.Command.automountlocation_show, -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return isinstance(api.Command.automountlocation_show, - _fake_automountlocation_show) - -+ NO_CLI = classproperty(__NO_CLI_getter) -+ - def output_for_cli(self, textui, result, *keys, **options): - maps = result['result']['maps'] - keys = result['result']['keys'] -diff --git a/ipaclient/plugins/otptoken_yubikey.py b/ipaclient/plugins/otptoken_yubikey.py -index 3c310eacbaeef654e43049db78437c8c29f52279..549376a0ff65d44c5698666a84608849152368b2 100644 ---- a/ipaclient/plugins/otptoken_yubikey.py -+++ b/ipaclient/plugins/otptoken_yubikey.py -@@ -23,10 +23,11 @@ import six - import usb.core - import yubico - --from ipalib import _, IntEnum -+from ipalib import _, api, IntEnum - from ipalib.errors import NotFound - from ipalib.frontend import Command, Method, Object - from ipalib.plugable import Registry -+from ipalib.util import classproperty - - if six.PY3: - unicode = str -@@ -74,11 +75,13 @@ class otptoken_add_yubikey(Command): - ) - has_output_params = takes_options - -- @property -- def NO_CLI(self): -- return isinstance(self.api.Command.otptoken_add, -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return isinstance(api.Command.otptoken_add, - _fake_otptoken_add) - -+ NO_CLI = classproperty(__NO_CLI_getter) -+ - def get_args(self): - for arg in self.api.Command.otptoken_add.args(): - yield arg -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index 3e116bbad54fea419b571d1f09c1b00280e94991..c0ded21d515fe41bde5fb0e547087cb7789aa6a3 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -38,7 +38,8 @@ import nss.nss as nss - - from ipaclient.frontend import MethodOverride - from ipalib.frontend import Local, Method, Object --from ipalib import errors -+from ipalib.util import classproperty -+from ipalib import api, errors - from ipalib import Bytes, Flag, Str - from ipalib.plugable import Registry - from ipalib import _ -@@ -202,11 +203,13 @@ class vault_add(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return isinstance(self.api.Command.vault_add_internal, -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return isinstance(api.Command.vault_add_internal, - _fake_vault_add_internal) - -+ NO_CLI = classproperty(__NO_CLI_getter) -+ - def get_args(self): - for arg in self.api.Command.vault_add_internal.args(): - yield arg -@@ -406,11 +409,13 @@ class vault_mod(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return isinstance(self.api.Command.vault_mod_internal, -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return isinstance(api.Command.vault_mod_internal, - _fake_vault_mod_internal) - -+ NO_CLI = classproperty(__NO_CLI_getter) -+ - def get_args(self): - for arg in self.api.Command.vault_mod_internal.args(): - yield arg -@@ -591,11 +596,13 @@ class vault_archive(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return isinstance(self.api.Command.vault_archive_internal, -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return isinstance(api.Command.vault_archive_internal, - _fake_vault_archive_internal) - -+ NO_CLI = classproperty(__NO_CLI_getter) -+ - def get_args(self): - for arg in self.api.Command.vault_archive_internal.args(): - yield arg -@@ -846,11 +853,13 @@ class vault_retrieve(Local): - ), - ) - -- @property -- def NO_CLI(self): -- return isinstance(self.api.Command.vault_retrieve_internal, -+ @classmethod -+ def __NO_CLI_getter(cls): -+ return isinstance(api.Command.vault_retrieve_internal, - _fake_vault_retrieve_internal) - -+ NO_CLI = classproperty(__NO_CLI_getter) -+ - def get_args(self): - for arg in self.api.Command.vault_retrieve_internal.args(): - yield arg -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index d039fb41991c26a9c7b7f76f6959668efb677586..f165736cde6f08d6d22c17070d570da261799e4b 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -89,10 +89,32 @@ class _SchemaPlugin(object): - bases = None - schema_key = None - -- def __init__(self, full_name): -+ def __init__(self, schema, full_name): - self.name, _slash, self.version = full_name.partition('/') - self.full_name = full_name -- self.__class = None -+ self._schema = schema -+ self._class = None -+ -+ @property -+ def doc(self): -+ if self._class is not None: -+ return self._class.doc -+ else: -+ schema = self._schema[self.schema_key][self.full_name] -+ try: -+ return schema['doc'] -+ except KeyError: -+ return None -+ -+ @property -+ def summary(self): -+ if self._class is not None: -+ return self._class.summary -+ else: -+ if self.doc is not None: -+ return self.doc.split('\n\n', 1)[0].strip() -+ else: -+ return u'<%s>' % self.full_name - - def _create_default_from(self, api, name, keys): - cmd_name = self.full_name -@@ -200,18 +222,37 @@ class _SchemaPlugin(object): - return self.name, self.bases, class_dict - - def __call__(self, api): -- if self.__class is None: -+ if self._class is None: - schema = api._schema[self.schema_key][self.full_name] - name, bases, class_dict = self._create_class(api, schema) -- self.__class = type(name, bases, class_dict) -+ self._class = type(name, bases, class_dict) - -- return self.__class(api) -+ return self._class(api) - - - class _SchemaCommandPlugin(_SchemaPlugin): - bases = (_SchemaCommand,) - schema_key = 'commands' - -+ @property -+ def topic(self): -+ if self._class is not None: -+ return self._class.topic -+ else: -+ schema = self._schema[self.schema_key][self.full_name] -+ try: -+ return str(schema['topic_topic']).partition('/')[0] -+ except KeyError: -+ return None -+ -+ @property -+ def NO_CLI(self): -+ if self._class is not None: -+ return self._class.NO_CLI -+ else: -+ schema = self._schema[self.schema_key][self.full_name] -+ return 'cli' in schema.get('exclude', []) -+ - def _create_output(self, api, schema): - if schema.get('multivalue', False): - type_type = (tuple, list) -@@ -565,7 +606,7 @@ def get_package(api, client): - module.register = plugable.Registry() - for plugin_cls in (_SchemaCommandPlugin, _SchemaObjectPlugin): - for full_name in schema[plugin_cls.schema_key]: -- plugin = plugin_cls(str(full_name)) -+ plugin = plugin_cls(schema, str(full_name)) - plugin = module.register()(plugin) - sys.modules[module_name] = module - -diff --git a/ipalib/frontend.py b/ipalib/frontend.py -index cb00841f21bd5a3e3b4095dcd17a8816ca24400f..455b222d4d7fcbb65b43c4d8e1ffbbaf3e131d22 100644 ---- a/ipalib/frontend.py -+++ b/ipalib/frontend.py -@@ -38,7 +38,7 @@ from ipalib.errors import (ZeroArgumentError, MaxArgumentError, OverlapError, - ValidationError, ConversionError) - from ipalib import errors, messages - from ipalib.request import context, context_frame --from ipalib.util import json_serialize -+from ipalib.util import classproperty, json_serialize - - if six.PY3: - unicode = str -@@ -426,9 +426,11 @@ class Command(HasParam): - - api_version = API_VERSION - -- @property -- def topic(self): -- return type(self).__module__.rpartition('.')[2] -+ @classmethod -+ def __topic_getter(cls): -+ return cls.__module__.rpartition('.')[2] -+ -+ topic = classproperty(__topic_getter) - - @property - def forwarded_name(self): -diff --git a/ipalib/plugable.py b/ipalib/plugable.py -index 26fbeaa26d7986f2e184f0974ef396bd323d6bf5..073ad05d7aee5e83cae5c6e20bac8f9439505198 100644 ---- a/ipalib/plugable.py -+++ b/ipalib/plugable.py -@@ -155,19 +155,22 @@ class Plugin(ReadOnly): - - bases = classproperty(__bases_getter) - -- @property -- def doc(self): -- return type(self).__doc__ -+ @classmethod -+ def __doc_getter(cls): -+ return cls.__doc__ - -- @property -- def summary(self): -- doc = self.doc -+ doc = classproperty(__doc_getter) -+ -+ @classmethod -+ def __summary_getter(cls): -+ doc = cls.doc - if not _(doc).msg: -- cls = type(self) - return u'<%s.%s>' % (cls.__module__, cls.__name__) - else: - return unicode(doc).split('\n\n', 1)[0].strip() - -+ summary = classproperty(__summary_getter) -+ - @property - def api(self): - """ --- -2.7.4 - diff --git a/SOURCES/0062-Get-correct-CA-cert-nickname-in-CA-less.patch b/SOURCES/0062-Get-correct-CA-cert-nickname-in-CA-less.patch new file mode 100644 index 0000000..cfd0cb5 --- /dev/null +++ b/SOURCES/0062-Get-correct-CA-cert-nickname-in-CA-less.patch @@ -0,0 +1,60 @@ +From f57c0fbd46d0cca82b45c2f16fab316aa2554a08 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 24 Mar 2017 09:52:18 +0100 +Subject: [PATCH] Get correct CA cert nickname in CA-less + +During CA-less installation, we initialize the HTTPD alias +database from a pkcs12 file. This means there's going to +be different nicknames to the added certificates. Store +the CA certificate nickname in HTTPInstance__setup_ssl() +to be able to correctly export it later. + +https://pagure.io/freeipa/issue/6806 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/httpinstance.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 01b55e7a7b00d020b7745c419267ad4f0ba86804..3e4252cb1e907618d4aa15f7381caff5e4e868e3 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -118,6 +118,7 @@ class WebGuiInstance(service.SimpleServiceInstance): + def __init__(self): + service.SimpleServiceInstance.__init__(self, "ipa_webgui") + ++ + class HTTPInstance(service.Service): + def __init__(self, fstore=None, cert_nickname='Server-Cert', + api=api): +@@ -130,6 +131,7 @@ class HTTPInstance(service.Service): + service_user=HTTPD_USER, + keytab=paths.HTTP_KEYTAB) + ++ self.cacert_nickname = None + self.cert_nickname = cert_nickname + self.ca_is_configured = True + self.keytab_user = constants.GSSPROXY_USER +@@ -441,6 +443,9 @@ class HTTPInstance(service.Service): + if not server_certs: + raise RuntimeError("Could not find a suitable server cert.") + ++ # store the CA cert nickname so that we can publish it later on ++ self.cacert_nickname = db.cacert_name ++ + def __import_ca_certs(self): + db = certs.CertDB(self.realm, nssdir=paths.HTTPD_ALIAS_DIR, + subject_base=self.subject_base) +@@ -449,7 +454,7 @@ class HTTPInstance(service.Service): + def __publish_ca_cert(self): + ca_db = certs.CertDB(self.realm, nssdir=paths.HTTPD_ALIAS_DIR, + subject_base=self.subject_base) +- ca_db.publish_ca_cert(paths.CA_CRT) ++ ca_db.export_pem_cert(self.cacert_nickname, paths.CA_CRT) + + def is_kdcproxy_configured(self): + """Check if KDC proxy has already been configured in the past""" +-- +2.12.2 + diff --git a/SOURCES/0062-schema-Introduce-schema-cache-format.patch b/SOURCES/0062-schema-Introduce-schema-cache-format.patch deleted file mode 100644 index 1e6d14f..0000000 --- a/SOURCES/0062-schema-Introduce-schema-cache-format.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 1242b26266b5f1222924dc06479e19d0914a0703 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 27 Jul 2016 10:54:16 +0200 -Subject: [PATCH] schema: Introduce schema cache format - -Information about schema cache format is stored in every cache item. -When schema cache format changes in incompatible way format will be -increased. When format stored in cache doesn't match currently used -format the entry in cache is ignored. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index f165736cde6f08d6d22c17070d570da261799e4b..d7c018e3de1cc79ffc086e3576542ce993ebc87a 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -23,6 +23,8 @@ from ipapython.dn import DN - from ipapython.dnsutil import DNSName - from ipapython.ipa_log_manager import log_mgr - -+FORMAT = '0' -+ - if six.PY3: - unicode = str - -@@ -478,6 +480,14 @@ class Schema(object): - return _LockedZipFile(path, mode) - - def _get_schema_fingerprint(self, schema): -+ try: -+ fmt = json.loads(schema.read('format')) -+ except KeyError: -+ fmt = '0' -+ -+ if fmt != FORMAT: -+ raise RuntimeError('invalid format') -+ - schema_info = json.loads(schema.read(self.schema_info_path)) - return schema_info['fingerprint'] - --- -2.7.4 - diff --git a/SOURCES/0063-Remove-publish_ca_cert-method-from-NSSDatabase.patch b/SOURCES/0063-Remove-publish_ca_cert-method-from-NSSDatabase.patch new file mode 100644 index 0000000..2ac172a --- /dev/null +++ b/SOURCES/0063-Remove-publish_ca_cert-method-from-NSSDatabase.patch @@ -0,0 +1,49 @@ +From caa2c2b6e4b6ac29774dc7f8ec7c3f5210e2f828 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Mon, 27 Mar 2017 10:31:36 +0200 +Subject: [PATCH] Remove publish_ca_cert() method from NSSDatabase + +NSSDatabase.publish_ca_cert() is not used anymore, remove it. + +https://pagure.io/freeipa/issue/6806 + +Reviewed-By: Jan Cholasta +--- + ipapython/certdb.py | 9 --------- + ipaserver/install/certs.py | 3 --- + 2 files changed, 12 deletions(-) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index f1410e5ae4290263573e9554ab4e66873d4344a1..0665f944457fb09820eb244c742cb1782e515ad1 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -596,12 +596,3 @@ class NSSDatabase(object): + finally: + del certdb, cert + nss.nss_shutdown() +- +- def publish_ca_cert(self, canickname, location): +- args = ["-L", "-n", canickname, "-a"] +- result = self.run_certutil(args, capture_output=True) +- cert = result.output +- fd = open(location, "w+") +- fd.write(cert) +- fd.close() +- os.chmod(location, 0o444) +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 0ca971358030db6a6e7e410e58a984675bcf53ac..16139f81f0d0bd6889a9f38948204bb5bc018028 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -640,9 +640,6 @@ class CertDB(object): + + self.export_ca_cert(nickname, False) + +- def publish_ca_cert(self, location): +- self.nssdb.publish_ca_cert(self.cacert_name, location) +- + def export_pem_cert(self, nickname, location): + return self.nssdb.export_pem_cert(nickname, location) + +-- +2.12.2 + diff --git a/SOURCES/0063-schema-Generate-bits-for-help-load-them-on-request.patch b/SOURCES/0063-schema-Generate-bits-for-help-load-them-on-request.patch deleted file mode 100644 index 2a0ba33..0000000 --- a/SOURCES/0063-schema-Generate-bits-for-help-load-them-on-request.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 5386802ebc96ef0c2bc4a3bfa260ee83a6d7fe5f Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 2 Aug 2016 08:16:30 +0200 -Subject: [PATCH] schema: Generate bits for help load them on request - -Store name, summary, topic_topic and exclude in single entry in cache -for all commands. These data are needed for help and storing and -loading them together allows fast help response. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 54 +++++++++++++++++++++++++++++--------- - 1 file changed, 42 insertions(+), 12 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index d7c018e3de1cc79ffc086e3576542ce993ebc87a..5264d4cc177ba457c517f93f203e0baca7b0ac01 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -23,7 +23,7 @@ from ipapython.dn import DN - from ipapython.dnsutil import DNSName - from ipapython.ipa_log_manager import log_mgr - --FORMAT = '0' -+FORMAT = '1' - - if six.PY3: - unicode = str -@@ -113,9 +113,11 @@ class _SchemaPlugin(object): - if self._class is not None: - return self._class.summary - else: -- if self.doc is not None: -- return self.doc.split('\n\n', 1)[0].strip() -- else: -+ self._schema.load_help() -+ schema = self._schema[self.schema_key][self.full_name] -+ try: -+ return schema['summary'] -+ except KeyError: - return u'<%s>' % self.full_name - - def _create_default_from(self, api, name, keys): -@@ -241,6 +243,7 @@ class _SchemaCommandPlugin(_SchemaPlugin): - if self._class is not None: - return self._class.topic - else: -+ self._schema.load_help() - schema = self._schema[self.schema_key][self.full_name] - try: - return str(schema['topic_topic']).partition('/')[0] -@@ -252,6 +255,7 @@ class _SchemaCommandPlugin(_SchemaPlugin): - if self._class is not None: - return self._class.NO_CLI - else: -+ self._schema.load_help() - schema = self._schema[self.schema_key][self.full_name] - return 'cli' in schema.get('exclude', []) - -@@ -432,7 +436,6 @@ class Schema(object): - - """ - namespaces = {'classes', 'commands', 'topics'} -- schema_info_path = 'schema' - _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema') - - def __init__(self, api, server_info, client): -@@ -488,8 +491,7 @@ class Schema(object): - if fmt != FORMAT: - raise RuntimeError('invalid format') - -- schema_info = json.loads(schema.read(self.schema_info_path)) -- return schema_info['fingerprint'] -+ return json.loads(schema.read('fingerprint')) - - def _fetch(self, client): - if not client.isconnected(): -@@ -522,6 +524,7 @@ class Schema(object): - else: - fp = schema['fingerprint'] - ttl = schema.pop('ttl', 0) -+ schema.pop('version', None) - - for key, value in schema.items(): - if key in self.namespaces: -@@ -534,8 +537,6 @@ class Schema(object): - def _read_schema(self): - with self._open_schema(self._fingerprint, 'r') as schema: - self._dict['fingerprint'] = self._get_schema_fingerprint(schema) -- schema_info = json.loads(schema.read(self.schema_info_path)) -- self._dict['version'] = schema_info['version'] - - for name in schema.namelist(): - ns, _slash, key = name.partition('/') -@@ -548,6 +549,27 @@ class Schema(object): - except KeyError: - return self._dict[key] - -+ def _generate_help(self, schema): -+ halp = {} -+ -+ for namespace in ('commands', 'topics'): -+ halp[namespace] = {} -+ -+ for member_schema in schema[namespace].values(): -+ member_full_name = member_schema['full_name'] -+ -+ topic = halp[namespace].setdefault(member_full_name, {}) -+ topic['name'] = member_schema['name'] -+ if 'doc' in member_schema: -+ topic['summary'] = ( -+ member_schema['doc'].split('\n\n', 1)[0].strip()) -+ if 'topic_topic' in member_schema: -+ topic['topic_topic'] = member_schema['topic_topic'] -+ if 'exclude' in member_schema: -+ topic['exclude'] = member_schema['exclude'] -+ -+ return halp -+ - def _write_schema(self): - try: - os.makedirs(self._DIR) -@@ -557,7 +579,6 @@ class Schema(object): - return - - with self._open_schema(self._fingerprint, 'w') as schema: -- schema_info = {} - for key, value in self._dict.items(): - if key in self.namespaces: - ns = value -@@ -565,9 +586,10 @@ class Schema(object): - path = '{}/{}'.format(key, member) - schema.writestr(path, json.dumps(ns[member])) - else: -- schema_info[key] = value -+ schema.writestr(key, json.dumps(value)) - -- schema.writestr(self.schema_info_path, json.dumps(schema_info)) -+ schema.writestr('_help', -+ json.dumps(self._generate_help(self._dict))) - - def _read(self, path): - with self._open_schema(self._fingerprint, 'r') as zf: -@@ -587,6 +609,14 @@ class Schema(object): - def iter_namespace(self, namespace): - return iter(self._dict[namespace]) - -+ def load_help(self): -+ if not self._help: -+ self._help = self._read('_help') -+ -+ for ns in self._help: -+ for member in self._help[ns]: -+ self._dict[ns][member].update(self._help[ns][member]) -+ - - def get_package(api, client): - try: --- -2.7.4 - diff --git a/SOURCES/0064-help-Do-not-create-instances-to-get-information-abou.patch b/SOURCES/0064-help-Do-not-create-instances-to-get-information-abou.patch deleted file mode 100644 index 62dca09..0000000 --- a/SOURCES/0064-help-Do-not-create-instances-to-get-information-abou.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0ae77ea176190307ef74598179fc8be83169628a Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Wed, 20 Jul 2016 13:24:03 +0200 -Subject: [PATCH] help: Do not create instances to get information about - commands and topics - -Creating instance requires that complete schema for the command is -read from schema cache and passed to constructor. This operation takes -a lot of time. Utilizing class properties and pregenerated help bits -allows to get the necessary information directly from classes reducing -time it takes significantly. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipalib/cli.py | 15 ++++++++------- - ipalib/plugable.py | 7 +++++-- - 2 files changed, 13 insertions(+), 9 deletions(-) - -diff --git a/ipalib/cli.py b/ipalib/cli.py -index 1faf8285c47d950d5fd311154b6936c8371d746c..d89a5320853ecf575c7ba710b2db2e62e1003141 100644 ---- a/ipalib/cli.py -+++ b/ipalib/cli.py -@@ -727,8 +727,8 @@ class help(frontend.Local): - self._builtins = [] - - # build help topics -- for c in self.api.Command(): -- if c is not self.api.Command[c.name]: -+ for c in self.api.Command: -+ if c is not self.api.Command.get_plugin(c.name): - continue - if c.NO_CLI: - continue -@@ -793,13 +793,14 @@ class help(frontend.Local): - self.print_commands(name, outfile) - elif name == "commands": - mcl = 0 -- for cmd in self.Command(): -- if cmd is not self.Command[cmd.name]: -+ for cmd_plugin in self.Command: -+ if cmd_plugin is not self.Command.get_plugin(cmd_plugin.name): - continue -- if cmd.NO_CLI: -+ if cmd_plugin.NO_CLI: - continue -- mcl = max(mcl, len(cmd.name)) -- writer('%s %s' % (to_cli(cmd.name).ljust(mcl), cmd.summary)) -+ mcl = max(mcl, len(cmd_plugin.name)) -+ writer('%s %s' % (to_cli(cmd_plugin.name).ljust(mcl), -+ cmd_plugin.summary)) - else: - raise HelpError(topic=name) - -diff --git a/ipalib/plugable.py b/ipalib/plugable.py -index 073ad05d7aee5e83cae5c6e20bac8f9439505198..af35f5bae27a17230267d5b10b5fdc4f784a4760 100644 ---- a/ipalib/plugable.py -+++ b/ipalib/plugable.py -@@ -318,9 +318,12 @@ class APINameSpace(collections.Mapping): - self.__enumerate() - return iter(self.__plugins) - -- def __getitem__(self, key): -+ def get_plugin(self, key): - self.__enumerate() -- plugin = self.__plugins_by_key[key] -+ return self.__plugins_by_key[key] -+ -+ def __getitem__(self, key): -+ plugin = self.get_plugin(key) - return self.__api._get(plugin) - - def __call__(self): --- -2.7.4 - diff --git a/SOURCES/0064-httpinstance-make-sure-NSS-database-is-backed-up.patch b/SOURCES/0064-httpinstance-make-sure-NSS-database-is-backed-up.patch new file mode 100644 index 0000000..4e78d20 --- /dev/null +++ b/SOURCES/0064-httpinstance-make-sure-NSS-database-is-backed-up.patch @@ -0,0 +1,39 @@ +From 27360b29b510d5ae92469b079569973676efd26c Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 3 Apr 2017 10:49:26 +0000 +Subject: [PATCH] httpinstance: make sure NSS database is backed up + +The NSS database at /etc/httpd/alias is not properly initialized and backed +up in CA-less replica promotion. This might cause the install to fail after +previous install and uninstall. + +Make sure the NSS database is initialized and backed up even in CA-less +replica promotion to fix the issue. + +https://pagure.io/freeipa/issue/4639 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/httpinstance.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 3e4252cb1e907618d4aa15f7381caff5e4e868e3..079ea92606cc53f98beca1759a7e24db64bfd3f4 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -375,10 +375,11 @@ class HTTPInstance(service.Service): + return False + + def __setup_ssl(self): ++ truncate = not self.promote or not self.ca_is_configured + db = certs.CertDB(self.realm, nssdir=paths.HTTPD_ALIAS_DIR, + subject_base=self.subject_base, user="root", + group=constants.HTTPD_GROUP, +- truncate=(not self.promote)) ++ truncate=truncate) + self.disable_system_trust() + if self.pkcs12_info: + if self.ca_is_configured: +-- +2.12.2 + diff --git a/SOURCES/0065-Fix-ipa-caalc-add-service-error-message.patch b/SOURCES/0065-Fix-ipa-caalc-add-service-error-message.patch deleted file mode 100644 index 5435828..0000000 --- a/SOURCES/0065-Fix-ipa-caalc-add-service-error-message.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 69a3d8a8abffe7a785efda8e6e2012718521783f Mon Sep 17 00:00:00 2001 -From: Tomas Krizek -Date: Tue, 9 Aug 2016 14:09:24 +0200 -Subject: [PATCH] Fix ipa-caalc-add-service error message - -When service is not found in ipa-caalc-add-service command, return the -entire principal name of the service instead of the first character. - -https://fedorahosted.org/freeipa/ticket/6171 - -Reviewed-By: Petr Spacek ---- - ipaserver/plugins/service.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/service.py b/ipaserver/plugins/service.py -index 28ea364e9aca8c997a86e27c529fc49d8410115b..a44dcaa5e348d3deedda6c0b4f55760ad873cf49 100644 ---- a/ipaserver/plugins/service.py -+++ b/ipaserver/plugins/service.py -@@ -575,7 +575,7 @@ class service(LDAPObject): - pass - - try: -- return dn['krbprincipalname'][0] -+ return dn['krbprincipalname'] - except KeyError: - return unicode(dn) - --- -2.7.4 - diff --git a/SOURCES/0065-IPA-KDB-use-relative-path-in-ipa-certmap-config-snip.patch b/SOURCES/0065-IPA-KDB-use-relative-path-in-ipa-certmap-config-snip.patch new file mode 100644 index 0000000..544e546 --- /dev/null +++ b/SOURCES/0065-IPA-KDB-use-relative-path-in-ipa-certmap-config-snip.patch @@ -0,0 +1,72 @@ +From cae66046bb31205283341cd3b19af799c5fe6a30 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 29 Mar 2017 15:46:50 +0200 +Subject: [PATCH] IPA-KDB: use relative path in ipa-certmap config snippet + +Architecture specific paths should be avoided in the global Kerberos +configuration because it is read e.g. by 32bit and 64bit libraries they +are installed in parallel. + +Resolves https://pagure.io/freeipa/issue/6833 + +Reviewed-By: Christian Heimes +Reviewed-By: Jan Cholasta +--- + daemons/ipa-kdb/Makefile.am | 12 ++++-------- + daemons/ipa-kdb/{ipa-certauth.in => ipa-certauth} | 2 +- + 2 files changed, 5 insertions(+), 9 deletions(-) + rename daemons/ipa-kdb/{ipa-certauth.in => ipa-certauth} (56%) + +diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am +index 715666e779a4fa64c2c0f71767f09efb19b5f908..259bc3b20fa96cadff43c3acdce1bd3ba49cdb31 100644 +--- a/daemons/ipa-kdb/Makefile.am ++++ b/daemons/ipa-kdb/Makefile.am +@@ -40,18 +40,16 @@ ipadb_la_SOURCES = \ + ipa_kdb_audit_as.c \ + $(NULL) + ++dist_noinst_DATA = ipa_kdb.exports ++ + if BUILD_IPA_CERTAUTH_PLUGIN + ipadb_la_SOURCES += ipa_kdb_certauth.c + + +-%: %.in +- sed \ +- -e 's|@plugindir@|$(plugindir)|g' \ +- '$(srcdir)/$@.in' >$@ +- + krb5confdir = $(sysconfdir)/krb5.conf.d + krb5conf_DATA = ipa-certauth +-CLEANFILES = $(krb5conf_DATA) ++else ++dist_noinst_DATA += ipa-certauth + endif + + ipadb_la_LDFLAGS = \ +@@ -105,8 +103,6 @@ ipa_kdb_tests_LDADD = \ + -lsss_idmap \ + $(NULL) + +-dist_noinst_DATA = ipa_kdb.exports ipa-certauth.in +- + clean-local: + rm -f tests/.dirstamp + +diff --git a/daemons/ipa-kdb/ipa-certauth.in b/daemons/ipa-kdb/ipa-certauth +similarity index 56% +rename from daemons/ipa-kdb/ipa-certauth.in +rename to daemons/ipa-kdb/ipa-certauth +index eda89a26f02fbea449eb754b232b8115904acd21..6fde08284da22161a97df675d15392f80ffcc6fb 100644 +--- a/daemons/ipa-kdb/ipa-certauth.in ++++ b/daemons/ipa-kdb/ipa-certauth +@@ -1,5 +1,5 @@ + [plugins] + certauth = { +- module = ipakdb:@plugindir@/ipadb.so ++ module = ipakdb:kdb/ipadb.so + enable_only = ipakdb + } +-- +2.12.2 + diff --git a/SOURCES/0066-Add-pki_pin-only-when-needed.patch b/SOURCES/0066-Add-pki_pin-only-when-needed.patch new file mode 100644 index 0000000..880c676 --- /dev/null +++ b/SOURCES/0066-Add-pki_pin-only-when-needed.patch @@ -0,0 +1,62 @@ +From 71061059a6c56bad818cb379070ef742bbe517a3 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Mon, 3 Apr 2017 14:08:46 +0200 +Subject: [PATCH] Add pki_pin only when needed + +If both the pki-tomcat NSS database and its password.conf have been +created, don't try to override the password.conf file. + +https://pagure.io/freeipa/issue/6839 + +Reviewed-By: Tomas Krizek +Reviewed-By: Christian Heimes +--- + ipaserver/install/cainstance.py | 10 +++++++--- + ipaserver/install/krainstance.py | 10 +++++++--- + 2 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 92bb760d39d23fedb40b7e3c5bea53381f1c87ad..3980e412603437b0db5804623f6626d11e52c009 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -541,9 +541,13 @@ class CAInstance(DogtagInstance): + # CA key algorithm + config.set("CA", "pki_ca_signing_key_algorithm", self.ca_signing_algorithm) + +- # generate pin which we know can be used for FIPS NSS database +- pki_pin = ipautil.ipa_generate_password() +- config.set("CA", "pki_pin", pki_pin) ++ if not (os.path.isdir(paths.PKI_TOMCAT_ALIAS_DIR) and ++ os.path.isfile(paths.PKI_TOMCAT_PASSWORD_CONF)): ++ # generate pin which we know can be used for FIPS NSS database ++ pki_pin = ipautil.ipa_generate_password() ++ config.set("CA", "pki_pin", pki_pin) ++ else: ++ pki_pin = None + + if self.clone: + +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index 34d667857a8055752e258a591af983190f33daa5..fc25ac72b0dc593f06a8b070b67b5d54a0ab8bce 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -235,9 +235,13 @@ class KRAInstance(DogtagInstance): + "KRA", "pki_share_dbuser_dn", + str(DN(('uid', 'pkidbuser'), ('ou', 'people'), ('o', 'ipaca')))) + +- # generate pin which we know can be used for FIPS NSS database +- pki_pin = ipautil.ipa_generate_password() +- config.set("KRA", "pki_pin", pki_pin) ++ if not (os.path.isdir(paths.PKI_TOMCAT_ALIAS_DIR) and ++ os.path.isfile(paths.PKI_TOMCAT_PASSWORD_CONF)): ++ # generate pin which we know can be used for FIPS NSS database ++ pki_pin = ipautil.ipa_generate_password() ++ config.set("KRA", "pki_pin", pki_pin) ++ else: ++ pki_pin = None + + _p12_tmpfile_handle, p12_tmpfile_name = tempfile.mkstemp(dir=paths.TMP) + +-- +2.9.3 + diff --git a/SOURCES/0066-Don-t-show-force-ntpd-option-in-replica-install.patch b/SOURCES/0066-Don-t-show-force-ntpd-option-in-replica-install.patch deleted file mode 100644 index 96e2a22..0000000 --- a/SOURCES/0066-Don-t-show-force-ntpd-option-in-replica-install.patch +++ /dev/null @@ -1,42 +0,0 @@ -From a1b1518f02e0237fb8080851d0722f866b127918 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka -Date: Tue, 9 Aug 2016 15:22:33 +0200 -Subject: [PATCH] Don't show --force-ntpd option in replica install - -Always run the client installation script with --no-ntp -option so that it does not show the message about --force-ntpd -option that does not exist in ipa-replica-install. The time -synchronization is done elsewhere anyway. - -https://fedorahosted.org/freeipa/ticket/6046 - -Reviewed-By: Martin Basti ---- - ipaserver/install/server/replicainstall.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 9d05a0be5a2679d825b4ee6bc2ea55ed358e8ff9..f54ff7da06c57b9c8251429cbdacc5c300805f84 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -881,7 +881,7 @@ def install(installer): - try: - args = [paths.IPA_CLIENT_INSTALL, "--on-master", "--unattended", - "--domain", config.domain_name, "--server", config.host_name, -- "--realm", config.realm_name] -+ "--realm", config.realm_name, "--no-ntp"] - if options.no_dns_sshfp: - args.append("--no-dns-sshfp") - if options.ssh_trust_dns: -@@ -918,7 +918,7 @@ def ensure_enrolled(installer): - try: - installer._enrollment_performed = True - -- args = [paths.IPA_CLIENT_INSTALL, "--unattended"] -+ args = [paths.IPA_CLIENT_INSTALL, "--unattended", "--no-ntp"] - stdin = None - - if installer.domain_name: --- -2.7.4 - diff --git a/SOURCES/0067-DNS-server-upgrade-do-not-fail-when-DNS-server-did-n.patch b/SOURCES/0067-DNS-server-upgrade-do-not-fail-when-DNS-server-did-n.patch deleted file mode 100644 index dce696d..0000000 --- a/SOURCES/0067-DNS-server-upgrade-do-not-fail-when-DNS-server-did-n.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 78ef6581483190fc60fc928fb2263f5520a5edfa Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Thu, 11 Aug 2016 13:44:29 +0200 -Subject: [PATCH] DNS server upgrade: do not fail when DNS server did not - respond - -Previously, update_dnsforward_emptyzones failed with an exeception if -DNS query failed for some reason. Now the error is logged and upgrade -continues. - -I assume that this is okay because the DNS query is used as heuristics -of last resort in the upgrade logic and failure to do so should not have -catastrophics consequences: In the worst case, the admin needs to -manually change forwarding policy from 'first' to 'only'. - -In the end I have decided not to auto-start BIND because BIND depends on -GSSAPI for authentication, which in turn depends on KDC ... Alternative -like reconfiguring BIND to use LDAPI+EXTERNAL and reconfiguring DS to -accept LDAP external bind from named user are too complicated. - -https://fedorahosted.org/freeipa/ticket/6205 - -Reviewed-By: Martin Basti ---- - ipaserver/install/plugins/dns.py | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py -index 32247eedbac7fc7e00c7277ef0bc593a74cd22e4..7b06a5c0d3a59e5825af75fae87c9739a53d9913 100644 ---- a/ipaserver/install/plugins/dns.py -+++ b/ipaserver/install/plugins/dns.py -@@ -17,6 +17,9 @@ - # You should have received a copy of the GNU General Public License - # along with this program. If not, see . - -+from __future__ import absolute_import -+ -+import dns.exception - import re - import traceback - import time -@@ -489,8 +492,15 @@ class update_dnsforward_emptyzones(DNSUpdater): - self.api.Command['dnsconfig_mod'](ipadnsversion=2) - - self.update_zones() -- if dnsutil.has_empty_zone_addresses(self.api.env.host): -- self.update_global_ldap_forwarder() -+ try: -+ if dnsutil.has_empty_zone_addresses(self.api.env.host): -+ self.update_global_ldap_forwarder() -+ except dns.exception.DNSException as ex: -+ self.log.error('Skipping update of global DNS forwarder in LDAP: ' -+ 'Unable to determine if local server is using an ' -+ 'IP address belonging to an automatic empty zone. ' -+ 'Consider changing forwarding policy to "only". ' -+ 'DNS exception: %s', ex) - - return False, [] - --- -2.7.4 - diff --git a/SOURCES/0067-idrange-add-properly-handle-empty-dom-name-option.patch b/SOURCES/0067-idrange-add-properly-handle-empty-dom-name-option.patch new file mode 100644 index 0000000..3ef7ec8 --- /dev/null +++ b/SOURCES/0067-idrange-add-properly-handle-empty-dom-name-option.patch @@ -0,0 +1,35 @@ +From 1f9d9de5dd0e5935bb71060d867b46f675977163 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 28 Mar 2017 16:02:45 +0200 +Subject: [PATCH] idrange-add: properly handle empty --dom-name option + +When idrange-add is called with --dom-name=, the CLI exits with +ipa: ERROR: an internal error has occurred +This happens because the code checks if the option is provided but does not +check if the value is None. + +We need to handle empty dom-name as if the option was not specified. + +https://pagure.io/freeipa/issue/6404 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/plugins/idrange.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py +index 5b88a6b0fd91271eaeb19c8315e23299a13ff7e4..c8ea95af801a86dd0180497964ddbd1b2741f279 100644 +--- a/ipaserver/plugins/idrange.py ++++ b/ipaserver/plugins/idrange.py +@@ -411,7 +411,7 @@ class idrange_add(LDAPCreate): + + # This needs to stay in options since there is no + # ipanttrusteddomainname attribute in LDAP +- if 'ipanttrusteddomainname' in options: ++ if options.get('ipanttrusteddomainname'): + if is_set('ipanttrusteddomainsid'): + raise errors.ValidationError(name='ID Range setup', + error=_('Options dom-sid and dom-name ' +-- +2.9.3 + diff --git a/SOURCES/0068-DNS-allow-to-add-forward-zone-to-already-broken-sub-.patch b/SOURCES/0068-DNS-allow-to-add-forward-zone-to-already-broken-sub-.patch deleted file mode 100644 index 567a26c..0000000 --- a/SOURCES/0068-DNS-allow-to-add-forward-zone-to-already-broken-sub-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9b4153fdc1af86344da9f4cf6fa139a8dcb18c8c Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Fri, 12 Aug 2016 17:08:30 +0200 -Subject: [PATCH] DNS: allow to add forward zone to already broken sub-domain - -Errors during DNS resolution might indicate that forwarder is the -necessary configuration which is missing. Now we disallow adding a -forwarder only if the zone is normally resolvable without the forwarder. - -https://fedorahosted.org/freeipa/ticket/6062 - -Reviewed-By: Martin Basti ---- - ipaserver/plugins/dns.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py -index 585b28c15daf00df2918a67585f7fb6e99462f1e..6f1bd716d202bd85dfc46b5eb94f73e85683b917 100644 ---- a/ipaserver/plugins/dns.py -+++ b/ipaserver/plugins/dns.py -@@ -2097,7 +2097,7 @@ class DNSZoneBase_add(LDAPCreate): - - if not options['skip_overlap_check']: - try: -- check_zone_overlap(keys[-1]) -+ check_zone_overlap(keys[-1], raise_on_error=False) - except ValueError as e: - raise errors.InvocationError(e.message) - --- -2.7.4 - diff --git a/SOURCES/0068-ipa-sam-create-the-gidNumber-attribute-in-the-truste.patch b/SOURCES/0068-ipa-sam-create-the-gidNumber-attribute-in-the-truste.patch new file mode 100644 index 0000000..462657b --- /dev/null +++ b/SOURCES/0068-ipa-sam-create-the-gidNumber-attribute-in-the-truste.patch @@ -0,0 +1,145 @@ +From 376a1fbfe97624116d8fb10f26d97ef15fd3b917 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 21 Mar 2017 17:33:20 +0100 +Subject: [PATCH] ipa-sam: create the gidNumber attribute in the trusted domain + entry + +When a trusted domain entry is created, the uidNumber attribute is created +but not the gidNumber attribute. This causes samba to log + Failed to find a Unix account for DOM-AD$ +because the samu structure does not contain a group_sid and is not put +in the cache. +The fix creates the gidNumber attribute in the trusted domain entry, +and initialises the group_sid field in the samu structure returned +by ldapsam_getsampwnam. This ensures that the entry is put in the cache. + +Note that this is only a partial fix for 6660 as it does not prevent +_netr_ServerAuthenticate3 from failing with the log + _netr_ServerAuthenticate3: netlogon_creds_server_check failed. Rejecting auth request from client VM-AD machine account dom-ad.example.com. + +https://pagure.io/freeipa/issue/6827 + +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-sam/ipa_sam.c | 40 +++++++++++++++++++++++++++++++++++++--- + 1 file changed, 37 insertions(+), 3 deletions(-) + +diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c +index 4c1fda5f82b43f69929613f9938410b32cff31e7..6a29e8e10b4299356b9ead76276eecc8083791a3 100644 +--- a/daemons/ipa-sam/ipa_sam.c ++++ b/daemons/ipa-sam/ipa_sam.c +@@ -195,6 +195,7 @@ struct ipasam_privates { + char *trust_dn; + char *flat_name; + struct dom_sid fallback_primary_group; ++ char *fallback_primary_group_gid_str; + char *server_princ; + char *client_princ; + struct sss_idmap_ctx *idmap_ctx; +@@ -2419,6 +2420,9 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods, + if (entry == NULL || sid == NULL) { + smbldap_make_mod(priv2ld(ldap_state), entry, &mods, + LDAP_ATTRIBUTE_UIDNUMBER, IPA_MAGIC_ID_STR); ++ smbldap_make_mod(priv2ld(ldap_state), entry, &mods, ++ LDAP_ATTRIBUTE_GIDNUMBER, ++ ldap_state->ipasam_privates->fallback_primary_group_gid_str); + } + + if (td->netbios_name != NULL) { +@@ -2829,6 +2833,7 @@ static bool init_sam_from_td(struct samu *user, struct pdb_trusted_domain *td, + { + NTSTATUS status; + struct dom_sid *u_sid; ++ struct dom_sid *g_sid; + char *name; + char *trustpw = NULL; + char *trustpw_utf8 = NULL; +@@ -2884,6 +2889,11 @@ static bool init_sam_from_td(struct samu *user, struct pdb_trusted_domain *td, + } + talloc_free(u_sid); + ++ g_sid = &ldap_state->ipasam_privates->fallback_primary_group; ++ if (!pdb_set_group_sid(user, g_sid, PDB_SET)) { ++ return false; ++ } ++ + status = get_trust_pwd(user, &td->trust_auth_incoming, &trustpw, NULL); + if (!NT_STATUS_IS_OK(status)) { + return false; +@@ -3594,14 +3604,17 @@ static void ipasam_free_private_data(void **vp) + static struct dom_sid *get_fallback_group_sid(TALLOC_CTX *mem_ctx, + struct smbldap_state *ldap_state, + struct sss_idmap_ctx *idmap_ctx, +- LDAPMessage *dom_entry) ++ LDAPMessage *dom_entry, ++ char **fallback_group_gid_str) + { + char *dn; + char *sid; ++ char *gidnumber; + int ret; + const char *filter = "objectClass=*"; + const char *attr_list[] = { + LDAP_ATTRIBUTE_SID, ++ LDAP_ATTRIBUTE_GIDNUMBER, + NULL}; + LDAPMessage *result; + LDAPMessage *entry; +@@ -3648,9 +3661,20 @@ static struct dom_sid *get_fallback_group_sid(TALLOC_CTX *mem_ctx, + talloc_free(sid); + return NULL; + } ++ talloc_free(sid); ++ ++ gidnumber = get_single_attribute(mem_ctx, ldap_state->ldap_struct, ++ entry, LDAP_ATTRIBUTE_GIDNUMBER); ++ if (gidnumber == NULL) { ++ DEBUG(0, ("Missing mandatory attribute %s.\n", ++ LDAP_ATTRIBUTE_GIDNUMBER)); ++ ldap_msgfree(result); ++ return NULL; ++ } ++ ++ *fallback_group_gid_str = gidnumber; + + ldap_msgfree(result); +- talloc_free(sid); + + return fallback_group_sid; + } +@@ -4443,6 +4467,7 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method, + char *domain_sid_string = NULL; + struct dom_sid *ldap_domain_sid = NULL; + struct dom_sid *fallback_group_sid = NULL; ++ char *fallback_group_gid_str = NULL; + + LDAPMessage *result = NULL; + LDAPMessage *entry = NULL; +@@ -4586,7 +4611,8 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method, + fallback_group_sid = get_fallback_group_sid(ldap_state, + ldap_state->smbldap_state, + ldap_state->ipasam_privates->idmap_ctx, +- result); ++ result, ++ &fallback_group_gid_str); + if (fallback_group_sid == NULL) { + DEBUG(0, ("Cannot find SID of fallback group.\n")); + ldap_msgfree(result); +@@ -4596,6 +4622,14 @@ static NTSTATUS pdb_init_ipasam(struct pdb_methods **pdb_method, + fallback_group_sid); + talloc_free(fallback_group_sid); + ++ if (fallback_group_gid_str == NULL) { ++ DEBUG(0, ("Cannot find gidNumber of fallback group.\n")); ++ ldap_msgfree(result); ++ return NT_STATUS_INVALID_PARAMETER; ++ } ++ ldap_state->ipasam_privates->fallback_primary_group_gid_str = ++ fallback_group_gid_str; ++ + domain_sid_string = get_single_attribute( + ldap_state, + ldap_state->smbldap_state->ldap_struct, +-- +2.9.3 + diff --git a/SOURCES/0069-Upgrade-add-gidnumber-to-trusted-domain-entry.patch b/SOURCES/0069-Upgrade-add-gidnumber-to-trusted-domain-entry.patch new file mode 100644 index 0000000..3a887bf --- /dev/null +++ b/SOURCES/0069-Upgrade-add-gidnumber-to-trusted-domain-entry.patch @@ -0,0 +1,104 @@ +From 54422d3c58ace8496b0bd2fc536365159e6666e6 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 3 Apr 2017 15:57:47 +0200 +Subject: [PATCH] Upgrade: add gidnumber to trusted domain entry + +The trusted domain entries created in earlier versions are missing gidnumber. +During upgrade, a new plugin will read the gidnumber of the fallback group +cn=Default SMB Group and add this value to trusted domain entries which do +not have a gidNumber. + +https://pagure.io/freeipa/issue/6827 + +Reviewed-By: Alexander Bokovoy +--- + install/updates/90-post_upgrade_plugins.update | 1 + + ipaserver/install/plugins/adtrust.py | 56 ++++++++++++++++++++++++++ + 2 files changed, 57 insertions(+) + +diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update +index 34069e7457dd9690a14c5c055c6d05ad76004d16..8477199e07d6729d5847e58bfa67d061bd1410c2 100644 +--- a/install/updates/90-post_upgrade_plugins.update ++++ b/install/updates/90-post_upgrade_plugins.update +@@ -10,6 +10,7 @@ plugin: update_sigden_extdom_broken_config + plugin: update_sids + plugin: update_default_range + plugin: update_default_trust_view ++plugin: update_tdo_gidnumber + plugin: update_ca_renewal_master + plugin: update_idrange_type + plugin: update_pacs +diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py +index 42968089f547f61edd2f1223d088a22762a33b70..075f197780edc2aadf42fa82b71e9e2b29e66ea9 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -22,6 +22,7 @@ from ipalib import Updater + from ipapython.dn import DN + from ipapython.ipa_log_manager import root_logger + from ipaserver.install import sysupgrade ++from ipaserver.install.adtrustinstance import ADTRUSTInstance + + register = Registry() + +@@ -316,3 +317,58 @@ class update_sids(Updater): + + sysupgrade.set_upgrade_state('sidgen', 'update_sids', False) + return False, () ++ ++ ++@register() ++class update_tdo_gidnumber(Updater): ++ """ ++ Create a gidNumber attribute for Trusted Domain Objects. ++ ++ The value is taken from the fallback group defined in cn=Default SMB Group. ++ """ ++ def execute(self, **options): ++ ldap = self.api.Backend.ldap2 ++ ++ # Read the gidnumber of the fallback group ++ dn = DN(('cn', ADTRUSTInstance.FALLBACK_GROUP_NAME), ++ self.api.env.container_group, ++ self.api.env.basedn) ++ ++ try: ++ entry = ldap.get_entry(dn, ['gidnumber']) ++ gidNumber = entry.get('gidnumber') ++ except errors.NotFound: ++ self.log.error("{0} not found".format( ++ ADTRUSTInstance.FALLBACK_GROUP_NAME)) ++ return False, () ++ ++ if not gidNumber: ++ self.log.error("{0} does not have a gidnumber".format( ++ ADTRUSTInstance.FALLBACK_GROUP_NAME)) ++ return False, () ++ ++ # For each trusted domain object, add gidNumber ++ try: ++ tdos = ldap.get_entries( ++ DN(self.api.env.container_adtrusts, self.api.env.basedn), ++ scope=ldap.SCOPE_ONELEVEL, ++ filter="(objectclass=ipaNTTrustedDomain)", ++ attrs_list=['gidnumber']) ++ for tdo in tdos: ++ # if the trusted domain object does not contain gidnumber, ++ # add the default fallback group gidnumber ++ if not tdo.get('gidnumber'): ++ try: ++ tdo['gidnumber'] = gidNumber ++ ldap.update_entry(tdo) ++ self.log.debug("Added gidnumber {0} to {1}".format( ++ gidNumber, tdo.dn)) ++ except Exception: ++ self.log.warning( ++ "Failed to add gidnumber to {0}".format(tdo.dn)) ++ ++ except errors.NotFound: ++ self.log.debug("No trusted domain object to update") ++ return False, () ++ ++ return False, () +-- +2.9.3 + diff --git a/SOURCES/0069-cert-speed-up-cert-find.patch b/SOURCES/0069-cert-speed-up-cert-find.patch deleted file mode 100644 index ecd9d83..0000000 --- a/SOURCES/0069-cert-speed-up-cert-find.patch +++ /dev/null @@ -1,479 +0,0 @@ -From be32fd1d727fc8398dd51fa0fd3f404ef451281a Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 1 Aug 2016 09:53:39 +0200 -Subject: [PATCH] cert: speed up cert-find - -Use issuer+serial rather than raw DER blob to identify certificates in -cert-find's intermediate result. - -Restructure the code to make it (hopefully) easier to follow. - -https://fedorahosted.org/freeipa/ticket/6098 - -Reviewed-By: Martin Basti -Reviewed-By: Pavel Vomacka ---- - ipaserver/plugins/cert.py | 398 +++++++++++++++++++++++++--------------------- - 1 file changed, 216 insertions(+), 182 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 06041d3083565e8d093b610473d6083111d406d2..47dccf15a4010f2766642aedd2cc16e0a1eb1dd4 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -21,6 +21,7 @@ - - import base64 - import binascii -+import collections - import datetime - import os - -@@ -295,18 +296,24 @@ class BaseCertObject(Object): - ), - ) - -- def _parse(self, obj): -- cert = x509.load_certificate(obj['certificate']) -- obj['subject'] = DN(unicode(cert.subject)) -- obj['issuer'] = DN(unicode(cert.issuer)) -- obj['valid_not_before'] = unicode(cert.valid_not_before_str) -- obj['valid_not_after'] = unicode(cert.valid_not_after_str) -- obj['md5_fingerprint'] = unicode( -- nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) -- obj['sha1_fingerprint'] = unicode( -- nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) -- obj['serial_number'] = cert.serial_number -- obj['serial_number_hex'] = u'0x%X' % cert.serial_number -+ def _parse(self, obj, full=True): -+ cert = obj.get('certificate') -+ if cert is not None: -+ cert = x509.load_certificate(cert) -+ obj['subject'] = DN(unicode(cert.subject)) -+ obj['issuer'] = DN(unicode(cert.issuer)) -+ obj['serial_number'] = cert.serial_number -+ if full: -+ obj['valid_not_before'] = unicode(cert.valid_not_before_str) -+ obj['valid_not_after'] = unicode(cert.valid_not_after_str) -+ obj['md5_fingerprint'] = unicode( -+ nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) -+ obj['sha1_fingerprint'] = unicode( -+ nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) -+ -+ serial_number = obj.get('serial_number') -+ if serial_number is not None: -+ obj['serial_number_hex'] = u'0x%X' % serial_number - - - class BaseCertMethod(Method): -@@ -691,10 +698,14 @@ class cert(BaseCertObject): - yield self.api.Object[name] - - def _fill_owners(self, obj): -+ dns = obj.pop('owner', None) -+ if dns is None: -+ return -+ - for owner in self._owners(): - container_dn = DN(owner.container_dn, self.api.env.basedn) - name = 'owner_' + owner.name -- for dn in obj['owner']: -+ for dn in dns: - if dn.endswith(container_dn, 1): - value = owner.get_primary_key_from_dn(dn) - obj.setdefault(name, []).append(value) -@@ -776,9 +787,7 @@ class cert_show(Retrieve, CertMethod, VirtualCommand): - result['certificate'] = result['certificate'].replace('\r\n', '') - self.obj._parse(result) - result['revoked'] = ('revocation_reason' in result) -- if 'owner' in result: -- self.obj._fill_owners(result) -- del result['owner'] -+ self.obj._fill_owners(result) - - if hostname: - # If we have a hostname we want to verify that the subject -@@ -984,36 +993,171 @@ class cert_find(Search, CertMethod): - label=owner.object_name, - ) - -- def execute(self, criteria=None, all=False, raw=False, pkey_only=False, -- no_members=True, timelimit=None, sizelimit=None, **options): -- ca_options = {'cacn', -- 'revocation_reason', -- 'issuer', -- 'subject', -- 'min_serial_number', 'max_serial_number', -- 'exactly', -- 'validnotafter_from', 'validnotafter_to', -- 'validnotbefore_from', 'validnotbefore_to', -- 'issuedon_from', 'issuedon_to', -- 'revokedon_from', 'revokedon_to'} -- ldap_options = {prefix + owner.name -- for owner in self.obj._owners() -- for prefix in ('', 'no_')} -- has_ca_options = ( -- any(name in options for name in ca_options - {'exactly'}) or -- options['exactly']) -- has_ldap_options = any(name in options for name in ldap_options) -- has_cert_option = 'certificate' in options -+ def _get_cert_key(self, cert): -+ nss_cert = x509.load_certificate(cert, x509.DER) -+ -+ return (DN(unicode(nss_cert.issuer)), nss_cert.serial_number) -+ -+ def _get_cert_obj(self, cert, all, raw, pkey_only): -+ obj = {'certificate': unicode(base64.b64encode(cert))} -+ -+ full = not pkey_only and all -+ if not raw: -+ self.obj._parse(obj, full) -+ if not full: -+ del obj['certificate'] -+ -+ return obj -+ -+ def _cert_search(self, all, raw, pkey_only, **options): -+ result = collections.OrderedDict() -+ -+ try: -+ cert = options['certificate'] -+ except KeyError: -+ return result, False, False -+ -+ key = self._get_cert_key(cert) -+ -+ result[key] = self._get_cert_obj(cert, all, raw, pkey_only) -+ -+ return result, False, True -+ -+ def _ca_search(self, all, raw, pkey_only, sizelimit, exactly, **options): -+ ra_options = {} -+ for name in ('revocation_reason', -+ 'issuer', -+ 'subject', -+ 'min_serial_number', 'max_serial_number', -+ 'validnotafter_from', 'validnotafter_to', -+ 'validnotbefore_from', 'validnotbefore_to', -+ 'issuedon_from', 'issuedon_to', -+ 'revokedon_from', 'revokedon_to'): -+ try: -+ value = options[name] -+ except KeyError: -+ continue -+ if isinstance(value, datetime.datetime): -+ value = value.strftime(PKIDATE_FORMAT) -+ elif isinstance(value, DN): -+ value = unicode(value) -+ ra_options[name] = value -+ if sizelimit: -+ ra_options['sizelimit'] = sizelimit -+ if exactly: -+ ra_options['exactly'] = True -+ -+ result = collections.OrderedDict() -+ complete = bool(ra_options) - - try: - ca_enabled_check() - except errors.NotFound: -- if has_ca_options: -+ if ra_options: - raise -- ca_enabled = False -+ return result, False, complete -+ -+ ra = self.api.Backend.ra -+ for ra_obj in ra.find(ra_options): -+ issuer = DN(ra_obj['issuer']) -+ serial_number = ra_obj['serial_number'] -+ -+ if pkey_only: -+ obj = {'serial_number': serial_number} -+ else: -+ obj = ra_obj -+ obj['issuer'] = issuer -+ obj['subject'] = DN(ra_obj['subject']) -+ del obj['serial_number_hex'] -+ -+ if all: -+ ra_obj = ra.get_certificate(str(serial_number)) -+ if not raw: -+ obj['certificate'] = ( -+ ra_obj['certificate'].replace('\r\n', '')) -+ self.obj._parse(obj) -+ -+ result[issuer, serial_number] = obj -+ -+ return result, False, complete -+ -+ def _ldap_search(self, all, raw, pkey_only, no_members, timelimit, -+ sizelimit, **options): -+ ldap = self.api.Backend.ldap2 -+ -+ filters = [] -+ for owner in self.obj._owners(): -+ for prefix, rule in (('', ldap.MATCH_ALL), -+ ('no_', ldap.MATCH_NONE)): -+ try: -+ value = options[prefix + owner.name] -+ except KeyError: -+ continue -+ -+ filter = ldap.make_filter_from_attr( -+ 'objectclass', -+ owner.object_class, -+ ldap.MATCH_ALL) -+ if filter not in filters: -+ filters.append(filter) -+ -+ filter = ldap.make_filter_from_attr( -+ owner.primary_key.name, -+ value, -+ rule) -+ filters.append(filter) -+ -+ cert = options.get('certificate') -+ if cert is not None: -+ filter = ldap.make_filter_from_attr('usercertificate', cert) -+ filters.append(filter) -+ -+ result = collections.OrderedDict() -+ complete = bool(filters) -+ -+ if cert is None: -+ filter = '(usercertificate=*)' -+ filters.append(filter) -+ -+ filter = ldap.combine_filters(filters, ldap.MATCH_ALL) -+ try: -+ entries, truncated = ldap.find_entries( -+ base_dn=self.api.env.basedn, -+ filter=filter, -+ attrs_list=['usercertificate'], -+ time_limit=timelimit, -+ size_limit=sizelimit, -+ ) -+ except errors.EmptyResult: -+ entries = [] -+ truncated = False - else: -- ca_enabled = True -+ truncated = bool(truncated) -+ -+ for entry in entries: -+ for attr in ('usercertificate', 'usercertificate;binary'): -+ for cert in entry.get(attr, []): -+ key = self._get_cert_key(cert) -+ -+ try: -+ obj = result[key] -+ except KeyError: -+ obj = self._get_cert_obj(cert, all, raw, pkey_only) -+ result[key] = obj - -+ if not pkey_only and (all or not no_members): -+ owners = obj.setdefault('owner', []) -+ if entry.dn not in owners: -+ owners.append(entry.dn) -+ -+ if not raw: -+ for obj in six.itervalues(result): -+ self.obj._fill_owners(obj) -+ -+ return result, truncated, complete -+ -+ def execute(self, criteria=None, all=False, raw=False, pkey_only=False, -+ no_members=True, timelimit=None, sizelimit=None, **options): - if 'cacn' in options: - ca_obj = api.Command.ca_show(options['cacn'])['result'] - ca_sdn = unicode(ca_obj['ipacasubjectdn'][0]) -@@ -1028,153 +1172,43 @@ class cert_find(Search, CertMethod): - if criteria is not None: - return dict(result=[], count=0, truncated=False) - -- obj_seq = [] -- obj_dict = {} -+ result = collections.OrderedDict() - truncated = False -- -- if has_cert_option: -- cert = options['certificate'] -- obj = {'certificate': unicode(base64.b64encode(cert))} -- obj_seq.append(obj) -- obj_dict[cert] = obj -- -- if ca_enabled: -- ra_options = {} -- for name, value in options.items(): -- if name not in ca_options: -- continue -- if isinstance(value, datetime.datetime): -- value = value.strftime(PKIDATE_FORMAT) -- elif isinstance(value, DN): -- value = unicode(value) -- ra_options[name] = value -- if sizelimit is not None: -- if sizelimit != 0: -- ra_options['sizelimit'] = sizelimit -- sizelimit = 0 -- has_ca_options = True -- -- for ra_obj in self.Backend.ra.find(ra_options): -- obj = {} -- if ((not pkey_only and all) or -- not no_members or -- not has_ca_options or -- has_ldap_options or -- has_cert_option): -- ra_obj.update( -- self.Backend.ra.get_certificate( -- str(ra_obj['serial_number']))) -- cert = base64.b64decode(ra_obj['certificate']) -- try: -- obj = obj_dict[cert] -- except KeyError: -- if has_cert_option: -- continue -- obj = {} -- obj_seq.append(obj) -- obj_dict[cert] = obj -+ complete = False -+ -+ for sub_search in (self._cert_search, -+ self._ca_search, -+ self._ldap_search): -+ sub_result, sub_truncated, sub_complete = sub_search( -+ all=all, -+ raw=raw, -+ pkey_only=pkey_only, -+ no_members=no_members, -+ timelimit=timelimit, -+ sizelimit=sizelimit, -+ **options) -+ -+ if sub_complete: -+ sizelimit = None -+ -+ for key in tuple(result): -+ if key not in sub_result: -+ del result[key] -+ -+ for key, sub_obj in six.iteritems(sub_result): -+ try: -+ obj = result[key] -+ except KeyError: -+ if complete: -+ continue -+ result[key] = sub_obj - else: -- obj_seq.append(obj) -- obj.update(ra_obj) -- -- if ((not pkey_only and all) or -- not no_members or -- not has_ca_options or -- has_ldap_options or -- has_cert_option): -- ldap = self.api.Backend.ldap2 -+ obj.update(sub_obj) - -- filters = [] -- if 'certificate' in options: -- cert_filter = ldap.make_filter_from_attr( -- 'usercertificate', options['certificate']) -- else: -- cert_filter = '(usercertificate=*)' -- filters.append(cert_filter) -- for owner in self.obj._owners(): -- oc_filter = ldap.make_filter_from_attr( -- 'objectclass', owner.object_class, ldap.MATCH_ALL) -- for prefix, rule in (('', ldap.MATCH_ALL), -- ('no_', ldap.MATCH_NONE)): -- value = options.get(prefix + owner.name) -- if value is None: -- continue -- pkey_filter = ldap.make_filter_from_attr( -- owner.primary_key.name, value, rule) -- filters.append(oc_filter) -- filters.append(pkey_filter) -- filter = ldap.combine_filters(filters, ldap.MATCH_ALL) -+ truncated = truncated or sub_truncated -+ complete = complete or sub_complete - -- try: -- entries, truncated = ldap.find_entries( -- base_dn=self.api.env.basedn, -- filter=filter, -- attrs_list=['usercertificate'], -- time_limit=timelimit, -- size_limit=sizelimit, -- ) -- except errors.EmptyResult: -- entries, truncated = [], False -- for entry in entries: -- seen = set() -- for attr in ('usercertificate', 'usercertificate;binary'): -- for cert in entry.get(attr, []): -- if cert in seen: -- continue -- seen.add(cert) -- try: -- obj = obj_dict[cert] -- except KeyError: -- if has_ca_options or has_cert_option: -- continue -- obj = { -- 'certificate': unicode(base64.b64encode(cert))} -- obj_seq.append(obj) -- obj_dict[cert] = obj -- obj.setdefault('owner', []).append(entry.dn) -- -- result = [] -- for obj in obj_seq: -- if has_ldap_options and 'owner' not in obj: -- continue -- if not pkey_only: -- if not raw: -- if 'certificate' in obj: -- obj['certificate'] = ( -- obj['certificate'].replace('\r\n', '')) -- self.obj._parse(obj) -- if not all: -- del obj['certificate'] -- del obj['valid_not_before'] -- del obj['valid_not_after'] -- del obj['md5_fingerprint'] -- del obj['sha1_fingerprint'] -- if 'subject' in obj: -- obj['subject'] = DN(obj['subject']) -- if 'issuer' in obj: -- obj['issuer'] = DN(obj['issuer']) -- if 'status' in obj: -- obj['revoked'] = ( -- obj['status'] in (u'REVOKED', u'REVOKED_EXPIRED')) -- if 'owner' in obj: -- if all or not no_members: -- self.obj._fill_owners(obj) -- del obj['owner'] -- else: -- if 'certificate' in obj: -- if not all: -- del obj['certificate'] -- if 'owner' in obj: -- if not all and no_members: -- del obj['owner'] -- else: -- if 'serial_number' in obj: -- serial_number = obj['serial_number'] -- obj.clear() -- obj['serial_number'] = serial_number -- else: -- obj.clear() -- result.append(obj) -+ result = list(six.itervalues(result)) - - ret = dict( - result=result --- -2.7.4 - diff --git a/SOURCES/0070-cert-do-not-crash-on-invalid-data-in-cert-find.patch b/SOURCES/0070-cert-do-not-crash-on-invalid-data-in-cert-find.patch deleted file mode 100644 index d1dba4e..0000000 --- a/SOURCES/0070-cert-do-not-crash-on-invalid-data-in-cert-find.patch +++ /dev/null @@ -1,81 +0,0 @@ -From adb6802b1b4dec30f19c3bf76089b6bc60ac0454 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 1 Aug 2016 09:55:58 +0200 -Subject: [PATCH] cert: do not crash on invalid data in cert-find - -https://fedorahosted.org/freeipa/ticket/6150 - -Reviewed-By: Martin Basti -Reviewed-By: Pavel Vomacka ---- - ipaserver/plugins/cert.py | 28 ++++++++++++++++++++++++---- - 1 file changed, 24 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 47dccf15a4010f2766642aedd2cc16e0a1eb1dd4..b8df074a186ca91daa8e8f5e725724ea7bc5a663 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -32,7 +32,7 @@ import six - - from ipalib import Command, Str, Int, Flag - from ipalib import api --from ipalib import errors -+from ipalib import errors, messages - from ipalib import pkcs10 - from ipalib import x509 - from ipalib import ngettext -@@ -994,7 +994,15 @@ class cert_find(Search, CertMethod): - ) - - def _get_cert_key(self, cert): -- nss_cert = x509.load_certificate(cert, x509.DER) -+ try: -+ nss_cert = x509.load_certificate(cert, x509.DER) -+ except NSPRError as e: -+ message = messages.SearchResultTruncated( -+ reason=_("failed to load certificate: %s") % e, -+ ) -+ self.add_message(message) -+ -+ raise ValueError("failed to load certificate") - - return (DN(unicode(nss_cert.issuer)), nss_cert.serial_number) - -@@ -1017,7 +1025,10 @@ class cert_find(Search, CertMethod): - except KeyError: - return result, False, False - -- key = self._get_cert_key(cert) -+ try: -+ key = self._get_cert_key(cert) -+ except ValueError: -+ return result, True, True - - result[key] = self._get_cert_obj(cert, all, raw, pkey_only) - -@@ -1132,12 +1143,21 @@ class cert_find(Search, CertMethod): - entries = [] - truncated = False - else: -+ try: -+ ldap.handle_truncated_result(truncated) -+ except errors.LimitsExceeded as e: -+ self.add_message(messages.SearchResultTruncated(reason=e)) -+ - truncated = bool(truncated) - - for entry in entries: - for attr in ('usercertificate', 'usercertificate;binary'): - for cert in entry.get(attr, []): -- key = self._get_cert_key(cert) -+ try: -+ key = self._get_cert_key(cert) -+ except ValueError: -+ truncated = True -+ continue - - try: - obj = result[key] --- -2.7.4 - diff --git a/SOURCES/0070-dsinstance-reconnect-ldap2-after-DS-is-restarted-by-.patch b/SOURCES/0070-dsinstance-reconnect-ldap2-after-DS-is-restarted-by-.patch new file mode 100644 index 0000000..0e7a34c --- /dev/null +++ b/SOURCES/0070-dsinstance-reconnect-ldap2-after-DS-is-restarted-by-.patch @@ -0,0 +1,53 @@ +From f6ecef4bdf8f5f99c89c0649232a230c28191869 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Fri, 7 Apr 2017 07:40:19 +0200 +Subject: [PATCH] dsinstance: reconnect ldap2 after DS is restarted by + certmonger + +DS is restarted by certmonger in the restart_dirsrv script after the DS +certificate is saved. This breaks the ldap2 backend and makes any operation +fail with NetworkError until it is reconnected. + +Reconnect ldap2 after the DS certificate request is finished to fix the +issue. Make sure restart_dirsrv waits for the ldapi socket so that the +reconnect does not fail. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Martin Babinsky +--- + install/restart_scripts/restart_dirsrv | 2 +- + ipaserver/install/dsinstance.py | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/install/restart_scripts/restart_dirsrv b/install/restart_scripts/restart_dirsrv +index b4c9490c10506aba60eee16c3f46ee7cb0474f50..ff476cac46f76d4964d39b12c04401dfc19c2d3a 100644 +--- a/install/restart_scripts/restart_dirsrv ++++ b/install/restart_scripts/restart_dirsrv +@@ -41,7 +41,7 @@ def _main(): + + try: + if services.knownservices.dirsrv.is_running(): +- services.knownservices.dirsrv.restart(instance) ++ services.knownservices.dirsrv.restart(instance, ldapi=True) + except Exception as e: + syslog.syslog(syslog.LOG_ERR, "Cannot restart dirsrv (instance: '%s'): %s" % (instance, str(e))) + +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 79dc90e92cac49a2b64ff6645f75dc3a8cbcc104..fb5f925de8e658dca9370714413012527f00c39d 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -837,6 +837,10 @@ class DsInstance(service.Service): + finally: + certmonger.modify_ca_helper('IPA', prev_helper) + ++ # restart_dirsrv in the request above restarts DS, reconnect ldap2 ++ api.Backend.ldap2.disconnect() ++ api.Backend.ldap2.connect() ++ + self.dercert = dsdb.get_cert_from_db(self.nickname, pem=False) + + dsdb.create_pin_file() +-- +2.9.3 + diff --git a/SOURCES/0071-Add-warning-about-only-one-existing-CA-server.patch b/SOURCES/0071-Add-warning-about-only-one-existing-CA-server.patch deleted file mode 100644 index 2526f30..0000000 --- a/SOURCES/0071-Add-warning-about-only-one-existing-CA-server.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 7767a6befe2cc461cd6b8aadff1626108e3101b0 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Tue, 16 Aug 2016 10:03:36 +0200 -Subject: [PATCH] Add warning about only one existing CA server - -It is not safe to have only one CA server in topology. Therefore there is a check -and in case that there is only one CA server a warning is shown. The warning is -shown after each refreshing of servers facet. - -https://fedorahosted.org/freeipa/ticket/5828 - -Reviewed-By: Tomas Krizek ---- - install/ui/src/freeipa/topology.js | 73 +++++++++++++++++++++++++++++++++++++- - install/ui/test/data/ipa_init.json | 2 ++ - ipaserver/plugins/internal.py | 2 ++ - 3 files changed, 76 insertions(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/topology.js b/install/ui/src/freeipa/topology.js -index 7e501eb3506587ea653497d2806938890066e4f0..c33adba9a3c704b66b85689dd18e927ab975d2fe 100644 ---- a/install/ui/src/freeipa/topology.js -+++ b/install/ui/src/freeipa/topology.js -@@ -28,13 +28,14 @@ define([ - './facets/Facet', - './topology_graph', - './navigation', -+ './widget', - // plain imports - './search', - './entity'], - function(lang, declare, Evented, Stateful, Deferred, on, all, when, - builder, IPA, $, menu, metadata_provider, phases, reg, rpc, - text, mod_details, mod_facet, mod_field, ActionMixin, -- HeaderMixin, Facet, topology_graph, navigation) { -+ HeaderMixin, Facet, topology_graph, navigation, widget_mod) { - /** - * Topology module - * @class -@@ -206,6 +207,7 @@ return { - facets: [ - { - $type: 'search', -+ $factory: topology.servers_search_facet, - no_update: true, - disable_facet_tabs: false, - tabs_in_sidebar: true, -@@ -483,6 +485,75 @@ topology.location_adapter = declare([mod_field.Adapter], { - } - }); - -+topology.servers_search_facet = function(spec, no_init) { -+ spec = spec || {}; -+ -+ var that = IPA.search_facet(spec); -+ -+ that.create_get_records_command = function(pkeys, on_success, on_error) { -+ -+ var on_success_extended = function(data, text_status, xhr) { -+ // Call original on_success handler -+ on_success(data, text_status, xhr); -+ -+ var result = data.result.results; -+ var counter = 0; -+ -+ for (var i=0, l=result.length; i +Date: Fri, 7 Apr 2017 07:40:41 +0200 +Subject: [PATCH] httpinstance: avoid httpd restart during certificate request + +httpd is restarted by certmonger in the restart_httpd script after the +httpd certificate is saved if it was previously running. The restart will +fail because httpd is not properly configured at this point. + +Stop httpd at the beginning of httpd install to avoid the restart. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/httpinstance.py | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 079ea92606cc53f98beca1759a7e24db64bfd3f4..d7cd776ab9831b5408797ae41b7c7fbb10707b18 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -160,6 +160,7 @@ class HTTPInstance(service.Service): + self.ca_is_configured = ca_is_configured + self.promote = promote + ++ self.step("stopping httpd", self.__stop) + self.step("setting mod_nss port to 443", self.__set_mod_nss_port) + self.step("setting mod_nss cipher suite", + self.set_mod_nss_cipher_suite) +@@ -185,15 +186,15 @@ class HTTPInstance(service.Service): + self.step("create KDC proxy user", create_kdcproxy_user) + self.step("create KDC proxy config", self.create_kdcproxy_conf) + self.step("enable KDC proxy", self.enable_kdcproxy) +- self.step("restarting httpd", self.__start) ++ self.step("starting httpd", self.start) + self.step("configuring httpd to start on boot", self.__enable) + self.step("enabling oddjobd", self.enable_and_start_oddjobd) + + self.start_creation() + +- def __start(self): ++ def __stop(self): + self.backup_state("running", self.is_running()) +- self.restart() ++ self.stop() + + def __enable(self): + self.backup_state("enabled", self.is_enabled()) +-- +2.9.3 + diff --git a/SOURCES/0072-Set-servers-list-as-default-facet-in-topology-facet-.patch b/SOURCES/0072-Set-servers-list-as-default-facet-in-topology-facet-.patch deleted file mode 100644 index a19800c..0000000 --- a/SOURCES/0072-Set-servers-list-as-default-facet-in-topology-facet-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 9f684d883f21747ba413bf456cca114e67c1e53a Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Tue, 16 Aug 2016 10:06:28 +0200 -Subject: [PATCH] Set servers list as default facet in topology facet group - -Since there is a new warning about only one CA server, the default facet -of topology facet group is set to servers list where the warning is. -So the warning will be shown right after clicking on Topology section. - -Part of: https://fedorahosted.org/freeipa/ticket/5828 - -Reviewed-By: Tomas Krizek ---- - install/ui/src/freeipa/navigation/menu_spec.js | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/navigation/menu_spec.js b/install/ui/src/freeipa/navigation/menu_spec.js -index 108f4577f7e1326b9c9bc495c54f6e1f12a0cce6..1abd7204f9d7cc2f6e9f840eb026ea78841ce438 100644 ---- a/install/ui/src/freeipa/navigation/menu_spec.js -+++ b/install/ui/src/freeipa/navigation/menu_spec.js -@@ -212,7 +212,7 @@ var nav = {}; - ] - }, - { -- entity: 'topologysuffix', -+ entity: 'server', - label: '@i18n:tabs.topology', - facet: 'search', - children: [ --- -2.7.4 - diff --git a/SOURCES/0072-dsinstance-httpinstance-consolidate-certificate-requ.patch b/SOURCES/0072-dsinstance-httpinstance-consolidate-certificate-requ.patch new file mode 100644 index 0000000..9c7a67f --- /dev/null +++ b/SOURCES/0072-dsinstance-httpinstance-consolidate-certificate-requ.patch @@ -0,0 +1,289 @@ +From 2409b5204101cceafb28289db0d99c1474ee2430 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Fri, 7 Apr 2017 07:43:09 +0200 +Subject: [PATCH] dsinstance, httpinstance: consolidate certificate request + code + +A different code path is used for DS and httpd certificate requests in +replica promotion. This is rather unnecessary and makes the certificate +request code not easy to follow. + +Consolidate the non-promotion and promotion code paths into one. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/dsinstance.py | 76 +++++++++--------------------- + ipaserver/install/httpinstance.py | 40 ++++++++-------- + ipaserver/install/server/install.py | 4 -- + ipaserver/install/server/replicainstall.py | 22 +-------- + 4 files changed, 43 insertions(+), 99 deletions(-) + +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index fb5f925de8e658dca9370714413012527f00c39d..31dbd4ec8bcaf4a7545b4f9f316fe609b845cb75 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -396,10 +396,7 @@ class DsInstance(service.Service): + + self.step("creating DS keytab", self.request_service_keytab) + if self.promote: +- if self.pkcs12_info: +- self.step("configuring TLS for DS instance", self.__enable_ssl) +- else: +- self.step("retrieving DS Certificate", self.__get_ds_cert) ++ self.step("configuring TLS for DS instance", self.__enable_ssl) + self.step("restarting directory server", self.__restart_instance) + + self.step("setting up initial replication", self.__setup_replica) +@@ -810,18 +807,23 @@ class DsInstance(service.Service): + dsdb.track_server_cert( + self.nickname, self.principal, dsdb.passwd_fname, + 'restart_dirsrv %s' % self.serverid) ++ ++ self.add_cert_to_service() + else: + dsdb.create_from_cacert() +- ca_args = [ +- paths.CERTMONGER_DOGTAG_SUBMIT, +- '--ee-url', 'https://%s:8443/ca/ee/ca' % self.fqdn, +- '--certfile', paths.RA_AGENT_PEM, +- '--keyfile', paths.RA_AGENT_KEY, +- '--cafile', paths.IPA_CA_CRT, +- '--agent-submit' +- ] +- helper = " ".join(ca_args) +- prev_helper = certmonger.modify_ca_helper('IPA', helper) ++ if self.master_fqdn is None: ++ ca_args = [ ++ paths.CERTMONGER_DOGTAG_SUBMIT, ++ '--ee-url', 'https://%s:8443/ca/ee/ca' % self.fqdn, ++ '--certfile', paths.RA_AGENT_PEM, ++ '--keyfile', paths.RA_AGENT_KEY, ++ '--cafile', paths.IPA_CA_CRT, ++ '--agent-submit' ++ ] ++ helper = " ".join(ca_args) ++ prev_helper = certmonger.modify_ca_helper('IPA', helper) ++ else: ++ prev_helper = None + try: + cmd = 'restart_dirsrv %s' % self.serverid + certmonger.request_and_wait_for_cert( +@@ -835,7 +837,8 @@ class DsInstance(service.Service): + dns=[self.fqdn], + post_command=cmd) + finally: +- certmonger.modify_ca_helper('IPA', prev_helper) ++ if prev_helper is not None: ++ certmonger.modify_ca_helper('IPA', prev_helper) + + # restart_dirsrv in the request above restarts DS, reconnect ldap2 + api.Backend.ldap2.disconnect() +@@ -843,6 +846,9 @@ class DsInstance(service.Service): + + self.dercert = dsdb.get_cert_from_db(self.nickname, pem=False) + ++ if prev_helper is not None: ++ self.add_cert_to_service() ++ + dsdb.create_pin_file() + + self.cacert_name = dsdb.cacert_name +@@ -1236,46 +1242,6 @@ class DsInstance(service.Service): + ipautil.config_replace_variables(paths.SYSCONFIG_DIRSRV, + replacevars=vardict) + +- def __get_ds_cert(self): +- nssdb_dir = config_dirname(self.serverid) +- db = certs.CertDB( +- self.realm, +- nssdir=nssdb_dir, +- subject_base=self.subject_base, +- ca_subject=self.ca_subject, +- ) +- db.create_from_cacert() +- db.request_service_cert(self.nickname, self.principal, self.fqdn) +- db.create_pin_file() +- +- # Connect to self over ldapi as Directory Manager and configure SSL +- ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=self.realm) +- conn = ipaldap.LDAPClient(ldap_uri) +- conn.external_bind() +- +- mod = [(ldap.MOD_REPLACE, "nsSSLClientAuth", "allowed"), +- (ldap.MOD_REPLACE, "nsSSL3Ciphers", "default"), +- (ldap.MOD_REPLACE, "allowWeakCipher", "off")] +- conn.modify_s(DN(('cn', 'encryption'), ('cn', 'config')), mod) +- +- mod = [(ldap.MOD_ADD, "nsslapd-security", "on")] +- conn.modify_s(DN(('cn', 'config')), mod) +- +- entry = conn.make_entry( +- DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')), +- objectclass=["top", "nsEncryptionModule"], +- cn=["RSA"], +- nsSSLPersonalitySSL=[self.nickname], +- nsSSLToken=["internal (software)"], +- nsSSLActivation=["on"], +- ) +- conn.add_entry(entry) +- +- conn.unbind() +- +- # check for open secure port 636 from now on +- self.open_ports.append(636) +- + + def write_certmap_conf(realm, ca_subject): + """(Re)write certmap.conf with given CA subject DN.""" +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index d7cd776ab9831b5408797ae41b7c7fbb10707b18..45bf479d1088c3b3396d955bf2592c4bce1e886f 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -376,12 +376,12 @@ class HTTPInstance(service.Service): + return False + + def __setup_ssl(self): +- truncate = not self.promote or not self.ca_is_configured + db = certs.CertDB(self.realm, nssdir=paths.HTTPD_ALIAS_DIR, + subject_base=self.subject_base, user="root", + group=constants.HTTPD_GROUP, +- truncate=truncate) ++ truncate=True) + self.disable_system_trust() ++ self.create_password_conf() + if self.pkcs12_info: + if self.ca_is_configured: + trust_flags = 'CT,C,C' +@@ -394,8 +394,6 @@ class HTTPInstance(service.Service): + if len(server_certs) == 0: + raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0]) + +- self.create_password_conf() +- + # We only handle one server cert + nickname = server_certs[0][0] + if nickname == 'ipaCert': +@@ -410,7 +408,6 @@ class HTTPInstance(service.Service): + + else: + if not self.promote: +- self.create_password_conf() + ca_args = [ + paths.CERTMONGER_DOGTAG_SUBMIT, + '--ee-url', 'https://%s:8443/ca/ee/ca' % self.fqdn, +@@ -421,23 +418,26 @@ class HTTPInstance(service.Service): + ] + helper = " ".join(ca_args) + prev_helper = certmonger.modify_ca_helper('IPA', helper) +- +- try: +- certmonger.request_and_wait_for_cert( +- certpath=db.secdir, +- nickname=self.cert_nickname, +- principal=self.principal, +- passwd_fname=db.passwd_fname, +- subject=str(DN(('CN', self.fqdn), self.subject_base)), +- ca='IPA', +- profile=dogtag.DEFAULT_PROFILE, +- dns=[self.fqdn], +- post_command='restart_httpd') +- self.dercert = db.get_cert_from_db( +- self.cert_nickname, pem=False) +- finally: ++ else: ++ prev_helper = None ++ try: ++ certmonger.request_and_wait_for_cert( ++ certpath=db.secdir, ++ nickname=self.cert_nickname, ++ principal=self.principal, ++ passwd_fname=db.passwd_fname, ++ subject=str(DN(('CN', self.fqdn), self.subject_base)), ++ ca='IPA', ++ profile=dogtag.DEFAULT_PROFILE, ++ dns=[self.fqdn], ++ post_command='restart_httpd') ++ finally: ++ if prev_helper is not None: + certmonger.modify_ca_helper('IPA', prev_helper) + ++ self.dercert = db.get_cert_from_db(self.cert_nickname, pem=False) ++ ++ if prev_helper is not None: + self.add_cert_to_service() + + # Verify we have a valid server cert +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index d7eb0bfacd0815026c82f59d76962f527e2b7dad..f8e64ec26e85bbc6218018eec8f403a0567b45a2 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -807,10 +807,6 @@ def install(installer): + if setup_ca: + ca.install_step_1(False, None, options) + +- # The DS instance is created before the keytab, add the SSL cert we +- # generated +- ds.add_cert_to_service() +- + otpd = otpdinstance.OtpdInstance() + otpd.create_instance('OTPD', host_name, + ipautil.realm_to_suffix(realm_name)) +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index f489e691999fd9d6e82879341922510e56eac47d..cd6a62f9540f4a46da70e0cc5686eff5f54e7dfe 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -27,7 +27,6 @@ from ipapython.dn import DN + from ipapython.ipa_log_manager import root_logger + from ipapython.admintool import ScriptError + from ipaplatform import services +-from ipaplatform.constants import constants as pconstants + from ipaplatform.tasks import tasks + from ipaplatform.paths import paths + from ipalib import api, constants, create_api, errors, rpc, x509 +@@ -77,18 +76,6 @@ def make_pkcs12_info(directory, cert_name, password_name): + return None + + +-def install_http_certs(host_name, realm_name, subject_base): +- principal = 'HTTP/%s@%s' % (host_name, realm_name) +- subject = subject_base or DN(('O', realm_name)) +- db = certs.CertDB(realm_name, nssdir=paths.HTTPD_ALIAS_DIR, +- subject_base=subject, user="root", +- group=pconstants.HTTPD_GROUP, truncate=True) +- db.request_service_cert('Server-Cert', principal, host_name) +- # Obtain certificate for the HTTP service +- http = httpinstance.HTTPInstance() +- http.create_password_conf() +- +- + def install_replica_ds(config, options, ca_is_configured, remote_api, + ca_file, promote=False, pkcs12_info=None): + dsinstance.check_ports() +@@ -175,7 +162,8 @@ def install_http(config, auto_redirect, ca_is_configured, ca_file, + http.create_instance( + config.realm_name, config.host_name, config.domain_name, + pkcs12_info, auto_redirect=auto_redirect, ca_file=ca_file, +- ca_is_configured=ca_is_configured, promote=promote) ++ ca_is_configured=ca_is_configured, promote=promote, ++ subject_base=config.subject_base) + + return http + +@@ -1414,12 +1402,6 @@ def install(installer): + # Always try to install DNS records + install_dns_records(config, options, remote_api) + +- if promote and ca_enabled: +- # we need to install http certs to setup ssl for httpd +- install_http_certs(config.host_name, +- config.realm_name, +- config.subject_base) +- + ntpinstance.ntp_ldap_enable(config.host_name, ds.suffix, + remote_api.env.realm) + finally: +-- +2.9.3 + diff --git a/SOURCES/0073-install-request-service-certs-after-host-keytab-is-s.patch b/SOURCES/0073-install-request-service-certs-after-host-keytab-is-s.patch new file mode 100644 index 0000000..45e18e6 --- /dev/null +++ b/SOURCES/0073-install-request-service-certs-after-host-keytab-is-s.patch @@ -0,0 +1,135 @@ +From acb04249a77f62f72179899223bfeacdd2292883 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Fri, 7 Apr 2017 07:44:21 +0200 +Subject: [PATCH] install: request service certs after host keytab is set up + +The certmonger renew agent and restart scripts use host keytab for +authentication. When they are executed during a certmonger request before +the host keytab is set up, the authentication will fail. + +Make sure all certmonger requests in the installer are done after the host +keytab is set up. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/dsinstance.py | 17 +++++++---------- + ipaserver/install/server/install.py | 18 +++++++----------- + ipaserver/install/server/replicainstall.py | 5 ++--- + 3 files changed, 16 insertions(+), 24 deletions(-) + +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 31dbd4ec8bcaf4a7545b4f9f316fe609b845cb75..72fcb65f2eb699d0077d3c5cc02a3fcaaad9b8e5 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -256,7 +256,7 @@ class DsInstance(service.Service): + + subject_base = ipautil.dn_attribute_property('_subject_base') + +- def __common_setup(self, enable_ssl=False): ++ def __common_setup(self): + + self.step("creating directory server user", create_ds_user) + self.step("creating directory server instance", self.__create_instance) +@@ -279,8 +279,6 @@ class DsInstance(service.Service): + self.step("configuring topology plugin", self.__config_topology_module) + self.step("creating indices", self.__create_indices) + self.step("enabling referential integrity plugin", self.__add_referint_module) +- if enable_ssl: +- self.step("configuring TLS for DS instance", self.__enable_ssl) + self.step("configuring certmap.conf", self.__certmap_conf) + self.step("configure new location for managed entries", self.__repoint_managed_entries) + self.step("configure dirsrv ccache", self.configure_dirsrv_ccache) +@@ -356,8 +354,12 @@ class DsInstance(service.Service): + self.steps = [] + + self.step("configuring TLS for DS instance", self.__enable_ssl) ++ if self.master_fqdn is None: ++ self.step("adding CA certificate entry", self.__upload_ca_cert) ++ else: ++ self.step("importing CA certificates from LDAP", ++ self.__import_ca_certs) + self.step("restarting directory server", self.__restart_instance) +- self.step("adding CA certificate entry", self.__upload_ca_cert) + + self.start_creation() + +@@ -391,21 +393,16 @@ class DsInstance(service.Service): + self.promote = promote + self.api = api + +- self.__common_setup(enable_ssl=(not self.promote)) ++ self.__common_setup() + self.step("restarting directory server", self.__restart_instance) + + self.step("creating DS keytab", self.request_service_keytab) +- if self.promote: +- self.step("configuring TLS for DS instance", self.__enable_ssl) +- self.step("restarting directory server", self.__restart_instance) +- + self.step("setting up initial replication", self.__setup_replica) + self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) + self.step("updating schema", self.__update_schema) + # See LDIFs for automember configuration during replica install + self.step("setting Auto Member configuration", self.__add_replica_automember_config) + self.step("enabling S4U2Proxy delegation", self.__setup_s4u2proxy) +- self.step("importing CA certificates from LDAP", self.__import_ca_certs) + + self.__common_post_setup() + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index f8e64ec26e85bbc6218018eec8f403a0567b45a2..bf2e248dceaae36ba0030d3eaa47976f51ce60ba 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -770,6 +770,13 @@ def install(installer): + realm_name, host_name, domain_name, dm_password, + options.subject_base, options.ca_subject, 1101, 1100, None) + ++ krb = krbinstance.KrbInstance(fstore) ++ krb.create_instance(realm_name, host_name, domain_name, ++ dm_password, master_password, ++ setup_pkinit=not options.no_pkinit, ++ pkcs12_info=pkinit_pkcs12_info, ++ subject_base=options.subject_base) ++ + if setup_ca: + if not options.external_cert_files and options.external_ca: + # stage 1 of external CA installation +@@ -793,17 +800,6 @@ def install(installer): + # we now need to enable ssl on the ds + ds.enable_ssl() + +- krb = krbinstance.KrbInstance(fstore) +- krb.create_instance(realm_name, host_name, domain_name, +- dm_password, master_password, +- setup_pkinit=not options.no_pkinit, +- pkcs12_info=pkinit_pkcs12_info, +- subject_base=options.subject_base) +- +- # restart DS to enable ipa-pwd-extop plugin +- print("Restarting directory server to enable password extension plugin") +- ds.restart() +- + if setup_ca: + ca.install_step_1(False, None, options) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index cd6a62f9540f4a46da70e0cc5686eff5f54e7dfe..6f1a0d6d29b20d53986205a63382a385e75f80ea 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1422,9 +1422,8 @@ def install(installer): + setup_pkinit=not options.no_pkinit, + promote=promote) + +- # restart DS to enable ipa-pwd-extop plugin +- print("Restarting directory server to enable password extension plugin") +- ds.restart() ++ # we now need to enable ssl on the ds ++ ds.enable_ssl() + + install_http( + config, +-- +2.9.3 + diff --git a/SOURCES/0073-schema-cache-Do-not-reset-ServerInfo-dirty-flag.patch b/SOURCES/0073-schema-cache-Do-not-reset-ServerInfo-dirty-flag.patch deleted file mode 100644 index e283fb8..0000000 --- a/SOURCES/0073-schema-cache-Do-not-reset-ServerInfo-dirty-flag.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 2ee7cd65c678f310154775d69bc0d044b8ad881a Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 4 Aug 2016 16:02:24 +0200 -Subject: [PATCH] schema cache: Do not reset ServerInfo dirty flag - -Once dirty flag is set to True it must not be set back to False. -Otherwise changes are not written back to file. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index 5264d4cc177ba457c517f93f203e0baca7b0ac01..b49ccbb7f7905e2561598d66beca6d8b1d5ed48e 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -401,7 +401,8 @@ class ServerInfo(collections.MutableMapping): - return self._dict[key] - - def __setitem__(self, key, value): -- self._dirty = key not in self._dict or self._dict[key] != value -+ if key not in self._dict or self._dict[key] != value: -+ self._dirty = True - self._dict[key] = value - - def __delitem__(self, key): --- -2.7.4 - diff --git a/SOURCES/0074-renew-agent-revert-to-host-keytab-authentication.patch b/SOURCES/0074-renew-agent-revert-to-host-keytab-authentication.patch new file mode 100644 index 0000000..3dbde6d --- /dev/null +++ b/SOURCES/0074-renew-agent-revert-to-host-keytab-authentication.patch @@ -0,0 +1,53 @@ +From 37ddd26bc4b2f99dfa27b2ad45219290a2f44ec5 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Fri, 7 Apr 2017 07:46:58 +0200 +Subject: [PATCH] renew agent: revert to host keytab authentication + +Fixes an issue where the renew agent uses GSSAPI for LDAP connection but +fails because it is not authenticated. + +This reverts commit 7462adec13c5b25b6868d2863dc38062c97d0ff7. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Martin Babinsky +--- + install/certmonger/dogtag-ipa-ca-renew-agent-submit | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index 5782db703c49d7c2e92c806e24e9925e8e7d710a..3389447a99d9ab9dac159b0d57ca02f60698ce0c 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -40,6 +40,7 @@ from cryptography.hazmat.backends import default_backend + + import six + ++from ipalib.install.kinit import kinit_keytab + from ipapython import ipautil + from ipapython.dn import DN + from ipalib import api, errors, x509 +@@ -132,7 +133,7 @@ def ldap_connect(): + conn = None + try: + conn = ldap2(api) +- conn.connect(autobind=True) ++ conn.connect(ccache=os.environ['KRB5CCNAME']) + yield conn + finally: + if conn is not None and conn.isconnected(): +@@ -526,6 +527,11 @@ def main(): + tmpdir = tempfile.mkdtemp(prefix="tmp-") + certs.renewal_lock.acquire() + try: ++ principal = str('host/%s@%s' % (api.env.host, api.env.realm)) ++ ccache_filename = os.path.join(tmpdir, 'ccache') ++ os.environ['KRB5CCNAME'] = ccache_filename ++ kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename) ++ + profile = os.environ.get('CERTMONGER_CA_PROFILE') + if is_replicated(): + if profile or is_renewal_master(): +-- +2.9.3 + diff --git a/SOURCES/0074-schema-cache-Do-not-read-fingerprint-and-format-from.patch b/SOURCES/0074-schema-cache-Do-not-read-fingerprint-and-format-from.patch deleted file mode 100644 index e7bc841..0000000 --- a/SOURCES/0074-schema-cache-Do-not-read-fingerprint-and-format-from.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 5138ff563b1ac870ecc77485c200d839e17622a8 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 4 Aug 2016 16:07:08 +0200 -Subject: [PATCH] schema cache: Do not read fingerprint and format from cache - -Fingerprint can be obtained from schema filename of from ServerInfo -instance. Use FORMAT in path to avoid openening schema just to read its -format. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 29 +++++------------------------ - 1 file changed, 5 insertions(+), 24 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index b49ccbb7f7905e2561598d66beca6d8b1d5ed48e..c62b74408b448faf794ed9e2b315b03fc1a5a315 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -19,6 +19,7 @@ from ipalib import errors, parameters, plugable - from ipalib.frontend import Object - from ipalib.output import Output - from ipalib.parameters import DefaultFrom, Flag, Password, Str -+from ipapython.ipautil import fsdecode - from ipapython.dn import DN - from ipapython.dnsutil import DNSName - from ipapython.ipa_log_manager import log_mgr -@@ -437,7 +438,7 @@ class Schema(object): - - """ - namespaces = {'classes', 'commands', 'topics'} -- _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema') -+ _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema', FORMAT) - - def __init__(self, api, server_info, client): - self._dict = {} -@@ -483,34 +484,14 @@ class Schema(object): - path = os.path.join(self._DIR, filename) - return _LockedZipFile(path, mode) - -- def _get_schema_fingerprint(self, schema): -- try: -- fmt = json.loads(schema.read('format')) -- except KeyError: -- fmt = '0' -- -- if fmt != FORMAT: -- raise RuntimeError('invalid format') -- -- return json.loads(schema.read('fingerprint')) -- - def _fetch(self, client): - if not client.isconnected(): - client.connect(verbose=False) - -- fps = [] - try: -- files = os.listdir(self._DIR) -+ fps = [fsdecode(f) for f in os.listdir(self._DIR)] - except EnvironmentError: -- pass -- else: -- for filename in files: -- try: -- with self._open_schema(filename, 'r') as schema: -- fps.append( -- unicode(self._get_schema_fingerprint(schema))) -- except Exception: -- continue -+ fps = [] - - kwargs = {u'version': u'2.170'} - if fps: -@@ -537,7 +518,7 @@ class Schema(object): - - def _read_schema(self): - with self._open_schema(self._fingerprint, 'r') as schema: -- self._dict['fingerprint'] = self._get_schema_fingerprint(schema) -+ self._dict['fingerprint'] = self._fingerprint - - for name in schema.namelist(): - ns, _slash, key = name.partition('/') --- -2.7.4 - diff --git a/SOURCES/0075-Access-data-for-help-separately.patch b/SOURCES/0075-Access-data-for-help-separately.patch deleted file mode 100644 index 182c526..0000000 --- a/SOURCES/0075-Access-data-for-help-separately.patch +++ /dev/null @@ -1,121 +0,0 @@ -From e91392536994ce3167a1f025e819926ba6de299f Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 4 Aug 2016 16:14:33 +0200 -Subject: [PATCH] Access data for help separately - -To avoid the need to read all data for a plugin from cache and actualy -use the separately stored help data it must be requested and returned -separately. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 37 ++++++++++++++++++------------------- - 1 file changed, 18 insertions(+), 19 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index c62b74408b448faf794ed9e2b315b03fc1a5a315..c72109ac3bb9b7a71f9cbc056eaf3a4d8371d035 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -114,10 +114,9 @@ class _SchemaPlugin(object): - if self._class is not None: - return self._class.summary - else: -- self._schema.load_help() -- schema = self._schema[self.schema_key][self.full_name] -+ halp = self._schema[self.schema_key].get_help(self.full_name) - try: -- return schema['summary'] -+ return halp['summary'] - except KeyError: - return u'<%s>' % self.full_name - -@@ -244,10 +243,9 @@ class _SchemaCommandPlugin(_SchemaPlugin): - if self._class is not None: - return self._class.topic - else: -- self._schema.load_help() -- schema = self._schema[self.schema_key][self.full_name] -+ halp = self._schema[self.schema_key].get_help(self.full_name) - try: -- return str(schema['topic_topic']).partition('/')[0] -+ return str(halp['topic_topic']).partition('/')[0] - except KeyError: - return None - -@@ -256,9 +254,8 @@ class _SchemaCommandPlugin(_SchemaPlugin): - if self._class is not None: - return self._class.NO_CLI - else: -- self._schema.load_help() -- schema = self._schema[self.schema_key][self.full_name] -- return 'cli' in schema.get('exclude', []) -+ halp = self._schema[self.schema_key].get_help(self.full_name) -+ return 'cli' in halp.get('exclude', []) - - def _create_output(self, api, schema): - if schema.get('multivalue', False): -@@ -355,6 +352,12 @@ class _SchemaNameSpace(collections.Mapping): - def __len__(self): - return len(list(self._schema.iter_namespace(self.name))) - -+ def get_help(self, key): -+ try: -+ return self._schema.get_help(self.name, key) -+ except KeyError: -+ raise KeyError(key) -+ - - class NotAvailable(Exception): - pass -@@ -523,7 +526,7 @@ class Schema(object): - for name in schema.namelist(): - ns, _slash, key = name.partition('/') - if ns in self.namespaces: -- self._dict[ns][key] = {} -+ self._dict[ns][key] = None - - def __getitem__(self, key): - try: -@@ -557,7 +560,7 @@ class Schema(object): - os.makedirs(self._DIR) - except EnvironmentError as e: - if e.errno != errno.EEXIST: -- logger.warning("Failed ti write schema: {}".format(e)) -+ logger.warning("Failed to write schema: {}".format(e)) - return - - with self._open_schema(self._fingerprint, 'w') as schema: -@@ -580,24 +583,20 @@ class Schema(object): - def read_namespace_member(self, namespace, member): - value = self._dict[namespace][member] - -- if (not value) or ('full_name' not in value): -+ if value is None: - path = '{}/{}'.format(namespace, member) -- value = self._dict[namespace].setdefault( -- member, {} -- ).update(self._read(path)) -+ value = self._dict[namespace][member] = self._read(path) - - return value - - def iter_namespace(self, namespace): - return iter(self._dict[namespace]) - -- def load_help(self): -+ def get_help(self, namespace, member): - if not self._help: - self._help = self._read('_help') - -- for ns in self._help: -- for member in self._help[ns]: -- self._dict[ns][member].update(self._help[ns][member]) -+ return self._help[namespace][member] - - - def get_package(api, client): --- -2.7.4 - diff --git a/SOURCES/0075-renew-agent-restart-scripts-connect-to-LDAP-after-ki.patch b/SOURCES/0075-renew-agent-restart-scripts-connect-to-LDAP-after-ki.patch new file mode 100644 index 0000000..baf91f4 --- /dev/null +++ b/SOURCES/0075-renew-agent-restart-scripts-connect-to-LDAP-after-ki.patch @@ -0,0 +1,117 @@ +From 429f07426014c51025d136b505165a43f5e0df21 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Fri, 7 Apr 2017 07:51:01 +0200 +Subject: [PATCH] renew agent, restart scripts: connect to LDAP after kinit + +Connect to LDAP after kinit is done, otherwise GSSAPI authentication will +fail. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Martin Babinsky +--- + install/certmonger/dogtag-ipa-ca-renew-agent-submit | 6 ++++-- + install/restart_scripts/renew_ca_cert | 6 ++++-- + install/restart_scripts/renew_ra_cert | 6 ++++-- + 3 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index 3389447a99d9ab9dac159b0d57ca02f60698ce0c..7a3d9551884c0fe43566dd9012699211a39294eb 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -518,7 +518,6 @@ def main(): + + api.bootstrap(in_server=True, context='renew', confdir=paths.ETC_IPA) + api.finalize() +- api.Backend.ldap2.connect() + + operation = os.environ.get('CERTMONGER_OPERATION') + if operation not in ('SUBMIT', 'POLL'): +@@ -532,6 +531,8 @@ def main(): + os.environ['KRB5CCNAME'] = ccache_filename + kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename) + ++ api.Backend.ldap2.connect() ++ + profile = os.environ.get('CERTMONGER_CA_PROFILE') + if is_replicated(): + if profile or is_renewal_master(): +@@ -547,9 +548,10 @@ def main(): + print(item) + return res[0] + finally: ++ if api.Backend.ldap2.isconnected(): ++ api.Backend.ldap2.disconnect() + certs.renewal_lock.release() + shutil.rmtree(tmpdir) +- api.Backend.ldap2.disconnect() + + + try: +diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert +index bbeae1ae1da5a230f3de1c2569c2324606ae9789..7a54b4c7e05a35b40b17e46b75ff8d47db1b2d23 100644 +--- a/install/restart_scripts/renew_ca_cert ++++ b/install/restart_scripts/renew_ca_cert +@@ -42,7 +42,6 @@ def _main(): + + api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) + api.finalize() +- api.Backend.ldap2.connect() + + dogtag_service = services.knownservices['pki_tomcatd'] + +@@ -77,6 +76,8 @@ def _main(): + kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename) + os.environ['KRB5CCNAME'] = ccache_filename + ++ api.Backend.ldap2.connect() ++ + ca = cainstance.CAInstance(host_name=api.env.host) + ca.update_cert_config(nickname, cert) + if ca.is_renewal_master(): +@@ -184,8 +185,9 @@ def _main(): + if conn is not None and conn.isconnected(): + conn.disconnect() + finally: ++ if api.Backend.ldap2.isconnected(): ++ api.Backend.ldap2.disconnect() + shutil.rmtree(tmpdir) +- api.Backend.ldap2.disconnect() + + # Now we can start the CA. Using the services start should fire + # off the servlet to verify that the CA is actually up and responding so +diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert +index 5c71d5791fa8254de686d1c3a8d01e2cda4d493b..486ee786629076687864f6ef9c3a69b8e389dc28 100644 +--- a/install/restart_scripts/renew_ra_cert ++++ b/install/restart_scripts/renew_ra_cert +@@ -38,7 +38,6 @@ from ipaplatform.paths import paths + def _main(): + api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) + api.finalize() +- api.Backend.ldap2.connect() + + tmpdir = tempfile.mkdtemp(prefix="tmp-") + try: +@@ -47,6 +46,8 @@ def _main(): + kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_filename) + os.environ['KRB5CCNAME'] = ccache_filename + ++ api.Backend.ldap2.connect() ++ + ca = cainstance.CAInstance(host_name=api.env.host) + ra_certpath = paths.RA_AGENT_PEM + if ca.is_renewal_master(): +@@ -71,8 +72,9 @@ def _main(): + # Load it into dogtag + cainstance.update_people_entry(dercert) + finally: ++ if api.Backend.ldap2.isconnected(): ++ api.Backend.ldap2.disconnect() + shutil.rmtree(tmpdir) +- api.Backend.ldap2.disconnect() + + + def main(): +-- +2.9.3 + diff --git a/SOURCES/0076-frontent-Add-summary-class-property-to-CommandOverri.patch b/SOURCES/0076-frontent-Add-summary-class-property-to-CommandOverri.patch deleted file mode 100644 index ab0ece5..0000000 --- a/SOURCES/0076-frontent-Add-summary-class-property-to-CommandOverri.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 5b427134d613a49bcbd2fe89e7cac938d664b9e7 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 9 Aug 2016 17:03:25 +0200 -Subject: [PATCH] frontent: Add summary class property to CommandOverride - -Avoid creating instance of overriden command to get its summary. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/frontend.py | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ipaclient/frontend.py b/ipaclient/frontend.py -index aeaed550771d3c6af04a9b34fcae414faacb47d7..587e31c89b3935984e799f7d4c500c652bcb5d43 100644 ---- a/ipaclient/frontend.py -+++ b/ipaclient/frontend.py -@@ -127,6 +127,12 @@ class CommandOverride(Command): - doc = classproperty(__doc_getter) - - @classmethod -+ def __summary_getter(cls): -+ return cls.__get_next().summary -+ -+ summary = classproperty(__summary_getter) -+ -+ @classmethod - def __NO_CLI_getter(cls): - return cls.__get_next().NO_CLI - --- -2.7.4 - diff --git a/SOURCES/0076-ipaserver-dcerpc-unify-error-processing.patch b/SOURCES/0076-ipaserver-dcerpc-unify-error-processing.patch new file mode 100644 index 0000000..40b8580 --- /dev/null +++ b/SOURCES/0076-ipaserver-dcerpc-unify-error-processing.patch @@ -0,0 +1,93 @@ +From 65579492d3d545d6acabaedc019c457551c32063 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 3 Apr 2017 10:29:21 +0300 +Subject: [PATCH] ipaserver/dcerpc: unify error processing + +Samba error code reporting changes from version to version but we also +did not provide proper input into DCE RPC error processing method we +have. + +Unify error processing and add few more fallback entries. + +With Samba 4.7 we'll have to change it again because error code +processing for Samba Python modules will change with introduction of +samba.ntstatus and samba.werror modules. + +Note that this commit also changes a message returned for error code +-1073741772 (NT_STATUS_OBJECT_NOT_FOUND) because it is more general one. + +Fixes https://pagure.io/freeipa/issue/6859 + +Reviewed-By: Martin Basti +--- + ipaserver/dcerpc.py | 23 +++++++++++++++++------ + 1 file changed, 17 insertions(+), 6 deletions(-) + +diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py +index 2d9d7e5577f1cac6f35701dd277199f9a37387f8..d684a17cabe43bbbd43d29f75f534b6e50fccd12 100644 +--- a/ipaserver/dcerpc.py ++++ b/ipaserver/dcerpc.py +@@ -117,19 +117,27 @@ dcerpc_error_codes = { + # we simply will skip the binding + access_denied_error, + -1073741772: # NT_STATUS_OBJECT_NAME_NOT_FOUND +- errors.RemoteRetrieveError( +- reason=_('CIFS server configuration does not allow ' +- 'access to \\\\pipe\\lsarpc')), ++ errors.NotFound( ++ reason=_('Cannot find specified domain or server name')), + } + + dcerpc_error_messages = { + "NT_STATUS_OBJECT_NAME_NOT_FOUND": + errors.NotFound( + reason=_('Cannot find specified domain or server name')), ++ "The object name is 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')), ++ # This is a very long key, don't change it ++ "There are currently no logon servers available to " ++ "service the logon request.": ++ 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')), +@@ -802,7 +810,8 @@ class DomainValidator(object): + + # Both methods should not fail at the same time + if finddc_error and len(info['gc']) == 0: +- raise assess_dcerpc_exception(message=str(finddc_error)) ++ num, message = e.args # pylint: disable=unpacking-non-sequence ++ raise assess_dcerpc_exception(num=num, message=message) + + self._info[domain] = info + return info +@@ -908,7 +917,8 @@ class TrustDomainInstance(object): + else: + result = netrc.finddc(address=remote_host, flags=flags) + except RuntimeError as e: +- raise assess_dcerpc_exception(message=str(e)) ++ num, message = e.args # pylint: disable=unpacking-non-sequence ++ raise assess_dcerpc_exception(num=num, message=message) + + if not result: + return False +@@ -1408,7 +1418,8 @@ def fetch_domains(api, mydomain, trustdomain, creds=None, server=None): + result = netrc.finddc(domain=trustdomain, + flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) + except RuntimeError as e: +- raise assess_dcerpc_exception(message=str(e)) ++ num, message = e.args # pylint: disable=unpacking-non-sequence ++ raise assess_dcerpc_exception(num=num, message=message) + + td.info['dc'] = unicode(result.pdc_dns_name) + td.info['name'] = unicode(result.dns_domain) +-- +2.9.3 + diff --git a/SOURCES/0077-schema-cache-Read-server-info-only-once.patch b/SOURCES/0077-schema-cache-Read-server-info-only-once.patch deleted file mode 100644 index 5ed5ee1..0000000 --- a/SOURCES/0077-schema-cache-Read-server-info-only-once.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 6959578fdbdfd38113b26cd9e4f94b298343a6f0 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 9 Aug 2016 17:05:17 +0200 -Subject: [PATCH] schema cache: Read server info only once - -Do not open/close the file with every access to plugins. Extensive -access to filesystem may cause significant slowdown. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index c72109ac3bb9b7a71f9cbc056eaf3a4d8371d035..aadc891750782b0961bc46989e3693d1d3ed0ecb 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -378,6 +378,9 @@ class ServerInfo(collections.MutableMapping): - return self - - def __exit__(self, *_exc_info): -+ self.flush() -+ -+ def flush(self): - if self._dirty: - self._write() - -@@ -603,9 +606,16 @@ def get_package(api, client): - try: - schema = api._schema - except AttributeError: -- with ServerInfo(api.env.hostname) as server_info: -+ try: -+ server_info = api._server_info -+ except AttributeError: -+ server_info = api._server_info = ServerInfo(api) -+ -+ try: - schema = Schema(api, server_info, client) - object.__setattr__(api, '_schema', schema) -+ finally: -+ server_info.flush() - - fingerprint = str(schema['fingerprint']) - package_name = '{}${}'.format(__name__, fingerprint) --- -2.7.4 - diff --git a/SOURCES/0077-trust-always-use-oddjobd-helper-for-fetching-trust-i.patch b/SOURCES/0077-trust-always-use-oddjobd-helper-for-fetching-trust-i.patch new file mode 100644 index 0000000..db6b720 --- /dev/null +++ b/SOURCES/0077-trust-always-use-oddjobd-helper-for-fetching-trust-i.patch @@ -0,0 +1,86 @@ +From 3353a259bb8ace57efcfd784f2a0c0c6884d9966 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 5 Apr 2017 12:37:10 +0300 +Subject: [PATCH] trust: always use oddjobd helper for fetching trust + information + +Since introduction of privilege separation in IPA framework none of the +operations that require direct access to the framework's credentials can +be done. All authentication has to be performed with GSSAPI. + +As result, we cannot obtain TGT for HTTP/.. principal with kinit +anymore, so it is better to re-route all types of trust to oddjobd +helper and get rid of casing out two-way trust. + +Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1438366 + +Reviewed-By: Martin Basti +--- + ipaserver/plugins/trust.py | 43 ++++++++++--------------------------------- + 1 file changed, 10 insertions(+), 33 deletions(-) + +diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py +index 3de2458466214044f6b1b5d8560a2a7ac53ede57..0829f8c714f15c4384a89e18ba29e417405c249c 100644 +--- a/ipaserver/plugins/trust.py ++++ b/ipaserver/plugins/trust.py +@@ -1742,47 +1742,24 @@ class trust_fetch_domains(LDAPRetrieve): + ldap = self.api.Backend.ldap2 + verify_samba_component_presence(ldap, self.api) + +- trust = self.api.Command.trust_show( +- keys[0], all=True, raw=True)['result'] ++ # Check first that the trust actually exists ++ result = self.api.Command.trust_show(keys[0], all=True, raw=True) ++ self.obj.warning_if_ad_trust_dom_have_missing_SID(result, **options) + + result = dict() + result['result'] = [] + result['count'] = 0 + result['truncated'] = False + +- trust_direction = int(trust['ipanttrustdirection'][0]) +- is_nontransitive = int(trust.get('ipanttrustattributes', +- [0])[0]) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE + # For one-way trust and external trust fetch over DBus. + # We don't get the list in this case. +- if trust_direction != TRUST_BIDIRECTIONAL or is_nontransitive: +- fetch_trusted_domains_over_dbus(self.api, self.log, keys[0]) +- result['summary'] = unicode(_('List of trust domains successfully refreshed. Use trustdomain-find command to list them.')) +- return result +- +- trustinstance = ipaserver.dcerpc.TrustDomainJoins(self.api) +- if not trustinstance.configured: +- raise errors.NotFound( +- name=_('AD Trust setup'), +- reason=_( +- 'Cannot perform join operation without own domain ' +- 'configured. Make sure you have run ipa-adtrust-install ' +- 'on the IPA server first' +- ) +- ) +- +- trustinstance.populate_remote_domain(keys[0]) +- +- res = fetch_domains_from_trust(self.api, trustinstance, **options) +- domains = add_new_domains_from_trust(self.api, trustinstance, trust, res, **options) +- +- if len(domains) > 0: +- result['summary'] = unicode(_('List of trust domains successfully refreshed')) +- else: +- result['summary'] = unicode(_('No new trust domains were found')) +- +- result['result'] = domains +- result['count'] = len(domains) ++ # With privilege separation we also cannot authenticate as ++ # HTTP/ principal because we have no access to its key material. ++ # Thus, we'll use DBus call out to oddjobd helper in all cases ++ fetch_trusted_domains_over_dbus(self.api, self.log, keys[0]) ++ result['summary'] = unicode(_('List of trust domains successfully ' ++ 'refreshed. Use trustdomain-find ' ++ 'command to list them.')) + return result + + +-- +2.9.3 + diff --git a/SOURCES/0078-WebUI-cert-login-Configure-name-of-parameter-used-to.patch b/SOURCES/0078-WebUI-cert-login-Configure-name-of-parameter-used-to.patch new file mode 100644 index 0000000..d547750 --- /dev/null +++ b/SOURCES/0078-WebUI-cert-login-Configure-name-of-parameter-used-to.patch @@ -0,0 +1,34 @@ +From 5ac1c55462297d4458d07a6ff9941170056216ef Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Mon, 10 Apr 2017 13:11:13 +0200 +Subject: [PATCH] WebUI: cert login: Configure name of parameter used to pass + username + +Directive LookupUserByCertificateParamName tells mod_lookup_identity module the +name of GET parameter that is used to provide username in case certificate is +mapped to multiple user accounts. +Without this directive login with certificate that's mapped to multiple users +doesn't work. + +https://pagure.io/freeipa/issue/6860 + +Reviewed-By: Florence Blanc-Renaud +--- + install/conf/ipa.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf +index e1f1a581b4e8a91b899bcf165ca81f266fa9e516..75c122e6c94b941c278d724add84315753082531 100644 +--- a/install/conf/ipa.conf ++++ b/install/conf/ipa.conf +@@ -117,6 +117,7 @@ Alias /ipa/session/cookie "/usr/share/ipa/gssapi.login" + NSSVerifyClient require + NSSUserName SSL_CLIENT_CERT + LookupUserByCertificate On ++ LookupUserByCertificateParamName "username" + WSGIProcessGroup ipa + WSGIApplicationGroup ipa + GssapiImpersonate On +-- +2.9.3 + diff --git a/SOURCES/0078-schema-cache-Store-API-schema-cache-in-memory.patch b/SOURCES/0078-schema-cache-Store-API-schema-cache-in-memory.patch deleted file mode 100644 index eb9dfd3..0000000 --- a/SOURCES/0078-schema-cache-Store-API-schema-cache-in-memory.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 1aa300c53f070436888150ae582dad23cddac03b Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Mon, 15 Aug 2016 08:01:59 +0200 -Subject: [PATCH] schema cache: Store API schema cache in memory - -Read whole cache into memory and keep it there for lifetime of api -object. This removes the need to repetitively open/close the cache and -speeds up every access to it. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 51 +++++++++++++++++++++----------------- - 1 file changed, 28 insertions(+), 23 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index aadc891750782b0961bc46989e3693d1d3ed0ecb..2fc6cce3eca392447cd4230216900116002934f4 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -3,6 +3,7 @@ - # - - import collections -+import contextlib - import errno - import fcntl - import json -@@ -315,24 +316,6 @@ class _SchemaObjectPlugin(_SchemaPlugin): - schema_key = 'classes' - - --class _LockedZipFile(zipfile.ZipFile): -- """ Add locking to zipfile.ZipFile -- Shared lock is used with read mode, exclusive with write mode. -- """ -- def __enter__(self): -- if 'r' in self.mode: -- fcntl.flock(self.fp, fcntl.LOCK_SH) -- elif 'w' in self.mode or 'a' in self.mode: -- fcntl.flock(self.fp, fcntl.LOCK_EX) -- -- return super(_LockedZipFile, self).__enter__() -- -- def __exit__(self, type_, value, traceback): -- fcntl.flock(self.fp, fcntl.LOCK_UN) -- -- return super(_LockedZipFile, self).__exit__(type_, value, traceback) -- -- - class _SchemaNameSpace(collections.Mapping): - - def __init__(self, schema, name): -@@ -450,6 +433,7 @@ class Schema(object): - self._dict = {} - self._namespaces = {} - self._help = None -+ self._file = six.StringIO() - - for ns in self.namespaces: - self._dict[ns] = {} -@@ -486,9 +470,20 @@ class Schema(object): - except AttributeError: - pass - -- def _open_schema(self, filename, mode): -+ @contextlib.contextmanager -+ def _open(self, filename, mode): - path = os.path.join(self._DIR, filename) -- return _LockedZipFile(path, mode) -+ -+ with open(path, mode) as f: -+ if mode.startswith('r'): -+ fcntl.flock(f, fcntl.LOCK_SH) -+ else: -+ fcntl.flock(f, fcntl.LOCK_EX) -+ -+ try: -+ yield f -+ finally: -+ fcntl.flock(f, fcntl.LOCK_UN) - - def _fetch(self, client): - if not client.isconnected(): -@@ -523,7 +518,11 @@ class Schema(object): - self._expiration = ttl + time.time() - - def _read_schema(self): -- with self._open_schema(self._fingerprint, 'r') as schema: -+ self._file.truncate(0) -+ with self._open(self._fingerprint, 'r') as f: -+ self._file.write(f.read()) -+ -+ with zipfile.ZipFile(self._file, 'r') as schema: - self._dict['fingerprint'] = self._fingerprint - - for name in schema.namelist(): -@@ -566,7 +565,8 @@ class Schema(object): - logger.warning("Failed to write schema: {}".format(e)) - return - -- with self._open_schema(self._fingerprint, 'w') as schema: -+ self._file.truncate(0) -+ with zipfile.ZipFile(self._file, 'w', zipfile.ZIP_DEFLATED) as schema: - for key, value in self._dict.items(): - if key in self.namespaces: - ns = value -@@ -579,8 +579,13 @@ class Schema(object): - schema.writestr('_help', - json.dumps(self._generate_help(self._dict))) - -+ self._file.seek(0) -+ with self._open(self._fingerprint, 'w') as f: -+ f.truncate(0) -+ f.write(self._file.read()) -+ - def _read(self, path): -- with self._open_schema(self._fingerprint, 'r') as zf: -+ with zipfile.ZipFile(self._file, 'r') as zf: - return json.loads(zf.read(path)) - - def read_namespace_member(self, namespace, member): --- -2.7.4 - diff --git a/SOURCES/0079-Create-system-users-for-FreeIPA-services-during-pack.patch b/SOURCES/0079-Create-system-users-for-FreeIPA-services-during-pack.patch new file mode 100644 index 0000000..586cc85 --- /dev/null +++ b/SOURCES/0079-Create-system-users-for-FreeIPA-services-during-pack.patch @@ -0,0 +1,414 @@ +From a4a85c69a945b023b4017ecf4285f9f5e97d5f20 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Tue, 11 Apr 2017 11:43:40 +0200 +Subject: [PATCH] Create system users for FreeIPA services during package + installation + +Previously system users needed by FreeIPA server services was created during +ipa-server-install. This led to problem when DBus policy was configured during +package installation but the user specified in the policy didn't exist yet +(and potentionally similar ones). Now the users will be created in package %pre +section so all users freeipa-server package needs exist before any installation +or configuration begins. +Another possibility would be using systemd-sysusers(8) for this purpose but +given that systemd is not available during container build the traditional +approach is superior. +Also dirsrv and pkiuser users are no longer created by FreeIPA instead it +depends on 389ds and dogtag to create those users. + +https://pagure.io/freeipa/issue/6743 + +Reviewed-By: Jan Cholasta +Reviewed-By: Christian Heimes +Reviewed-By: Stanislav Laznicka +--- + freeipa.spec.in | 9 +++++ + ipaplatform/base/tasks.py | 53 ------------------------------ + ipaplatform/redhat/tasks.py | 26 --------------- + ipaserver/install/cainstance.py | 12 ------- + ipaserver/install/dsinstance.py | 11 ------- + ipaserver/install/httpinstance.py | 13 -------- + ipaserver/install/installutils.py | 13 -------- + ipaserver/install/ipa_restore.py | 7 ---- + ipaserver/install/server/install.py | 6 +--- + ipaserver/install/server/replicainstall.py | 6 +--- + ipaserver/install/server/upgrade.py | 2 -- + 11 files changed, 11 insertions(+), 147 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 829c3f0b2898de1ecbf0cfb769fde5cd978c241c..978ebb184f7d051b303940560f44c7a094b071a1 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -1030,6 +1030,15 @@ if [ -e /usr/sbin/ipa_kpasswd ]; then + # END + fi + ++# create users and groups ++# create kdcproxy group and user ++getent group kdcproxy >/dev/null || groupadd -f -r kdcproxy ++getent passwd kdcproxy >/dev/null || useradd -r -g kdcproxy -s /sbin/nologin -d / -c "IPA KDC Proxy User" kdcproxy ++# create ipaapi group and user ++getent group ipaapi >/dev/null || groupadd -f -r ipaapi ++getent passwd ipaapi >/dev/null || useradd -r -g ipaapi -s /sbin/nologin -d / -c "IPA Framework User" ipaapi ++# add apache to ipaaapi group ++id -Gn apache | grep '\bipaapi\b' >/dev/null || usermod apache -a -G ipaapi + + %postun server-trust-ad + if [ "$1" -ge "1" ]; then +diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py +index 9f91fef2b572a29bf876641fd9ad879604054a2f..3358b7d257cc60ceaecfbbac5155d79b0e63de2e 100644 +--- a/ipaplatform/base/tasks.py ++++ b/ipaplatform/base/tasks.py +@@ -22,9 +22,6 @@ + This module contains default platform-specific implementations of system tasks. + ''' + +-import pwd +-import grp +- + from pkg_resources import parse_version + + from ipaplatform.paths import paths +@@ -186,56 +183,6 @@ class BaseTaskNamespace(object): + + raise NotImplementedError() + +- def create_system_user(self, name, group, homedir, shell, +- uid=None, gid=None, comment=None, +- create_homedir=False, groups=None): +- """Create a system user with a corresponding group""" +- try: +- grp.getgrnam(group) +- except KeyError: +- log.debug('Adding group %s', group) +- args = [paths.GROUPADD, '-r', group] +- if gid: +- args += ['-g', str(gid)] +- try: +- ipautil.run(args) +- log.debug('Done adding group') +- except ipautil.CalledProcessError as e: +- log.critical('Failed to add group: %s', e) +- raise +- else: +- log.debug('group %s exists', group) +- +- try: +- pwd.getpwnam(name) +- except KeyError: +- log.debug('Adding user %s', name) +- args = [ +- paths.USERADD, +- '-g', group, +- '-d', homedir, +- '-s', shell, +- '-r', name, +- ] +- if uid: +- args += ['-u', str(uid)] +- if comment: +- args += ['-c', comment] +- if create_homedir: +- args += ['-m'] +- else: +- args += ['-M'] +- if groups is not None: +- args += ['-G', groups.join(',')] +- try: +- ipautil.run(args) +- log.debug('Done adding user') +- except ipautil.CalledProcessError as e: +- log.critical('Failed to add user: %s', e) +- raise +- else: +- log.debug('user %s exists', name) +- + @staticmethod + def parse_ipa_version(version): + """ +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index d0ef5fbd1ceb8110dd417dda44a74dc63898456a..07efebab97eabcf2dc39bd345920a1c7be56e9f5 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -431,32 +431,6 @@ class RedHatTaskNamespace(BaseTaskNamespace): + + return True + +- def create_system_user(self, name, group, homedir, shell, +- uid=None, gid=None, comment=None, +- create_homedir=False, groups=None): +- """ +- Create a system user with a corresponding group +- +- According to https://fedoraproject.org/wiki/Packaging:UsersAndGroups?rd=Packaging/UsersAndGroups#Soft_static_allocation +- some system users should have fixed UID, GID and other parameters set. +- This values should be constant and may be hardcoded. +- Add other values for other users when needed. +- """ +- if name == constants.PKI_USER: +- if uid is None: +- uid = 17 +- if gid is None: +- gid = 17 +- if comment is None: +- comment = 'CA System User' +- if name == constants.DS_USER: +- if comment is None: +- comment = 'DS System User' +- +- super(RedHatTaskNamespace, self).create_system_user( +- name, group, homedir, shell, uid, gid, comment, create_homedir, +- groups) +- + def parse_ipa_version(self, version): + """ + :param version: textual version +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 3980e412603437b0db5804623f6626d11e52c009..ac5d9e2fc633c5ad732670245b72bee0f03268a6 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -46,7 +46,6 @@ from ipalib import errors + import ipalib.constants + from ipalib.install import certmonger + from ipaplatform import services +-from ipaplatform.constants import constants + from ipaplatform.paths import paths + from ipaplatform.tasks import tasks + +@@ -263,16 +262,6 @@ def is_ca_installed_locally(): + return os.path.exists(paths.CA_CS_CFG_PATH) + + +-def create_ca_user(): +- """Create PKI user/group if it doesn't exist yet.""" +- tasks.create_system_user( +- name=constants.PKI_USER, +- group=constants.PKI_GROUP, +- homedir=paths.VAR_LIB, +- shell=paths.NOLOGIN, +- ) +- +- + class CAInstance(DogtagInstance): + """ + When using a dogtag CA the DS database contains just the +@@ -382,7 +371,6 @@ class CAInstance(DogtagInstance): + has_ra_cert = False + + if not ra_only: +- self.step("creating certificate server user", create_ca_user) + if promote: + # Setup Database + self.step("creating certificate server db", self.__create_ds_db) +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 72fcb65f2eb699d0077d3c5cc02a3fcaaad9b8e5..99a1781ca4475805e9bf3b2bac3f26b5fb107a43 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -158,16 +158,6 @@ def is_ds_running(server_id=''): + return services.knownservices.dirsrv.is_running(instance_name=server_id) + + +-def create_ds_user(): +- """Create DS user/group if it doesn't exist yet.""" +- tasks.create_system_user( +- name=DS_USER, +- group=DS_USER, +- homedir=paths.VAR_LIB_DIRSRV, +- shell=paths.NOLOGIN, +- ) +- +- + def get_domain_level(api=api): + ldap_uri = ipaldap.get_ldap_uri(protocol='ldapi', realm=api.env.realm) + conn = ipaldap.LDAPClient(ldap_uri) +@@ -258,7 +248,6 @@ class DsInstance(service.Service): + + def __common_setup(self): + +- self.step("creating directory server user", create_ds_user) + self.step("creating directory server instance", self.__create_instance) + self.step("enabling ldapi", self.__enable_ldapi) + self.step("configure autobind for root", self.__root_autobind) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 45bf479d1088c3b3396d955bf2592c4bce1e886f..8e444be2d23ec5e7890d221508bc866de2854c89 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -102,18 +102,6 @@ def httpd_443_configured(): + return False + + +-def create_kdcproxy_user(): +- """Create KDC proxy user/group if it doesn't exist yet.""" +- tasks.create_system_user( +- name=KDCPROXY_USER, +- group=KDCPROXY_USER, +- homedir=paths.VAR_LIB_KDCPROXY, +- shell=paths.NOLOGIN, +- comment="IPA KDC Proxy User", +- create_homedir=True, +- ) +- +- + class WebGuiInstance(service.SimpleServiceInstance): + def __init__(self): + service.SimpleServiceInstance.__init__(self, "ipa_webgui") +@@ -183,7 +171,6 @@ class HTTPInstance(service.Service): + self.remove_httpd_ccaches) + self.step("configuring SELinux for httpd", self.configure_selinux_for_httpd) + if not self.is_kdcproxy_configured(): +- self.step("create KDC proxy user", create_kdcproxy_user) + self.step("create KDC proxy config", self.create_kdcproxy_conf) + self.step("enable KDC proxy", self.enable_kdcproxy) + self.step("starting httpd", self.start) +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index ef6a399ad28ae8b8646864baea9965f762050484..9230e70056b1a773246a0d95e6ecb943cada953c 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -44,7 +44,6 @@ import six + from six.moves.configparser import SafeConfigParser, NoOptionError + # pylint: enable=import-error + +-from ipalib.constants import IPAAPI_USER, IPAAPI_GROUP + from ipalib.install import sysrestore + from ipalib.install.kinit import kinit_password + import ipaplatform +@@ -56,7 +55,6 @@ from ipalib import api, errors, x509 + from ipapython.dn import DN + from ipaserver.install import certs, service, sysupgrade + from ipaplatform import services +-from ipaplatform.constants import constants + from ipaplatform.paths import paths + from ipaplatform.tasks import tasks + +@@ -1515,14 +1513,3 @@ def default_subject_base(realm_name): + + def default_ca_subject_dn(subject_base): + return DN(('CN', 'Certificate Authority'), subject_base) +- +- +-def create_ipaapi_user(): +- """Create IPA API user/group if it doesn't exist yet.""" +- tasks.create_system_user( +- name=IPAAPI_USER, +- group=IPAAPI_GROUP, +- homedir=paths.VAR_LIB, +- shell=paths.NOLOGIN +- ) +- tasks.add_user_to_group(constants.HTTPD_USER, IPAAPI_GROUP) +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 2552bbdef36f653f1c377ea096ca227d09e5f3e6..378c013b6f4a4656768d7a484d2014a0f9eef3c0 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -36,8 +36,6 @@ from ipapython import version, ipautil + from ipapython.ipautil import run, user_input + from ipapython import admintool + from ipapython.dn import DN +-from ipaserver.install.dsinstance import create_ds_user +-from ipaserver.install.cainstance import create_ca_user + from ipaserver.install.replication import (wait_for_task, ReplicationManager, + get_cs_replication_manager) + from ipaserver.install import installutils +@@ -296,7 +294,6 @@ class Restore(admintool.AdminTool): + not user_input("Continue to restore?", False)): + raise admintool.ScriptError("Aborted") + +- create_ds_user() + pent = pwd.getpwnam(constants.DS_USER) + + # Temporary directory for decrypting files before restoring +@@ -379,15 +376,11 @@ class Restore(admintool.AdminTool): + # We do either a full file restore or we restore data. + if restore_type == 'FULL': + self.remove_old_files() +- if 'CA' in self.backup_services: +- create_ca_user() + self.cert_restore_prepare() + self.file_restore(options.no_logs) + self.cert_restore() + if 'CA' in self.backup_services: + self.__create_dogtag_log_dirs() +- if http.is_kdcproxy_configured(): +- httpinstance.create_kdcproxy_user() + + # Always restore the data from ldif + # We need to restore both userRoot and ipaca. +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index bf2e248dceaae36ba0030d3eaa47976f51ce60ba..197f01ccef58bb3564eb4c6b5b4d615bff1e523d 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -39,7 +39,7 @@ from ipaserver.install import ( + from ipaserver.install.installutils import ( + IPA_MODULES, BadHostError, get_fqdn, get_server_ip_address, + is_ipa_configured, load_pkcs12, read_password, verify_fqdn, +- update_hosts_file, create_ipaapi_user) ++ update_hosts_file) + + if six.PY3: + unicode = str +@@ -721,12 +721,8 @@ def install(installer): + update_hosts_file(ip_addresses, host_name, fstore) + + # Make sure tmpfiles dir exist before installing components +- create_ipaapi_user() + tasks.create_tmpfiles_dirs() + +- # Create DS user/group if it doesn't exist yet +- dsinstance.create_ds_user() +- + # Create a directory server instance + if not options.external_cert_files: + # Configure ntpd +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 6f1a0d6d29b20d53986205a63382a385e75f80ea..b82d7b474640e24da7d978e9546ebd7a8e602c29 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -41,8 +41,7 @@ from ipaserver.install import ( + installutils, kra, krbinstance, + ntpinstance, otpdinstance, custodiainstance, service) + from ipaserver.install.installutils import ( +- create_replica_config, ReplicaConfig, load_pkcs12, is_ipa_configured, +- create_ipaapi_user) ++ create_replica_config, ReplicaConfig, load_pkcs12, is_ipa_configured) + from ipaserver.install.replication import ( + ReplicationManager, replica_conn_check) + import SSSDConfig +@@ -1347,7 +1346,6 @@ def install(installer): + ccache = os.environ['KRB5CCNAME'] + + # Make sure tmpfiles dir exist before installing components +- create_ipaapi_user() + tasks.create_tmpfiles_dirs() + + if promote: +@@ -1376,8 +1374,6 @@ def install(installer): + ntp = ntpinstance.NTPInstance() + ntp.create_instance() + +- dsinstance.create_ds_user() +- + try: + if promote: + conn.connect(ccache=ccache) +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 25b86297af3ae9d5f21cebb93f493b90670dcfc3..927acb011172de926773196eb1d032af8376f3d9 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1652,7 +1652,6 @@ def upgrade_configuration(): + + if not http.is_kdcproxy_configured(): + root_logger.info('[Enabling KDC Proxy]') +- httpinstance.create_kdcproxy_user() + http.create_kdcproxy_conf() + http.enable_kdcproxy() + +@@ -1837,7 +1836,6 @@ def upgrade_check(options): + + def upgrade(): + # Do this early so that any code depending on these dirs will not fail +- installutils.create_ipaapi_user() + tasks.create_tmpfiles_dirs() + tasks.configure_tmpfiles() + +-- +2.9.3 + diff --git a/SOURCES/0079-client-Do-not-create-instance-just-to-check-isinstan.patch b/SOURCES/0079-client-Do-not-create-instance-just-to-check-isinstan.patch deleted file mode 100644 index 60707e8..0000000 --- a/SOURCES/0079-client-Do-not-create-instance-just-to-check-isinstan.patch +++ /dev/null @@ -1,97 +0,0 @@ -From bac0d7c286768a67715ca1ac1e835a272e540721 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 11 Aug 2016 14:30:00 +0200 -Subject: [PATCH] client: Do not create instance just to check isinstance - -Checking that classes are idenical gives the same result and -avoids unnecessary instantiation. - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/plugins/automount.py | 4 ++-- - ipaclient/plugins/otptoken_yubikey.py | 3 +-- - ipaclient/plugins/vault.py | 16 ++++++++-------- - 3 files changed, 11 insertions(+), 12 deletions(-) - -diff --git a/ipaclient/plugins/automount.py b/ipaclient/plugins/automount.py -index 925b635ff27411fc7e2f8c3dae17c747216d7fb6..3742705face49d02370e845e3d6e6599a34809eb 100644 ---- a/ipaclient/plugins/automount.py -+++ b/ipaclient/plugins/automount.py -@@ -55,8 +55,8 @@ class _fake_automountlocation_show(Method): - class automountlocation_tofiles(MethodOverride): - @classmethod - def __NO_CLI_getter(cls): -- return isinstance(api.Command.automountlocation_show, -- _fake_automountlocation_show) -+ return (api.Command.get_plugin('automountlocation_show') is -+ _fake_automountlocation_show) - - NO_CLI = classproperty(__NO_CLI_getter) - -diff --git a/ipaclient/plugins/otptoken_yubikey.py b/ipaclient/plugins/otptoken_yubikey.py -index 549376a0ff65d44c5698666a84608849152368b2..1075b6d839c785b44f035050ed5c9773c66d57b7 100644 ---- a/ipaclient/plugins/otptoken_yubikey.py -+++ b/ipaclient/plugins/otptoken_yubikey.py -@@ -77,8 +77,7 @@ class otptoken_add_yubikey(Command): - - @classmethod - def __NO_CLI_getter(cls): -- return isinstance(api.Command.otptoken_add, -- _fake_otptoken_add) -+ return api.Command.get_plugin('otptoken_add') is _fake_otptoken_add - - NO_CLI = classproperty(__NO_CLI_getter) - -diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py -index c0ded21d515fe41bde5fb0e547087cb7789aa6a3..08bbeb50f3bdc756321df9e45496e5388edd92c5 100644 ---- a/ipaclient/plugins/vault.py -+++ b/ipaclient/plugins/vault.py -@@ -205,8 +205,8 @@ class vault_add(Local): - - @classmethod - def __NO_CLI_getter(cls): -- return isinstance(api.Command.vault_add_internal, -- _fake_vault_add_internal) -+ return (api.Command.get_plugin('vault_add_internal') is -+ _fake_vault_add_internal) - - NO_CLI = classproperty(__NO_CLI_getter) - -@@ -411,8 +411,8 @@ class vault_mod(Local): - - @classmethod - def __NO_CLI_getter(cls): -- return isinstance(api.Command.vault_mod_internal, -- _fake_vault_mod_internal) -+ return (api.Command.get_plugin('vault_mod_internal') is -+ _fake_vault_mod_internal) - - NO_CLI = classproperty(__NO_CLI_getter) - -@@ -598,8 +598,8 @@ class vault_archive(Local): - - @classmethod - def __NO_CLI_getter(cls): -- return isinstance(api.Command.vault_archive_internal, -- _fake_vault_archive_internal) -+ return (api.Command.get_plugin('vault_archive_internal') is -+ _fake_vault_archive_internal) - - NO_CLI = classproperty(__NO_CLI_getter) - -@@ -855,8 +855,8 @@ class vault_retrieve(Local): - - @classmethod - def __NO_CLI_getter(cls): -- return isinstance(api.Command.vault_retrieve_internal, -- _fake_vault_retrieve_internal) -+ return (api.Command.get_plugin('vault_retrieve_internal') is -+ _fake_vault_retrieve_internal) - - NO_CLI = classproperty(__NO_CLI_getter) - --- -2.7.4 - diff --git a/SOURCES/0080-Fix-s4u2self-with-adtrust.patch b/SOURCES/0080-Fix-s4u2self-with-adtrust.patch new file mode 100644 index 0000000..af64e74 --- /dev/null +++ b/SOURCES/0080-Fix-s4u2self-with-adtrust.patch @@ -0,0 +1,60 @@ +From 542c31e057cbd4bd6261abcc883ace14f69719d6 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 10 Apr 2017 15:32:54 -0400 +Subject: [PATCH] Fix s4u2self with adtrust + +When ADtrust is installed we add a PAC to all tickets, during protocol +transition we need to generate a new PAC for the requested user ticket, +not check the existing PAC on the requestor ticket. + +https://pagure.io/freeipa/issue/6862 + +Signed-off-by: Simo Sorce +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb_mspac.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index cf1bd5b4eaf6ac8eba92639cc48cb7c333a6e836..00cc19ca1e757e28530eafcd38ebf73003e251e3 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -2117,6 +2117,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, + struct ipadb_context *ipactx; + bool with_pac; + bool with_pad; ++ bool make_ad = false; + int result; + krb5_db_entry *client_entry = NULL; + krb5_boolean is_equal; +@@ -2165,7 +2166,14 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, + "currently not supported."); + } + +- if (is_as_req && with_pac && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) { ++ /* we need to create a PAC if we are requested one and this is an AS REQ, ++ * or we are doing protocol transition (s4u2self) */ ++ if ((is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC)) || ++ (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) { ++ make_ad = true; ++ } ++ ++ if (with_pac && make_ad) { + /* Be aggressive here: special case for discovering range type + * immediately after establishing the trust by IPA framework */ + if ((krb5_princ_size(context, ks_client_princ) == 2) && +@@ -2188,9 +2196,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context, + if (kerr != 0 && kerr != ENOENT) { + goto done; + } +- } +- +- if (!is_as_req && with_pac) { ++ } else if (with_pac && !is_as_req) { + /* find the existing PAC, if present */ + kerr = krb5_find_authdata(context, tgt_auth_data, NULL, + KRB5_AUTHDATA_WIN2K_PAC, &pac_auth_data); +-- +2.9.3 + diff --git a/SOURCES/0080-schema-cache-Read-schema-instead-of-rewriting-it-whe.patch b/SOURCES/0080-schema-cache-Read-schema-instead-of-rewriting-it-whe.patch deleted file mode 100644 index acc7d26..0000000 --- a/SOURCES/0080-schema-cache-Read-schema-instead-of-rewriting-it-whe.patch +++ /dev/null @@ -1,104 +0,0 @@ -From a9ebd731b23ebf9a56401139fe20dafc50322ff3 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 16 Aug 2016 15:32:47 +0200 -Subject: [PATCH] schema cache: Read schema instead of rewriting it when - SchemaUpToDate - -https://fedorahosted.org/freeipa/ticket/6048 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 46 ++++++++++++++++++++------------------ - 1 file changed, 24 insertions(+), 22 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index 2fc6cce3eca392447cd4230216900116002934f4..e8b3f61bd8460c60630e8710028da79654819bd1 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -17,6 +17,7 @@ import six - - from ipaclient.frontend import ClientCommand, ClientMethod - from ipalib import errors, parameters, plugable -+from ipalib.errors import SchemaUpToDate - from ipalib.frontend import Object - from ipalib.output import Output - from ipalib.parameters import DefaultFrom, Flag, Password, Str -@@ -439,15 +440,14 @@ class Schema(object): - self._dict[ns] = {} - self._namespaces[ns] = _SchemaNameSpace(self, ns) - -- is_known = False -- if not api.env.force_schema_check: -- try: -- self._fingerprint = server_info['fingerprint'] -- self._expiration = server_info['expiration'] -- except KeyError: -- pass -- else: -- is_known = True -+ try: -+ self._fingerprint = server_info['fingerprint'] -+ self._expiration = server_info['expiration'] -+ except KeyError: -+ is_known = False -+ else: -+ is_known = (not api.env.force_schema_check and -+ self._expiration > time.time()) - - if is_known: - try: -@@ -461,14 +461,15 @@ class Schema(object): - self._fetch(client) - except NotAvailable: - raise -+ except SchemaUpToDate as e: -+ self._fingerprint = e.fingerprint -+ self._expiration = time.time() + e.ttl -+ self._read_schema() - else: - self._write_schema() -- finally: -- try: -- server_info['fingerprint'] = self._fingerprint -- server_info['expiration'] = self._expiration -- except AttributeError: -- pass -+ -+ server_info['fingerprint'] = self._fingerprint -+ server_info['expiration'] = self._expiration - - @contextlib.contextmanager - def _open(self, filename, mode): -@@ -501,21 +502,22 @@ class Schema(object): - schema = client.forward(u'schema', **kwargs)['result'] - except errors.CommandError: - raise NotAvailable() -- except errors.SchemaUpToDate as e: -- fp = e.fingerprint -- ttl = e.ttl -- else: -+ -+ try: - fp = schema['fingerprint'] -- ttl = schema.pop('ttl', 0) -- schema.pop('version', None) -+ ttl = schema.pop('ttl') -+ schema.pop('version') - - for key, value in schema.items(): - if key in self.namespaces: - value = {m['full_name']: m for m in value} - self._dict[key] = value -+ except KeyError as e: -+ logger.warning("Failed to fetch schema: %s", e) -+ raise NotAvailable() - - self._fingerprint = fp -- self._expiration = ttl + time.time() -+ self._expiration = time.time() + ttl - - def _read_schema(self): - self._file.truncate(0) --- -2.7.4 - diff --git a/SOURCES/0081-Add-debug-log-in-case-cookie-retrieval-went-wrong.patch b/SOURCES/0081-Add-debug-log-in-case-cookie-retrieval-went-wrong.patch new file mode 100644 index 0000000..eef3ee2 --- /dev/null +++ b/SOURCES/0081-Add-debug-log-in-case-cookie-retrieval-went-wrong.patch @@ -0,0 +1,31 @@ +From 6a66a69f4500fc8b324f3f3f0f0a4d79ea3fbe1e Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 17 Mar 2017 08:55:30 +0100 +Subject: [PATCH] Add debug log in case cookie retrieval went wrong + +https://pagure.io/freeipa/issue/6774 + +Reviewed-By: Martin Basti +--- + ipalib/rpc.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index 5c49bd2456b7e564043a886c840fa2678060f9e3..e23ca3d061645b2695a9e0deaa0b7d666f986e0e 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -895,7 +895,10 @@ class RPCClient(Connectible): + session_cookie = Cookie.get_named_cookie_from_string( + cookie_string, COOKIE_NAME, + timestamp=datetime.datetime.utcnow()) +- except Exception: ++ except Exception as e: ++ self.log.debug( ++ 'Error retrieving cookie from the persistent storage: {err}' ++ .format(err=e)) + return None + + return session_cookie +-- +2.12.2 + diff --git a/SOURCES/0081-schema-check-Check-current-client-language-against-c.patch b/SOURCES/0081-schema-check-Check-current-client-language-against-c.patch deleted file mode 100644 index 1837ad4..0000000 --- a/SOURCES/0081-schema-check-Check-current-client-language-against-c.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 70430cf0c22ab28a145de775aee343b3605c798a Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 16 Aug 2016 15:36:07 +0200 -Subject: [PATCH] schema check: Check current client language against cached - one - -https://fedorahosted.org/freeipa/ticket/6204 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index e8b3f61bd8460c60630e8710028da79654819bd1..6fc70bf4b294badedd651e15b7e403cc40619f5c 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -7,6 +7,7 @@ import contextlib - import errno - import fcntl - import json -+import locale - import os - import sys - import time -@@ -440,14 +441,19 @@ class Schema(object): - self._dict[ns] = {} - self._namespaces[ns] = _SchemaNameSpace(self, ns) - -+ self._language = ( -+ locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() -+ ) - try: - self._fingerprint = server_info['fingerprint'] - self._expiration = server_info['expiration'] -+ language = server_info['language'] - except KeyError: - is_known = False - else: - is_known = (not api.env.force_schema_check and -- self._expiration > time.time()) -+ self._expiration > time.time() and -+ self._language == language) - - if is_known: - try: -@@ -470,6 +476,7 @@ class Schema(object): - - server_info['fingerprint'] = self._fingerprint - server_info['expiration'] = self._expiration -+ server_info['language'] = self._language - - @contextlib.contextmanager - def _open(self, filename, mode): --- -2.7.4 - diff --git a/SOURCES/0082-Fail-on-topology-disconnect-last-role-removal.patch b/SOURCES/0082-Fail-on-topology-disconnect-last-role-removal.patch deleted file mode 100644 index 91f2417..0000000 --- a/SOURCES/0082-Fail-on-topology-disconnect-last-role-removal.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 90b827a6d23d864bfac96d2ff0f89f1a3ba1d245 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka -Date: Fri, 12 Aug 2016 11:59:41 +0200 -Subject: [PATCH] Fail on topology disconnect/last role removal - -Disconnecting topology/removing last-role-host during server -uninstallation should raise error rather than just being logged -if the appropriate ignore settings are not present. - -https://fedorahosted.org/freeipa/ticket/6168 - -Reviewed-By: Martin Babinsky ---- - ipaserver/install/server/install.py | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 94698898934844350488d5fc52d6e1e567624502..86b8402750b503ea7dacd1f4c59c82d9bd4082e6 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -25,6 +25,7 @@ from ipapython.ipa_log_manager import root_logger - from ipapython.ipautil import ( - decrypt_file, format_netloc, ipa_generate_password, run, user_input, - is_fips_enabled) -+from ipapython.admintool import ScriptError - from ipaplatform import services - from ipaplatform.paths import paths - from ipaplatform.tasks import tasks -@@ -294,7 +295,6 @@ def common_cleanup(func): - def remove_master_from_managed_topology(api_instance, options): - try: - # we may force the removal -- # if the master was already deleted we will just get a warning - server_del_options = dict( - force=True, - ignore_topology_disconnect=options.ignore_topology_disconnect, -@@ -303,8 +303,10 @@ def remove_master_from_managed_topology(api_instance, options): - - replication.run_server_del_as_cli( - api_instance, api_instance.env.host, **server_del_options) -- -+ except errors.ServerRemovalError as e: -+ raise ScriptError(str(e)) - except Exception as e: -+ # if the master was already deleted we will just get a warning - root_logger.warning("Failed to delete master: {}".format(e)) - - --- -2.9.3 - diff --git a/SOURCES/0082-server-install-remove-broken-no-pkinit-check.patch b/SOURCES/0082-server-install-remove-broken-no-pkinit-check.patch new file mode 100644 index 0000000..bb4e410 --- /dev/null +++ b/SOURCES/0082-server-install-remove-broken-no-pkinit-check.patch @@ -0,0 +1,36 @@ +From e4f21a17762e3dcdbe05d9d62255fff9a7e2c8fa Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 4 Apr 2017 10:41:23 +0200 +Subject: [PATCH] server-install: remove broken no-pkinit check + +Don't check for no-pkinit option in case pkinit cert file was +provided. Setting no-pkinit is prohibited in this case, so without +this fix we have an impossible option-check if we want to provide +an own pkinit certificate and private key. + +https://pagure.io/freeipa/issue/6807 + +Reviewed-By: Martin Basti +--- + ipaserver/install/server/install.py | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 197f01ccef58bb3564eb4c6b5b4d615bff1e523d..b899b4be4028e6cdfd95bb9868fba8be25a07b65 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -513,11 +513,6 @@ def install_check(installer): + dirsrv_pkcs12_info = (dirsrv_pkcs12_file.name, dirsrv_pin) + + if options.pkinit_cert_files: +- if not options.no_pkinit: +- raise ScriptError("Cannot create KDC PKINIT certificate and use " +- "provided external PKINIT certificate at the " +- "same time. Please choose one of them.") +- + if options.pkinit_pin is None: + options.pkinit_pin = read_password( + "Enter Kerberos KDC private key unlock", +-- +2.12.2 + diff --git a/SOURCES/0083-Add-the-force-join-option-to-replica-install.patch b/SOURCES/0083-Add-the-force-join-option-to-replica-install.patch new file mode 100644 index 0000000..db317df --- /dev/null +++ b/SOURCES/0083-Add-the-force-join-option-to-replica-install.patch @@ -0,0 +1,55 @@ +From 8af160743817054289d1fff9aa904168e9606061 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 5 Apr 2017 09:49:57 +0200 +Subject: [PATCH] Add the force-join option to replica install + +When installing client from inside replica installation on DL1, +it's possible that the client installation would fail and recommend +using --force-join option which is not available in replica installer. +Add the option there. + +https://pagure.io/freeipa/issue/6183 + +Reviewed-By: Tomas Krizek +Reviewed-By: Jan Cholasta +--- + ipaserver/install/server/__init__.py | 2 +- + ipaserver/install/server/replicainstall.py | 2 ++ + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py +index 89444f21fefc902931b7ecfaba861a18ecc28dbe..028a4aa60feccf5af85f76d443dcb42b01684406 100644 +--- a/ipaserver/install/server/__init__.py ++++ b/ipaserver/install/server/__init__.py +@@ -166,7 +166,6 @@ class ServerInstallInterface(ServerCertificateInstallInterface, + """ + description = "Server" + +- force_join = False + kinit_attempts = 1 + fixed_primary = True + ntp_servers = None +@@ -526,6 +525,7 @@ class ServerMasterInstall(ServerMasterInstallInterface): + Server master installer + """ + ++ force_join = False + servers = None + no_wait_for_dns = True + host_password = None +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index b82d7b474640e24da7d978e9546ebd7a8e602c29..383932b39b9ee99a7a5ce3275a5a7e02581b85b7 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -935,6 +935,8 @@ def ensure_enrolled(installer): + args.append("--no-sshd") + if installer.mkhomedir: + args.append("--mkhomedir") ++ if installer.force_join: ++ args.append("--force-join") + + ipautil.run(args, stdin=stdin, nolog=nolog, redirect_output=True) + print() +-- +2.12.2 + diff --git a/SOURCES/0083-server-install-do-not-prompt-for-cert-file-PIN-repea.patch b/SOURCES/0083-server-install-do-not-prompt-for-cert-file-PIN-repea.patch deleted file mode 100644 index d701518..0000000 --- a/SOURCES/0083-server-install-do-not-prompt-for-cert-file-PIN-repea.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 620dced81e4ef95522fcaf50c0b3e060f911754f Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 16 Aug 2016 17:34:06 +0200 -Subject: [PATCH] server install: do not prompt for cert file PIN repeatedly - -Prompt for PIN only once in interactive mode. - -This fixes ipa-server-install, ipa-server-certinstall and -ipa-replica-prepare prompting over and over when the PIN is empty. - -https://fedorahosted.org/freeipa/ticket/6032 - -Reviewed-By: Pavel Vomacka ---- - ipaserver/install/ipa_replica_prepare.py | 6 +++--- - ipaserver/install/ipa_server_certinstall.py | 3 ++- - ipaserver/install/server/install.py | 6 +++--- - 3 files changed, 8 insertions(+), 7 deletions(-) - -diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py -index fdd32f0c8437a0d8c3947d57089662ea09bb2304..80813086c6a7212bdb6ef9d54202b28808b80076 100644 ---- a/ipaserver/install/ipa_replica_prepare.py -+++ b/ipaserver/install/ipa_replica_prepare.py -@@ -303,7 +303,7 @@ class ReplicaPrepare(admintool.AdminTool): - if options.http_pin is None: - options.http_pin = installutils.read_password( - "Enter Apache Server private key unlock", -- confirm=False, validate=False) -+ confirm=False, validate=False, retry=False) - if options.http_pin is None: - raise admintool.ScriptError( - "Apache Server private key unlock password required") -@@ -317,7 +317,7 @@ class ReplicaPrepare(admintool.AdminTool): - if options.dirsrv_pin is None: - options.dirsrv_pin = installutils.read_password( - "Enter Directory Server private key unlock", -- confirm=False, validate=False) -+ confirm=False, validate=False, retry=False) - if options.dirsrv_pin is None: - raise admintool.ScriptError( - "Directory Server private key unlock password required") -@@ -331,7 +331,7 @@ class ReplicaPrepare(admintool.AdminTool): - if options.pkinit_pin is None: - options.pkinit_pin = installutils.read_password( - "Enter Kerberos KDC private key unlock", -- confirm=False, validate=False) -+ confirm=False, validate=False, retry=False) - if options.pkinit_pin is None: - raise admintool.ScriptError( - "Kerberos KDC private key unlock password required") -diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py -index 5ab47303add479c7c492c251b0cf6646de681a4b..0a8fb214a232e60a89b6c06940b928f97c007b93 100644 ---- a/ipaserver/install/ipa_server_certinstall.py -+++ b/ipaserver/install/ipa_server_certinstall.py -@@ -92,7 +92,8 @@ class ServerCertInstall(admintool.AdminTool): - - if self.options.pin is None: - self.options.pin = installutils.read_password( -- "Enter private key unlock", confirm=False, validate=False) -+ "Enter private key unlock", -+ confirm=False, validate=False, retry=False) - if self.options.pin is None: - raise admintool.ScriptError( - "Private key unlock password required") -diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index 86b8402750b503ea7dacd1f4c59c82d9bd4082e6..b33b0243d4d909a561b59d93f0014c390146b333 100644 ---- a/ipaserver/install/server/install.py -+++ b/ipaserver/install/server/install.py -@@ -488,7 +488,7 @@ def install_check(installer): - if options.http_pin is None: - options.http_pin = installutils.read_password( - "Enter Apache Server private key unlock", -- confirm=False, validate=False) -+ confirm=False, validate=False, retry=False) - if options.http_pin is None: - sys.exit( - "Apache Server private key unlock password required") -@@ -504,7 +504,7 @@ def install_check(installer): - if options.dirsrv_pin is None: - options.dirsrv_pin = read_password( - "Enter Directory Server private key unlock", -- confirm=False, validate=False) -+ confirm=False, validate=False, retry=False) - if options.dirsrv_pin is None: - sys.exit( - "Directory Server private key unlock password required") -@@ -520,7 +520,7 @@ def install_check(installer): - if options.pkinit_pin is None: - options.pkinit_pin = read_password( - "Enter Kerberos KDC private key unlock", -- confirm=False, validate=False) -+ confirm=False, validate=False, retry=False) - if options.pkinit_pin is None: - sys.exit( - "Kerberos KDC private key unlock password required") --- -2.9.3 - diff --git a/SOURCES/0084-replicainstall-better-client-install-exception-handl.patch b/SOURCES/0084-replicainstall-better-client-install-exception-handl.patch new file mode 100644 index 0000000..6e8ac10 --- /dev/null +++ b/SOURCES/0084-replicainstall-better-client-install-exception-handl.patch @@ -0,0 +1,120 @@ +From 9303e3d0912e60b2069f7c5bad6b816ed8b033ef Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 5 Apr 2017 09:57:44 +0200 +Subject: [PATCH] replicainstall: better client install exception handling + +The exception handling of client install inside replica installation +was rather promiscuous, hungrily eating any possible exception thrown +at it. Scoped down the try-except block and reduced its promiscuity. +This change should improve the future development experience debugging +this part of the code. + +https://pagure.io/freeipa/issue/6183 + +Reviewed-By: Tomas Krizek +Reviewed-By: Jan Cholasta +--- + ipaserver/install/server/replicainstall.py | 83 +++++++++++++++--------------- + 1 file changed, 41 insertions(+), 42 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 383932b39b9ee99a7a5ce3275a5a7e02581b85b7..aa8e67f60b8abe591d55a907c409b584c74d4541 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -895,52 +895,51 @@ def install_check(installer): + + + def ensure_enrolled(installer): +- # Call client install script +- service.print_msg("Configuring client side components") ++ args = [paths.IPA_CLIENT_INSTALL, "--unattended", "--no-ntp"] ++ stdin = None ++ nolog = [] ++ ++ if installer.domain_name: ++ args.extend(["--domain", installer.domain_name]) ++ if installer.server: ++ args.extend(["--server", installer.server]) ++ if installer.realm_name: ++ args.extend(["--realm", installer.realm_name]) ++ if installer.host_name: ++ args.extend(["--hostname", installer.host_name]) ++ ++ if installer.password: ++ args.extend(["--password", installer.password]) ++ nolog.append(installer.password) ++ else: ++ if installer.admin_password: ++ # Always set principal if password was set explicitly, ++ # the password itself gets passed directly via stdin ++ args.extend(["--principal", installer.principal or "admin"]) ++ stdin = installer.admin_password ++ if installer.keytab: ++ args.extend(["--keytab", installer.keytab]) ++ ++ if installer.no_dns_sshfp: ++ args.append("--no-dns-sshfp") ++ if installer.ssh_trust_dns: ++ args.append("--ssh-trust-dns") ++ if installer.no_ssh: ++ args.append("--no-ssh") ++ if installer.no_sshd: ++ args.append("--no-sshd") ++ if installer.mkhomedir: ++ args.append("--mkhomedir") ++ if installer.force_join: ++ args.append("--force-join") ++ + try: ++ # Call client install script ++ service.print_msg("Configuring client side components") + installer._enrollment_performed = True +- +- args = [paths.IPA_CLIENT_INSTALL, "--unattended", "--no-ntp"] +- stdin = None +- nolog = [] +- +- if installer.domain_name: +- args.extend(["--domain", installer.domain_name]) +- if installer.server: +- args.extend(["--server", installer.server]) +- if installer.realm_name: +- args.extend(["--realm", installer.realm_name]) +- if installer.host_name: +- args.extend(["--hostname", installer.host_name]) +- +- if installer.password: +- args.extend(["--password", installer.password]) +- nolog.append(installer.password) +- else: +- if installer.admin_password: +- # Always set principal if password was set explicitly, +- # the password itself gets passed directly via stdin +- args.extend(["--principal", installer.principal or "admin"]) +- stdin = installer.admin_password +- if installer.keytab: +- args.extend(["--keytab", installer.keytab]) +- +- if installer.no_dns_sshfp: +- args.append("--no-dns-sshfp") +- if installer.ssh_trust_dns: +- args.append("--ssh-trust-dns") +- if installer.no_ssh: +- args.append("--no-ssh") +- if installer.no_sshd: +- args.append("--no-sshd") +- if installer.mkhomedir: +- args.append("--mkhomedir") +- if installer.force_join: +- args.append("--force-join") +- + ipautil.run(args, stdin=stdin, nolog=nolog, redirect_output=True) + print() +- except Exception: ++ except ipautil.CalledProcessError: + raise ScriptError("Configuration of client side components failed!") + + +-- +2.12.2 + diff --git a/SOURCES/0084-service-add-flag-to-allow-S4U2Self.patch b/SOURCES/0084-service-add-flag-to-allow-S4U2Self.patch deleted file mode 100644 index 2655bd6..0000000 --- a/SOURCES/0084-service-add-flag-to-allow-S4U2Self.patch +++ /dev/null @@ -1,122 +0,0 @@ -From e885fdff4d1bfee23bd41e6e64f64680ae643624 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 11 Aug 2016 11:52:05 +0300 -Subject: [PATCH] service: add flag to allow S4U2Self - -Prerequisite for: https://fedorahosted.org/freeipa/ticket/5764 - -Reviewed-By: Stanislav Laznicka ---- - API.txt | 12 ++++++++---- - VERSION | 4 ++-- - ipaserver/plugins/service.py | 7 +++++++ - 3 files changed, 17 insertions(+), 6 deletions(-) - -diff --git a/API.txt b/API.txt -index 535d8ec9a4990395207e2455a09a8c1bdef5529a..5b83bfbd0b457b77e0522ab7d83abfae4df3ebe9 100644 ---- a/API.txt -+++ b/API.txt -@@ -2260,7 +2260,7 @@ output: Output('summary', type=[, ]) - output: Output('value', type=[]) - output: Output('warning', type=[, , ]) - command: host_add/1 --args: 1,24,3 -+args: 1,25,3 - arg: Str('fqdn', cli_name='hostname') - option: Str('addattr*', cli_name='addattr') - option: Flag('all', autofill=True, cli_name='all', default=False) -@@ -2269,6 +2269,7 @@ option: Flag('force', autofill=True, default=False) - option: Str('ip_address?') - option: Str('ipaassignedidview?') - option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate') -+option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate') - option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth') - option: Str('ipasshpubkey*', cli_name='sshpubkey') - option: Str('krbprincipalauthind*', cli_name='auth_ind') -@@ -2437,7 +2438,7 @@ output: ListOfEntries('result') - output: Output('summary', type=[, ]) - output: Output('truncated', type=[]) - command: host_mod/1 --args: 1,25,3 -+args: 1,26,3 - arg: Str('fqdn', cli_name='hostname') - option: Str('addattr*', cli_name='addattr') - option: Flag('all', autofill=True, cli_name='all', default=False) -@@ -2445,6 +2446,7 @@ option: Str('delattr*', cli_name='delattr') - option: Str('description?', autofill=False, cli_name='desc') - option: Str('ipaassignedidview?', autofill=False) - option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate') -+option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate') - option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth') - option: Str('ipasshpubkey*', autofill=False, cli_name='sshpubkey') - option: Str('krbprincipalauthind*', autofill=False, cli_name='auth_ind') -@@ -4293,13 +4295,14 @@ output: Entry('result') - output: Output('summary', type=[, ]) - output: PrimaryKey('value') - command: service_add/1 --args: 1,12,3 -+args: 1,13,3 - arg: Principal('krbcanonicalname', cli_name='canonical_principal') - option: Str('addattr*', cli_name='addattr') - option: Flag('all', autofill=True, cli_name='all', default=False) - option: Flag('force', autofill=True, default=False) - option: StrEnum('ipakrbauthzdata*', cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE']) - option: Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate') -+option: Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate') - option: Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth') - option: Str('krbprincipalauthind*', cli_name='auth_ind') - option: Flag('no_members', autofill=True, default=False) -@@ -4435,13 +4438,14 @@ output: ListOfEntries('result') - output: Output('summary', type=[, ]) - output: Output('truncated', type=[]) - command: service_mod/1 --args: 1,14,3 -+args: 1,15,3 - arg: Principal('krbcanonicalname', cli_name='canonical_principal') - option: Str('addattr*', cli_name='addattr') - option: Flag('all', autofill=True, cli_name='all', default=False) - option: Str('delattr*', cli_name='delattr') - option: StrEnum('ipakrbauthzdata*', autofill=False, cli_name='pac_type', values=[u'MS-PAC', u'PAD', u'NONE']) - option: Bool('ipakrbokasdelegate?', autofill=False, cli_name='ok_as_delegate') -+option: Bool('ipakrboktoauthasdelegate?', autofill=False, cli_name='ok_to_auth_as_delegate') - option: Bool('ipakrbrequirespreauth?', autofill=False, cli_name='requires_pre_auth') - option: Str('krbprincipalauthind*', autofill=False, cli_name='auth_ind') - option: Principal('krbprincipalname*', autofill=False, cli_name='principal') -diff --git a/VERSION b/VERSION -index ca489965050f32d2d8987dfd251ec2b2a0ba1768..a8b89ed305bcfdf2990a7400d005a68d734fa7e8 100644 ---- a/VERSION -+++ b/VERSION -@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 - # # - ######################################################## - IPA_API_VERSION_MAJOR=2 --IPA_API_VERSION_MINOR=211 --# Last change: mbabinsk: allow 'value' output param in commands without primary key -+IPA_API_VERSION_MINOR=212 -+# Last change: ab: service: add flag to allow S4U2Self -diff --git a/ipaserver/plugins/service.py b/ipaserver/plugins/service.py -index a44dcaa5e348d3deedda6c0b4f55760ad873cf49..04d1916fe989a8651bcc4d44f1914c460be1081c 100644 ---- a/ipaserver/plugins/service.py -+++ b/ipaserver/plugins/service.py -@@ -171,11 +171,18 @@ ticket_flags_params = ( - doc=_('Client credentials may be delegated to the service'), - flags=['virtual_attribute', 'no_search'], - ), -+ Bool('ipakrboktoauthasdelegate?', -+ cli_name='ok_to_auth_as_delegate', -+ label=_('Trusted to authenticate as user'), -+ doc=_('The service is allowed to authenticate on behalf of a client'), -+ flags=['virtual_attribute', 'no_search'], -+ ), - ) - - _ticket_flags_map = { - 'ipakrbrequirespreauth': 0x00000080, - 'ipakrbokasdelegate': 0x00100000, -+ 'ipakrboktoauthasdelegate': 0x00200000, - } - - _ticket_flags_default = _ticket_flags_map['ipakrbrequirespreauth'] --- -2.7.4 - diff --git a/SOURCES/0085-Add-trusted-to-auth-as-user-checkbox.patch b/SOURCES/0085-Add-trusted-to-auth-as-user-checkbox.patch deleted file mode 100644 index 46d91b1..0000000 --- a/SOURCES/0085-Add-trusted-to-auth-as-user-checkbox.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 9bad7f0d876a0ed4f7ee9fdff6ca6d117debf404 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Thu, 11 Aug 2016 18:53:55 +0200 -Subject: [PATCH] Add 'trusted to auth as user' checkbox - -Add new checkbox to host and service details page - -Prerequisite for: https://fedorahosted.org/freeipa/ticket/5764 - -Reviewed-By: Stanislav Laznicka ---- - install/ui/src/freeipa/host.js | 5 +++++ - install/ui/src/freeipa/service.js | 5 +++++ - 2 files changed, 10 insertions(+) - -diff --git a/install/ui/src/freeipa/host.js b/install/ui/src/freeipa/host.js -index 33d443c2bc96c385bd13abf4d85adda6e51db718..87cf264ef20b79aceed639f45d926fd7aef19edf 100644 ---- a/install/ui/src/freeipa/host.js -+++ b/install/ui/src/freeipa/host.js -@@ -142,6 +142,11 @@ return { - flags: ['w_if_no_aci'] - }, - { -+ name: 'ipakrboktoauthasdelegate', -+ $type: 'checkbox', -+ acl_param: 'krbticketflags' -+ }, -+ { - name: 'ipaassignedidview', - $type: 'link', - label: '@i18n:objects.idview.ipaassignedidview', -diff --git a/install/ui/src/freeipa/service.js b/install/ui/src/freeipa/service.js -index 35d486605ebfee41d8b3ffa5bb77bf9e72a60c01..30e336c35b8eece2e5e3ef55629d0c98f097fbf5 100644 ---- a/install/ui/src/freeipa/service.js -+++ b/install/ui/src/freeipa/service.js -@@ -142,6 +142,11 @@ return { - acl_param: 'krbticketflags' - }, - { -+ name: 'ipakrboktoauthasdelegate', -+ $type: 'checkbox', -+ acl_param: 'krbticketflags' -+ }, -+ { - name: 'ipakrbrequirespreauth', - $type: 'checkbox', - acl_param: 'krbticketflags' --- -2.7.4 - diff --git a/SOURCES/0085-Fix-CA-less-to-CA-full-upgrade.patch b/SOURCES/0085-Fix-CA-less-to-CA-full-upgrade.patch new file mode 100644 index 0000000..18f9500 --- /dev/null +++ b/SOURCES/0085-Fix-CA-less-to-CA-full-upgrade.patch @@ -0,0 +1,110 @@ +From c3ee037c2dd92ccb277523919e991471c9caa3c6 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 11 Apr 2017 10:21:15 +0200 +Subject: [PATCH] Fix CA-less to CA-full upgrade + +CertDB would have always created a directory on initialization. This +behavior changes here by replacing the truncate argument with create +which will only create the database when really required. + +https://pagure.io/freeipa/issue/6853 + +Reviewed-By: Tomas Krizek +--- + ipaserver/install/ca.py | 2 ++ + ipaserver/install/certs.py | 38 ++++++++++++++++++++++++++++---------- + ipaserver/install/httpinstance.py | 2 +- + 3 files changed, 31 insertions(+), 11 deletions(-) + +diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py +index db3b744a51b0ae2ba12f79c155a1bb0698d94bec..8ee0fda23411563c70b7db5f39f43c2869c108b5 100644 +--- a/ipaserver/install/ca.py ++++ b/ipaserver/install/ca.py +@@ -183,6 +183,8 @@ def install_check(standalone, replica_config, options): + realm_name, nssdir=dirname, subject_base=options._subject_base) + + for db in (cadb, dsdb): ++ if not db.exists(): ++ continue + for nickname, _trust_flags in db.list_certs(): + if nickname == certdb.get_ca_nickname(realm_name): + raise ScriptError( +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 16139f81f0d0bd6889a9f38948204bb5bc018028..89e57134f24c505d669057eefffb7862b3b8179a 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -99,7 +99,7 @@ class CertDB(object): + # TODO: Remove all selfsign code + def __init__(self, realm, nssdir, fstore=None, + host_name=None, subject_base=None, ca_subject=None, +- user=None, group=None, mode=None, truncate=False): ++ user=None, group=None, mode=None, create=False): + self.nssdb = NSSDatabase(nssdir) + + self.secdir = nssdir +@@ -132,15 +132,16 @@ class CertDB(object): + self.uid = 0 + self.gid = 0 + +- if not truncate and os.path.exists(self.secdir): +- # We are going to set the owner of all of the cert +- # files to the owner of the containing directory +- # instead of that of the process. This works when +- # this is called by root for a daemon that runs as +- # a normal user +- mode = os.stat(self.secdir) +- self.uid = mode[stat.ST_UID] +- self.gid = mode[stat.ST_GID] ++ if not create: ++ if os.path.isdir(self.secdir): ++ # We are going to set the owner of all of the cert ++ # files to the owner of the containing directory ++ # instead of that of the process. This works when ++ # this is called by root for a daemon that runs as ++ # a normal user ++ mode = os.stat(self.secdir) ++ self.uid = mode[stat.ST_UID] ++ self.gid = mode[stat.ST_GID] + else: + if user is not None: + pu = pwd.getpwnam(user) +@@ -162,6 +163,23 @@ class CertDB(object): + def passwd_fname(self): + return self.nssdb.pwd_file + ++ def exists(self): ++ """ ++ Checks whether all NSS database files + our pwd_file exist ++ """ ++ db_files = ( ++ self.secdir, ++ self.certdb_fname, ++ self.keydb_fname, ++ self.secmod_fname, ++ self.nssdb.pwd_file, ++ ) ++ ++ for f in db_files: ++ if not os.path.exists(f): ++ return False ++ return True ++ + def __del__(self): + if self.reqdir is not None: + shutil.rmtree(self.reqdir, ignore_errors=True) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 8e444be2d23ec5e7890d221508bc866de2854c89..aeb5c5e450813469e1b6cd374b30cd4aab338537 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -366,7 +366,7 @@ class HTTPInstance(service.Service): + db = certs.CertDB(self.realm, nssdir=paths.HTTPD_ALIAS_DIR, + subject_base=self.subject_base, user="root", + group=constants.HTTPD_GROUP, +- truncate=True) ++ create=True) + self.disable_system_trust() + self.create_password_conf() + if self.pkcs12_info: +-- +2.12.2 + diff --git a/SOURCES/0086-Added-new-authentication-method.patch b/SOURCES/0086-Added-new-authentication-method.patch deleted file mode 100644 index fb222f6..0000000 --- a/SOURCES/0086-Added-new-authentication-method.patch +++ /dev/null @@ -1,79 +0,0 @@ -From b620de7a08aa626290f166213bb8e1eac62a47be Mon Sep 17 00:00:00 2001 -From: Tiboris -Date: Tue, 16 Aug 2016 14:13:29 +0200 -Subject: [PATCH] Added new authentication method - -Addressing ticket https://fedorahosted.org/freeipa/ticket/5764 - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/plugins/xmlserver.py | 6 +++++- - ipaserver/rpcserver.py | 17 +++++++++++++---- - 2 files changed, 18 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/plugins/xmlserver.py b/ipaserver/plugins/xmlserver.py -index d8fe24e0cb407603e9898e934229c9373f3c8b62..08c7456ed6dbfcc59f532314894031fba584e20a 100644 ---- a/ipaserver/plugins/xmlserver.py -+++ b/ipaserver/plugins/xmlserver.py -@@ -28,12 +28,16 @@ register = Registry() - - - if api.env.context in ('server', 'lite'): -- from ipaserver.rpcserver import wsgi_dispatch, xmlserver, jsonserver_kerb, jsonserver_session, login_kerberos, login_password, change_password, sync_token, xmlserver_session -+ from ipaserver.rpcserver import ( -+ wsgi_dispatch, xmlserver, jsonserver_kerb, jsonserver_session, -+ login_kerberos, login_x509, login_password, change_password, -+ sync_token, xmlserver_session) - register()(wsgi_dispatch) - register()(xmlserver) - register()(jsonserver_kerb) - register()(jsonserver_session) - register()(login_kerberos) -+ register()(login_x509) - register()(login_password) - register()(change_password) - register()(sync_token) -diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py -index d036f3c27521f17709672b830d5aa58167c76b34..e48dc3498d6ed8feb6ea44a9a678a8b8c50e8d9b 100644 ---- a/ipaserver/rpcserver.py -+++ b/ipaserver/rpcserver.py -@@ -857,16 +857,16 @@ class jsonserver_kerb(jsonserver, KerberosWSGIExecutioner): - key = '/json' - - --class login_kerberos(Backend, KerberosSession, HTTP_Status): -- key = '/session/login_kerberos' -+class KerberosLogin(Backend, KerberosSession, HTTP_Status): -+ key = None - - def _on_finalize(self): -- super(login_kerberos, self)._on_finalize() -+ super(KerberosLogin, self)._on_finalize() - self.api.Backend.wsgi_dispatch.mount(self, self.key) - self.kerb_session_on_finalize() - - def __call__(self, environ, start_response): -- self.debug('WSGI login_kerberos.__call__:') -+ self.debug('WSGI KerberosLogin.__call__:') - - # Get the ccache created by mod_auth_gssapi - user_ccache_name=environ.get('KRB5CCNAME') -@@ -876,6 +876,15 @@ class login_kerberos(Backend, KerberosSession, HTTP_Status): - - return self.finalize_kerberos_acquisition('login_kerberos', user_ccache_name, environ, start_response) - -+ -+class login_kerberos(KerberosLogin): -+ key = '/session/login_kerberos' -+ -+ -+class login_x509(KerberosLogin): -+ key = '/session/login_x509' -+ -+ - class login_password(Backend, KerberosSession, HTTP_Status): - - content_type = 'text/plain' --- -2.7.4 - diff --git a/SOURCES/0086-cert-defer-cert-find-result-post-processing.patch b/SOURCES/0086-cert-defer-cert-find-result-post-processing.patch new file mode 100644 index 0000000..044f33a --- /dev/null +++ b/SOURCES/0086-cert-defer-cert-find-result-post-processing.patch @@ -0,0 +1,221 @@ +From eb9d14debc4276f422ae55d141e30246d5943067 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 30 Mar 2017 08:33:30 +0000 +Subject: [PATCH] cert: defer cert-find result post-processing + +Rather than post-processing the results of each internal search, +post-process the combined result. + +This avoids expensive per-certificate searches when cert-find is executed +with the --all option on certificates which won't even be included in the +combined result. + +https://pagure.io/freeipa/issue/6808 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/plugins/cert.py | 93 +++++++++++++++++++++++++++------------------ + ipaserver/plugins/dogtag.py | 10 +++++ + 2 files changed, 66 insertions(+), 37 deletions(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index dfc7444ddbf31ac3c194e050af28220fc2a87a92..68402679cf0320e9c664ea89276f6c4332730a15 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -162,6 +162,11 @@ def normalize_pkidate(value): + return datetime.datetime.strptime(value, PKIDATE_FORMAT) + + ++def convert_pkidatetime(value): ++ value = datetime.datetime.fromtimestamp(int(value) // 1000) ++ return x509.format_datetime(value) ++ ++ + def validate_csr(ugettext, csr): + """ + Ensure the CSR is base64-encoded and can be decoded by our PKCS#10 +@@ -1296,18 +1301,7 @@ class cert_find(Search, CertMethod): + + return (DN(cert_obj.issuer), cert_obj.serial_number) + +- def _get_cert_obj(self, cert, all, raw, pkey_only): +- obj = {'certificate': base64.b64encode(cert).decode('ascii')} +- +- full = not pkey_only and all +- if not raw: +- self.obj._parse(obj, full) +- if not full: +- del obj['certificate'] +- +- return obj +- +- def _cert_search(self, all, raw, pkey_only, **options): ++ def _cert_search(self, pkey_only, **options): + result = collections.OrderedDict() + + try: +@@ -1316,15 +1310,19 @@ class cert_find(Search, CertMethod): + return result, False, False + + try: +- key = self._get_cert_key(cert) ++ issuer, serial_number = self._get_cert_key(cert) + except ValueError: + return result, True, True + +- result[key] = self._get_cert_obj(cert, all, raw, pkey_only) ++ obj = {'serial_number': serial_number} ++ if not pkey_only: ++ obj['certificate'] = base64.b64encode(cert).decode('ascii') ++ ++ result[issuer, serial_number] = obj + + return result, False, True + +- def _ca_search(self, all, raw, pkey_only, exactly, **options): ++ def _ca_search(self, raw, pkey_only, exactly, **options): + ra_options = {} + for name in ('revocation_reason', + 'issuer', +@@ -1357,7 +1355,6 @@ class cert_find(Search, CertMethod): + return result, False, complete + + ca_objs = self.api.Command.ca_find( +- all=all, + timelimit=0, + sizelimit=0, + )['result'] +@@ -1377,24 +1374,16 @@ class cert_find(Search, CertMethod): + obj = {'serial_number': serial_number} + else: + obj = ra_obj +- if all: +- obj.update(ra.get_certificate(str(serial_number))) + + if not raw: + obj['issuer'] = issuer + obj['subject'] = DN(ra_obj['subject']) ++ obj['valid_not_before'] = ( ++ convert_pkidatetime(obj['valid_not_before'])) ++ obj['valid_not_after'] = ( ++ convert_pkidatetime(obj['valid_not_after'])) + obj['revoked'] = ( + ra_obj['status'] in (u'REVOKED', u'REVOKED_EXPIRED')) +- if all: +- obj['certificate'] = ( +- obj['certificate'].replace('\r\n', '')) +- self.obj._parse(obj) +- +- if 'certificate_chain' in ca_obj: +- cert = x509.load_certificate(obj['certificate']) +- cert_der = cert.public_bytes(serialization.Encoding.DER) +- obj['certificate_chain'] = ( +- [cert_der] + ca_obj['certificate_chain']) + + obj['cacn'] = ca_obj['cn'][0] + +@@ -1402,7 +1391,7 @@ class cert_find(Search, CertMethod): + + return result, False, complete + +- def _ldap_search(self, all, raw, pkey_only, no_members, **options): ++ def _ldap_search(self, all, pkey_only, no_members, **options): + ldap = self.api.Backend.ldap2 + + filters = [] +@@ -1461,26 +1450,25 @@ class cert_find(Search, CertMethod): + for attr in ('usercertificate', 'usercertificate;binary'): + for cert in entry.get(attr, []): + try: +- key = self._get_cert_key(cert) ++ issuer, serial_number = self._get_cert_key(cert) + except ValueError: + truncated = True + continue + + try: +- obj = result[key] ++ obj = result[issuer, serial_number] + except KeyError: +- obj = self._get_cert_obj(cert, all, raw, pkey_only) +- result[key] = obj ++ obj = {'serial_number': serial_number} ++ if not pkey_only and all: ++ obj['certificate'] = ( ++ base64.b64encode(cert).decode('ascii')) ++ result[issuer, serial_number] = obj + + if not pkey_only and (all or not no_members): + owners = obj.setdefault('owner', []) + if entry.dn not in owners: + owners.append(entry.dn) + +- if not raw: +- for obj in six.itervalues(result): +- self.obj._fill_owners(obj) +- + return result, truncated, complete + + def execute(self, criteria=None, all=False, raw=False, pkey_only=False, +@@ -1537,6 +1525,37 @@ class cert_find(Search, CertMethod): + truncated = truncated or sub_truncated + complete = complete or sub_complete + ++ if not pkey_only: ++ ca_objs = {} ++ ra = self.api.Backend.ra ++ ++ for key, obj in six.iteritems(result): ++ if all and 'cacn' in obj: ++ _issuer, serial_number = key ++ cacn = obj['cacn'] ++ ++ try: ++ ca_obj = ca_objs[cacn] ++ except KeyError: ++ ca_obj = ca_objs[cacn] = ( ++ self.api.Command.ca_show(cacn, all=True)['result']) ++ ++ obj.update(ra.get_certificate(str(serial_number))) ++ if not raw: ++ obj['certificate'] = ( ++ obj['certificate'].replace('\r\n', '')) ++ ++ if 'certificate_chain' in ca_obj: ++ cert = x509.load_certificate(obj['certificate']) ++ cert_der = ( ++ cert.public_bytes(serialization.Encoding.DER)) ++ obj['certificate_chain'] = ( ++ [cert_der] + ca_obj['certificate_chain']) ++ ++ if not raw: ++ self.obj._parse(obj, all) ++ self.obj._fill_owners(obj) ++ + result = list(six.itervalues(result)) + if sizelimit > 0 and len(result) > sizelimit: + if not truncated: +diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py +index d1dd707f145e0f58bfa721df55513d46c14358f2..3997531032746a22243a4219250af4172e9ae5b3 100644 +--- a/ipaserver/plugins/dogtag.py ++++ b/ipaserver/plugins/dogtag.py +@@ -1945,6 +1945,16 @@ class ra(rabase.rabase, RestClient): + if len(issuer_dn) == 1: + response_request['issuer'] = unicode(issuer_dn[0].text) + ++ not_valid_before = cert.xpath('NotValidBefore') ++ if len(not_valid_before) == 1: ++ response_request['valid_not_before'] = ( ++ unicode(not_valid_before[0].text)) ++ ++ not_valid_after = cert.xpath('NotValidAfter') ++ if len(not_valid_after) == 1: ++ response_request['valid_not_after'] = ( ++ unicode(not_valid_after[0].text)) ++ + status = cert.xpath('Status') + if len(status) == 1: + response_request['status'] = unicode(status[0].text) +-- +2.12.2 + diff --git a/SOURCES/0087-schema-cache-Fallback-to-en_us-when-locale-is-not-av.patch b/SOURCES/0087-schema-cache-Fallback-to-en_us-when-locale-is-not-av.patch deleted file mode 100644 index 0d7d637..0000000 --- a/SOURCES/0087-schema-cache-Fallback-to-en_us-when-locale-is-not-av.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 444907f8dd6d840bfbb97cf65ae754f0d816f706 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 18 Aug 2016 10:59:09 +0200 -Subject: [PATCH] schema cache: Fallback to 'en_us' when locale is not - available - -https://fedorahosted.org/freeipa/ticket/6204 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/schema.py | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index 6fc70bf4b294badedd651e15b7e403cc40619f5c..8a77a15d489f067ab1312e863178458570403cc6 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -441,9 +441,15 @@ class Schema(object): - self._dict[ns] = {} - self._namespaces[ns] = _SchemaNameSpace(self, ns) - -- self._language = ( -- locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() -- ) -+ # copy-paste from ipalib/rpc.py -+ try: -+ self._language = ( -+ locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() -+ ) -+ except locale.Error: -+ # fallback to default locale -+ self._language = 'en_us' -+ - try: - self._fingerprint = server_info['fingerprint'] - self._expiration = server_info['expiration'] --- -2.7.4 - diff --git a/SOURCES/0087-server-install-No-double-Kerberos-install.patch b/SOURCES/0087-server-install-No-double-Kerberos-install.patch new file mode 100644 index 0000000..9750dd7 --- /dev/null +++ b/SOURCES/0087-server-install-No-double-Kerberos-install.patch @@ -0,0 +1,42 @@ +From fabf804e7351b546310cc1f50164785099ff1811 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 18 Apr 2017 17:14:27 +0200 +Subject: [PATCH] server-install: No double Kerberos install + +When we're installing server with an external CA, the installation +would have failed in the second step where it's passed the required +CA cert file because it would have tried to perform the Kerberos +installation for the second time. + +https://pagure.io/freeipa/issue/6757 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/server/install.py | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index b899b4be4028e6cdfd95bb9868fba8be25a07b65..b360e0532ce1b9b729be1cc2398cb2b46620901c 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -762,11 +762,12 @@ def install(installer): + options.subject_base, options.ca_subject, 1101, 1100, None) + + krb = krbinstance.KrbInstance(fstore) +- krb.create_instance(realm_name, host_name, domain_name, +- dm_password, master_password, +- setup_pkinit=not options.no_pkinit, +- pkcs12_info=pkinit_pkcs12_info, +- subject_base=options.subject_base) ++ if not options.external_cert_files: ++ krb.create_instance(realm_name, host_name, domain_name, ++ dm_password, master_password, ++ setup_pkinit=not options.no_pkinit, ++ pkcs12_info=pkinit_pkcs12_info, ++ subject_base=options.subject_base) + + if setup_ca: + if not options.external_cert_files and options.external_ca: +-- +2.12.2 + diff --git a/SOURCES/0088-cert-revoke-fix-permission-check-bypass-CVE-2016-540.patch b/SOURCES/0088-cert-revoke-fix-permission-check-bypass-CVE-2016-540.patch deleted file mode 100644 index 7876cbf..0000000 --- a/SOURCES/0088-cert-revoke-fix-permission-check-bypass-CVE-2016-540.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 18d4af260f777920dc2b474a588c3dcda20d8801 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 30 Jun 2016 10:21:01 +1000 -Subject: [PATCH] cert-revoke: fix permission check bypass (CVE-2016-5404) - -The 'cert_revoke' command checks the 'revoke certificate' -permission, however, if an ACIError is raised, it then invokes the -'cert_show' command. The rational was to re-use a "host manages -certificate" check that is part of the 'cert_show' command, however, -it is sufficient that 'cert_show' executes successfully for -'cert_revoke' to recover from the ACIError continue. Therefore, -anyone with 'retrieve certificate' permission can revoke *any* -certificate and cause various kinds of DoS. - -Fix the problem by extracting the "host manages certificate" check -to its own method and explicitly calling it from 'cert_revoke'. - -Fixes: https://fedorahosted.org/freeipa/ticket/6232 -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/cert.py | 60 +++++++++++++++++++++++++---------------------- - 1 file changed, 32 insertions(+), 28 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index b8df074a186ca91daa8e8f5e725724ea7bc5a663..6dd9f6ffcdcd9d051d50d912996fea2104d71dff 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -242,6 +242,24 @@ def validate_certificate(value): - return x509.validate_certificate(value, x509.DER) - - -+def bind_principal_can_manage_cert(cert): -+ """Check that the bind principal can manage the given cert. -+ -+ ``cert`` -+ An NSS certificate object. -+ -+ """ -+ bind_principal = kerberos.Principal(getattr(context, 'principal')) -+ if not bind_principal.is_host: -+ return False -+ -+ hostname = bind_principal.hostname -+ -+ # If we have a hostname we want to verify that the subject -+ # of the certificate matches it. -+ return hostname == cert.subject.common_name #pylint: disable=E1101 -+ -+ - class BaseCertObject(Object): - takes_params = ( - Bytes( -@@ -744,18 +762,6 @@ class cert_show(Retrieve, CertMethod, VirtualCommand): - def execute(self, serial_number, all=False, raw=False, no_members=False, - **options): - ca_enabled_check() -- hostname = None -- try: -- self.check_access() -- except errors.ACIError as acierr: -- self.debug("Not granted by ACI to retrieve certificate, looking at principal") -- bind_principal = kerberos.Principal(getattr(context, 'principal')) -- if not bind_principal.is_host: -- raise acierr -- hostname = bind_principal.hostname -- -- ca_obj = api.Command.ca_show(options['cacn'])['result'] -- issuer_dn = ca_obj['ipacasubjectdn'][0] - - # Dogtag lightweight CAs have shared serial number domain, so - # we don't tell Dogtag the issuer (but we check the cert after). -@@ -763,7 +769,15 @@ class cert_show(Retrieve, CertMethod, VirtualCommand): - result = self.Backend.ra.get_certificate(str(serial_number)) - cert = x509.load_certificate(result['certificate']) - -- if DN(unicode(cert.issuer)) != DN(issuer_dn): -+ try: -+ self.check_access() -+ except errors.ACIError as acierr: -+ self.debug("Not granted by ACI to retrieve certificate, looking at principal") -+ if not bind_principal_can_manage_cert(cert): -+ raise acierr # pylint: disable=E0702 -+ -+ ca_obj = api.Command.ca_show(options['cacn'])['result'] -+ if DN(unicode(cert.issuer)) != DN(ca_obj['ipacasubjectdn'][0]): - # DN of cert differs from what we requested - raise errors.NotFound( - reason=_("Certificate with serial number %(serial)s " -@@ -789,12 +803,6 @@ class cert_show(Retrieve, CertMethod, VirtualCommand): - result['revoked'] = ('revocation_reason' in result) - self.obj._fill_owners(result) - -- if hostname: -- # If we have a hostname we want to verify that the subject -- # of the certificate matches it, otherwise raise an error -- if hostname != cert.subject.common_name: #pylint: disable=E1101 -- raise acierr -- - return dict(result=result, value=pkey_to_value(serial_number, options)) - - -@@ -819,22 +827,18 @@ class cert_revoke(PKQuery, CertMethod, VirtualCommand): - - # Make sure that the cert specified by issuer+serial exists. - # Will raise NotFound if it does not. -- cert_show_options = dict(cacn=kw['cacn']) -- api.Command.cert_show(unicode(serial_number), **cert_show_options) -+ resp = api.Command.cert_show(unicode(serial_number), cacn=kw['cacn']) - -- hostname = None - try: - self.check_access() - except errors.ACIError as acierr: - self.debug("Not granted by ACI to revoke certificate, looking at principal") - try: -- # Let cert_show() handle verifying that the subject of the -- # cert we're dealing with matches the hostname in the principal -- result = api.Command['cert_show']( -- unicode(serial_number), **cert_show_options -- )['result'] -+ cert = x509.load_certificate(resp['result']['certificate']) -+ if not bind_principal_can_manage_cert(cert): -+ raise acierr - except errors.NotImplementedError: -- pass -+ raise acierr - revocation_reason = kw['revocation_reason'] - if revocation_reason == 7: - raise errors.CertificateOperationError(error=_('7 is not a valid revocation reason')) --- -2.9.3 - diff --git a/SOURCES/0088-ext.-CA-correctly-write-the-cert-chain.patch b/SOURCES/0088-ext.-CA-correctly-write-the-cert-chain.patch new file mode 100644 index 0000000..92d8a1c --- /dev/null +++ b/SOURCES/0088-ext.-CA-correctly-write-the-cert-chain.patch @@ -0,0 +1,35 @@ +From 3ee73ed6d739a9d89dadd78f37388e8cfdba143b Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 18 Apr 2017 17:17:48 +0200 +Subject: [PATCH] ext. CA: correctly write the cert chain + +The cert file would have been rewritten all over again with +any of the cert in the CA cert chain without this patch. + +https://pagure.io/freeipa/issue/6872 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/cainstance.py | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index ac5d9e2fc633c5ad732670245b72bee0f03268a6..e2070e39f7e162fcff6e1f8cca41218e440b5f58 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -783,9 +783,10 @@ class CAInstance(DogtagInstance): + certlist = x509.pkcs7_to_pems(data, x509.DER) + + # We have all the certificates in certlist, write them to a PEM file +- for cert in certlist: +- with open(paths.IPA_CA_CRT, 'w') as ipaca_pem: ++ with open(paths.IPA_CA_CRT, 'w') as ipaca_pem: ++ for cert in certlist: + ipaca_pem.write(cert) ++ ipaca_pem.write('\n') + + def __request_ra_certificate(self): + # create a temp file storing the pwd +-- +2.12.2 + diff --git a/SOURCES/0089-Fix-RA-cert-import-during-DL0-replication.patch b/SOURCES/0089-Fix-RA-cert-import-during-DL0-replication.patch new file mode 100644 index 0000000..0804309 --- /dev/null +++ b/SOURCES/0089-Fix-RA-cert-import-during-DL0-replication.patch @@ -0,0 +1,122 @@ +From 899f9b980afba02cfdf80155905354a7371ad871 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 19 Apr 2017 11:42:40 +0200 +Subject: [PATCH] Fix RA cert import during DL0 replication + +Previous versions of FreeIPA add password to the ra.p12 file +contained in the password-protected tarball. This was forgotten +about in the recent changes and fixed now. + +https://pagure.io/freeipa/issue/6878 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/cainstance.py | 43 +++++++++++++++++++------------- + ipaserver/install/ipa_replica_prepare.py | 17 +++++++------ + 2 files changed, 35 insertions(+), 25 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index e2070e39f7e162fcff6e1f8cca41218e440b5f58..640d2884130dd152012e50dde45514f5ca26a523 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -338,6 +338,7 @@ class CAInstance(DogtagInstance): + self.clone = True + self.master_host = master_host + self.master_replication_port = master_replication_port ++ self.ra_p12 = ra_p12 + + self.subject_base = \ + subject_base or installutils.default_subject_base(self.realm) +@@ -400,7 +401,7 @@ class CAInstance(DogtagInstance): + self.step("Importing RA key", self.__import_ra_key) + else: + self.step("importing RA certificate from PKCS #12 file", +- lambda: self.import_ra_cert(ra_p12)) ++ self.__import_ra_cert) + + if not ra_only: + self.step("setting up signing cert profile", self.__setup_sign_profile) +@@ -673,28 +674,36 @@ class CAInstance(DogtagInstance): + 'NSS_ENABLE_PKIX_VERIFY', '1', + quotes=False, separator='=') + +- def import_ra_cert(self, rafile): ++ def __import_ra_cert(self): ++ """ ++ Helper method for IPA domain level 0 replica install ++ """ ++ self.import_ra_cert(self.ra_p12, self.dm_password) ++ ++ def import_ra_cert(self, rafile, password=''): + """ + Cloned RAs will use the same RA agent cert as the master so we + need to import from a PKCS#12 file. + + Used when setting up replication + """ +- # get the private key from the file +- ipautil.run([paths.OPENSSL, +- "pkcs12", +- "-in", rafile, +- "-nocerts", "-nodes", +- "-out", paths.RA_AGENT_KEY, +- "-passin", "pass:"]) +- +- # get the certificate from the pkcs12 file +- ipautil.run([paths.OPENSSL, +- "pkcs12", +- "-in", rafile, +- "-clcerts", "-nokeys", +- "-out", paths.RA_AGENT_PEM, +- "-passin", "pass:"]) ++ with ipautil.write_tmp_file(password) as f: ++ pwdarg = 'file:{file}'.format(file=f.name) ++ # get the private key from the file ++ ipautil.run([paths.OPENSSL, ++ "pkcs12", ++ "-in", rafile, ++ "-nocerts", "-nodes", ++ "-out", paths.RA_AGENT_KEY, ++ "-passin", pwdarg]) ++ ++ # get the certificate from the pkcs12 file ++ ipautil.run([paths.OPENSSL, ++ "pkcs12", ++ "-in", rafile, ++ "-clcerts", "-nokeys", ++ "-out", paths.RA_AGENT_PEM, ++ "-passin", pwdarg]) + self.__set_ra_cert_perms() + + self.configure_agent_renewal() +diff --git a/ipaserver/install/ipa_replica_prepare.py b/ipaserver/install/ipa_replica_prepare.py +index 95c3818a9fc34c937f8b418e91a1bfc28352b02e..d4456dd796167c3717be013d2378413519a3b366 100644 +--- a/ipaserver/install/ipa_replica_prepare.py ++++ b/ipaserver/install/ipa_replica_prepare.py +@@ -571,14 +571,15 @@ class ReplicaPrepare(admintool.AdminTool): + def export_ra_pkcs12(self): + if (os.path.exists(paths.RA_AGENT_PEM) and + os.path.exists(paths.RA_AGENT_KEY)): +- ipautil.run([ +- paths.OPENSSL, +- "pkcs12", "-export", +- "-inkey", paths.RA_AGENT_KEY, +- "-in", paths.RA_AGENT_PEM, +- "-out", os.path.join(self.dir, "ra.p12"), +- "-passout", "pass:" +- ]) ++ with ipautil.write_tmp_file(self.dirman_password) as f: ++ ipautil.run([ ++ paths.OPENSSL, ++ "pkcs12", "-export", ++ "-inkey", paths.RA_AGENT_KEY, ++ "-in", paths.RA_AGENT_PEM, ++ "-out", os.path.join(self.dir, "ra.p12"), ++ "-passout", "file:{pwfile}".format(pwfile=f.name) ++ ]) + + def update_pki_admin_password(self): + dn = DN('uid=admin', 'ou=people', 'o=ipaca') +-- +2.12.2 + diff --git a/SOURCES/0089-Fix-container-owner-should-be-able-to-add-vault.patch b/SOURCES/0089-Fix-container-owner-should-be-able-to-add-vault.patch deleted file mode 100644 index 03c7269..0000000 --- a/SOURCES/0089-Fix-container-owner-should-be-able-to-add-vault.patch +++ /dev/null @@ -1,34 +0,0 @@ -From d3e11b06bbb996b1605f15912be106dcf47b357a Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Thu, 18 Aug 2016 10:11:25 +0200 -Subject: [PATCH] Fix: container owner should be able to add vault - -With recent change in DS (CVE fix), ds is not returging DuplicatedEntry -error in case that user is not permitted by ACI to write, but ACIError instead. - -Is safe to ignore ACI error in container, because it will be raised -again later if user has no access to container. - -https://fedorahosted.org/freeipa/ticket/6159 - -Reviewed-By: Martin Basti ---- - ipaserver/plugins/vault.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py -index c9b7cb942cfbca74134bce4ba039619b4f5f2845..5c4c09685ceb95c6634306c4275008d602099e12 100644 ---- a/ipaserver/plugins/vault.py -+++ b/ipaserver/plugins/vault.py -@@ -783,7 +783,7 @@ class vault_add_internal(LDAPCreate): - - try: - self.obj.create_container(parent_dn, owner_dn) -- except errors.DuplicateEntry as e: -+ except (errors.DuplicateEntry, errors.ACIError): - pass - - # vault should be owned by the creator --- -2.7.4 - diff --git a/SOURCES/0090-configure-fix-AC_CHECK_LIB-usage.patch b/SOURCES/0090-configure-fix-AC_CHECK_LIB-usage.patch new file mode 100644 index 0000000..edc2836 --- /dev/null +++ b/SOURCES/0090-configure-fix-AC_CHECK_LIB-usage.patch @@ -0,0 +1,64 @@ +From 03750b1c1ba8ed670691e4e464d110b9329d85be Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 5 Apr 2017 10:24:17 +0000 +Subject: [PATCH] configure: fix AC_CHECK_LIB usage + +Replace empty string with a single space in the third argument of +`AC_CHECK_LIB` (`action-if-found`) where applicable. + +Empty string in the argument causes `AC_CHECK_LIB` to use the default +action when a library is found which includes adding the library to `LIBS`, +which specifies libraries to be linked in every binary and library in the +project. + +This fixes libkrad, liblber, libldap_r and libsss_nss_idmap being linked to +every binary and library in IPA, even where unused. + +https://pagure.io/freeipa/issue/6846 + +Reviewed-By: Stanislav Laznicka +--- + configure.ac | 4 ++-- + server.m4 | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/configure.ac b/configure.ac +index ded1d71fd079a5f6947ef0627fb699783c8cc109..e31a9849c4c0556833f5cd47104381d006c96eef 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -86,8 +86,8 @@ dnl --------------------------------------------------------------------------- + + SAVE_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$NSPR_CFLAGS $NSS_CFLAGS" +-AC_CHECK_LIB([ldap_r], [ldap_search], [], AC_MSG_ERROR([libldap_r not found])) +-AC_CHECK_LIB([lber], [ber_peek_tag], [], AC_MSG_ERROR([liblber not found])) ++AC_CHECK_LIB([ldap_r], [ldap_search], [ ], AC_MSG_ERROR([libldap_r not found])) ++AC_CHECK_LIB([lber], [ber_peek_tag], [ ], AC_MSG_ERROR([liblber not found])) + LDAP_LIBS="-lldap_r -llber" + LDAP_CFLAGS="" + AC_SUBST(LDAP_LIBS) +diff --git a/server.m4 b/server.m4 +index 346d73e906c5d0499e46fcc4da070007b2ff5973..aa784e096299d5a6cc599a0d6a0652168f9bafbc 100644 +--- a/server.m4 ++++ b/server.m4 +@@ -31,7 +31,7 @@ PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap]) + PKG_CHECK_MODULES([SSSNSSIDMAP], [sss_nss_idmap >= 1.15.2]) + AC_CHECK_LIB([sss_nss_idmap], + [sss_nss_getlistbycert], +- [], ++ [ ], + [AC_MSG_ERROR([Required sss_nss_getlistbycert symbol in sss_nss_idmap not found])], + []) + +@@ -48,7 +48,7 @@ dnl - Check for KRB5 krad + dnl --------------------------------------------------------------------------- + + AC_CHECK_HEADER(krad.h, [], [AC_MSG_ERROR([krad.h not found])]) +-AC_CHECK_LIB(krad, main, [], [AC_MSG_ERROR([libkrad not found])]) ++AC_CHECK_LIB(krad, main, [ ], [AC_MSG_ERROR([libkrad not found])]) + KRAD_LIBS="-lkrad" + krb5rundir="${localstatedir}/run/krb5kdc" + AC_SUBST(KRAD_LIBS) +-- +2.12.2 + diff --git a/SOURCES/0090-ipaserver-dcerpc-reformat-to-make-the-code-closer-to.patch b/SOURCES/0090-ipaserver-dcerpc-reformat-to-make-the-code-closer-to.patch deleted file mode 100644 index f4bc1d9..0000000 --- a/SOURCES/0090-ipaserver-dcerpc-reformat-to-make-the-code-closer-to.patch +++ /dev/null @@ -1,1005 +0,0 @@ -From a9a73b0e0b601767324d5b6747b6ba46b6e5e90f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 7 Jun 2016 22:41:10 +0300 -Subject: [PATCH] ipaserver/dcerpc: reformat to make the code closer to pep8 - -Because Samba Python bindings provide long-named methods and constants, -sometimes it is impossible to fit into 80 columns without causing -damage to readability of the code. This patchset attempts to reduce -pep8 complaints to a minimum. - -https://fedorahosted.org/freeipa/ticket/6076 - -Reviewed-By: Martin Babinsky ---- - ipaserver/dcerpc.py | 473 +++++++++++++++++++++++++++++++++------------------- - 1 file changed, 298 insertions(+), 175 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 21ac89dfd71271ed384b875f95054d7ad1c0556d..19be6bf7a3617a3b867d51a9358c9926e91049a7 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -44,10 +44,12 @@ import samba - import random - from cryptography.hazmat.primitives.ciphers import Cipher, algorithms - from cryptography.hazmat.backends import default_backend -+# pylint: disable=F0401 - try: -- from ldap.controls import RequestControl as LDAPControl #pylint: disable=F0401 -+ from ldap.controls import RequestControl as LDAPControl - except ImportError: -- from ldap.controls import LDAPControl as LDAPControl #pylint: disable=F0401 -+ from ldap.controls import LDAPControl as LDAPControl -+# pylint: enable=F0401 - import ldap as _ldap - from ipapython.ipaldap import IPAdmin - from ipaserver.session import krbccache_dir, krbccache_prefix -@@ -74,7 +76,7 @@ and Samba4 python bindings. - - # Both constants can be used as masks against trust direction - # because bi-directional has two lower bits set. --TRUST_ONEWAY = 1 -+TRUST_ONEWAY = 1 - TRUST_BIDIRECTIONAL = 3 - - # Trust join behavior -@@ -91,31 +93,44 @@ def is_sid_valid(sid): - return True - - --access_denied_error = errors.ACIError(info=_('CIFS server denied your credentials')) -+access_denied_error = errors.ACIError( -+ info=_('CIFS server denied your credentials')) - dcerpc_error_codes = { - -1073741823: -- errors.RemoteRetrieveError(reason=_('communication with CIFS server was unsuccessful')), -+ errors.RemoteRetrieveError( -+ reason=_('communication with CIFS server was unsuccessful')), - -1073741790: access_denied_error, - -1073741715: access_denied_error, - -1073741614: access_denied_error, - -1073741603: -- errors.ValidationError(name=_('AD domain controller'), error=_('unsupported functional level')), -- -1073741811: # NT_STATUS_INVALID_PARAMETER -+ 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')), -- -1073741776: # NT_STATUS_INVALID_PARAMETER_MIX, we simply will skip the binding -+ reason=_('AD domain controller complains about communication ' -+ 'sequence. It may mean unsynchronized time on both ' -+ 'sides, for example')), -+ -1073741776: # NT_STATUS_INVALID_PARAMETER_MIX, -+ # we simply will skip the binding - access_denied_error, -- -1073741772: # NT_STATUS_OBJECT_NAME_NOT_FOUND -- errors.RemoteRetrieveError(reason=_('CIFS server configuration does not allow access to \\\\pipe\\lsarpc')), -+ -1073741772: # NT_STATUS_OBJECT_NAME_NOT_FOUND -+ errors.RemoteRetrieveError( -+ reason=_('CIFS server configuration does not allow ' -+ 'access to \\\\pipe\\lsarpc')), - } - - dcerpc_error_messages = { - "NT_STATUS_OBJECT_NAME_NOT_FOUND": -- errors.NotFound(reason=_('Cannot find specified domain or server name')), -+ 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')), -+ 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')), -+ errors.RequirementError( -+ name=_('At least the domain or IP address should be specified')), - } - - pysss_type_key_translation_dict = { -@@ -126,7 +141,7 @@ pysss_type_key_translation_dict = { - } - - --def assess_dcerpc_exception(num=None,message=None): -+def assess_dcerpc_exception(num=None, message=None): - """ - Takes error returned by Samba bindings and converts it into - an IPA error class. -@@ -135,8 +150,9 @@ def assess_dcerpc_exception(num=None,message=None): - return dcerpc_error_codes[num] - if message and message in dcerpc_error_messages: - return dcerpc_error_messages[message] -- reason = _('''CIFS server communication error: code "%(num)s", -- message "%(message)s" (both may be "None")''') % dict(num=num, message=message) -+ reason = _('CIFS server communication error: code "%(num)s", ' -+ 'message "%(message)s" (both may be "None")') % \ -+ dict(num=num, message=message) - return errors.RemoteRetrieveError(reason=reason) - - -@@ -182,9 +198,13 @@ class DomainValidator(object): - self._parm = None - - def is_configured(self): -- cn_trust_local = DN(('cn', self.api.env.domain), self.api.env.container_cifsdomains, self.api.env.basedn) -+ cn_trust_local = DN(('cn', self.api.env.domain), -+ self.api.env.container_cifsdomains, -+ self.api.env.basedn) - try: -- entry_attrs = self.ldap.get_entry(cn_trust_local, [self.ATTR_FLATNAME, self.ATTR_SID]) -+ entry_attrs = self.ldap.get_entry(cn_trust_local, -+ [self.ATTR_FLATNAME, -+ self.ATTR_SID]) - self.flatname = entry_attrs[self.ATTR_FLATNAME][0] - self.sid = entry_attrs[self.ATTR_SID][0] - self.dn = entry_attrs.dn -@@ -203,7 +223,8 @@ class DomainValidator(object): - - try: - search_kw = {'objectClass': 'ipaNTTrustedDomain'} -- filter = self.ldap.make_filter(search_kw, rules=self.ldap.MATCH_ALL) -+ filter = self.ldap.make_filter(search_kw, -+ rules=self.ldap.MATCH_ALL) - (entries, truncated) = self.ldap.find_entries( - filter=filter, - base_dn=cn_trust, -@@ -216,22 +237,22 @@ class DomainValidator(object): - # domain names as keys and those are generally case-insensitive - result = ipautil.CIDict() - -- for entry in entries: -+ for e in entries: - try: -- trust_partner = entry[self.ATTR_TRUST_PARTNER][0] -- flatname_normalized = entry[self.ATTR_FLATNAME][0].lower() -- trusted_sid = entry[self.ATTR_TRUSTED_SID][0] -- except KeyError as e: -+ t_partner = e.single_value.get(self.ATTR_TRUST_PARTNER) -+ fname_norm = e.single_value.get(self.ATTR_FLATNAME).lower() -+ trusted_sid = e.single_value.get(self.ATTR_TRUSTED_SID) -+ except KeyError as exc: - # Some piece of trusted domain info in LDAP is missing - # Skip the domain, but leave log entry for investigation - api.log.warning("Trusted domain '%s' entry misses an " -- "attribute: %s", entry.dn, e) -+ "attribute: %s", e.dn, exc) - continue - -- result[trust_partner] = (flatname_normalized, -- security.dom_sid(trusted_sid)) -+ result[t_partner] = (fname_norm, -+ security.dom_sid(trusted_sid)) - return result -- except errors.NotFound as e: -+ except errors.NotFound as exc: - return [] - - def set_trusted_domains(self): -@@ -244,21 +265,22 @@ class DomainValidator(object): - # This means we can't check the correctness of a trusted - # domain SIDs - raise errors.ValidationError(name='sid', -- error=_('no trusted domain is configured')) -+ error=_('no trusted domain ' -+ 'is configured')) - - def get_domain_by_sid(self, sid, exact_match=False): - if not self.domain: - # our domain is not configured or self.is_configured() never run - # reject SIDs as we can't check correctness of them - raise errors.ValidationError(name='sid', -- error=_('domain is not configured')) -+ error=_('domain is not configured')) - - # Parse sid string to see if it is really in a SID format - try: - test_sid = security.dom_sid(sid) - except TypeError: - raise errors.ValidationError(name='sid', -- error=_('SID is not valid')) -+ error=_('SID is not valid')) - - # At this point we have SID_NT_AUTHORITY family SID and really need to - # check it against prefixes of domain SIDs we trust to -@@ -314,30 +336,34 @@ class DomainValidator(object): - return None - - def get_trusted_domain_objects(self, domain=None, flatname=None, filter="", -- attrs=None, scope=_ldap.SCOPE_SUBTREE, basedn=None): -+ attrs=None, scope=_ldap.SCOPE_SUBTREE, -+ basedn=None): - """ -- Search for LDAP objects in a trusted domain specified either by `domain' -- or `flatname'. The actual LDAP search is specified by `filter', `attrs', -- `scope' and `basedn'. When `basedn' is empty, database root DN is used. -+ Search for LDAP objects in a trusted domain specified either by -+ `domain' or `flatname'. The actual LDAP search is specified by -+ `filter', `attrs', `scope' and `basedn'. When `basedn' is empty, -+ database root DN is used. - """ - assert domain is not None or flatname is not None - """Returns SID for the trusted domain object (user or group only)""" - if not self.domain: - # our domain is not configured or self.is_configured() never run - raise errors.ValidationError(name=_('Trust setup'), -- error=_('Our domain is not configured')) -+ error=_('Our domain is ' -+ 'not configured')) - if not self._domains: - self._domains = self.get_trusted_domains() - if len(self._domains) == 0: - # Our domain is configured but no trusted domains are configured - raise errors.ValidationError(name=_('Trust setup'), -- error=_('No trusted domain is not configured')) -+ error=_('No trusted domain is ' -+ 'not configured')) - - entries = None - if domain is not None: - if domain not in self._domains: - raise errors.ValidationError(name=_('trusted domain object'), -- error= _('domain is not trusted')) -+ error=_('domain is not trusted')) - # Now we have a name to check against our list of trusted domains - entries = self.search_in_dc(domain, filter, attrs, scope, basedn) - elif flatname is not None: -@@ -347,53 +373,65 @@ class DomainValidator(object): - for domain in self._domains: - if self._domains[domain][0] == flatname: - found_flatname = True -- entries = self.search_in_dc(domain, filter, attrs, scope, basedn) -+ entries = self.search_in_dc(domain, filter, -+ attrs, scope, basedn) - if entries: - break - if not found_flatname: - raise errors.ValidationError(name=_('trusted domain object'), -- error= _('no trusted domain matched the specified flat name')) -+ error=_('no trusted domain ' -+ 'matched the specified ' -+ 'flat name')) - if not entries: - raise errors.NotFound(reason=_('trusted domain object not found')) - - return entries - -- def get_trusted_domain_object_sid(self, object_name, fallback_to_ldap=True): -+ def get_trusted_domain_object_sid(self, object_name, -+ fallback_to_ldap=True): - result = pysss_nss_idmap.getsidbyname(object_name) -- if object_name in result and (pysss_nss_idmap.SID_KEY in result[object_name]): -+ if object_name in result and \ -+ (pysss_nss_idmap.SID_KEY in result[object_name]): - object_sid = result[object_name][pysss_nss_idmap.SID_KEY] - return object_sid - - # If fallback to AD DC LDAP is not allowed, bail out - if not fallback_to_ldap: - raise errors.ValidationError(name=_('trusted domain object'), -- error= _('SSSD was unable to resolve the object to a valid SID')) -+ error=_('SSSD was unable to resolve ' -+ 'the object to a valid SID')) - - # Else, we are going to contact AD DC LDAP - components = normalize_name(object_name) - if not ('domain' in components or 'flatname' in components): - # No domain or realm specified, ambiguous search -- raise errors.ValidationError(name=_('trusted domain object'), -- error= _('Ambiguous search, user domain was not specified')) -+ raise errors.ValidationError(name=_('trusted domain object'), -+ error=_('Ambiguous search, user ' -+ 'domain was not specified')) - - attrs = ['objectSid'] -- filter = '(&(sAMAccountName=%(name)s)(|(objectClass=user)(objectClass=group)))' \ -- % dict(name=components['name']) -+ filter = '(&(sAMAccountName=%(name)s)' \ -+ '(|(objectClass=user)(objectClass=group)))' \ -+ % dict(name=components['name']) - scope = _ldap.SCOPE_SUBTREE - entries = self.get_trusted_domain_objects(components.get('domain'), -- components.get('flatname'), filter, attrs, scope) -+ components.get('flatname'), -+ filter, attrs, scope) - - if len(entries) > 1: - # Treat non-unique entries as invalid - raise errors.ValidationError(name=_('trusted domain object'), -- error= _('Trusted domain did not return a unique object')) -+ error=_('Trusted domain did not ' -+ 'return a unique object')) - sid = self.__sid_to_str(entries[0]['objectSid'][0]) - try: - test_sid = security.dom_sid(sid) - return unicode(test_sid) - except TypeError as e: - raise errors.ValidationError(name=_('trusted domain object'), -- error= _('Trusted domain did not return a valid SID for the object')) -+ error=_('Trusted domain did not ' -+ 'return a valid SID for ' -+ 'the object')) - - def get_trusted_domain_object_type(self, name_or_sid): - """ -@@ -443,7 +481,8 @@ class DomainValidator(object): - ) - - attrs = ['sAMAccountName'] -- filter = (r'(&(objectSid=%(sid)s)(|(objectClass=user)(objectClass=group)))' -+ filter = (r'(&(objectSid=%(sid)s)' -+ '(|(objectClass=user)(objectClass=group)))' - % dict(sid=escaped_sid)) # sid in binary - domain = self.get_domain_by_sid(sid) - -@@ -454,7 +493,8 @@ class DomainValidator(object): - if len(entries) > 1: - # Treat non-unique entries as invalid - raise errors.ValidationError(name=_('trusted domain object'), -- error=_('Trusted domain did not return a unique object')) -+ error=_('Trusted domain did not ' -+ 'return a unique object')) - - object_name = ( - "%s@%s" % (entries[0].single_value['sAMAccountName'].lower(), -@@ -486,27 +526,31 @@ class DomainValidator(object): - # Now search a trusted domain for a user with this SID - attrs = ['cn'] - filter = '(&(objectClass=user)(objectSid=%(sid)s))' \ -- % dict(sid=object_name) -+ % dict(sid=object_name) - try: -- entries = self.get_trusted_domain_objects(domain=domain, filter=filter, -- attrs=attrs, scope=_ldap.SCOPE_SUBTREE) -+ entries = self.get_trusted_domain_objects(domain=domain, -+ filter=filter, -+ attrs=attrs, -+ scope=_ldap.SCOPE_SUBTREE) - except errors.NotFound: - raise errors.NotFound(reason=_('trusted domain user not found')) - user_dn = entries[0].dn - elif domain or flatname: - attrs = ['cn'] - filter = '(&(sAMAccountName=%(name)s)(objectClass=user))' \ -- % dict(name=name) -+ % dict(name=name) - try: - entries = self.get_trusted_domain_objects(domain, -- flatname, filter, attrs, _ldap.SCOPE_SUBTREE) -+ flatname, filter, attrs, -+ _ldap.SCOPE_SUBTREE) - except errors.NotFound: - raise errors.NotFound(reason=_('trusted domain user not found')) - user_dn = entries[0].dn - else: - # No domain or realm specified, ambiguous search - raise errors.ValidationError(name=_('trusted domain object'), -- error= _('Ambiguous search, user domain was not specified')) -+ error=_('Ambiguous search, ' -+ 'user domain was not specified')) - - # Get SIDs of user object and it's groups - # tokenGroups attribute must be read with a scope BASE for a known user -@@ -514,9 +558,11 @@ class DomainValidator(object): - attrs = ['objectSID', 'tokenGroups'] - filter = "(objectClass=user)" - entries = self.get_trusted_domain_objects(domain, -- flatname, filter, attrs, _ldap.SCOPE_BASE, user_dn) -+ flatname, filter, attrs, -+ _ldap.SCOPE_BASE, user_dn) - object_sid = self.__sid_to_str(entries[0]['objectSid'][0]) -- group_sids = [self.__sid_to_str(sid) for sid in entries[0]['tokenGroups']] -+ group_sids = [self.__sid_to_str(sid) -+ for sid in entries[0]['tokenGroups']] - return (object_sid, group_sids) - - def get_trusted_domain_user_and_groups(self, object_name): -@@ -540,11 +586,14 @@ class DomainValidator(object): - if is_valid_sid: - object_sid = object_name - result = pysss_nss_idmap.getnamebysid(object_name) -- if object_name in result and (pysss_nss_idmap.NAME_KEY in result[object_name]): -- group_list = pysss.getgrouplist(result[object_name][pysss_nss_idmap.NAME_KEY]) -+ if object_name in result and \ -+ (pysss_nss_idmap.NAME_KEY in result[object_name]): -+ group_list = pysss.getgrouplist( -+ result[object_name][pysss_nss_idmap.NAME_KEY]) - else: - result = pysss_nss_idmap.getsidbyname(object_name) -- if object_name in result and (pysss_nss_idmap.SID_KEY in result[object_name]): -+ if object_name in result and \ -+ (pysss_nss_idmap.SID_KEY in result[object_name]): - object_sid = result[object_name][pysss_nss_idmap.SID_KEY] - group_list = pysss.getgrouplist(object_name) - -@@ -552,7 +601,10 @@ class DomainValidator(object): - return self.__get_trusted_domain_user_and_groups(object_name) - - group_sids = pysss_nss_idmap.getsidbyname(group_list) -- return (object_sid, [el[1][pysss_nss_idmap.SID_KEY] for el in group_sids.items()]) -+ return ( -+ object_sid, -+ [el[1][pysss_nss_idmap.SID_KEY] for el in group_sids.items()] -+ ) - - def __sid_to_str(self, sid): - """ -@@ -561,12 +613,13 @@ class DomainValidator(object): - """ - sid_rev_num = ord(sid[0]) - number_sub_id = ord(sid[1]) -- ia = struct.unpack('!Q','\x00\x00'+sid[2:8])[0] -+ ia = struct.unpack('!Q', '\x00\x00'+sid[2:8])[0] - subs = [ -- struct.unpack(' 0: - self.parm.set('netbios name', hostname) - self.creds = creds -@@ -810,14 +867,14 @@ class TrustDomainInstance(object): - self.validation_attempts = 0 - - def __gen_lsa_connection(self, binding): -- if self.creds is None: -- raise errors.RequirementError(name=_('CIFS credentials object')) -- try: -- result = lsa.lsarpc(binding, self.parm, self.creds) -- return result -- except RuntimeError as e: -- num, message = e.args # pylint: disable=unpacking-non-sequence -- raise assess_dcerpc_exception(num=num, message=message) -+ if self.creds is None: -+ raise errors.RequirementError(name=_('CIFS credentials object')) -+ try: -+ result = lsa.lsarpc(binding, self.parm, self.creds) -+ return result -+ except RuntimeError as e: -+ num, message = e.args # pylint: disable=unpacking-non-sequence -+ raise assess_dcerpc_exception(num=num, message=message) - - def init_lsa_pipe(self, remote_host): - """ -@@ -847,30 +904,35 @@ class TrustDomainInstance(object): - # When session key is not available, we just skip this binding - session_attempts = session_attempts + 1 - -- if self._pipe is None and (attempts + session_attempts) == len(bindings): -+ if self._pipe is None and \ -+ (attempts + session_attempts) == len(bindings): - raise errors.ACIError( -- info=_('CIFS server %(host)s denied your credentials') % dict(host=remote_host)) -+ info=_('CIFS server %(host)s denied your credentials') -+ % dict(host=remote_host)) - - if self._pipe is None: - raise errors.RemoteRetrieveError( -- reason=_('Cannot establish LSA connection to %(host)s. Is CIFS server running?') % dict(host=remote_host)) -+ reason=_('Cannot establish LSA connection to %(host)s. ' -+ 'Is CIFS server running?') % dict(host=remote_host)) - self.binding = binding - self.session_key = self._pipe.session_key - - 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. -+ 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 - there is one working. - -- We try NCACN_NP before NCACN_IP_TCP and use SMB2 before SMB1 or defaults. -+ We try NCACN_NP before NCACN_IP_TCP and use SMB2 before SMB1. - """ - transports = (u'ncacn_np', u'ncacn_ip_tcp') -- options = ( u'smb2,print', u'print') -- return [u'%s:%s[%s]' % (t, remote_host, o) for t in transports for o in options] -+ options = (u'smb2,print', u'print') -+ return [u'%s:%s[%s]' % (t, remote_host, o) -+ for t in transports for o in options] - -- def retrieve_anonymously(self, remote_host, discover_srv=False, search_pdc=False): -+ 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 - """ -@@ -896,7 +958,8 @@ class TrustDomainInstance(object): - 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 -+ # We need to do rootDSE search with LDAP_SERVER_EXTENDED_DN_OID -+ # control to reveal the SID - ldap_uri = 'ldap://%s' % (result.pdc_dns_name) - conn = _ldap.initialize(ldap_uri) - conn.set_option(_ldap.OPT_SERVER_CONTROLS, [ExtendedDNControl()]) -@@ -908,7 +971,7 @@ class TrustDomainInstance(object): - except _ldap.LDAPError as e: - root_logger.error( - "LDAP error when connecting to %(host)s: %(error)s" % -- dict(host=unicode(result.pdc_name), error=str(e))) -+ dict(host=unicode(result.pdc_name), error=str(e))) - except KeyError as e: - root_logger.error("KeyError: {err}, LDAP entry from {host} " - "returned malformed. Your DNS might be " -@@ -930,8 +993,11 @@ class TrustDomainInstance(object): - objectAttribute = lsa.ObjectAttribute() - objectAttribute.sec_qos = lsa.QosInfo() - try: -- self._policy_handle = self._pipe.OpenPolicy2(u"", objectAttribute, security.SEC_FLAG_MAXIMUM_ALLOWED) -- result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_DNS) -+ self._policy_handle = \ -+ self._pipe.OpenPolicy2(u"", objectAttribute, -+ security.SEC_FLAG_MAXIMUM_ALLOWED) -+ result = self._pipe.QueryInfoPolicy2(self._policy_handle, -+ lsa.LSA_POLICY_INFO_DNS) - except RuntimeError as e: - num, message = e.args # pylint: disable=unpacking-non-sequence - raise assess_dcerpc_exception(num=num, message=message) -@@ -944,7 +1010,8 @@ class TrustDomainInstance(object): - self.info['dc'] = remote_host - - try: -- result = self._pipe.QueryInfoPolicy2(self._policy_handle, lsa.LSA_POLICY_INFO_ROLE) -+ result = self._pipe.QueryInfoPolicy2(self._policy_handle, -+ lsa.LSA_POLICY_INFO_ROLE) - except RuntimeError as e: - num, message = e.args # pylint: disable=unpacking-non-sequence - raise assess_dcerpc_exception(num=num, message=message) -@@ -958,18 +1025,18 @@ class TrustDomainInstance(object): - clear_value.size = len(password_blob) - clear_value.password = password_blob - -- clear_authentication_information = drsblobs.AuthenticationInformation() -- clear_authentication_information.LastUpdateTime = samba.unix2nttime(int(time.time())) -- clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR -- clear_authentication_information.AuthInfo = clear_value -+ clear_authinfo = drsblobs.AuthenticationInformation() -+ clear_authinfo.LastUpdateTime = samba.unix2nttime(int(time.time())) -+ clear_authinfo.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR -+ clear_authinfo.AuthInfo = clear_value - -- authentication_information_array = drsblobs.AuthenticationInformationArray() -- authentication_information_array.count = 1 -- authentication_information_array.array = [clear_authentication_information] -+ authinfo_array = drsblobs.AuthenticationInformationArray() -+ authinfo_array.count = 1 -+ authinfo_array.array = [clear_authinfo] - - outgoing = drsblobs.trustAuthInOutBlob() - outgoing.count = 1 -- outgoing.current = authentication_information_array -+ outgoing.current = authinfo_array - - confounder = [3]*512 - for i in range(512): -@@ -983,7 +1050,8 @@ class TrustDomainInstance(object): - - trustpass_blob = ndr_pack(trustpass) - -- encrypted_trustpass = arcfour_encrypt(self._pipe.session_key, trustpass_blob) -+ encrypted_trustpass = arcfour_encrypt(self._pipe.session_key, -+ trustpass_blob) - - auth_blob = lsa.DATA_BUF2() - auth_blob.size = len(encrypted_trustpass) -@@ -993,7 +1061,6 @@ class TrustDomainInstance(object): - auth_info.auth_blob = auth_blob - self.auth_info = auth_info - -- - def generate_ftinfo(self, another_domain): - """ - Generates TrustDomainInfoFullInfo2Internal structure -@@ -1032,27 +1099,38 @@ class TrustDomainInstance(object): - # smbd already has the information about itself - ldname = lsa.StringLarge() - ldname.string = another_domain.info['dns_domain'] -- collision_info = self._pipe.lsaRSetForestTrustInformation(self._policy_handle, -- ldname, -- lsa.LSA_FOREST_TRUST_DOMAIN_INFO, -- ftinfo, 0) -- if collision_info: -- root_logger.error("When setting forest trust information, got collision info back:\n%s" % (ndr_print(collision_info))) -+ ftlevel = lsa.LSA_FOREST_TRUST_DOMAIN_INFO -+ # RSetForestTrustInformation returns collision information -+ # for trust topology -+ cinfo = self._pipe.lsaRSetForestTrustInformation( -+ self._policy_handle, -+ ldname, -+ ftlevel, -+ ftinfo, 0) -+ if cinfo: -+ root_logger.error("When setting forest trust information, " -+ "got collision info back:\n%s" -+ % (ndr_print(cinfo))) - except RuntimeError as e: -- # We can ignore the error here -- setting up name suffix routes may fail -+ # We can ignore the error here -- -+ # setting up name suffix routes may fail - pass - -- def establish_trust(self, another_domain, trustdom_secret, trust_type='bidirectional', trust_external=False): -+ def establish_trust(self, another_domain, trustdom_secret, -+ trust_type='bidirectional', trust_external=False): - """ - Establishes trust between our and another domain -- Input: another_domain -- instance of TrustDomainInstance, initialized with #retrieve call -+ Input: another_domain -- instance of TrustDomainInstance, -+ initialized with #retrieve call - trustdom_secret -- shared secred used for the trust - """ - if self.info['name'] == another_domain.info['name']: - # Check that NetBIOS names do not clash - raise errors.ValidationError(name=u'AD Trust Setup', -- error=_('the IPA server and the remote domain cannot share the same ' -- 'NetBIOS name: %s') % self.info['name']) -+ error=_('the IPA server and the ' -+ 'remote domain cannot share ' -+ 'the same NetBIOS name: %s') -+ % self.info['name']) - - self.generate_auth(trustdom_secret) - -@@ -1071,8 +1149,12 @@ class TrustDomainInstance(object): - try: - dname = lsa.String() - 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) -+ 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 as e: - num, message = e.args # pylint: disable=unpacking-non-sequence - # Ignore anything but access denied (NT_STATUS_ACCESS_DENIED) -@@ -1080,7 +1162,10 @@ class TrustDomainInstance(object): - raise access_denied_error - - try: -- trustdom_handle = self._pipe.CreateTrustedDomainEx2(self._policy_handle, info, self.auth_info, security.SEC_STD_DELETE) -+ trustdom_handle = self._pipe.CreateTrustedDomainEx2( -+ self._policy_handle, -+ info, self.auth_info, -+ security.SEC_STD_DELETE) - except RuntimeError as e: - num, message = e.args # pylint: disable=unpacking-non-sequence - raise assess_dcerpc_exception(num=num, message=message) -@@ -1089,13 +1174,19 @@ class TrustDomainInstance(object): - # trust settings. Samba insists this has to be done with LSA - # OpenTrustedDomain* calls, it is not enough to have a handle - # returned by the CreateTrustedDomainEx2 call. -- trustdom_handle = self._pipe.OpenTrustedDomainByName(self._policy_handle, dname, security.SEC_FLAG_MAXIMUM_ALLOWED) -+ trustdom_handle = self._pipe.OpenTrustedDomainByName( -+ self._policy_handle, -+ dname, -+ security.SEC_FLAG_MAXIMUM_ALLOWED) - try: -- infoclass = lsa.TrustDomainInfoSupportedEncTypes() -- infoclass.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5 -- infoclass.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 -- infoclass.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 -- self._pipe.SetInformationTrustedDomain(trustdom_handle, lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES, infoclass) -+ infocls = lsa.TrustDomainInfoSupportedEncTypes() -+ infocls.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5 -+ infocls.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 -+ infocls.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 -+ self._pipe.SetInformationTrustedDomain( -+ trustdom_handle, -+ lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES, -+ infocls) - except RuntimeError as e: - # We can ignore the error here -- changing enctypes is for - # improved security but the trust will work with default values as -@@ -1105,13 +1196,16 @@ class TrustDomainInstance(object): - - if not trust_external: - try: -- info = self._pipe.QueryTrustedDomainInfo(trustdom_handle, -- lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX) -+ info = self._pipe.QueryTrustedDomainInfo( -+ trustdom_handle, -+ lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX) - info.trust_attributes |= lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE -- self._pipe.SetInformationTrustedDomain(trustdom_handle, -- lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX, info) -+ self._pipe.SetInformationTrustedDomain( -+ trustdom_handle, -+ lsa.LSA_TRUSTED_DOMAIN_INFO_INFO_EX, info) - except RuntimeError as e: -- root_logger.error('unable to set trust transitivity status: %s' % (str(e))) -+ root_logger.error( -+ 'unable to set trust transitivity status: %s' % (str(e))) - - if self.info['is_pdc'] or trust_external: - self.update_ftinfo(another_domain) -@@ -1119,12 +1213,13 @@ class TrustDomainInstance(object): - def verify_trust(self, another_domain): - def retrieve_netlogon_info_2(logon_server, domain, function_code, data): - try: -- netr_pipe = netlogon.netlogon(domain.binding, domain.parm, domain.creds) -- result = netr_pipe.netr_LogonControl2Ex(logon_server=logon_server, -+ netr_pipe = netlogon.netlogon(domain.binding, -+ domain.parm, domain.creds) -+ result = netr_pipe.netr_LogonControl2Ex( -+ logon_server=logon_server, - function_code=function_code, - level=2, -- data=data -- ) -+ data=data) - return result - except RuntimeError as e: - num, message = e.args # pylint: disable=unpacking-non-sequence -@@ -1135,9 +1230,11 @@ class TrustDomainInstance(object): - another_domain.info['dns_domain']) - - if result and result.flags and netlogon.NETLOGON_VERIFY_STATUS_RETURNED: -- if result.pdc_connection_status[0] != 0 and result.tc_connection_status[0] != 0: -+ if result.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 -+ # Most likely AD DC hit another IPA replica which -+ # yet has no trust secret replicated - - # Sleep and repeat again - self.validation_attempts += 1 -@@ -1176,23 +1273,23 @@ class TrustDomainInstance(object): - - def fetch_domains(api, mydomain, trustdomain, creds=None, server=None): - trust_flags = dict( -- NETR_TRUST_FLAG_IN_FOREST = 0x00000001, -- NETR_TRUST_FLAG_OUTBOUND = 0x00000002, -- NETR_TRUST_FLAG_TREEROOT = 0x00000004, -- NETR_TRUST_FLAG_PRIMARY = 0x00000008, -- NETR_TRUST_FLAG_NATIVE = 0x00000010, -- NETR_TRUST_FLAG_INBOUND = 0x00000020, -- NETR_TRUST_FLAG_MIT_KRB5 = 0x00000080, -- NETR_TRUST_FLAG_AES = 0x00000100) -+ NETR_TRUST_FLAG_IN_FOREST=0x00000001, -+ NETR_TRUST_FLAG_OUTBOUND=0x00000002, -+ NETR_TRUST_FLAG_TREEROOT=0x00000004, -+ NETR_TRUST_FLAG_PRIMARY=0x00000008, -+ NETR_TRUST_FLAG_NATIVE=0x00000010, -+ NETR_TRUST_FLAG_INBOUND=0x00000020, -+ NETR_TRUST_FLAG_MIT_KRB5=0x00000080, -+ NETR_TRUST_FLAG_AES=0x00000100) - - trust_attributes = dict( -- NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001, -- NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY = 0x00000002, -- NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN = 0x00000004, -- NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE = 0x00000008, -- NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION = 0x00000010, -- NETR_TRUST_ATTRIBUTE_WITHIN_FOREST = 0x00000020, -- NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL = 0x00000040) -+ NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE=0x00000001, -+ NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY=0x00000002, -+ NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN=0x00000004, -+ NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE=0x00000008, -+ NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION=0x00000010, -+ NETR_TRUST_ATTRIBUTE_WITHIN_FOREST=0x00000020, -+ NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL=0x00000040) - - def communicate(td): - td.init_lsa_pipe(td.info['dc']) -@@ -1314,7 +1411,8 @@ class TrustDomainJoins(object): - ld.retrieve(installutils.get_fqdn()) - self.local_domain = ld - -- def populate_remote_domain(self, realm, realm_server=None, realm_admin=None, realm_passwd=None): -+ def populate_remote_domain(self, realm, realm_server=None, -+ realm_admin=None, realm_passwd=None): - def get_instance(self): - # Fetch data from foreign domain using password only - rd = TrustDomainInstance('') -@@ -1330,7 +1428,8 @@ class TrustDomainJoins(object): - if realm_server is None: - rd.retrieve_anonymously(realm, discover_srv=True, search_pdc=True) - else: -- rd.retrieve_anonymously(realm_server, discover_srv=False, search_pdc=True) -+ 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: -@@ -1339,12 +1438,14 @@ class TrustDomainJoins(object): - # realm admin is in DOMAIN\user format - # strip DOMAIN part as we'll enforce the one discovered - realm_admin = names[-1] -- auth_string = u"%s\%s%%%s" % (rd.info['name'], realm_admin, realm_passwd) -+ auth_string = u"%s\%s%%%s" \ -+ % (rd.info['name'], realm_admin, realm_passwd) - td = get_instance(self) - td.creds.parse_string(auth_string) - td.creds.set_workstation(self.local_domain.hostname) - if realm_server is None: -- # we must have rd.info['dns_hostname'] then, part of anonymous discovery -+ # we must have rd.info['dns_hostname'] then -+ # as it is part of the anonymous discovery - td.retrieve(rd.info['dns_hostname']) - else: - td.retrieve(realm_server) -@@ -1358,8 +1459,8 @@ class TrustDomainJoins(object): - """ - Generate list of records for forest trust information about - our realm domains. Note that the list generated currently -- includes only top level domains, no exclusion domains, and no TDO objects -- as we handle the latter in a separate way -+ includes only top level domains, no exclusion domains, and -+ no TDO objects as we handle the latter in a separate way - """ - if self.local_domain.read_only: - return -@@ -1367,10 +1468,15 @@ class TrustDomainJoins(object): - self.local_domain.ftinfo_records = [] - - realm_domains = self.api.Command.realmdomains_show()['result'] -- # Use realmdomains' modification timestamp to judge records last update time -- entry = self.api.Backend.ldap2.get_entry(realm_domains['dn'], ['modifyTimestamp']) -+ # Use realmdomains' modification timestamp -+ # to judge records' last update time -+ entry = self.api.Backend.ldap2.get_entry( -+ realm_domains['dn'], ['modifyTimestamp']) - # Convert the timestamp to Windows 64-bit timestamp format -- trust_timestamp = long(time.mktime(entry['modifytimestamp'][0].timetuple())*1e7+116444736000000000) -+ trust_timestamp = long( -+ time.mktime( -+ entry.single_value.get('modifytimestamp').timetuple() -+ )*1e7+116444736000000000) - - for dom in realm_domains['associateddomain']: - ftinfo = dict() -@@ -1379,7 +1485,8 @@ class TrustDomainJoins(object): - ftinfo['rec_type'] = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME - self.local_domain.ftinfo_records.append(ftinfo) - -- def join_ad_full_credentials(self, realm, realm_server, realm_admin, realm_passwd, trust_type): -+ def join_ad_full_credentials(self, realm, realm_server, realm_admin, -+ realm_passwd, trust_type): - if not self.configured: - return None - -@@ -1392,24 +1499,33 @@ class TrustDomainJoins(object): - ) - - trust_external = bool(self.__allow_behavior & TRUST_JOIN_EXTERNAL) -- if self.remote_domain.info['dns_domain'] != self.remote_domain.info['dns_forest']: -+ if self.remote_domain.info['dns_domain'] != \ -+ self.remote_domain.info['dns_forest']: - if not trust_external: -- raise errors.NotAForestRootError(forest=self.remote_domain.info['dns_forest'], -- domain=self.remote_domain.info['dns_domain']) -+ 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() - self.remote_domain.establish_trust(self.local_domain, -- trustdom_pass, trust_type, trust_external) -+ trustdom_pass, -+ trust_type, trust_external) - self.local_domain.establish_trust(self.remote_domain, -- trustdom_pass, trust_type, trust_external) -- # if trust is inbound, we don't need to verify it because AD DC will respond -- # with WERR_NO_SUCH_DOMAIN -- in only does verification for outbound trusts. -+ trustdom_pass, -+ trust_type, trust_external) -+ # if trust is inbound, we don't need to verify it because -+ # AD DC will respond with WERR_NO_SUCH_DOMAIN -- -+ # it only does verification for outbound trusts. - result = True - if trust_type == TRUST_BIDIRECTIONAL: - result = self.remote_domain.verify_trust(self.local_domain) -- return dict(local=self.local_domain, remote=self.remote_domain, verified=result) -+ return dict( -+ local=self.local_domain, -+ remote=self.remote_domain, -+ verified=result -+ ) - return None - - def join_ad_ipa_half(self, realm, realm_server, trustdom_passwd, trust_type): -@@ -1420,11 +1536,18 @@ class TrustDomainJoins(object): - self.populate_remote_domain(realm, realm_server, realm_passwd=None) - - trust_external = bool(self.__allow_behavior & TRUST_JOIN_EXTERNAL) -- if self.remote_domain.info['dns_domain'] != self.remote_domain.info['dns_forest']: -+ if self.remote_domain.info['dns_domain'] != \ -+ self.remote_domain.info['dns_forest']: - if not trust_external: -- raise errors.NotAForestRootError(forest=self.remote_domain.info['dns_forest'], -- domain=self.remote_domain.info['dns_domain']) -+ 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, trust_type, trust_external) -- return dict(local=self.local_domain, remote=self.remote_domain, verified=False) -+ trustdom_passwd, -+ trust_type, trust_external) -+ return dict( -+ local=self.local_domain, -+ remote=self.remote_domain, -+ verified=False -+ ) --- -2.7.4 - diff --git a/SOURCES/0091-Fix-CAInstance.import_ra_cert-for-empty-passwords.patch b/SOURCES/0091-Fix-CAInstance.import_ra_cert-for-empty-passwords.patch new file mode 100644 index 0000000..cc63d38 --- /dev/null +++ b/SOURCES/0091-Fix-CAInstance.import_ra_cert-for-empty-passwords.patch @@ -0,0 +1,30 @@ +From 61b5a76bcd856d679f05c5f5f12f770cc6826783 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Thu, 20 Apr 2017 10:09:05 +0200 +Subject: [PATCH] Fix CAInstance.import_ra_cert for empty passwords + +OpenSSL can't cope with empty files, add a newline after each password + +https://pagure.io/freeipa/issue/6878 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/cainstance.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 640d2884130dd152012e50dde45514f5ca26a523..0672bccf79d7cc6133fdb20f0854366306bfc2e0 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -687,7 +687,7 @@ class CAInstance(DogtagInstance): + + Used when setting up replication + """ +- with ipautil.write_tmp_file(password) as f: ++ with ipautil.write_tmp_file(password + '\n') as f: + pwdarg = 'file:{file}'.format(file=f.name) + # get the private key from the file + ipautil.run([paths.OPENSSL, +-- +2.12.2 + diff --git a/SOURCES/0091-trust-automatically-resolve-DNS-trust-conflicts-for-.patch b/SOURCES/0091-trust-automatically-resolve-DNS-trust-conflicts-for-.patch deleted file mode 100644 index 3d3a5e8..0000000 --- a/SOURCES/0091-trust-automatically-resolve-DNS-trust-conflicts-for-.patch +++ /dev/null @@ -1,382 +0,0 @@ -From 79bcdeb76d51fec5e8eab08f7642e7910e925bb4 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 15 Aug 2016 18:14:00 +0300 -Subject: [PATCH] trust: automatically resolve DNS trust conflicts for triangle - trusts - -For configuration where: - - AD example.com trusts IPA at ipa.example.com - - AD example.org trusts AD example.com - - a trust is tried to be established between ipa.example.com and - example.org, - -there will be a trust topology conflict detected by example.org domain -controller because ipa.example.com DNS namespace overlaps with -example.com DNS namespace. - -This type of trust topology conflict is documented in MS-ADTS 6.1.6.9.3.2 -"Building Well-Formed msDS-TrustForestTrustInfo Message". A similar -conflict can arise for SID and NetBIOS namespaces. However, unlike SID -and NetBIOS namespaces, we can solve DNS namespace conflict -automatically if there are administrative credentials for example.org -available. - -A manual sequence to solve the DNS namespace conflict is described in -https://msdn.microsoft.com/it-it/library/cc786254%28v=ws.10%29.aspx. -This sequence boils down to the following steps: - - 1. As an administrator of the example.org, you need to add an -exclusion entry for ipa.example.com in the properties of the trust to -example.com - 2. Establish trust between ipa.example.com and example.org - -It is important to add the exclusion entry before step 4 or there will -be conflict recorded which cannot be cleared easily right now due to a -combination of bugs in both IPA and Active Directory. - -This patchset implements automated solution for the case when we have -access to the example.org's administrator credentials: - - 1. Attempt to establish trust and update trust topology information. - 2. If trust topology conflict is detected as result of (1): - 2.1. Fetch trust topology infromation for the conflicting forest - trust - 2.2. Add exclusion entry to our domain to the trust topology obtained - in (2.1) - 2.3. Update trust topology for the conflicting forest trust - 3. Re-establish trust between ipa.example.com and example.org - -We cannot do the same for shared secret trust and for external trust, -though: - - 1. For shared secret trust we don't have administrative credentials - in the forest reporting the conflict - - 2. For the external trust we cannot set topology information due to - MS-LSAD 3.1.4.7.16 because external trust is non-transitive by - definition and thus setting topology information will fail. - -To test this logic one can use two Samba AD forests with FreeIPA -using a sub-domain of one of them. - -Fixes: https://fedorahosted.org/freeipa/ticket/6076 -Reviewed-By: Martin Babinsky ---- - ipalib/errors.py | 29 ++++++- - ipaserver/dcerpc.py | 220 +++++++++++++++++++++++++++++++++++++++++++++------- - 2 files changed, 220 insertions(+), 29 deletions(-) - -diff --git a/ipalib/errors.py b/ipalib/errors.py -index 7b4f15dd60ee80719195ba1b9b85d075b10bdf4f..4cc4455b0abf7d2b1366e1ce6dbb3762bc551cc6 100644 ---- a/ipalib/errors.py -+++ b/ipalib/errors.py -@@ -866,7 +866,6 @@ class NotAForestRootError(InvocationError): - errno = 3016 - format = _("Domain '%(domain)s' is not a root domain for forest '%(forest)s'") - -- - ############################################################################## - # 4000 - 4999: Execution errors - -@@ -1908,6 +1907,34 @@ class DNSResolverError(DNSError): - errno = 4401 - format = _('%(exception)s') - -+class TrustError(ExecutionError): -+ """ -+ **4500** Base class for trust execution errors (*4500 - 4599*). -+ These are typically instantiated when there is an error in establishing or -+ modifying a trust to another forest. -+ """ -+ -+ errno = 4500 -+ -+class TrustTopologyConflictError(TrustError): -+ """ -+ **4501** Raised when an attempt to establish trust fails with a topology -+ conflict against another forest the target forest trusts -+ -+ For example: -+ -+ >>> raise TrustTopologyConflictError(forest='example.test', -+ conflict='my.ad.test', -+ domains=['ad.test']) -+ Traceback (most recent call last): -+ ... -+ TrustTopologyConflictError: Forest 'example.test' has existing trust to forest(s) ['ad.test'] which prevents a trust to 'my.ad.test' -+ """ -+ -+ errno = 4501 -+ format = _("Forest '%(forest)s' has existing trust to forest(s) " -+ "%(domains)s which prevents a trust to '%(conflict)s'") -+ - - ############################################################################## - # 5000 - 5999: Generic errors -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 19be6bf7a3617a3b867d51a9358c9926e91049a7..a1c12f16a655493808d50e6adb95e618a664a98c 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -1,7 +1,7 @@ - # Authors: - # Alexander Bokovoy - # --# Copyright (C) 2011 Red Hat -+# Copyright (C) 2011-2016 Red Hat - # see file 'COPYING' for use and warranty information - # - # Portions (C) Andrew Tridgell, Andrew Bartlett -@@ -140,6 +140,15 @@ pysss_type_key_translation_dict = { - pysss_nss_idmap.ID_BOTH: 'both', - } - -+class TrustTopologyConflictSolved(Exception): -+ """ -+ Internal trust error: raised when previously detected -+ trust topology conflict is automatically solved. -+ -+ No separate errno is assigned as this error should -+ not be visible outside the dcerpc.py code. -+ """ -+ pass - - def assess_dcerpc_exception(num=None, message=None): - """ -@@ -1087,34 +1096,165 @@ class TrustDomainInstance(object): - info.entries = ftinfo_records - return info - -+ def clear_ftinfo_conflict(self, another_domain, cinfo): -+ """ -+ Attempt to clean up the forest trust collisions -+ -+ :param self: the forest we establish trust to -+ :param another_domain: a forest that establishes trust to 'self' -+ :param cinfo: lsa_ForestTrustCollisionInfo structure that contain -+ set of of lsa_ForestTrustCollisionRecord structures -+ :raises: TrustTopologyConflictSolved, TrustTopologyConflictError -+ -+ This code tries to perform intelligent job of going -+ over individual collisions and making exclusion entries -+ for affected IPA namespaces. -+ -+ There are three possible conflict configurations: -+ - conflict of DNS namespace (TLN conflict, LSA_TLN_DISABLED_CONFLICT) -+ - conflict of SID namespace (LSA_SID_DISABLED_CONFLICT) -+ - conflict of NetBIOS namespace (LSA_NB_DISABLED_CONFLICT) -+ -+ we only can handle TLN conflicts because (a) excluding SID namespace -+ is not possible and (b) excluding NetBIOS namespace not possible. -+ These two types of conflicts should result in trust-add CLI error -+ -+ These conflicts can come from external source (another forest) or -+ from internal source (another domain in the same forest). We only -+ can fix the problems with another forest. -+ -+ To resolve TLN conflict we need to do following: -+ 1. Retrieve forest trust information for the forest we conflict on -+ 2. Add an exclusion entry for IPA DNS namespace to it -+ 3. Set forest trust information for the forest we conflict on -+ 4. Re-try establishing trust to the original forest -+ -+ This all can only be done under privileges of Active Directory admin -+ that can change forest trusts. If we cannot have those privileges, -+ the work has to be done manually in the Windows UI for -+ 'Active Directory Domains and Trusts' by the administrator of the -+ original forest. -+ """ -+ -+ # List of entries for unsolved conflicts -+ result = [] -+ -+ trust_timestamp = long(time.time()*1e7+116444736000000000) -+ -+ # Collision information contains entries for specific trusted domains -+ # we collide with. Look into TLN collisions and add a TLN exclusion -+ # entry to the specific domain trust. -+ root_logger.error("Attempt to solve forest trust topology conflicts") -+ for rec in cinfo.entries: -+ if rec.type == lsa.LSA_FOREST_TRUST_COLLISION_TDO: -+ dominfo = self._pipe.lsaRQueryForestTrustInformation( -+ self._policy_handle, -+ rec.name, -+ lsa.LSA_FOREST_TRUST_DOMAIN_INFO) -+ -+ # Oops, we were unable to retrieve trust topology for this -+ # trusted domain (forest). -+ if not dominfo: -+ result.append(rec) -+ root_logger.error("Unable to resolve conflict for " -+ "DNS domain %s in the forest %s " -+ "for domain trust %s. Trust cannot " -+ "be established unless this conflict " -+ "is fixed manually." -+ % (another_domain.info['dns_domain'], -+ self.info['dns_domain'], -+ rec.name.string)) -+ continue -+ -+ # Copy over the entries, extend with TLN exclusion -+ entries = [] -+ for e in dominfo.entries: -+ e1 = lsa.ForestTrustRecord() -+ e1.type = e.type -+ e1.flags = e.flags -+ e1.time = e.time -+ e1.forest_trust_data = e.forest_trust_data -+ entries.append(e1) -+ -+ # Create TLN exclusion record -+ record = lsa.ForestTrustRecord() -+ record.type = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX -+ record.flags = 0 -+ record.time = trust_timestamp -+ record.forest_trust_data.string = \ -+ another_domain.info['dns_domain'] -+ entries.append(record) -+ -+ fti = lsa.ForestTrustInformation() -+ fti.count = len(entries) -+ fti.entries = entries -+ -+ # Update the forest trust information now -+ ldname = lsa.StringLarge() -+ ldname.string = rec.name.string -+ cninfo = self._pipe.lsaRSetForestTrustInformation( -+ self._policy_handle, -+ ldname, -+ lsa.LSA_FOREST_TRUST_DOMAIN_INFO, -+ fti, 0) -+ if cninfo: -+ result.append(rec) -+ root_logger.error("When defining exception for DNS " -+ "domain %s in forest %s for " -+ "trusted forest %s, " -+ "got collision info back:\n%s" -+ % (another_domain.info['dns_domain'], -+ self.info['dns_domain'], -+ rec.name.string, -+ ndr_print(cninfo))) -+ else: -+ result.append(rec) -+ root_logger.error("Unable to resolve conflict for " -+ "DNS domain %s in the forest %s " -+ "for in-forest domain %s. Trust cannot " -+ "be established unless this conflict " -+ "is fixed manually." -+ % (another_domain.info['dns_domain'], -+ self.info['dns_domain'], -+ rec.name.string)) -+ -+ if len(result) == 0: -+ root_logger.error("Successfully solved all conflicts") -+ raise TrustTopologyConflictSolved() -+ -+ # Otherwise, raise TrustTopologyConflictError() exception -+ domains = [x.name.string for x in result] -+ raise errors.TrustTopologyConflictError( -+ target=self.info['dns_domain'], -+ conflict=another_domain.info['dns_domain'], -+ domains=domains) -+ -+ -+ - def update_ftinfo(self, another_domain): - """ - Updates forest trust information in this forest corresponding - to the another domain's information. - """ -- try: -- if another_domain.ftinfo_records: -- ftinfo = self.generate_ftinfo(another_domain) -- # Set forest trust information -- we do it only against AD DC as -- # smbd already has the information about itself -- ldname = lsa.StringLarge() -- ldname.string = another_domain.info['dns_domain'] -- ftlevel = lsa.LSA_FOREST_TRUST_DOMAIN_INFO -- # RSetForestTrustInformation returns collision information -- # for trust topology -- cinfo = self._pipe.lsaRSetForestTrustInformation( -- self._policy_handle, -- ldname, -- ftlevel, -- ftinfo, 0) -- if cinfo: -- root_logger.error("When setting forest trust information, " -- "got collision info back:\n%s" -- % (ndr_print(cinfo))) -- except RuntimeError as e: -- # We can ignore the error here -- -- # setting up name suffix routes may fail -- pass -+ if another_domain.ftinfo_records: -+ ftinfo = self.generate_ftinfo(another_domain) -+ # Set forest trust information -- we do it only against AD DC as -+ # smbd already has the information about itself -+ ldname = lsa.StringLarge() -+ ldname.string = another_domain.info['dns_domain'] -+ ftlevel = lsa.LSA_FOREST_TRUST_DOMAIN_INFO -+ # RSetForestTrustInformation returns collision information -+ # for trust topology -+ cinfo = self._pipe.lsaRSetForestTrustInformation( -+ self._policy_handle, -+ ldname, -+ ftlevel, -+ ftinfo, 0) -+ if cinfo: -+ root_logger.error("When setting forest trust information, " -+ "got collision info back:\n%s" -+ % (ndr_print(cinfo))) -+ self.clear_ftinfo_conflict(another_domain, cinfo) - - def establish_trust(self, another_domain, trustdom_secret, - trust_type='bidirectional', trust_external=False): -@@ -1207,7 +1347,19 @@ class TrustDomainInstance(object): - root_logger.error( - 'unable to set trust transitivity status: %s' % (str(e))) - -- if self.info['is_pdc'] or trust_external: -+ # Updating forest trust info may fail -+ # If it failed due to topology conflict, it may be fixed automatically -+ # update_ftinfo() will through exceptions in that case -+ # Note that MS-LSAD 3.1.4.7.16 says: -+ # ------------------------- -+ # The server MUST also make sure that the trust attributes associated -+ # with the trusted domain object referenced by the TrustedDomainName -+ # parameter has the TRUST_ATTRIBUTE_FOREST_TRANSITIVE set. -+ # If the attribute is not present, the server MUST return -+ # STATUS_INVALID_PARAMETER. -+ # ------------------------- -+ # Thus, we must not update forest trust info for the external trust -+ if self.info['is_pdc'] and not trust_external: - self.update_ftinfo(another_domain) - - def verify_trust(self, another_domain): -@@ -1509,9 +1661,21 @@ class TrustDomainJoins(object): - if not self.remote_domain.read_only: - trustdom_pass = samba.generate_random_password(128, 128) - self.get_realmdomains() -- self.remote_domain.establish_trust(self.local_domain, -- trustdom_pass, -- trust_type, trust_external) -+ -+ # Establishing trust may throw an exception for topology -+ # conflict. If it was solved, re-establish the trust again -+ # Otherwise let the CLI to display a message about the conflict -+ try: -+ self.remote_domain.establish_trust(self.local_domain, -+ trustdom_pass, -+ trust_type, trust_external) -+ except TrustTopologyConflictSolved as e: -+ # we solved topology conflict, retry again -+ self.remote_domain.establish_trust(self.local_domain, -+ trustdom_pass, -+ trust_type, trust_external) -+ -+ # For local domain we don't set topology information - self.local_domain.establish_trust(self.remote_domain, - trustdom_pass, - trust_type, trust_external) --- -2.7.4 - diff --git a/SOURCES/0092-trust-make-sure-external-trust-topology-is-correctly.patch b/SOURCES/0092-trust-make-sure-external-trust-topology-is-correctly.patch deleted file mode 100644 index ed41671..0000000 --- a/SOURCES/0092-trust-make-sure-external-trust-topology-is-correctly.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 2026313385db9ff2d1e74b22b7e2c6be7f7a9705 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 15 Aug 2016 18:32:25 +0300 -Subject: [PATCH] trust: make sure external trust topology is correctly - rendered - -When external trust is established, it is by definition is -non-transitive: it is not possible to obtain Kerberos tickets to any -service outside the trusted domain. - -Reflect this reality by only accepting UPN suffixes from the external -trust -- since the trusted domain is a part of another forest and UPN -suffixes are forest-wide, there could be user accounts in the trusted -domain that use forest-wide UPN suffix but it will be impossible to -reach the forest root via the externally trusted domain. - -Also, an argument to netr_DsRGetForestTrustInformation() has to be -either forest root domain name or None (NULL). Otherwise we'll get -an error as explained in MS-NRPC 3.5.4.7.5. - -https://fedorahosted.org/freeipa/ticket/6021 - -Reviewed-By: Martin Babinsky ---- - ipaserver/dcerpc.py | 2 +- - ipaserver/plugins/trust.py | 28 +++++++++++++++++----------- - 2 files changed, 18 insertions(+), 12 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index a1c12f16a655493808d50e6adb95e618a664a98c..4d98485e17a9113322b7e38629fc43b593e99fd9 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -1449,7 +1449,7 @@ def fetch_domains(api, mydomain, trustdomain, creds=None, server=None): - # Older FreeIPA versions used netr_DsrEnumerateDomainTrusts call - # but it doesn't provide information about non-domain UPNs associated - # with the forest, thus we have to use netr_DsRGetForestTrustInformation -- domains = netr_pipe.netr_DsRGetForestTrustInformation(td.info['dc'], '', 0) -+ domains = netr_pipe.netr_DsRGetForestTrustInformation(td.info['dc'], None, 0) - return domains - - domains = None -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index f2e0b1ee4b261ddc4f29477f46b7f4027af18892..8a25b560f9ae086ba8524cca22f39e8f67696146 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -1663,6 +1663,23 @@ def add_new_domains_from_trust(myapi, trustinstance, trust_entry, domains, **opt - for x, y in six.iteritems(domains['suffixes']) - if x not in domains['domains']) - -+ try: -+ dn = myapi.Object.trust.get_dn(trust_name, trust_type=u'ad') -+ ldap = myapi.Backend.ldap2 -+ entry = ldap.get_entry(dn) -+ tlns = entry.get('ipantadditionalsuffixes', []) -+ tlns.extend(x for x in suffixes if x not in tlns) -+ entry['ipantadditionalsuffixes'] = tlns -+ ldap.update_entry(entry) -+ except errors.EmptyModlist: -+ pass -+ -+ is_nontransitive = int(trust_entry.get('ipanttrustattributes', -+ [0])[0]) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE -+ -+ if is_nontransitive: -+ return result -+ - for dom in six.itervalues(domains['domains']): - dom['trust_type'] = u'ad' - try: -@@ -1686,17 +1703,6 @@ def add_new_domains_from_trust(myapi, trustinstance, trust_entry, domains, **opt - # Ignore updating duplicate entries - pass - -- try: -- dn = myapi.Object.trust.get_dn(trust_name, trust_type=u'ad') -- ldap = myapi.Backend.ldap2 -- entry = ldap.get_entry(dn) -- tlns = entry.get('ipantadditionalsuffixes', []) -- tlns.extend(x for x in suffixes if x not in tlns) -- entry['ipantadditionalsuffixes'] = tlns -- ldap.update_entry(entry) -- except errors.EmptyModlist: -- pass -- - return result - - --- -2.7.4 - diff --git a/SOURCES/0092-upgrade-adtrust-update_tdo_gidnumber-plugin-must-che.patch b/SOURCES/0092-upgrade-adtrust-update_tdo_gidnumber-plugin-must-che.patch new file mode 100644 index 0000000..8d8b44a --- /dev/null +++ b/SOURCES/0092-upgrade-adtrust-update_tdo_gidnumber-plugin-must-che.patch @@ -0,0 +1,37 @@ +From f50331d2f9f34ae17a3d5323e74982ca87eba12e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 20 Apr 2017 16:31:53 +0200 +Subject: [PATCH] upgrade: adtrust update_tdo_gidnumber plugin must check if + adtrust is installed + +During upgrade, the plugin update_tdo_gidnumber is launched in order to +add a gidnumber to the Trusted Domain Object. +This plugin should not be run when ad trust is not installed, otherwise an +error message is displayed. + +https://pagure.io/freeipa/issue/6881 + +Reviewed-By: Alexander Bokovoy +--- + ipaserver/install/plugins/adtrust.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py +index 075f197780edc2aadf42fa82b71e9e2b29e66ea9..a72af00635649ddf54640738c2f28cb09c7e91bb 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -329,6 +329,11 @@ class update_tdo_gidnumber(Updater): + def execute(self, **options): + ldap = self.api.Backend.ldap2 + ++ # First, see if trusts are enabled on the server ++ if not self.api.Command.adtrust_is_enabled()['result']: ++ self.log.debug('AD Trusts are not enabled on this server') ++ return False, [] ++ + # Read the gidnumber of the fallback group + dn = DN(('cn', ADTRUSTInstance.FALLBACK_GROUP_NAME), + self.api.env.container_group, +-- +2.12.2 + diff --git a/SOURCES/0093-compat-manage-behave-the-same-for-all-users.patch b/SOURCES/0093-compat-manage-behave-the-same-for-all-users.patch new file mode 100644 index 0000000..0729953 --- /dev/null +++ b/SOURCES/0093-compat-manage-behave-the-same-for-all-users.patch @@ -0,0 +1,34 @@ +From 03b605a70c8f5a6def7a572ceb302051934c78e7 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 21 Apr 2017 09:32:34 +0200 +Subject: [PATCH] compat-manage: behave the same for all users + +Due to LDAP connection refactoring, compat-manage would have behaved +differently for root and for other users even though it requires +the directory manager password. This is caused by it trying to do +external bind when it does not have the DIRMAN password which was +previously not supplied. + +https://pagure.io/freeipa/issue/6821 + +Reviewed-By: Martin Basti +--- + install/tools/ipa-compat-manage | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage +index a29a92fabd653bb983778420cca0983048ee39ef..6dd259d2aad870e575093d6732157de743502ac2 100755 +--- a/install/tools/ipa-compat-manage ++++ b/install/tools/ipa-compat-manage +@@ -105,7 +105,7 @@ def main(): + debug=options.debug, + confdir=paths.ETC_IPA) + api.finalize() +- api.Backend.ldap2.connect() ++ api.Backend.ldap2.connect(bind_pw=dirman_password) + + if args[0] == "status": + entry = None +-- +2.12.2 + diff --git a/SOURCES/0093-trust-make-sure-ID-range-is-created-for-the-child-do.patch b/SOURCES/0093-trust-make-sure-ID-range-is-created-for-the-child-do.patch deleted file mode 100644 index eab6add..0000000 --- a/SOURCES/0093-trust-make-sure-ID-range-is-created-for-the-child-do.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 590c3649471832092a20a5eaf09ed0418ae468f6 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Sat, 6 Aug 2016 11:12:13 +0300 -Subject: [PATCH] trust: make sure ID range is created for the child domain - even if it exists - -ID ranges for child domains of a forest trust were created incorrectly -in FreeIPA 4.4.0 due to refactoring of -- if the domain was already -existing, we never attempted to create the ID range for it. - -At the same time, when domain was missing, we attempted to add ID range -and passed both forest root and the child domain names to add_range(). -However, add_range() only looks at the first positional argument which -was the forest root name. That ID range always exists (it is created -before child domains are processed). - -Modify the code to make sure child domain name is passed as the first -positional argument. In addition, the oddjob helper should explicitly -set context='server' so that idrange code will be able to see and use -ipaserver/dcerpc.py helpers. - -Resolves: https://fedorahosted.org/freeipa/ticket/5738 -Reviewed-By: Martin Babinsky ---- - install/oddjob/com.redhat.idm.trust-fetch-domains | 2 +- - ipaserver/plugins/trust.py | 10 +++++++--- - 2 files changed, 8 insertions(+), 4 deletions(-) - -diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains -index 7c948fd53bd54bf3638ef3cc4407576b9011f4fb..bffa021cd4f01d31b7271d1ad84420884ce8d99e 100755 ---- a/install/oddjob/com.redhat.idm.trust-fetch-domains -+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains -@@ -76,7 +76,7 @@ env._bootstrap(debug=options.debug, log=None) - env._finalize_core(**dict(DEFAULT_CONFIG)) - - # Initialize the API with the proper debug level --api.bootstrap(in_server=True, debug=env.debug, log=None) -+api.bootstrap(in_server=True, debug=env.debug, log=None, context='server') - api.finalize() - - # Only import trust plugin after api is initialized or internal imports -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index 8a25b560f9ae086ba8524cca22f39e8f67696146..b9d9b122a90de62946307b99b44932129eb611e8 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -1690,15 +1690,19 @@ def add_new_domains_from_trust(myapi, trustinstance, trust_entry, domains, **opt - if 'raw' in options: - dom['raw'] = options['raw'] - -- res = myapi.Command.trustdomain_add(trust_name, name, **dom) -- result.append(res['result']) -+ try: -+ res = myapi.Command.trustdomain_add(trust_name, name, **dom) -+ result.append(res['result']) -+ except errors.DuplicateEntry: -+ # Ignore updating duplicate entries -+ pass - - if idrange_type != u'ipa-ad-trust-posix': - range_name = name.upper() + '_id_range' - dom['range_type'] = u'ipa-ad-trust' - add_range(myapi, trustinstance, - range_name, dom['ipanttrusteddomainsid'], -- trust_name, name, **dom) -+ name, **dom) - except errors.DuplicateEntry: - # Ignore updating duplicate entries - pass --- -2.7.4 - diff --git a/SOURCES/0094-Move-the-compat-plugin-setup-at-the-end-of-install.patch b/SOURCES/0094-Move-the-compat-plugin-setup-at-the-end-of-install.patch new file mode 100644 index 0000000..2a1fcb9 --- /dev/null +++ b/SOURCES/0094-Move-the-compat-plugin-setup-at-the-end-of-install.patch @@ -0,0 +1,317 @@ +From f0bd45fb0c1071006887dc10abac233d2756d951 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Thu, 13 Apr 2017 09:15:47 +0200 +Subject: [PATCH] Move the compat plugin setup at the end of install + +The compat plugin was causing deadlocks with the topology plugin. Move +its setup at the end of the installation and remove the +cn=topology,cn=ipa,cn=etc subtree from its scope. + +https://pagure.io/freeipa/issue/6821 + +Reviewed-By: Martin Basti +--- + install/share/Makefile.am | 1 - + install/updates/10-schema_compat.update | 93 --------------------- + .../80-schema_compat.update} | 96 +++++++++++++++++++++- + install/updates/Makefile.am | 2 +- + ipaplatform/base/paths.py | 3 +- + ipaserver/install/dsinstance.py | 9 -- + 6 files changed, 98 insertions(+), 106 deletions(-) + delete mode 100644 install/updates/10-schema_compat.update + rename install/{share/schema_compat.uldif => updates/80-schema_compat.update} (55%) + +diff --git a/install/share/Makefile.am b/install/share/Makefile.am +index 9e539a3f30c2979de26575ba66bbb23fecd03a88..b27861da37153d77d693ce6e46340525bbd50173 100644 +--- a/install/share/Makefile.am ++++ b/install/share/Makefile.am +@@ -65,7 +65,6 @@ dist_app_DATA = \ + opendnssec_conf.template \ + opendnssec_kasp.template \ + unique-attributes.ldif \ +- schema_compat.uldif \ + ldapi.ldif \ + wsgi.py \ + repoint-managed-entries.ldif \ +diff --git a/install/updates/10-schema_compat.update b/install/updates/10-schema_compat.update +deleted file mode 100644 +index fbe8703407aacd75baf160630c20835a1b4ddc65..0000000000000000000000000000000000000000 +--- a/install/updates/10-schema_compat.update ++++ /dev/null +@@ -1,93 +0,0 @@ +-dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config +-only:schema-compat-entry-rdn:%ifeq("ipaEnabledFlag", "FALSE", "DISABLED", "cn=%{cn}") +-add:schema-compat-entry-attribute: sudoHost=%ifeq("hostCategory","all","ALL","%{hostMask}") +-add:schema-compat-entry-attribute: sudoRunAsUser=%%%{ipaSudoRunAsExtUserGroup} +-# Fix for #4324 (regression of #1309) +-remove:schema-compat-entry-attribute:sudoRunAsGroup=%deref("ipaSudoRunAs","cn") +-remove:schema-compat-entry-attribute:sudoRunAsUser=%{ipaSudoRunAsExtUser} +-remove:schema-compat-entry-attribute:sudoRunAsUser=%%%{ipaSudoRunAsExtUserGroup} +-remove:schema-compat-entry-attribute:sudoRunAsUser=%deref("ipaSudoRunAs","uid") +-remove:schema-compat-entry-attribute:sudoRunAsGroup=%{ipaSudoRunAsExtGroup} +-remove:schema-compat-entry-attribute:sudoRunAsGroup=%deref_f("ipaSudoRunAsGroup","(objectclass=posixGroup)","cn") +- +-# We need to add the value in a separate transaction +-dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config +-add: schema-compat-entry-attribute: sudoRunAsGroup=%deref_f("ipaSudoRunAsGroup","(objectclass=posixGroup)","cn") +-add: schema-compat-entry-attribute: sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%{ipaSudoRunAsExtUser}") +-add: schema-compat-entry-attribute: sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%%%{ipaSudoRunAsExtUserGroup}") +-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\")") +-remove: schema-compat-ignore-subtree: cn=changelog +-remove: schema-compat-ignore-subtree: o=ipaca +-add: schema-compat-restrict-subtree: $SUFFIX +-add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config +-add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX +- +-# Change padding for host and userCategory so the pad returns the same value +-# as the original, '' or -. +-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:-}) +-remove: schema-compat-ignore-subtree: cn=changelog +-remove: schema-compat-ignore-subtree: o=ipaca +-add: schema-compat-restrict-subtree: $SUFFIX +-add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config +-add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX +- +-dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config +-default:objectClass: top +-default:objectClass: extensibleObject +-default:cn: computers +-default:schema-compat-container-group: cn=compat, $SUFFIX +-default:schema-compat-container-rdn: cn=computers +-default:schema-compat-search-base: cn=computers, cn=accounts, $SUFFIX +-default:schema-compat-search-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) +-default:schema-compat-entry-rdn: cn=%first("%{fqdn}") +-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} +-remove: schema-compat-ignore-subtree: cn=changelog +-remove: schema-compat-ignore-subtree: o=ipaca +-add: schema-compat-restrict-subtree: $SUFFIX +-add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config +-add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX +- +-dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config +-add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} +- +-dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config +-remove: schema-compat-ignore-subtree: cn=changelog +-remove: schema-compat-ignore-subtree: o=ipaca +-add: schema-compat-restrict-subtree: $SUFFIX +-add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config +-add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX +- +-dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config +-remove: schema-compat-ignore-subtree: cn=changelog +-remove: schema-compat-ignore-subtree: o=ipaca +-add: schema-compat-restrict-subtree: $SUFFIX +-add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config +-add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX +- +-dn: cn=Schema Compatibility,cn=plugins,cn=config +-# We need to run schema-compat pre-bind callback before +-# other IPA pre-bind callbacks to make sure bind DN is +-# rewritten to the original entry if needed +-add:nsslapd-pluginprecedence: 40 +- +-dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config +-add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","objectclass=ipaOverrideTarget","") +-add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","ipaanchoruuid=:IPA:$DOMAIN:%{ipauniqueid}","") +-add:schema-compat-entry-attribute: ipaanchoruuid=%{ipaanchoruuid} +-add:schema-compat-entry-attribute: %ifeq("ipaanchoruuid","%{ipaanchoruuid}","objectclass=ipaOverrideTarget","") +- +-dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config +-add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","objectclass=ipaOverrideTarget","") +-add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","ipaanchoruuid=:IPA:$DOMAIN:%{ipauniqueid}","") +-add:schema-compat-entry-attribute: ipaanchoruuid=%{ipaanchoruuid} +-add:schema-compat-entry-attribute: %ifeq("ipaanchoruuid","%{ipaanchoruuid}","objectclass=ipaOverrideTarget","") +- +-dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config +-add:schema-compat-entry-attribute: uid=%{uid} +-replace:schema-compat-entry-rdn: uid=%{uid}::uid=%first("%{uid}") +diff --git a/install/share/schema_compat.uldif b/install/updates/80-schema_compat.update +similarity index 55% +rename from install/share/schema_compat.uldif +rename to install/updates/80-schema_compat.update +index 66f8ea1c31bc534b3ee134c6df6132f4318c81fc..06cbcab8ad809d95a907c161044ff91df827ebf3 100644 +--- a/install/share/schema_compat.uldif ++++ b/install/updates/80-schema_compat.update +@@ -1,5 +1,6 @@ + # +-# Enable the Schema Compatibility plugin provided by slapi-nis. ++# Setup the Schema Compatibility plugin provided by slapi-nis. ++# This should be done after all other updates have been applied + # + # http://slapi-nis.fedorahosted.org/ + # +@@ -126,3 +127,96 @@ default:schema-compat-entry-attribute: macAddress=%{macAddress} + dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config + only:aci: (targetattr !="aci")(version 3.0; acl "VLV Request Control"; allow (read, search, compare, proxy) userdn = "ldap:///anyone"; ) + ++dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config ++only:schema-compat-entry-rdn:%ifeq("ipaEnabledFlag", "FALSE", "DISABLED", "cn=%{cn}") ++add:schema-compat-entry-attribute: sudoHost=%ifeq("hostCategory","all","ALL","%{hostMask}") ++add:schema-compat-entry-attribute: sudoRunAsUser=%%%{ipaSudoRunAsExtUserGroup} ++# Fix for #4324 (regression of #1309) ++remove:schema-compat-entry-attribute:sudoRunAsGroup=%deref("ipaSudoRunAs","cn") ++remove:schema-compat-entry-attribute:sudoRunAsUser=%{ipaSudoRunAsExtUser} ++remove:schema-compat-entry-attribute:sudoRunAsUser=%%%{ipaSudoRunAsExtUserGroup} ++remove:schema-compat-entry-attribute:sudoRunAsUser=%deref("ipaSudoRunAs","uid") ++remove:schema-compat-entry-attribute:sudoRunAsGroup=%{ipaSudoRunAsExtGroup} ++remove:schema-compat-entry-attribute:sudoRunAsGroup=%deref_f("ipaSudoRunAsGroup","(objectclass=posixGroup)","cn") ++ ++# We need to add the value in a separate transaction ++dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config ++add: schema-compat-entry-attribute: sudoRunAsGroup=%deref_f("ipaSudoRunAsGroup","(objectclass=posixGroup)","cn") ++add: schema-compat-entry-attribute: sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%{ipaSudoRunAsExtUser}") ++add: schema-compat-entry-attribute: sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%%%{ipaSudoRunAsExtUserGroup}") ++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\")") ++remove: schema-compat-ignore-subtree: cn=changelog ++remove: schema-compat-ignore-subtree: o=ipaca ++add: schema-compat-restrict-subtree: $SUFFIX ++add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config ++add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++ ++# Change padding for host and userCategory so the pad returns the same value ++# as the original, '' or -. ++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:-}) ++remove: schema-compat-ignore-subtree: cn=changelog ++remove: schema-compat-ignore-subtree: o=ipaca ++add: schema-compat-restrict-subtree: $SUFFIX ++add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config ++add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++ ++dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config ++default:objectClass: top ++default:objectClass: extensibleObject ++default:cn: computers ++default:schema-compat-container-group: cn=compat, $SUFFIX ++default:schema-compat-container-rdn: cn=computers ++default:schema-compat-search-base: cn=computers, cn=accounts, $SUFFIX ++default:schema-compat-search-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) ++default:schema-compat-entry-rdn: cn=%first("%{fqdn}") ++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} ++remove: schema-compat-ignore-subtree: cn=changelog ++remove: schema-compat-ignore-subtree: o=ipaca ++add: schema-compat-restrict-subtree: $SUFFIX ++add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config ++add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++ ++dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config ++add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} ++ ++dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config ++remove: schema-compat-ignore-subtree: cn=changelog ++remove: schema-compat-ignore-subtree: o=ipaca ++add: schema-compat-restrict-subtree: $SUFFIX ++add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config ++add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++ ++dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config ++remove: schema-compat-ignore-subtree: cn=changelog ++remove: schema-compat-ignore-subtree: o=ipaca ++add: schema-compat-restrict-subtree: $SUFFIX ++add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config ++add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++ ++dn: cn=Schema Compatibility,cn=plugins,cn=config ++# We need to run schema-compat pre-bind callback before ++# other IPA pre-bind callbacks to make sure bind DN is ++# rewritten to the original entry if needed ++add:nsslapd-pluginprecedence: 40 ++ ++dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config ++add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","objectclass=ipaOverrideTarget","") ++add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","ipaanchoruuid=:IPA:$DOMAIN:%{ipauniqueid}","") ++add:schema-compat-entry-attribute: ipaanchoruuid=%{ipaanchoruuid} ++add:schema-compat-entry-attribute: %ifeq("ipaanchoruuid","%{ipaanchoruuid}","objectclass=ipaOverrideTarget","") ++ ++dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config ++add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","objectclass=ipaOverrideTarget","") ++add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","ipaanchoruuid=:IPA:$DOMAIN:%{ipauniqueid}","") ++add:schema-compat-entry-attribute: ipaanchoruuid=%{ipaanchoruuid} ++add:schema-compat-entry-attribute: %ifeq("ipaanchoruuid","%{ipaanchoruuid}","objectclass=ipaOverrideTarget","") ++ ++dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config ++add:schema-compat-entry-attribute: uid=%{uid} ++replace:schema-compat-entry-rdn: uid=%{uid}::uid=%first("%{uid}") +diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am +index 0ff0edb93abf4c4656b7504bd9ce8f774918fc2d..e18d01127b592a6c7941729d6160d10fb2d3e76c 100644 +--- a/install/updates/Makefile.am ++++ b/install/updates/Makefile.am +@@ -9,7 +9,6 @@ app_DATA = \ + 10-selinuxusermap.update \ + 10-rootdse.update \ + 10-uniqueness.update \ +- 10-schema_compat.update \ + 19-managed-entries.update \ + 20-aci.update \ + 20-dna.update \ +@@ -62,6 +61,7 @@ app_DATA = \ + 73-custodia.update \ + 73-winsync.update \ + 73-certmap.update \ ++ 80-schema_compat.update \ + 90-post_upgrade_plugins.update \ + $(NULL) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 9cf160fac483157b508dedac7a5fc26cb12c63a4..dbdd71ed0b4d69c1101db4aeb7d93152ab8aa730 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -236,7 +236,8 @@ class BasePathNamespace(object): + HTML_KRBREALM_CON = "/usr/share/ipa/html/krbrealm.con" + NIS_ULDIF = "/usr/share/ipa/nis.uldif" + NIS_UPDATE_ULDIF = "/usr/share/ipa/nis-update.uldif" +- SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/schema_compat.uldif" ++ SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/updates/91-schema_compat.update" ++ SCHEMA_COMPAT_POST_ULDIF = "/usr/share/ipa/schema_compat_post.uldif" + IPA_JS_PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins" + UPDATES_DIR = "/usr/share/ipa/updates/" + DICT_WORDS = "/usr/share/dict/words" +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 99a1781ca4475805e9bf3b2bac3f26b5fb107a43..403fe8489fdd9e0dbf40dd4df3794b51185d45b9 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -38,7 +38,6 @@ from ipapython import dogtag + from ipaserver.install import service + from ipaserver.install import installutils + from ipaserver.install import certs +-from ipaserver.install import ldapupdate + from ipaserver.install import replication + from ipaserver.install import sysupgrade + from ipaserver.install import upgradeinstance +@@ -281,8 +280,6 @@ class DsInstance(service.Service): + self.step("configuring Posix uid/gid generation", + self.__config_uidgid_gen) + self.step("adding replication acis", self.__add_replication_acis) +- self.step("enabling compatibility plugin", +- self.__enable_compat_plugin) + self.step("activating sidgen plugin", self._add_sidgen_plugin) + self.step("activating extdom plugin", self._add_extdom_plugin) + self.step("tuning directory server", self.__tuning) +@@ -706,12 +703,6 @@ class DsInstance(service.Service): + def __add_winsync_module(self): + self._ldap_mod("ipa-winsync-conf.ldif") + +- def __enable_compat_plugin(self): +- ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password, sub_dict=self.sub_dict) +- rv = ld.update([paths.SCHEMA_COMPAT_ULDIF]) +- if not rv: +- raise RuntimeError("Enabling compatibility plugin failed") +- + def __config_version_module(self): + self._ldap_mod("version-conf.ldif") + +-- +2.12.2 + diff --git a/SOURCES/0094-ipa-kdb-simplify-trusted-domain-parent-search.patch b/SOURCES/0094-ipa-kdb-simplify-trusted-domain-parent-search.patch deleted file mode 100644 index 416bba9..0000000 --- a/SOURCES/0094-ipa-kdb-simplify-trusted-domain-parent-search.patch +++ /dev/null @@ -1,87 +0,0 @@ -From 6c69ea75765b93768ccc3cf55a4813f2d4b81dac Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Sun, 7 Aug 2016 21:42:14 +0300 -Subject: [PATCH] ipa-kdb: simplify trusted domain parent search - -In terms of cross-forest trust parent domain is the root domain of -the forest because we only have trust established with the forest root. - -In FreeIPA LDAP store all sub-domains stored in cn=, -cn=ad,cn=trusts,... subtree. Thus, a first RDN after cn=ad is the -forest root domain. This allows us to simplify logic of finding -the parent domain. - -For complex hierachical forests with more than two levels of -sub-domains, this will still be true because of the forest trust: -as forest trust is established to the forest root domain, any -communication to any sub-domain must traverse forest root domain's -domain controller. - -Note that SSSD also generated incorrectly CA paths information -for forests with non-hierarchical tree-roots. In such cases -IPA KDC got confused and mistakenly assumed direct trust to the -non-hierarchical tree-root instead of going through the forest -root domain. See https://fedorahosted.org/sssd/ticket/3103 for -details. - -Resolves: https://fedorahosted.org/freeipa/ticket/5738 -Reviewed-By: Martin Babinsky ---- - daemons/ipa-kdb/ipa_kdb_mspac.c | 27 ++++++++++++++------------- - 1 file changed, 14 insertions(+), 13 deletions(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c -index 80e7055fd6cd7b962eeffbccc675a73d73700793..76e9e99d0b691d06ccc86e0e851fb7e226d62597 100644 ---- a/daemons/ipa-kdb/ipa_kdb_mspac.c -+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c -@@ -2420,6 +2420,7 @@ krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx) - char *base = NULL; - char *dnstr = NULL; - char *dnl = NULL; -+ LDAPDN dn = NULL; - char **sid_blacklist_incoming = NULL; - char **sid_blacklist_outgoing = NULL; - int ret, n, i; -@@ -2547,26 +2548,26 @@ krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx) - goto done; - } - -- /* Note that after ldap_str2rdn() call dnl will point to end of one RDN -- * which would be '\0' for trust root domain and ',' for subdomain */ - dnl--; dnl[0] = '\0'; -- ret = ldap_str2rdn(dnstr, &rdn, &dnl, LDAP_DN_FORMAT_LDAPV3); -+ /* Create a DN, which is now everything before the base, -+ * to get list of rdn values -- the last one would be a root domain. -+ * Since with cross-forest trust we have to route everything via root -+ * domain, that is enough for us to assign parentship. */ -+ ret = ldap_str2dn(dnstr, &dn, LDAP_DN_FORMAT_LDAPV3); - if (ret) { - goto done; - } - -- ldap_rdnfree(rdn); -- -- if (dnl[0] != '\0') { -- dnl++; -- ret = ldap_str2rdn(dnl, &rdn, &dnl, LDAP_DN_FORMAT_LDAPV3); -- if (ret) { -- goto done; -- } -- t[n].parent_name = strndup(rdn[0]->la_value.bv_val, rdn[0]->la_value.bv_len); -- ldap_rdnfree(rdn); -+ rdn = NULL; -+ for (i = 0; dn[i] != NULL; i++) { -+ rdn = dn[i]; - } - -+ /* We should have a single AVA in the domain RDN */ -+ t[n].parent_name = strndup(rdn[0]->la_value.bv_val, rdn[0]->la_value.bv_len); -+ -+ ldap_dnfree(dn); -+ - free(dnstr); - dnstr = NULL; - } --- -2.7.4 - diff --git a/SOURCES/0095-Remove-Custodia-server-keys-from-LDAP.patch b/SOURCES/0095-Remove-Custodia-server-keys-from-LDAP.patch deleted file mode 100644 index c4fdee1..0000000 --- a/SOURCES/0095-Remove-Custodia-server-keys-from-LDAP.patch +++ /dev/null @@ -1,78 +0,0 @@ -From dd108a1fd1088f6a4f382cccec2aec69c7d9f0fe Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 8 Aug 2016 16:06:08 +0200 -Subject: [PATCH] Remove Custodia server keys from LDAP - -The server-del plugin now removes the Custodia keys for encryption and -key signing from LDAP. - -https://fedorahosted.org/freeipa/ticket/6015 - -Reviewed-By: Martin Basti ---- - ipalib/constants.py | 1 + - ipaserver/plugins/server.py | 29 +++++++++++++++++++++++++++++ - 2 files changed, 30 insertions(+) - -diff --git a/ipalib/constants.py b/ipalib/constants.py -index 0574bb3aa457dd79a6d64f6b8a6b57161d32da92..9b351e260f15211330521453b3ffcd41433a04bb 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -124,6 +124,7 @@ DEFAULT_CONFIG = ( - ('container_locations', DN(('cn', 'locations'), ('cn', 'etc'))), - ('container_ca', DN(('cn', 'cas'), ('cn', 'ca'))), - ('container_dnsservers', DN(('cn', 'servers'), ('cn', 'dns'))), -+ ('container_custodia', DN(('cn', 'custodia'), ('cn', 'ipa'), ('cn', 'etc'))), - - # Ports, hosts, and URIs: - ('xmlrpc_uri', 'http://localhost:8888/ipa/xml'), -diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py -index b245dcf72a2f9f32f52ec9acf68d96c69d6169c5..d62c0232c5e33642e44a088dbfd9f10675d733f4 100644 ---- a/ipaserver/plugins/server.py -+++ b/ipaserver/plugins/server.py -@@ -609,6 +609,32 @@ class server_del(LDAPDelete): - message=_("Failed to remove server %(master)s from server " - "list: %(err)s") % dict(master=master, err=e))) - -+ def _remove_server_custodia_keys(self, ldap, master): -+ """ -+ Delete all Custodia encryption and signing keys -+ """ -+ conn = self.Backend.ldap2 -+ env = self.api.env -+ # search for memberPrincipal=*/fqdn@realm -+ member_filter = ldap.make_filter_from_attr( -+ 'memberPrincipal', "/{}@{}".format(master, env.realm), -+ exact=False, leading_wildcard=True, trailing_wildcard=False) -+ custodia_subtree = DN(env.container_custodia, env.basedn) -+ try: -+ entries = conn.get_entries(custodia_subtree, -+ ldap.SCOPE_SUBTREE, -+ filter=member_filter) -+ for entry in entries: -+ conn.delete_entry(entry) -+ except errors.NotFound: -+ pass -+ except Exception as e: -+ self.add_message( -+ messages.ServerRemovalWarning( -+ message=_( -+ "Failed to clean up Custodia keys for " -+ "%(master)s: %(err)s") % dict(master=master, err=e))) -+ - def _remove_server_host_services(self, ldap, master): - """ - delete server kerberos key and all its svc principals -@@ -682,6 +708,9 @@ class server_del(LDAPDelete): - # remove the references to master's ldap/http principals - self._remove_server_principal_references(pkey) - -+ # remove Custodia encryption and signing keys -+ self._remove_server_custodia_keys(ldap, pkey) -+ - # finally destroy all Kerberos principals - self._remove_server_host_services(ldap, pkey) - --- -2.7.4 - diff --git a/SOURCES/0095-compat-ignore-cn-topology-cn-ipa-cn-etc-subtree.patch b/SOURCES/0095-compat-ignore-cn-topology-cn-ipa-cn-etc-subtree.patch new file mode 100644 index 0000000..43b196f --- /dev/null +++ b/SOURCES/0095-compat-ignore-cn-topology-cn-ipa-cn-etc-subtree.patch @@ -0,0 +1,62 @@ +From 08c5150d76971ab17eb02ceef0e65e993b7732ff Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 21 Apr 2017 09:39:56 +0200 +Subject: [PATCH] compat: ignore cn=topology,cn=ipa,cn=etc subtree + +The entries in cn=topology,cn=ipa,cn=etc should not be taken in +account for the compat plugin. + +https://pagure.io/freeipa/issue/6821 + +Reviewed-By: Martin Basti +--- + install/updates/80-schema_compat.update | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/install/updates/80-schema_compat.update b/install/updates/80-schema_compat.update +index 06cbcab8ad809d95a907c161044ff91df827ebf3..7483518134aad47195ab136626acb5130c0d536d 100644 +--- a/install/updates/80-schema_compat.update ++++ b/install/updates/80-schema_compat.update +@@ -152,6 +152,7 @@ remove: schema-compat-ignore-subtree: o=ipaca + add: schema-compat-restrict-subtree: $SUFFIX + add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config + add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++add: schema-compat-ignore-subtree: cn=topology,cn=ipa,cn=etc,$SUFFIX + + # Change padding for host and userCategory so the pad returns the same value + # as the original, '' or -. +@@ -162,6 +163,7 @@ remove: schema-compat-ignore-subtree: o=ipaca + add: schema-compat-restrict-subtree: $SUFFIX + add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config + add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++add: schema-compat-ignore-subtree: cn=topology,cn=ipa,cn=etc,$SUFFIX + + dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config + default:objectClass: top +@@ -181,6 +183,7 @@ remove: schema-compat-ignore-subtree: o=ipaca + add: schema-compat-restrict-subtree: $SUFFIX + add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config + add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++add: schema-compat-ignore-subtree: cn=topology,cn=ipa,cn=etc,$SUFFIX + + dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config + add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} +@@ -191,6 +194,7 @@ remove: schema-compat-ignore-subtree: o=ipaca + add: schema-compat-restrict-subtree: $SUFFIX + add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config + add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++add: schema-compat-ignore-subtree: cn=topology,cn=ipa,cn=etc,$SUFFIX + + dn: cn=groups,cn=Schema Compatibility,cn=plugins,cn=config + remove: schema-compat-ignore-subtree: cn=changelog +@@ -198,6 +202,7 @@ remove: schema-compat-ignore-subtree: o=ipaca + add: schema-compat-restrict-subtree: $SUFFIX + add: schema-compat-restrict-subtree: cn=Schema Compatibility,cn=plugins,cn=config + add: schema-compat-ignore-subtree: cn=dna,cn=ipa,cn=etc,$SUFFIX ++add: schema-compat-ignore-subtree: cn=topology,cn=ipa,cn=etc,$SUFFIX + + dn: cn=Schema Compatibility,cn=plugins,cn=config + # We need to run schema-compat pre-bind callback before +-- +2.12.2 + diff --git a/SOURCES/0096-Handled-empty-hostname-in-server-del-command.patch b/SOURCES/0096-Handled-empty-hostname-in-server-del-command.patch deleted file mode 100644 index 0d24e57..0000000 --- a/SOURCES/0096-Handled-empty-hostname-in-server-del-command.patch +++ /dev/null @@ -1,42 +0,0 @@ -From eddc43e5973cb81d88fe2e88bab5eed72d7d3cff Mon Sep 17 00:00:00 2001 -From: Abhijeet Kasurde -Date: Tue, 23 Aug 2016 17:34:51 +0530 -Subject: [PATCH] Handled empty hostname in server-del command - -Fixes: https://fedorahosted.org/freeipa/ticket/6248 - -Signed-off-by: Abhijeet Kasurde -Reviewed-By: Martin Basti -Reviewed-By: Stanislav Laznicka ---- - ipaclient/plugins/server.py | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/ipaclient/plugins/server.py b/ipaclient/plugins/server.py -index 725a2ce95708529bd4e1de7fc364c2aba0d805de..5356dbbf58373eebeab1c8c59ff0e23b374a15f3 100644 ---- a/ipaclient/plugins/server.py -+++ b/ipaclient/plugins/server.py -@@ -3,7 +3,7 @@ - # - - from ipaclient.frontend import MethodOverride --from ipalib import _ -+from ipalib import _, errors - from ipalib.plugable import Registry - - register = Registry() -@@ -12,6 +12,10 @@ register = Registry() - @register(override=True, no_fail=True) - class server_del(MethodOverride): - def interactive_prompt_callback(self, kw): -+ server_list = kw.get('cn') -+ if not server_list: -+ raise errors.RequirementError(name='cn') -+ - self.api.Backend.textui.print_plain( - _("Removing %(servers)s from replication topology, " -- "please wait...") % {'servers': ', '.join(kw['cn'])}) -+ "please wait...") % {'servers': ', '.join(server_list)}) --- -2.7.4 - diff --git a/SOURCES/0096-spec-file-bump-krb5-Requires-for-certauth-fixes.patch b/SOURCES/0096-spec-file-bump-krb5-Requires-for-certauth-fixes.patch new file mode 100644 index 0000000..2f0c64d --- /dev/null +++ b/SOURCES/0096-spec-file-bump-krb5-Requires-for-certauth-fixes.patch @@ -0,0 +1,68 @@ +From c8a4e5d946d8261748d632361a016950ab42f4ba Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 25 Apr 2017 12:35:34 +0000 +Subject: [PATCH] spec file: bump krb5 Requires for certauth fixes + +Bump krb5-* Requires to the version which includes the final version of +certauth support. + +https://pagure.io/freeipa/issue/4905 + +Reviewed-By: Stanislav Laznicka +--- + freeipa.spec.in | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 978ebb184f7d051b303940560f44c7a094b071a1..3b7410b6bda3afc877d928b4df21529ae2faf0aa 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -36,11 +36,15 @@ + + %global alt_name ipa + %if 0%{?rhel} ++# 1.15.1-7: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561) ++%global krb5_version 1.15.1-4 + # Require 4.6.0-4 which brings RC4 for FIPS + trust fixes to priv. separation + %global samba_version 4.6.0-4 + %global selinux_policy_version 3.12.1-153 + %global slapi_nis_version 0.56.0-4 + %else ++# 1.15.1-7: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561) ++%global krb5_version 1.15.1-7 + # Require 4.6.0-4 which brings RC4 for FIPS + trust fixes to priv. separation + %global samba_version 2:4.6.0-4 + %global selinux_policy_version 3.13.1-158.4 +@@ -82,8 +86,7 @@ BuildRequires: openldap-devel + %if 0%{?fedora} > 25 + BuildRequires: krb5-kdb-version = 6.1 + %endif +-# 1.15.1-3: certauth (http://krbdev.mit.edu/rt/Ticket/Display.html?id=8561) +-BuildRequires: krb5-devel >= 1.15.1-3 ++BuildRequires: krb5-devel >= %{krb5_version} + # 1.27.4: xmlrpc_curl_xportparms.gssapi_delegation + BuildRequires: xmlrpc-c-devel >= 1.27.4 + BuildRequires: popt-devel +@@ -263,8 +266,9 @@ Requires: 389-ds-base >= 1.3.5.14 + Requires: openldap-clients > 2.4.35-4 + Requires: nss >= 3.14.3-12.0 + Requires: nss-tools >= 3.14.3-12.0 ++Requires(post): krb5-server >= %{krb5_version} + Requires(post): krb5-server >= %{krb5_base_version}, krb5-server < %{krb5_base_version}.100 +-Requires: krb5-pkinit-openssl ++Requires: krb5-pkinit-openssl >= %{krb5_version} + Requires: cyrus-sasl-gssapi%{?_isa} + Requires: ntp + Requires: httpd >= 2.4.6-31 +@@ -481,7 +485,7 @@ Requires: python2-ipaclient = %{version}-%{release} + Requires: python-ldap + Requires: cyrus-sasl-gssapi%{?_isa} + Requires: ntp +-Requires: krb5-workstation ++Requires: krb5-workstation >= %{krb5_version} + Requires: authconfig + Requires: curl + # NIS domain name config: /usr/lib/systemd/system/*-domainname.service +-- +2.12.2 + diff --git a/SOURCES/0097-Hide-PKI-Client-database-password-in-log-file.patch b/SOURCES/0097-Hide-PKI-Client-database-password-in-log-file.patch new file mode 100644 index 0000000..bb0c79f --- /dev/null +++ b/SOURCES/0097-Hide-PKI-Client-database-password-in-log-file.patch @@ -0,0 +1,70 @@ +From 4106c7dcfc685580eeb0f2074872036cd5faaaae Mon Sep 17 00:00:00 2001 +From: Abhijeet Kasurde +Date: Thu, 27 Apr 2017 16:23:41 +0530 +Subject: [PATCH] Hide PKI Client database password in log file + +This fix masks PKI client database password from showing +in CA/KRA installer log file + +Fixes https://pagure.io/freeipa/issue/6904 + +Signed-off-by: Abhijeet Kasurde +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/cainstance.py | 5 ++++- + ipaserver/install/krainstance.py | 9 ++++++--- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 0672bccf79d7cc6133fdb20f0854366306bfc2e0..84d60bfddc0fb968f31706e54e36557e9543846e 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -610,7 +610,10 @@ class CAInstance(DogtagInstance): + try: + DogtagInstance.spawn_instance( + self, cfg_file, +- nolog_list=(self.dm_password, self.admin_password, pki_pin) ++ nolog_list=(self.dm_password, ++ self.admin_password, ++ pki_pin, ++ self.tmp_agent_pwd) + ) + finally: + os.remove(cfg_file) +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index fc25ac72b0dc593f06a8b070b67b5d54a0ab8bce..c39d6874a9d685f91b5d30ea1954320b8ee0c1ed 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -150,6 +150,7 @@ class KRAInstance(DogtagInstance): + os.chown(cfg_file, pent.pw_uid, pent.pw_gid) + self.tmp_agent_db = tempfile.mkdtemp( + prefix="tmp-", dir=paths.VAR_LIB_IPA) ++ tmp_agent_pwd = ipautil.ipa_generate_password() + + # Create KRA configuration + config = ConfigParser() +@@ -173,8 +174,7 @@ class KRAInstance(DogtagInstance): + + # Client security database + config.set("KRA", "pki_client_database_dir", self.tmp_agent_db) +- config.set("KRA", "pki_client_database_password", +- ipautil.ipa_generate_password()) ++ config.set("KRA", "pki_client_database_password", tmp_agent_pwd) + config.set("KRA", "pki_client_database_purge", "True") + config.set("KRA", "pki_client_pkcs12_password", self.admin_password) + +@@ -283,7 +283,10 @@ class KRAInstance(DogtagInstance): + try: + DogtagInstance.spawn_instance( + self, cfg_file, +- nolog_list=(self.dm_password, self.admin_password, pki_pin) ++ nolog_list=(self.dm_password, ++ self.admin_password, ++ pki_pin, ++ tmp_agent_pwd) + ) + finally: + os.remove(p12_tmpfile_name) +-- +2.12.2 + diff --git a/SOURCES/0097-Secure-permissions-of-Custodia-server.keys.patch b/SOURCES/0097-Secure-permissions-of-Custodia-server.keys.patch deleted file mode 100644 index 6da375e..0000000 --- a/SOURCES/0097-Secure-permissions-of-Custodia-server.keys.patch +++ /dev/null @@ -1,69 +0,0 @@ -From f7d3a49f3cf88b5950b11a19785794348d072c20 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 8 Aug 2016 15:05:52 +0200 -Subject: [PATCH] Secure permissions of Custodia server.keys - -Custodia's server.keys file contain the private RSA keys for encrypting -and signing Custodia messages. The file was created with permission 644 -and is only secured by permission 700 of the directory -/etc/ipa/custodia. The installer and upgrader ensure that the file -has 600. - -https://bugzilla.redhat.com/show_bug.cgi?id=1353936 -https://fedorahosted.org/freeipa/ticket/6056 - -Reviewed-By: Martin Basti ---- - ipapython/secrets/kem.py | 5 ++++- - ipaserver/install/custodiainstance.py | 5 +++++ - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/ipapython/secrets/kem.py b/ipapython/secrets/kem.py -index d45efe8cc4fb63ae9d8c0b2c920fd1f9e5331a9d..fb51e64a678bbdec45d690a5223bd61f84ef770e 100644 ---- a/ipapython/secrets/kem.py -+++ b/ipapython/secrets/kem.py -@@ -1,6 +1,7 @@ - # Copyright (C) 2015 IPA Project Contributors, see COPYING for license - - from __future__ import print_function -+import os - from ipaplatform.paths import paths - from six.moves.configparser import ConfigParser - from ipapython.dn import DN -@@ -143,7 +144,9 @@ class KEMLdap(iSecLdap): - def newServerKeys(path, keyid): - skey = JWK(generate='RSA', use='sig', kid=keyid) - ekey = JWK(generate='RSA', use='enc', kid=keyid) -- with open(path, 'w+') as f: -+ with open(path, 'w') as f: -+ os.fchmod(f.fileno(), 0o600) -+ os.fchown(f.fileno(), 0, 0) - f.write('[%s,%s]' % (skey.export(), ekey.export())) - return [skey.get_op_key('verify'), ekey.get_op_key('encrypt')] - -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index fd30430bbf9c39e7153986999199474cfca60d09..785f86fc159f2d73184ea5bb3c0303cecde153df 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -15,6 +15,7 @@ from jwcrypto.common import json_decode - import functools - import shutil - import os -+import stat - import tempfile - import pwd - -@@ -73,6 +74,10 @@ class CustodiaInstance(SimpleServiceInstance): - if not sysupgrade.get_upgrade_state("custodia", "installed"): - root_logger.info("Custodia service is being configured") - self.create_instance() -+ mode = os.stat(self.server_keys).st_mode -+ if stat.S_IMODE(mode) != 0o600: -+ root_logger.info("Secure server.keys mode") -+ os.chmod(self.server_keys, 0o600) - - def create_replica(self, master_host_name): - suffix = ipautil.realm_to_suffix(self.realm) --- -2.7.4 - diff --git a/SOURCES/0098-Require-httpd-2.4.6-31-with-mod_proxy-Unix-socket-su.patch b/SOURCES/0098-Require-httpd-2.4.6-31-with-mod_proxy-Unix-socket-su.patch deleted file mode 100644 index f8a52c6..0000000 --- a/SOURCES/0098-Require-httpd-2.4.6-31-with-mod_proxy-Unix-socket-su.patch +++ /dev/null @@ -1,45 +0,0 @@ -From eaa631227fa1a89d55c8dbaa236b7c8a1cdf7d9c Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Wed, 24 Aug 2016 12:28:47 +0200 -Subject: [PATCH] Require httpd 2.4.6-31 with mod_proxy Unix socket support - -httpd 2.4.6-6 does not support mod_proxy ProxyPass for Unix sockets. The -feature is provided by 2.4.7 upstream was backported to 2.4.6-31 -(bz1168081). It's required to proxy Custodia. - -https://bugzilla.redhat.com/show_bug.cgi?id=1168081 -https://httpd.apache.org/docs/trunk/mod/mod_proxy.html#proxypass - -https://fedorahosted.org/freeipa/ticket/6251 - -Signed-off-by: Christian Heimes -Reviewed-By: Martin Basti ---- - freeipa.spec.in | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 29b63c9300b73d82aea88dbcf50f2f6ab5f9e9bd..08343d9f2049680185ddd32428b040824d882d66 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -141,7 +141,7 @@ Requires(post): krb5-server >= %{krb5_base_version}, krb5-server < %{krb5_base_v - Requires: krb5-pkinit-openssl - Requires: cyrus-sasl-gssapi%{?_isa} - Requires: ntp --Requires: httpd >= 2.4.6-6 -+Requires: httpd >= 2.4.6-31 - Requires: mod_wsgi - Requires: mod_auth_gssapi >= 1.4.0 - Requires: mod_nss >= 1.0.8-26 -@@ -231,7 +231,7 @@ Summary: Common files used by IPA server - Group: System Environment/Base - BuildArch: noarch - Requires: %{name}-client-common = %{version}-%{release} --Requires: httpd >= 2.4.6-6 -+Requires: httpd >= 2.4.6-31 - Requires: systemd-units >= 38 - Requires: custodia - --- -2.7.4 - diff --git a/SOURCES/0098-Vault-Explicitly-default-to-3DES-CBC.patch b/SOURCES/0098-Vault-Explicitly-default-to-3DES-CBC.patch new file mode 100644 index 0000000..b6cf014 --- /dev/null +++ b/SOURCES/0098-Vault-Explicitly-default-to-3DES-CBC.patch @@ -0,0 +1,50 @@ +From c6b9b76307faa001670bc990fbe88aeb23bad403 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 26 Apr 2017 18:15:40 +0200 +Subject: [PATCH] Vault: Explicitly default to 3DES CBC + +The server-side plugin for IPA Vault relied on the fact that the default +oid for encryption algorithm is 3DES in CBC mode (DES-EDE3-CBC). Dogtag +10.4 has changed the default from 3DES to AES. Pass the correct +algorithm OID to KeyClient.archive_encrypted_data(). + +Closes: https://pagure.io/freeipa/issue/6899 +Signed-off-by: Christian Heimes +Reviewed-By: Fraser Tweedale +--- + ipaserver/plugins/vault.py | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py +index 57e1ed7800063822f87da5a71f0f3a0df4d8dd33..d46aca821d2ec94a38dd7cc930f26038d5d80a90 100644 +--- a/ipaserver/plugins/vault.py ++++ b/ipaserver/plugins/vault.py +@@ -38,6 +38,14 @@ from ipapython.dn import DN + if api.env.in_server: + import pki.account + import pki.key ++ # pylint: disable=no-member ++ try: ++ # pki >= 10.4.0 ++ from pki.crypto import DES_EDE3_CBC_OID ++ except ImportError: ++ DES_EDE3_CBC_OID = pki.key.KeyClient.DES_EDE3_CBC_OID ++ # pylint: enable=no-member ++ + + if six.PY3: + unicode = str +@@ -1059,8 +1067,8 @@ class vault_archive_internal(PKQuery): + pki.key.KeyClient.PASS_PHRASE_TYPE, + wrapped_vault_data, + wrapped_session_key, +- None, +- nonce, ++ algorithm_oid=DES_EDE3_CBC_OID, ++ nonce_iv=nonce, + ) + + kra_account.logout() +-- +2.12.2 + diff --git a/SOURCES/0099-Fix-ipa-server-install-in-pure-IPv6-environment.patch b/SOURCES/0099-Fix-ipa-server-install-in-pure-IPv6-environment.patch deleted file mode 100644 index 1a66f1f..0000000 --- a/SOURCES/0099-Fix-ipa-server-install-in-pure-IPv6-environment.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 2dab553e06ce7b01a285c9d80866a6efa80d254d Mon Sep 17 00:00:00 2001 -From: Tomas Krizek -Date: Fri, 19 Aug 2016 12:16:54 +0200 -Subject: [PATCH] Fix ipa-server-install in pure IPv6 environment - -Installation in pure IPv6 environment failed because pki-tomcat tried to use -IPv4 loopback. Configuring tomcat to use IPv6 loopback instead of IPv4 fixes -this issue. - -https://fedorahosted.org/freeipa/ticket/4291 - -Reviewed-By: Martin Basti ---- - ipaserver/install/cainstance.py | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 070498fe8a394802ea55f848a268e2b6563ec472..e94fec5f6fd898b66dc12407be6e3f671ac3f4de 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -577,6 +577,10 @@ class CAInstance(DogtagInstance): - config.set("CA", "pki_external_ca_cert_chain_path", cert_chain_file.name) - config.set("CA", "pki_external_step_two", "True") - -+ # PKI IPv6 Configuration -+ config.add_section("Tomcat") -+ config.set("Tomcat", "pki_ajp_host", "::1") -+ - # Generate configuration file - with open(cfg_file, "wb") as f: - config.write(f) --- -2.7.4 - diff --git a/SOURCES/0099-separate-function-to-set-ipaConfigString-values-on-s.patch b/SOURCES/0099-separate-function-to-set-ipaConfigString-values-on-s.patch new file mode 100644 index 0000000..2ca4e1b --- /dev/null +++ b/SOURCES/0099-separate-function-to-set-ipaConfigString-values-on-s.patch @@ -0,0 +1,244 @@ +From fd6873ad33493b5f395a92f03d54cd184b90d2a2 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Tue, 25 Apr 2017 18:55:59 +0200 +Subject: [PATCH] separate function to set ipaConfigString values on service + entry + +There is some code duplication regarding setting ipaConfigString values +when: + * LDAP-enabling a service entry + * advertising enabled KDCProxy in LDAP + +We can delegate the common work to a single re-usable function and thus +expose it to future use-cases (like PKINIT advertising). + +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaserver/install/httpinstance.py | 43 +----------- + ipaserver/install/service.py | 135 ++++++++++++++++++++++++++------------ + 2 files changed, 94 insertions(+), 84 deletions(-) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index aeb5c5e450813469e1b6cd374b30cd4aab338537..f0a477e0bf16b03ed8b937279dad88e6e2b3aab6 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -42,7 +42,6 @@ from ipapython.ipa_log_manager import root_logger + import ipapython.errors + from ipaserver.install import sysupgrade + from ipalib import api +-from ipalib import errors + from ipalib.constants import ANON_USER + from ipaplatform.constants import constants + from ipaplatform.tasks import tasks +@@ -451,46 +450,8 @@ class HTTPInstance(service.Service): + + def enable_kdcproxy(self): + """Add ipaConfigString=kdcProxyEnabled to cn=KDC""" +- entry_name = DN(('cn', 'KDC'), ('cn', self.fqdn), ('cn', 'masters'), +- ('cn', 'ipa'), ('cn', 'etc'), self.suffix) +- attr_name = 'kdcProxyEnabled' +- +- try: +- entry = api.Backend.ldap2.get_entry( +- entry_name, ['ipaConfigString']) +- except errors.NotFound: +- pass +- else: +- if any(attr_name.lower() == val.lower() +- for val in entry.get('ipaConfigString', [])): +- root_logger.debug("service KDCPROXY already enabled") +- return +- +- entry.setdefault('ipaConfigString', []).append(attr_name) +- try: +- api.Backend.ldap2.update_entry(entry) +- except errors.EmptyModlist: +- root_logger.debug("service KDCPROXY already enabled") +- return +- except: +- root_logger.debug("failed to enable service KDCPROXY") +- raise +- +- root_logger.debug("service KDCPROXY enabled") +- return +- +- entry = api.Backend.ldap2.make_entry( +- entry_name, +- objectclass=["nsContainer", "ipaConfigObject"], +- cn=['KDC'], +- ipaconfigstring=[attr_name] +- ) +- +- try: +- api.Backend.ldap2.add_entry(entry) +- except errors.DuplicateEntry: +- root_logger.debug("failed to add service KDCPROXY entry") +- raise ++ service.set_service_entry_config( ++ 'KDC', self.fqdn, [u'kdcProxyEnabled'], self.suffix) + + def create_kdcproxy_conf(self): + """Create ipa-kdc-proxy.conf in /etc/ipa/kdcproxy""" +diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py +index 9533a887ca41b8d9f9480ec30b908b213807ca7e..6b5e69ccd08444c591f15eb680b4cbdf5b6f4de1 100644 +--- a/ipaserver/install/service.py ++++ b/ipaserver/install/service.py +@@ -136,6 +136,87 @@ def find_providing_server(svcname, conn, host_name=None, api=api): + return None + + ++def case_insensitive_attr_has_value(attr, value): ++ """ ++ Helper function to find value in an attribute having case-insensitive ++ matching rules ++ ++ :param attr: attribute values ++ :param value: value to find ++ ++ :returns: True if the case-insensitive match succeeds, false otherwise ++ ++ """ ++ if any(value.lower() == val.lower() ++ for val in attr): ++ return True ++ ++ return False ++ ++ ++def set_service_entry_config(name, fqdn, config_values, ++ ldap_suffix='', ++ post_add_config=()): ++ """ ++ Sets the 'ipaConfigString' values on the entry. If the entry is not present ++ already, create a new one with desired 'ipaConfigString' ++ ++ :param name: service entry name ++ :param config_values: configuration values to store ++ :param fqdn: master fqdn ++ :param ldap_suffix: LDAP backend suffix ++ :param post_add_config: additional configuration to add when adding a ++ non-existent entry ++ """ ++ assert isinstance(ldap_suffix, DN) ++ ++ entry_name = DN( ++ ('cn', name), ('cn', fqdn), ('cn', 'masters'), ++ ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) ++ ++ # enable disabled service ++ try: ++ entry = api.Backend.ldap2.get_entry( ++ entry_name, ['ipaConfigString']) ++ except errors.NotFound: ++ pass ++ else: ++ existing_values = entry.get('ipaConnfigString', []) ++ for value in config_values: ++ if case_insensitive_attr_has_value(existing_values, value): ++ root_logger.debug( ++ "service %s: config string %s already set", name, value) ++ ++ entry.setdefault('ipaConfigString', []).append(value) ++ ++ try: ++ api.Backend.ldap2.update_entry(entry) ++ except errors.EmptyModlist: ++ root_logger.debug( ++ "service %s has already enabled config values %s", name, ++ config_values) ++ return ++ except: ++ root_logger.debug("failed to set service %s config values", name) ++ raise ++ ++ root_logger.debug("service %s has all config values set", name) ++ return ++ ++ entry = api.Backend.ldap2.make_entry( ++ entry_name, ++ objectclass=["nsContainer", "ipaConfigObject"], ++ cn=[name], ++ ipaconfigstring=config_values + list(post_add_config), ++ ) ++ ++ try: ++ api.Backend.ldap2.add_entry(entry) ++ except (errors.DuplicateEntry) as e: ++ root_logger.debug("failed to add service entry %s", name) ++ raise e ++ ++ + class Service(object): + def __init__(self, service_name, service_desc=None, sstore=None, + fstore=None, api=api, realm_name=None, +@@ -442,51 +523,19 @@ class Service(object): + + def ldap_enable(self, name, fqdn, dm_password=None, ldap_suffix='', + config=[]): +- assert isinstance(ldap_suffix, DN) +- self.disable() ++ extra_config_opts = [ ++ ' '.join([u'startOrder', unicode(SERVICE_LIST[name][1])]) ++ ] ++ extra_config_opts.extend(config) + +- entry_name = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) +- +- # enable disabled service +- try: +- entry = api.Backend.ldap2.get_entry( +- entry_name, ['ipaConfigString']) +- except errors.NotFound: +- pass +- else: +- if any(u'enabledservice' == val.lower() +- for val in entry.get('ipaConfigString', [])): +- root_logger.debug("service %s startup entry already enabled", name) +- return +- +- entry.setdefault('ipaConfigString', []).append(u'enabledService') +- +- try: +- api.Backend.ldap2.update_entry(entry) +- except errors.EmptyModlist: +- root_logger.debug("service %s startup entry already enabled", name) +- return +- except: +- root_logger.debug("failed to enable service %s startup entry", name) +- raise +- +- root_logger.debug("service %s startup entry enabled", name) +- return +- +- order = SERVICE_LIST[name][1] +- entry = api.Backend.ldap2.make_entry( +- entry_name, +- objectclass=["nsContainer", "ipaConfigObject"], +- cn=[name], +- ipaconfigstring=[ +- "enabledService", "startOrder " + str(order)] + config, +- ) ++ self.disable() + +- try: +- api.Backend.ldap2.add_entry(entry) +- except (errors.DuplicateEntry) as e: +- root_logger.debug("failed to add service %s startup entry", name) +- raise e ++ set_service_entry_config( ++ name, ++ fqdn, ++ [u'enabledService'], ++ ldap_suffix=ldap_suffix, ++ post_add_config=extra_config_opts) + + def ldap_disable(self, name, fqdn, ldap_suffix): + assert isinstance(ldap_suffix, DN) +-- +2.12.2 + diff --git a/SOURCES/0100-Allow-for-configuration-of-all-three-PKINIT-variants.patch b/SOURCES/0100-Allow-for-configuration-of-all-three-PKINIT-variants.patch new file mode 100644 index 0000000..0106656 --- /dev/null +++ b/SOURCES/0100-Allow-for-configuration-of-all-three-PKINIT-variants.patch @@ -0,0 +1,205 @@ +From 152715b8514b1b94e1c353baedff12d24efaacb7 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 31 Mar 2017 15:06:46 +0200 +Subject: [PATCH] Allow for configuration of all three PKINIT variants when + deploying KDC + +The PKINIT setup code now can configure PKINIT using IPA CA signed +certificate, 3rd party certificate and local PKINIT with self-signed +keypair. The local PKINIT is also selected as a fallback mechanism if +the CSR is rejected by CA master or `--no-pkinit` is used. + +http://www.freeipa.org/page/V4/Kerberos_PKINIT +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaserver/install/krbinstance.py | 145 +++++++++++++++++++++++++-------------- + 1 file changed, 93 insertions(+), 52 deletions(-) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 6c105f74c8da2bfd34ace607b13170bc96a8ff1d..80215788cf4031ef82e9ec7e08bde6cfc4390303 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -38,6 +38,7 @@ from ipalib.constants import ANON_USER + from ipalib.install import certmonger + from ipapython.ipa_log_manager import root_logger + from ipapython.dn import DN ++from ipapython.dogtag import KDC_PROFILE + + from ipaserver.install import replication + from ipaserver.install import ldapupdate +@@ -354,61 +355,84 @@ class KrbInstance(service.Service): + remote_ldap.gssapi_bind() + replication.wait_for_entry(remote_ldap, kdc_dn, timeout=60) + +- def setup_pkinit(self): +- if self.pkcs12_info: +- certs.install_pem_from_p12(self.pkcs12_info[0], +- self.pkcs12_info[1], +- paths.KDC_CERT) +- certs.install_key_from_p12(self.pkcs12_info[0], +- self.pkcs12_info[1], +- paths.KDC_KEY) +- else: +- subject = str(DN(('cn', self.fqdn), self.subject_base)) +- krbtgt = "krbtgt/" + self.realm + "@" + self.realm +- certpath = (paths.KDC_CERT, paths.KDC_KEY) ++ def _call_certmonger(self, certmonger_ca='IPA'): ++ subject = str(DN(('cn', self.fqdn), self.subject_base)) ++ krbtgt = "krbtgt/" + self.realm + "@" + self.realm ++ certpath = (paths.KDC_CERT, paths.KDC_KEY) + +- try: +- prev_helper = None +- if self.master_fqdn is None: +- ca_args = [ +- paths.CERTMONGER_DOGTAG_SUBMIT, +- '--ee-url', 'https://%s:8443/ca/ee/ca' % self.fqdn, +- '--certfile', paths.RA_AGENT_PEM, +- '--keyfile', paths.RA_AGENT_KEY, +- '--cafile', paths.IPA_CA_CRT, +- '--agent-submit' +- ] +- helper = " ".join(ca_args) +- prev_helper = certmonger.modify_ca_helper('IPA', helper) +- else: +- self._wait_for_replica_kdc_entry() +- +- certmonger.request_and_wait_for_cert( +- certpath, +- subject, +- krbtgt, +- dns=self.fqdn, +- storage='FILE', +- profile='KDCs_PKINIT_Certs') +- except dbus.DBusException as e: +- # if the certificate is already tracked, ignore the error +- name = e.get_dbus_name() +- if name != 'org.fedorahosted.certmonger.duplicate': +- root_logger.error("Failed to initiate the request: %s", e) +- return +- finally: +- if prev_helper is not None: +- certmonger.modify_ca_helper('IPA', prev_helper) +- +- # Finally copy the cacert in the krb directory so we don't +- # have any selinux issues with the file context ++ try: ++ prev_helper = None ++ # on the first CA-ful master without '--no-pkinit', we issue the ++ # certificate by contacting Dogtag directly ++ use_dogtag_submit = all( ++ [self.master_fqdn is None, ++ self.pkcs12_info is None, ++ self.config_pkinit]) ++ ++ if use_dogtag_submit: ++ ca_args = [ ++ paths.CERTMONGER_DOGTAG_SUBMIT, ++ '--ee-url', 'https://%s:8443/ca/ee/ca' % self.fqdn, ++ '--certfile', paths.RA_AGENT_PEM, ++ '--keyfile', paths.RA_AGENT_KEY, ++ '--cafile', paths.IPA_CA_CRT, ++ '--agent-submit' ++ ] ++ helper = " ".join(ca_args) ++ prev_helper = certmonger.modify_ca_helper(certmonger_ca, helper) ++ ++ certmonger.request_and_wait_for_cert( ++ certpath, ++ subject, ++ krbtgt, ++ ca=certmonger_ca, ++ dns=self.fqdn, ++ storage='FILE', ++ profile=KDC_PROFILE) ++ except dbus.DBusException as e: ++ # if the certificate is already tracked, ignore the error ++ name = e.get_dbus_name() ++ if name != 'org.fedorahosted.certmonger.duplicate': ++ root_logger.error("Failed to initiate the request: %s", e) ++ return ++ finally: ++ if prev_helper is not None: ++ certmonger.modify_ca_helper(certmonger_ca, prev_helper) ++ ++ def issue_selfsigned_pkinit_certs(self): ++ self._call_certmonger(certmonger_ca="SelfSign") ++ # for self-signed certificate, the certificate is its own CA, copy it ++ # as CA cert ++ shutil.copyfile(paths.KDC_CERT, paths.CACERT_PEM) ++ ++ def issue_ipa_ca_signed_pkinit_certs(self): ++ try: ++ self._call_certmonger() ++ # copy IPA CA bundle to the KDC's CA cert bundle ++ shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM) ++ except RuntimeError as e: ++ root_logger.error("PKINIT certificate request failed: %s", e) ++ root_logger.error("Failed to configure PKINIT") ++ self.stop_tracking_certs() ++ self.issue_selfsigned_pkinit_certs() ++ ++ def install_external_pkinit_certs(self): ++ certs.install_pem_from_p12(self.pkcs12_info[0], ++ self.pkcs12_info[1], ++ paths.KDC_CERT) ++ certs.install_key_from_p12(self.pkcs12_info[0], ++ self.pkcs12_info[1], ++ paths.KDC_KEY) ++ # copy IPA CA bundle to the KDC's CA cert bundle ++ # NOTE: this may not be the same set of CA certificates trusted by ++ # externally provided PKINIT cert. + shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM) + +- try: +- self.restart() +- except Exception: +- root_logger.critical("krb5kdc service failed to restart") +- raise ++ def setup_pkinit(self): ++ if self.pkcs12_info: ++ self.install_external_pkinit_certs() ++ elif self.config_pkinit: ++ self.issue_ipa_ca_signed_pkinit_certs() + + def test_anonymous_pkinit(self): + with ipautil.private_ccache() as anon_ccache: +@@ -418,6 +442,15 @@ class KrbInstance(service.Service): + raise RuntimeError("Failed to configure anonymous PKINIT") + + def enable_ssl(self): ++ """ ++ generate PKINIT certificate for KDC. If `--no-pkinit` was specified, ++ only configure local self-signed KDC certificate for use as a FAST ++ channel generator for WebUI. Do not advertise the installation steps in ++ this case. ++ """ ++ if self.master_fqdn is not None: ++ self._wait_for_replica_kdc_entry() ++ + if self.config_pkinit: + self.steps = [] + self.step("installing X509 Certificate for PKINIT", +@@ -425,6 +458,14 @@ class KrbInstance(service.Service): + self.step("testing anonymous PKINIT", self.test_anonymous_pkinit) + + self.start_creation() ++ else: ++ self.issue_selfsigned_pkinit_certs() ++ ++ try: ++ self.restart() ++ except Exception: ++ root_logger.critical("krb5kdc service failed to restart") ++ raise + + def get_anonymous_principal_name(self): + return "%s@%s" % (ANON_USER, self.realm) +-- +2.12.2 + diff --git a/SOURCES/0100-support-multiple-uid-values-in-schema-compatibility-.patch b/SOURCES/0100-support-multiple-uid-values-in-schema-compatibility-.patch deleted file mode 100644 index 58433e2..0000000 --- a/SOURCES/0100-support-multiple-uid-values-in-schema-compatibility-.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 485e70f9ca0e7352b17839b2375092f7a886bc81 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 4 Aug 2016 09:58:50 +0300 -Subject: [PATCH] support multiple uid values in schema compatibility tree - -https://fedorahosted.org/freeipa/ticket/6138 - -Reviewed-By: Thierry Bordaz ---- - freeipa.spec.in | 4 +++- - install/updates/10-schema_compat.update | 4 ++++ - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 08343d9f2049680185ddd32428b040824d882d66..7456a9ea77ec289312eb11c05709018b3d6d0c90 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -12,9 +12,11 @@ - %if 0%{?rhel} - %global samba_version 4.0.5-1 - %global selinux_policy_version 3.12.1-153 -+%global slapi_nis_version 0.56.0-4 - %else - %global samba_version 2:4.0.5-1 - %global selinux_policy_version 3.13.1-158.4 -+%global slapi_nis_version 0.56.1 - %endif - - %define krb5_base_version %(LC_ALL=C rpm -q --qf '%%{VERSION}' krb5-devel | grep -Eo '^[^.]+\.[^.]+') -@@ -156,7 +158,7 @@ Requires(pre): systemd-units - Requires(post): systemd-units - Requires: selinux-policy >= %{selinux_policy_version} - Requires(post): selinux-policy-base >= %{selinux_policy_version} --Requires: slapi-nis >= 0.56.0 -+Requires: slapi-nis >= %{slapi_nis_version} - Requires: pki-ca >= 10.3.4 - Requires: pki-kra >= 10.3.4 - Requires(preun): python systemd-units -diff --git a/install/updates/10-schema_compat.update b/install/updates/10-schema_compat.update -index e4c257d323644a93757e01027d3b8ed62c2ca98c..fbe8703407aacd75baf160630c20835a1b4ddc65 100644 ---- a/install/updates/10-schema_compat.update -+++ b/install/updates/10-schema_compat.update -@@ -87,3 +87,7 @@ add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","objectc - add:schema-compat-entry-attribute: %ifeq("ipauniqueid","%{ipauniqueid}","ipaanchoruuid=:IPA:$DOMAIN:%{ipauniqueid}","") - add:schema-compat-entry-attribute: ipaanchoruuid=%{ipaanchoruuid} - add:schema-compat-entry-attribute: %ifeq("ipaanchoruuid","%{ipaanchoruuid}","objectclass=ipaOverrideTarget","") -+ -+dn: cn=users,cn=Schema Compatibility,cn=plugins,cn=config -+add:schema-compat-entry-attribute: uid=%{uid} -+replace:schema-compat-entry-rdn: uid=%{uid}::uid=%first("%{uid}") --- -2.7.4 - diff --git a/SOURCES/0101-API-for-retrieval-of-master-s-PKINIT-status-and-publ.patch b/SOURCES/0101-API-for-retrieval-of-master-s-PKINIT-status-and-publ.patch new file mode 100644 index 0000000..8c7687e --- /dev/null +++ b/SOURCES/0101-API-for-retrieval-of-master-s-PKINIT-status-and-publ.patch @@ -0,0 +1,99 @@ +From a6f958875f3b42a8ea5856b672f5e8416c0aad90 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 31 Mar 2017 14:44:29 +0200 +Subject: [PATCH] API for retrieval of master's PKINIT status and publishing it + in LDAP + +An API was provided to report whether PKINIT is enabled for clients or +not. If yes, the pkinitEnabled value will be added to the +ipaConfigString attribute of master's KDC entry. + +See http://www.freeipa.org/page/V4/Kerberos_PKINIT#Configuration for +more details. + +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaserver/install/krbinstance.py | 41 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 80215788cf4031ef82e9ec7e08bde6cfc4390303..ad3475f95371c9ae17c8b0ac082039c041d5c64c 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -48,6 +48,38 @@ from ipaplatform.constants import constants + from ipaplatform.tasks import tasks + from ipaplatform.paths import paths + ++PKINIT_ENABLED = 'pkinitEnabled' ++ ++ ++def get_pkinit_request_ca(): ++ """ ++ Return the certmonger CA name which is serving the PKINIT certificate ++ request. If the certificate is not tracked by Certmonger, return None ++ """ ++ pkinit_request_id = certmonger.get_request_id( ++ {'cert-file': paths.KDC_CERT}) ++ ++ if pkinit_request_id is None: ++ return ++ ++ return certmonger.get_request_value(pkinit_request_id, 'ca-name') ++ ++ ++def is_pkinit_enabled(): ++ """ ++ check whether PKINIT is enabled on the master by checking for the presence ++ of KDC certificate and it's tracking CA ++ """ ++ ++ if os.path.exists(paths.KDC_CERT): ++ pkinit_request_ca = get_pkinit_request_ca() ++ ++ if pkinit_request_ca != "SelfSign": ++ return True ++ ++ return False ++ ++ + class KpasswdInstance(service.SimpleServiceInstance): + def __init__(self): + service.SimpleServiceInstance.__init__(self, "kadmin") +@@ -399,6 +431,13 @@ class KrbInstance(service.Service): + if prev_helper is not None: + certmonger.modify_ca_helper(certmonger_ca, prev_helper) + ++ def pkinit_enable(self): ++ """ ++ advertise enabled PKINIT feature in master's KDC entry in LDAP ++ """ ++ service.set_service_entry_config( ++ 'KDC', self.fqdn, [PKINIT_ENABLED], self.suffix) ++ + def issue_selfsigned_pkinit_certs(self): + self._call_certmonger(certmonger_ca="SelfSign") + # for self-signed certificate, the certificate is its own CA, copy it +@@ -410,6 +449,7 @@ class KrbInstance(service.Service): + self._call_certmonger() + # copy IPA CA bundle to the KDC's CA cert bundle + shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM) ++ self.pkinit_enable() + except RuntimeError as e: + root_logger.error("PKINIT certificate request failed: %s", e) + root_logger.error("Failed to configure PKINIT") +@@ -427,6 +467,7 @@ class KrbInstance(service.Service): + # NOTE: this may not be the same set of CA certificates trusted by + # externally provided PKINIT cert. + shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM) ++ self.pkinit_enable() + + def setup_pkinit(self): + if self.pkcs12_info: +-- +2.12.2 + diff --git a/SOURCES/0101-custodia-include-known-CA-certs-in-the-PKCS-12-file-.patch b/SOURCES/0101-custodia-include-known-CA-certs-in-the-PKCS-12-file-.patch deleted file mode 100644 index 256e70a..0000000 --- a/SOURCES/0101-custodia-include-known-CA-certs-in-the-PKCS-12-file-.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 70ec9193404463ad62ee6fe14a033425906e6b13 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 23 Aug 2016 10:39:08 +0200 -Subject: [PATCH] custodia: include known CA certs in the PKCS#12 file for - Dogtag - -This fixes CA replica install in a topology upgraded from CA-less to -CA-full. - -https://fedorahosted.org/freeipa/ticket/6207 - -Reviewed-By: Martin Basti ---- - ipaserver/install/custodiainstance.py | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index 785f86fc159f2d73184ea5bb3c0303cecde153df..18bd51426cde09af6a34855a49db386a72cc6b9c 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -2,6 +2,7 @@ - - from ipapython.secrets.kem import IPAKEMKeys - from ipapython.secrets.client import CustodiaClient -+from ipaserver.install.certs import CertDB - from ipaplatform.paths import paths - from ipaplatform.constants import constants - from ipaserver.install.service import SimpleServiceInstance -@@ -154,6 +155,11 @@ class CustodiaInstance(SimpleServiceInstance): - '-i', pk12file, - '-w', pk12pwfile]) - -+ # Add CA certificates -+ tmpdb = CertDB(self.realm, nssdir=tmpnssdir) -+ self.suffix = ipautil.realm_to_suffix(self.realm) -+ self.import_ca_certs(tmpdb, True) -+ - # Now that we gathered all certs, re-export - ipautil.run([paths.PKCS12EXPORT, - '-d', tmpnssdir, --- -2.7.4 - diff --git a/SOURCES/0102-Use-only-anonymous-PKINIT-to-fetch-armor-ccache.patch b/SOURCES/0102-Use-only-anonymous-PKINIT-to-fetch-armor-ccache.patch new file mode 100644 index 0000000..0588dee --- /dev/null +++ b/SOURCES/0102-Use-only-anonymous-PKINIT-to-fetch-armor-ccache.patch @@ -0,0 +1,79 @@ +From 15da0d16e99f5c6956f1ed687cc3cffdade83cb5 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 31 Mar 2017 14:14:11 +0200 +Subject: [PATCH] Use only anonymous PKINIT to fetch armor ccache + +Since the anonymous principal can only use PKINIT to fetch credential +cache it makes no sense to try and use its kerberos key to establish +FAST channel. + +We should also be able to use custom PKINIT anchor for the armoring. + +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipalib/install/kinit.py | 30 +++++++++++++----------------- + 1 file changed, 13 insertions(+), 17 deletions(-) + +diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py +index 1e4d1a82fdefe968db13c3847b9b37b3b3f75d6f..fb6caee4d6b5fef27b53753b21ad83572da31ac4 100644 +--- a/ipalib/install/kinit.py ++++ b/ipalib/install/kinit.py +@@ -7,7 +7,6 @@ import time + + import gssapi + +-from ipalib.constants import ANON_USER + from ipaplatform.paths import paths + from ipapython.ipa_log_manager import root_logger + from ipapython.ipautil import run +@@ -97,29 +96,26 @@ def kinit_password(principal, password, ccache_name, config=None, + raise RuntimeError(result.error_output) + + +-def kinit_armor(ccache_name): ++def kinit_armor(ccache_name, pkinit_anchor=None): + """ +- perform kinit to obtain anonymous ticket to be used as armor for FAST. ++ perform anonymous pkinit to obtain anonymous ticket to be used as armor ++ for FAST. ++ ++ :param ccache_name: location of the armor ccache ++ :param pkinit_anchor: if not None, the location of PKINIT anchor file to ++ use. Otherwise the value from Kerberos client library configuration is ++ used ++ ++ :raises: CalledProcessError if the anonymous PKINIT fails + """ + root_logger.debug("Initializing anonymous ccache") + + env = {'LC_ALL': 'C'} +- # try with the keytab first and then again fallback to try with pkinit in +- # case someone decided it is fun to remove Anonymous keys from the entry +- # or in future pkinit enabled principal enforce the use of pkinit +- try: +- # Gssapi does not understand anonymous cred use kinit command instead +- args = [paths.KINIT, '-k', '-t', paths.ANON_KEYTAB, +- ANON_USER, '-c', ccache_name] +- run(args, env=env, raiseonerr=True, capture_error=True) +- return +- except Exception as e: +- root_logger.debug("Failed to init Anonymous keytab: %s", e, +- exc_info=True) +- +- root_logger.debug("Fallback to slower Anonymous PKINIT") + args = [paths.KINIT, '-n', '-c', ccache_name] + ++ if pkinit_anchor is not None: ++ args.extend(['-X', 'X509_anchors=FILE:{}'.format(pkinit_anchor)]) ++ + # this workaround enables us to capture stderr and put it + # into the raised exception in case of unsuccessful authentication + run(args, env=env, raiseonerr=True, capture_error=True) +-- +2.12.2 + diff --git a/SOURCES/0102-otptoken-permission-Convert-custom-type-parameters-o.patch b/SOURCES/0102-otptoken-permission-Convert-custom-type-parameters-o.patch deleted file mode 100644 index 017a0ef..0000000 --- a/SOURCES/0102-otptoken-permission-Convert-custom-type-parameters-o.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 321bd7bf56109c546a92298d54bcaccfe1289800 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 25 Aug 2016 11:53:39 +0200 -Subject: [PATCH] otptoken, permission: Convert custom type parameters on - server - -Force client to send the value of ipatokenotpkey and ipapermlocation as -entered by user. - -https://fedorahosted.org/freeipa/ticket/6247 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/otptoken.py | 2 ++ - ipaserver/plugins/permission.py | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py -index 39012e2f9106c33c520e19f14331fc440333015a..0b4250043618b4f434d2f8b337b88ee396c312ce 100644 ---- a/ipaserver/plugins/otptoken.py -+++ b/ipaserver/plugins/otptoken.py -@@ -214,6 +214,8 @@ class otptoken(LDAPObject): - doc=_('Token secret (Base32; default: random)'), - default_from=lambda: os.urandom(KEY_LENGTH), - autofill=True, -+ # force server-side conversion -+ normalizer=lambda x: x, - flags=('no_display', 'no_update', 'no_search'), - ), - StrEnum('ipatokenotpalgorithm?', -diff --git a/ipaserver/plugins/permission.py b/ipaserver/plugins/permission.py -index 830773ae7a09f0197da702e4ec31b0b58f1214dd..0c040ce874534dc4716e700493e547df5b97ea99 100644 ---- a/ipaserver/plugins/permission.py -+++ b/ipaserver/plugins/permission.py -@@ -283,6 +283,8 @@ class permission(baseldap.LDAPObject): - cli_name='subtree', - label=_('Subtree'), - doc=_('Subtree to apply permissions to'), -+ # force server-side conversion -+ normalizer=lambda x: x, - flags={'ask_create'}, - ), - Str( --- -2.7.4 - diff --git a/SOURCES/0103-Raise-DuplicatedEnrty-error-when-user-exists-in-dele.patch b/SOURCES/0103-Raise-DuplicatedEnrty-error-when-user-exists-in-dele.patch deleted file mode 100644 index 716b615..0000000 --- a/SOURCES/0103-Raise-DuplicatedEnrty-error-when-user-exists-in-dele.patch +++ /dev/null @@ -1,61 +0,0 @@ -From ef2480e2a9a10665208a6547fe3d3cb1d4047763 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Fri, 19 Aug 2016 10:39:40 +0200 -Subject: [PATCH] Raise DuplicatedEnrty error when user exists in - delete_container - -We do not have right to write to users delete_container. In case that -user already exists in that container and we tried to add entry, we -receive ACIError. This must be checked and DuplicationEntry error must -be raised before. - -https://fedorahosted.org/freeipa/ticket/6199 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/user.py | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index 935ea892cde9e2cb5b21f4714fd93e73c3fa53d5..d690f01ab4d155f6b403790a7215e1777f383604 100644 ---- a/ipaserver/plugins/user.py -+++ b/ipaserver/plugins/user.py -@@ -381,6 +381,10 @@ class user(baseuser): - ), - ) - -+ def get_delete_dn(self, *keys, **options): -+ active_dn = self.get_dn(*keys, **options) -+ return DN(active_dn[0], self.delete_container_dn, api.env.basedn) -+ - def get_either_dn(self, *keys, **options): - ''' - Returns the DN of a user -@@ -397,7 +401,7 @@ class user(baseuser): - dn = active_dn - except errors.NotFound: - # Check that this value is a Delete user -- delete_dn = DN(active_dn[0], self.delete_container_dn, api.env.basedn) -+ delete_dn = self.get_delete_dn(*keys, **options) - try: - ldap.get_entry(delete_dn, ['dn']) - -@@ -441,7 +445,14 @@ class user_add(baseuser_add): - ) - - def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): -- dn = self.obj.get_either_dn(*keys, **options) -+ delete_dn = self.obj.get_delete_dn(*keys, **options) -+ try: -+ ldap.get_entry(delete_dn, ['']) -+ except errors.NotFound: -+ pass -+ else: -+ raise self.obj.handle_duplicate_entry(*keys) -+ - if not options.get('noprivate', False): - try: - # The Managed Entries plugin will allow a user to be created --- -2.7.4 - diff --git a/SOURCES/0103-Stop-requesting-anonymous-keytab-and-purge-all-refer.patch b/SOURCES/0103-Stop-requesting-anonymous-keytab-and-purge-all-refer.patch new file mode 100644 index 0000000..0b0431a --- /dev/null +++ b/SOURCES/0103-Stop-requesting-anonymous-keytab-and-purge-all-refer.patch @@ -0,0 +1,110 @@ +From 2bd0e49b7a7ba98a8ee6872cc7c3e619578c4431 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Wed, 5 Apr 2017 17:29:26 +0200 +Subject: [PATCH] Stop requesting anonymous keytab and purge all references of + it + +anonymous kinit using keytab never worked so we may safely remove all +code that requests/uses it. + +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaplatform/base/paths.py | 1 - + ipaserver/install/httpinstance.py | 17 ----------------- + ipaserver/install/ipa_backup.py | 1 - + ipaserver/install/server/upgrade.py | 1 - + 4 files changed, 20 deletions(-) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index dbdd71ed0b4d69c1101db4aeb7d93152ab8aa730..f80c9e95ab875222887e3692ab80151f84345469 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -50,7 +50,6 @@ class BasePathNamespace(object): + HTTPD_SSL_CONF = "/etc/httpd/conf.d/ssl.conf" + OLD_IPA_KEYTAB = "/etc/httpd/conf/ipa.keytab" + HTTP_KEYTAB = "/var/lib/ipa/gssproxy/http.keytab" +- ANON_KEYTAB = "/var/lib/ipa/api/anon.keytab" + HTTPD_PASSWORD_CONF = "/etc/httpd/conf/password.conf" + IDMAPD_CONF = "/etc/idmapd.conf" + ETC_IPA = "/etc/ipa" +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index f0a477e0bf16b03ed8b937279dad88e6e2b3aab6..7898c53bc02785e2750dba61a5696f079355c9d7 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -30,7 +30,6 @@ import locale + + import six + +-from ipalib.constants import IPAAPI_USER + from ipalib.install import certmonger + from ipaserver.install import service + from ipaserver.install import certs +@@ -42,7 +41,6 @@ from ipapython.ipa_log_manager import root_logger + import ipapython.errors + from ipaserver.install import sysupgrade + from ipalib import api +-from ipalib.constants import ANON_USER + from ipaplatform.constants import constants + from ipaplatform.tasks import tasks + from ipaplatform.paths import paths +@@ -158,7 +156,6 @@ class HTTPInstance(service.Service): + self.step("adding URL rewriting rules", self.__add_include) + self.step("configuring httpd", self.__configure_http) + self.step("setting up httpd keytab", self.request_service_keytab) +- self.step("retrieving anonymous keytab", self.request_anon_keytab) + self.step("configuring Gssproxy", self.configure_gssproxy) + self.step("setting up ssl", self.__setup_ssl) + if self.ca_is_configured: +@@ -304,20 +301,6 @@ class HTTPInstance(service.Service): + if certmonger_stopped: + certmonger.stop() + +- def request_anon_keytab(self): +- parent = os.path.dirname(paths.ANON_KEYTAB) +- if not os.path.exists(parent): +- os.makedirs(parent, 0o755) +- +- self.clean_previous_keytab(keytab=paths.ANON_KEYTAB) +- self.run_getkeytab(self.api.env.ldap_uri, paths.ANON_KEYTAB, ANON_USER) +- +- pent = pwd.getpwnam(IPAAPI_USER) +- os.chmod(parent, 0o700) +- os.chown(parent, pent.pw_uid, pent.pw_gid) +- +- self.set_keytab_owner(keytab=paths.ANON_KEYTAB, owner=IPAAPI_USER) +- + def create_password_conf(self): + """ + This is the format of mod_nss pin files. +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index f71a40bb06545c8d89d1e3fdbc37d5e6e1fe8d58..40f08d7d727a8b97b5996f15d27c1e20788e1473 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -120,7 +120,6 @@ class Backup(admintool.AdminTool): + ) + + files = ( +- paths.ANON_KEYTAB, + paths.NAMED_CONF, + paths.NAMED_KEYTAB, + paths.RESOLV_CONF, +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 927acb011172de926773196eb1d032af8376f3d9..ea2918f5037898b6b8dc601441a439b6150d54e5 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1795,7 +1795,6 @@ def upgrade_configuration(): + KDC_KEY=paths.KDC_KEY, + CACERT_PEM=paths.CACERT_PEM) + krb.add_anonymous_principal() +- http.request_anon_keytab() + setup_pkinit(krb) + + if not ds_running: +-- +2.12.2 + diff --git a/SOURCES/0104-Use-local-anchor-when-armoring-password-requests.patch b/SOURCES/0104-Use-local-anchor-when-armoring-password-requests.patch new file mode 100644 index 0000000..eb161d5 --- /dev/null +++ b/SOURCES/0104-Use-local-anchor-when-armoring-password-requests.patch @@ -0,0 +1,31 @@ +From b5992ea987f6d8d49c988a9ab42463655b3d8e05 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 31 Mar 2017 15:15:50 +0200 +Subject: [PATCH] Use local anchor when armoring password requests + +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaserver/rpcserver.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 77ed7e124c2ca3dcb49d3a68269d6fa9875d4da0..161872450d141a61af4345a20e278db728fe2aac 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -944,7 +944,7 @@ class login_password(Backend, KerberosSession): + self.debug('Obtaining armor in ccache %s', armor_path) + + try: +- kinit_armor(armor_path) ++ kinit_armor(armor_path, pkinit_anchor=paths.CACERT_PEM) + except RuntimeError as e: + self.error("Failed to obtain armor cache") + # We try to continue w/o armor, 2FA will be impacted +-- +2.12.2 + diff --git a/SOURCES/0104-cert-add-missing-param-values-to-cert-find-output.patch b/SOURCES/0104-cert-add-missing-param-values-to-cert-find-output.patch deleted file mode 100644 index f37807b..0000000 --- a/SOURCES/0104-cert-add-missing-param-values-to-cert-find-output.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 7bad2b168b2abbfcd0d81afe7f52342648b75bc4 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 29 Aug 2016 17:49:56 +0200 -Subject: [PATCH] cert: add missing param values to cert-find output - -Add back `serial_number_hex` and `revoked` param values to cert-find output -accidentally removed in commit c718ef058847bb39e78236e8af0ad69ac961bbcf. - -https://fedorahosted.org/freeipa/ticket/6269 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/cert.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 6dd9f6ffcdcd9d051d50d912996fea2104d71dff..a1166a0d0e5b09586832550c055fc6714c3efe26 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1083,7 +1083,8 @@ class cert_find(Search, CertMethod): - obj = ra_obj - obj['issuer'] = issuer - obj['subject'] = DN(ra_obj['subject']) -- del obj['serial_number_hex'] -+ obj['revoked'] = ( -+ ra_obj['status'] in (u'REVOKED', u'REVOKED_EXPIRED')) - - if all: - ra_obj = ra.get_certificate(str(serial_number)) --- -2.7.4 - diff --git a/SOURCES/0105-Upgrade-configure-local-full-PKINIT-depending-on-the.patch b/SOURCES/0105-Upgrade-configure-local-full-PKINIT-depending-on-the.patch new file mode 100644 index 0000000..b679de0 --- /dev/null +++ b/SOURCES/0105-Upgrade-configure-local-full-PKINIT-depending-on-the.patch @@ -0,0 +1,52 @@ +From c40683f85776f401b3e6bb0a3a69a48a206ab633 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 6 Apr 2017 18:52:05 +0200 +Subject: [PATCH] Upgrade: configure local/full PKINIT depending on the master + status + +The upgrader has been modified to configure either local or full PKINIT +depending on the CA status. Additionally, the new PKINIT configuration +will be written to the master's KDC entry. + +https://pagure.io/freeipa/issue/6830 +http://www.freeipa.org/page/V4/Kerberos_PKINIT + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaserver/install/server/upgrade.py | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index ea2918f5037898b6b8dc601441a439b6150d54e5..8da918114066598ec5a74098d85dfef06d22bf86 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1485,14 +1485,17 @@ def add_default_caacl(ca): + def setup_pkinit(krb): + root_logger.info("[Setup PKINIT]") + +- if not api.Command.ca_is_enabled()['result']: +- root_logger.info("CA is not enabled") +- return ++ pkinit_is_enabled = krbinstance.is_pkinit_enabled() ++ ca_is_enabled = api.Command.ca_is_enabled()['result'] + +- if not os.path.exists(paths.KDC_CERT): +- root_logger.info("Requesting PKINIT certificate") +- krb.setup_pkinit() ++ if not pkinit_is_enabled: ++ if ca_is_enabled: ++ krb.issue_ipa_ca_signed_pkinit_certs() ++ else: ++ krb.issue_selfsigned_pkinit_certs() + ++ # reconfigure KDC just in case in order to handle potentially broken ++ # 4.5.0 -> 4.5.1 upgrade path + replacevars = dict() + replacevars['pkinit_identity'] = 'FILE:{},{}'.format( + paths.KDC_CERT,paths.KDC_KEY) +-- +2.12.2 + diff --git a/SOURCES/0105-rpcserver-assume-version-1-for-unversioned-command-c.patch b/SOURCES/0105-rpcserver-assume-version-1-for-unversioned-command-c.patch deleted file mode 100644 index acafde6..0000000 --- a/SOURCES/0105-rpcserver-assume-version-1-for-unversioned-command-c.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 96bb5ecac07255fd4b6149c617c5ef23b7e7c84f Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 29 Aug 2016 14:49:44 +0200 -Subject: [PATCH] rpcserver: assume version 1 for unversioned command calls - -When a command is called on the server over RPC without its version -specified, assume version 1 instead of the highest known version. - -This ensures backward compatibility with old clients, which do not support -versioned commands and understand only the first version of any given -command. - -https://fedorahosted.org/freeipa/ticket/6217 - -Reviewed-By: David Kupka ---- - ipaserver/rpcserver.py | 43 +++++++++++++++++++++++++++---------------- - 1 file changed, 27 insertions(+), 16 deletions(-) - -diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py -index e48dc3498d6ed8feb6ea44a9a678a8b8c50e8d9b..dd446ae849076d350c97ce9cd6c5a704783f39c0 100644 ---- a/ipaserver/rpcserver.py -+++ b/ipaserver/rpcserver.py -@@ -42,7 +42,7 @@ from ipalib import plugable, errors - from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES - from ipalib.frontend import Local - from ipalib.backend import Executioner --from ipalib.errors import (PublicError, InternalError, CommandError, JSONError, -+from ipalib.errors import (PublicError, InternalError, JSONError, - CCacheError, RefererError, InvalidSessionPassword, NotFound, ACIError, - ExecutionError, PasswordExpired, KrbPrincipalExpired, UserLocked) - from ipalib.request import context, destroy_context -@@ -311,6 +311,21 @@ class WSGIExecutioner(Executioner): - if 'wsgi_dispatch' in self.api.Backend: - self.api.Backend.wsgi_dispatch.mount(self, self.key) - -+ def __get_command(self, name): -+ try: -+ # assume version 1 for unversioned command calls -+ command = self.api.Command[name, '1'] -+ except KeyError: -+ try: -+ command = self.api.Command[name] -+ except KeyError: -+ command = None -+ -+ if command is None or isinstance(command, Local): -+ raise errors.CommandError(name=name) -+ -+ return command -+ - def wsgi_execute(self, environ): - result = None - error = None -@@ -319,6 +334,7 @@ class WSGIExecutioner(Executioner): - name = None - args = () - options = {} -+ command = None - - e = None - if not 'HTTP_REFERER' in environ: -@@ -345,11 +361,9 @@ class WSGIExecutioner(Executioner): - (name, args, options, _id) = self.simple_unmarshal(environ) - if name in self._system_commands: - result = self._system_commands[name](self, *args, **options) -- elif (name not in self.api.Command or -- isinstance(self.api.Command[name], Local)): -- raise CommandError(name=name) - else: -- result = self.Command[name](*args, **options) -+ command = self.__get_command(name) -+ result = command(*args, **options) - except PublicError as e: - if self.api.env.debug: - self.debug('WSGI wsgi_execute PublicError: %s', traceback.format_exc()) -@@ -363,9 +377,9 @@ class WSGIExecutioner(Executioner): - os.environ['LANG'] = lang - - principal = getattr(context, 'principal', 'UNKNOWN') -- if name and name in self.Command: -+ if command is not None: - try: -- params = self.Command[name].args_options_2_params(*args, **options) -+ params = command.args_options_2_params(*args, **options) - except Exception as e: - self.info( - 'exception %s caught when converting options: %s', e.__class__.__name__, str(e) -@@ -380,7 +394,7 @@ class WSGIExecutioner(Executioner): - type(self).__name__, - principal, - name, -- ', '.join(self.Command[name]._repr_iter(**params)), -+ ', '.join(command._repr_iter(**params)), - result_string) - else: - self.info('[%s] %s: %s: %s', -@@ -698,24 +712,21 @@ class xmlserver(KerberosWSGIExecutioner): - # TODO - # for now let's not go out of our way to document standard XML-RPC - return u'undef' -- elif (method_name in self.api.Command and -- not isinstance(self.api.Command[method_name], Local)): -+ else: -+ self.__get_command(method_name) -+ - # All IPA commands return a dict (struct), - # and take a params, options - list and dict (array, struct) - return [[u'struct', u'array', u'struct']] -- else: -- raise errors.CommandError(name=method_name) - - def methodHelp(self, *params): - """get method docstring for XML-RPC introspection""" - method_name = self._get_method_name('system.methodHelp', *params) - if method_name in self._system_commands: - return u'' -- elif (method_name in self.api.Command and -- not isinstance(self.api.Command[method_name], Local)): -- return unicode(self.Command[method_name].doc or '') - else: -- raise errors.CommandError(name=method_name) -+ command = self.__get_command(method_name) -+ return unicode(command.doc or '') - - _system_commands = { - 'system.listMethods': listMethods, --- -2.7.4 - diff --git a/SOURCES/0106-Do-not-test-anonymous-PKINIT-after-install-upgrade.patch b/SOURCES/0106-Do-not-test-anonymous-PKINIT-after-install-upgrade.patch new file mode 100644 index 0000000..34a1b07 --- /dev/null +++ b/SOURCES/0106-Do-not-test-anonymous-PKINIT-after-install-upgrade.patch @@ -0,0 +1,62 @@ +From 60412d08baa5a6836e505428a8b9bc73bdce0353 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Tue, 25 Apr 2017 19:12:51 +0200 +Subject: [PATCH] Do not test anonymous PKINIT after install/upgrade + +Local FAST armoring will now work regardless of PKINIT status so there +is no need to explicitly test for working PKINIT. If there is, there +should be a test case for that. + +https://pagure.io/freeipa/issue/6830 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +Reviewed-By: Simo Sorce +--- + ipaserver/install/krbinstance.py | 9 --------- + ipaserver/install/server/upgrade.py | 1 - + 2 files changed, 10 deletions(-) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index ad3475f95371c9ae17c8b0ac082039c041d5c64c..76ac3029ca6d1cbdd85c6ced6272c6f9a21f04a1 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -475,13 +475,6 @@ class KrbInstance(service.Service): + elif self.config_pkinit: + self.issue_ipa_ca_signed_pkinit_certs() + +- def test_anonymous_pkinit(self): +- with ipautil.private_ccache() as anon_ccache: +- try: +- ipautil.run([paths.KINIT, '-n', '-c', anon_ccache]) +- except ipautil.CalledProcessError: +- raise RuntimeError("Failed to configure anonymous PKINIT") +- + def enable_ssl(self): + """ + generate PKINIT certificate for KDC. If `--no-pkinit` was specified, +@@ -496,8 +489,6 @@ class KrbInstance(service.Service): + self.steps = [] + self.step("installing X509 Certificate for PKINIT", + self.setup_pkinit) +- self.step("testing anonymous PKINIT", self.test_anonymous_pkinit) +- + self.start_creation() + else: + self.issue_selfsigned_pkinit_certs() +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 8da918114066598ec5a74098d85dfef06d22bf86..0f27428dd492bb44dd8c69a7e7f47abb531843f5 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1507,7 +1507,6 @@ def setup_pkinit(krb): + if krb.is_running(): + krb.stop() + krb.start() +- krb.test_anonymous_pkinit() + + + def disable_httpd_system_trust(http): +-- +2.12.2 + diff --git a/SOURCES/0106-custodia-force-reconnect-before-retrieving-CA-certs-.patch b/SOURCES/0106-custodia-force-reconnect-before-retrieving-CA-certs-.patch deleted file mode 100644 index c88ceb7..0000000 --- a/SOURCES/0106-custodia-force-reconnect-before-retrieving-CA-certs-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From d5723c202f45edc17c45a7f2a1970eebed259dd5 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 1 Sep 2016 10:32:18 +0200 -Subject: [PATCH] custodia: force reconnect before retrieving CA certs from - LDAP - -Force reconnect to LDAP as DS might have been restarted after the -connection was opened, rendering the connection invalid. - -This fixes a crash in ipa-replica-install with --setup-ca. - -https://fedorahosted.org/freeipa/ticket/6207 - -Reviewed-By: Martin Basti ---- - ipaserver/install/custodiainstance.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py -index 18bd51426cde09af6a34855a49db386a72cc6b9c..32740274ceae17eebeeb32ef5e043cf4b738ee0d 100644 ---- a/ipaserver/install/custodiainstance.py -+++ b/ipaserver/install/custodiainstance.py -@@ -158,6 +158,8 @@ class CustodiaInstance(SimpleServiceInstance): - # Add CA certificates - tmpdb = CertDB(self.realm, nssdir=tmpnssdir) - self.suffix = ipautil.realm_to_suffix(self.realm) -+ if self.admin_conn is not None: -+ self.ldap_disconnect() - self.import_ca_certs(tmpdb, True) - - # Now that we gathered all certs, re-export --- -2.7.4 - diff --git a/SOURCES/0107-rpcserver-fix-crash-in-XML-RPC-system-commands.patch b/SOURCES/0107-rpcserver-fix-crash-in-XML-RPC-system-commands.patch deleted file mode 100644 index 4bd2649..0000000 --- a/SOURCES/0107-rpcserver-fix-crash-in-XML-RPC-system-commands.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 71910b902993cb0b263bc5a6483fcce733820c80 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 1 Sep 2016 09:59:37 +0200 -Subject: [PATCH] rpcserver: fix crash in XML-RPC system commands - -Fix an AttributeError in XML-RPC methodSignature and methodHelp commands -caused by incorrect mangled name usage. - -https://fedorahosted.org/freeipa/ticket/6217 - -Reviewed-By: Lenka Doudova -Reviewed-By: David Kupka ---- - ipaserver/rpcserver.py | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py -index dd446ae849076d350c97ce9cd6c5a704783f39c0..f1d5a40694f015fd7f9ad05836ec55c6906d764e 100644 ---- a/ipaserver/rpcserver.py -+++ b/ipaserver/rpcserver.py -@@ -311,7 +311,7 @@ class WSGIExecutioner(Executioner): - if 'wsgi_dispatch' in self.api.Backend: - self.api.Backend.wsgi_dispatch.mount(self, self.key) - -- def __get_command(self, name): -+ def _get_command(self, name): - try: - # assume version 1 for unversioned command calls - command = self.api.Command[name, '1'] -@@ -362,7 +362,7 @@ class WSGIExecutioner(Executioner): - if name in self._system_commands: - result = self._system_commands[name](self, *args, **options) - else: -- command = self.__get_command(name) -+ command = self._get_command(name) - result = command(*args, **options) - except PublicError as e: - if self.api.env.debug: -@@ -713,7 +713,7 @@ class xmlserver(KerberosWSGIExecutioner): - # for now let's not go out of our way to document standard XML-RPC - return u'undef' - else: -- self.__get_command(method_name) -+ self._get_command(method_name) - - # All IPA commands return a dict (struct), - # and take a params, options - list and dict (array, struct) -@@ -725,7 +725,7 @@ class xmlserver(KerberosWSGIExecutioner): - if method_name in self._system_commands: - return u'' - else: -- command = self.__get_command(method_name) -+ command = self._get_command(method_name) - return unicode(command.doc or '') - - _system_commands = { --- -2.7.4 - diff --git a/SOURCES/0107-vault-piped-input-for-ipa-vault-add-fails.patch b/SOURCES/0107-vault-piped-input-for-ipa-vault-add-fails.patch new file mode 100644 index 0000000..545fb7f --- /dev/null +++ b/SOURCES/0107-vault-piped-input-for-ipa-vault-add-fails.patch @@ -0,0 +1,104 @@ +From a0ea8706fddb0459982c2ae276679cea6b0a812e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 27 Apr 2017 18:20:06 +0200 +Subject: [PATCH] vault: piped input for ipa vault-add fails + +An exception is raised when using echo "Secret123\n" | ipa vault-add myvault + +This happens because the code is using (string).decode(sys.stdin.encoding) +and sys.stdin.encoding is None when the input is read from a pipe. +The fix is using the prompt_password method defined by Backend.textui, +which gracefully handles this issue. + +https://pagure.io/freeipa/issue/6907 + +Reviewed-By: Christian Heimes +Reviewed-By: Abhijeet Kasurde +Reviewed-By: Stanislav Laznicka +--- + ipaclient/plugins/vault.py | 37 ++++++++----------------------------- + 1 file changed, 8 insertions(+), 29 deletions(-) + +diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py +index 3fb4900d9cf90e6902c40e1c3d8cfdafec2e28b8..f21dc4dbb6579c0f92ae9ab94d76a6396b26b233 100644 +--- a/ipaclient/plugins/vault.py ++++ b/ipaclient/plugins/vault.py +@@ -21,11 +21,9 @@ from __future__ import print_function + + import base64 + import errno +-import getpass + import io + import json + import os +-import sys + import tempfile + + from cryptography.fernet import Fernet, InvalidToken +@@ -84,29 +82,6 @@ register = Registry() + MAX_VAULT_DATA_SIZE = 2**20 # = 1 MB + + +-def get_new_password(): +- """ +- Gets new password from user and verify it. +- """ +- while True: +- password = getpass.getpass('New password: ').decode( +- sys.stdin.encoding) +- password2 = getpass.getpass('Verify password: ').decode( +- sys.stdin.encoding) +- +- if password == password2: +- return password +- +- print(' ** Passwords do not match! **') +- +- +-def get_existing_password(): +- """ +- Gets existing password from user. +- """ +- return getpass.getpass('Password: ').decode(sys.stdin.encoding) +- +- + def generate_symmetric_key(password, salt): + """ + Generates symmetric key from password and salt. +@@ -304,7 +279,8 @@ class vault_add(Local): + password = password.rstrip('\n') + + else: +- password = get_new_password() ++ password = self.api.Backend.textui.prompt_password( ++ 'New password') + + # generate vault salt + options['ipavaultsalt'] = os.urandom(16) +@@ -887,9 +863,11 @@ class vault_archive(ModVaultData): + + else: + if override_password: +- password = get_new_password() ++ password = self.api.Backend.textui.prompt_password( ++ 'New password') + else: +- password = get_existing_password() ++ password = self.api.Backend.textui.prompt_password( ++ 'Password', confirm=False) + + if not override_password: + # verify password by retrieving existing data +@@ -1112,7 +1090,8 @@ class vault_retrieve(ModVaultData): + password = password.rstrip('\n') + + else: +- password = get_existing_password() ++ password = self.api.Backend.textui.prompt_password( ++ 'Password', confirm=False) + + # generate encryption key from password + encryption_key = generate_symmetric_key(password, salt) +-- +2.12.2 + diff --git a/SOURCES/0108-automount-install-fix-checking-of-SSSD-functionality.patch b/SOURCES/0108-automount-install-fix-checking-of-SSSD-functionality.patch new file mode 100644 index 0000000..524993f --- /dev/null +++ b/SOURCES/0108-automount-install-fix-checking-of-SSSD-functionality.patch @@ -0,0 +1,83 @@ +From 5a96db72e6bb7597217c5fbbcaa1b29836a9c8c0 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 25 Apr 2017 18:19:21 +0200 +Subject: [PATCH] automount install: fix checking of SSSD functionality on + uninstall + +Change in 2d4d1a9dc0ef2bbe86751768d6e6b009a52c0dc9 no longer initializes +api in `ipa-client-automount --uninstallation` Which caused error in +wait_for_sssd which gets realm from initialized API. + +This patch initializes the API in a way that it doesn't download schema +on uninstallation and on installation it uses host keytab for it so it +no longer requires user's Kerberos credentials. + +Also fix call of xxx_service_class_factory which requires api as param. + +https://pagure.io/freeipa/issue/6861 + +Reviewed-By: Rob Crittenden +Reviewed-By: Tomas Krizek +--- + client/ipa-client-automount | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/client/ipa-client-automount b/client/ipa-client-automount +index 18914bd74932180f300fcbc7b7db0ba1505881bd..2b1d8b9a8ca14d5403635fb20cee37984fe4a101 100755 +--- a/client/ipa-client-automount ++++ b/client/ipa-client-automount +@@ -193,7 +193,7 @@ def configure_autofs_sssd(fstore, statestore, autodiscover, options): + sssdconfig.write(paths.SSSD_CONF) + statestore.backup_state('autofs', 'sssd', True) + +- sssd = services.service('sssd') ++ sssd = services.service('sssd', api) + sssd.restart() + print("Restarting sssd, waiting for it to become available.") + wait_for_sssd() +@@ -281,7 +281,7 @@ def uninstall(fstore, statestore): + break + sssdconfig.save_domain(domain) + sssdconfig.write(paths.SSSD_CONF) +- sssd = services.service('sssd') ++ sssd = services.service('sssd', api) + sssd.restart() + wait_for_sssd() + except Exception as e: +@@ -379,9 +379,6 @@ def main(): + paths.IPACLIENT_INSTALL_LOG, verbose=False, debug=options.debug, + filemode='a', console_format='%(message)s') + +- if options.uninstall: +- return uninstall(fstore, statestore) +- + cfg = dict( + context='cli_installer', + confdir=paths.ETC_IPA, +@@ -390,8 +387,11 @@ def main(): + verbose=0, + ) + ++ # Bootstrap API early so that env object is available + api.bootstrap(**cfg) +- api.finalize() ++ ++ if options.uninstall: ++ return uninstall(fstore, statestore) + + ca_cert_path = None + if os.path.exists(paths.IPA_CA_CRT): +@@ -449,6 +449,10 @@ def main(): + os.environ['KRB5CCNAME'] = ccache_name + except gssapi.exceptions.GSSError as e: + sys.exit("Failed to obtain host TGT: %s" % e) ++ ++ # Finalize API when TGT obtained using host keytab exists ++ api.finalize() ++ + # Now we have a TGT, connect to IPA + try: + api.Backend.rpcclient.connect() +-- +2.12.2 + diff --git a/SOURCES/0108-compat-Save-server-s-API-version-in-for-pre-schema-s.patch b/SOURCES/0108-compat-Save-server-s-API-version-in-for-pre-schema-s.patch deleted file mode 100644 index ea6cd5e..0000000 --- a/SOURCES/0108-compat-Save-server-s-API-version-in-for-pre-schema-s.patch +++ /dev/null @@ -1,346 +0,0 @@ -From b738ea5d78d7c6d7ba9d72c7cd57fe10f0f1b305 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 26 Jul 2016 13:35:22 +0200 -Subject: [PATCH] compat: Save server's API version in for pre-schema servers - -When client comunicates with server that doesn't support 'schema' -command it needs to determine its api version to be able to use the -right compat code. Storing information about server version reduces the -need to call 'env' or 'ping' command only to first time the server is -contacted. - -https://fedorahosted.org/freeipa/ticket/6069 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/__init__.py | 81 ++++++++++++++++++++++++++++++- - ipaclient/remote_plugins/compat.py | 29 +++++++----- - ipaclient/remote_plugins/schema.py | 92 +++--------------------------------- - ipaplatform/base/paths.py | 15 ++++++ - 4 files changed, 116 insertions(+), 101 deletions(-) - -diff --git a/ipaclient/remote_plugins/__init__.py b/ipaclient/remote_plugins/__init__.py -index 6454a4f4ef956a1ef545b82a649ebf26ef6edd7b..2be9222be693a5c4a04a735c216f590d75c1ecfe 100644 ---- a/ipaclient/remote_plugins/__init__.py -+++ b/ipaclient/remote_plugins/__init__.py -@@ -2,9 +2,79 @@ - # Copyright (C) 2016 FreeIPA Contributors see COPYING for license - # - -+import collections -+import errno -+import json -+import os -+ - from . import compat - from . import schema - from ipaclient.plugins.rpcclient import rpcclient -+from ipaplatform.paths import paths -+from ipapython.dnsutil import DNSName -+from ipapython.ipa_log_manager import log_mgr -+ -+logger = log_mgr.get_logger(__name__) -+ -+ -+class ServerInfo(collections.MutableMapping): -+ _DIR = os.path.join(paths.USER_CACHE_PATH, 'ipa', 'servers') -+ -+ def __init__(self, api): -+ hostname = DNSName(api.env.server).ToASCII() -+ self._path = os.path.join(self._DIR, hostname) -+ self._dict = {} -+ self._dirty = False -+ -+ self._read() -+ -+ def __enter__(self): -+ return self -+ -+ def __exit__(self, *_exc_info): -+ self.flush() -+ -+ def flush(self): -+ if self._dirty: -+ self._write() -+ -+ def _read(self): -+ try: -+ with open(self._path, 'r') as sc: -+ self._dict = json.load(sc) -+ except EnvironmentError as e: -+ if e.errno != errno.ENOENT: -+ logger.warning('Failed to read server info: {}'.format(e)) -+ -+ def _write(self): -+ try: -+ try: -+ os.makedirs(self._DIR) -+ except EnvironmentError as e: -+ if e.errno != errno.EEXIST: -+ raise -+ with open(self._path, 'w') as sc: -+ json.dump(self._dict, sc) -+ except EnvironmentError as e: -+ logger.warning('Failed to write server info: {}'.format(e)) -+ -+ def __getitem__(self, key): -+ return self._dict[key] -+ -+ def __setitem__(self, key, value): -+ if key not in self._dict or self._dict[key] != value: -+ self._dirty = True -+ self._dict[key] = value -+ -+ def __delitem__(self, key): -+ del self._dict[key] -+ self._dirty = True -+ -+ def __iter__(self): -+ return iter(self._dict) -+ -+ def __len__(self): -+ return len(self._dict) - - - def get_package(api): -@@ -13,11 +83,18 @@ def get_package(api): - else: - client = rpcclient(api) - client.finalize() -+ -+ try: -+ server_info = api._server_info -+ except AttributeError: -+ server_info = api._server_info = ServerInfo(api) -+ - try: -- plugins = schema.get_package(api, client) -+ plugins = schema.get_package(api, server_info, client) - except schema.NotAvailable: -- plugins = compat.get_package(api, client) -+ plugins = compat.get_package(api, server_info, client) - finally: -+ server_info.flush() - if client.isconnected(): - client.disconnect() - -diff --git a/ipaclient/remote_plugins/compat.py b/ipaclient/remote_plugins/compat.py -index aef5718fcaade157487c0e65562c3bc8a11ad7de..b6d099a075deaaa17143f8ddddfb11d97b75f0ed 100644 ---- a/ipaclient/remote_plugins/compat.py -+++ b/ipaclient/remote_plugins/compat.py -@@ -31,23 +31,26 @@ class CompatObject(Object): - pass - - --def get_package(api, client): -- if not client.isconnected(): -- client.connect(verbose=False) -- -- env = client.forward(u'env', u'api_version', version=u'2.0') -+def get_package(api, server_info, client): - try: -- server_version = env['result']['api_version'] -+ server_version = server_info['version'] - except KeyError: -- ping = client.forward(u'ping', version=u'2.0') -+ if not client.isconnected(): -+ client.connect(verbose=False) -+ env = client.forward(u'env', u'api_version', version=u'2.0') - try: -- match = re.search(u'API version (2\.[0-9]+)', ping['summary']) -+ server_version = env['result']['api_version'] - except KeyError: -- match = None -- if match is not None: -- server_version = match.group(1) -- else: -- server_version = u'2.0' -+ ping = client.forward(u'ping', u'api_version', version=u'2.0') -+ try: -+ match = re.search(u'API version (2\.[0-9]+)', ping['summary']) -+ except KeyError: -+ match = None -+ if match is not None: -+ server_version = match.group(1) -+ else: -+ server_version = u'2.0' -+ server_info['version'] = server_version - server_version = LooseVersion(server_version) - - package_names = {} -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index 8a77a15d489f067ab1312e863178458570403cc6..553da35127188b1ae842a7a0b58433e632c82b9f 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -22,6 +22,7 @@ from ipalib.errors import SchemaUpToDate - from ipalib.frontend import Object - from ipalib.output import Output - from ipalib.parameters import DefaultFrom, Flag, Password, Str -+from ipaplatform.paths import paths - from ipapython.ipautil import fsdecode - from ipapython.dn import DN - from ipapython.dnsutil import DNSName -@@ -59,17 +60,6 @@ _PARAMS = { - 'str': parameters.Str, - } - --USER_CACHE_PATH = ( -- os.environ.get('XDG_CACHE_HOME') or -- os.path.join( -- os.environ.get( -- 'HOME', -- os.path.expanduser('~') -- ), -- '.cache' -- ) --) -- - logger = log_mgr.get_logger(__name__) - - -@@ -348,66 +338,6 @@ class NotAvailable(Exception): - pass - - --class ServerInfo(collections.MutableMapping): -- _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'servers') -- -- def __init__(self, api): -- hostname = DNSName(api.env.server).ToASCII() -- self._path = os.path.join(self._DIR, hostname) -- self._dict = {} -- self._dirty = False -- -- self._read() -- -- def __enter__(self): -- return self -- -- def __exit__(self, *_exc_info): -- self.flush() -- -- def flush(self): -- if self._dirty: -- self._write() -- -- def _read(self): -- try: -- with open(self._path, 'r') as sc: -- self._dict = json.load(sc) -- except EnvironmentError as e: -- if e.errno != errno.ENOENT: -- logger.warning('Failed to read server info: {}'.format(e)) -- -- def _write(self): -- try: -- try: -- os.makedirs(self._DIR) -- except EnvironmentError as e: -- if e.errno != errno.EEXIST: -- raise -- with open(self._path, 'w') as sc: -- json.dump(self._dict, sc) -- except EnvironmentError as e: -- logger.warning('Failed to write server info: {}'.format(e)) -- -- def __getitem__(self, key): -- return self._dict[key] -- -- def __setitem__(self, key, value): -- if key not in self._dict or self._dict[key] != value: -- self._dirty = True -- self._dict[key] = value -- -- def __delitem__(self, key): -- del self._dict[key] -- self._dirty = True -- -- def __iter__(self): -- return iter(self._dict) -- -- def __len__(self): -- return len(self._dict) -- -- - class Schema(object): - """ - Store and provide schema for commands and topics -@@ -429,7 +359,7 @@ class Schema(object): - - """ - namespaces = {'classes', 'commands', 'topics'} -- _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema', FORMAT) -+ _DIR = os.path.join(paths.USER_CACHE_PATH, 'ipa', 'schema', FORMAT) - - def __init__(self, api, server_info, client): - self._dict = {} -@@ -538,8 +468,6 @@ class Schema(object): - self._file.write(f.read()) - - with zipfile.ZipFile(self._file, 'r') as schema: -- self._dict['fingerprint'] = self._fingerprint -- - for name in schema.namelist(): - ns, _slash, key = name.partition('/') - if ns in self.namespaces: -@@ -622,22 +550,14 @@ class Schema(object): - return self._help[namespace][member] - - --def get_package(api, client): -+def get_package(api, server_info, client): - try: - schema = api._schema - except AttributeError: -- try: -- server_info = api._server_info -- except AttributeError: -- server_info = api._server_info = ServerInfo(api) -- -- try: -- schema = Schema(api, server_info, client) -- object.__setattr__(api, '_schema', schema) -- finally: -- server_info.flush() -+ schema = Schema(api, server_info, client) -+ object.__setattr__(api, '_schema', schema) - -- fingerprint = str(schema['fingerprint']) -+ fingerprint = str(server_info['fingerprint']) - package_name = '{}${}'.format(__name__, fingerprint) - package_dir = '{}${}'.format(os.path.splitext(__file__)[0], fingerprint) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index 5ffe689950792a40c179533c8baf2794c2388696..065a2011027bf362abd498d227e24928ccf66724 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -21,6 +21,8 @@ - This base platform module exports default filesystem paths. - ''' - -+import os -+ - - class BasePathNamespace(object): - BASH = "/bin/bash" -@@ -353,4 +355,17 @@ class BasePathNamespace(object): - IPA_CUSTODIA_AUDIT_LOG = '/var/log/ipa-custodia.audit.log' - IPA_GETKEYTAB = '/usr/sbin/ipa-getkeytab' - -+ @property -+ def USER_CACHE_PATH(self): -+ return ( -+ os.environ.get('XDG_CACHE_HOME') or -+ os.path.join( -+ os.environ.get( -+ 'HOME', -+ os.path.expanduser('~') -+ ), -+ '.cache' -+ ) -+ ) -+ - path_namespace = BasePathNamespace --- -2.7.4 - diff --git a/SOURCES/0109-Fix-CA-server-cert-validation-in-FIPS.patch b/SOURCES/0109-Fix-CA-server-cert-validation-in-FIPS.patch new file mode 100644 index 0000000..f10a3a1 --- /dev/null +++ b/SOURCES/0109-Fix-CA-server-cert-validation-in-FIPS.patch @@ -0,0 +1,72 @@ +From 83fe9a4eb7b96d9d02066a73fe1894fb8b797753 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 26 Apr 2017 08:19:27 +0200 +Subject: [PATCH] Fix CA/server cert validation in FIPS + +In FIPS, the NSS library needs to be passed passwords to perform +certificate validation. Should we not have passed it and the NSS +guys have not fixed this yet, we would get SEC_ERROR_BAD_SIGNATURE +which is completely different error than one would expect but +that's just how things are with NSS right now. + +https://pagure.io/freeipa/issue/6897 + +Reviewed-By: Christian Heimes +Reviewed-By: Abhijeet Kasurde +--- + ipapython/certdb.py | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index 0665f944457fb09820eb244c742cb1782e515ad1..ea73ec139df9013b860df447fcffd9038cf7c8f2 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -77,6 +77,11 @@ def find_cert_from_txt(cert, start=0): + return (cert, e) + + ++def get_file_cont(slot, token, filename): ++ with open(filename) as f: ++ return f.read() ++ ++ + class NSSDatabase(object): + """A general-purpose wrapper around a NSS cert database + +@@ -547,12 +552,14 @@ class NSSDatabase(object): + if nss.nss_is_initialized(): + nss.nss_shutdown() + nss.nss_init(self.secdir) ++ nss.set_password_callback(get_file_cont) + try: + certdb = nss.get_default_certdb() + cert = nss.find_cert_from_nickname(nickname) + intended_usage = nss.certificateUsageSSLServer + try: +- approved_usage = cert.verify_now(certdb, True, intended_usage) ++ approved_usage = cert.verify_now(certdb, True, intended_usage, ++ self.pwd_file) + except NSPRError as e: + if e.errno != -8102: + raise ValueError(e.strerror) +@@ -572,6 +579,7 @@ class NSSDatabase(object): + if nss.nss_is_initialized(): + nss.nss_shutdown() + nss.nss_init(self.secdir) ++ nss.set_password_callback(get_file_cont) + try: + certdb = nss.get_default_certdb() + cert = nss.find_cert_from_nickname(nickname) +@@ -586,7 +594,8 @@ class NSSDatabase(object): + raise ValueError("not a CA certificate") + intended_usage = nss.certificateUsageSSLCA + try: +- approved_usage = cert.verify_now(certdb, True, intended_usage) ++ approved_usage = cert.verify_now(certdb, True, intended_usage, ++ self.pwd_file) + except NSPRError as e: + if e.errno != -8102: # SEC_ERROR_INADEQUATE_KEY_USAGE + raise ValueError(e.strerror) +-- +2.12.2 + diff --git a/SOURCES/0109-compat-Fix-ping-command-call.patch b/SOURCES/0109-compat-Fix-ping-command-call.patch deleted file mode 100644 index ac1a53c..0000000 --- a/SOURCES/0109-compat-Fix-ping-command-call.patch +++ /dev/null @@ -1,30 +0,0 @@ -From a13d964ab5b76816a38170f569c3edb4cbe3e06d Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Tue, 16 Aug 2016 16:49:57 +0200 -Subject: [PATCH] compat: Fix ping command call - -Remove extra argument from client.forward call. - -https://fedorahosted.org/freeipa/ticket/6095 - -Reviewed-By: Jan Cholasta ---- - ipaclient/remote_plugins/compat.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaclient/remote_plugins/compat.py b/ipaclient/remote_plugins/compat.py -index b6d099a075deaaa17143f8ddddfb11d97b75f0ed..5e08cb0ed73becbc17e724864d1a853142a5ef6f 100644 ---- a/ipaclient/remote_plugins/compat.py -+++ b/ipaclient/remote_plugins/compat.py -@@ -41,7 +41,7 @@ def get_package(api, server_info, client): - try: - server_version = env['result']['api_version'] - except KeyError: -- ping = client.forward(u'ping', u'api_version', version=u'2.0') -+ ping = client.forward(u'ping', version=u'2.0') - try: - match = re.search(u'API version (2\.[0-9]+)', ping['summary']) - except KeyError: --- -2.7.4 - diff --git a/SOURCES/0110-Fix-man-page-ipa-replica-manage-remove-duplicate-c-o.patch b/SOURCES/0110-Fix-man-page-ipa-replica-manage-remove-duplicate-c-o.patch deleted file mode 100644 index 4afdce0..0000000 --- a/SOURCES/0110-Fix-man-page-ipa-replica-manage-remove-duplicate-c-o.patch +++ /dev/null @@ -1,36 +0,0 @@ -From bce240ec6a80d5d401387d727ea891f7c961c879 Mon Sep 17 00:00:00 2001 -From: Petr Spacek -Date: Mon, 22 Aug 2016 08:33:34 +0200 -Subject: [PATCH] Fix man page ipa-replica-manage: remove duplicate -c option - from --no-lookup - -https://fedorahosted.org/freeipa/ticket/6233 - -Reviewed-By: Martin Basti ---- - install/tools/man/ipa-replica-manage.1 | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1 -index 34cd314a517ae2f74da7bc87d6336e62d7b57118..ed975c92c4453798e6536a75318d5e5065c876a4 100644 ---- a/install/tools/man/ipa-replica-manage.1 -+++ b/install/tools/man/ipa-replica-manage.1 -@@ -109,12 +109,12 @@ Provide additional information - \fB\-f\fR, \fB\-\-force\fR - Ignore some types of errors, don't prompt when deleting a master - .TP --\fB\-c\fR, \fB\-\-no\-lookup\fR --Do not perform DNS lookup checks. --.TP - \fB\-c\fR, \fB\-\-cleanup\fR - When deleting a master with the \-\-force flag, remove leftover references to an already deleted master. - .TP -+\fB\-\-no\-lookup\fR -+Do not perform DNS lookup checks. -+.TP - \fB\-\-binddn\fR=\fIADMIN_DN\fR - Bind DN to use with remote server (default is cn=Directory Manager) \- Be careful to quote this value on the command line - .TP --- -2.7.4 - diff --git a/SOURCES/0110-restore-restart-reload-gssproxy-after-restore.patch b/SOURCES/0110-restore-restart-reload-gssproxy-after-restore.patch new file mode 100644 index 0000000..5905a68 --- /dev/null +++ b/SOURCES/0110-restore-restart-reload-gssproxy-after-restore.patch @@ -0,0 +1,77 @@ +From 5a2424fc07c931be1788bca19726df41f02479e7 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Wed, 26 Apr 2017 18:47:53 +0200 +Subject: [PATCH] restore: restart/reload gssproxy after restore + +So that gssproxy picks up new configuration and therefore related +usages like authentication of CLI against server works + +https://pagure.io/freeipa/issue/6902 + +Reviewed-By: Tomas Krizek +--- + ipaplatform/base/services.py | 21 ++++++++++++++++++--- + ipaserver/install/ipa_restore.py | 3 +++ + 2 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py +index 068b9723cab2773ca2e274e1734723371410675a..fca6298fc07e03ab4ceeba0b51286e33ae168fcc 100644 +--- a/ipaplatform/base/services.py ++++ b/ipaplatform/base/services.py +@@ -154,6 +154,10 @@ class PlatformService(object): + + return + ++ def reload_or_restart(self, instance_name="", capture_output=True, ++ wait=True): ++ return ++ + def restart(self, instance_name="", capture_output=True, wait=True): + return + +@@ -298,14 +302,25 @@ class SystemdService(PlatformService): + instance_name, + update_service_list=update_service_list) + +- def restart(self, instance_name="", capture_output=True, wait=True): +- ipautil.run([paths.SYSTEMCTL, "restart", +- self.service_instance(instance_name)], ++ def _restart_base(self, instance_name, operation, capture_output=True, ++ wait=False): ++ ++ ipautil.run([paths.SYSTEMCTL, operation, ++ self.service_instance(instance_name)], + skip_output=not capture_output) + + if wait and self.is_running(instance_name): + self.wait_for_open_ports(self.service_instance(instance_name)) + ++ def reload_or_restart(self, instance_name="", capture_output=True, ++ wait=True): ++ self._restart_base(instance_name, "reload-or-restart", ++ capture_output, wait) ++ ++ def restart(self, instance_name="", capture_output=True, wait=True): ++ self._restart_base(instance_name, "restart", ++ capture_output, wait) ++ + def is_running(self, instance_name="", wait=True): + instance = self.service_instance(instance_name, 'is-active') + +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 378c013b6f4a4656768d7a484d2014a0f9eef3c0..96fc493c774f5de4c8149bf477cb66ec4960de4f 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -401,6 +401,9 @@ class Restore(admintool.AdminTool): + services.knownservices.pki_tomcatd.enable() + services.knownservices.pki_tomcatd.disable() + ++ self.log.info('Restarting GSS-proxy') ++ gssproxy = services.service('gssproxy', api) ++ gssproxy.reload_or_restart() + self.log.info('Starting IPA services') + run(['ipactl', 'start']) + self.log.info('Restarting SSSD') +-- +2.12.2 + diff --git a/SOURCES/0111-cert-include-CA-name-in-cert-command-output.patch b/SOURCES/0111-cert-include-CA-name-in-cert-command-output.patch deleted file mode 100644 index 2499a32..0000000 --- a/SOURCES/0111-cert-include-CA-name-in-cert-command-output.patch +++ /dev/null @@ -1,112 +0,0 @@ -From c5fe2ba58e011425d56d5edc7823d575e3366b7d Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 23 Aug 2016 13:59:33 +0200 -Subject: [PATCH] cert: include CA name in cert command output - -Include name of the CA that issued a certificate in cert-request, cert-show -and cert-find. - -This allows the caller to call further commands on the cert without having -to call ca-find to find the name of the CA. - -https://fedorahosted.org/freeipa/ticket/6151 - -Reviewed-By: Martin Basti ---- - ipaserver/plugins/cert.py | 33 ++++++++++++++++++++++++--------- - 1 file changed, 24 insertions(+), 9 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index a1166a0d0e5b09586832550c055fc6714c3efe26..67eaeba33610321bf88143dc4ac06a94887427cd 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -262,6 +262,15 @@ def bind_principal_can_manage_cert(cert): - - class BaseCertObject(Object): - takes_params = ( -+ Str( -+ 'cacn?', -+ cli_name='ca', -+ default=IPA_CA_CN, -+ autofill=True, -+ label=_('Issuing CA'), -+ doc=_('Name of issuing CA'), -+ flags={'no_create', 'no_update', 'no_search'}, -+ ), - Bytes( - 'certificate', validate_certificate, - label=_("Certificate"), -@@ -336,14 +345,7 @@ class BaseCertObject(Object): - - class BaseCertMethod(Method): - def get_options(self): -- yield Str('cacn?', -- cli_name='ca', -- default=IPA_CA_CN, -- autofill=True, -- query=True, -- label=_('Issuing CA'), -- doc=_('Name of issuing CA'), -- ) -+ yield self.obj.params['cacn'].clone(query=True) - - for option in super(BaseCertMethod, self).get_options(): - yield option -@@ -432,7 +434,8 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - # referencing nonexistant CA) and look up authority ID. - # - ca = kw['cacn'] -- ca_id = api.Command.ca_show(ca)['result']['ipacaid'][0] -+ ca_obj = api.Command.ca_show(ca)['result'] -+ ca_id = ca_obj['ipacaid'][0] - - """ - Access control is partially handled by the ACI titled -@@ -623,6 +626,7 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - if not raw: - self.obj._parse(result) - result['request_id'] = int(result['request_id']) -+ result['cacn'] = ca_obj['cn'][0] - - # Success? Then add it to the principal's entry - # (unless the profile tells us not to) -@@ -802,6 +806,7 @@ class cert_show(Retrieve, CertMethod, VirtualCommand): - self.obj._parse(result) - result['revoked'] = ('revocation_reason' in result) - self.obj._fill_owners(result) -+ result['cacn'] = ca_obj['cn'][0] - - return dict(result=result, value=pkey_to_value(serial_number, options)) - -@@ -1072,11 +1077,19 @@ class cert_find(Search, CertMethod): - raise - return result, False, complete - -+ ca_objs = self.api.Command.ca_find()['result'] -+ ca_objs = {DN(ca['ipacasubjectdn'][0]): ca for ca in ca_objs} -+ - ra = self.api.Backend.ra - for ra_obj in ra.find(ra_options): - issuer = DN(ra_obj['issuer']) - serial_number = ra_obj['serial_number'] - -+ try: -+ ca_obj = ca_objs[issuer] -+ except KeyError: -+ continue -+ - if pkey_only: - obj = {'serial_number': serial_number} - else: -@@ -1093,6 +1106,8 @@ class cert_find(Search, CertMethod): - ra_obj['certificate'].replace('\r\n', '')) - self.obj._parse(obj) - -+ obj['cacn'] = ca_obj['cn'][0] -+ - result[issuer, serial_number] = obj - - return result, False, complete --- -2.7.4 - diff --git a/SOURCES/0111-kerberos-session-use-CA-cert-with-full-cert-chain-fo.patch b/SOURCES/0111-kerberos-session-use-CA-cert-with-full-cert-chain-fo.patch new file mode 100644 index 0000000..2b6cf22 --- /dev/null +++ b/SOURCES/0111-kerberos-session-use-CA-cert-with-full-cert-chain-fo.patch @@ -0,0 +1,39 @@ +From 1815435956746814362ddafca4f7a967e8886d90 Mon Sep 17 00:00:00 2001 +From: Petr Vobornik +Date: Tue, 25 Apr 2017 17:19:36 +0200 +Subject: [PATCH] kerberos session: use CA cert with full cert chain for + obtaining cookie + +Http request performed in finalize_kerberos_acquisition doesn't use +CA certificate/certificate store with full certificate chain of IPA server. +So it might happen that in case that IPA is installed with externally signed +CA certificate, the call can fail because of certificate validation +and e.g. prevent session acquisition. + +If it will fail for sure is not known - the use case was not discovered, +but it is faster and safer to fix preemptively. + +https://pagure.io/freeipa/issue/6876 + +Reviewed-By: Martin Basti +--- + ipaserver/rpcserver.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 161872450d141a61af4345a20e278db728fe2aac..996a3d29884ca0180c39841f6986abf9b23ff13a 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -602,7 +602,8 @@ class KerberosSession(HTTP_Status): + try: + target = self.api.env.host + r = requests.get('http://{0}/ipa/session/cookie'.format(target), +- auth=NegotiateAuth(target, ccache_name)) ++ auth=NegotiateAuth(target, ccache_name), ++ verify=paths.IPA_CA_CRT) + session_cookie = r.cookies.get("ipa_session") + if not session_cookie: + raise ValueError('No session cookie found') +-- +2.12.2 + diff --git a/SOURCES/0112-Fix-CA-ACL-Check-on-SubjectAltNames.patch b/SOURCES/0112-Fix-CA-ACL-Check-on-SubjectAltNames.patch deleted file mode 100644 index a5043e2..0000000 --- a/SOURCES/0112-Fix-CA-ACL-Check-on-SubjectAltNames.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 645ddb282a5b75cc17a80c97445cf61806b53cb4 Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Tue, 26 Jul 2016 11:25:27 -0400 -Subject: [PATCH] Fix CA ACL Check on SubjectAltNames - -The code is supposed to check that the SAN name is also authorized to be used -with the specified profile id. -The original principal has already been checked. - -Signed-off-by: Simo Sorce -Reviewed-By: Fraser Tweedale -Reviewed-By: Martin Babinsky ---- - ipaserver/plugins/cert.py | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 67eaeba33610321bf88143dc4ac06a94887427cd..6495bf1491f939a032fad03fe4ef86839c0575ef 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -565,14 +565,18 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - for name_type, name in subjectaltname: - if name_type == pkcs10.SAN_DNSNAME: - name = unicode(name) -+ alt_principal = None - alt_principal_obj = None -- alt_principal_string = unicode(principal) - try: - if principal_type == HOST: -+ alt_principal = kerberos.Principal( -+ (u'host', name), principal.realm) - alt_principal_obj = api.Command['host_show'](name, all=True) - elif principal_type == SERVICE: -+ alt_principal = kerberos.Principal( -+ (principal.service_name, name), principal.realm) - alt_principal_obj = api.Command['service_show']( -- alt_principal_string, all=True) -+ alt_principal, all=True) - elif principal_type == USER: - raise errors.ValidationError( - name='csr', -@@ -592,8 +596,8 @@ class cert_request(Create, BaseCertMethod, VirtualCommand): - raise errors.ACIError(info=_( - "Insufficient privilege to create a certificate " - "with subject alt name '%s'.") % name) -- if alt_principal_string is not None and not bypass_caacl: -- caacl_check(principal_type, principal, ca, profile_id) -+ if alt_principal is not None and not bypass_caacl: -+ caacl_check(principal_type, alt_principal, ca, profile_id) - elif name_type in (pkcs10.SAN_OTHERNAME_KRB5PRINCIPALNAME, - pkcs10.SAN_OTHERNAME_UPN): - if name != principal_string: --- -2.7.4 - diff --git a/SOURCES/0112-ipa-client-install-remove-extra-space-in-pkinit_anch.patch b/SOURCES/0112-ipa-client-install-remove-extra-space-in-pkinit_anch.patch new file mode 100644 index 0000000..05ccb90 --- /dev/null +++ b/SOURCES/0112-ipa-client-install-remove-extra-space-in-pkinit_anch.patch @@ -0,0 +1,34 @@ +From 7066dcf1154f9538e9da6bcbcedb69b973509b3c Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 2 May 2017 10:22:22 +0200 +Subject: [PATCH] ipa-client-install: remove extra space in pkinit_anchors + definition + +ipa-client-install modifies /etc/krb5.conf and defines the following line: + pkinit_anchors = FILE: /etc/ipa/ca.crt + +The extra space between FILE: and /etc/ipa/ca.crt break pkinit. + +https://pagure.io/freeipa/issue/6916 + +Reviewed-By: Alexander Bokovoy +--- + ipaclient/install/client.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 549c9b8199255ec57cde3624d34e98d2a9be8d69..abca692fd61be4a9f35a1398fb2af4b1d9e8689b 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -710,7 +710,7 @@ def configure_krb5_conf( + kropts.append(krbconf.setOption('default_domain', cli_domain)) + + kropts.append( +- krbconf.setOption('pkinit_anchors', 'FILE: %s' % paths.IPA_CA_CRT)) ++ krbconf.setOption('pkinit_anchors', 'FILE:%s' % paths.IPA_CA_CRT)) + ropts = [{ + 'name': cli_realm, + 'type': 'subsection', +-- +2.12.2 + diff --git a/SOURCES/0113-Refresh-Dogtag-RestClient.ca_host-property.patch b/SOURCES/0113-Refresh-Dogtag-RestClient.ca_host-property.patch new file mode 100644 index 0000000..509618f --- /dev/null +++ b/SOURCES/0113-Refresh-Dogtag-RestClient.ca_host-property.patch @@ -0,0 +1,114 @@ +From 103d784865c4ebab9085e8edda34f9cb47d70150 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Thu, 27 Apr 2017 12:51:30 +0200 +Subject: [PATCH] Refresh Dogtag RestClient.ca_host property + +Refresh the ca_host property of the Dogtag's RestClient class when +it's requested as a context manager. + +This solves the problem which would occur on DL0 when installing +CA which needs to perform a set of steps against itself accessing +8443 port. This port should however only be available locally so +trying to connect to remote master would fail. We need to make +sure the right CA host is accessed. + +https://pagure.io/freeipa/issue/6878 + +Reviewed-By: Martin Basti +Reviewed-By: Christian Heimes +--- + ipaserver/install/cainstance.py | 5 ++--- + ipaserver/plugins/dogtag.py | 30 ++++++++++++++++++------------ + 2 files changed, 20 insertions(+), 15 deletions(-) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 84d60bfddc0fb968f31706e54e36557e9543846e..d72feb884964ecf49fe0166cbfeb3cb2c10737fe 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -425,6 +425,8 @@ class CAInstance(DogtagInstance): + self.step("Configure HTTP to proxy connections", + self.http_proxy) + self.step("restarting certificate server", self.restart_instance) ++ self.step("updating IPA configuration", update_ipa_conf) ++ self.step("enabling CA instance", self.__enable_instance) + if not promote: + self.step("migrating certificate profiles to LDAP", + migrate_profiles_to_ldap) +@@ -432,9 +434,6 @@ class CAInstance(DogtagInstance): + import_included_profiles) + self.step("adding default CA ACL", ensure_default_caacl) + self.step("adding 'ipa' CA entry", ensure_ipa_authority_entry) +- self.step("updating IPA configuration", update_ipa_conf) +- +- self.step("enabling CA instance", self.__enable_instance) + + self.step("configuring certmonger renewal for lightweight CAs", + self.__add_lightweight_ca_tracking_requests) +diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py +index 3997531032746a22243a4219250af4172e9ae5b3..bddaab58a546196958811f10bb4d049db4aea524 100644 +--- a/ipaserver/plugins/dogtag.py ++++ b/ipaserver/plugins/dogtag.py +@@ -1202,7 +1202,6 @@ import os + import random + from ipaserver.plugins import rabase + from ipalib.constants import TYPE_ERROR +-from ipalib.util import cachedproperty + from ipalib import _ + from ipaplatform.paths import paths + +@@ -1250,34 +1249,41 @@ class RestClient(Backend): + self.client_keyfile = paths.RA_AGENT_KEY + super(RestClient, self).__init__(api) + ++ self._ca_host = None + # session cookie + self.override_port = None + self.cookie = None + +- @cachedproperty ++ @property + def ca_host(self): + """ +- :return: host +- as str ++ :returns: FQDN of a host hopefully providing a CA service + +- Select our CA host. ++ Select our CA host, cache it for the first time. + """ ++ if self._ca_host is not None: ++ return self._ca_host ++ + ldap2 = self.api.Backend.ldap2 + if host_has_service(api.env.ca_host, ldap2, "CA"): +- return api.env.ca_host +- if api.env.host != api.env.ca_host: ++ object.__setattr__(self, '_ca_host', api.env.ca_host) ++ elif api.env.host != api.env.ca_host: + if host_has_service(api.env.host, ldap2, "CA"): +- return api.env.host +- host = select_any_master(ldap2) +- if host: +- return host ++ object.__setattr__(self, '_ca_host', api.env.host) + else: +- return api.env.ca_host ++ object.__setattr__(self, '_ca_host', select_any_master(ldap2)) ++ if self._ca_host is None: ++ object.__setattr__(self, '_ca_host', api.env.ca_host) ++ return self._ca_host + + def __enter__(self): + """Log into the REST API""" + if self.cookie is not None: + return ++ ++ # Refresh the ca_host property ++ object.__setattr__(self, '_ca_host', None) ++ + status, resp_headers, _resp_body = dogtag.https_request( + self.ca_host, self.override_port or self.env.ca_agent_port, + url='/ca/rest/account/login', +-- +2.12.2 + diff --git a/SOURCES/0113-do-not-use-trusted-forest-name-to-construct-domain-a.patch b/SOURCES/0113-do-not-use-trusted-forest-name-to-construct-domain-a.patch deleted file mode 100644 index be6a22a..0000000 --- a/SOURCES/0113-do-not-use-trusted-forest-name-to-construct-domain-a.patch +++ /dev/null @@ -1,37 +0,0 @@ -From c8f3d08c4b90bf89dd4c180d14ced95c14692ff7 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Wed, 31 Aug 2016 13:59:14 +0200 -Subject: [PATCH] do not use trusted forest name to construct domain admin - principal - -When `trust-add` is supplied AD domain admin name without realm component, the -code appends the uppercased AD forest root domain name to construct the full -principal. This can cause authentication error, however, when external trust -with non-root domain is requested. - -We should instead use the supplied DNS domain name (if valid) as a realm -component. - -https://fedorahosted.org/freeipa/ticket/6277 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/trust.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index b9d9b122a90de62946307b99b44932129eb611e8..8ed96c253e7c7862f60ad668aa6c252038274624 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -319,7 +319,7 @@ def generate_creds(trustinstance, style, **options): - else: - sp = admin_name.split(sep) - if len(sp) == 1: -- sp.append(trustinstance.remote_domain.info['dns_forest'].upper()) -+ sp.append(trustinstance.remote_domain.info['dns_domain'].upper()) - creds = u"{name}%{password}".format(name=sep.join(sp), - password=password) - return creds --- -2.7.4 - diff --git a/SOURCES/0114-Always-fetch-forest-info-from-root-DCs-when-establis.patch b/SOURCES/0114-Always-fetch-forest-info-from-root-DCs-when-establis.patch deleted file mode 100644 index 540d3cc..0000000 --- a/SOURCES/0114-Always-fetch-forest-info-from-root-DCs-when-establis.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 95d17d4e632effc37eda54e77a71cbf2cf2f888c Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 1 Sep 2016 09:30:23 +0200 -Subject: [PATCH] Always fetch forest info from root DCs when establishing - two-way trust - -Prior To Windows Server 2012R2, the `netr_DsRGetForestTrustInformation` calls -performed against non-root forest domain DCs were automatically routed to the -root domain DCs to resolve trust topology information. - -This is no longer the case, so the `dcerpc.fetch_domains` function must -explicitly contact root domain DCs even in the case when an external two-way -trust to non-root domain is requested. - -https://fedorahosted.org/freeipa/ticket/6057 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/trust.py | 29 +++++++++++++++++++++-------- - 1 file changed, 21 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index 8ed96c253e7c7862f60ad668aa6c252038274624..b3cb56c14496c0d56d3f3fedddee8d123f929344 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -770,7 +770,7 @@ sides. - # Bidirectional trust allows us to use cross-realm TGT, so we can - # run the call under original user's credentials - res = fetch_domains_from_trust(self.api, self.trustinstance, -- result['result'], **options) -+ **options) - domains = add_new_domains_from_trust(self.api, self.trustinstance, - result['result'], res, **options) - else: -@@ -1631,8 +1631,21 @@ class trustdomain_del(LDAPDelete): - return result - - --def fetch_domains_from_trust(myapi, trustinstance, trust_entry, **options): -- trust_name = trust_entry['cn'][0] -+def fetch_domains_from_trust(myapi, trustinstance, **options): -+ """ -+ Contact trust forest root DC and fetch trusted forest topology information. -+ -+ :param myapi: API instance -+ :param trustinstance: Initialized instance of `dcerpc.TrustDomainJoins` -+ class -+ :param options: options passed from API command's `execute()` method -+ -+ :returns: dict containing forest domain information and forest-wide UPN -+ suffixes (if any) -+ """ -+ -+ forest_root_name = trustinstance.remote_domain.info['dns_forest'] -+ - # We want to use Kerberos if we have admin credentials even with SMB calls - # as eventually use of NTLMSSP will be deprecated for trusted domain operations - # If admin credentials are missing, 'creds' will be None and fetch_domains -@@ -1640,10 +1653,10 @@ def fetch_domains_from_trust(myapi, trustinstance, trust_entry, **options): - # as well. - creds = generate_creds(trustinstance, style=CRED_STYLE_KERBEROS, **options) - server = options.get('realm_server', None) -- domains = ipaserver.dcerpc.fetch_domains(myapi, -- trustinstance.local_flatname, -- trust_name, creds=creds, -- server=server) -+ domains = ipaserver.dcerpc.fetch_domains( -+ myapi, trustinstance.local_flatname, forest_root_name, creds=creds, -+ server=server) -+ - return domains - - -@@ -1749,7 +1762,7 @@ class trust_fetch_domains(LDAPRetrieve): - 'on the IPA server first' - ) - ) -- res = fetch_domains_from_trust(self.api, trustinstance, trust, **options) -+ res = fetch_domains_from_trust(self.api, trustinstance, **options) - domains = add_new_domains_from_trust(self.api, trustinstance, trust, res, **options) - - if len(domains) > 0: --- -2.7.4 - diff --git a/SOURCES/0114-Remove-the-cachedproperty-class.patch b/SOURCES/0114-Remove-the-cachedproperty-class.patch new file mode 100644 index 0000000..727c632 --- /dev/null +++ b/SOURCES/0114-Remove-the-cachedproperty-class.patch @@ -0,0 +1,71 @@ +From 4fe9684ccd97f0c6cd32d858f681f98fb97162dc Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 28 Apr 2017 09:31:45 +0200 +Subject: [PATCH] Remove the cachedproperty class + +The cachedproperty class was used in one special use-case where it only +caused issues. Let's get rid of it. + +https://pagure.io/freeipa/issue/6878 + +Reviewed-By: Martin Basti +Reviewed-By: Christian Heimes +--- + ipalib/util.py | 34 ---------------------------------- + 1 file changed, 34 deletions(-) + +diff --git a/ipalib/util.py b/ipalib/util.py +index e9d4105775a2c9096b1718a604d31034b44bf0bd..8973a19abf56d1d1c5ba04f6edb4228dd2329e65 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -34,7 +34,6 @@ import dns + import encodings + import sys + import ssl +-from weakref import WeakKeyDictionary + + import netaddr + from dns import resolver, rdatatype +@@ -492,39 +491,6 @@ def remove_sshpubkey_from_output_list_post(context, entries): + delattr(context, 'ipasshpubkey_added') + + +-class cachedproperty(object): +- """ +- A property-like attribute that caches the return value of a method call. +- +- When the attribute is first read, the method is called and its return +- value is saved and returned. On subsequent reads, the saved value is +- returned. +- +- Typical usage: +- class C(object): +- @cachedproperty +- def attr(self): +- return 'value' +- """ +- __slots__ = ('getter', 'store') +- +- def __init__(self, getter): +- self.getter = getter +- self.store = WeakKeyDictionary() +- +- def __get__(self, obj, cls): +- if obj is None: +- return None +- if obj not in self.store: +- self.store[obj] = self.getter(obj) +- return self.store[obj] +- +- def __set__(self, obj, value): +- raise AttributeError("can't set attribute") +- +- def __delete__(self, obj): +- raise AttributeError("can't delete attribute") +- + # regexp matching signed floating point number (group 1) followed by + # optional whitespace followed by time unit, e.g. day, hour (group 7) + time_duration_re = re.compile(r'([-+]?((\d+)|(\d+\.\d+)|(\.\d+)|(\d+\.)))\s*([a-z]+)', re.IGNORECASE) +-- +2.12.2 + diff --git a/SOURCES/0115-factor-out-populate_remote_domain-method-into-module.patch b/SOURCES/0115-factor-out-populate_remote_domain-method-into-module.patch deleted file mode 100644 index 522e57d..0000000 --- a/SOURCES/0115-factor-out-populate_remote_domain-method-into-module.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 9b3a64e24a25a6ebbf7e755ae67c2f0eb2bfdf39 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 1 Sep 2016 18:09:05 +0200 -Subject: [PATCH] factor out `populate_remote_domain` method into module-level - function - -This allows for re-use of this method in cases where the caller can not or -wishes not to instantiate local Samba domain to retrieve information about -remote ones. - -https://fedorahosted.org/freeipa/ticket/6057 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/dcerpc.py | 94 ++++++++++++++++++++++++++++++----------------------- - 1 file changed, 53 insertions(+), 41 deletions(-) - -diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py -index 4d98485e17a9113322b7e38629fc43b593e99fd9..71b8ba6f17bea6b52ae26fe2467de380e5458099 100644 ---- a/ipaserver/dcerpc.py -+++ b/ipaserver/dcerpc.py -@@ -1534,6 +1534,52 @@ def fetch_domains(api, mydomain, trustdomain, creds=None, server=None): - return result - - -+def retrieve_remote_domain(hostname, local_flatname, -+ realm, realm_server=None, -+ realm_admin=None, realm_passwd=None): -+ def get_instance(local_flatname): -+ # Fetch data from foreign domain using password only -+ rd = TrustDomainInstance('') -+ rd.parm.set('workgroup', local_flatname) -+ rd.creds = credentials.Credentials() -+ rd.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS) -+ rd.creds.guess(rd.parm) -+ return rd -+ -+ rd = get_instance(local_flatname) -+ rd.creds.set_anonymous() -+ rd.creds.set_workstation(hostname) -+ if realm_server is None: -+ rd.retrieve_anonymously(realm, discover_srv=True, search_pdc=True) -+ else: -+ 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: -+ names = realm_admin.split('\\') -+ if len(names) > 1: -+ # realm admin is in DOMAIN\user format -+ # strip DOMAIN part as we'll enforce the one discovered -+ realm_admin = names[-1] -+ auth_string = u"%s\%s%%%s" \ -+ % (rd.info['name'], realm_admin, realm_passwd) -+ td = get_instance(local_flatname) -+ td.creds.parse_string(auth_string) -+ td.creds.set_workstation(hostname) -+ if realm_server is None: -+ # we must have rd.info['dns_hostname'] then -+ # as it is part of the anonymous discovery -+ td.retrieve(rd.info['dns_hostname']) -+ else: -+ td.retrieve(realm_server) -+ td.read_only = False -+ return td -+ -+ # Otherwise, use anonymously obtained data -+ return rd -+ -+ - class TrustDomainJoins(object): - def __init__(self, api): - self.api = api -@@ -1565,47 +1611,13 @@ class TrustDomainJoins(object): - - def populate_remote_domain(self, realm, realm_server=None, - realm_admin=None, realm_passwd=None): -- def get_instance(self): -- # Fetch data from foreign domain using password only -- rd = TrustDomainInstance('') -- rd.parm.set('workgroup', self.local_domain.info['name']) -- rd.creds = credentials.Credentials() -- rd.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS) -- rd.creds.guess(rd.parm) -- return rd -- -- rd = get_instance(self) -- rd.creds.set_anonymous() -- rd.creds.set_workstation(self.local_domain.hostname) -- if realm_server is None: -- rd.retrieve_anonymously(realm, discover_srv=True, search_pdc=True) -- else: -- 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: -- names = realm_admin.split('\\') -- if len(names) > 1: -- # realm admin is in DOMAIN\user format -- # strip DOMAIN part as we'll enforce the one discovered -- realm_admin = names[-1] -- auth_string = u"%s\%s%%%s" \ -- % (rd.info['name'], realm_admin, realm_passwd) -- td = get_instance(self) -- td.creds.parse_string(auth_string) -- td.creds.set_workstation(self.local_domain.hostname) -- if realm_server is None: -- # we must have rd.info['dns_hostname'] then -- # as it is part of the anonymous discovery -- td.retrieve(rd.info['dns_hostname']) -- else: -- td.retrieve(realm_server) -- td.read_only = False -- self.remote_domain = td -- return -- # Otherwise, use anonymously obtained data -- self.remote_domain = rd -+ self.remote_domain = retrieve_remote_domain( -+ self.local_domain.hostname, -+ self.local_domain.info['name'], -+ realm, -+ realm_server=realm_server, -+ realm_admin=realm_admin, -+ realm_passwd=realm_passwd) - - def get_realmdomains(self): - """ --- -2.7.4 - diff --git a/SOURCES/0115-ipa-server-install-with-external-CA-fix-pkinit-cert-.patch b/SOURCES/0115-ipa-server-install-with-external-CA-fix-pkinit-cert-.patch new file mode 100644 index 0000000..74bfec8 --- /dev/null +++ b/SOURCES/0115-ipa-server-install-with-external-CA-fix-pkinit-cert-.patch @@ -0,0 +1,62 @@ +From 23030ef4f4faa9bf3ee13d13dedb2e0a21da1f2a Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 3 May 2017 10:21:12 +0200 +Subject: [PATCH] ipa-server-install with external CA: fix pkinit cert issuance + +ipa-server-install with external CA fails to issue pkinit certs. +This happens because the installer calls +krb = krbinstance.KrbInstance(fstore) +then +krb.enable_ssl() +and in this code path self.config_pkinit is set to None, leading to a wrong +code path. + +The fix initializes the required fields of the krbinstance before calling +krb.enable_ssl. + +https://pagure.io/freeipa/issue/6921 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Abhijeet Kasurde +--- + ipaserver/install/krbinstance.py | 8 ++++++++ + ipaserver/install/server/install.py | 4 ++++ + 2 files changed, 12 insertions(+) + +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 76ac3029ca6d1cbdd85c6ced6272c6f9a21f04a1..2f14ff592064d3446f73b31e615b2de88d6d786c 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -108,6 +108,14 @@ class KrbInstance(service.Service): + suffix = ipautil.dn_attribute_property('_suffix') + subject_base = ipautil.dn_attribute_property('_subject_base') + ++ def init_info(self, realm_name, host_name, setup_pkinit=False, ++ subject_base=None): ++ self.fqdn = host_name ++ self.realm = realm_name ++ self.suffix = ipautil.realm_to_suffix(realm_name) ++ self.subject_base = subject_base ++ self.config_pkinit = setup_pkinit ++ + def get_realm_suffix(self): + return DN(('cn', self.realm), ('cn', 'kerberos'), self.suffix) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index b360e0532ce1b9b729be1cc2398cb2b46620901c..0ce60e964cb210708e56fb43a5b70f8e3405caf2 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -768,6 +768,10 @@ def install(installer): + setup_pkinit=not options.no_pkinit, + pkcs12_info=pkinit_pkcs12_info, + subject_base=options.subject_base) ++ else: ++ krb.init_info(realm_name, host_name, ++ setup_pkinit=not options.no_pkinit, ++ subject_base=options.subject_base) + + if setup_ca: + if not options.external_cert_files and options.external_ca: +-- +2.12.2 + diff --git a/SOURCES/0116-Always-fetch-forest-info-from-root-DCs-when-establis.patch b/SOURCES/0116-Always-fetch-forest-info-from-root-DCs-when-establis.patch deleted file mode 100644 index 2defd3e..0000000 --- a/SOURCES/0116-Always-fetch-forest-info-from-root-DCs-when-establis.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 6686a4d8906f283a394eb9991af1ab6b66d5dfd1 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Thu, 1 Sep 2016 18:14:22 +0200 -Subject: [PATCH] Always fetch forest info from root DCs when establishing - one-way trust - -Prior To Windows Server 2012R2, the `netr_DsRGetForestTrustInformation` calls -performed against non-root forest domain DCs were automatically routed to -the root domain DCs to resolve trust topology information. - -This is no longer the case, so the `com.redhat.idm.trust-fetch-domains` oddjob -helper used to establish one-way needs to explicitly contact root domain DCs -even in the case when an external trust to non-root domain is requested. - -https://fedorahosted.org/freeipa/ticket/6057 - -Reviewed-By: Alexander Bokovoy ---- - install/oddjob/com.redhat.idm.trust-fetch-domains | 25 ++++++++++++++++++++++- - 1 file changed, 24 insertions(+), 1 deletion(-) - -diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains -index bffa021cd4f01d31b7271d1ad84420884ce8d99e..32406ac9274f63251180a1e1051e1f1e60f5ecec 100755 ---- a/install/oddjob/com.redhat.idm.trust-fetch-domains -+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains -@@ -40,6 +40,24 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): - pass - - -+def get_forest_root_domain(api_instance, trusted_domain): -+ """ -+ retrieve trusted forest root domain for given domain name -+ -+ :param api_instance: IPA API instance -+ :param trusted_domain: trusted domain name -+ -+ :returns: forest root domain DNS name -+ """ -+ trustconfig_show = api_instance.Command.trustconfig_show -+ flatname = trustconfig_show()['result']['ipantflatname'][0] -+ -+ remote_domain = dcerpc.retrieve_remote_domain( -+ api_instance.env.host, flatname, trusted_domain) -+ -+ return remote_domain.info['dns_forest'] -+ -+ - def parse_options(): - usage = "%prog \n" - parser = config.IPAOptionParser(usage=usage, -@@ -169,7 +187,12 @@ except gssapi.exceptions.GSSError: - # We are done: we have ccache with TDO credentials and can fetch domains - ipa_domain = api.env.domain - os.environ['KRB5CCNAME'] = oneway_ccache_name --domains = dcerpc.fetch_domains(api, ipa_domain, trusted_domain, creds=True) -+ -+# retrieve the forest root domain name and contact it to retrieve trust -+# topology info -+forest_root = get_forest_root_domain(api, trusted_domain) -+ -+domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True) - trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result'] - trust.add_new_domains_from_trust(api, None, trust_domain_object, domains) - --- -2.7.4 - diff --git a/SOURCES/0116-kra-install-update-installation-failure-message.patch b/SOURCES/0116-kra-install-update-installation-failure-message.patch new file mode 100644 index 0000000..086a672 --- /dev/null +++ b/SOURCES/0116-kra-install-update-installation-failure-message.patch @@ -0,0 +1,32 @@ +From 17a0ed476c206cea4e72a262da6392f9c2ad2eff Mon Sep 17 00:00:00 2001 +From: Tomas Krizek +Date: Wed, 3 May 2017 15:29:55 +0200 +Subject: [PATCH] kra install: update installation failure message + +When installation fails, do not advise the user to use the +obsoleted --uninstall option. + +Signed-off-by: Tomas Krizek +Fixes https://pagure.io/freeipa/issue/6923 + +Reviewed-By: Martin Basti +--- + ipaserver/install/ipa_kra_install.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py +index 25766541df53f034a813487321a3ad6a0ae43e57..b06d49c834d0ffa4f2e35c3241a83e42c4c9c337 100644 +--- a/ipaserver/install/ipa_kra_install.py ++++ b/ipaserver/install/ipa_kra_install.py +@@ -103,7 +103,7 @@ class KRAInstaller(KRAInstall): + + FAIL_MESSAGE = ''' + Your system may be partly configured. +- Run ipa-kra-install --uninstall to clean up. ++ If you run into issues, you may have to re-install IPA on this server. + ''' + + def validate_options(self, needs_root=True): +-- +2.12.2 + diff --git a/SOURCES/0117-Make-sure-remote-hosts-have-our-keys.patch b/SOURCES/0117-Make-sure-remote-hosts-have-our-keys.patch new file mode 100644 index 0000000..37fc42f --- /dev/null +++ b/SOURCES/0117-Make-sure-remote-hosts-have-our-keys.patch @@ -0,0 +1,114 @@ +From 948ab2a1f44676769e1e8c9be439606d05672c9b Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Fri, 31 Mar 2017 11:22:45 -0400 +Subject: [PATCH] Make sure remote hosts have our keys + +In complex replication setups a replica may try to obtain CA keys from a +host that is not the master we initially create the keys against. +In this case race conditions may happen due to replication. So we need +to make sure the server we are contacting to get the CA keys has our +keys in LDAP. We do this by waiting to positively fetch our encryption +public key (the last one we create) from the target host LDAP server. + +Fixes: https://pagure.io/freeipa/issue/6838 + +Signed-off-by: Simo Sorce +Reviewed-By: Stanislav Laznicka +Reviewed-By: Christian Heimes +--- + ipaserver/install/custodiainstance.py | 28 +++++++++++++++++++++++++++- + ipaserver/secrets/kem.py | 12 ++++++++++++ + 2 files changed, 39 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py +index 6a613923163bccd1b59e0c3b3672905715a8de7c..390576bc0c0edfb7d8f8895eca9df30079526aa8 100644 +--- a/ipaserver/install/custodiainstance.py ++++ b/ipaserver/install/custodiainstance.py +@@ -1,6 +1,6 @@ + # Copyright (C) 2015 FreeIPa Project Contributors, see 'COPYING' for license. + +-from ipaserver.secrets.kem import IPAKEMKeys ++from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap + from ipaserver.secrets.client import CustodiaClient + from ipaplatform.paths import paths + from ipaplatform.constants import constants +@@ -18,6 +18,7 @@ import shutil + import os + import stat + import tempfile ++import time + import pwd + + +@@ -122,6 +123,27 @@ class CustodiaInstance(SimpleServiceInstance): + cli = self.__CustodiaClient(server=master_host_name) + cli.fetch_key('dm/DMHash') + ++ def __wait_keys(self, host, timeout=300): ++ ldap_uri = 'ldap://%s' % host ++ deadline = int(time.time()) + timeout ++ root_logger.info("Waiting up to {} seconds to see our keys " ++ "appear on host: {}".format(timeout, host)) ++ ++ konn = KEMLdap(ldap_uri) ++ saved_e = None ++ while True: ++ try: ++ return konn.check_host_keys(self.fqdn) ++ except Exception as e: ++ # log only once for the same error ++ if not isinstance(e, type(saved_e)): ++ root_logger.debug( ++ "Transient error getting keys: '{err}'".format(err=e)) ++ saved_e = e ++ if int(time.time()) > deadline: ++ raise RuntimeError("Timed out trying to obtain keys.") ++ time.sleep(1) ++ + def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): + # Fecth all needed certs one by one, then combine them in a single + # p12 file +@@ -129,6 +151,10 @@ class CustodiaInstance(SimpleServiceInstance): + prefix = data['prefix'] + certlist = data['list'] + ++ # Before we attempt to fetch keys from this host, make sure our public ++ # keys have been replicated there. ++ self.__wait_keys(ca_host) ++ + cli = self.__CustodiaClient(server=ca_host) + + # Temporary nssdb +diff --git a/ipaserver/secrets/kem.py b/ipaserver/secrets/kem.py +index 28fb4d31b35fc96c77ddd3f09cb3927efb4000fa..c1991c6b2ae00ed7147b2ec18389e463784b9f98 100644 +--- a/ipaserver/secrets/kem.py ++++ b/ipaserver/secrets/kem.py +@@ -24,6 +24,7 @@ import ldap + + IPA_REL_BASE_DN = 'cn=custodia,cn=ipa,cn=etc' + IPA_KEYS_QUERY = '(&(ipaKeyUsage={usage:s})(memberPrincipal={princ:s}))' ++IPA_CHECK_QUERY = '(cn=enc/{host:s})' + RFC5280_USAGE_MAP = {KEY_USAGE_SIG: 'digitalSignature', + KEY_USAGE_ENC: 'dataEncipherment'} + +@@ -78,6 +79,17 @@ class KEMLdap(iSecLdap): + jwk['use'] = KEY_USAGE_MAP[usage] + return json_encode(jwk) + ++ def check_host_keys(self, host): ++ conn = self.connect() ++ scope = ldap.SCOPE_SUBTREE ++ ++ ldap_filter = self.build_filter(IPA_CHECK_QUERY, {'host': host}) ++ r = conn.search_s(self.keysbase, scope, ldap_filter) ++ if len(r) != 1: ++ raise ValueError("Incorrect number of results (%d) searching for" ++ "public key for %s" % (len(r), host)) ++ return True ++ + def _format_public_key(self, key): + if isinstance(key, str): + jwkey = json_decode(key) +-- +2.12.2 + diff --git a/SOURCES/0117-cli-use-full-name-when-executing-a-command.patch b/SOURCES/0117-cli-use-full-name-when-executing-a-command.patch deleted file mode 100644 index 7bf6ae2..0000000 --- a/SOURCES/0117-cli-use-full-name-when-executing-a-command.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 5139c4ad3a4601d0fc7204b46e2a889d44a79b36 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 5 Sep 2016 10:18:13 +0200 -Subject: [PATCH] cli: use full name when executing a command - -Fixes the CLI not to always call the default version of a command even when -the version was explicitly specified. - -https://fedorahosted.org/freeipa/ticket/6279 - -Reviewed-By: Martin Basti ---- - ipalib/cli.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipalib/cli.py b/ipalib/cli.py -index d89a5320853ecf575c7ba710b2db2e62e1003141..df9e6cfd20fead7fd28667386c359db250e64b20 100644 ---- a/ipalib/cli.py -+++ b/ipalib/cli.py -@@ -1101,7 +1101,7 @@ class cli(backend.Executioner): - cmd = self.get_command(argv) - if cmd is None: - return -- name = cmd.name -+ name = cmd.full_name - kw = self.parse(cmd, argv[1:]) - if not isinstance(cmd, frontend.Local): - self.create_context() --- -2.7.4 - diff --git a/SOURCES/0118-Use-RSA-OAEP-instead-of-RSA-PKCS-1-v1.5.patch b/SOURCES/0118-Use-RSA-OAEP-instead-of-RSA-PKCS-1-v1.5.patch deleted file mode 100644 index 301cfd9..0000000 --- a/SOURCES/0118-Use-RSA-OAEP-instead-of-RSA-PKCS-1-v1.5.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 88b8163fa5f3b4f01dab588c2b08db9258c55be1 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 5 Sep 2016 15:38:48 +0200 -Subject: [PATCH] Use RSA-OAEP instead of RSA PKCS#1 v1.5 - -jwcrypto's RSA1-5 (PKCS#1 v1.5) is vulnerable to padding oracle -side-channel attacks. OAEP (PKCS#1 v2.0) is a safe, more modern -alternative. - -https://fedorahosted.org/freeipa/ticket/6278 - -Signed-off-by: Christian Heimes -Reviewed-By: Martin Basti ---- - ipapython/secrets/client.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipapython/secrets/client.py b/ipapython/secrets/client.py -index 56ed6f7944c46393ed225cde1b5e0bb80fe6bef0..d9cc7d0f5b066dfd8efba480feb5f271ed1ebe83 100644 ---- a/ipapython/secrets/client.py -+++ b/ipapython/secrets/client.py -@@ -86,7 +86,7 @@ class CustodiaClient(object): - url = 'https://%s/ipa/keys/%s' % (self.server, keyname) - - # Prepare signed/encrypted request -- encalg = ('RSA1_5', 'A256CBC-HS512') -+ encalg = ('RSA-OAEP', 'A256CBC-HS512') - request = self.kemcli.make_request(keyname, encalg=encalg) - - # Prepare Authentication header --- -2.7.4 - diff --git a/SOURCES/0118-Use-proper-SELinux-context-with-http.keytab.patch b/SOURCES/0118-Use-proper-SELinux-context-with-http.keytab.patch new file mode 100644 index 0000000..d5c36af --- /dev/null +++ b/SOURCES/0118-Use-proper-SELinux-context-with-http.keytab.patch @@ -0,0 +1,40 @@ +From 488c433c369bfcd13e95d910b500c455a01715b6 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 3 May 2017 13:51:02 +0200 +Subject: [PATCH] Use proper SELinux context with http.keytab + +During upgrade keytab is moved to a new location using "move" operation. +This commit replaces move operation with "copy" and "remove" that +ensures a proper selinux context. + +https://pagure.io/freeipa/issue/6924 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/upgrade.py | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 0f27428dd492bb44dd8c69a7e7f47abb531843f5..4d8fd666dfd4e918103b449d4c31bb7661727115 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1427,7 +1427,15 @@ def update_ipa_httpd_service_conf(http): + def update_http_keytab(http): + root_logger.info('[Moving HTTPD service keytab to gssproxy]') + if os.path.exists(paths.OLD_IPA_KEYTAB): +- shutil.move(paths.OLD_IPA_KEYTAB, http.keytab) ++ # ensure proper SELinux context by using copy operation ++ shutil.copy(paths.OLD_IPA_KEYTAB, http.keytab) ++ try: ++ os.remove(paths.OLD_IPA_KEYTAB) ++ except OSError as e: ++ root_logger.error( ++ 'Cannot remove file %s (%s). Please remove the file manually.', ++ paths.OLD_IPA_KEYTAB, e ++ ) + pent = pwd.getpwnam(http.keytab_user) + os.chown(http.keytab, pent.pw_uid, pent.pw_gid) + +-- +2.12.2 + diff --git a/SOURCES/0119-Fix-ipa-certupdate-for-CA-less-installation.patch b/SOURCES/0119-Fix-ipa-certupdate-for-CA-less-installation.patch deleted file mode 100644 index 31d64a9..0000000 --- a/SOURCES/0119-Fix-ipa-certupdate-for-CA-less-installation.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 0c3b7bd3b51626fc7f29c98087e1d59ea079bcda Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 1 Sep 2016 15:53:38 +0200 -Subject: [PATCH] Fix ipa-certupdate for CA-less installation - -In a CA-less installation, ipa-certupdate fails with the error message: - $ ipa-certupdate - trying https://vm-180.abc.idm.lab.eng.brq.redhat.com/ipa/session/json - Forwarding 'ca_is_enabled' to json server 'https://vm-180.abc.idm.lab.eng.brq.redhat.com/ipa/session/json' - Forwarding 'ca_find/1' to json server 'https://vm-180.abc.idm.lab.eng.brq.redhat.com/ipa/session/json' - CA is not configured - The ipa-certupdate command failed. - -The issue happens because ipa-certupdate tries to call ca_find even on a -CA_less deployment. The fix skips the call to ca_find in this case. - -https://fedorahosted.org/freeipa/ticket/6288 - -Reviewed-By: Tomas Krizek ---- - ipaclient/ipa_certupdate.py | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/ipaclient/ipa_certupdate.py b/ipaclient/ipa_certupdate.py -index e59047a2705eb8ccb98b5213c4c8771f55a29bc5..f340f32bcdca5f5d98177f7aa9af366b67d8dd80 100644 ---- a/ipaclient/ipa_certupdate.py -+++ b/ipaclient/ipa_certupdate.py -@@ -87,9 +87,10 @@ class CertUpdate(admintool.AdminTool): - - # find lightweight CAs (on renewal master only) - lwcas = [] -- for ca_obj in api.Command.ca_find()['result']: -- if IPA_CA_CN not in ca_obj['cn']: -- lwcas.append(ca_obj) -+ if ca_enabled: -+ for ca_obj in api.Command.ca_find()['result']: -+ if IPA_CA_CN not in ca_obj['cn']: -+ lwcas.append(ca_obj) - - api.Backend.rpcclient.disconnect() - finally: --- -2.7.4 - diff --git a/SOURCES/0119-ipa-kra-install-fix-check_host_keys.patch b/SOURCES/0119-ipa-kra-install-fix-check_host_keys.patch new file mode 100644 index 0000000..50522f5 --- /dev/null +++ b/SOURCES/0119-ipa-kra-install-fix-check_host_keys.patch @@ -0,0 +1,47 @@ +From 85cd84580f45c99b6ab49814ead7eb2f259ca444 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 5 May 2017 17:06:09 +0200 +Subject: [PATCH] ipa-kra-install: fix check_host_keys + +ipa-kra-install on a replica checks that the keys are available before +going further to avoid race condition due to replication. The issue is +that the check_host_keys method expects to find exactly one key for +cn=env/host but 2 may exist: one below cn=custodia and one below +cn=dogtag,cn=custodia. +The fix is to check that at least one key exist (not exactly one key). + +https://pagure.io/freeipa/issue/6934 + +Reviewed-By: Martin Basti +--- + ipaserver/secrets/kem.py | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/secrets/kem.py b/ipaserver/secrets/kem.py +index c1991c6b2ae00ed7147b2ec18389e463784b9f98..3363d82fef54c463f498edeb95ddee454b20d31d 100644 +--- a/ipaserver/secrets/kem.py ++++ b/ipaserver/secrets/kem.py +@@ -72,7 +72,7 @@ class KEMLdap(iSecLdap): + 'princ': principal}) + r = conn.search_s(self.keysbase, scope, ldap_filter) + if len(r) != 1: +- raise ValueError("Incorrect number of results (%d) searching for" ++ raise ValueError("Incorrect number of results (%d) searching for " + "public key for %s" % (len(r), principal)) + ipa_public_key = r[0][1]['ipaPublicKey'][0] + jwk = self._parse_public_key(ipa_public_key) +@@ -85,9 +85,8 @@ class KEMLdap(iSecLdap): + + ldap_filter = self.build_filter(IPA_CHECK_QUERY, {'host': host}) + r = conn.search_s(self.keysbase, scope, ldap_filter) +- if len(r) != 1: +- raise ValueError("Incorrect number of results (%d) searching for" +- "public key for %s" % (len(r), host)) ++ if not r: ++ raise ValueError("No public keys were found for %s" % host) + return True + + def _format_public_key(self, key): +-- +2.12.2 + diff --git a/SOURCES/0120-Track-lightweight-CAs-on-replica-installation.patch b/SOURCES/0120-Track-lightweight-CAs-on-replica-installation.patch deleted file mode 100644 index dc2fe2f..0000000 --- a/SOURCES/0120-Track-lightweight-CAs-on-replica-installation.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 01fcae3f99ba3368cb88418e14b6bbbe81bc555d Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Tue, 23 Aug 2016 16:14:30 +1000 -Subject: [PATCH] Track lightweight CAs on replica installation - -Add Certmonger tracking requests for lightweight CAs on replica -installation. As part of this change, extract most of the -lightweight CA tracking code out of ipa-certupdate and into -cainstance. - -Fixes: https://fedorahosted.org/freeipa/ticket/6019 -Reviewed-By: Martin Babinsky ---- - ipaclient/ipa_certupdate.py | 53 ++++++--------------------------- - ipalib/constants.py | 2 ++ - ipaserver/install/cainstance.py | 66 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 77 insertions(+), 44 deletions(-) - -diff --git a/ipaclient/ipa_certupdate.py b/ipaclient/ipa_certupdate.py -index f340f32bcdca5f5d98177f7aa9af366b67d8dd80..4b97b85b83c8b1a130d6db9cdcc7a76fc569af9e 100644 ---- a/ipaclient/ipa_certupdate.py -+++ b/ipaclient/ipa_certupdate.py -@@ -29,10 +29,8 @@ from ipaplatform import services - from ipaplatform.paths import paths - from ipaplatform.tasks import tasks - from ipalib import api, errors, x509, certstore --from ipalib.constants import IPA_CA_CN -+from ipalib.constants import IPA_CA_NICKNAME, RENEWAL_CA_NAME - --IPA_CA_NICKNAME = 'caSigningCert cert-pki-ca' --RENEWAL_CA_NAME = 'dogtag-ipa-ca-renew-agent' - - class CertUpdate(admintool.AdminTool): - command_name = 'ipa-certupdate' -@@ -85,12 +83,7 @@ class CertUpdate(admintool.AdminTool): - certs = certstore.get_ca_certs(ldap, api.env.basedn, - api.env.realm, ca_enabled) - -- # find lightweight CAs (on renewal master only) -- lwcas = [] -- if ca_enabled: -- for ca_obj in api.Command.ca_find()['result']: -- if IPA_CA_CN not in ca_obj['cn']: -- lwcas.append(ca_obj) -+ lwcas = api.Command.ca_find()['result'] - - api.Backend.rpcclient.disconnect() - finally: -@@ -99,8 +92,13 @@ class CertUpdate(admintool.AdminTool): - server_fstore = sysrestore.FileStore(paths.SYSRESTORE) - if server_fstore.has_files(): - self.update_server(certs) -- for entry in lwcas: -- self.server_track_lightweight_ca(entry) -+ try: -+ from ipaserver.install import cainstance -+ cainstance.add_lightweight_ca_tracking_requests( -+ self.log, lwcas) -+ except Exception as e: -+ self.log.exception( -+ "Failed to add lightweight CA tracking requests") - - self.update_client(certs) - -@@ -164,39 +162,6 @@ class CertUpdate(admintool.AdminTool): - - self.update_file(paths.CA_CRT, certs) - -- def server_track_lightweight_ca(self, entry): -- nickname = "{} {}".format(IPA_CA_NICKNAME, entry['ipacaid'][0]) -- criteria = { -- 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, -- 'cert-nickname': nickname, -- 'ca-name': RENEWAL_CA_NAME, -- } -- request_id = certmonger.get_request_id(criteria) -- if request_id is None: -- try: -- certmonger.dogtag_start_tracking( -- secdir=paths.PKI_TOMCAT_ALIAS_DIR, -- pin=certmonger.get_pin('internal'), -- pinfile=None, -- nickname=nickname, -- ca=RENEWAL_CA_NAME, -- pre_command='stop_pkicad', -- post_command='renew_ca_cert "%s"' % nickname, -- ) -- request_id = certmonger.get_request_id(criteria) -- certmonger.modify(request_id, profile='ipaCACertRenewal') -- self.log.debug( -- 'Lightweight CA renewal: ' -- 'added tracking request for "%s"', nickname) -- except RuntimeError as e: -- self.log.error( -- 'Lightweight CA renewal: Certmonger failed to ' -- 'start tracking certificate: %s', e) -- else: -- self.log.debug( -- 'Lightweight CA renewal: ' -- 'already tracking certificate "%s"', nickname) -- - def update_file(self, filename, certs, mode=0o444): - certs = (c[0] for c in certs if c[2] is not False) - try: -diff --git a/ipalib/constants.py b/ipalib/constants.py -index 9b351e260f15211330521453b3ffcd41433a04bb..04515dcd25d066d8f1ab79ae8e8b96e909a1d884 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -274,3 +274,5 @@ CA_SUFFIX_NAME = 'ca' - PKI_GSSAPI_SERVICE_NAME = 'dogtag' - IPA_CA_CN = u'ipa' - IPA_CA_RECORD = "ipa-ca" -+IPA_CA_NICKNAME = 'caSigningCert cert-pki-ca' -+RENEWAL_CA_NAME = 'dogtag-ipa-ca-renew-agent' -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index e94fec5f6fd898b66dc12407be6e3f671ac3f4de..3551887cd8ff8baa5e17f8969c84fb92d7552ef3 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1382,6 +1382,9 @@ class CAInstance(DogtagInstance): - - self.step("enabling CA instance", self.__enable_instance) - -+ self.step("configuring certmonger renewal for lightweight CAs", -+ self.__add_lightweight_ca_tracking_requests) -+ - self.start_creation(runtime=210) - - def setup_lightweight_ca_key_retrieval(self): -@@ -1447,6 +1450,22 @@ class CAInstance(DogtagInstance): - os.chmod(keyfile, 0o600) - os.chown(keyfile, pent.pw_uid, pent.pw_gid) - -+ def __add_lightweight_ca_tracking_requests(self): -+ if not self.admin_conn: -+ self.ldap_connect() -+ -+ try: -+ lwcas = self.admin_conn.get_entries( -+ base_dn=api.env.basedn, -+ filter='(objectclass=ipaca)', -+ attrs_list=['cn', 'ipacaid'], -+ ) -+ add_lightweight_ca_tracking_requests(self.log, lwcas) -+ except errors.NotFound: -+ # shouldn't happen, but don't fail if it does -+ root_logger.warning( -+ "Did not find any lightweight CAs; nothing to track") -+ - - def replica_ca_install_check(config): - if not config.setup_ca: -@@ -2069,6 +2088,53 @@ def ensure_default_caacl(): - api.Backend.ldap2.disconnect() - - -+def add_lightweight_ca_tracking_requests(logger, lwcas): -+ """Add tracking requests for the given lightweight CAs. -+ -+ The entries must have the 'cn' and 'ipacaid' attributes. -+ -+ The IPA CA, if present, is skipped. -+ -+ """ -+ for entry in lwcas: -+ if ipalib.constants.IPA_CA_CN in entry['cn']: -+ continue -+ -+ nickname = "{} {}".format( -+ ipalib.constants.IPA_CA_NICKNAME, -+ entry['ipacaid'][0]) -+ criteria = { -+ 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, -+ 'cert-nickname': nickname, -+ 'ca-name': ipalib.constants.RENEWAL_CA_NAME, -+ } -+ request_id = certmonger.get_request_id(criteria) -+ if request_id is None: -+ try: -+ certmonger.dogtag_start_tracking( -+ secdir=paths.PKI_TOMCAT_ALIAS_DIR, -+ pin=certmonger.get_pin('internal'), -+ pinfile=None, -+ nickname=nickname, -+ ca=ipalib.constants.RENEWAL_CA_NAME, -+ pre_command='stop_pkicad', -+ post_command='renew_ca_cert "%s"' % nickname, -+ ) -+ request_id = certmonger.get_request_id(criteria) -+ certmonger.modify(request_id, profile='ipaCACertRenewal') -+ logger.debug( -+ 'Lightweight CA renewal: ' -+ 'added tracking request for "%s"', nickname) -+ except RuntimeError as e: -+ logger.error( -+ 'Lightweight CA renewal: Certmonger failed to ' -+ 'start tracking certificate: %s', e) -+ else: -+ logger.debug( -+ 'Lightweight CA renewal: ' -+ 'already tracking certificate "%s"', nickname) -+ -+ - def update_ipa_conf(): - """ - Update IPA configuration file to ensure that RA plugins are enabled and --- -2.7.4 - diff --git a/SOURCES/0120-python2-ipalib-add-missing-python-dependency.patch b/SOURCES/0120-python2-ipalib-add-missing-python-dependency.patch new file mode 100644 index 0000000..ef73fef --- /dev/null +++ b/SOURCES/0120-python2-ipalib-add-missing-python-dependency.patch @@ -0,0 +1,30 @@ +From d0df144c6411bc0966dfd475c5d781ac5d44f476 Mon Sep 17 00:00:00 2001 +From: Tomas Krizek +Date: Tue, 2 May 2017 18:32:34 +0200 +Subject: [PATCH] python2-ipalib: add missing python dependency + +Commit dfd560a190cb2ab13f34ed9e21c5fb5c6e793f18 started to use +ssl symbols like ssl.OP_NO_SSLv2 that were introduced in Python 2.7.9. + +Related https://pagure.io/freeipa/issue/6920 + +Reviewed-By: Martin Babinsky +--- + freeipa.spec.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 3b7410b6bda3afc877d928b4df21529ae2faf0aa..1dd550bd39fd14349ede58bde337783aa5c0ea04 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -639,6 +639,7 @@ Requires: python-gssapi >= 1.2.0 + Requires: gnupg + Requires: keyutils + Requires: pyOpenSSL ++Requires: python >= 2.7.9 + Requires: python-nss >= 0.16 + Requires: python-cryptography >= 1.4 + Requires: python-netaddr +-- +2.9.3 + diff --git a/SOURCES/0121-dns-normalize-record-type-read-interactively-in-dnsr.patch b/SOURCES/0121-dns-normalize-record-type-read-interactively-in-dnsr.patch deleted file mode 100644 index f2700cb..0000000 --- a/SOURCES/0121-dns-normalize-record-type-read-interactively-in-dnsr.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 52ad614c1d2c7dedc46ce2420cbd146a623fbd94 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Mon, 5 Sep 2016 09:35:42 +0200 -Subject: [PATCH] dns: normalize record type read interactively in - dnsrecord_add - -When dnsrecord_add is called without options in interactive mode, it -prompts the user to enter a record type. The record type is expected to be -upper case further in the code, which causes non-upper case values not to -work correctly. - -Fix this issue by upper casing the value after it is read. - -https://fedorahosted.org/freeipa/ticket/6203 - -Reviewed-By: Martin Basti ---- - ipaclient/plugins/dns.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipaclient/plugins/dns.py b/ipaclient/plugins/dns.py -index e17c282fab2bf1ede095fe37e5cb240eaea21e35..db9c17f8b523365779e53adfb2acc43f4a23401f 100644 ---- a/ipaclient/plugins/dns.py -+++ b/ipaclient/plugins/dns.py -@@ -175,6 +175,8 @@ class dnsrecord_add(MethodOverride): - if rrtype is None: - return - -+ rrtype = rrtype.upper() -+ - try: - name = record_name_format % rrtype.lower() - param = self.params[name] --- -2.7.4 - diff --git a/SOURCES/0121-installer-service-fix-typo-in-service-entry.patch b/SOURCES/0121-installer-service-fix-typo-in-service-entry.patch new file mode 100644 index 0000000..4bb270e --- /dev/null +++ b/SOURCES/0121-installer-service-fix-typo-in-service-entry.patch @@ -0,0 +1,31 @@ +From b7c0c372c3d78e60f5b2889c88f4f3b4a5abdcad Mon Sep 17 00:00:00 2001 +From: Tomas Krizek +Date: Tue, 2 May 2017 18:42:13 +0200 +Subject: [PATCH] installer service: fix typo in service entry + +The typo would result in incorrect resolution of existing keys and +their existence wasn't properly logged as intended. + +Related https://pagure.io/freeipa/issue/6920 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/service.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py +index 6b5e69ccd08444c591f15eb680b4cbdf5b6f4de1..1aa49ed25b25366afd2bb17073b4b214c231d54b 100644 +--- a/ipaserver/install/service.py ++++ b/ipaserver/install/service.py +@@ -181,7 +181,7 @@ def set_service_entry_config(name, fqdn, config_values, + except errors.NotFound: + pass + else: +- existing_values = entry.get('ipaConnfigString', []) ++ existing_values = entry.get('ipaConfigString', []) + for value in config_values: + if case_insensitive_attr_has_value(existing_values, value): + root_logger.debug( +-- +2.9.3 + diff --git a/SOURCES/0122-dns-prompt-for-missing-record-parts-in-CLI.patch b/SOURCES/0122-dns-prompt-for-missing-record-parts-in-CLI.patch deleted file mode 100644 index f7bcdf2..0000000 --- a/SOURCES/0122-dns-prompt-for-missing-record-parts-in-CLI.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 7563ae6257c56555e502d40bc6fc2e142f850094 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Fri, 2 Sep 2016 16:42:57 +0200 -Subject: [PATCH] dns: prompt for missing record parts in CLI - -Fix the code which determines if a record part is required and thus should -be prompted not to wrongfully consider all record parts to be optional. - -https://fedorahosted.org/freeipa/ticket/6203 - -Reviewed-By: Martin Basti ---- - API.txt | 29 +++++++++++++++++++++++++++++ - VERSION | 4 ++-- - ipaclient/plugins/dns.py | 30 ++++++++++++++++-------------- - ipaserver/plugins/dns.py | 15 +++++++++++++++ - 4 files changed, 62 insertions(+), 16 deletions(-) - -diff --git a/API.txt b/API.txt -index 5b83bfbd0b457b77e0522ab7d83abfae4df3ebe9..fb5bf83cea0633130217cf1327481c8e9b11c4fc 100644 ---- a/API.txt -+++ b/API.txt -@@ -6312,9 +6312,20 @@ default: dns_is_enabled/1 - default: dns_resolve/1 - default: dns_system_records/1 - default: dns_update_system_records/1 -+default: dnsa6record/1 -+default: dnsaaaarecord/1 -+default: dnsafsdbrecord/1 -+default: dnsaplrecord/1 -+default: dnsarecord/1 -+default: dnscertrecord/1 -+default: dnscnamerecord/1 - default: dnsconfig/1 - default: dnsconfig_mod/1 - default: dnsconfig_show/1 -+default: dnsdhcidrecord/1 -+default: dnsdlvrecord/1 -+default: dnsdnamerecord/1 -+default: dnsdsrecord/1 - default: dnsforwardzone/1 - default: dnsforwardzone_add/1 - default: dnsforwardzone_add_permission/1 -@@ -6325,6 +6336,16 @@ default: dnsforwardzone_find/1 - default: dnsforwardzone_mod/1 - default: dnsforwardzone_remove_permission/1 - default: dnsforwardzone_show/1 -+default: dnshiprecord/1 -+default: dnsipseckeyrecord/1 -+default: dnskeyrecord/1 -+default: dnskxrecord/1 -+default: dnslocrecord/1 -+default: dnsmxrecord/1 -+default: dnsnaptrrecord/1 -+default: dnsnsecrecord/1 -+default: dnsnsrecord/1 -+default: dnsptrrecord/1 - default: dnsrecord/1 - default: dnsrecord_add/1 - default: dnsrecord_del/1 -@@ -6333,12 +6354,20 @@ default: dnsrecord_find/1 - default: dnsrecord_mod/1 - default: dnsrecord_show/1 - default: dnsrecord_split_parts/1 -+default: dnsrprecord/1 -+default: dnsrrsigrecord/1 - default: dnsserver/1 - default: dnsserver_add/1 - default: dnsserver_del/1 - default: dnsserver_find/1 - default: dnsserver_mod/1 - default: dnsserver_show/1 -+default: dnssigrecord/1 -+default: dnsspfrecord/1 -+default: dnssrvrecord/1 -+default: dnssshfprecord/1 -+default: dnstlsarecord/1 -+default: dnstxtrecord/1 - default: dnszone/1 - default: dnszone_add/1 - default: dnszone_add_permission/1 -diff --git a/VERSION b/VERSION -index a8b89ed305bcfdf2990a7400d005a68d734fa7e8..796e9fea36b72f3a63372c84b9bfb1538efccfb7 100644 ---- a/VERSION -+++ b/VERSION -@@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 - # # - ######################################################## - IPA_API_VERSION_MAJOR=2 --IPA_API_VERSION_MINOR=212 --# Last change: ab: service: add flag to allow S4U2Self -+IPA_API_VERSION_MINOR=213 -+# Last change: dns: prompt for missing record parts in CLI -diff --git a/ipaclient/plugins/dns.py b/ipaclient/plugins/dns.py -index db9c17f8b523365779e53adfb2acc43f4a23401f..5e29b8c6666f94f52add7f2e1de8679127886fc2 100644 ---- a/ipaclient/plugins/dns.py -+++ b/ipaclient/plugins/dns.py -@@ -25,10 +25,10 @@ import copy - - from ipaclient.frontend import MethodOverride - from ipalib import errors --from ipalib.dns import (get_part_rrtype, -- get_record_rrtype, -+from ipalib.dns import (get_record_rrtype, - has_cli_options, - iterate_rrparams_by_parts, -+ part_name_format, - record_name_format) - from ipalib.parameters import Bool - from ipalib.plugable import Registry -@@ -46,9 +46,9 @@ _rev_top_record_types = ('PTR', ) - _zone_top_record_types = ('NS', 'MX', 'LOC', ) - - --def __get_part_param(cmd, part, output_kw, default=None): -- name = part.name -- label = unicode(part.label) -+def __get_part_param(rrtype, cmd, part, output_kw, default=None): -+ name = part_name_format % (rrtype.lower(), part.name) -+ label = unicode(cmd.params[name].label) - optional = not part.required - - output_kw[name] = cmd.prompt_param(part, -@@ -64,29 +64,31 @@ def prompt_parts(rrtype, cmd, mod_dnsvalue=None): - name, mod_dnsvalue)['result'] - - user_options = {} -- parts = [p for p in cmd.params() if get_part_rrtype(p.name) == rrtype] -- if not parts: -+ try: -+ rrobj = cmd.api.Object['dns{}record'.format(rrtype.lower())] -+ except KeyError: - return user_options - -- for part_id, part in enumerate(parts): -+ for part_id, part in enumerate(rrobj.params()): - if mod_parts: - default = mod_parts[part_id] - else: - default = None - -- __get_part_param(cmd, part, user_options, default) -+ __get_part_param(rrtype, cmd, part, user_options, default) - - return user_options - - - def prompt_missing_parts(rrtype, cmd, kw, prompt_optional=False): - user_options = {} -- parts = [p for p in cmd.params() if get_part_rrtype(p.name) == rrtype] -- if not parts: -+ try: -+ rrobj = cmd.api.Object['dns{}record'.format(rrtype.lower())] -+ except KeyError: - return user_options - -- for part in parts: -- name = part.name -+ for part in rrobj.params(): -+ name = part_name_format % (rrtype.lower(), part.name) - - if name in kw: - continue -@@ -96,7 +98,7 @@ def prompt_missing_parts(rrtype, cmd, kw, prompt_optional=False): - continue - - default = part.get_default(**kw) -- __get_part_param(cmd, part, user_options, default) -+ __get_part_param(rrtype, cmd, part, user_options, default) - - return user_options - -diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py -index 6f1bd716d202bd85dfc46b5eb94f73e85683b917..f048351e649fe0e8e2893627946333b14c11018a 100644 ---- a/ipaserver/plugins/dns.py -+++ b/ipaserver/plugins/dns.py -@@ -3471,6 +3471,21 @@ class dnsrecord(LDAPObject): - ) - - -+# Make DNS record types available as objects in the API. -+# This is used by the CLI to get otherwise unavailable attributes of record -+# parts. -+for param in _dns_records: -+ register()( -+ type( -+ 'dns{}record'.format(param.rrtype.lower()), -+ (Object,), -+ dict( -+ takes_params=(param.parts or ()) + (param.extra or ()), -+ ) -+ ) -+ ) -+ -+ - @register() - class dnsrecord_split_parts(Command): - NO_CLI = True --- -2.7.4 - diff --git a/SOURCES/0122-upgrade-add-missing-suffix-to-http-instance.patch b/SOURCES/0122-upgrade-add-missing-suffix-to-http-instance.patch new file mode 100644 index 0000000..2dbb567 --- /dev/null +++ b/SOURCES/0122-upgrade-add-missing-suffix-to-http-instance.patch @@ -0,0 +1,31 @@ +From b16fba6f07455cc62284f0a225e2cd6aa6253efb Mon Sep 17 00:00:00 2001 +From: Tomas Krizek +Date: Tue, 2 May 2017 19:26:04 +0200 +Subject: [PATCH] upgrade: add missing suffix to http instance + +During an upgrade, http.suffix is used to identify ldap entry when +configuring kdc proxy. When the suffix is missing, the script crashed +when enabling KDC proxy, because it used invalid DN. + +Fixes https://pagure.io/freeipa/issue/6920 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/upgrade.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 4d8fd666dfd4e918103b449d4c31bb7661727115..9aec2d857aee1a601f351218e253d44b14f6d4ec 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1638,6 +1638,7 @@ def upgrade_configuration(): + http = httpinstance.HTTPInstance(fstore) + http.fqdn = fqdn + http.realm = api.env.realm ++ http.suffix = ipautil.realm_to_suffix(api.env.realm) + http.configure_selinux_for_httpd() + http.change_mod_nss_port_from_http() + +-- +2.9.3 + diff --git a/SOURCES/0123-Turn-on-NSSOCSP-check-in-mod_nss-conf.patch b/SOURCES/0123-Turn-on-NSSOCSP-check-in-mod_nss-conf.patch new file mode 100644 index 0000000..8d4caa9 --- /dev/null +++ b/SOURCES/0123-Turn-on-NSSOCSP-check-in-mod_nss-conf.patch @@ -0,0 +1,227 @@ +From e8f329dd4340d5216d86160a8065e0530b981b47 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Thu, 6 Apr 2017 16:15:47 +0200 +Subject: [PATCH] Turn on NSSOCSP check in mod_nss conf + +Turn on NSSOCSP directive during install/replica install/upgrade. +That check whether the certificate which is used for login is +revoked or not using OSCP. + +Marks the server cert in httpd NSS DB as trusted peer ('P,,') +to avoid chicken and egg problem when it is needed to contact +the OCSP responder when httpd is starting. + +https://pagure.io/freeipa/issue/6370 + +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +Reviewed-By: Jan Cholasta +Reviewed-By: Martin Basti +--- + freeipa.spec.in | 4 ++++ + install/restart_scripts/restart_httpd | 14 +++++++++++++- + ipaserver/install/httpinstance.py | 30 ++++++++++++++++++++++++++++++ + ipaserver/install/server/upgrade.py | 25 +++++++++++++++++++++++++ + ipaserver/setup.py | 1 + + 5 files changed, 73 insertions(+), 1 deletion(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 1dd550bd39fd14349ede58bde337783aa5c0ea04..1b3ed15036eab6262b144d970cbdfdad31ac13ea 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -195,6 +195,7 @@ BuildRequires: python-nose + BuildRequires: python-paste + BuildRequires: systemd-python + BuildRequires: python2-jinja2 ++BuildRequires: python-augeas + + %if 0%{?with_python3} + # FIXME: this depedency is missing - server will not work +@@ -232,6 +233,7 @@ BuildRequires: python3-nose + BuildRequires: python3-paste + BuildRequires: python3-systemd + BuildRequires: python3-jinja2 ++BuildRequires: python3-augeas + %endif # with_python3 + %endif # with_lint + +@@ -355,6 +357,7 @@ Requires: python-dns >= 1.15 + Requires: python-kdcproxy >= 0.3 + Requires: rpm-libs + Requires: pki-base-python2 ++Requires: python-augeas + + %description -n python2-ipaserver + IPA is an integrated solution to provide centrally managed Identity (users, +@@ -384,6 +387,7 @@ Requires: python3-pyasn1 + Requires: python3-dbus + Requires: python3-dns >= 1.15 + Requires: python3-kdcproxy >= 0.3 ++Requires: python3-augeas + Requires: rpm-libs + Requires: pki-base-python3 + +diff --git a/install/restart_scripts/restart_httpd b/install/restart_scripts/restart_httpd +index d1684812904a9d32842a0ca548ec6b9df5a5a0b7..b661b82b896b109c3859ac82c2d84ab27b839f72 100644 +--- a/install/restart_scripts/restart_httpd ++++ b/install/restart_scripts/restart_httpd +@@ -21,11 +21,23 @@ + + import syslog + import traceback ++from ipalib import api + from ipaplatform import services +-from ipaserver.install import certs ++from ipaplatform.paths import paths ++from ipaserver.install import certs, installutils + + + def _main(): ++ ++ api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) ++ api.finalize() ++ ++ db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) ++ nickname = installutils.get_directive(paths.HTTPD_NSS_CONF, "NSSNickname") ++ ++ # Add trust flag which set certificate trusted for SSL connections. ++ db.trust_root_cert(nickname, "P,,") ++ + syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd') + + try: +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 7898c53bc02785e2750dba61a5696f079355c9d7..ab688a85f157b1886842a91bb7d22f9ea99e3615 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -29,6 +29,7 @@ import pipes + import locale + + import six ++from augeas import Augeas + + from ipalib.install import certmonger + from ipaserver.install import service +@@ -153,6 +154,7 @@ class HTTPInstance(service.Service): + 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("enabling mod_nss OCSP", self.enable_mod_nss_ocsp) + self.step("adding URL rewriting rules", self.__add_include) + self.step("configuring httpd", self.__configure_http) + self.step("setting up httpd keytab", self.request_service_keytab) +@@ -259,6 +261,31 @@ class HTTPInstance(service.Service): + installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRenegotiation', 'on', False) + installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRequireSafeNegotiation', 'on', False) + ++ def enable_mod_nss_ocsp(self): ++ aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD) ++ ++ aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') ++ aug.set('/augeas/load/Httpd/incl', paths.HTTPD_NSS_CONF) ++ aug.load() ++ ++ path = '/files{}/VirtualHost'.format(paths.HTTPD_NSS_CONF) ++ ++ ocsp_comment = aug.get( ++ '{}/#comment[.=~regexp("NSSOCSP .*")]'.format(path)) ++ ocsp_dir = aug.get('{}/directive[.="NSSOCSP"]'.format(path)) ++ ++ if ocsp_dir is None and ocsp_comment is not None: ++ # Directive is missing, comment is present ++ aug.set('{}/#comment[.=~regexp("NSSOCSP .*")]'.format(path), ++ 'NSSOCSP') ++ aug.rename('{}/#comment[.="NSSOCSP"]'.format(path), 'directive') ++ elif ocsp_dir is None: ++ # Directive is missing and comment is missing ++ aug.set('{}/directive[last()+1]'.format(path), "NSSOCSP") ++ ++ aug.set('{}/directive[. = "NSSOCSP"]/arg'.format(path), 'on') ++ aug.save() ++ + def set_mod_nss_cipher_suite(self): + ciphers = ','.join(NSS_CIPHER_SUITE) + installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSCipherSuite', ciphers, False) +@@ -351,6 +378,7 @@ class HTTPInstance(service.Service): + create=True) + self.disable_system_trust() + self.create_password_conf() ++ + if self.pkcs12_info: + if self.ca_is_configured: + trust_flags = 'CT,C,C' +@@ -375,6 +403,8 @@ class HTTPInstance(service.Service): + self.__set_mod_nss_nickname(nickname) + self.add_cert_to_service() + ++ db.trust_root_cert(nickname, "P,,") ++ + else: + if not self.promote: + ca_args = [ +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 9aec2d857aee1a601f351218e253d44b14f6d4ec..7b0476d442902f2c3dc65819d54953e820f5e560 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1392,6 +1392,24 @@ def fix_trust_flags(): + sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True) + + ++def fix_server_cert_trust_flags(): ++ root_logger.info( ++ '[Fixing server certificate trust flags in %s]' % ++ paths.HTTPD_ALIAS_DIR) ++ ++ if sysupgrade.get_upgrade_state('http', 'fix_serv_cert_trust_flags'): ++ root_logger.info("Trust flags already processed") ++ return ++ ++ db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) ++ sc_nickname = installutils.get_directive(paths.HTTPD_NSS_CONF, ++ "NSSNickname") ++ # Add trust flag which set certificate trusted for SSL connections. ++ db.trust_root_cert(sc_nickname, "P,,") ++ ++ sysupgrade.set_upgrade_state('http', 'fix_serv_cert_trust_flags', True) ++ ++ + def update_mod_nss_protocol(http): + root_logger.info('[Updating mod_nss protocol versions]') + +@@ -1404,6 +1422,11 @@ def update_mod_nss_protocol(http): + sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True) + + ++def enable_mod_nss_ocsp(http): ++ root_logger.info('[Updating mod_nss enabling OCSP]') ++ http.enable_mod_nss_ocsp() ++ ++ + def update_mod_nss_cipher_suite(http): + root_logger.info('[Updating mod_nss cipher suite]') + +@@ -1671,7 +1694,9 @@ def upgrade_configuration(): + update_ipa_httpd_service_conf(http) + update_mod_nss_protocol(http) + update_mod_nss_cipher_suite(http) ++ enable_mod_nss_ocsp(http) + fix_trust_flags() ++ fix_server_cert_trust_flags() + update_http_keytab(http) + http.configure_gssproxy() + http.start() +diff --git a/ipaserver/setup.py b/ipaserver/setup.py +index 42b0c1b0618ef9867acb1fe2add5702a756cf2d2..e0b69e547ef8c2b76ce14ab27c1c29260e33f57f 100755 +--- a/ipaserver/setup.py ++++ b/ipaserver/setup.py +@@ -60,6 +60,7 @@ if __name__ == '__main__': + "pyasn1", + "pyldap", + "six", ++ "python-augeas", + # not available on PyPI + # "python-libipa_hbac", + # "python-sss", +-- +2.9.3 + diff --git a/SOURCES/0123-dns-fix-crash-in-interactive-mode-against-old-server.patch b/SOURCES/0123-dns-fix-crash-in-interactive-mode-against-old-server.patch deleted file mode 100644 index c826cda..0000000 --- a/SOURCES/0123-dns-fix-crash-in-interactive-mode-against-old-server.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 89544d521e6aa52e8b9e5e7dc4676046b5792abd Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 23 Aug 2016 12:53:39 +0200 -Subject: [PATCH] dns: fix crash in interactive mode against old servers - -Add a client-side fallback of the dnsrecord_split_parts command for old -servers to avoid CommandError in dnsrecord_add and dnsrecord_mod CLI -interactive mode. - -https://fedorahosted.org/freeipa/ticket/6203 - -Reviewed-By: Martin Basti ---- - ipaclient/plugins/dns.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 61 insertions(+), 1 deletion(-) - -diff --git a/ipaclient/plugins/dns.py b/ipaclient/plugins/dns.py -index 5e29b8c6666f94f52add7f2e1de8679127886fc2..b9ab709bf0b1d72cfb9d32aeefd77a0e8bc74d7a 100644 ---- a/ipaclient/plugins/dns.py -+++ b/ipaclient/plugins/dns.py -@@ -22,6 +22,7 @@ from __future__ import print_function - - import six - import copy -+import re - - from ipaclient.frontend import MethodOverride - from ipalib import errors -@@ -30,7 +31,8 @@ from ipalib.dns import (get_record_rrtype, - iterate_rrparams_by_parts, - part_name_format, - record_name_format) --from ipalib.parameters import Bool -+from ipalib.frontend import Command -+from ipalib.parameters import Bool, Str - from ipalib.plugable import Registry - from ipalib import _, ngettext - from ipapython.dnsutil import DNSName -@@ -121,6 +123,64 @@ class dnszone_mod(DNSZoneMethodOverride): - pass - - -+# Support old servers without dnsrecord_split_parts -+# Do not add anything new here! -+@register(no_fail=True) -+class dnsrecord_split_parts(Command): -+ NO_CLI = True -+ -+ takes_args = ( -+ Str('name'), -+ Str('value'), -+ ) -+ -+ def execute(self, name, value, *args, **options): -+ def split_exactly(count): -+ values = value.split() -+ if len(values) != count: -+ return None -+ return tuple(values) -+ -+ result = () -+ -+ rrtype = get_record_rrtype(name) -+ if rrtype in ('A', 'AAAA', 'CNAME', 'DNAME', 'NS', 'PTR'): -+ result = split_exactly(1) -+ elif rrtype in ('AFSDB', 'KX', 'MX'): -+ result = split_exactly(2) -+ elif rrtype in ('CERT', 'DLV', 'DS', 'SRV', 'TLSA'): -+ result = split_exactly(4) -+ elif rrtype in ('NAPTR'): -+ result = split_exactly(6) -+ elif rrtype in ('A6', 'TXT'): -+ result = (value,) -+ elif rrtype == 'LOC': -+ regex = re.compile( -+ r'(?P\d{1,2}\s+)' -+ r'(?:(?P\d{1,2}\s+)' -+ r'(?P\d{1,2}(?:\.\d{1,3})?\s+)?)?' -+ r'(?P[NS])\s+' -+ r'(?P\d{1,3}\s+)' -+ r'(?:(?P\d{1,2}\s+)' -+ r'(?P\d{1,2}(?:\.\d{1,3})?\s+)?)?' -+ r'(?P[WE])\s+' -+ r'(?P-?\d{1,8}(?:\.\d{1,2})?)m?' -+ r'(?:\s+(?P\d{1,8}(?:\.\d{1,2})?)m?' -+ r'(?:\s+(?P\d{1,8}(?:\.\d{1,2})?)m?' -+ r'(?:\s+(?P\d{1,8}(?:\.\d{1,2})?)m?\s*)?)?)?$') -+ -+ m = regex.match(value) -+ if m is not None: -+ result = tuple( -+ x.strip() if x is not None else x for x in m.groups()) -+ elif rrtype == 'SSHFP': -+ values = value.split(None, 2) -+ if len(values) == 3: -+ result = tuple(values) -+ -+ return dict(result=result) -+ -+ - @register(override=True, no_fail=True) - class dnsrecord_add(MethodOverride): - no_option_msg = 'No options to add a specific record provided.\n' \ --- -2.7.4 - diff --git a/SOURCES/0124-cert-show-writable-files-does-not-mean-dirs.patch b/SOURCES/0124-cert-show-writable-files-does-not-mean-dirs.patch new file mode 100644 index 0000000..70b071f --- /dev/null +++ b/SOURCES/0124-cert-show-writable-files-does-not-mean-dirs.patch @@ -0,0 +1,31 @@ +From 348fdfd66d9b3ab0214af91d193ae93b9969610e Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 9 May 2017 17:49:56 +0200 +Subject: [PATCH] cert-show: writable files does not mean dirs + +ipalib.util.check_writable_file didn't check whether the argument +is an actual file which is now fixed. + +https://pagure.io/freeipa/issue/6883 + +Reviewed-By: Fraser Tweedale +--- + ipalib/util.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipalib/util.py b/ipalib/util.py +index 8973a19abf56d1d1c5ba04f6edb4228dd2329e65..713fc107e9374eefe7805bc4e1abc40b6d150c32 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -170,7 +170,7 @@ def check_writable_file(filename): + if filename is None: + raise errors.FileError(reason=_('Filename is empty')) + try: +- if os.path.exists(filename): ++ if os.path.isfile(filename): + if not os.access(filename, os.W_OK): + raise errors.FileError(reason=_('Permission denied: %(file)s') % dict(file=filename)) + else: +-- +2.9.3 + diff --git a/SOURCES/0124-schema-cache-Store-and-check-info-for-pre-schema-ser.patch b/SOURCES/0124-schema-cache-Store-and-check-info-for-pre-schema-ser.patch deleted file mode 100644 index a634f3b..0000000 --- a/SOURCES/0124-schema-cache-Store-and-check-info-for-pre-schema-ser.patch +++ /dev/null @@ -1,393 +0,0 @@ -From 2618c2fbbd9e23f79a667ac373b0a828cdd5d643 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Mon, 22 Aug 2016 13:34:30 +0200 -Subject: [PATCH] schema cache: Store and check info for pre-schema servers - -Cache CommandError answer to schema command to avoid sending the command -to pre-schema servers every time. This information expires after some -time (1 hour) in order to start using schema as soon as the server is -upgraded. - -https://fedorahosted.org/freeipa/ticket/6095 - -Signed-off-by: Jan Cholasta -Signed-off-by: David Kupka -Reviewed-By: Tomas Krizek ---- - ipaclient/remote_plugins/__init__.py | 80 +++++++++++++-------- - ipaclient/remote_plugins/compat.py | 9 ++- - ipaclient/remote_plugins/schema.py | 130 ++++++++++++++++++----------------- - 3 files changed, 128 insertions(+), 91 deletions(-) - -diff --git a/ipaclient/remote_plugins/__init__.py b/ipaclient/remote_plugins/__init__.py -index 2be9222be693a5c4a04a735c216f590d75c1ecfe..b783c32819e58f49532531b6d7f3a594c17bae16 100644 ---- a/ipaclient/remote_plugins/__init__.py -+++ b/ipaclient/remote_plugins/__init__.py -@@ -5,7 +5,9 @@ - import collections - import errno - import json -+import locale - import os -+import time - - from . import compat - from . import schema -@@ -23,20 +25,18 @@ class ServerInfo(collections.MutableMapping): - def __init__(self, api): - hostname = DNSName(api.env.server).ToASCII() - self._path = os.path.join(self._DIR, hostname) -+ self._force_check = api.env.force_schema_check - self._dict = {} -- self._dirty = False - -- self._read() -- -- def __enter__(self): -- return self -- -- def __exit__(self, *_exc_info): -- self.flush() -+ # copy-paste from ipalib/rpc.py -+ try: -+ self._language = ( -+ locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() -+ ) -+ except locale.Error: -+ self._language = 'en_us' - -- def flush(self): -- if self._dirty: -- self._write() -+ self._read() - - def _read(self): - try: -@@ -62,13 +62,10 @@ class ServerInfo(collections.MutableMapping): - return self._dict[key] - - def __setitem__(self, key, value): -- if key not in self._dict or self._dict[key] != value: -- self._dirty = True - self._dict[key] = value - - def __delitem__(self, key): - del self._dict[key] -- self._dirty = True - - def __iter__(self): - return iter(self._dict) -@@ -76,26 +73,55 @@ class ServerInfo(collections.MutableMapping): - def __len__(self): - return len(self._dict) - -+ def update_validity(self, ttl=None): -+ if ttl is None: -+ ttl = 3600 -+ self['expiration'] = time.time() + ttl -+ self['language'] = self._language -+ self._write() -+ -+ def is_valid(self): -+ if self._force_check: -+ return False -+ -+ try: -+ expiration = self._dict['expiration'] -+ language = self._dict['language'] -+ except KeyError: -+ # if any of these is missing consider the entry expired -+ return False -+ -+ if expiration < time.time(): -+ # validity passed -+ return False -+ -+ if language != self._language: -+ # language changed since last check -+ return False -+ -+ return True -+ - - def get_package(api): - if api.env.in_tree: - from ipaserver import plugins - else: -- client = rpcclient(api) -- client.finalize() -- - try: -- server_info = api._server_info -+ plugins = api._remote_plugins - except AttributeError: -- server_info = api._server_info = ServerInfo(api) -+ server_info = ServerInfo(api) - -- try: -- plugins = schema.get_package(api, server_info, client) -- except schema.NotAvailable: -- plugins = compat.get_package(api, server_info, client) -- finally: -- server_info.flush() -- if client.isconnected(): -- client.disconnect() -+ client = rpcclient(api) -+ client.finalize() -+ -+ try: -+ plugins = schema.get_package(server_info, client) -+ except schema.NotAvailable: -+ plugins = compat.get_package(server_info, client) -+ finally: -+ if client.isconnected(): -+ client.disconnect() -+ -+ object.__setattr__(api, '_remote_plugins', plugins) - - return plugins -diff --git a/ipaclient/remote_plugins/compat.py b/ipaclient/remote_plugins/compat.py -index 5e08cb0ed73becbc17e724864d1a853142a5ef6f..984eecd3f86fada96084d70bbbeb81c3730346e8 100644 ---- a/ipaclient/remote_plugins/compat.py -+++ b/ipaclient/remote_plugins/compat.py -@@ -31,10 +31,15 @@ class CompatObject(Object): - pass - - --def get_package(api, server_info, client): -+def get_package(server_info, client): - try: - server_version = server_info['version'] - except KeyError: -+ is_valid = False -+ else: -+ is_valid = server_info.is_valid() -+ -+ if not is_valid: - if not client.isconnected(): - client.connect(verbose=False) - env = client.forward(u'env', u'api_version', version=u'2.0') -@@ -51,6 +56,8 @@ def get_package(api, server_info, client): - else: - server_version = u'2.0' - server_info['version'] = server_version -+ server_info.update_validity() -+ - server_version = LooseVersion(server_version) - - package_names = {} -diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py -index 553da35127188b1ae842a7a0b58433e632c82b9f..5634fd1c8fc9c4f9276b57eac2e4abecc8d7c792 100644 ---- a/ipaclient/remote_plugins/schema.py -+++ b/ipaclient/remote_plugins/schema.py -@@ -7,10 +7,8 @@ import contextlib - import errno - import fcntl - import json --import locale - import os - import sys --import time - import types - import zipfile - -@@ -220,7 +218,7 @@ class _SchemaPlugin(object): - - def __call__(self, api): - if self._class is None: -- schema = api._schema[self.schema_key][self.full_name] -+ schema = self._schema[self.schema_key][self.full_name] - name, bases, class_dict = self._create_class(api, schema) - self._class = type(name, bases, class_dict) - -@@ -361,7 +359,7 @@ class Schema(object): - namespaces = {'classes', 'commands', 'topics'} - _DIR = os.path.join(paths.USER_CACHE_PATH, 'ipa', 'schema', FORMAT) - -- def __init__(self, api, server_info, client): -+ def __init__(self, client, fingerprint=None): - self._dict = {} - self._namespaces = {} - self._help = None -@@ -371,48 +369,29 @@ class Schema(object): - self._dict[ns] = {} - self._namespaces[ns] = _SchemaNameSpace(self, ns) - -- # copy-paste from ipalib/rpc.py -- try: -- self._language = ( -- locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() -- ) -- except locale.Error: -- # fallback to default locale -- self._language = 'en_us' -- -- try: -- self._fingerprint = server_info['fingerprint'] -- self._expiration = server_info['expiration'] -- language = server_info['language'] -- except KeyError: -- is_known = False -- else: -- is_known = (not api.env.force_schema_check and -- self._expiration > time.time() and -- self._language == language) -+ ttl = None -+ read_failed = False - -- if is_known: -+ if fingerprint is not None: - try: -- self._read_schema() -- except Exception: -- pass -- else: -- return -- -- try: -- self._fetch(client) -- except NotAvailable: -- raise -- except SchemaUpToDate as e: -- self._fingerprint = e.fingerprint -- self._expiration = time.time() + e.ttl -- self._read_schema() -- else: -- self._write_schema() -+ self._read_schema(fingerprint) -+ except Exception as e: -+ # Failed to read the schema from cache. There may be a lot of -+ # causes and not much we can do about it. Just ensure we will -+ # ignore the cache and fetch the schema from server. -+ logger.warning("Failed to read schema: {}".format(e)) -+ fingerprint = None -+ read_failed = True -+ -+ if fingerprint is None: -+ fingerprint, ttl = self._fetch(client, ignore_cache=read_failed) -+ try: -+ self._write_schema(fingerprint) -+ except Exception as e: -+ logger.warning("Failed to write schema: {}".format(e)) - -- server_info['fingerprint'] = self._fingerprint -- server_info['expiration'] = self._expiration -- server_info['language'] = self._language -+ self.fingerprint = fingerprint -+ self.ttl = ttl - - @contextlib.contextmanager - def _open(self, filename, mode): -@@ -429,14 +408,16 @@ class Schema(object): - finally: - fcntl.flock(f, fcntl.LOCK_UN) - -- def _fetch(self, client): -+ def _fetch(self, client, ignore_cache=False): - if not client.isconnected(): - client.connect(verbose=False) - -- try: -- fps = [fsdecode(f) for f in os.listdir(self._DIR)] -- except EnvironmentError: -- fps = [] -+ fps = [] -+ if not ignore_cache: -+ try: -+ fps = [fsdecode(f) for f in os.listdir(self._DIR)] -+ except EnvironmentError: -+ pass - - kwargs = {u'version': u'2.170'} - if fps: -@@ -459,12 +440,11 @@ class Schema(object): - logger.warning("Failed to fetch schema: %s", e) - raise NotAvailable() - -- self._fingerprint = fp -- self._expiration = time.time() + ttl -+ return (fp, ttl,) - -- def _read_schema(self): -+ def _read_schema(self, fingerprint): - self._file.truncate(0) -- with self._open(self._fingerprint, 'r') as f: -+ with self._open(fingerprint, 'r') as f: - self._file.write(f.read()) - - with zipfile.ZipFile(self._file, 'r') as schema: -@@ -500,13 +480,12 @@ class Schema(object): - - return halp - -- def _write_schema(self): -+ def _write_schema(self, fingerprint): - try: - os.makedirs(self._DIR) - except EnvironmentError as e: - if e.errno != errno.EEXIST: -- logger.warning("Failed to write schema: {}".format(e)) -- return -+ raise - - self._file.truncate(0) - with zipfile.ZipFile(self._file, 'w', zipfile.ZIP_DEFLATED) as schema: -@@ -523,7 +502,7 @@ class Schema(object): - json.dumps(self._generate_help(self._dict))) - - self._file.seek(0) -- with self._open(self._fingerprint, 'w') as f: -+ with self._open(fingerprint, 'w') as f: - f.truncate(0) - f.write(self._file.read()) - -@@ -550,14 +529,39 @@ class Schema(object): - return self._help[namespace][member] - - --def get_package(api, server_info, client): -- try: -- schema = api._schema -- except AttributeError: -- schema = Schema(api, server_info, client) -- object.__setattr__(api, '_schema', schema) -+def get_package(server_info, client): -+ NO_FINGERPRINT = object() -+ -+ fingerprint = NO_FINGERPRINT -+ if server_info.is_valid(): -+ fingerprint = server_info.get('fingerprint', fingerprint) -+ -+ if fingerprint is not None: -+ try: -+ try: -+ if fingerprint is NO_FINGERPRINT: -+ schema = Schema(client) -+ else: -+ schema = Schema(client, fingerprint) -+ except SchemaUpToDate as e: -+ schema = Schema(client, e.fingerprint) -+ except NotAvailable: -+ fingerprint = None -+ ttl = None -+ except SchemaUpToDate as e: -+ fingerprint = e.fingerprint -+ ttl = e.ttl -+ else: -+ fingerprint = schema.fingerprint -+ ttl = schema.ttl -+ -+ server_info['fingerprint'] = fingerprint -+ server_info.update_validity(ttl) -+ -+ if fingerprint is None: -+ raise NotAvailable() - -- fingerprint = str(server_info['fingerprint']) -+ fingerprint = str(fingerprint) - package_name = '{}${}'.format(__name__, fingerprint) - package_dir = '{}${}'.format(os.path.splitext(__file__)[0], fingerprint) - --- -2.7.4 - diff --git a/SOURCES/0125-Bump-version-of-ipa.conf-file.patch b/SOURCES/0125-Bump-version-of-ipa.conf-file.patch new file mode 100644 index 0000000..d45ab9c --- /dev/null +++ b/SOURCES/0125-Bump-version-of-ipa.conf-file.patch @@ -0,0 +1,30 @@ +From dd433bd402b847b651ba2aa722e4b37c3235984b Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Thu, 11 May 2017 10:17:33 +0200 +Subject: [PATCH] Bump version of ipa.conf file + +In commit 157831a287c64106eed4 the version bump was forgotten and therefore the +ipa.conf file is not replaced during upgrade and login using certificate when +single certificate is mapped to multiple users doesn't work. + +https://pagure.io/freeipa/issue/6860 + +Reviewed-By: Martin Basti +--- + install/conf/ipa.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf +index 75c122e6c94b941c278d724add84315753082531..a7ca5ce715e55960b8edd307cdbe41dcbd6b29ca 100644 +--- a/install/conf/ipa.conf ++++ b/install/conf/ipa.conf +@@ -1,5 +1,5 @@ + # +-# VERSION 25 - DO NOT REMOVE THIS LINE ++# VERSION 26 - DO NOT REMOVE THIS LINE + # + # This file may be overwritten on upgrades. + # +-- +2.9.3 + diff --git a/SOURCES/0125-Fix-parse-errors-with-link-local-addresses.patch b/SOURCES/0125-Fix-parse-errors-with-link-local-addresses.patch deleted file mode 100644 index 146fff5..0000000 --- a/SOURCES/0125-Fix-parse-errors-with-link-local-addresses.patch +++ /dev/null @@ -1,38 +0,0 @@ -From fd11c06c34a45688c7609872b93413823f9ccb4d Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Mon, 5 Sep 2016 14:33:58 +0200 -Subject: [PATCH] Fix parse errors with link-local addresses - -Link-local addresses received from netifaces contains '%suffix' that -causes parse error in IPNetwork class. We must remove %suffix before -it us used in IPNetwork objects. - -https://fedorahosted.org/freeipa/ticket/6296 - -Reviewed-By: Tomas Krizek ---- - ipapython/ipautil.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py -index fdfebb65ecb8b62108852f6517b5ffb22fd7eedc..a099ea45747100946aa97bb5010ae58c49a089ba 100644 ---- a/ipapython/ipautil.py -+++ b/ipapython/ipautil.py -@@ -173,8 +173,13 @@ class CheckedIPAddress(UnsafeIPAddress): - iface = None - for interface in netifaces.interfaces(): - for ifdata in netifaces.ifaddresses(interface).get(family, []): -+ -+ # link-local addresses contain '%suffix' that causes parse -+ # errors in IPNetwork -+ ifaddr = ifdata['addr'].split(u'%', 1)[0] -+ - ifnet = netaddr.IPNetwork('{addr}/{netmask}'.format( -- addr=ifdata['addr'], -+ addr=ifaddr, - netmask=ifdata['netmask'] - )) - if ifnet == self._net or ( --- -2.7.4 - diff --git a/SOURCES/0126-Add-support-for-additional-options-taken-from-table-.patch b/SOURCES/0126-Add-support-for-additional-options-taken-from-table-.patch deleted file mode 100644 index 957f4d7..0000000 --- a/SOURCES/0126-Add-support-for-additional-options-taken-from-table-.patch +++ /dev/null @@ -1,104 +0,0 @@ -From a5918fbd136d1b597e30629f66a3d69d567737f3 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Fri, 26 Aug 2016 12:50:00 +0200 -Subject: [PATCH] Add support for additional options taken from table facet - -Sometimes the entity_show command must be called with options which are gathered -from result of entity_find command. These options needs to be passed as -arguments in URL which points to details page. - -This functionality is implemented to table facet. There is new property -'additional_navigation_arguments' which is prepared for array of attributes -which will be passed to URL. - -Part of: https://fedorahosted.org/freeipa/ticket/6238 - -Reviewed-By: Petr Vobornik ---- - install/ui/src/freeipa/facet.js | 49 ++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 48 insertions(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/facet.js b/install/ui/src/freeipa/facet.js -index 4553c5c65e6c334ed451e9c2f1a89ddc455d71c3..06eca189fa2c7b125fdfbd964e6192ddf709b2c8 100644 ---- a/install/ui/src/freeipa/facet.js -+++ b/install/ui/src/freeipa/facet.js -@@ -1819,6 +1819,15 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) { - var that = IPA.facet(spec, no_init); - - /** -+ * Names of additional row attributes which will be send to another facet -+ * during navigation as URL parameters. -+ * -+ * @property {Array} -+ */ -+ that.additional_navigation_arguments = spec.additional_navigation_arguments; -+ -+ -+ /** - * Entity of data displayed in the table - * @property {entity.entity} - */ -@@ -2268,6 +2277,38 @@ exp.table_facet = IPA.table_facet = function(spec, no_init) { - - - /** -+ * Extract data from command response and return them. -+ * -+ * @param pkey {string} primary key of row which is chosen -+ * @param attrs {Array} names of attributes which will be extracted -+ */ -+ that.get_row_attribute_values = function(key, attrs) { -+ var result = that.data.result.result; -+ var options = {}; -+ var row; -+ -+ if (result) { -+ for (var i=0, l=result.length; i +Date: Wed, 10 May 2017 18:04:52 +0200 +Subject: [PATCH] ipa-kra-install manpage: document domain-level 1 + +ipa-kra-install man page was missing a specific section for domain level 1. +This commits also fixes a wrong option short name (for --log-file) and +indents the text corresponding to -p DM_PASSWORD + +https://pagure.io/freeipa/issue/6922 + +Reviewed-By: Tomas Krizek +--- + install/tools/man/ipa-kra-install.1 | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/install/tools/man/ipa-kra-install.1 b/install/tools/man/ipa-kra-install.1 +index 0aa9073c3303bd852627e430102ceb40575decc4..51afaac6474a9483e8c02bae605fe95994cce1f2 100644 +--- a/install/tools/man/ipa-kra-install.1 ++++ b/install/tools/man/ipa-kra-install.1 +@@ -16,26 +16,37 @@ + .\" + .\" Author: Ade Lee + .\" +-.TH "ipa-kra-install" "1" "Aug 24 2014" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-kra-install" "1" "May 10 2017" "FreeIPA" "FreeIPA Manual Pages" + .SH "NAME" + ipa\-kra\-install \- Install a KRA on a server + .SH "SYNOPSIS" ++.SS "DOMAIN LEVEL 0" ++.TP + ipa\-kra\-install [\fIOPTION\fR]... [replica_file] ++.SS "DOMAIN LEVEL 1" ++.TP ++ipa\-kra\-install [\fIOPTION\fR]... + .SH "DESCRIPTION" + Adds a KRA as an IPA\-managed service. This requires that the IPA server is already installed and configured, including a CA. + + The KRA (Key Recovery Authority) is a component used to securely store secrets such as passwords, symmetric keys and private asymmetric keys. It is used as the back-end repository for the IPA Password Vault. + +-ipa\-kra\-install can be run without replica_file to add KRA to the existing CA. ++In a domain at domain level 0, ipa\-kra\-install can be run without replica_file to add KRA to the existing CA, or with replica_file to install the KRA service on the replica. + ipa\-kra\-install will contact the CA to determine if a KRA has already been installed on another replica, and if so, will exit indicating that a replica_file is required. + + The replica_file is created using the ipa\-replica\-prepare utility. A new replica_file should be generated on the master IPA server after the KRA has been installed and configured, so that the replica_file will contain the master KRA configuration and system certificates. + ++In a domain at domain level 1, ipa\-kra\-install can be used to add KRA to the existing CA, or to install the KRA service on a replica, and does not require any replica file. ++ + KRA can only be removed along with the entire server using ipa\-server\-install \-\-uninstall. + .SH "OPTIONS" ++.TP + \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR + Directory Manager (existing master) password + .TP ++\fB\-\-no-host-dns\fR ++Do not use DNS for hostname lookup during installation ++.TP + \fB\-U\fR, \fB\-\-unattended\fR + An unattended installation that will never prompt for user input + .TP +@@ -45,7 +56,7 @@ Enable debug output when more verbose output is needed + \fB\-q\fR, \fB\-\-quiet\fR + Output only errors + .TP +-\fB\-v\fR, \fB\-\-log-file\fR=\fFILE\fR ++\fB\-\-log-file\fR=\fRFILE\fR + Log to the given file + .SH "EXIT STATUS" + 0 if the command was successful +-- +2.9.3 + diff --git a/SOURCES/0127-WebUI-Fix-showing-certificates-issued-by-sub-CA.patch b/SOURCES/0127-WebUI-Fix-showing-certificates-issued-by-sub-CA.patch deleted file mode 100644 index 85f7b6d..0000000 --- a/SOURCES/0127-WebUI-Fix-showing-certificates-issued-by-sub-CA.patch +++ /dev/null @@ -1,57 +0,0 @@ -From f718361b95258244df1d26b5f15d3a8098259939 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Fri, 26 Aug 2016 13:03:58 +0200 -Subject: [PATCH] WebUI: Fix showing certificates issued by sub-CA - -The cert-show command needs to be called with cacn option. Cacn option is -passed using URL attribute. - -https://fedorahosted.org/freeipa/ticket/6238 - -Reviewed-By: Petr Vobornik ---- - install/ui/src/freeipa/certificate.js | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/install/ui/src/freeipa/certificate.js b/install/ui/src/freeipa/certificate.js -index 232bdbf2fa95c3a68943539cd80129d481d8563a..e67c348b7edbd2e273f18ed1df40ef8b5b5e59c3 100755 ---- a/install/ui/src/freeipa/certificate.js -+++ b/install/ui/src/freeipa/certificate.js -@@ -1543,6 +1543,7 @@ return { - row_enabled_attribute: 'status', - facet_groups: [exp.facet_group], - facet_group: 'certificates', -+ additional_navigation_arguments: [ 'cacn' ], - pagination: false, - no_update: true, - columns: [ -@@ -1552,6 +1553,7 @@ return { - width: '90px' - }, - 'subject', -+ 'cacn', - { - name: 'status', - width: '120px' -@@ -1645,6 +1647,7 @@ return { - fields: [ - 'serial_number', - 'serial_number_hex', -+ 'cacn', - 'subject', - { - name: 'issuer', -@@ -1772,6 +1775,10 @@ IPA.cert.details_facet = function(spec, no_init) { - var command = that.details_facet_create_refresh_command(); - delete command.options.all; - delete command.options.rights; -+ -+ command.options = command.options || {}; -+ $.extend(command.options, { cacn: that.state.cacn }); -+ - return command; - }; - --- -2.7.4 - diff --git a/SOURCES/0127-renew-agent-respect-CA-renewal-master-setting.patch b/SOURCES/0127-renew-agent-respect-CA-renewal-master-setting.patch new file mode 100644 index 0000000..a1aafa9 --- /dev/null +++ b/SOURCES/0127-renew-agent-respect-CA-renewal-master-setting.patch @@ -0,0 +1,54 @@ +From 55e779b19714532744c8b22e514e9e49563350e3 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 24 Apr 2017 05:24:24 +0000 +Subject: [PATCH] renew agent: respect CA renewal master setting + +Do not bypass the renewal master check when a non-virtual profile is used +in dogtag-ipa-ca-renew-agent-submit. + +This fixes dogtag-ipa-ca-renew-agent not respecting the CA renewal master +setting for certificates tracked with a real profile. (Note that there +currently aren't any such certificates tracked by us.) + +Request the RA certificate using dogtag-submit rather than +dogtag-ipa-ca-renew-agent-submit as the CA renewal master setting is not +available so early in the install process. + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + install/certmonger/dogtag-ipa-ca-renew-agent-submit | 2 +- + ipaserver/install/cainstance.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index 7a3d9551884c0fe43566dd9012699211a39294eb..f253fd9587ac1ef3ece712ca9999c1ea4f3d55d8 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -535,7 +535,7 @@ def main(): + + profile = os.environ.get('CERTMONGER_CA_PROFILE') + if is_replicated(): +- if profile or is_renewal_master(): ++ if is_renewal_master(): + handler = request_and_store_cert + else: + handler = retrieve_cert_continuous +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index d72feb884964ecf49fe0166cbfeb3cb2c10737fe..97baa606c960806376e025b5654eea816da207ed 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -822,7 +822,7 @@ class CAInstance(DogtagInstance): + "-out", chain_file.name, + ], stdin=data, capture_output=False) + +- agent_args = [paths.DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT, ++ agent_args = [paths.CERTMONGER_DOGTAG_SUBMIT, + "--dbdir", self.tmp_agent_db, + "--nickname", "ipa-ca-agent", + "--cafile", chain_file.name, +-- +2.9.3 + diff --git a/SOURCES/0128-WebUI-add-support-for-sub-CAs-while-revoking-certifi.patch b/SOURCES/0128-WebUI-add-support-for-sub-CAs-while-revoking-certifi.patch deleted file mode 100644 index 5d1de8c..0000000 --- a/SOURCES/0128-WebUI-add-support-for-sub-CAs-while-revoking-certifi.patch +++ /dev/null @@ -1,252 +0,0 @@ -From f5efedd4c4f25e423e83c45efdc779fa567eb451 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Fri, 26 Aug 2016 13:11:22 +0200 -Subject: [PATCH] WebUI add support for sub-CAs while revoking certificates - -Also the same for removing certificate hold. - -https://fedorahosted.org/freeipa/ticket/6216 - -Reviewed-By: Petr Vobornik -Reviewed-By: Stanislav Laznicka ---- - install/ui/src/freeipa/certificate.js | 129 ++++++++++++++++++++++++++-------- - install/ui/src/freeipa/widget.js | 1 + - 2 files changed, 100 insertions(+), 30 deletions(-) - -diff --git a/install/ui/src/freeipa/certificate.js b/install/ui/src/freeipa/certificate.js -index e67c348b7edbd2e273f18ed1df40ef8b5b5e59c3..9ab40027817cdcc242762399a0b4d9f41afec0b7 100755 ---- a/install/ui/src/freeipa/certificate.js -+++ b/install/ui/src/freeipa/certificate.js -@@ -244,44 +244,104 @@ IPA.cert.download_dialog = function(spec) { - return that; - }; - --IPA.cert.revoke_dialog = function(spec) { -+IPA.cert.revocation_reason_select_widget = function(spec) { -+ spec = spec || {}; -+ -+ var that = IPA.select_widget(spec); -+ -+ that.create_options = function() { -+ for (var i=0; i').appendTo(td); -- for (var i=0; i', { -- 'value': i, -- 'html': text.get('@i18n:objects.cert.'+reason) -- }).appendTo(that.select); -- } -+ that.init = function() { -+ var note = text.get('@i18n:objects.cert.revoke_confirmation'); -+ that.widgets.get_widget('note.note').html = note; - }; - -+ if (!no_init) that.init(); -+ - return that; - }; - -@@ -718,7 +778,7 @@ IPA.cert.request_action = function(spec) { - return that; - }; - --IPA.cert.perform_revoke = function(spec, sn, revocation_reason) { -+IPA.cert.perform_revoke = function(spec, sn, revocation_reason, cacn) { - - spec.hide_activity_icon = spec.hide_activity_icon || false; - -@@ -728,7 +788,8 @@ IPA.cert.perform_revoke = function(spec, sn, revocation_reason) { - hide_activity_icon: spec.hide_activity_icon, - args: [ sn ], - options: { -- 'revocation_reason': revocation_reason -+ revocation_reason: revocation_reason, -+ cacn: cacn - }, - notify_activity_start: spec.notify_activity_start, - notify_activity_end: spec.notify_activity_end, -@@ -782,7 +843,8 @@ IPA.cert.revoke_action = function(spec) { - - var sn = facet.certificate.serial_number; - var revocation_reason = that.dialog.get_reason(); -- IPA.cert.perform_revoke(spec, sn, revocation_reason); -+ var cacn = that.dialog.get_cacn(); -+ IPA.cert.perform_revoke(spec, sn, revocation_reason, cacn); - }; - - return that; -@@ -835,19 +897,22 @@ IPA.cert.remove_hold_action = function(spec) { - } - }; - -- IPA.cert.perform_remove_hold(spec, facet.certificate.serial_number); -- -+ IPA.cert.perform_remove_hold(spec, facet.certificate.serial_number, -+ facet.state.cacn); - }; - - return that; - }; - --IPA.cert.perform_remove_hold = function(spec, sn) { -+IPA.cert.perform_remove_hold = function(spec, sn, cacn) { - - rpc.command({ - entity: 'cert', - method: 'remove_hold', - args: [sn], -+ options: { -+ cacn: cacn -+ }, - on_success: spec.on_success - }).execute(); - }; -@@ -1360,13 +1425,15 @@ IPA.cert.cert_widget = function(spec) { - }; - - var sn = that.certificate.serial_number; -+ var cacn = dialog.get_cacn(); - var revocation_reason = dialog.get_reason(); -- IPA.cert.perform_revoke(command_spec, sn, revocation_reason); -+ IPA.cert.perform_revoke(command_spec, sn, revocation_reason, cacn); - } - }; - - var dialog = IPA.cert.revoke_dialog(spec); - dialog.open(); -+ dialog.set_cacn(that.certificate.cacn); - }; - - that.perform_remove_hold = function() { -@@ -1392,7 +1459,8 @@ IPA.cert.cert_widget = function(spec) { - }; - - var sn = that.certificate.serial_number; -- IPA.cert.perform_remove_hold(command_spec, sn); -+ var cacn = that.certificate.cacn; -+ IPA.cert.perform_remove_hold(command_spec, sn, cacn); - } - }; - -@@ -1834,6 +1902,7 @@ exp.register = function() { - f.register('certificate_status', IPA.cert.status_field); - f.register('revocation_reason', IPA.revocation_reason_field); - w.register('revocation_reason', IPA.text_widget); -+ w.register('revocation_reason_select', IPA.cert.revocation_reason_select_widget); - - a.register('cert_request', IPA.cert.request_action); - a.register('download_cert', IPA.cert.download_action); -diff --git a/install/ui/src/freeipa/widget.js b/install/ui/src/freeipa/widget.js -index 9151ebac9438e9e674f81bfb1ccfe7a63872b1ae..4769ca616e4337e8f10339048f9851252e6dfd2e 100644 ---- a/install/ui/src/freeipa/widget.js -+++ b/install/ui/src/freeipa/widget.js -@@ -2878,6 +2878,7 @@ IPA.select_widget = function(spec) { - // methods that should be invoked by subclasses - that.select_save = that.save; - that.select_update = that.update; -+ that.select_create_options = that.create_options; - - return that; - }; --- -2.7.4 - diff --git a/SOURCES/0128-server-upgrade-always-fix-certmonger-tracking-reques.patch b/SOURCES/0128-server-upgrade-always-fix-certmonger-tracking-reques.patch new file mode 100644 index 0000000..8e8a48d --- /dev/null +++ b/SOURCES/0128-server-upgrade-always-fix-certmonger-tracking-reques.patch @@ -0,0 +1,93 @@ +From ba42557e2acb526587b07956e75a2a1394882771 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 28 Feb 2017 10:55:54 +0000 +Subject: [PATCH] server upgrade: always fix certmonger tracking request + +Fix certmonger tracking requests on every run of ipa-server-upgrade rather +than only when the tracking configuration has changed and the requests have +not yet been updated. + +This allows fixing broken tracking requests just by re-running +ipa-server-upgrade. + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/server/upgrade.py | 28 +++++++--------------------- + 1 file changed, 7 insertions(+), 21 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 7b0476d442902f2c3dc65819d54953e820f5e560..855056dc1fa20e813d82ecc5090a14cfc4f91831 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -905,8 +905,6 @@ def certificate_renewal_update(ca, ds, http): + template = paths.CERTMONGER_COMMAND_TEMPLATE + serverid = installutils.realm_to_serverid(api.env.realm) + +- # bump version when requests is changed +- version = 6 + requests = [ + { + 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, +@@ -971,25 +969,17 @@ def certificate_renewal_update(ca, ds, http): + } + ] + +- root_logger.info("[Update certmonger certificate renewal configuration to " +- "version %d]" % version) ++ root_logger.info("[Update certmonger certificate renewal configuration]") + if not ca.is_configured(): + root_logger.info('CA is not configured') + return False + +- state = 'certificate_renewal_update_%d' % version +- if sysupgrade.get_upgrade_state('dogtag', state): +- return False +- + # State not set, lets see if we are already configured + for request in requests: + request_id = certmonger.get_request_id(request) + if request_id is None: + break + else: +- sysupgrade.set_upgrade_state('dogtag', state, True) +- root_logger.info("Certmonger certificate renewal configuration is " +- "already at version %d" % version) + return False + + # Ok, now we need to stop tracking, then we can start tracking them +@@ -998,13 +988,11 @@ def certificate_renewal_update(ca, ds, http): + ds.stop_tracking_certificates(serverid) + http.stop_tracking_certificates() + +- if not sysupgrade.get_upgrade_state('dogtag', +- 'certificate_renewal_update_1'): +- filename = paths.CERTMONGER_CAS_CA_RENEWAL +- if os.path.exists(filename): +- with installutils.stopped_service('certmonger'): +- root_logger.info("Removing %s" % filename) +- installutils.remove_file(filename) ++ filename = paths.CERTMONGER_CAS_CA_RENEWAL ++ if os.path.exists(filename): ++ with installutils.stopped_service('certmonger'): ++ root_logger.info("Removing %s" % filename) ++ installutils.remove_file(filename) + + ca.configure_certmonger_renewal() + ca.configure_renewal() +@@ -1013,9 +1001,7 @@ def certificate_renewal_update(ca, ds, http): + ds.start_tracking_certificates(serverid) + http.start_tracking_certificates() + +- sysupgrade.set_upgrade_state('dogtag', state, True) +- root_logger.info("Certmonger certificate renewal configuration updated to " +- "version %d" % version) ++ root_logger.info("Certmonger certificate renewal configuration updated") + return True + + def copy_crl_file(old_path, new_path=None): +-- +2.9.3 + diff --git a/SOURCES/0129-cainstance-use-correct-profile-for-lightweight-CA-ce.patch b/SOURCES/0129-cainstance-use-correct-profile-for-lightweight-CA-ce.patch new file mode 100644 index 0000000..2865b5c --- /dev/null +++ b/SOURCES/0129-cainstance-use-correct-profile-for-lightweight-CA-ce.patch @@ -0,0 +1,182 @@ +From 1b17dfa9fb62215eeb1ceadc7902785a7ed384e9 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 28 Feb 2017 10:58:28 +0000 +Subject: [PATCH] cainstance: use correct profile for lightweight CA + certificates + +Use Dogtag's `caCACert` CA certificate profile rather than the +`ipaCACertRenewal` virtual profile for lightweight CA certificates. + +The `ipaCACertRenewal` virtual profile adds special handling of externally +signed CA certificates and LDAP replication of issued certificates on top +of `caCACert`, neither of which is relevant for lightweight CA +certificates. + +Remove all of the special casing of lightweight CA certificates from +dogtag-ipa-ca-renew-agent-submit. + +Make sure existing lightweight CA certmonger tracking requests are updated +on server upgrade. + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + .../certmonger/dogtag-ipa-ca-renew-agent-submit | 36 +++------------------- + ipaserver/install/cainstance.py | 7 ++--- + ipaserver/install/server/upgrade.py | 16 ++++++++++ + 3 files changed, 23 insertions(+), 36 deletions(-) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index f253fd9587ac1ef3ece712ca9999c1ea4f3d55d8..51b0880c5b57758845e2ffa0c9545bbca7e8c751 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -98,25 +98,7 @@ def get_nickname(): + DN('CN=IPA RA', subject_base): 'ipaCert', + } + +- try: +- return nickname_by_subject_dn[DN(subject)] +- except KeyError: +- cas = api.Command.ca_find(ipacasubjectdn=DN(subject))['result'] +- if len(cas) == 0: +- return None +- return 'caSigningCert cert-pki-ca {}'.format(cas[0]['ipacaid'][0]) +- +- +-def is_lightweight_ca(): +- nickname = get_nickname() or '' +- return nickname != IPA_CA_NICKNAME and nickname.startswith(IPA_CA_NICKNAME) +- +-def is_renewable(): +- cert = os.environ.get('CERTMONGER_CERTIFICATE') +- if not cert: +- return False +- else: +- return x509.is_self_signed(cert) or is_lightweight_ca() ++ return nickname_by_subject_dn.get(DN(subject)) + + + def is_replicated(): +@@ -276,11 +258,6 @@ def store_cert(): + if not cert: + return (REJECTED, "New certificate requests not supported") + +- if is_lightweight_ca(): +- # Lightweight CAs are updated in Dogtag's NSSDB +- # by Dogtag itself, so do not store it +- return (ISSUED, cert) +- + dercert = x509.normalize_certificate(cert) + + dn = DN(('cn', nickname), ('cn', 'ca_renewal'), +@@ -405,12 +382,6 @@ def retrieve_cert_continuous(): + if old_cert: + old_cert = x509.normalize_certificate(old_cert) + +- if is_lightweight_ca(): +- # Lightweight CAs are updated in Dogtag's NSSDB +- # by Dogtag itself, so do not try to retrieve it. +- # Everything is fine as is. +- return (ISSUED, os.environ.get('CERTMONGER_CERTIFICATE')) +- + result = call_handler(retrieve_or_reuse_cert) + if result[0] != ISSUED: + return result +@@ -466,12 +437,13 @@ def renew_ca_cert(): + cert = os.environ.get('CERTMONGER_CERTIFICATE') + if not cert: + return (REJECTED, "New certificate requests not supported") ++ is_self_signed = x509.is_self_signed(cert) + + operation = os.environ.get('CERTMONGER_OPERATION') + if operation == 'SUBMIT': + state = 'retrieve' + +- if is_renewable() and is_renewal_master(): ++ if is_self_signed and is_renewal_master(): + state = 'request' + elif operation == 'POLL': + cookie = os.environ.get('CERTMONGER_CA_COOKIE') +@@ -489,7 +461,7 @@ def renew_ca_cert(): + + if state == 'retrieve': + result = call_handler(retrieve_cert) +- if result[0] == REJECTED and not is_renewable(): ++ if result[0] == REJECTED and not is_self_signed: + syslog.syslog(syslog.LOG_ALERT, + "Certificate with subject '%s' is about to expire, " + "use ipa-cacert-manage to renew it" +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 97baa606c960806376e025b5654eea816da207ed..546e1b7b39b323bbaeae3fb57d31ea4152d5e418 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -436,7 +436,7 @@ class CAInstance(DogtagInstance): + self.step("adding 'ipa' CA entry", ensure_ipa_authority_entry) + + self.step("configuring certmonger renewal for lightweight CAs", +- self.__add_lightweight_ca_tracking_requests) ++ self.add_lightweight_ca_tracking_requests) + + if ra_only: + runtime = None +@@ -1246,7 +1246,7 @@ class CAInstance(DogtagInstance): + os.chmod(keyfile, 0o600) + os.chown(keyfile, pent.pw_uid, pent.pw_gid) + +- def __add_lightweight_ca_tracking_requests(self): ++ def add_lightweight_ca_tracking_requests(self): + try: + lwcas = api.Backend.ldap2.get_entries( + base_dn=api.env.basedn, +@@ -1810,11 +1810,10 @@ def add_lightweight_ca_tracking_requests(logger, lwcas): + pin=certmonger.get_pin('internal'), + nickname=nickname, + ca=ipalib.constants.RENEWAL_CA_NAME, ++ profile='caCACert', + pre_command='stop_pkicad', + post_command='renew_ca_cert "%s"' % nickname, + ) +- request_id = certmonger.get_request_id(criteria) +- certmonger.modify(request_id, profile='ipaCACertRenewal') + logger.debug( + 'Lightweight CA renewal: ' + 'added tracking request for "%s"', nickname) +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 855056dc1fa20e813d82ecc5090a14cfc4f91831..96fdadf751ef619e198a861d9f62440c98f3abae 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -974,6 +974,21 @@ def certificate_renewal_update(ca, ds, http): + root_logger.info('CA is not configured') + return False + ++ db = certs.CertDB(api.env.realm, paths.PKI_TOMCAT_ALIAS_DIR) ++ for nickname, _trust_flags in db.list_certs(): ++ if nickname.startswith('caSigningCert cert-pki-ca '): ++ requests.append( ++ { ++ 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, ++ 'cert-nickname': nickname, ++ 'ca': 'dogtag-ipa-ca-renew-agent', ++ 'cert-presave-command': template % 'stop_pkicad', ++ 'cert-postsave-command': ++ (template % ('renew_ca_cert "%s"' % nickname)), ++ 'template-profile': 'caCACert', ++ } ++ ) ++ + # State not set, lets see if we are already configured + for request in requests: + request_id = certmonger.get_request_id(request) +@@ -998,6 +1013,7 @@ def certificate_renewal_update(ca, ds, http): + ca.configure_renewal() + ca.configure_agent_renewal() + ca.track_servercert() ++ ca.add_lightweight_ca_tracking_requests() + ds.start_tracking_certificates(serverid) + http.start_tracking_certificates() + +-- +2.9.3 + diff --git a/SOURCES/0129-cert-fix-cert-find-certificate-when-the-cert-is-not-.patch b/SOURCES/0129-cert-fix-cert-find-certificate-when-the-cert-is-not-.patch deleted file mode 100644 index 49e9537..0000000 --- a/SOURCES/0129-cert-fix-cert-find-certificate-when-the-cert-is-not-.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 95a8519afa82707c8d3b2e60f65cbc4d79d144e2 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 7 Sep 2016 08:06:10 +0200 -Subject: [PATCH] cert: fix cert-find --certificate when the cert is not in - LDAP - -Always return the cert specified in --certificate in cert-find result, even -when the cert is not found in LDAP. - -https://fedorahosted.org/freeipa/ticket/6304 - -Reviewed-By: David Kupka ---- - ipaserver/plugins/cert.py | 12 +++++------- - 1 file changed, 5 insertions(+), 7 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 6495bf1491f939a032fad03fe4ef86839c0575ef..00bae4560d601e28e0b983786bff9144bcc1b065 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1142,17 +1142,15 @@ class cert_find(Search, CertMethod): - rule) - filters.append(filter) - -- cert = options.get('certificate') -- if cert is not None: -- filter = ldap.make_filter_from_attr('usercertificate', cert) -- filters.append(filter) -- - result = collections.OrderedDict() - complete = bool(filters) - -- if cert is None: -+ cert = options.get('certificate') -+ if cert is not None: -+ filter = ldap.make_filter_from_attr('usercertificate', cert) -+ else: - filter = '(usercertificate=*)' -- filters.append(filter) -+ filters.append(filter) - - filter = ldap.combine_filters(filters, ldap.MATCH_ALL) - try: --- -2.7.4 - diff --git a/SOURCES/0130-Make-host-service-cert-revocation-aware-of-lightweig.patch b/SOURCES/0130-Make-host-service-cert-revocation-aware-of-lightweig.patch deleted file mode 100644 index d154616..0000000 --- a/SOURCES/0130-Make-host-service-cert-revocation-aware-of-lightweig.patch +++ /dev/null @@ -1,184 +0,0 @@ -From c9428fe0a1230fb9ea9c18c895c0834678e94da8 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Fri, 26 Aug 2016 15:31:13 +1000 -Subject: [PATCH] Make host/service cert revocation aware of lightweight CAs - -Revocation of host/service certs on host/service deletion or other -operations is broken when cert is issued by a lightweight (sub)CA, -causing the delete operation to be aborted. Look up the issuing CA -and pass it to 'cert_revoke' to fix the issue. - -Fixes: https://fedorahosted.org/freeipa/ticket/6221 -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/host.py | 20 +++++++--------- - ipaserver/plugins/service.py | 56 ++++++++++++++++++++++---------------------- - 2 files changed, 37 insertions(+), 39 deletions(-) - -diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py -index 03c64c637cbba0aee1b6569f3b5dbe200953bff8..2362b6247af87b4ce63c21083e6bc8ac39db0804 100644 ---- a/ipaserver/plugins/host.py -+++ b/ipaserver/plugins/host.py -@@ -843,12 +843,8 @@ class host_del(LDAPDelete): - ) - - if self.api.Command.ca_is_enabled()['result']: -- try: -- entry_attrs = ldap.get_entry(dn, ['usercertificate']) -- except errors.NotFound: -- self.obj.handle_not_found(*keys) -- -- revoke_certs(entry_attrs.get('usercertificate', []), self.log) -+ certs = self.api.Command.cert_find(host=keys)['result'] -+ revoke_certs(certs) - - return dn - -@@ -910,7 +906,9 @@ class host_mod(LDAPUpdate): - old_certs = entry_attrs_old.get('usercertificate', []) - old_certs_der = [x509.normalize_certificate(c) for c in old_certs] - removed_certs_der = set(old_certs_der) - set(certs_der) -- revoke_certs(removed_certs_der, self.log) -+ for der in removed_certs_der: -+ rm_certs = api.Command.cert_find(certificate=der)['result'] -+ revoke_certs(rm_certs) - - if certs: - entry_attrs['usercertificate'] = certs_der -@@ -1196,10 +1194,10 @@ class host_disable(LDAPQuery): - except errors.NotFound: - self.obj.handle_not_found(*keys) - if self.api.Command.ca_is_enabled()['result']: -- certs = entry_attrs.get('usercertificate', []) -+ certs = self.api.Command.cert_find(host=keys)['result'] - - if certs: -- revoke_certs(certs, self.log) -+ revoke_certs(certs) - # Remove the usercertificate altogether - entry_attrs['usercertificate'] = None - ldap.update_entry(entry_attrs) -@@ -1341,8 +1339,8 @@ class host_remove_cert(LDAPRemoveAttributeViaOption): - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) - -- if 'usercertificate' in options: -- revoke_certs(options['usercertificate'], self.log) -+ for cert in options.get('usercertificate', []): -+ revoke_certs(api.Command.cert_find(certificate=cert)['result']) - - return dn - -diff --git a/ipaserver/plugins/service.py b/ipaserver/plugins/service.py -index 04d1916fe989a8651bcc4d44f1914c460be1081c..093525f2e7cb84b18f0658dcb5d7c786e45c6ab6 100644 ---- a/ipaserver/plugins/service.py -+++ b/ipaserver/plugins/service.py -@@ -220,37 +220,38 @@ def validate_certificate(ugettext, cert): - x509.validate_certificate(cert, datatype=x509.DER) - - --def revoke_certs(certs, logger=None): -+def revoke_certs(certs): - """ - revoke the certificates removed from host/service entry -- """ -- for cert in certs: -- try: -- cert = x509.normalize_certificate(cert) -- except errors.CertificateFormatError as e: -- if logger is not None: -- logger.info("Problem decoding certificate: %s" % e) - -- serial = unicode(x509.get_serial_number(cert, x509.DER)) -+ :param certs: Output of a 'cert_find' command. - -- try: -- result = api.Command['cert_show'](unicode(serial))['result'] -- except errors.CertificateOperationError: -- continue -- if 'revocation_reason' in result: -+ """ -+ for cert in certs: -+ if 'cacn' not in cert: -+ # Cert is known to IPA, but has no associated CA. -+ # If it was issued by 3rd-party CA, we can't revoke it. -+ # If it was issued by a Dogtag lightweight CA that was -+ # subsequently deleted, we can't revoke it via IPA. -+ # We could go directly to Dogtag to revoke it, but the -+ # issuer's cert should have been revoked so never mind. - continue -- if x509.normalize_certificate(result['certificate']) != cert: -+ -+ if cert['revoked']: -+ # cert is already revoked - continue - - try: -- api.Command['cert_revoke'](unicode(serial), -- revocation_reason=4) -+ api.Command['cert_revoke']( -+ cert['serial_number'], -+ cacn=cert['cacn'], -+ revocation_reason=4, -+ ) - except errors.NotImplementedError: - # some CA's might not implement revoke - pass - - -- - def set_certificate_attrs(entry_attrs): - """ - Set individual attributes from some values from a certificate. -@@ -674,11 +675,8 @@ class service_del(LDAPDelete): - # custom services allow them to manage them. - check_required_principal(ldap, keys[-1]) - if self.api.Command.ca_is_enabled()['result']: -- try: -- entry_attrs = ldap.get_entry(dn, ['usercertificate']) -- except errors.NotFound: -- self.obj.handle_not_found(*keys) -- revoke_certs(entry_attrs.get('usercertificate', []), self.log) -+ certs = self.api.Command.cert_find(service=keys)['result'] -+ revoke_certs(certs) - - return dn - -@@ -711,7 +709,9 @@ class service_mod(LDAPUpdate): - old_certs = entry_attrs_old.get('usercertificate', []) - old_certs_der = [x509.normalize_certificate(c) for c in old_certs] - removed_certs_der = set(old_certs_der) - set(certs_der) -- revoke_certs(removed_certs_der, self.log) -+ for der in removed_certs_der: -+ rm_certs = api.Command.cert_find(certificate=der)['result'] -+ revoke_certs(rm_certs) - - if certs: - entry_attrs['usercertificate'] = certs_der -@@ -950,10 +950,10 @@ class service_disable(LDAPQuery): - done_work = False - - if self.api.Command.ca_is_enabled()['result']: -- certs = entry_attrs.get('usercertificate', []) -+ certs = self.api.Command.cert_find(service=keys)['result'] - - if len(certs) > 0: -- revoke_certs(certs, self.log) -+ revoke_certs(certs) - # Remove the usercertificate altogether - entry_attrs['usercertificate'] = None - ldap.update_entry(entry_attrs) -@@ -989,8 +989,8 @@ class service_remove_cert(LDAPRemoveAttributeViaOption): - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - assert isinstance(dn, DN) - -- if 'usercertificate' in options: -- revoke_certs(options['usercertificate'], self.log) -+ for cert in options.get('usercertificate', []): -+ revoke_certs(api.Command.cert_find(certificate=cert)['result']) - - return dn - --- -2.7.4 - diff --git a/SOURCES/0130-renew-agent-allow-reusing-existing-certs.patch b/SOURCES/0130-renew-agent-allow-reusing-existing-certs.patch new file mode 100644 index 0000000..e1db085 --- /dev/null +++ b/SOURCES/0130-renew-agent-allow-reusing-existing-certs.patch @@ -0,0 +1,260 @@ +From 854ceb13a72630ba357ca5c1ec8ac5b320a4c9c5 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 19 Apr 2017 12:55:47 +0000 +Subject: [PATCH] renew agent: allow reusing existing certs + +Add a switch which makes `dogtag-ipa-ca-renew-agent-submit` reuse the +existing certificate rather than request a new one from the CA while +maintaining LDAP replication of the certificate. + +Make this available as a new `dogtag-ipa-ca-renew-agent-reuse` certmonger +CA. + +This allows redoing the LDAP replication and reexecuting pre- and post-save +commands of a tracking request without reissuing the certificate. + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + .../certmonger/dogtag-ipa-ca-renew-agent-submit | 67 ++++++++++++++++------ + ipaserver/install/cainstance.py | 8 ++- + ipaserver/install/dogtaginstance.py | 15 +++-- + 3 files changed, 63 insertions(+), 27 deletions(-) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index 51b0880c5b57758845e2ffa0c9545bbca7e8c751..7b5489555d069856a6da7a21b5ab2b0f4dd4a41c 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -193,10 +193,18 @@ def call_handler(_handler, *args, **kwargs): + + return result + +-def request_cert(): ++ ++def request_cert(reuse_existing, **kwargs): + """ + Request certificate from IPA CA. + """ ++ if reuse_existing: ++ cert = os.environ.get('CERTMONGER_CERTIFICATE') ++ if cert: ++ return (ISSUED, cert) ++ else: ++ return (REJECTED, "New certificate requests not supported") ++ + syslog.syslog(syslog.LOG_NOTICE, + "Forwarding request to dogtag-ipa-renew-agent") + +@@ -231,7 +239,8 @@ def request_cert(): + else: + return (rc, stdout) + +-def store_cert(): ++ ++def store_cert(**kwargs): + """ + Store certificate in LDAP. + """ +@@ -292,7 +301,8 @@ def store_cert(): + + return (ISSUED, cert) + +-def request_and_store_cert(): ++ ++def request_and_store_cert(**kwargs): + """ + Request certificate from IPA CA and store it in LDAP. + """ +@@ -318,7 +328,7 @@ def request_and_store_cert(): + else: + os.environ['CERTMONGER_CA_COOKIE'] = cookie + +- result = call_handler(request_cert) ++ result = call_handler(request_cert, **kwargs) + if result[0] == WAIT: + return (result[0], 'request:%s' % result[1]) + elif result[0] == WAIT_WITH_DELAY: +@@ -337,7 +347,7 @@ def request_and_store_cert(): + os.environ['CERTMONGER_CA_COOKIE'] = cookie + os.environ['CERTMONGER_CERTIFICATE'] = cert + +- result = call_handler(store_cert) ++ result = call_handler(store_cert, **kwargs) + if result[0] == WAIT: + return (result[0], 'store:%s:%s' % (cert, result[1])) + elif result[0] == WAIT_WITH_DELAY: +@@ -345,7 +355,8 @@ def request_and_store_cert(): + else: + return result + +-def retrieve_or_reuse_cert(): ++ ++def retrieve_or_reuse_cert(**kwargs): + """ + Retrieve certificate from LDAP. If the certificate is not available, reuse + the old certificate. +@@ -373,7 +384,8 @@ def retrieve_or_reuse_cert(): + + return (ISSUED, cert) + +-def retrieve_cert_continuous(): ++ ++def retrieve_cert_continuous(reuse_existing, **kwargs): + """ + Retrieve new certificate from LDAP. Repeat every eight hours until the + certificate is available. +@@ -382,8 +394,10 @@ def retrieve_cert_continuous(): + if old_cert: + old_cert = x509.normalize_certificate(old_cert) + +- result = call_handler(retrieve_or_reuse_cert) +- if result[0] != ISSUED: ++ result = call_handler(retrieve_or_reuse_cert, ++ reuse_existing=reuse_existing, ++ **kwargs) ++ if result[0] != ISSUED or reuse_existing: + return result + + new_cert = x509.normalize_certificate(result[1]) +@@ -394,17 +408,19 @@ def retrieve_cert_continuous(): + + return result + +-def retrieve_cert(): ++ ++def retrieve_cert(**kwargs): + """ + Retrieve new certificate from LDAP. + """ +- result = call_handler(retrieve_cert_continuous) ++ result = call_handler(retrieve_cert_continuous, **kwargs) + if result[0] == WAIT_WITH_DELAY: + return (REJECTED, "Updated certificate not available") + + return result + +-def export_csr(): ++ ++def export_csr(**kwargs): + """ + This does not actually renew the cert, it just writes the CSR provided + by certmonger to /var/lib/ipa/ca.csr and returns the existing cert. +@@ -430,7 +446,8 @@ def export_csr(): + + return (ISSUED, cert) + +-def renew_ca_cert(): ++ ++def renew_ca_cert(reuse_existing, **kwargs): + """ + This is used for automatic CA certificate renewal. + """ +@@ -443,7 +460,7 @@ def renew_ca_cert(): + if operation == 'SUBMIT': + state = 'retrieve' + +- if is_self_signed and is_renewal_master(): ++ if is_self_signed and not reuse_existing and is_renewal_master(): + state = 'request' + elif operation == 'POLL': + cookie = os.environ.get('CERTMONGER_CA_COOKIE') +@@ -460,8 +477,10 @@ def renew_ca_cert(): + return (OPERATION_NOT_SUPPORTED_BY_HELPER,) + + if state == 'retrieve': +- result = call_handler(retrieve_cert) +- if result[0] == REJECTED and not is_self_signed: ++ result = call_handler(retrieve_cert, ++ reuse_existing=reuse_existing, ++ **kwargs) ++ if result[0] == REJECTED and not is_self_signed and not reuse_existing: + syslog.syslog(syslog.LOG_ALERT, + "Certificate with subject '%s' is about to expire, " + "use ipa-cacert-manage to renew it" +@@ -469,7 +488,9 @@ def renew_ca_cert(): + elif state == 'request': + profile = os.environ['CERTMONGER_CA_PROFILE'] + os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert' +- result = call_handler(request_and_store_cert) ++ result = call_handler(request_and_store_cert, ++ reuse_existing=reuse_existing, ++ **kwargs) + os.environ['CERTMONGER_CA_PROFILE'] = profile + + if result[0] == WAIT: +@@ -480,6 +501,16 @@ def renew_ca_cert(): + return result + + def main(): ++ kwargs = { ++ 'reuse_existing': False, ++ } ++ try: ++ sys.argv.remove('--reuse-existing') ++ except ValueError: ++ pass ++ else: ++ kwargs['reuse_existing'] = True ++ + handlers = { + 'ipaStorage': store_cert, + 'ipaRetrievalOrReuse': retrieve_or_reuse_cert, +@@ -515,7 +546,7 @@ def main(): + handler = request_cert + handler = handlers.get(profile, handler) + +- res = call_handler(handler) ++ res = call_handler(handler, **kwargs) + for item in res[1:]: + print(item) + return res[0] +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index 546e1b7b39b323bbaeae3fb57d31ea4152d5e418..ff5432d1a7460f1b853c7cf7490b3604c82cd1f7 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -964,9 +964,11 @@ class CAInstance(DogtagInstance): + 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-ca-renew-agent') +- if path: +- iface.remove_known_ca(path) ++ for suffix in ['', '-reuse']: ++ name = 'dogtag-ipa-ca-renew-agent' + suffix ++ path = iface.find_ca_by_nickname(name) ++ if path: ++ iface.remove_known_ca(path) + + cmonger.stop() + +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index 356358adf1b60e236ce821fb44a77ca5f8c1942f..e0515973f7a598b30c6f12675b9ebdbfd0cf3423 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -265,12 +265,15 @@ class DogtagInstance(service.Service): + 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-ca-renew-agent') +- if not path: +- iface.add_known_ca( +- 'dogtag-ipa-ca-renew-agent', +- paths.DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT, +- dbus.Array([], dbus.Signature('s'))) ++ for suffix, args in [('', ''), ('-reuse', ' --reuse-existing')]: ++ name = 'dogtag-ipa-ca-renew-agent' + suffix ++ path = iface.find_ca_by_nickname(name) ++ if not path: ++ command = paths.DOGTAG_IPA_CA_RENEW_AGENT_SUBMIT + args ++ iface.add_known_ca( ++ name, ++ command, ++ dbus.Array([], dbus.Signature('s'))) + + def __get_pin(self): + try: +-- +2.9.3 + diff --git a/SOURCES/0131-Fix-regression-introduced-in-ipa-certupdate.patch b/SOURCES/0131-Fix-regression-introduced-in-ipa-certupdate.patch deleted file mode 100644 index 18cc8e1..0000000 --- a/SOURCES/0131-Fix-regression-introduced-in-ipa-certupdate.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 29933c3f480344b7066554f3e66874c2aa4625a8 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Fri, 9 Sep 2016 15:04:35 +0200 -Subject: [PATCH] Fix regression introduced in ipa-certupdate - -The fix for 6288 was overwritten by commit 08b768313020c45bfa82d67cd214afabf605f4b3. - -https://fedorahosted.org/freeipa/ticket/6288 - -Reviewed-By: Martin Babinsky ---- - ipaclient/ipa_certupdate.py | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ipaclient/ipa_certupdate.py b/ipaclient/ipa_certupdate.py -index 4b97b85b83c8b1a130d6db9cdcc7a76fc569af9e..52f73e196c8f18c9f944dd7eeaa442780e17cb7d 100644 ---- a/ipaclient/ipa_certupdate.py -+++ b/ipaclient/ipa_certupdate.py -@@ -83,7 +83,10 @@ class CertUpdate(admintool.AdminTool): - certs = certstore.get_ca_certs(ldap, api.env.basedn, - api.env.realm, ca_enabled) - -- lwcas = api.Command.ca_find()['result'] -+ if ca_enabled: -+ lwcas = api.Command.ca_find()['result'] -+ else: -+ lwcas = [] - - api.Backend.rpcclient.disconnect() - finally: --- -2.9.3 - diff --git a/SOURCES/0131-renew-agent-always-export-CSR-on-IPA-CA-certificate-.patch b/SOURCES/0131-renew-agent-always-export-CSR-on-IPA-CA-certificate-.patch new file mode 100644 index 0000000..c13f5f9 --- /dev/null +++ b/SOURCES/0131-renew-agent-always-export-CSR-on-IPA-CA-certificate-.patch @@ -0,0 +1,51 @@ +From da3e6ab68f4f40b2851770fcc928b5bb93831c42 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 24 Apr 2017 06:20:07 +0000 +Subject: [PATCH] renew agent: always export CSR on IPA CA certificate renewal + +Make sure a CSR is exported for the IPA CA whenever certmonger detects that +the CA certificate is about to expire. + +This is a pre-requisite for using the `dogtag-ipa-ca-renew-agent-reuse` CA +instead of the `ipaCSRExport` virtual profile to export the CSR. + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + install/certmonger/dogtag-ipa-ca-renew-agent-submit | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index 7b5489555d069856a6da7a21b5ab2b0f4dd4a41c..657a1bc638e1da680522c638e92914098fc6ab4b 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -451,6 +451,10 @@ def renew_ca_cert(reuse_existing, **kwargs): + """ + This is used for automatic CA certificate renewal. + """ ++ csr = os.environ.get('CERTMONGER_CSR') ++ if not csr: ++ return (UNCONFIGURED, "Certificate request not provided") ++ + cert = os.environ.get('CERTMONGER_CERTIFICATE') + if not cert: + return (REJECTED, "New certificate requests not supported") +@@ -462,6 +466,13 @@ def renew_ca_cert(reuse_existing, **kwargs): + + if is_self_signed and not reuse_existing and is_renewal_master(): + state = 'request' ++ ++ csr_file = paths.IPA_CA_CSR ++ try: ++ with open(csr_file, 'wb') as f: ++ f.write(csr) ++ except Exception as e: ++ return (UNREACHABLE, "Failed to write %s: %s" % (csr_file, e)) + elif operation == 'POLL': + cookie = os.environ.get('CERTMONGER_CA_COOKIE') + if not cookie: +-- +2.9.3 + diff --git a/SOURCES/0132-Start-named-during-configuration-upgrade.patch b/SOURCES/0132-Start-named-during-configuration-upgrade.patch deleted file mode 100644 index 89b1e1f..0000000 --- a/SOURCES/0132-Start-named-during-configuration-upgrade.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 82ffbefb88013e125e8377fe525fdef1de0c7ad4 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Tue, 13 Sep 2016 18:37:43 +0200 -Subject: [PATCH] Start named during configuration upgrade. - -Some upgrade steps require bind running, to be succesfull. Upgrader -makes sure that bind starts. - -https://fedorahosted.org/freeipa/ticket/6205 - -Reviewed-By: Martin Babinsky ---- - ipaserver/install/server/upgrade.py | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index 43427178b11f63797a9537eadee836d7cf224311..e1343f423cec21f02e3d9581012496baa7b30cc6 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1706,6 +1706,15 @@ def upgrade_configuration(): - cleanup_kdc(fstore) - cleanup_adtrust(fstore) - setup_firefox_extension(fstore) -+ -+ bind = bindinstance.BindInstance(fstore) -+ if bind.is_configured() and not bind.is_running(): -+ # some upgrade steps may require bind running -+ bind_started = True -+ bind.start() -+ else: -+ bind_started = False -+ - add_ca_dns_records() - - # Any of the following functions returns True iff the named.conf file -@@ -1736,6 +1745,9 @@ def upgrade_configuration(): - except ipautil.CalledProcessError as e: - root_logger.error("Failed to restart %s: %s", bind.service_name, e) - -+ if bind_started: -+ bind.stop() -+ - custodia = custodiainstance.CustodiaInstance(api.env.host, api.env.realm) - custodia.upgrade_instance() - --- -2.7.4 - diff --git a/SOURCES/0132-renew-agent-get-rid-of-virtual-profiles.patch b/SOURCES/0132-renew-agent-get-rid-of-virtual-profiles.patch new file mode 100644 index 0000000..3088979 --- /dev/null +++ b/SOURCES/0132-renew-agent-get-rid-of-virtual-profiles.patch @@ -0,0 +1,321 @@ +From 6a30753c5a437240e4678ef4acae3255ad6d15ee Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 24 Apr 2017 06:40:11 +0000 +Subject: [PATCH] renew agent: get rid of virtual profiles + +Replace all uses of virtual profiles with `dogtag-ipa-ca-renew-agent-reuse` +and remove profile from the IPA CA certificate tracking request. + +This prevents virtual profiles from making their way into CSRs and in turn +being rejected by certain CAs. This affected the IPA CA CSR with Microsoft +CS in particular. + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + .../certmonger/dogtag-ipa-ca-renew-agent-submit | 50 ++++------------------ + ipaclient/install/ipa_certupdate.py | 4 +- + ipalib/install/certmonger.py | 25 ++++++++--- + ipaserver/install/cainstance.py | 8 ++-- + ipaserver/install/dogtaginstance.py | 6 +-- + ipaserver/install/ipa_cacert_manage.py | 12 +++--- + ipaserver/install/krainstance.py | 6 +-- + ipaserver/install/server/upgrade.py | 2 +- + 8 files changed, 46 insertions(+), 67 deletions(-) + +diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +index 657a1bc638e1da680522c638e92914098fc6ab4b..3d3e791449014082060ecdc50118a28a9ef315b8 100755 +--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit ++++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit +@@ -297,7 +297,7 @@ def store_cert(**kwargs): + syslog.syslog( + syslog.LOG_ERR, + "Giving up. To retry storing the certificate, resubmit the " +- "request with profile \"ipaStorage\"") ++ "request with CA \"dogtag-ipa-ca-renew-agent-reuse\"") + + return (ISSUED, cert) + +@@ -420,33 +420,6 @@ def retrieve_cert(**kwargs): + return result + + +-def export_csr(**kwargs): +- """ +- This does not actually renew the cert, it just writes the CSR provided +- by certmonger to /var/lib/ipa/ca.csr and returns the existing cert. +- """ +- operation = os.environ.get('CERTMONGER_OPERATION') +- if operation != 'SUBMIT': +- return (OPERATION_NOT_SUPPORTED_BY_HELPER,) +- +- csr = os.environ.get('CERTMONGER_CSR') +- if not csr: +- return (UNCONFIGURED, "Certificate request not provided") +- +- cert = os.environ.get('CERTMONGER_CERTIFICATE') +- if not cert: +- return (REJECTED, "New certificate requests not supported") +- +- csr_file = paths.IPA_CA_CSR +- try: +- with open(csr_file, 'wb') as f: +- f.write(csr) +- except Exception as e: +- return (UNREACHABLE, "Failed to write %s: %s" % (csr_file, e)) +- +- return (ISSUED, cert) +- +- + def renew_ca_cert(reuse_existing, **kwargs): + """ + This is used for automatic CA certificate renewal. +@@ -497,12 +470,15 @@ def renew_ca_cert(reuse_existing, **kwargs): + "use ipa-cacert-manage to renew it" + % (os.environ.get("CERTMONGER_REQ_SUBJECT"),)) + elif state == 'request': +- profile = os.environ['CERTMONGER_CA_PROFILE'] ++ profile = os.environ.get('CERTMONGER_CA_PROFILE') + os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert' + result = call_handler(request_and_store_cert, + reuse_existing=reuse_existing, + **kwargs) +- os.environ['CERTMONGER_CA_PROFILE'] = profile ++ if profile is not None: ++ os.environ['CERTMONGER_CA_PROFILE'] = profile ++ else: ++ del os.environ['CERTMONGER_CA_PROFILE'] + + if result[0] == WAIT: + return (result[0], '%s:%s' % (state, result[1])) +@@ -522,14 +498,6 @@ def main(): + else: + kwargs['reuse_existing'] = True + +- handlers = { +- 'ipaStorage': store_cert, +- 'ipaRetrievalOrReuse': retrieve_or_reuse_cert, +- 'ipaRetrieval': retrieve_cert, +- 'ipaCSRExport': export_csr, +- 'ipaCACertRenewal': renew_ca_cert, +- } +- + api.bootstrap(in_server=True, context='renew', confdir=paths.ETC_IPA) + api.finalize() + +@@ -547,15 +515,15 @@ def main(): + + api.Backend.ldap2.connect() + +- profile = os.environ.get('CERTMONGER_CA_PROFILE') +- if is_replicated(): ++ if get_nickname() == IPA_CA_NICKNAME: ++ handler = renew_ca_cert ++ elif is_replicated(): + if is_renewal_master(): + handler = request_and_store_cert + else: + handler = retrieve_cert_continuous + else: + handler = request_cert +- handler = handlers.get(profile, handler) + + res = call_handler(handler, **kwargs) + for item in res[1:]: +diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py +index d6ffbde1900280b548877752726e4f066632877a..7dc88f07ae14e5416f6fe3dc8400b7d4bcabef72 100644 +--- a/ipaclient/install/ipa_certupdate.py ++++ b/ipaclient/install/ipa_certupdate.py +@@ -153,7 +153,7 @@ class CertUpdate(admintool.AdminTool): + + self.log.debug("resubmitting certmonger request '%s'", request_id) + certmonger.resubmit_request( +- request_id, profile='ipaRetrievalOrReuse') ++ request_id, ca='dogtag-ipa-ca-renew-agent-reuse', profile='') + try: + state = certmonger.wait_for_request(request_id, timeout) + except RuntimeError: +@@ -167,7 +167,7 @@ class CertUpdate(admintool.AdminTool): + "please check the request manually" % request_id) + + self.log.debug("modifying certmonger request '%s'", request_id) +- certmonger.modify(request_id, profile='ipaCACertRenewal') ++ certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent') + + self.update_file(paths.CA_CRT, certs) + +diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py +index 2a7876ea9ba986f57c00fc7ad61d10fe91894f55..5709853ffebdbf58929b9a935e906ae67341bea8 100644 +--- a/ipalib/install/certmonger.py ++++ b/ipalib/install/certmonger.py +@@ -501,18 +501,29 @@ def stop_tracking(secdir=None, request_id=None, nickname=None, certfile=None): + request.parent.obj_if.remove_request(request.path) + + +-def modify(request_id, profile=None): +- if profile: ++def modify(request_id, ca=None, profile=None): ++ if ca or profile: + request = _get_request({'nickname': request_id}) +- if request: +- request.obj_if.modify({'template-profile': profile}) ++ update = {} ++ if ca is not None: ++ cm = _certmonger() ++ update['CA'] = cm.obj_if.find_ca_by_nickname(ca) ++ if profile is not None: ++ update['template-profile'] = profile ++ request.obj_if.modify(update) + + +-def resubmit_request(request_id, profile=None): ++def resubmit_request(request_id, ca=None, profile=None): + request = _get_request({'nickname': request_id}) + if request: +- if profile: +- request.obj_if.modify({'template-profile': profile}) ++ if ca or profile: ++ update = {} ++ if ca is not None: ++ cm = _certmonger() ++ update['CA'] = cm.obj_if.find_ca_by_nickname(ca) ++ if profile is not None: ++ update['template-profile'] = profile ++ request.obj_if.modify(update) + request.obj_if.resubmit() + + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index ff5432d1a7460f1b853c7cf7490b3604c82cd1f7..a4aa4f2069277181501ebd92f3795c452b10acd0 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -279,10 +279,10 @@ class CAInstance(DogtagInstance): + 2 = have signed cert, continue installation + """ + +- tracking_reqs = (('auditSigningCert cert-pki-ca', None), +- ('ocspSigningCert cert-pki-ca', None), +- ('subsystemCert cert-pki-ca', None), +- ('caSigningCert cert-pki-ca', 'ipaCACertRenewal')) ++ tracking_reqs = ('auditSigningCert cert-pki-ca', ++ 'ocspSigningCert cert-pki-ca', ++ 'subsystemCert cert-pki-ca', ++ 'caSigningCert cert-pki-ca') + server_cert_name = 'Server-Cert cert-pki-ca' + + def __init__(self, realm=None, host_name=None): +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index e0515973f7a598b30c6f12675b9ebdbfd0cf3423..3ba13815055612c5fff44831c8f874e6175d94cd 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -287,7 +287,7 @@ class DogtagInstance(service.Service): + """ Configure certmonger to renew system certs """ + pin = self.__get_pin() + +- for nickname, profile in self.tracking_reqs: ++ for nickname in self.tracking_reqs: + try: + certmonger.start_tracking( + certpath=self.nss_db, +@@ -296,7 +296,7 @@ class DogtagInstance(service.Service): + pin=pin, + pre_command='stop_pkicad', + post_command='renew_ca_cert "%s"' % nickname, +- profile=profile) ++ ) + except RuntimeError as e: + self.log.error( + "certmonger failed to start tracking certificate: %s", e) +@@ -331,7 +331,7 @@ class DogtagInstance(service.Service): + services.knownservices.messagebus.start() + cmonger.start() + +- nicknames = [nickname for nickname, _profile in self.tracking_reqs] ++ nicknames = self.tracking_reqs + if self.server_cert_name is not None: + nicknames.append(self.server_cert_name) + +diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py +index 363ba378ab206fae5c220b754f212666f20384af..6d28c62b36b3909c9a3d95a5c6c84d1779fe4c33 100644 +--- a/ipaserver/install/ipa_cacert_manage.py ++++ b/ipaserver/install/ipa_cacert_manage.py +@@ -172,14 +172,14 @@ class CACertManage(admintool.AdminTool): + except errors.NotFound: + raise admintool.ScriptError("CA renewal master not found") + +- self.resubmit_request(ca, 'caCACert') ++ self.resubmit_request() + + print("CA certificate successfully renewed") + + def renew_external_step_1(self, ca): + print("Exporting CA certificate signing request, please wait") + +- self.resubmit_request(ca, 'ipaCSRExport') ++ self.resubmit_request('dogtag-ipa-ca-renew-agent-reuse') + + print(("The next step is to get %s signed by your CA and re-run " + "ipa-cacert-manage as:" % paths.IPA_CA_CSR)) +@@ -282,15 +282,15 @@ class CACertManage(admintool.AdminTool): + except errors.NotFound: + raise admintool.ScriptError("CA renewal master not found") + +- self.resubmit_request(ca, 'ipaRetrieval') ++ self.resubmit_request('dogtag-ipa-ca-renew-agent-reuse') + + print("CA certificate successfully renewed") + +- def resubmit_request(self, ca, profile): ++ def resubmit_request(self, ca='dogtag-ipa-ca-renew-agent'): + timeout = api.env.startup_timeout + 60 + + self.log.debug("resubmitting certmonger request '%s'", self.request_id) +- certmonger.resubmit_request(self.request_id, profile=profile) ++ certmonger.resubmit_request(self.request_id, ca=ca, profile='') + try: + state = certmonger.wait_for_request(self.request_id, timeout) + except RuntimeError: +@@ -304,7 +304,7 @@ class CACertManage(admintool.AdminTool): + "please check the request manually" % self.request_id) + + self.log.debug("modifying certmonger request '%s'", self.request_id) +- certmonger.modify(self.request_id, profile='ipaCACertRenewal') ++ certmonger.modify(self.request_id, ca='dogtag-ipa-ca-renew-agent') + + def install(self): + print("Installing CA certificate, please wait") +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index c39d6874a9d685f91b5d30ea1954320b8ee0c1ed..abb81897a404613e20be10d348096402ef08624b 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -60,9 +60,9 @@ class KRAInstance(DogtagInstance): + be the same for both the CA and KRA. + """ + +- tracking_reqs = (('auditSigningCert cert-pki-kra', None), +- ('transportCert cert-pki-kra', None), +- ('storageCert cert-pki-kra', None)) ++ tracking_reqs = ('auditSigningCert cert-pki-kra', ++ 'transportCert cert-pki-kra', ++ 'storageCert cert-pki-kra') + + def __init__(self, realm): + super(KRAInstance, self).__init__( +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 96fdadf751ef619e198a861d9f62440c98f3abae..5e5c83731d3d3415deb61271baa7865c62f60336 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -937,7 +937,7 @@ def certificate_renewal_update(ca, ds, http): + 'cert-presave-command': template % 'stop_pkicad', + 'cert-postsave-command': + (template % 'renew_ca_cert "caSigningCert cert-pki-ca"'), +- 'template-profile': 'ipaCACertRenewal', ++ 'template-profile': '', + }, + { + 'cert-database': paths.PKI_TOMCAT_ALIAS_DIR, +-- +2.9.3 + diff --git a/SOURCES/0133-Catch-DNS-exceptions-during-emptyzones-named.conf-up.patch b/SOURCES/0133-Catch-DNS-exceptions-during-emptyzones-named.conf-up.patch deleted file mode 100644 index db5de87..0000000 --- a/SOURCES/0133-Catch-DNS-exceptions-during-emptyzones-named.conf-up.patch +++ /dev/null @@ -1,54 +0,0 @@ -From bbc716fa6c58305e81962ea9f7e7e710ff51ad99 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Tue, 13 Sep 2016 19:12:40 +0200 -Subject: [PATCH] Catch DNS exceptions during emptyzones named.conf upgrade - -For some reasons named may not be runnig and this cause fail of this -upgrade step. This step is not critical so only ERROR message with -recommendation is shown. - -https://fedorahosted.org/freeipa/ticket/6205 - -Reviewed-By: Martin Babinsky ---- - ipaserver/install/server/upgrade.py | 17 ++++++++++++++--- - 1 file changed, 14 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index e1343f423cec21f02e3d9581012496baa7b30cc6..3b23c2e688f436453cfa185f87780b7ff5cafa16 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -11,6 +11,8 @@ import pwd - import fileinput - import sys - -+import dns.exception -+ - import six - from six.moves.configparser import SafeConfigParser - -@@ -840,9 +842,18 @@ def named_update_global_forwarder_policy(): - 'forward_policy_conflict_with_empty_zones_handled', - True - ) -- if not dnsutil.has_empty_zone_addresses(api.env.host): -- # guess: local server does not have IP addresses from private ranges -- # so hopefully automatic empty zones are not a problem -+ try: -+ if not dnsutil.has_empty_zone_addresses(api.env.host): -+ # guess: local server does not have IP addresses from private -+ # ranges so hopefully automatic empty zones are not a problem -+ return False -+ except dns.exception.DNSException as ex: -+ root_logger.error( -+ 'Skipping update of global DNS forwarder in named.conf: ' -+ 'Unable to determine if local server is using an ' -+ 'IP address belonging to an automatic empty zone. ' -+ 'Consider changing forwarding policy to "only". ' -+ 'DNS exception: %s', ex) - return False - - if bindinstance.named_conf_get_directive( --- -2.7.4 - diff --git a/SOURCES/0133-ipa-cacert-manage-add-external-ca-type.patch b/SOURCES/0133-ipa-cacert-manage-add-external-ca-type.patch new file mode 100644 index 0000000..0e037b2 --- /dev/null +++ b/SOURCES/0133-ipa-cacert-manage-add-external-ca-type.patch @@ -0,0 +1,97 @@ +From 993d41e5105653412cec40b8e2a386da802a62bb Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 24 Apr 2017 07:10:41 +0000 +Subject: [PATCH] ipa-cacert-manage: add --external-ca-type + +Add the `--external-ca-type`, as known from `ipa-server-install` and +`ipa-ca-install`, to `ipa-cacert-manage`. + +This allows creating IPA CA CSRs suitable for use with Microsoft CS using +`ipa-cacert-manage`: + +``` +ipa-cacert-manage renew --external-ca --external-ca-type=ms-cs +``` + +https://pagure.io/freeipa/issue/5799 + +Reviewed-By: David Kupka +Reviewed-By: Stanislav Laznicka +--- + install/tools/man/ipa-cacert-manage.1 | 3 +++ + ipaserver/install/ipa_cacert_manage.py | 21 +++++++++++++++++---- + 2 files changed, 20 insertions(+), 4 deletions(-) + +diff --git a/install/tools/man/ipa-cacert-manage.1 b/install/tools/man/ipa-cacert-manage.1 +index 128edd8bd2500a09f406da8dc01a53b269007ab0..e36258d0f96aa1050fe88b05f4fe9a1a8f9a7978 100644 +--- a/install/tools/man/ipa-cacert-manage.1 ++++ b/install/tools/man/ipa-cacert-manage.1 +@@ -78,6 +78,9 @@ Sign the renewed certificate by itself. + \fB\-\-external\-ca\fR + Sign the renewed certificate by external CA. + .TP ++\fB\-\-external\-ca\-type\fR=\fITYPE\fR ++Type of the external CA. Possible values are "generic", "ms-cs". Default value is "generic". Use "ms-cs" to include template name required by Microsoft Certificate Services (MS CS) in the generated CSR. ++.TP + \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. + .RE +diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py +index 6d28c62b36b3909c9a3d95a5c6c84d1779fe4c33..3b732e4dcbb5c9b4dfbb9e3608bc7d7afd3e10c2 100644 +--- a/ipaserver/install/ipa_cacert_manage.py ++++ b/ipaserver/install/ipa_cacert_manage.py +@@ -54,6 +54,12 @@ class CACertManage(admintool.AdminTool): + "--self-signed", dest='self_signed', + action='store_true', + help="Sign the renewed certificate by itself") ++ ext_cas = ("generic", "ms-cs") ++ renew_group.add_option( ++ "--external-ca-type", dest="external_ca_type", ++ type="choice", choices=ext_cas, ++ metavar="{{{0}}}".format(",".join(ext_cas)), ++ help="Type of the external CA. Default: generic") + renew_group.add_option( + "--external-ca", dest='self_signed', + action='store_false', +@@ -179,7 +185,12 @@ class CACertManage(admintool.AdminTool): + def renew_external_step_1(self, ca): + print("Exporting CA certificate signing request, please wait") + +- self.resubmit_request('dogtag-ipa-ca-renew-agent-reuse') ++ if self.options.external_ca_type == 'ms-cs': ++ profile = 'SubCA' ++ else: ++ profile = '' ++ ++ self.resubmit_request('dogtag-ipa-ca-renew-agent-reuse', profile) + + print(("The next step is to get %s signed by your CA and re-run " + "ipa-cacert-manage as:" % paths.IPA_CA_CSR)) +@@ -286,11 +297,11 @@ class CACertManage(admintool.AdminTool): + + print("CA certificate successfully renewed") + +- def resubmit_request(self, ca='dogtag-ipa-ca-renew-agent'): ++ def resubmit_request(self, ca='dogtag-ipa-ca-renew-agent', profile=''): + timeout = api.env.startup_timeout + 60 + + self.log.debug("resubmitting certmonger request '%s'", self.request_id) +- certmonger.resubmit_request(self.request_id, ca=ca, profile='') ++ certmonger.resubmit_request(self.request_id, ca=ca, profile=profile) + try: + state = certmonger.wait_for_request(self.request_id, timeout) + except RuntimeError: +@@ -304,7 +315,9 @@ class CACertManage(admintool.AdminTool): + "please check the request manually" % self.request_id) + + self.log.debug("modifying certmonger request '%s'", self.request_id) +- certmonger.modify(self.request_id, ca='dogtag-ipa-ca-renew-agent') ++ certmonger.modify(self.request_id, ++ ca='dogtag-ipa-ca-renew-agent', ++ profile='') + + def install(self): + print("Installing CA certificate, please wait") +-- +2.9.3 + diff --git a/SOURCES/0134-Fixing-adding-authenticator-indicators-to-host.patch b/SOURCES/0134-Fixing-adding-authenticator-indicators-to-host.patch new file mode 100644 index 0000000..e080db4 --- /dev/null +++ b/SOURCES/0134-Fixing-adding-authenticator-indicators-to-host.patch @@ -0,0 +1,70 @@ +From 43871c023ac22a0ae2c4b5fb264b69c6e8029f49 Mon Sep 17 00:00:00 2001 +From: Felipe Volpone +Date: Thu, 11 May 2017 10:26:03 -0300 +Subject: [PATCH] Fixing adding authenticator indicators to host + +The check for krbprincipalaux in the entries is now made +case-insensitively. + +https://pagure.io/freeipa/issue/6911 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Petr Vobornik +--- + ipaserver/plugins/host.py | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py +index dcadd54a10692f64f0464d964f43c7881875d433..1e1f9d82dfdfcf9e7fef65ce729cd8ee7b76e605 100644 +--- a/ipaserver/plugins/host.py ++++ b/ipaserver/plugins/host.py +@@ -884,7 +884,8 @@ class host_mod(LDAPUpdate): + msg = 'Principal name already set, it is unchangeable.' + raise errors.ACIError(info=msg) + obj_classes = entry_attrs_old['objectclass'] +- if 'krbprincipalaux' not in obj_classes: ++ if 'krbprincipalaux' not in (item.lower() for item in ++ obj_classes): + obj_classes.append('krbprincipalaux') + entry_attrs['objectclass'] = obj_classes + +@@ -920,7 +921,7 @@ class host_mod(LDAPUpdate): + else: + _entry_attrs = ldap.get_entry(dn, ['objectclass']) + obj_classes = _entry_attrs['objectclass'] +- if 'ieee802device' not in obj_classes: ++ if 'ieee802device' not in (item.lower() for item in obj_classes): + obj_classes.append('ieee802device') + entry_attrs['objectclass'] = obj_classes + +@@ -940,7 +941,7 @@ class host_mod(LDAPUpdate): + else: + _entry_attrs = ldap.get_entry(dn, ['objectclass']) + obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass'] +- if 'ipasshhost' not in obj_classes: ++ if 'ipasshhost' not in (item.lower() for item in obj_classes): + obj_classes.append('ipasshhost') + + update_krbticketflags(ldap, entry_attrs, attrs_list, options, True) +@@ -949,14 +950,16 @@ class host_mod(LDAPUpdate): + if 'objectclass' not in entry_attrs: + entry_attrs_old = ldap.get_entry(dn, ['objectclass']) + entry_attrs['objectclass'] = entry_attrs_old['objectclass'] +- if 'krbticketpolicyaux' not in entry_attrs['objectclass']: ++ if 'krbticketpolicyaux' not in (item.lower() for item in ++ entry_attrs['objectclass']): + entry_attrs['objectclass'].append('krbticketpolicyaux') + + if 'krbprincipalauthind' in entry_attrs: + if 'objectclass' not in entry_attrs: + entry_attrs_old = ldap.get_entry(dn, ['objectclass']) + entry_attrs['objectclass'] = entry_attrs_old['objectclass'] +- if 'krbprincipalaux' not in entry_attrs['objectclass']: ++ if 'krbprincipalaux' not in (item.lower() for item in ++ entry_attrs['objectclass']): + entry_attrs['objectclass'].append('krbprincipalaux') + + add_sshpubkey_to_attrs_pre(self.context, attrs_list) +-- +2.9.3 + diff --git a/SOURCES/0134-trust-fetch-domains-contact-forest-DCs-when-fetching.patch b/SOURCES/0134-trust-fetch-domains-contact-forest-DCs-when-fetching.patch deleted file mode 100644 index d09400a..0000000 --- a/SOURCES/0134-trust-fetch-domains-contact-forest-DCs-when-fetching.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 1db0d09a59c6fbfdfd080f9f78f5a5d9b61e2c19 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Tue, 13 Sep 2016 15:59:40 +0200 -Subject: [PATCH] trust-fetch-domains: contact forest DCs when fetching trust - domain info - -The code should always contact forest root DCs when requesting trust domain -info. In the case of one-way or external trusts -`com.redhat.idm.trust-fetch-domains` helper is leveraged, otherwise forest -root domain is contacted directly through Samba using the credentials of HTTP -principal. - -https://fedorahosted.org/freeipa/ticket/6328 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/trust.py | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index b3cb56c14496c0d56d3f3fedddee8d123f929344..720a45a4d12d59f00e3e63f2b4f62edd45646065 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -1739,15 +1739,20 @@ class trust_fetch_domains(LDAPRetrieve): - ldap = self.api.Backend.ldap2 - verify_samba_component_presence(ldap, self.api) - -- trust = self.api.Command.trust_show(keys[0], raw=True)['result'] -+ trust = self.api.Command.trust_show( -+ keys[0], all=True, raw=True)['result'] - - result = dict() - result['result'] = [] - result['count'] = 0 - result['truncated'] = False - -- # For one-way trust fetch over DBus. we don't get the list in this case. -- if int(trust['ipanttrustdirection'][0]) != TRUST_BIDIRECTIONAL: -+ trust_direction = int(trust['ipanttrustdirection'][0]) -+ is_nontransitive = int(trust.get('ipanttrustattributes', -+ [0])[0]) & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE -+ # For one-way trust and external trust fetch over DBus. -+ # We don't get the list in this case. -+ if trust_direction != TRUST_BIDIRECTIONAL or is_nontransitive: - fetch_trusted_domains_over_dbus(self.api, self.log, keys[0]) - result['summary'] = unicode(_('List of trust domains successfully refreshed. Use trustdomain-find command to list them.')) - return result -@@ -1762,6 +1767,9 @@ class trust_fetch_domains(LDAPRetrieve): - 'on the IPA server first' - ) - ) -+ -+ trustinstance.populate_remote_domain(keys[0]) -+ - res = fetch_domains_from_trust(self.api, trustinstance, **options) - domains = add_new_domains_from_trust(self.api, trustinstance, trust, res, **options) - --- -2.7.4 - diff --git a/SOURCES/0135-Added-plugins-directory-to-ipaclient-subpackages.patch b/SOURCES/0135-Added-plugins-directory-to-ipaclient-subpackages.patch new file mode 100644 index 0000000..eb46399 --- /dev/null +++ b/SOURCES/0135-Added-plugins-directory-to-ipaclient-subpackages.patch @@ -0,0 +1,35 @@ +From b62710ef8fe96ac012d61f6fc76f7d4e69a49f09 Mon Sep 17 00:00:00 2001 +From: Oliver Gutierrez +Date: Fri, 28 Apr 2017 15:21:49 +0100 +Subject: [PATCH] Added plugins directory to ipaclient subpackages + +https://pagure.io/freeipa/issue/6927 + +Reviewed-By: Pavel Vomacka +--- + freeipa.spec.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 1b3ed15036eab6262b144d970cbdfdad31ac13ea..3a5a9b4087d2394d6e8556d62da46a3dc922c913 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -1404,6 +1404,7 @@ fi + %doc README.md Contributors.txt + %license COPYING + %dir %{python_sitelib}/ipaclient ++%dir %{python_sitelib}/ipaclient/plugins + %{python_sitelib}/ipaclient/*.py* + %{python_sitelib}/ipaclient/install/*.py* + %{python_sitelib}/ipaclient/plugins/*.py* +@@ -1422,6 +1423,7 @@ fi + %doc README.md Contributors.txt + %license COPYING + %dir %{python3_sitelib}/ipaclient ++%dir %{python3_sitelib}/ipaclient/plugins + %{python3_sitelib}/ipaclient/*.py + %{python3_sitelib}/ipaclient/__pycache__/*.py* + %{python3_sitelib}/ipaclient/install/*.py +-- +2.9.3 + diff --git a/SOURCES/0135-ipa-passwd-use-correct-normalizer-for-user-principal.patch b/SOURCES/0135-ipa-passwd-use-correct-normalizer-for-user-principal.patch deleted file mode 100644 index b2d6909..0000000 --- a/SOURCES/0135-ipa-passwd-use-correct-normalizer-for-user-principal.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 8750c84bbfef36ceeaac8e7c8e3b788c31f68317 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Tue, 13 Sep 2016 15:40:04 +0200 -Subject: [PATCH] ipa passwd: use correct normalizer for user principals - -Commit c2af032c0333f7e210c54369159d1d9f5e3fec74 introduced a regression in the -handling of user principals supplied to the`ipa passwd` command. This patch -restores the original behavior which lowercases the username portion of the -principal. - -https://fedorahosted.org/freeipa/ticket/6329 - -Reviewed-By: Alexander Bokovoy ---- - ipaserver/plugins/passwd.py | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/plugins/passwd.py b/ipaserver/plugins/passwd.py -index 1576c4ca85cb761d2a124a932a26b371b9e87107..ebc41d90009d7145ada75f3cabe3c01c6d25f6ea 100644 ---- a/ipaserver/plugins/passwd.py -+++ b/ipaserver/plugins/passwd.py -@@ -29,7 +29,8 @@ from ipalib.plugable import Registry - from ipalib.request import context - from ipapython import kerberos - from ipapython.dn import DN --from ipaserver.plugins.service import validate_realm, normalize_principal -+from ipaserver.plugins.baseuser import normalize_user_principal -+from ipaserver.plugins.service import validate_realm - - if six.PY3: - unicode = str -@@ -66,7 +67,7 @@ def get_current_password(principal): - be ignored later. - """ - current_principal = krb_utils.get_principal() -- if current_principal == unicode(normalize_principal(principal)): -+ if current_principal == unicode(normalize_user_principal(principal)): - return None - else: - return MAGIC_VALUE -@@ -84,7 +85,7 @@ class passwd(Command): - primary_key=True, - autofill=True, - default_from=lambda: kerberos.Principal(krb_utils.get_principal()), -- normalizer=lambda value: normalize_principal(value), -+ normalizer=lambda value: normalize_user_principal(value), - ), - Password('password', - label=_('New Password'), --- -2.10.2 - diff --git a/SOURCES/0136-Keep-NSS-trust-flags-of-existing-certificates.patch b/SOURCES/0136-Keep-NSS-trust-flags-of-existing-certificates.patch deleted file mode 100644 index b71c7b7..0000000 --- a/SOURCES/0136-Keep-NSS-trust-flags-of-existing-certificates.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 08d3dcb1834fc227dcd9d2071fda58e6dc639394 Mon Sep 17 00:00:00 2001 -From: Tomas Krizek -Date: Tue, 13 Sep 2016 10:14:47 +0200 -Subject: [PATCH] Keep NSS trust flags of existing certificates - -Backup and restore trust flags of existing certificates during CA -installation. This prevents marking a previously trusted certificate -as untrusted, as was the case when CA-less was converted to CA-full -with external CA when using the same certificate. - -https://fedorahosted.org/freeipa/ticket/5791 - -Reviewed-By: Florence Blanc-Renaud -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/cainstance.py | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 3551887cd8ff8baa5e17f8969c84fb92d7552ef3..6c57aadfcdc2864f8cdc84c16556dce7163737fc 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -832,6 +832,10 @@ class CAInstance(DogtagInstance): - raise RuntimeError("Unable to retrieve CA chain: %s" % str(e)) - - def __import_ca_chain(self): -+ # Backup NSS trust flags of all already existing certificates -+ certdb = certs.CertDB(self.realm) -+ cert_backup_list = certdb.list_certs() -+ - chain = self.__get_ca_chain() - - # If this chain contains multiple certs then certutil will only import -@@ -882,6 +886,10 @@ class CAInstance(DogtagInstance): - os.remove(chain_name) - subid += 1 - -+ # Restore NSS trust flags of all previously existing certificates -+ for nick, trust_flags in cert_backup_list: -+ certdb.trust_root_cert(nick, trust_flags) -+ - def __request_ra_certificate(self): - # Create a noise file for generating our private key - noise = array.array('B', os.urandom(128)) --- -2.10.2 - diff --git a/SOURCES/0136-ipaclient-fix-missing-RPM-ownership.patch b/SOURCES/0136-ipaclient-fix-missing-RPM-ownership.patch new file mode 100644 index 0000000..3f1cbff --- /dev/null +++ b/SOURCES/0136-ipaclient-fix-missing-RPM-ownership.patch @@ -0,0 +1,71 @@ +From 6f2708e350a096a8d3ea4feb177370d9cb1afa81 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 10 May 2017 18:39:22 +0200 +Subject: [PATCH] ipaclient: fix missing RPM ownership + +FreeIPA package should own all subdirectories to work properly with +3rd party packages/plugins. + +https://pagure.io/freeipa/issue/6927 + +Reviewed-By: Pavel Vomacka +--- + freeipa.spec.in | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 3a5a9b4087d2394d6e8556d62da46a3dc922c913..0335a9970be82e80e98696f3d7fd4ec64894ef5f 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -1404,14 +1404,20 @@ fi + %doc README.md Contributors.txt + %license COPYING + %dir %{python_sitelib}/ipaclient +-%dir %{python_sitelib}/ipaclient/plugins + %{python_sitelib}/ipaclient/*.py* ++%dir %{python_sitelib}/ipaclient/install + %{python_sitelib}/ipaclient/install/*.py* ++%dir %{python_sitelib}/ipaclient/plugins + %{python_sitelib}/ipaclient/plugins/*.py* ++%dir %{python_sitelib}/ipaclient/remote_plugins + %{python_sitelib}/ipaclient/remote_plugins/*.py* + %{python_sitelib}/ipaclient/remote_plugins/2_*/*.py* ++%dir %{python_sitelib}/ipaclient/csrgen ++%dir %{python_sitelib}/ipaclient/csrgen/profiles + %{python_sitelib}/ipaclient/csrgen/profiles/*.json ++%dir %{python_sitelib}/ipaclient/csrgen/rules + %{python_sitelib}/ipaclient/csrgen/rules/*.json ++%dir %{python_sitelib}/ipaclient/csrgen/templates + %{python_sitelib}/ipaclient/csrgen/templates/*.tmpl + %{python_sitelib}/ipaclient-*.egg-info + +@@ -1423,19 +1429,25 @@ fi + %doc README.md Contributors.txt + %license COPYING + %dir %{python3_sitelib}/ipaclient +-%dir %{python3_sitelib}/ipaclient/plugins + %{python3_sitelib}/ipaclient/*.py + %{python3_sitelib}/ipaclient/__pycache__/*.py* ++%dir %{python3_sitelib}/ipaclient/install + %{python3_sitelib}/ipaclient/install/*.py + %{python3_sitelib}/ipaclient/install/__pycache__/*.py* ++%dir %{python3_sitelib}/ipaclient/plugins + %{python3_sitelib}/ipaclient/plugins/*.py + %{python3_sitelib}/ipaclient/plugins/__pycache__/*.py* ++%dir %{python3_sitelib}/ipaclient/remote_plugins + %{python3_sitelib}/ipaclient/remote_plugins/*.py + %{python3_sitelib}/ipaclient/remote_plugins/__pycache__/*.py* + %{python3_sitelib}/ipaclient/remote_plugins/2_*/*.py + %{python3_sitelib}/ipaclient/remote_plugins/2_*/__pycache__/*.py* ++%dir %{python3_sitelib}/ipaclient/csrgen ++%dir %{python3_sitelib}/ipaclient/csrgen/profiles + %{python3_sitelib}/ipaclient/csrgen/profiles/*.json ++%dir %{python3_sitelib}/ipaclient/csrgen/rules + %{python3_sitelib}/ipaclient/csrgen/rules/*.json ++%dir %{python3_sitelib}/ipaclient/csrgen/templates + %{python3_sitelib}/ipaclient/csrgen/templates/*.tmpl + %{python3_sitelib}/ipaclient-*.egg-info + +-- +2.9.3 + diff --git a/SOURCES/0137-Properly-handle-LDAP-socket-closures-in-ipa-otpd.patch b/SOURCES/0137-Properly-handle-LDAP-socket-closures-in-ipa-otpd.patch deleted file mode 100644 index 6a44a36..0000000 --- a/SOURCES/0137-Properly-handle-LDAP-socket-closures-in-ipa-otpd.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 31007eff1b8d858dfc51f730b47a7aaefc8e33e8 Mon Sep 17 00:00:00 2001 -From: Nathaniel McCallum -Date: Tue, 27 Sep 2016 14:34:05 -0400 -Subject: [PATCH] Properly handle LDAP socket closures in ipa-otpd - -In at least one case, when an LDAP socket closes, a read event is fired -rather than an error event. Without this patch, ipa-otpd silently -ignores this event and enters a state where all bind auths fail. - -To remedy this problem, we pass error events along the same path as read -events. Should the actual read fail, we exit. - -https://bugzilla.redhat.com/show_bug.cgi?id=1377858 -https://fedorahosted.org/freeipa/ticket/6368 - -Reviewed-By: Alexander Bokovoy ---- - daemons/ipa-otpd/bind.c | 10 ++++------ - daemons/ipa-otpd/query.c | 13 ++++++------- - 2 files changed, 10 insertions(+), 13 deletions(-) - -diff --git a/daemons/ipa-otpd/bind.c b/daemons/ipa-otpd/bind.c -index 022525b786705b4f58f861bc3b0a745ab8693755..a98312f906a785bfa9c98603a3577561552bfc0a 100644 ---- a/daemons/ipa-otpd/bind.c -+++ b/daemons/ipa-otpd/bind.c -@@ -85,6 +85,9 @@ static void on_bind_readable(verto_ctx *vctx, verto_ev *ev) - if (rslt <= 0) - results = NULL; - ldap_msgfree(results); -+ otpd_log_err(EIO, "IO error received on bind socket"); -+ verto_break(ctx.vctx); -+ ctx.exitstatus = 1; - return; - } - -@@ -137,11 +140,6 @@ void otpd_on_bind_io(verto_ctx *vctx, verto_ev *ev) - flags = verto_get_fd_state(ev); - if (flags & VERTO_EV_FLAG_IO_WRITE) - on_bind_writable(vctx, ev); -- if (flags & VERTO_EV_FLAG_IO_READ) -+ if (flags & (VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_IO_ERROR)) - on_bind_readable(vctx, ev); -- if (flags & VERTO_EV_FLAG_IO_ERROR) { -- otpd_log_err(EIO, "IO error received on bind socket"); -- verto_break(ctx.vctx); -- ctx.exitstatus = 1; -- } - } -diff --git a/daemons/ipa-otpd/query.c b/daemons/ipa-otpd/query.c -index 67e2d751d8d1511d077a93d7673439be11812e6f..50e15603322c550a0eb14e1e3c502e1a229d1ebe 100644 ---- a/daemons/ipa-otpd/query.c -+++ b/daemons/ipa-otpd/query.c -@@ -133,7 +133,11 @@ static void on_query_readable(verto_ctx *vctx, verto_ev *ev) - if (i != LDAP_RES_SEARCH_ENTRY && i != LDAP_RES_SEARCH_RESULT) { - if (i <= 0) - results = NULL; -- goto egress; -+ ldap_msgfree(results); -+ otpd_log_err(EIO, "IO error received on query socket"); -+ verto_break(ctx.vctx); -+ ctx.exitstatus = 1; -+ return; - } - - item = otpd_queue_pop_msgid(&ctx.query.responses, ldap_msgid(results)); -@@ -243,11 +247,6 @@ void otpd_on_query_io(verto_ctx *vctx, verto_ev *ev) - flags = verto_get_fd_state(ev); - if (flags & VERTO_EV_FLAG_IO_WRITE) - on_query_writable(vctx, ev); -- if (flags & VERTO_EV_FLAG_IO_READ) -+ if (flags & (VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_IO_ERROR)) - on_query_readable(vctx, ev); -- if (flags & VERTO_EV_FLAG_IO_ERROR) { -- otpd_log_err(EIO, "IO error received on query socket"); -- verto_break(ctx.vctx); -- ctx.exitstatus = 1; -- } - } --- -2.10.2 - diff --git a/SOURCES/0137-otptoken-add-yubikey-When-digits-not-provided-use-de.patch b/SOURCES/0137-otptoken-add-yubikey-When-digits-not-provided-use-de.patch new file mode 100644 index 0000000..62760ea --- /dev/null +++ b/SOURCES/0137-otptoken-add-yubikey-When-digits-not-provided-use-de.patch @@ -0,0 +1,36 @@ +From b16661f4dab141ef692ed6c893c0cb05566b64ec Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Fri, 12 May 2017 17:17:05 +0200 +Subject: [PATCH] otptoken-add-yubikey: When --digits not provided use default + value + +Since Thin client was introduced default values for options are not populated +in client side plugins. When option has default value and is needed in client +plugin it must be handled by explicitly. + +https://pagure.io/freeipa/issue/6900 + +Reviewed-By: Stanislav Laznicka +--- + ipaclient/plugins/otptoken_yubikey.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ipaclient/plugins/otptoken_yubikey.py b/ipaclient/plugins/otptoken_yubikey.py +index 759b7226819f0fa693e475b25262b5d93ac2d39f..9e0e98996ca2d34f34f61c9c07088a3f544ad166 100644 +--- a/ipaclient/plugins/otptoken_yubikey.py ++++ b/ipaclient/plugins/otptoken_yubikey.py +@@ -142,7 +142,10 @@ class otptoken_add_yubikey(Command): + + # Write the config. + cfg = yk.init_config() +- cfg.mode_oath_hotp(key, kwargs['ipatokenotpdigits']) ++ cfg.mode_oath_hotp(key, kwargs.get( ++ 'ipatokenotpdigits', ++ self.get_default_of('ipatokenotpdigits') ++ )) + cfg.extended_flag('SERIAL_API_VISIBLE', True) + yk.write_config(cfg, slot=kwargs['slot']) + +-- +2.9.3 + diff --git a/SOURCES/0138-cert-add-revocation-reason-back-to-cert-find-output.patch b/SOURCES/0138-cert-add-revocation-reason-back-to-cert-find-output.patch deleted file mode 100644 index 44a9376..0000000 --- a/SOURCES/0138-cert-add-revocation-reason-back-to-cert-find-output.patch +++ /dev/null @@ -1,54 +0,0 @@ -From c3ceffccc56dea782a3dfac5bc3a14d1d022d33a Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Wed, 12 Oct 2016 12:58:46 +0200 -Subject: [PATCH] cert: add revocation reason back to cert-find output - -In commit c718ef058847bb39e78236e8af0ad69ac961bbcf some param values were -accidentally removed from cert-find output. - -In commit 22d5f579bbd8bb452cf1bf620294ab6ade6e7c47 `serial_number_hex` and -`revoked` were added back. - -Add back `revocation_reason` as well. Also, do not include `revoked` with ---raw, as it's a virtual attribute. - -https://fedorahosted.org/freeipa/ticket/6269 - -Reviewed-By: Pavel Vomacka ---- - ipaserver/plugins/cert.py | 17 +++++++++-------- - 1 file changed, 9 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index 00bae4560d601e28e0b983786bff9144bcc1b065..68516391a54aead8e92f3cdeb33463d8fa624bbd 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -1098,16 +1098,17 @@ class cert_find(Search, CertMethod): - obj = {'serial_number': serial_number} - else: - obj = ra_obj -- obj['issuer'] = issuer -- obj['subject'] = DN(ra_obj['subject']) -- obj['revoked'] = ( -- ra_obj['status'] in (u'REVOKED', u'REVOKED_EXPIRED')) -- - if all: -- ra_obj = ra.get_certificate(str(serial_number)) -- if not raw: -+ obj.update(ra.get_certificate(str(serial_number))) -+ -+ if not raw: -+ obj['issuer'] = issuer -+ obj['subject'] = DN(ra_obj['subject']) -+ obj['revoked'] = ( -+ ra_obj['status'] in (u'REVOKED', u'REVOKED_EXPIRED')) -+ if all: - obj['certificate'] = ( -- ra_obj['certificate'].replace('\r\n', '')) -+ obj['certificate'].replace('\r\n', '')) - self.obj._parse(obj) - - obj['cacn'] = ca_obj['cn'][0] --- -2.10.2 - diff --git a/SOURCES/0138-ipa-server-install-fix-uninstall.patch b/SOURCES/0138-ipa-server-install-fix-uninstall.patch new file mode 100644 index 0000000..badd794 --- /dev/null +++ b/SOURCES/0138-ipa-server-install-fix-uninstall.patch @@ -0,0 +1,34 @@ +From 632a1d97c2110cf8ccb4311fac51b98b03b7e26b Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 15 May 2017 16:36:44 +0200 +Subject: [PATCH] ipa-server-install: fix uninstall + +ipa-server-install --uninstall fails to stop tracking the certificates +because it assigns a tuple to the variable nicknames, then tries to +call nicknames.append(). This is a regression introduced by 21f4cbf8. + +Assignment should be done using nicknames = list(self.tracking_reqs) instead. + +https://pagure.io/freeipa/issue/6950 + +Reviewed-By: Jan Cholasta +--- + ipaserver/install/dogtaginstance.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py +index 3ba13815055612c5fff44831c8f874e6175d94cd..4c6e1f70672f1553696d53bcd0cf8064c411441d 100644 +--- a/ipaserver/install/dogtaginstance.py ++++ b/ipaserver/install/dogtaginstance.py +@@ -331,7 +331,7 @@ class DogtagInstance(service.Service): + services.knownservices.messagebus.start() + cmonger.start() + +- nicknames = self.tracking_reqs ++ nicknames = list(self.tracking_reqs) + if self.server_cert_name is not None: + nicknames.append(self.server_cert_name) + +-- +2.9.4 + diff --git a/SOURCES/0139-Make-httpd-publish-its-CA-certificate-on-DL1.patch b/SOURCES/0139-Make-httpd-publish-its-CA-certificate-on-DL1.patch deleted file mode 100644 index d6ad038..0000000 --- a/SOURCES/0139-Make-httpd-publish-its-CA-certificate-on-DL1.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 3ea5984f2806958dee1b94fe993d20b09f64b107 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka -Date: Tue, 11 Oct 2016 15:48:47 +0200 -Subject: [PATCH] Make httpd publish its CA certificate on DL1 - -httpd did not publish its certificate on DL1 which could -cause issues during client installation in a rare corner -case where there would be no way of getting the certificate -but from a HTTP instance. - -https://fedorahosted.org/freeipa/ticket/6393 - -Reviewed-By: Martin Basti ---- - ipaserver/install/httpinstance.py | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 00f890175ae583f485797da6f913a7f83b302df3..431671eaf55d4ac63dc01190e254931dac096dec 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -175,8 +175,7 @@ class HTTPInstance(service.Service): - self.step("importing CA certificates from LDAP", self.__import_ca_certs) - if autoconfig: - self.step("setting up browser autoconfig", self.__setup_autoconfig) -- if not self.promote: -- self.step("publish CA cert", self.__publish_ca_cert) -+ self.step("publish CA cert", self.__publish_ca_cert) - self.step("clean up any existing httpd ccache", self.remove_httpd_ccache) - self.step("configuring SELinux for httpd", self.configure_selinux_for_httpd) - if not self.is_kdcproxy_configured(): --- -2.10.2 - diff --git a/SOURCES/0139-ca-install-merge-duplicated-code-for-DM-password.patch b/SOURCES/0139-ca-install-merge-duplicated-code-for-DM-password.patch new file mode 100644 index 0000000..e0ac02e --- /dev/null +++ b/SOURCES/0139-ca-install-merge-duplicated-code-for-DM-password.patch @@ -0,0 +1,85 @@ +From fd7b5b32f907fff7c454a91838f5483501220971 Mon Sep 17 00:00:00 2001 +From: Tomas Krizek +Date: Wed, 3 May 2017 10:05:25 +0200 +Subject: [PATCH] ca install: merge duplicated code for DM password + +Extract copy-pasted code to a single function. + +Related https://pagure.io/freeipa/issue/6892 + +Signed-off-by: Tomas Krizek +Reviewed-By: Martin Basti +Reviewed-By: Christian Heimes +Reviewed-By: Stanislav Laznicka +--- + install/tools/ipa-ca-install | 40 +++++++++++++++++----------------------- + 1 file changed, 17 insertions(+), 23 deletions(-) + +diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install +index c05abb9646884ad5a4411dba98df466c37f09613..4bcb59a29d5a64c118649374104ae8f1cd451ea4 100755 +--- a/install/tools/ipa-ca-install ++++ b/install/tools/ipa-ca-install +@@ -116,9 +116,19 @@ def parse_options(): + return safe_options, options, filename + + +-def get_dirman_password(): +- return installutils.read_password( +- "Directory Manager (existing master)", confirm=False, validate=False) ++def _get_dirman_password(password=None, unattended=False): ++ if not password: ++ if unattended: ++ sys.exit('Directory Manager password required') ++ try: ++ password = installutils.read_password( ++ "Directory Manager (existing master)", confirm=False, ++ validate=False) ++ except KeyboardInterrupt: ++ sys.exit(0) ++ if password is None: ++ sys.exit("Directory Manager password required") ++ return password + + + def install_replica(safe_options, options, filename): +@@ -142,16 +152,8 @@ def install_replica(safe_options, options, filename): + check_creds(options, api.env.realm) + + # get the directory manager password +- dirman_password = options.password +- if not dirman_password: +- if options.unattended: +- sys.exit('Directory Manager password required') +- try: +- dirman_password = get_dirman_password() +- except KeyboardInterrupt: +- sys.exit(0) +- if dirman_password is None: +- sys.exit("Directory Manager password required") ++ dirman_password = _get_dirman_password( ++ options.password, options.unattended) + + if (not options.promote and not options.admin_password and + not options.skip_conncheck and options.unattended): +@@ -199,16 +201,8 @@ def install_replica(safe_options, options, filename): + + + def install_master(safe_options, options): +- dm_password = options.password +- if not dm_password: +- if options.unattended: +- sys.exit('Directory Manager password required') +- try: +- dm_password = get_dirman_password() +- except KeyboardInterrupt: +- sys.exit(0) +- if dm_password is None: +- sys.exit("Directory Manager password required") ++ dm_password = _get_dirman_password( ++ options.password, options.unattended) + + options.realm_name = api.env.realm + options.domain_name = api.env.domain +-- +2.9.4 + diff --git a/SOURCES/0140-Add-cert-checks-in-ipa-server-certinstall.patch b/SOURCES/0140-Add-cert-checks-in-ipa-server-certinstall.patch deleted file mode 100644 index be7d0f1..0000000 --- a/SOURCES/0140-Add-cert-checks-in-ipa-server-certinstall.patch +++ /dev/null @@ -1,88 +0,0 @@ -From b3512bae94edc33448466cae6f2716a5527f9eed Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 1 Sep 2016 13:56:24 +0200 -Subject: [PATCH] Add cert checks in ipa-server-certinstall - -When ipa-server-certinstall is called to install a new server certificate, -the prerequisite is that the certificate issuer must be already known by IPA. -This fix adds new checks to make sure that the tool exits before -modifying the target NSS database if it is not the case. -The fix consists in creating a temp NSS database with the CA certs from the -target NSS database + the new server cert and checking the new server cert -validity. - -https://fedorahosted.org/freeipa/ticket/6263 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/ipa_server_certinstall.py | 40 +++++++++++++++++++++++++++-- - 1 file changed, 38 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py -index 0a8fb214a232e60a89b6c06940b928f97c007b93..7bc39e356ef3082ab229fa66eaeebba85eaa2802 100644 ---- a/ipaserver/install/ipa_server_certinstall.py -+++ b/ipaserver/install/ipa_server_certinstall.py -@@ -25,8 +25,8 @@ import optparse - - from ipaplatform.constants import constants - from ipaplatform.paths import paths --from ipapython import admintool --from ipapython.certdb import get_ca_nickname -+from ipapython import admintool, ipautil -+from ipapython.certdb import get_ca_nickname, NSSDatabase - from ipapython.dn import DN - from ipalib import api, errors - from ipalib.constants import CACERT -@@ -157,6 +157,38 @@ class ServerCertInstall(admintool.AdminTool): - os.chown(os.path.join(dirname, 'key3.db'), 0, pent.pw_gid) - os.chown(os.path.join(dirname, 'secmod.db'), 0, pent.pw_gid) - -+ def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb): -+ # create a temp nssdb -+ with NSSDatabase() as tempnssdb: -+ db_password = ipautil.ipa_generate_password() -+ db_pwdfile = ipautil.write_tmp_file(db_password) -+ tempnssdb.create_db(db_pwdfile.name) -+ -+ # import the PKCS12 file, then delete all CA certificates -+ # this leaves only the server certs in the temp db -+ tempnssdb.import_pkcs12( -+ pkcs12_filename, db_pwdfile.name, pkcs12_pin) -+ for nickname, flags in tempnssdb.list_certs(): -+ if 'u' not in flags: -+ while tempnssdb.has_nickname(nickname): -+ tempnssdb.delete_cert(nickname) -+ -+ # import all the CA certs from nssdb into the temp db -+ for nickname, flags in nssdb.list_certs(): -+ if 'u' not in flags: -+ cert = nssdb.get_cert_from_db(nickname) -+ tempnssdb.add_cert(cert, nickname, flags) -+ -+ # now get the server certs from tempnssdb and check their validity -+ try: -+ for nick, flags in tempnssdb.find_server_certs(): -+ tempnssdb.verify_server_cert_validity(nick, api.env.host) -+ except ValueError as e: -+ raise admintool.ScriptError( -+ "Peer's certificate issuer is not trusted (%s). " -+ "Please run ipa-cacert-manage install and ipa-certupdate " -+ "to install the CA certificate." % str(e)) -+ - def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): - pkcs12_file, pin, ca_cert = installutils.load_pkcs12( - cert_files=self.args, -@@ -167,6 +199,10 @@ class ServerCertInstall(admintool.AdminTool): - - dirname = os.path.normpath(dirname) - cdb = certs.CertDB(api.env.realm, nssdir=dirname) -+ -+ # Check that the ca_cert is known and trusted -+ self.check_chain(pkcs12_file.name, pin, cdb) -+ - try: - ca_enabled = api.Command.ca_is_enabled()['result'] - if ca_enabled: --- -2.10.2 - diff --git a/SOURCES/0140-installutils-add-DM-password-validator.patch b/SOURCES/0140-installutils-add-DM-password-validator.patch new file mode 100644 index 0000000..91ee892 --- /dev/null +++ b/SOURCES/0140-installutils-add-DM-password-validator.patch @@ -0,0 +1,55 @@ +From fe7778b52ac9bacbedceec641ccb41d5f79f131c Mon Sep 17 00:00:00 2001 +From: Tomas Krizek +Date: Wed, 3 May 2017 10:01:09 +0200 +Subject: [PATCH] installutils: add DM password validator + +Add a validator that checks whether provided Directory Manager +is valid by attempting to connect to LDAP. + +Related https://pagure.io/freeipa/issue/6892 + +Signed-off-by: Tomas Krizek +Reviewed-By: Martin Basti +Reviewed-By: Christian Heimes +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/installutils.py | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 9230e70056b1a773246a0d95e6ecb943cada953c..b6f01489ccc65dcbc360929e0a7b315b074df8ce 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -50,6 +50,7 @@ import ipaplatform + from ipapython import ipautil, admintool, version + from ipapython.admintool import ScriptError + from ipapython.ipa_log_manager import root_logger ++from ipapython.ipaldap import DIRMAN_DN, LDAPClient + from ipalib.util import validate_hostname + from ipalib import api, errors, x509 + from ipapython.dn import DN +@@ -329,6 +330,21 @@ def _read_password_default_validator(password): + if len(password) < 8: + raise ValueError("Password must be at least 8 characters long") + ++ ++def validate_dm_password_ldap(password): ++ """ ++ Validate DM password by attempting to connect to LDAP. api.env has to ++ contain valid ldap_uri. ++ """ ++ client = LDAPClient(api.env.ldap_uri, cacert=paths.IPA_CA_CRT) ++ try: ++ client.simple_bind(DIRMAN_DN, password) ++ except errors.ACIError: ++ raise ValueError("Invalid Directory Manager password") ++ else: ++ client.unbind() ++ ++ + def read_password(user, confirm=True, validate=True, retry=True, validator=_read_password_default_validator): + correct = False + pwd = None +-- +2.9.4 + diff --git a/SOURCES/0141-WebUI-services-without-canonical-name-are-shown-corr.patch b/SOURCES/0141-WebUI-services-without-canonical-name-are-shown-corr.patch deleted file mode 100644 index 079bde0..0000000 --- a/SOURCES/0141-WebUI-services-without-canonical-name-are-shown-corr.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 014aab243a4e7185ad5ebdc0a71e7de81553e501 Mon Sep 17 00:00:00 2001 -From: Pavel Vomacka -Date: Mon, 17 Oct 2016 14:33:07 +0200 -Subject: [PATCH] WebUI: services without canonical name are shown correctly - -There is a change introduced in 4.4 that new services have canonical name. The old ones -didn't have it, therefore these services were not correctly displayed in WebUI. - -This patch adds support for this type of services. Service name is taken from -'krbprincipalname' attribute in case that 'krbcanonicalname' attribute is not present -in server response. - -https://fedorahosted.org/freeipa/ticket/6397 - -Reviewed-By: Petr Vobornik ---- - install/ui/src/freeipa/field.js | 41 ++++++++++++++++++++++++++++++ - install/ui/src/freeipa/service.js | 52 ++++++++++++++++++++++++++++++++++++++- - 2 files changed, 92 insertions(+), 1 deletion(-) - -diff --git a/install/ui/src/freeipa/field.js b/install/ui/src/freeipa/field.js -index d8b957f5ab28b5ee4bc4ebce2ae6f454083bc4fd..efa2fb6ef4d4b5384661e9023ace511730954153 100644 ---- a/install/ui/src/freeipa/field.js -+++ b/install/ui/src/freeipa/field.js -@@ -1306,6 +1306,46 @@ field.ObjectAdapter = declare([field.Adapter], { - - - /** -+ * Custom adapter for fields which handles situations when there is no value -+ * for attribute (name) of the field and we want to use alternative attribute -+ * from response. We can set the alternative attribute name to the 'alt_attr' -+ * attribute of the adapter. -+ * This adapter is used i.e. in table in search facet for services. Handles -+ * situations where older services don't have canonical name. -+ * -+ * @class -+ * @extends field.Adapter -+ */ -+field.AlternateAttrFieldAdapter = declare([field.Adapter], { -+ /** -+ * In case that the value is not get using field name then use alternative -+ * name. -+ * @param {Object} data Object which contains the record or the record -+ * @param {string} [attribute] attribute name - overrides `context.param` -+ * @param {Mixed} [def_val] default value - overrides `context.default_value` -+ * @returns {Array} attribute value -+ */ -+ load: function(data, attribute, def_val) { -+ var record = this.get_record(data); -+ var value = null; -+ var attr = attribute || this.context.param; -+ var def = def_val || this.context.default_value; -+ if (record) { -+ value = this.get_value(record, attr); -+ if (util.is_empty(value) && this.context.adapter.alt_attr) { -+ value = this.get_value(record, this.context.adapter.alt_attr); -+ } -+ } -+ if (util.is_empty(value) && !util.is_empty(def)) { -+ value = util.normalize_value(def); -+ } -+ value = rpc.extract_objects(value); -+ return value; -+ } -+}); -+ -+ -+/** - * Field for enabling/disabling entity - * - * - expects radio widget -@@ -1577,6 +1617,7 @@ field.register = function() { - - l.register('adapter', field.Adapter); - l.register('object_adapter', field.ObjectAdapter); -+ l.register('alternate_attr_field_adapter', field.AlternateAttrFieldAdapter); - }; - phases.on('registration', field.register); - -diff --git a/install/ui/src/freeipa/service.js b/install/ui/src/freeipa/service.js -index 30e336c35b8eece2e5e3ef55629d0c98f097fbf5..a6607d22e83047fb2d0dcc7775891445df4910b7 100644 ---- a/install/ui/src/freeipa/service.js -+++ b/install/ui/src/freeipa/service.js -@@ -58,7 +58,16 @@ return { - facets: [ - { - $type: 'search', -- columns: [ 'krbcanonicalname' ] -+ $factory: IPA.service.search_facet, -+ columns: [ -+ { -+ name: 'krbcanonicalname', -+ adapter: { -+ $type: 'alternate_attr_field_adapter', -+ alt_attr: 'krbprincipalname' -+ } -+ } -+ ] - }, - { - $type: 'details', -@@ -403,6 +412,47 @@ return { - } - };}; - -+ -+/** -+ * Custom search facet for services. It has alternative primary key, in case -+ * that the service doesn't have canonical name. -+ */ -+IPA.service.search_facet = function(spec) { -+ spec = spec || {}; -+ -+ spec.alternative_pkey = spec.alternative_pkey || 'krbprincipalname'; -+ -+ var that = IPA.search_facet(spec); -+ -+ that.alternative_pkey = spec.alternative_pkey; -+ -+ that.get_records_map = function(data) { -+ -+ var records_map = $.ordered_map(); -+ -+ var result = data.result.result; -+ var pkey_name = that.managed_entity.metadata.primary_key || -+ that.primary_key_name; -+ var adapter = builder.build('adapter', 'adapter', {context: that}); -+ -+ for (var i=0; i +Date: Wed, 3 May 2017 10:16:13 +0200 +Subject: [PATCH] ca, kra install: validate DM password + +Before proceeding with installation, validate DM password. If the +provided DM password is invalid, abort the installation. + +Fixes https://pagure.io/freeipa/issue/6892 + +Signed-off-by: Tomas Krizek +Reviewed-By: Martin Basti +Reviewed-By: Christian Heimes +Reviewed-By: Stanislav Laznicka +--- + install/tools/ipa-ca-install | 18 ++++++++++-------- + ipaserver/install/ipa_kra_install.py | 8 ++++++++ + 2 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install +index 4bcb59a29d5a64c118649374104ae8f1cd451ea4..f84b4749a3e2a80aca002a2aa057b200e6187f18 100755 +--- a/install/tools/ipa-ca-install ++++ b/install/tools/ipa-ca-install +@@ -117,17 +117,19 @@ def parse_options(): + + + def _get_dirman_password(password=None, unattended=False): ++ # sys.exit() is used on purpose, because otherwise user is advised to ++ # uninstall the component, even though it is not needed + if not password: + if unattended: + sys.exit('Directory Manager password required') +- try: +- password = installutils.read_password( +- "Directory Manager (existing master)", confirm=False, +- validate=False) +- except KeyboardInterrupt: +- sys.exit(0) +- if password is None: +- sys.exit("Directory Manager password required") ++ password = installutils.read_password( ++ "Directory Manager (existing master)", confirm=False, ++ validate=False) ++ try: ++ installutils.validate_dm_password_ldap(password) ++ except ValueError: ++ sys.exit("Directory Manager password is invalid") ++ + return password + + +diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py +index b06d49c834d0ffa4f2e35c3241a83e42c4c9c337..8369d2f4082d35b453487ee0f17c9ce050188daf 100644 +--- a/ipaserver/install/ipa_kra_install.py ++++ b/ipaserver/install/ipa_kra_install.py +@@ -137,6 +137,14 @@ class KRAInstaller(KRAInstall): + def run(self): + super(KRAInstaller, self).run() + ++ # Verify DM password. This has to be called after ask_for_options(), ++ # so it can't be placed in validate_options(). ++ try: ++ installutils.validate_dm_password_ldap(self.options.password) ++ except ValueError: ++ raise admintool.ScriptError( ++ "Directory Manager password is invalid") ++ + if not cainstance.is_ca_installed_locally(): + raise RuntimeError("Dogtag CA is not installed. " + "Please install the CA first") +-- +2.9.4 + diff --git a/SOURCES/0142-Fix-missing-file-that-fails-DL1-replica-installation.patch b/SOURCES/0142-Fix-missing-file-that-fails-DL1-replica-installation.patch deleted file mode 100644 index 8d34501..0000000 --- a/SOURCES/0142-Fix-missing-file-that-fails-DL1-replica-installation.patch +++ /dev/null @@ -1,55 +0,0 @@ -From eb844fe9e56a30be9462508f1e5330aaa73342b3 Mon Sep 17 00:00:00 2001 -From: Stanislav Laznicka -Date: Mon, 31 Oct 2016 16:51:49 +0100 -Subject: [PATCH] Fix missing file that fails DL1 replica installation - -Replica installation on DL1 would fail to create a httpd instance -due to missing '/etc/httpd/alias/cacert.asc'. Create this file -in the setup_ssl step to avoid the error. - -https://fedorahosted.org/freeipa/ticket/6393 - -Reviewed-By: Jan Cholasta ---- - ipaserver/install/httpinstance.py | 25 +++++++++++++++++-------- - 1 file changed, 17 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py -index 431671eaf55d4ac63dc01190e254931dac096dec..aeae10902e6597ca1e494240a625caed9f7b7192 100644 ---- a/ipaserver/install/httpinstance.py -+++ b/ipaserver/install/httpinstance.py -@@ -343,14 +343,23 @@ class HTTPInstance(service.Service): - self.__set_mod_nss_nickname(nickname) - self.add_cert_to_service() - -- elif not self.promote: -- db.create_password_conf() -- self.dercert = db.create_server_cert(self.cert_nickname, self.fqdn, -- ca_db) -- db.track_server_cert(self.cert_nickname, self.principal, -- db.passwd_fname, 'restart_httpd') -- db.create_signing_cert("Signing-Cert", "Object Signing Cert", ca_db) -- self.add_cert_to_service() -+ else: -+ if not self.promote: -+ db.create_password_conf() -+ self.dercert = db.create_server_cert(self.cert_nickname, self.fqdn, -+ ca_db) -+ db.track_server_cert(self.cert_nickname, self.principal, -+ db.passwd_fname, 'restart_httpd') -+ db.create_signing_cert("Signing-Cert", "Object Signing Cert", ca_db) -+ self.add_cert_to_service() -+ -+ server_certs = db.find_server_certs() -+ if not server_certs: -+ raise RuntimeError("Could not find a suitable server cert.") -+ -+ # We only handle one server cert -+ nickname = server_certs[0][0] -+ db.export_ca_cert(nickname) - - # Fix the database permissions - os.chmod(certs.NSS_DIR + "/cert8.db", 0o660) --- -2.7.4 - diff --git a/SOURCES/0142-ipa-kra-install-fix-pkispawn-setting-for-pki_securit.patch b/SOURCES/0142-ipa-kra-install-fix-pkispawn-setting-for-pki_securit.patch new file mode 100644 index 0000000..ff1f2f8 --- /dev/null +++ b/SOURCES/0142-ipa-kra-install-fix-pkispawn-setting-for-pki_securit.patch @@ -0,0 +1,45 @@ +From 58a9bd7ec98de555db23159e614b2021ec91b2e3 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 11 May 2017 14:53:09 +0200 +Subject: [PATCH] ipa-kra-install: fix pkispawn setting for + pki_security_domain_hostname + +During ipa-kra-install, the installer prepares a configuration file +provided to pkispawn. This configuration file defines +pki_security_domain_hostname=(first master) + +but when we are installing a clone, it should be set to the local hostname +instead, see man page pki_default.cfg: + pki_security_domain_hostname, pki_security_domain_https_port + Location of the security domain. Required for KRA, OCSP, TKS, + and TPS subsystems and for CA subsystems joining a security + domain. Defaults to the location of the CA subsystem within the + same instance. + +When pki_security_domain_hostname points to the 1st master, and this first +master is decommissioned, ipa-kra-install fails on new replicas because pkispawn +tries to connect to this (non-existing) host. + +https://pagure.io/freeipa/issue/6895 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/krainstance.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py +index abb81897a404613e20be10d348096402ef08624b..cdd25b9d05bcb1a30260475cc2341a258a3cf93c 100644 +--- a/ipaserver/install/krainstance.py ++++ b/ipaserver/install/krainstance.py +@@ -252,7 +252,7 @@ class KRAInstance(DogtagInstance): + os.chown(p12_tmpfile_name, pent.pw_uid, pent.pw_gid) + + # Security domain registration +- config.set("KRA", "pki_security_domain_hostname", self.master_host) ++ config.set("KRA", "pki_security_domain_hostname", self.fqdn) + config.set("KRA", "pki_security_domain_https_port", "443") + config.set("KRA", "pki_security_domain_user", self.admin_user) + config.set("KRA", "pki_security_domain_password", +-- +2.9.4 + diff --git a/SOURCES/0143-certdb-add-named-trust-flag-constants.patch b/SOURCES/0143-certdb-add-named-trust-flag-constants.patch new file mode 100644 index 0000000..3c81de1 --- /dev/null +++ b/SOURCES/0143-certdb-add-named-trust-flag-constants.patch @@ -0,0 +1,344 @@ +From b98b21aaa709ccd91369e89a836f64c06c4593e8 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 27 Apr 2017 09:33:25 +0200 +Subject: [PATCH] certdb: add named trust flag constants + +Add named constants for common trust flag combinations. + +Use the named constants instead of trust flags strings in the code. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + install/restart_scripts/restart_httpd | 3 ++- + install/tools/ipa-replica-conncheck | 4 +++- + ipaclient/install/client.py | 9 ++++++--- + ipapython/certdb.py | 9 +++++++-- + ipaserver/install/ca.py | 2 +- + ipaserver/install/certs.py | 5 +++-- + ipaserver/install/dsinstance.py | 5 +++-- + ipaserver/install/httpinstance.py | 5 +++-- + ipaserver/install/ipa_cacert_manage.py | 16 +++++++++++----- + ipaserver/install/plugins/upload_cacrt.py | 2 +- + ipaserver/install/server/replicainstall.py | 3 ++- + ipaserver/install/server/upgrade.py | 4 ++-- + 12 files changed, 44 insertions(+), 23 deletions(-) + +diff --git a/install/restart_scripts/restart_httpd b/install/restart_scripts/restart_httpd +index b661b82b896b109c3859ac82c2d84ab27b839f72..cd7f12024ea3cab16e9c664687cd854e666c9570 100644 +--- a/install/restart_scripts/restart_httpd ++++ b/install/restart_scripts/restart_httpd +@@ -24,6 +24,7 @@ import traceback + from ipalib import api + from ipaplatform import services + from ipaplatform.paths import paths ++from ipapython.certdb import TRUSTED_PEER_TRUST_FLAGS + from ipaserver.install import certs, installutils + + +@@ -36,7 +37,7 @@ def _main(): + nickname = installutils.get_directive(paths.HTTPD_NSS_CONF, "NSSNickname") + + # Add trust flag which set certificate trusted for SSL connections. +- db.trust_root_cert(nickname, "P,,") ++ db.trust_root_cert(nickname, TRUSTED_PEER_TRUST_FLAGS) + + syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd') + +diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck +index fdbd4f32d9fa4a625cca3614e13e71d00f58e57e..528242268f9992e903781b76a379039d533853c0 100755 +--- a/install/tools/ipa-replica-conncheck ++++ b/install/tools/ipa-replica-conncheck +@@ -549,7 +549,9 @@ def main(): + data = ca_cert.public_bytes( + serialization.Encoding.DER) + nss_db.add_cert( +- data, str(DN(ca_cert.subject)), 'C,,') ++ data, ++ str(DN(ca_cert.subject)), ++ certdb.EXTERNAL_CA_TRUST_FLAGS) + + api.bootstrap(context='client', + confdir=paths.ETC_IPA, +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index abca692fd61be4a9f35a1398fb2af4b1d9e8689b..e78be904dd6bad491d9f3c1bb1e1410bc1779d45 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -2318,8 +2318,9 @@ def update_ipa_nssdb(): + if not os.path.exists(os.path.join(ipa_db.secdir, 'cert8.db')): + create_ipa_nssdb() + +- for nickname, trust_flags in (('IPA CA', 'CT,C,C'), +- ('External CA cert', 'C,,')): ++ for nickname, trust_flags in ( ++ ('IPA CA', certdb.IPA_CA_TRUST_FLAGS), ++ ('External CA cert', certdb.EXTERNAL_CA_TRUST_FLAGS)): + try: + cert = sys_db.get_cert(nickname) + except RuntimeError: +@@ -2680,7 +2681,9 @@ def _install(options): + tmp_db.create_db() + + for i, cert in enumerate(ca_certs): +- tmp_db.add_cert(cert, 'CA certificate %d' % (i + 1), 'C,,') ++ tmp_db.add_cert(cert, ++ 'CA certificate %d' % (i + 1), ++ certdb.EXTERNAL_CA_TRUST_FLAGS) + except CalledProcessError: + raise ScriptError( + "Failed to add CA to temporary NSS database.", +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index ea73ec139df9013b860df447fcffd9038cf7c8f2..44c7bf3197c198295035742e6db48527d76e85a6 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -52,6 +52,11 @@ CA_NICKNAME_FMT = "%s IPA CA" + + NSS_FILES = ("cert8.db", "key3.db", "secmod.db", "pwdfile.txt") + ++EMPTY_TRUST_FLAGS = ',,' ++IPA_CA_TRUST_FLAGS = 'CT,C,C' ++EXTERNAL_CA_TRUST_FLAGS = 'C,,' ++TRUSTED_PEER_TRUST_FLAGS = 'P,,' ++ + + def get_ca_nickname(realm, format=CA_NICKNAME_FMT): + return format % realm +@@ -441,7 +446,7 @@ class NSSDatabase(object): + cert = x509.load_certificate(cert_pem) + nickname = str(DN(cert.subject)) + data = cert.public_bytes(serialization.Encoding.DER) +- self.add_cert(data, nickname, ',,') ++ self.add_cert(data, nickname, EMPTY_TRUST_FLAGS) + + if extracted_key: + in_file = ipautil.write_tmp_file( +@@ -473,7 +478,7 @@ class NSSDatabase(object): + root_nickname) + else: + if trust_flags is None: +- trust_flags = 'C,,' ++ trust_flags = EXTERNAL_CA_TRUST_FLAGS + try: + self.run_certutil(["-M", "-n", root_nickname, + "-t", trust_flags]) +diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py +index 8ee0fda23411563c70b7db5f39f43c2869c108b5..52cb20f1cb3612394544a6a41f10e9e939bc0657 100644 +--- a/ipaserver/install/ca.py ++++ b/ipaserver/install/ca.py +@@ -320,7 +320,7 @@ def install_step_1(standalone, replica_config, options): + realm_name, nssdir=dirname, subject_base=subject_base) + cacert = cadb.get_cert_from_db('caSigningCert cert-pki-ca', pem=False) + nickname = certdb.get_ca_nickname(realm_name) +- trust_flags = 'CT,C,C' ++ trust_flags = certdb.IPA_CA_TRUST_FLAGS + dsdb.add_cert(cacert, nickname, trust_flags) + certstore.put_ca_cert_nss(api.Backend.ldap2, api.env.basedn, + cacert, nickname, trust_flags, +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 89e57134f24c505d669057eefffb7862b3b8179a..f87e00eb5e9c14ed30d39ef9f6e86b6f24bb1c61 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -37,6 +37,7 @@ from ipalib.install import certmonger, sysrestore + from ipapython.ipa_log_manager import root_logger + from ipapython import dogtag + from ipapython import ipautil ++from ipapython.certdb import EMPTY_TRUST_FLAGS, IPA_CA_TRUST_FLAGS + from ipapython.certdb import get_ca_nickname, find_cert_from_txt, NSSDatabase + from ipapython.dn import DN + from ipalib import pkcs10, x509, api +@@ -597,7 +598,7 @@ class CertDB(object): + # a new certificate database. + self.create_passwd_file() + self.create_certdbs() +- self.load_cacert(cacert_fname, 'CT,C,C') ++ self.load_cacert(cacert_fname, IPA_CA_TRUST_FLAGS) + + def create_from_pkcs12(self, pkcs12_fname, pkcs12_passwd, passwd=None, + ca_file=None, trust_flags=None): +@@ -643,7 +644,7 @@ class CertDB(object): + cert, st = find_cert_from_txt(certs, st) + except RuntimeError: + break +- self.add_cert(cert, 'CA %s' % num, ',,', pem=True) ++ self.add_cert(cert, 'CA %s' % num, EMPTY_TRUST_FLAGS, pem=True) + num += 1 + + # We only handle one server cert +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 403fe8489fdd9e0dbf40dd4df3794b51185d45b9..0db0368fa4b48495718afd779291ce164d1687c8 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -32,6 +32,7 @@ import fnmatch + import ldap + + from ipalib.install import certmonger, certstore ++from ipapython.certdb import IPA_CA_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS + from ipapython.ipa_log_manager import root_logger + from ipapython import ipautil, ipaldap + from ipapython import dogtag +@@ -766,7 +767,7 @@ class DsInstance(service.Service): + ) + if self.pkcs12_info: + if self.ca_is_configured: +- trust_flags = 'CT,C,C' ++ trust_flags = IPA_CA_TRUST_FLAGS + else: + trust_flags = None + dsdb.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], +@@ -1065,7 +1066,7 @@ class DsInstance(service.Service): + certdb.cacert_name = cacert_name + status = True + try: +- certdb.load_cacert(cacert_fname, 'C,,') ++ certdb.load_cacert(cacert_fname, EXTERNAL_CA_TRUST_FLAGS) + except ipautil.CalledProcessError as e: + root_logger.critical("Error importing CA cert file named [%s]: %s" % + (cacert_fname, str(e))) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index ab688a85f157b1886842a91bb7d22f9ea99e3615..a6aeb21edc73783ff9a3f9b526409ea525aa66dd 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -32,6 +32,7 @@ import six + from augeas import Augeas + + from ipalib.install import certmonger ++from ipapython.certdb import IPA_CA_TRUST_FLAGS, TRUSTED_PEER_TRUST_FLAGS + from ipaserver.install import service + from ipaserver.install import certs + from ipaserver.install import installutils +@@ -381,7 +382,7 @@ class HTTPInstance(service.Service): + + if self.pkcs12_info: + if self.ca_is_configured: +- trust_flags = 'CT,C,C' ++ trust_flags = IPA_CA_TRUST_FLAGS + else: + trust_flags = None + db.init_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], +@@ -403,7 +404,7 @@ class HTTPInstance(service.Service): + self.__set_mod_nss_nickname(nickname) + self.add_cert_to_service() + +- db.trust_root_cert(nickname, "P,,") ++ db.trust_root_cert(nickname, TRUSTED_PEER_TRUST_FLAGS) + + else: + if not self.promote: +diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py +index 3b732e4dcbb5c9b4dfbb9e3608bc7d7afd3e10c2..88b40d45e10281d272882d21e06f5d53cf5a701d 100644 +--- a/ipaserver/install/ipa_cacert_manage.py ++++ b/ipaserver/install/ipa_cacert_manage.py +@@ -26,6 +26,7 @@ import gssapi + + from ipalib.install import certmonger, certstore + from ipapython import admintool, ipautil ++from ipapython.certdb import EMPTY_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS + from ipapython.dn import DN + from ipaplatform.paths import paths + from ipalib import api, errors, x509 +@@ -242,10 +243,10 @@ class CACertManage(admintool.AdminTool): + + with certs.NSSDatabase() as tmpdb: + tmpdb.create_db() +- tmpdb.add_cert(old_cert_der, 'IPA CA', 'C,,') ++ tmpdb.add_cert(old_cert_der, 'IPA CA', EXTERNAL_CA_TRUST_FLAGS) + + try: +- tmpdb.add_cert(new_cert_der, 'IPA CA', 'C,,') ++ tmpdb.add_cert(new_cert_der, 'IPA CA', EXTERNAL_CA_TRUST_FLAGS) + except ipautil.CalledProcessError as e: + raise admintool.ScriptError( + "Not compatible with the current CA certificate: %s" % e) +@@ -253,7 +254,8 @@ class CACertManage(admintool.AdminTool): + ca_certs = x509.load_certificate_list_from_file(ca_file.name) + for ca_cert in ca_certs: + data = ca_cert.public_bytes(serialization.Encoding.DER) +- tmpdb.add_cert(data, str(DN(ca_cert.subject)), 'C,,') ++ tmpdb.add_cert( ++ data, str(DN(ca_cert.subject)), EXTERNAL_CA_TRUST_FLAGS) + + try: + tmpdb.verify_ca_cert_validity('IPA CA') +@@ -270,7 +272,11 @@ class CACertManage(admintool.AdminTool): + except RuntimeError: + break + certstore.put_ca_cert_nss( +- conn, api.env.basedn, ca_cert, nickname, ',,') ++ conn, ++ api.env.basedn, ++ ca_cert, ++ nickname, ++ EMPTY_TRUST_FLAGS) + + dn = DN(('cn', self.cert_nickname), ('cn', 'ca_renewal'), + ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) +@@ -343,7 +349,7 @@ class CACertManage(admintool.AdminTool): + + with certs.NSSDatabase() as tmpdb: + tmpdb.create_db() +- tmpdb.add_cert(cert, nickname, 'C,,') ++ tmpdb.add_cert(cert, nickname, EXTERNAL_CA_TRUST_FLAGS) + for ca_cert, ca_nickname, ca_trust_flags in ca_certs: + tmpdb.add_cert(ca_cert, ca_nickname, ca_trust_flags) + +diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py +index 425ea63976ec92a6d69492d90a1e970e528c4a26..7d294ff971bd109e5fbb3570bfff0198f24b68d3 100644 +--- a/ipaserver/install/plugins/upload_cacrt.py ++++ b/ipaserver/install/plugins/upload_cacrt.py +@@ -55,7 +55,7 @@ class update_upload_cacrt(Updater): + if 'u' in trust_flags: + continue + if nickname == ca_nickname and ca_enabled: +- trust_flags = 'CT,C,C' ++ trust_flags = certdb.IPA_CA_TRUST_FLAGS + cert = db.get_cert_from_db(nickname, pem=False) + trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index aa8e67f60b8abe591d55a907c409b584c74d4541..5e78e6faf51ded2fe7634f230c66aa15ae84bad4 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -23,6 +23,7 @@ import ipaclient.install.ntpconf + from ipalib.install import certstore, sysrestore + from ipalib.install.kinit import kinit_keytab + from ipapython import ipaldap, ipautil ++from ipapython.certdb import IPA_CA_TRUST_FLAGS + from ipapython.dn import DN + from ipapython.ipa_log_manager import root_logger + from ipapython.admintool import ScriptError +@@ -737,7 +738,7 @@ def install_check(installer): + nssdir=tmp_db_dir, + subject_base=config.subject_base) + if ca_enabled: +- trust_flags = 'CT,C,C' ++ trust_flags = IPA_CA_TRUST_FLAGS + else: + trust_flags = None + tmp_db.create_from_pkcs12(pkcs12_info[0], pkcs12_info[1], +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 5e5c83731d3d3415deb61271baa7865c62f60336..73a4f1108a56a766cdbbcb93d7050482a8264a75 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1389,7 +1389,7 @@ def fix_trust_flags(): + nickname = certdb.get_ca_nickname(api.env.realm) + cert = db.get_cert_from_db(nickname) + if cert: +- db.trust_root_cert(nickname, 'CT,C,C') ++ db.trust_root_cert(nickname, certdb.IPA_CA_TRUST_FLAGS) + + sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True) + +@@ -1407,7 +1407,7 @@ def fix_server_cert_trust_flags(): + sc_nickname = installutils.get_directive(paths.HTTPD_NSS_CONF, + "NSSNickname") + # Add trust flag which set certificate trusted for SSL connections. +- db.trust_root_cert(sc_nickname, "P,,") ++ db.trust_root_cert(sc_nickname, certdb.TRUSTED_PEER_TRUST_FLAGS) + + sysupgrade.set_upgrade_state('http', 'fix_serv_cert_trust_flags', True) + +-- +2.9.4 + diff --git a/SOURCES/0143-trustdomain-del-fix-the-way-how-subdomain-is-searche.patch b/SOURCES/0143-trustdomain-del-fix-the-way-how-subdomain-is-searche.patch deleted file mode 100644 index 035a451..0000000 --- a/SOURCES/0143-trustdomain-del-fix-the-way-how-subdomain-is-searche.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 99c93ce55d740fd8c6901dc3cfa3ecbf71edbff8 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 31 Oct 2016 18:17:35 +0200 -Subject: [PATCH] trustdomain-del: fix the way how subdomain is searched - -With FreeIPA 4.4 we moved child domains behind the 'trustdomain' topic. -Update 'ipa trustdomain-del' command to properly calculate DN to the -actual child domain and handle the case when it is missing correctly. - -Fixes https://fedorahosted.org/freeipa/ticket/6445 - -Reviewed-By: Martin Babinsky ---- - ipaserver/plugins/trust.py | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index 720a45a4d12d59f00e3e63f2b4f62edd45646065..723dba6a26311752ecde8589d22e2911b72e8044 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -1614,13 +1614,16 @@ class trustdomain_del(LDAPDelete): - # to always receive empty keys. We need to catch the case when root domain is being deleted - - for domain in keys[1]: -- # Fetch the trust to verify that the entered domain is trusted -- self.api.Command.trust_show(domain) -+ try: -+ self.obj.get_dn_if_exists(keys[0], domain, trust_type=u'ad') -+ except errors.NotFound: -+ if keys[0].lower() == domain: -+ raise errors.ValidationError( -+ name='domain', -+ error=_("cannot delete root domain of the trust, " -+ "use trust-del to delete the trust itself")) -+ self.obj.handle_not_found(keys[0], domain) - -- if keys[0].lower() == domain: -- raise errors.ValidationError(name='domain', -- error=_("cannot delete root domain of the trust, " -- "use trust-del to delete the trust itself")) - try: - res = self.api.Command.trustdomain_enable(keys[0], domain) - except errors.AlreadyActive: --- -2.7.4 - diff --git a/SOURCES/0144-certdb-certs-make-trust-flags-argument-mandatory.patch b/SOURCES/0144-certdb-certs-make-trust-flags-argument-mandatory.patch new file mode 100644 index 0000000..8ed40ad --- /dev/null +++ b/SOURCES/0144-certdb-certs-make-trust-flags-argument-mandatory.patch @@ -0,0 +1,181 @@ +From 997ebc0f56963769bdcbeda60a2dca222c884b1e Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 27 Apr 2017 09:57:45 +0200 +Subject: [PATCH] certdb, certs: make trust flags argument mandatory + +Make the trust flags argument mandatory in all functions in `certdb` and +`certs`. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipapython/certdb.py | 4 +--- + ipaserver/install/certs.py | 11 +++++------ + ipaserver/install/dsinstance.py | 2 +- + ipaserver/install/httpinstance.py | 6 ++++-- + ipaserver/install/installutils.py | 5 +++-- + ipaserver/install/server/replicainstall.py | 4 ++-- + 6 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index 44c7bf3197c198295035742e6db48527d76e85a6..88dcae750de5881ae7b4921ca1ae23daa9c5d4b0 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -471,14 +471,12 @@ class NSSDatabase(object): + + self.import_pkcs12(out_file.name, out_password) + +- def trust_root_cert(self, root_nickname, trust_flags=None): ++ def trust_root_cert(self, root_nickname, trust_flags): + if root_nickname[:7] == "Builtin": + root_logger.debug( + "No need to add trust for built-in root CAs, skipping %s" % + root_nickname) + else: +- if trust_flags is None: +- trust_flags = EXTERNAL_CA_TRUST_FLAGS + try: + self.run_certutil(["-M", "-n", root_nickname, + "-t", trust_flags]) +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index f87e00eb5e9c14ed30d39ef9f6e86b6f24bb1c61..17b9ebad4a128e292e453af44ca9d63cfb1e6ea2 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -550,7 +550,7 @@ class CertDB(object): + + return root_nicknames + +- def trust_root_cert(self, root_nickname, trust_flags=None): ++ def trust_root_cert(self, root_nickname, trust_flags): + if root_nickname is None: + root_logger.debug("Unable to identify root certificate to trust. Continuing but things are likely to fail.") + return +@@ -600,14 +600,13 @@ class CertDB(object): + self.create_certdbs() + self.load_cacert(cacert_fname, IPA_CA_TRUST_FLAGS) + +- def create_from_pkcs12(self, pkcs12_fname, pkcs12_passwd, passwd=None, +- ca_file=None, trust_flags=None): ++ def create_from_pkcs12(self, pkcs12_fname, pkcs12_passwd, ++ ca_file, trust_flags): + """Create a new NSS database using the certificates in a PKCS#12 file. + + pkcs12_fname: the filename of the PKCS#12 file + pkcs12_pwd_fname: the file containing the pin for the PKCS#12 file + nickname: the nickname/friendly-name of the cert we are loading +- passwd: The password to use for the new NSS database we are creating + + The global CA may be added as well in case it wasn't included in the + PKCS#12 file. Extra certs won't hurt in any case. +@@ -615,7 +614,7 @@ class CertDB(object): + The global CA may be specified in ca_file, as a PEM filename. + """ + self.create_noise_file() +- self.create_passwd_file(passwd) ++ self.create_passwd_file() + self.create_certdbs() + self.init_from_pkcs12( + pkcs12_fname, +@@ -624,7 +623,7 @@ class CertDB(object): + trust_flags=trust_flags) + + def init_from_pkcs12(self, pkcs12_fname, pkcs12_passwd, +- ca_file=None, trust_flags=None): ++ ca_file, trust_flags): + self.import_pkcs12(pkcs12_fname, pkcs12_passwd) + server_certs = self.find_server_certs() + if len(server_certs) == 0: +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 0db0368fa4b48495718afd779291ce164d1687c8..0e4ae4bfe6f1445de167df8fe5328d6a421e416f 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -769,7 +769,7 @@ class DsInstance(service.Service): + if self.ca_is_configured: + trust_flags = IPA_CA_TRUST_FLAGS + else: +- trust_flags = None ++ trust_flags = EXTERNAL_CA_TRUST_FLAGS + dsdb.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], + ca_file=self.ca_file, + trust_flags=trust_flags) +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index a6aeb21edc73783ff9a3f9b526409ea525aa66dd..c76a1a4e484c5777ced92761916c1c586e8b2d5d 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -32,7 +32,9 @@ import six + from augeas import Augeas + + from ipalib.install import certmonger +-from ipapython.certdb import IPA_CA_TRUST_FLAGS, TRUSTED_PEER_TRUST_FLAGS ++from ipapython.certdb import (IPA_CA_TRUST_FLAGS, ++ EXTERNAL_CA_TRUST_FLAGS, ++ TRUSTED_PEER_TRUST_FLAGS) + from ipaserver.install import service + from ipaserver.install import certs + from ipaserver.install import installutils +@@ -384,7 +386,7 @@ class HTTPInstance(service.Service): + if self.ca_is_configured: + trust_flags = IPA_CA_TRUST_FLAGS + else: +- trust_flags = None ++ trust_flags = EXTERNAL_CA_TRUST_FLAGS + db.init_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], + ca_file=self.ca_file, + trust_flags=trust_flags) +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index b6f01489ccc65dcbc360929e0a7b315b074df8ce..0445a1d3c403fab690e5afb7c8801ed85773b1e0 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -49,6 +49,7 @@ from ipalib.install.kinit import kinit_password + import ipaplatform + from ipapython import ipautil, admintool, version + from ipapython.admintool import ScriptError ++from ipapython.certdb import EXTERNAL_CA_TRUST_FLAGS + from ipapython.ipa_log_manager import root_logger + from ipapython.ipaldap import DIRMAN_DN, LDAPClient + from ipalib.util import validate_hostname +@@ -1036,7 +1037,7 @@ def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files, + if 'u' in trust_flags: + key_nickname = nickname + continue +- nssdb.trust_root_cert(nickname) ++ nssdb.trust_root_cert(nickname, EXTERNAL_CA_TRUST_FLAGS) + + # Check we have the whole cert chain & the CA is in it + trust_chain = list(reversed(nssdb.get_trust_chain(key_nickname))) +@@ -1176,7 +1177,7 @@ def load_external_cert(files, ca_subject): + cache[nickname] = (cert, subject, issuer) + if subject == ca_subject: + ca_nickname = nickname +- nssdb.trust_root_cert(nickname) ++ nssdb.trust_root_cert(nickname, EXTERNAL_CA_TRUST_FLAGS) + + if ca_nickname is None: + raise ScriptError( +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 5e78e6faf51ded2fe7634f230c66aa15ae84bad4..fb738cb9f590f3f9595de92ef025c6032e9343f8 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -23,7 +23,7 @@ import ipaclient.install.ntpconf + from ipalib.install import certstore, sysrestore + from ipalib.install.kinit import kinit_keytab + from ipapython import ipaldap, ipautil +-from ipapython.certdb import IPA_CA_TRUST_FLAGS ++from ipapython.certdb import IPA_CA_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS + from ipapython.dn import DN + from ipapython.ipa_log_manager import root_logger + from ipapython.admintool import ScriptError +@@ -740,7 +740,7 @@ def install_check(installer): + if ca_enabled: + trust_flags = IPA_CA_TRUST_FLAGS + else: +- trust_flags = None ++ trust_flags = EXTERNAL_CA_TRUST_FLAGS + tmp_db.create_from_pkcs12(pkcs12_info[0], pkcs12_info[1], + ca_file=cafile, + trust_flags=trust_flags) +-- +2.9.4 + diff --git a/SOURCES/0144-spec-file-bump-minimal-required-version-of-389-ds-ba.patch b/SOURCES/0144-spec-file-bump-minimal-required-version-of-389-ds-ba.patch deleted file mode 100644 index 953b80e..0000000 --- a/SOURCES/0144-spec-file-bump-minimal-required-version-of-389-ds-ba.patch +++ /dev/null @@ -1,40 +0,0 @@ -From df19f8d314894b747181c5bb360a79e519065798 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Tue, 1 Nov 2016 11:36:30 +0100 -Subject: [PATCH] spec file: bump minimal required version of 389-ds-base - -Require 389-ds-base >= 1.3.5.14 for: -https://fedorahosted.org/389/ticket/48992 - -https://fedorahosted.org/freeipa/ticket/6369 - -Reviewed-By: Stanislav Laznicka ---- - freeipa.spec.in | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 7456a9ea77ec289312eb11c05709018b3d6d0c90..dba59edc2dc1c6dd12017fbc5c9a6f7bb385e7c3 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -135,7 +135,7 @@ Requires: %{name}-client = %{version}-%{release} - Requires: %{name}-admintools = %{version}-%{release} - Requires: %{name}-common = %{version}-%{release} - Requires: python2-ipaserver = %{version}-%{release} --Requires: 389-ds-base >= 1.3.5.6 -+Requires: 389-ds-base >= 1.3.5.14 - Requires: openldap-clients > 2.4.35-4 - Requires: nss >= 3.14.3-12.0 - Requires: nss-tools >= 3.14.3-12.0 -@@ -167,7 +167,7 @@ Requires: zip - Requires: policycoreutils >= 2.1.12-5 - Requires: tar - Requires(pre): certmonger >= 0.78 --Requires(pre): 389-ds-base >= 1.3.5.6 -+Requires(pre): 389-ds-base >= 1.3.5.14 - Requires: fontawesome-fonts - Requires: open-sans-fonts - Requires: openssl --- -2.7.4 - diff --git a/SOURCES/0145-certdb-use-custom-object-for-trust-flags.patch b/SOURCES/0145-certdb-use-custom-object-for-trust-flags.patch new file mode 100644 index 0000000..6699565 --- /dev/null +++ b/SOURCES/0145-certdb-use-custom-object-for-trust-flags.patch @@ -0,0 +1,358 @@ +From e8805e118446a1ad542d183e2f6bea0f87651795 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 27 Apr 2017 09:37:38 +0200 +Subject: [PATCH] certdb: use custom object for trust flags + +Replace trust flag strings with `TrustFlags` objects. The `TrustFlags` +class encapsulates `certstore` key policy and has an additional flag +indicating the presence of a private key. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + install/restart_scripts/renew_ca_cert | 2 +- + ipalib/install/certstore.py | 49 +------------ + ipapython/certdb.py | 109 ++++++++++++++++++++++++++-- + ipaserver/install/installutils.py | 2 +- + ipaserver/install/ipa_cacert_manage.py | 6 +- + ipaserver/install/ipa_server_certinstall.py | 4 +- + ipaserver/install/plugins/upload_cacrt.py | 2 +- + ipaserver/install/server/upgrade.py | 2 +- + 8 files changed, 117 insertions(+), 59 deletions(-) + +diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert +index 7a54b4c7e05a35b40b17e46b75ff8d47db1b2d23..bb31defc0e2bdca044e68ae067f42fb3bd41a57f 100644 +--- a/install/restart_scripts/renew_ca_cert ++++ b/install/restart_scripts/renew_ca_cert +@@ -125,7 +125,7 @@ def _main(): + + # Remove old external CA certificates + for ca_nick, ca_flags in db.list_certs(): +- if 'u' in ca_flags: ++ if ca_flags.has_key: + continue + # Delete *all* certificates that use the nickname + while True: +diff --git a/ipalib/install/certstore.py b/ipalib/install/certstore.py +index 310e08ed2273badba6fde4ada0ee52501fddc72c..bc2079fb12873444cbe6796eebfdfcfebd0e284d 100644 +--- a/ipalib/install/certstore.py ++++ b/ipalib/install/certstore.py +@@ -25,7 +25,7 @@ LDAP shared certificate store. + from pyasn1.error import PyAsn1Error + + from ipapython.dn import DN +-from ipapython.certdb import get_ca_nickname ++from ipapython.certdb import get_ca_nickname, TrustFlags + from ipalib import errors, x509 + + def _parse_cert(dercert): +@@ -344,57 +344,14 @@ def trust_flags_to_key_policy(trust_flags): + """ + Convert certutil trust flags to certificate store key policy. + """ +- if 'p' in trust_flags: +- if 'C' in trust_flags or 'P' in trust_flags or 'T' in trust_flags: +- raise ValueError("cannot be both trusted and not trusted") +- return False, None, None +- elif 'C' in trust_flags or 'T' in trust_flags: +- if 'P' in trust_flags: +- raise ValueError("cannot be both CA and not CA") +- ca = True +- elif 'P' in trust_flags: +- ca = False +- else: +- return None, None, set() +- +- trust_flags = trust_flags.split(',') +- ext_key_usage = set() +- for i, kp in enumerate((x509.EKU_SERVER_AUTH, +- x509.EKU_EMAIL_PROTECTION, +- x509.EKU_CODE_SIGNING)): +- if 'C' in trust_flags[i] or 'P' in trust_flags[i]: +- ext_key_usage.add(kp) +- if 'T' in trust_flags[0]: +- ext_key_usage.add(x509.EKU_CLIENT_AUTH) +- +- return True, ca, ext_key_usage ++ return trust_flags[1:] + + + def key_policy_to_trust_flags(trusted, ca, ext_key_usage): + """ + Convert certificate store key policy to certutil trust flags. + """ +- if trusted is False: +- return 'p,p,p' +- elif trusted is None or ca is None: +- return ',,' +- elif ext_key_usage is None: +- if ca: +- return 'CT,C,C' +- else: +- return 'P,P,P' +- +- trust_flags = ['', '', ''] +- for i, kp in enumerate((x509.EKU_SERVER_AUTH, +- x509.EKU_EMAIL_PROTECTION, +- x509.EKU_CODE_SIGNING)): +- if kp in ext_key_usage: +- trust_flags[i] += ('C' if ca else 'P') +- if ca and x509.EKU_CLIENT_AUTH in ext_key_usage: +- trust_flags[0] += 'T' +- +- trust_flags = ','.join(trust_flags) +- return trust_flags ++ return TrustFlags(False, trusted, ca, ext_key_usage) + + + def put_ca_cert_nss(ldap, base_dn, dercert, nickname, trust_flags, +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index 88dcae750de5881ae7b4921ca1ae23daa9c5d4b0..af95eba3cbad1c354615457ed0501f97bff0e22d 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -17,6 +17,7 @@ + # along with this program. If not, see . + # + ++import collections + import os + import io + import pwd +@@ -52,10 +53,26 @@ CA_NICKNAME_FMT = "%s IPA CA" + + NSS_FILES = ("cert8.db", "key3.db", "secmod.db", "pwdfile.txt") + +-EMPTY_TRUST_FLAGS = ',,' +-IPA_CA_TRUST_FLAGS = 'CT,C,C' +-EXTERNAL_CA_TRUST_FLAGS = 'C,,' +-TRUSTED_PEER_TRUST_FLAGS = 'P,,' ++TrustFlags = collections.namedtuple('TrustFlags', 'has_key trusted ca usages') ++ ++EMPTY_TRUST_FLAGS = TrustFlags(False, None, None, None) ++ ++IPA_CA_TRUST_FLAGS = TrustFlags( ++ False, True, True, frozenset({ ++ x509.EKU_SERVER_AUTH, ++ x509.EKU_CLIENT_AUTH, ++ x509.EKU_CODE_SIGNING, ++ x509.EKU_EMAIL_PROTECTION, ++ }), ++) ++ ++EXTERNAL_CA_TRUST_FLAGS = TrustFlags( ++ False, True, True, frozenset({x509.EKU_SERVER_AUTH}), ++) ++ ++TRUSTED_PEER_TRUST_FLAGS = TrustFlags( ++ False, True, False, frozenset({x509.EKU_SERVER_AUTH}), ++) + + + def get_ca_nickname(realm, format=CA_NICKNAME_FMT): +@@ -87,6 +104,82 @@ def get_file_cont(slot, token, filename): + return f.read() + + ++def parse_trust_flags(trust_flags): ++ """ ++ Convert certutil trust flags to TrustFlags object. ++ """ ++ has_key = 'u' in trust_flags ++ ++ if 'p' in trust_flags: ++ if 'C' in trust_flags or 'P' in trust_flags or 'T' in trust_flags: ++ raise ValueError("cannot be both trusted and not trusted") ++ return False, None, None ++ elif 'C' in trust_flags or 'T' in trust_flags: ++ if 'P' in trust_flags: ++ raise ValueError("cannot be both CA and not CA") ++ ca = True ++ elif 'P' in trust_flags: ++ ca = False ++ else: ++ return TrustFlags(has_key, None, None, frozenset()) ++ ++ trust_flags = trust_flags.split(',') ++ ext_key_usage = set() ++ for i, kp in enumerate((x509.EKU_SERVER_AUTH, ++ x509.EKU_EMAIL_PROTECTION, ++ x509.EKU_CODE_SIGNING)): ++ if 'C' in trust_flags[i] or 'P' in trust_flags[i]: ++ ext_key_usage.add(kp) ++ if 'T' in trust_flags[0]: ++ ext_key_usage.add(x509.EKU_CLIENT_AUTH) ++ ++ return TrustFlags(has_key, True, ca, frozenset(ext_key_usage)) ++ ++ ++def unparse_trust_flags(trust_flags): ++ """ ++ Convert TrustFlags object to certutil trust flags. ++ """ ++ has_key, trusted, ca, ext_key_usage = trust_flags ++ ++ if trusted is False: ++ if has_key: ++ return 'pu,pu,pu' ++ else: ++ return 'p,p,p' ++ elif trusted is None or ca is None: ++ if has_key: ++ return 'u,u,u' ++ else: ++ return ',,' ++ elif ext_key_usage is None: ++ if ca: ++ if has_key: ++ return 'CTu,Cu,Cu' ++ else: ++ return 'CT,C,C' ++ else: ++ if has_key: ++ return 'Pu,Pu,Pu' ++ else: ++ return 'P,P,P' ++ ++ trust_flags = ['', '', ''] ++ for i, kp in enumerate((x509.EKU_SERVER_AUTH, ++ x509.EKU_EMAIL_PROTECTION, ++ x509.EKU_CODE_SIGNING)): ++ if kp in ext_key_usage: ++ trust_flags[i] += ('C' if ca else 'P') ++ if ca and x509.EKU_CLIENT_AUTH in ext_key_usage: ++ trust_flags[0] += 'T' ++ if has_key: ++ for i in range(3): ++ trust_flags[i] += 'u' ++ ++ trust_flags = ','.join(trust_flags) ++ return trust_flags ++ ++ + class NSSDatabase(object): + """A general-purpose wrapper around a NSS cert database + +@@ -205,7 +298,9 @@ class NSSDatabase(object): + for cert in certs: + match = re.match(r'^(.+?)\s+(\w*,\w*,\w*)\s*$', cert) + if match: +- certlist.append(match.groups()) ++ nickname = match.group(1) ++ trust_flags = parse_trust_flags(match.group(2)) ++ certlist.append((nickname, trust_flags)) + + return tuple(certlist) + +@@ -218,7 +313,7 @@ class NSSDatabase(object): + """ + server_certs = [] + for name, flags in self.list_certs(): +- if 'u' in flags: ++ if flags.has_key: + server_certs.append((name, flags)) + + return server_certs +@@ -477,6 +572,7 @@ class NSSDatabase(object): + "No need to add trust for built-in root CAs, skipping %s" % + root_nickname) + else: ++ trust_flags = unparse_trust_flags(trust_flags) + try: + self.run_certutil(["-M", "-n", root_nickname, + "-t", trust_flags]) +@@ -538,6 +634,7 @@ class NSSDatabase(object): + location) + + def add_cert(self, cert, nick, flags, pem=False): ++ flags = unparse_trust_flags(flags) + args = ["-A", "-n", nick, "-t", flags] + if pem: + args.append("-a") +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 0445a1d3c403fab690e5afb7c8801ed85773b1e0..5bce9894780bd920db11196b925492a7fe8f22d0 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -1034,7 +1034,7 @@ def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files, + raise ScriptError(str(e)) + + for nickname, trust_flags in nssdb.list_certs(): +- if 'u' in trust_flags: ++ if trust_flags.has_key: + key_nickname = nickname + continue + nssdb.trust_root_cert(nickname, EXTERNAL_CA_TRUST_FLAGS) +diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py +index 88b40d45e10281d272882d21e06f5d53cf5a701d..d28a5966f054141819463cdb1dfef48ee1e46e92 100644 +--- a/ipaserver/install/ipa_cacert_manage.py ++++ b/ipaserver/install/ipa_cacert_manage.py +@@ -26,7 +26,9 @@ import gssapi + + from ipalib.install import certmonger, certstore + from ipapython import admintool, ipautil +-from ipapython.certdb import EMPTY_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS ++from ipapython.certdb import (EMPTY_TRUST_FLAGS, ++ EXTERNAL_CA_TRUST_FLAGS, ++ parse_trust_flags) + from ipapython.dn import DN + from ipaplatform.paths import paths + from ipalib import api, errors, x509 +@@ -366,6 +368,8 @@ class CACertManage(admintool.AdminTool): + len(trust_flags.split(',')) != 3): + raise admintool.ScriptError("Invalid trust flags") + ++ trust_flags = parse_trust_flags(trust_flags) ++ + try: + certstore.put_ca_cert_nss( + api.Backend.ldap2, api.env.basedn, cert, nickname, trust_flags) +diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py +index ee93535edfd258fe71099881c54c413516b24d17..9f2cd9573a156949ae979e7b69fbd23adaf2feb8 100644 +--- a/ipaserver/install/ipa_server_certinstall.py ++++ b/ipaserver/install/ipa_server_certinstall.py +@@ -170,13 +170,13 @@ class ServerCertInstall(admintool.AdminTool): + # this leaves only the server certs in the temp db + tempnssdb.import_pkcs12(pkcs12_filename, pkcs12_pin) + for nickname, flags in tempnssdb.list_certs(): +- if 'u' not in flags: ++ if not flags.has_key: + while tempnssdb.has_nickname(nickname): + tempnssdb.delete_cert(nickname) + + # import all the CA certs from nssdb into the temp db + for nickname, flags in nssdb.list_certs(): +- if 'u' not in flags: ++ if not flags.has_key: + cert = nssdb.get_cert_from_db(nickname) + tempnssdb.add_cert(cert, nickname, flags) + +diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py +index 7d294ff971bd109e5fbb3570bfff0198f24b68d3..73cc91d8f6dd5811ec74efecd6c885cd8937a0f2 100644 +--- a/ipaserver/install/plugins/upload_cacrt.py ++++ b/ipaserver/install/plugins/upload_cacrt.py +@@ -52,7 +52,7 @@ class update_upload_cacrt(Updater): + ldap = self.api.Backend.ldap2 + + for nickname, trust_flags in db.list_certs(): +- if 'u' in trust_flags: ++ if trust_flags.has_key: + continue + if nickname == ca_nickname and ca_enabled: + trust_flags = certdb.IPA_CA_TRUST_FLAGS +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 73a4f1108a56a766cdbbcb93d7050482a8264a75..c244958f4cddba0d1edded5165a295b1e1ee2b8a 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1547,7 +1547,7 @@ def disable_httpd_system_trust(http): + + db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) + for nickname, trust_flags in db.list_certs(): +- if 'u' not in trust_flags: ++ if not trust_flags.has_key: + cert = db.get_cert_from_db(nickname, pem=False) + if cert: + ca_certs.append((cert, nickname, trust_flags)) +-- +2.9.4 + diff --git a/SOURCES/0145-replication-ensure-bind-DN-group-check-interval-is-s.patch b/SOURCES/0145-replication-ensure-bind-DN-group-check-interval-is-s.patch deleted file mode 100644 index 245f42b..0000000 --- a/SOURCES/0145-replication-ensure-bind-DN-group-check-interval-is-s.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 405446b0f08551fa82fd0f6d71f219d68641732b Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Wed, 23 Nov 2016 16:58:39 +0100 -Subject: [PATCH] replication: ensure bind DN group check interval is set on - replica config - -This is a safeguard ensuring valid replica configuration against incorrectly -upgraded masters lacking 'nsds5replicabinddngroupcheckinterval' attribute on -their domain/ca topology config. - -https://fedorahosted.org/freeipa/ticket/6508 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/replication.py | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index b8b665267ea8debba9f0ce01f54a78cd67d88292..e9624894d7d1e745be8072268fa76d51a8c117e3 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -452,6 +452,12 @@ class ReplicationManager(object): - if replica_groupdn not in binddn_groups: - mod.append((ldap.MOD_ADD, 'nsds5replicabinddngroup', - replica_groupdn)) -+ -+ if 'nsds5replicabinddngroupcheckinterval' not in entry: -+ mod.append( -+ (ldap.MOD_ADD, -+ 'nsds5replicabinddngroupcheckinterval', -+ '60')) - if mod: - conn.modify_s(dn, mod) - --- -2.7.4 - diff --git a/SOURCES/0146-bindinstance-use-data-in-named.conf-to-determine-con.patch b/SOURCES/0146-bindinstance-use-data-in-named.conf-to-determine-con.patch deleted file mode 100644 index 268bb59..0000000 --- a/SOURCES/0146-bindinstance-use-data-in-named.conf-to-determine-con.patch +++ /dev/null @@ -1,38 +0,0 @@ -From b84a175ad6a8c2b25d6db388fa88e6441d97ae94 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Tue, 6 Dec 2016 12:13:34 +0100 -Subject: [PATCH] bindinstance: use data in named.conf to determine - configuration status - -Instead of checking sysrestore status which leads to incorrect -evaluation of DNS configuration status during 4.2 -> 4.4 upgrade, look -into named.conf to see whther it was already modified by IPA installer. - -https://fedorahosted.org/freeipa/ticket/6503 - -Reviewed-By: Martin Basti ---- - ipaserver/install/bindinstance.py | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 7538e145cbe37dfc21963d97dea0e835e3bd5072..a65b065fd654655ff034e277eb7e0ad49e4a418e 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -1170,6 +1170,13 @@ class BindInstance(service.Service): - self.api.Command.dnsconfig_show.output_for_cli(textui, result, None, - reverse=False) - -+ def is_configured(self): -+ """ -+ Override the default logic querying StateFile for configuration status -+ and look whether named.conf was already modified by IPA installer. -+ """ -+ return named_conf_exists() -+ - def uninstall(self): - if self.is_configured(): - self.print_msg("Unconfiguring %s" % self.service_name) --- -2.7.4 - diff --git a/SOURCES/0146-install-trust-IPA-CA-for-PKINIT.patch b/SOURCES/0146-install-trust-IPA-CA-for-PKINIT.patch new file mode 100644 index 0000000..c69b8f0 --- /dev/null +++ b/SOURCES/0146-install-trust-IPA-CA-for-PKINIT.patch @@ -0,0 +1,202 @@ +From e45762bf5b94c064668752160271a00af854b6cf Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:38:20 +0000 +Subject: [PATCH] install: trust IPA CA for PKINIT + +Trust IPA CA to issue PKINIT KDC and client authentication certificates in +the IPA certificate store. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipalib/x509.py | 2 ++ + ipapython/certdb.py | 2 ++ + ipaserver/install/dsinstance.py | 31 +++++++++++++++++++++++------- + ipaserver/install/plugins/upload_cacrt.py | 6 +++++- + ipaserver/install/server/install.py | 9 ++++++--- + ipaserver/install/server/replicainstall.py | 1 + + 6 files changed, 40 insertions(+), 11 deletions(-) + +diff --git a/ipalib/x509.py b/ipalib/x509.py +index f65cf816c9ead50a43e08a3b982f428112e7c1b3..5d1a7b8f4b99e057d4732d388efb0f27def07085 100644 +--- a/ipalib/x509.py ++++ b/ipalib/x509.py +@@ -64,6 +64,8 @@ EKU_SERVER_AUTH = '1.3.6.1.5.5.7.3.1' + EKU_CLIENT_AUTH = '1.3.6.1.5.5.7.3.2' + EKU_CODE_SIGNING = '1.3.6.1.5.5.7.3.3' + EKU_EMAIL_PROTECTION = '1.3.6.1.5.5.7.3.4' ++EKU_PKINIT_CLIENT_AUTH = '1.3.6.1.5.2.3.4' ++EKU_PKINIT_KDC = '1.3.6.1.5.2.3.5' + EKU_ANY = '2.5.29.37.0' + EKU_PLACEHOLDER = '1.3.6.1.4.1.3319.6.10.16' + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index af95eba3cbad1c354615457ed0501f97bff0e22d..1ee2603653452577476cf413e6af951cd29c273e 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -63,6 +63,8 @@ IPA_CA_TRUST_FLAGS = TrustFlags( + x509.EKU_CLIENT_AUTH, + x509.EKU_CODE_SIGNING, + x509.EKU_EMAIL_PROTECTION, ++ x509.EKU_PKINIT_CLIENT_AUTH, ++ x509.EKU_PKINIT_KDC, + }), + ) + +diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py +index 0e4ae4bfe6f1445de167df8fe5328d6a421e416f..39248edb285ee4d792b4500d83d88b24f5732d10 100644 +--- a/ipaserver/install/dsinstance.py ++++ b/ipaserver/install/dsinstance.py +@@ -31,8 +31,11 @@ import fnmatch + + import ldap + ++from ipalib import x509 + from ipalib.install import certmonger, certstore +-from ipapython.certdb import IPA_CA_TRUST_FLAGS, EXTERNAL_CA_TRUST_FLAGS ++from ipapython.certdb import (IPA_CA_TRUST_FLAGS, ++ EXTERNAL_CA_TRUST_FLAGS, ++ TrustFlags) + from ipapython.ipa_log_manager import root_logger + from ipapython import ipautil, ipaldap + from ipapython import dogtag +@@ -289,7 +292,8 @@ class DsInstance(service.Service): + + def init_info(self, realm_name, fqdn, domain_name, dm_password, + subject_base, ca_subject, +- idstart, idmax, pkcs12_info, ca_file=None): ++ idstart, idmax, pkcs12_info, ca_file=None, ++ setup_pkinit=False): + self.realm = realm_name.upper() + self.serverid = installutils.realm_to_serverid(self.realm) + self.suffix = ipautil.realm_to_suffix(self.realm) +@@ -303,6 +307,7 @@ class DsInstance(service.Service): + self.pkcs12_info = pkcs12_info + if pkcs12_info: + self.ca_is_configured = False ++ self.setup_pkinit = setup_pkinit + self.ca_file = ca_file + + self.__setup_sub_dict() +@@ -311,11 +316,12 @@ class DsInstance(service.Service): + dm_password, pkcs12_info=None, + idstart=1100, idmax=999999, + subject_base=None, ca_subject=None, +- hbac_allow=True, ca_file=None): ++ hbac_allow=True, ca_file=None, setup_pkinit=False): + self.init_info( + realm_name, fqdn, domain_name, dm_password, + subject_base, ca_subject, +- idstart, idmax, pkcs12_info, ca_file=ca_file) ++ idstart, idmax, pkcs12_info, ca_file=ca_file, ++ setup_pkinit=setup_pkinit) + + self.__common_setup() + self.step("restarting directory server", self.__restart_instance) +@@ -354,7 +360,8 @@ class DsInstance(service.Service): + domain_name, dm_password, + subject_base, ca_subject, + api, pkcs12_info=None, ca_file=None, +- ca_is_configured=None, promote=False): ++ ca_is_configured=None, promote=False, ++ setup_pkinit=False): + # idstart and idmax are configured so that the range is seen as + # depleted by the DNA plugin and the replica will go and get a + # new range from the master. +@@ -372,7 +379,8 @@ class DsInstance(service.Service): + idstart=idstart, + idmax=idmax, + pkcs12_info=pkcs12_info, +- ca_file=ca_file ++ ca_file=ca_file, ++ setup_pkinit=setup_pkinit, + ) + self.master_fqdn = master_fqdn + if ca_is_configured is not None: +@@ -882,8 +890,17 @@ class DsInstance(service.Service): + + nickname = self.cacert_name + cert = dsdb.get_cert_from_db(nickname, pem=False) ++ cacert_flags = trust_flags[nickname] ++ if self.setup_pkinit: ++ cacert_flags = TrustFlags( ++ cacert_flags.has_key, ++ cacert_flags.trusted, ++ cacert_flags.ca, ++ (cacert_flags.usages | ++ {x509.EKU_PKINIT_CLIENT_AUTH, x509.EKU_PKINIT_KDC}), ++ ) + certstore.put_ca_cert_nss(conn, self.suffix, cert, nickname, +- trust_flags[nickname], ++ cacert_flags, + config_ipa=self.ca_is_configured, + config_compat=self.master_fqdn is None) + +diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py +index 73cc91d8f6dd5811ec74efecd6c885cd8937a0f2..a1957ca5b675b86f0df36dc820ee31305f54f863 100644 +--- a/ipaserver/install/plugins/upload_cacrt.py ++++ b/ipaserver/install/plugins/upload_cacrt.py +@@ -79,7 +79,11 @@ class update_upload_cacrt(Updater): + try: + ldap.add_entry(entry) + except errors.DuplicateEntry: +- pass ++ if nickname == ca_nickname and ca_enabled: ++ try: ++ ldap.update_entry(entry) ++ except errors.EmptyModlist: ++ pass + + if ca_cert: + dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn','etc'), +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 0ce60e964cb210708e56fb43a5b70f8e3405caf2..25c21db721c58388ae8fd6ab1fbc443d513a4324 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -737,7 +737,8 @@ def install(installer): + idstart=options.idstart, idmax=options.idmax, + subject_base=options.subject_base, + ca_subject=options.ca_subject, +- hbac_allow=not options.no_hbac_allow) ++ hbac_allow=not options.no_hbac_allow, ++ setup_pkinit=not options.no_pkinit) + else: + ds = dsinstance.DsInstance(fstore=fstore, + domainlevel=options.domainlevel, +@@ -748,7 +749,8 @@ def install(installer): + idstart=options.idstart, idmax=options.idmax, + subject_base=options.subject_base, + ca_subject=options.ca_subject, +- hbac_allow=not options.no_hbac_allow) ++ hbac_allow=not options.no_hbac_allow, ++ setup_pkinit=not options.no_pkinit) + + ntpinstance.ntp_ldap_enable(host_name, ds.suffix, realm_name) + +@@ -759,7 +761,8 @@ def install(installer): + installer._ds = ds + ds.init_info( + realm_name, host_name, domain_name, dm_password, +- options.subject_base, options.ca_subject, 1101, 1100, None) ++ options.subject_base, options.ca_subject, 1101, 1100, None, ++ setup_pkinit=not options.no_pkinit) + + krb = krbinstance.KrbInstance(fstore) + if not options.external_cert_files: +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index fb738cb9f590f3f9595de92ef025c6032e9343f8..c19edceec42845f3169adc923762f700739232f2 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -107,6 +107,7 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, + ca_file=ca_file, + promote=promote, # we need promote because of replication setup + api=remote_api, ++ setup_pkinit=not options.no_pkinit, + ) + + return ds +-- +2.9.4 + diff --git a/SOURCES/0147-client-install-fix-client-PKINIT-configuration.patch b/SOURCES/0147-client-install-fix-client-PKINIT-configuration.patch new file mode 100644 index 0000000..2f7ca49 --- /dev/null +++ b/SOURCES/0147-client-install-fix-client-PKINIT-configuration.patch @@ -0,0 +1,254 @@ +From e5491b62d3ec21feb7809f7f65797151d256c580 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:48:57 +0000 +Subject: [PATCH] client install: fix client PKINIT configuration + +Set `pkinit_anchors` in `krb5.conf` to a CA certificate bundle of CAs +trusted to issue KDC certificates rather than `/etc/ipa/ca.crt`. + +Set `pkinit_pool` in `krb5.conf` to a CA certificate bundle of all CAs +known to IPA. + +Make sure both bundles are exported in all installation code paths. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + client/Makefile.am | 1 + + freeipa.spec.in | 10 ++++++++++ + install/share/krb5.conf.template | 3 ++- + ipaclient/install/client.py | 15 ++++++++++++++- + ipaclient/install/ipa_certupdate.py | 2 ++ + ipaplatform/base/paths.py | 2 ++ + ipaserver/install/cainstance.py | 11 +++++++---- + ipaserver/install/ipa_backup.py | 2 ++ + ipaserver/install/krbinstance.py | 4 +++- + ipaserver/install/server/install.py | 10 ++++++++++ + ipaserver/install/server/replicainstall.py | 4 ++++ + ipaserver/install/server/upgrade.py | 4 +++- + 12 files changed, 60 insertions(+), 8 deletions(-) + +diff --git a/client/Makefile.am b/client/Makefile.am +index b6c9dea437460b0f912854a6a2fb9d1f30f3b1e7..e354cb41a4ee0d7da04197abe0e750c5d727bb4d 100644 +--- a/client/Makefile.am ++++ b/client/Makefile.am +@@ -101,4 +101,5 @@ EXTRA_DIST = \ + + install-data-hook: + $(INSTALL) -d -m 755 $(DESTDIR)$(IPA_SYSCONF_DIR)/nssdb ++ $(INSTALL) -d -m 755 $(DESTDIR)$(localstatedir)/lib/ipa-client/pki + $(INSTALL) -d -m 755 $(DESTDIR)$(localstatedir)/lib/ipa-client/sysrestore +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 0335a9970be82e80e98696f3d7fd4ec64894ef5f..6cb37ae53b039aa1d0e0509f62a3237504be6555 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -1097,6 +1097,15 @@ if [ $1 -gt 1 ] ; then + fi + fi + ++ if [ $restore -ge 2 ]; then ++ if grep -E -q '\s*pkinit_anchors = FILE:/etc/ipa/ca.crt$' /etc/krb5.conf 2>/dev/null; then ++ sed -E 's|(\s*)pkinit_anchors = FILE:/etc/ipa/ca.crt$|\1pkinit_anchors = FILE:/var/lib/ipa-client/pki/kdc-ca-bundle.pem\n\1pkinit_pool = FILE:/var/lib/ipa-client/pki/ca-bundle.pem|' /etc/krb5.conf >/etc/krb5.conf.ipanew ++ mv -Z /etc/krb5.conf.ipanew /etc/krb5.conf ++ cp /etc/ipa/ca.crt /var/lib/ipa-client/pki/kdc-ca-bundle.pem ++ cp /etc/ipa/ca.crt /var/lib/ipa-client/pki/ca-bundle.pem ++ fi ++ fi ++ + if [ -f '/etc/sysconfig/ntpd' -a $restore -ge 2 ]; then + if grep -E -q 'OPTIONS=.*-u ntp:ntp' /etc/sysconfig/ntpd 2>/dev/null; then + sed -r '/OPTIONS=/ { s/\s+-u ntp:ntp\s+/ /; s/\s*-u ntp:ntp\s*// }' /etc/sysconfig/ntpd >/etc/sysconfig/ntpd.ipanew +@@ -1468,6 +1477,7 @@ fi + %ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt + %ghost %config(noreplace) %{_sysconfdir}/pki/ca-trust/source/ipa.p11-kit + %dir %{_localstatedir}/lib/ipa-client ++%dir %{_localstatedir}/lib/ipa-client/pki + %dir %{_localstatedir}/lib/ipa-client/sysrestore + %{_mandir}/man5/default.conf.5* + +diff --git a/install/share/krb5.conf.template b/install/share/krb5.conf.template +index e8b2ad8dace8264cd9345285f55c42422bf81ca3..1f18ff90d34ccccb42c4b64d188e7d70e9892b71 100644 +--- a/install/share/krb5.conf.template ++++ b/install/share/krb5.conf.template +@@ -21,7 +21,8 @@ $OTHER_LIBDEFAULTS + master_kdc = $FQDN:88 + admin_server = $FQDN:749 + default_domain = $DOMAIN +- pkinit_anchors = FILE:/etc/ipa/ca.crt ++ pkinit_anchors = FILE:$KDC_CA_BUNDLE_PEM ++ pkinit_pool = FILE:$CA_BUNDLE_PEM + } + + [domain_realm] +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index e78be904dd6bad491d9f3c1bb1e1410bc1779d45..6f10f5258747881b9af8c6b70b499f9ff7d577ff 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -710,7 +710,11 @@ def configure_krb5_conf( + kropts.append(krbconf.setOption('default_domain', cli_domain)) + + kropts.append( +- krbconf.setOption('pkinit_anchors', 'FILE:%s' % paths.IPA_CA_CRT)) ++ krbconf.setOption('pkinit_anchors', ++ 'FILE:%s' % paths.KDC_CA_BUNDLE_PEM)) ++ kropts.append( ++ krbconf.setOption('pkinit_pool', ++ 'FILE:%s' % paths.CA_BUNDLE_PEM)) + ropts = [{ + 'name': cli_realm, + 'type': 'subsection', +@@ -2770,6 +2774,13 @@ def _install(options): + ca_certs_trust = [(c, n, certstore.key_policy_to_trust_flags(t, True, u)) + for (c, n, t, u) in ca_certs] + ++ x509.write_certificate_list( ++ [c for c, n, t, u in ca_certs if t is not False], ++ paths.KDC_CA_BUNDLE_PEM) ++ x509.write_certificate_list( ++ [c for c, n, t, u in ca_certs if t is not False], ++ paths.CA_BUNDLE_PEM) ++ + # Add the CA certificates to the IPA NSS database + root_logger.debug("Adding CA certificates to the IPA NSS database.") + ipa_db = certdb.NSSDatabase(paths.IPA_NSSDB_DIR) +@@ -3317,6 +3328,8 @@ def uninstall(options): + + # Remove the CA cert + remove_file(paths.IPA_CA_CRT) ++ remove_file(paths.KDC_CA_BUNDLE_PEM) ++ remove_file(paths.CA_BUNDLE_PEM) + + root_logger.info("Client uninstall complete.") + +diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py +index 7dc88f07ae14e5416f6fe3dc8400b7d4bcabef72..7e8527e1fcb575844e8f4c90016435124b70e381 100644 +--- a/ipaclient/install/ipa_certupdate.py ++++ b/ipaclient/install/ipa_certupdate.py +@@ -113,6 +113,8 @@ class CertUpdate(admintool.AdminTool): + + def update_client(self, certs): + self.update_file(paths.IPA_CA_CRT, certs) ++ self.update_file(paths.KDC_CA_BUNDLE_PEM, certs) ++ self.update_file(paths.CA_BUNDLE_PEM, certs) + + ipa_db = certdb.NSSDatabase(api.env.nss_dir) + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index f80c9e95ab875222887e3692ab80151f84345469..804fddee60f787e161947bbe4b1914995257ceb4 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -331,6 +331,8 @@ class BasePathNamespace(object): + VAR_RUN_DIRSRV_DIR = "/var/run/dirsrv" + IPA_CCACHES = "/var/run/ipa/ccaches" + HTTP_CCACHE = "/var/lib/ipa/gssproxy/http.ccache" ++ CA_BUNDLE_PEM = "/var/lib/ipa-client/pki/ca-bundle.pem" ++ KDC_CA_BUNDLE_PEM = "/var/lib/ipa-client/pki/kdc-ca-bundle.pem" + IPA_RENEWAL_LOCK = "/var/run/ipa/renewal.lock" + SVC_LIST_FILE = "/var/run/ipa/services.list" + KRB5CC_SAMBA = "/var/run/samba/krb5cc_samba" +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index a4aa4f2069277181501ebd92f3795c452b10acd0..b8c8cc4fc4532fc2c911ec174d363f8280ce863b 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -794,10 +794,13 @@ class CAInstance(DogtagInstance): + certlist = x509.pkcs7_to_pems(data, x509.DER) + + # We have all the certificates in certlist, write them to a PEM file +- with open(paths.IPA_CA_CRT, 'w') as ipaca_pem: +- for cert in certlist: +- ipaca_pem.write(cert) +- ipaca_pem.write('\n') ++ for path in [paths.IPA_CA_CRT, ++ paths.KDC_CA_BUNDLE_PEM, ++ paths.CA_BUNDLE_PEM]: ++ with open(path, 'w') as ipaca_pem: ++ for cert in certlist: ++ ipaca_pem.write(cert) ++ ipaca_pem.write('\n') + + def __request_ra_certificate(self): + # create a temp file storing the pwd +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 40f08d7d727a8b97b5996f15d27c1e20788e1473..f8cdd56d26636678279ba5afb423c5eef10c33d0 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -150,6 +150,8 @@ class Backup(admintool.AdminTool): + paths.SSHD_CONFIG, + paths.SSH_CONFIG, + paths.KRB5_CONF, ++ paths.KDC_CA_BUNDLE_PEM, ++ paths.CA_BUNDLE_PEM, + paths.IPA_CA_CRT, + paths.IPA_DEFAULT_CONF, + paths.DS_KEYTAB, +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 2f14ff592064d3446f73b31e615b2de88d6d786c..e52577bbaa15064946f9a3c9720aa40ffc3251aa 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -261,7 +261,9 @@ class KrbInstance(service.Service): + KRB5KDC_KADM5_KEYTAB=paths.KRB5KDC_KADM5_KEYTAB, + KDC_CERT=paths.KDC_CERT, + KDC_KEY=paths.KDC_KEY, +- CACERT_PEM=paths.CACERT_PEM) ++ CACERT_PEM=paths.CACERT_PEM, ++ KDC_CA_BUNDLE_PEM=paths.KDC_CA_BUNDLE_PEM, ++ CA_BUNDLE_PEM=paths.CA_BUNDLE_PEM) + + # IPA server/KDC is not a subdomain of default domain + # Proper domain-realm mapping needs to be specified +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 25c21db721c58388ae8fd6ab1fbc443d513a4324..c1bdce6c8459dfeabd0096d105e535ec4ee56a2a 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -796,6 +796,16 @@ def install(installer): + x509.write_certificate(http_ca_cert, paths.IPA_CA_CRT) + os.chmod(paths.IPA_CA_CRT, 0o444) + ++ if not options.no_pkinit: ++ x509.write_certificate(http_ca_cert, paths.KDC_CA_BUNDLE_PEM) ++ else: ++ with open(paths.KDC_CA_BUNDLE_PEM, 'w'): ++ pass ++ os.chmod(paths.KDC_CA_BUNDLE_PEM, 0o444) ++ ++ x509.write_certificate(http_ca_cert, paths.CA_BUNDLE_PEM) ++ os.chmod(paths.CA_BUNDLE_PEM, 0o444) ++ + # we now need to enable ssl on the ds + ds.enable_ssl() + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index c19edceec42845f3169adc923762f700739232f2..66d7ba44645aed69b12f0e5ea14f5080492fe5ef 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1390,6 +1390,10 @@ def install(installer): + + # Update and istall updated CA file + cafile = install_ca_cert(conn, api.env.basedn, api.env.realm, cafile) ++ install_ca_cert(conn, api.env.basedn, api.env.realm, cafile, ++ destfile=paths.KDC_CA_BUNDLE_PEM) ++ install_ca_cert(conn, api.env.basedn, api.env.realm, cafile, ++ destfile=paths.CA_BUNDLE_PEM) + + # Configure dirsrv + ds = install_replica_ds(config, options, ca_enabled, +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index c244958f4cddba0d1edded5165a295b1e1ee2b8a..648dc1f29c44f89d9fbceb7b50373d93c88b5c1a 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1831,7 +1831,9 @@ def upgrade_configuration(): + KRB5KDC_KADM5_KEYTAB=paths.KRB5KDC_KADM5_KEYTAB, + KDC_CERT=paths.KDC_CERT, + KDC_KEY=paths.KDC_KEY, +- CACERT_PEM=paths.CACERT_PEM) ++ CACERT_PEM=paths.CACERT_PEM, ++ KDC_CA_BUNDLE_PEM=paths.KDC_CA_BUNDLE_PEM, ++ CA_BUNDLE_PEM=paths.CA_BUNDLE_PEM) + krb.add_anonymous_principal() + setup_pkinit(krb) + +-- +2.9.4 + diff --git a/SOURCES/0147-gracefully-handle-setting-replica-bind-dn-group-on-o.patch b/SOURCES/0147-gracefully-handle-setting-replica-bind-dn-group-on-o.patch deleted file mode 100644 index ab2aa23..0000000 --- a/SOURCES/0147-gracefully-handle-setting-replica-bind-dn-group-on-o.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 32b222610532b543d713d4d4b5ce02eed15a66d5 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Tue, 6 Dec 2016 18:07:50 +0100 -Subject: [PATCH] gracefully handle setting replica bind dn group on old - masters - -Pre-3.3 masters do not support setting 'nsds5replicabinddngroup' -attribute on existing replica entry during setup of initial replication. -In this case UNWILLING_TO_PERFORM is returned. The code can interpret -this error as an indication of old master and fall back to just adding -its LDAP principal to entry's 'nsds5replicabinddn' attribute. - -https://fedorahosted.org/freeipa/ticket/6532 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/replication.py | 48 ++++++++++++++++++++++++++-------------- - 1 file changed, 32 insertions(+), 16 deletions(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index e9624894d7d1e745be8072268fa76d51a8c117e3..5f03ddeadfc515255509a1f49d3b38687e561b9f 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -429,6 +429,34 @@ class ReplicationManager(object): - return DN(('cn', 'replica'), ('cn', self.db_suffix), - ('cn', 'mapping tree'), ('cn', 'config')) - -+ def set_replica_binddngroup(self, r_conn, entry, replica_groupdn): -+ """ -+ Set nsds5replicabinddngroup attribute on remote master's replica entry. -+ Older masters (ipa < 3.3) may not support setting this attribute. In -+ this case log the error and fall back to setting replica's binddn -+ directly. -+ """ -+ binddn_groups = { -+ DN(p) for p in entry.get('nsds5replicabinddngroup', [])} -+ -+ mod = [] -+ if replica_groupdn not in binddn_groups: -+ mod.append((ldap.MOD_ADD, 'nsds5replicabinddngroup', -+ replica_groupdn)) -+ -+ if 'nsds5replicabinddngroupcheckinterval' not in entry: -+ mod.append( -+ (ldap.MOD_ADD, -+ 'nsds5replicabinddngroupcheckinterval', -+ '60')) -+ if mod: -+ try: -+ r_conn.modify_s(entry.dn, mod) -+ except ldap.UNWILLING_TO_PERFORM: -+ root_logger.debug( -+ "nsds5replicabinddngroup attribute not supported on " -+ "remote master.") -+ - def replica_config(self, conn, replica_id, replica_binddn): - assert isinstance(replica_binddn, DN) - dn = self.replica_dn() -@@ -440,27 +468,15 @@ class ReplicationManager(object): - try: - entry = conn.get_entry(dn) - managers = {DN(m) for m in entry.get('nsDS5ReplicaBindDN', [])} -- binddn_groups = { -- DN(p) for p in entry.get('nsds5replicabinddngroup', [])} - -- mod = [] - if replica_binddn not in managers: - # Add the new replication manager -- mod.append((ldap.MOD_ADD, 'nsDS5ReplicaBindDN', -- replica_binddn)) -- -- if replica_groupdn not in binddn_groups: -- mod.append((ldap.MOD_ADD, 'nsds5replicabinddngroup', -- replica_groupdn)) -- -- if 'nsds5replicabinddngroupcheckinterval' not in entry: -- mod.append( -- (ldap.MOD_ADD, -- 'nsds5replicabinddngroupcheckinterval', -- '60')) -- if mod: -+ mod = [(ldap.MOD_ADD, 'nsDS5ReplicaBindDN', -+ replica_binddn)] - conn.modify_s(dn, mod) - -+ self.set_replica_binddngroup(conn, entry, replica_groupdn) -+ - # replication is already configured - return - except errors.NotFound: --- -2.7.4 - diff --git a/SOURCES/0148-add-missing-attribute-to-ipaca-replica-during-CA-top.patch b/SOURCES/0148-add-missing-attribute-to-ipaca-replica-during-CA-top.patch deleted file mode 100644 index 6844cbb..0000000 --- a/SOURCES/0148-add-missing-attribute-to-ipaca-replica-during-CA-top.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 3ff9fc2141e16e7cbd4fa30c16d60e915c2c3ee4 Mon Sep 17 00:00:00 2001 -From: Martin Babinsky -Date: Wed, 7 Dec 2016 14:00:09 +0100 -Subject: [PATCH] add missing attribute to ipaca replica during CA topology - update - -'nsds5replicabinddngroupcheckinterval' attribute was not properly added -to 'o=ipaca' replica attribute during upgrade. The CA topology update -plugin should now add it to the entry if it exists. - -https://fedorahosted.org/freeipa/ticket/6508 - -Reviewed-By: Martin Basti ---- - ipaserver/install/plugins/update_ca_topology.py | 22 ++++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/ipaserver/install/plugins/update_ca_topology.py b/ipaserver/install/plugins/update_ca_topology.py -index d76849bf9de46b1e4ad52dbae7081b4d3aec5273..f82926b19175c3fd42bd794205ec4216fc776707 100644 ---- a/ipaserver/install/plugins/update_ca_topology.py -+++ b/ipaserver/install/plugins/update_ca_topology.py -@@ -2,8 +2,10 @@ - # Copyright (C) 2015 FreeIPA Contributors see COPYING for license - # - -+from ipalib import errors - from ipalib import Registry - from ipalib import Updater -+from ipapython.dn import DN - from ipaserver.install import certs, cainstance - from ipaserver.install import ldapupdate - from ipaplatform.paths import paths -@@ -31,4 +33,24 @@ class update_ca_topology(Updater): - - ld.update([paths.CA_TOPOLOGY_ULDIF]) - -+ ldap = self.api.Backend.ldap2 -+ -+ ca_replica_dn = DN( -+ ('cn', 'replica'), -+ ('cn', 'o=ipaca'), -+ ('cn', 'mapping tree'), -+ ('cn', 'config')) -+ -+ check_interval_attr = 'nsds5replicabinddngroupcheckinterval' -+ default_check_interval = ['60'] -+ -+ try: -+ ca_replica_entry = ldap.get_entry(ca_replica_dn) -+ except errors.NotFound: -+ pass -+ else: -+ if check_interval_attr not in ca_replica_entry: -+ ca_replica_entry[check_interval_attr] = default_check_interval -+ ldap.update_entry(ca_replica_entry) -+ - return False, [] --- -2.7.4 - diff --git a/SOURCES/0148-install-introduce-generic-Kerberos-Augeas-lens.patch b/SOURCES/0148-install-introduce-generic-Kerberos-Augeas-lens.patch new file mode 100644 index 0000000..eed37f5 --- /dev/null +++ b/SOURCES/0148-install-introduce-generic-Kerberos-Augeas-lens.patch @@ -0,0 +1,98 @@ +From 01440531b0805d647b0a0a37e2c3ea9489d19a35 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 18 May 2017 07:57:40 +0000 +Subject: [PATCH] install: introduce generic Kerberos Augeas lens + +Introduce new IPAKrb5 lens to handle krb5.conf and kdc.conf changes using +Augeas. The stock Krb5 lens does not work on our krb5.conf and kdc.conf. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + freeipa.spec.in | 1 + + install/share/Makefile.am | 1 + + install/share/ipakrb5.aug | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 48 insertions(+) + create mode 100644 install/share/ipakrb5.aug + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 6cb37ae53b039aa1d0e0509f62a3237504be6555..790e5838e0ba45ea9bbfe3bc3a1bd40c0bd3ac1a 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -1362,6 +1362,7 @@ fi + %dir %{_usr}/share/ipa/schema.d + %attr(0644,root,root) %{_usr}/share/ipa/schema.d/README + %attr(0644,root,root) %{_usr}/share/ipa/gssapi.login ++%{_usr}/share/ipa/ipakrb5.aug + + %files server-dns + %defattr(-,root,root,-) +diff --git a/install/share/Makefile.am b/install/share/Makefile.am +index b27861da37153d77d693ce6e46340525bbd50173..85a061c6976dcc55b0ba2250423a344e14f2ce97 100644 +--- a/install/share/Makefile.am ++++ b/install/share/Makefile.am +@@ -89,6 +89,7 @@ dist_app_DATA = \ + gssapi.login \ + ipa.conf.tmpfiles \ + gssproxy.conf.template \ ++ ipakrb5.aug \ + $(NULL) + + kdcproxyconfdir = $(IPA_SYSCONF_DIR)/kdcproxy +diff --git a/install/share/ipakrb5.aug b/install/share/ipakrb5.aug +new file mode 100644 +index 0000000000000000000000000000000000000000..4a31a84e147a680067acddac683c672ccb6f9c31 +--- /dev/null ++++ b/install/share/ipakrb5.aug +@@ -0,0 +1,46 @@ ++module IPAKrb5 = ++ autoload xfm ++ ++ let dels (s:string) = Util.del_str s ++ ++ let indent = Util.indent ++ let space = Sep.space ++ let opt_space = Sep.opt_space ++ let sep = Sep.space_equal ++ let eol = IniFile.eol ++ ++ let kw = Rx.word ++ let val = Rx.space_in ++ ++ let comment = IniFile.comment IniFile.comment_re "# " ++ let empty = IniFile.empty ++ ++ let entry_generic (v:lens) = [ indent . key kw . sep . v . eol ] ++ ++ (* ++ FIXME: combine entry and subrecord into a single recursive lens ++ ++ This does not work for some reason: ++ let rec entry = entry_generic ( store ( val - "{" ) ) ++ | entry_generic ( dels "{" . eol ++ . ( entry | comment | empty )* ++ . indent . dels "}" ) ++ *) ++ let entry = entry_generic ( store ( val - "{" ) ) ++ let subrecord = entry_generic ( dels "{" . eol ++ . ( entry | comment | empty )* ++ . indent . dels "}" ) ++ ++ let title = IniFile.indented_title kw ++ let record = IniFile.record title ( entry | subrecord | comment ) ++ ++ let directive = Build.key_value_line kw space ( store val ) ++ ++ let lns = IniFile.lns record ( directive | comment ) ++ ++ let filter = incl "/etc/krb5.conf" ++ . incl "/etc/krb5.conf.d/*" ++ . incl "/var/kerberos/krb5kdc/kdc.conf" ++ . Util.stdexcl ++ ++ let xfm = transform lns filter +-- +2.9.4 + diff --git a/SOURCES/0149-Check-for-conflict-entries-before-raising-domain-lev.patch b/SOURCES/0149-Check-for-conflict-entries-before-raising-domain-lev.patch deleted file mode 100644 index a3fd173..0000000 --- a/SOURCES/0149-Check-for-conflict-entries-before-raising-domain-lev.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 81a1bdae1743c4cd7aab296cb0a7474b9bd52b33 Mon Sep 17 00:00:00 2001 -From: Ludwig Krispenz -Date: Fri, 9 Dec 2016 15:04:21 +0100 -Subject: [PATCH] Check for conflict entries before raising domain level - -Checking of conflicts is not only done in topology container as -tests showed it can occurs elsewhere - -https://fedorahosted.org/freeipa/ticket/6534 - -Reviewed-By: Martin Babinsky ---- - ipaserver/plugins/domainlevel.py | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/ipaserver/plugins/domainlevel.py b/ipaserver/plugins/domainlevel.py -index 23fa2a1b2f0f681ac215e96a651d688294df4b99..d8c508a64dd91a0a18e061d2af3080c8f1b38260 100644 ---- a/ipaserver/plugins/domainlevel.py -+++ b/ipaserver/plugins/domainlevel.py -@@ -48,6 +48,30 @@ def get_domainlevel_range(master_entry): - return DomainLevelRange(0, 0) - - -+def check_conflict_entries(ldap, api, desired_value): -+ """ -+ Check if conflict entries exist in topology subtree -+ """ -+ -+ container_dn = DN( -+ ('cn', 'ipa'), -+ ('cn', 'etc'), -+ api.env.basedn -+ ) -+ conflict = "(nsds5replconflict=*)" -+ subentry = "(|(objectclass=ldapsubentry)(objectclass=*))" -+ try: -+ ldap.get_entries( -+ filter="(& %s %s)" % (conflict, subentry), -+ base_dn=container_dn, -+ scope=ldap.SCOPE_SUBTREE) -+ message = _("Domain Level cannot be raised to {0}, " -+ "existing replication conflicts have to be resolved." -+ .format(desired_value)) -+ raise errors.InvalidDomainLevelError(reason=message) -+ except errors.NotFound: -+ pass -+ - def get_master_entries(ldap, api): - """ - Returns list of LDAPEntries representing IPA masters. -@@ -131,6 +155,10 @@ class domainlevel_set(Command): - .format(desired_value, master['cn'][0])) - raise errors.InvalidDomainLevelError(reason=message) - -+ # Check if conflict entries exist in topology subtree -+ # should be resolved first -+ check_conflict_entries(ldap, self.api, desired_value) -+ - current_entry.single_value['ipaDomainLevel'] = desired_value - ldap.update_entry(current_entry) - --- -2.7.4 - diff --git a/SOURCES/0149-server-install-fix-KDC-PKINIT-configuration.patch b/SOURCES/0149-server-install-fix-KDC-PKINIT-configuration.patch new file mode 100644 index 0000000..5e9747e --- /dev/null +++ b/SOURCES/0149-server-install-fix-KDC-PKINIT-configuration.patch @@ -0,0 +1,292 @@ +From 2558a0336e9d61b2b7e321b7dfa32426151b4bbb Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:09:03 +0000 +Subject: [PATCH] server install: fix KDC PKINIT configuration + +Set `pkinit_pool` in `kdc.conf` to a CA certificate bundle of all CAs known +to IPA. + +Make sure `cacert.pem` is exported in all installation code paths. + +Use the KDC certificate itself as a PKINIT anchor in `login_password`. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + install/restart_scripts/Makefile.am | 1 + + install/restart_scripts/renew_kdc_cert | 31 ++++++++++++++++++ + install/share/kdc.conf.template | 2 ++ + ipaclient/install/ipa_certupdate.py | 1 + + ipalib/install/kinit.py | 7 +++-- + ipaserver/install/krbinstance.py | 27 +++++++++------- + ipaserver/install/server/upgrade.py | 57 ++++++++++++++++++++++++++-------- + ipaserver/rpcserver.py | 5 ++- + 8 files changed, 103 insertions(+), 28 deletions(-) + create mode 100755 install/restart_scripts/renew_kdc_cert + +diff --git a/install/restart_scripts/Makefile.am b/install/restart_scripts/Makefile.am +index 04881b406b6be92b46e630f30d724918506e2aa8..240cebdee8cae7a0c7bdf88f5300583b4232fc94 100644 +--- a/install/restart_scripts/Makefile.am ++++ b/install/restart_scripts/Makefile.am +@@ -5,6 +5,7 @@ app_DATA = \ + restart_dirsrv \ + restart_httpd \ + renew_ca_cert \ ++ renew_kdc_cert \ + renew_ra_cert \ + stop_pkicad \ + renew_ra_cert_pre \ +diff --git a/install/restart_scripts/renew_kdc_cert b/install/restart_scripts/renew_kdc_cert +new file mode 100755 +index 0000000000000000000000000000000000000000..9247920874fc9540ac3421dd59fd902cc195243f +--- /dev/null ++++ b/install/restart_scripts/renew_kdc_cert +@@ -0,0 +1,31 @@ ++#!/usr/bin/python2 -E ++# ++# Copyright (C) 2017 FreeIPA Contributors see COPYING for license ++# ++ ++import os ++import syslog ++import traceback ++ ++from ipaplatform import services ++from ipaplatform.paths import paths ++from ipaserver.install import certs ++ ++ ++def main(): ++ with certs.renewal_lock: ++ os.chmod(paths.KDC_CERT, 0o644) ++ ++ try: ++ if services.knownservices.krb5kdc.is_running(): ++ syslog.syslog(syslog.LOG_NOTICE, 'restarting krb5kdc') ++ services.knownservices.krb5kdc.restart() ++ except Exception as e: ++ syslog.syslog( ++ syslog.LOG_ERR, "cannot restart krb5kdc: {}".format(e)) ++ ++ ++try: ++ main() ++except Exception: ++ syslog.syslog(syslog.LOG_ERR, traceback.format_exc()) +diff --git a/install/share/kdc.conf.template b/install/share/kdc.conf.template +index ec53a1ff5f7110704143074bc7a5d1dfdc705344..306351b86111eb0e883b2398678f50b821e0ad7f 100644 +--- a/install/share/kdc.conf.template ++++ b/install/share/kdc.conf.template +@@ -13,5 +13,7 @@ + default_principal_flags = +preauth + ; admin_keytab = $KRB5KDC_KADM5_KEYTAB + pkinit_identity = FILE:$KDC_CERT,$KDC_KEY ++ pkinit_anchors = FILE:$KDC_CERT + pkinit_anchors = FILE:$CACERT_PEM ++ pkinit_pool = FILE:$CA_BUNDLE_PEM + } +diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py +index 7e8527e1fcb575844e8f4c90016435124b70e381..93da8422b6f503b8c44db678736d7f71f7d7567e 100644 +--- a/ipaclient/install/ipa_certupdate.py ++++ b/ipaclient/install/ipa_certupdate.py +@@ -172,6 +172,7 @@ class CertUpdate(admintool.AdminTool): + certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent') + + self.update_file(paths.CA_CRT, certs) ++ self.update_file(paths.CACERT_PEM, certs) + + def update_file(self, filename, certs, mode=0o444): + certs = (c[0] for c in certs if c[2] is not False) +diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py +index fb6caee4d6b5fef27b53753b21ad83572da31ac4..73471f103eabfe39580c8fbd0665157f635fa5c5 100644 +--- a/ipalib/install/kinit.py ++++ b/ipalib/install/kinit.py +@@ -96,7 +96,7 @@ def kinit_password(principal, password, ccache_name, config=None, + raise RuntimeError(result.error_output) + + +-def kinit_armor(ccache_name, pkinit_anchor=None): ++def kinit_armor(ccache_name, pkinit_anchors=None): + """ + perform anonymous pkinit to obtain anonymous ticket to be used as armor + for FAST. +@@ -113,8 +113,9 @@ def kinit_armor(ccache_name, pkinit_anchor=None): + env = {'LC_ALL': 'C'} + args = [paths.KINIT, '-n', '-c', ccache_name] + +- if pkinit_anchor is not None: +- args.extend(['-X', 'X509_anchors=FILE:{}'.format(pkinit_anchor)]) ++ if pkinit_anchors is not None: ++ for pkinit_anchor in pkinit_anchors: ++ args.extend(['-X', 'X509_anchors=FILE:{}'.format(pkinit_anchor)]) + + # this workaround enables us to capture stderr and put it + # into the raised exception in case of unsuccessful authentication +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index e52577bbaa15064946f9a3c9720aa40ffc3251aa..1692e0b2badb23c18386346a552c83881018cf60 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -20,7 +20,6 @@ + from __future__ import absolute_import + from __future__ import print_function + +-import shutil + import os + import pwd + import socket +@@ -28,6 +27,8 @@ import dbus + + import dns.name + ++from ipalib import x509 ++from ipalib.install import certstore + from ipaserver.install import service + from ipaserver.install import installutils + from ipapython import ipaldap +@@ -430,7 +431,8 @@ class KrbInstance(service.Service): + ca=certmonger_ca, + dns=self.fqdn, + storage='FILE', +- profile=KDC_PROFILE) ++ profile=KDC_PROFILE, ++ post_command='renew_kdc_cert') + except dbus.DBusException as e: + # if the certificate is already tracked, ignore the error + name = e.get_dbus_name() +@@ -448,17 +450,23 @@ class KrbInstance(service.Service): + service.set_service_entry_config( + 'KDC', self.fqdn, [PKINIT_ENABLED], self.suffix) + ++ def _install_pkinit_ca_bundle(self): ++ ca_certs = certstore.get_ca_certs(self.api.Backend.ldap2, ++ self.api.env.basedn, ++ self.api.env.realm, ++ False) ++ ca_certs = [c for c, _n, t, _u in ca_certs if t is not False] ++ x509.write_certificate_list(ca_certs, paths.CACERT_PEM) ++ + def issue_selfsigned_pkinit_certs(self): + self._call_certmonger(certmonger_ca="SelfSign") +- # for self-signed certificate, the certificate is its own CA, copy it +- # as CA cert +- shutil.copyfile(paths.KDC_CERT, paths.CACERT_PEM) ++ with open(paths.CACERT_PEM, 'w'): ++ pass + + def issue_ipa_ca_signed_pkinit_certs(self): + try: + self._call_certmonger() +- # copy IPA CA bundle to the KDC's CA cert bundle +- shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM) ++ self._install_pkinit_ca_bundle() + self.pkinit_enable() + except RuntimeError as e: + root_logger.error("PKINIT certificate request failed: %s", e) +@@ -473,10 +481,7 @@ class KrbInstance(service.Service): + certs.install_key_from_p12(self.pkcs12_info[0], + self.pkcs12_info[1], + paths.KDC_KEY) +- # copy IPA CA bundle to the KDC's CA cert bundle +- # NOTE: this may not be the same set of CA certificates trusted by +- # externally provided PKINIT cert. +- shutil.copyfile(paths.IPA_CA_CRT, paths.CACERT_PEM) ++ self._install_pkinit_ca_bundle() + self.pkinit_enable() + + def setup_pkinit(self): +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index 648dc1f29c44f89d9fbceb7b50373d93c88b5c1a..db86353165809c57d1ac27bf762393721231fefd 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -11,6 +11,7 @@ import pwd + import fileinput + import sys + ++from augeas import Augeas + import dns.exception + + import six +@@ -1527,19 +1528,49 @@ def setup_pkinit(krb): + else: + krb.issue_selfsigned_pkinit_certs() + +- # reconfigure KDC just in case in order to handle potentially broken +- # 4.5.0 -> 4.5.1 upgrade path +- replacevars = dict() +- replacevars['pkinit_identity'] = 'FILE:{},{}'.format( +- paths.KDC_CERT,paths.KDC_KEY) +- appendvars = {} +- ipautil.backup_config_and_replace_variables( +- krb.fstore, paths.KRB5KDC_KDC_CONF, replacevars=replacevars, +- appendvars=appendvars) +- tasks.restore_context(paths.KRB5KDC_KDC_CONF) +- if krb.is_running(): +- krb.stop() +- krb.start() ++ aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD, ++ loadpath=paths.USR_SHARE_IPA_DIR) ++ try: ++ aug.transform('IPAKrb5', paths.KRB5KDC_KDC_CONF) ++ aug.load() ++ ++ path = '/files{}/realms/{}'.format(paths.KRB5KDC_KDC_CONF, krb.realm) ++ modified = False ++ ++ value = 'FILE:{},{}'.format(paths.KDC_CERT, paths.KDC_KEY) ++ expr = '{}[count(pkinit_identity)=1][pkinit_identity="{}"]'.format( ++ path, value) ++ if not aug.match(expr): ++ aug.remove('{}/pkinit_identity'.format(path)) ++ aug.set('{}/pkinit_identity'.format(path), value) ++ modified = True ++ ++ for value in ['FILE:{}'.format(paths.KDC_CERT), ++ 'FILE:{}'.format(paths.CACERT_PEM)]: ++ expr = '{}/pkinit_anchors[.="{}"]'.format(path, value) ++ if not aug.match(expr): ++ aug.set('{}/pkinit_anchors[last()+1]'.format(path), value) ++ modified = True ++ ++ value = 'FILE:{}'.format(paths.CA_BUNDLE_PEM) ++ expr = '{}/pkinit_pool[.="{}"]'.format(path, value) ++ if not aug.match(expr): ++ aug.set('{}/pkinit_pool[last()+1]'.format(path), value) ++ modified = True ++ ++ if modified: ++ try: ++ aug.save() ++ except IOError: ++ for error_path in aug.match('/augeas//error'): ++ root_logger.error('augeas: %s', aug.get(error_path)) ++ raise ++ ++ if krb.is_running(): ++ krb.stop() ++ krb.start() ++ finally: ++ aug.close() + + + def disable_httpd_system_trust(http): +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 996a3d29884ca0180c39841f6986abf9b23ff13a..4cde2815a0fe9332d67c84b531f573ff88b1a302 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -945,7 +945,10 @@ class login_password(Backend, KerberosSession): + self.debug('Obtaining armor in ccache %s', armor_path) + + try: +- kinit_armor(armor_path, pkinit_anchor=paths.CACERT_PEM) ++ kinit_armor( ++ armor_path, ++ pkinit_anchors=[paths.KDC_CERT, paths.KDC_CA_BUNDLE_PEM], ++ ) + except RuntimeError as e: + self.error("Failed to obtain armor cache") + # We try to continue w/o armor, 2FA will be impacted +-- +2.9.4 + diff --git a/SOURCES/0150-certprofile-mod-correctly-authorise-config-update.patch b/SOURCES/0150-certprofile-mod-correctly-authorise-config-update.patch deleted file mode 100644 index 55acdcc..0000000 --- a/SOURCES/0150-certprofile-mod-correctly-authorise-config-update.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 59e072eab0d58af195a14d53240de20ee4a3171f Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Tue, 15 Nov 2016 14:02:54 +1000 -Subject: [PATCH] certprofile-mod: correctly authorise config update - -Certificate profiles consist of an FreeIPA object, and a -corresponding Dogtag configuration object. When updating profile -configuration, changes to the Dogtag configuration are not properly -authorised, allowing unprivileged operators to modify (but not -create or delete) profiles. This could result in issuance of -certificates with fraudulent subject naming information, improper -key usage, or other badness. - -Update certprofile-mod to ensure that the operator has permission to -modify FreeIPA certprofile objects before modifying the Dogtag -configuration. - -https://fedorahosted.org/freeipa/ticket/6560 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/certprofile.py | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/ipaserver/plugins/certprofile.py b/ipaserver/plugins/certprofile.py -index f4466077484591c8e941027fa8e4897602384f7c..2bd3311e3b729b768188d537bf7f675a0f9346c2 100644 ---- a/ipaserver/plugins/certprofile.py -+++ b/ipaserver/plugins/certprofile.py -@@ -310,6 +310,11 @@ class certprofile_mod(LDAPUpdate): - raise errors.ProtectedEntryError(label='certprofile', key=keys[0], - reason=_('Certificate profiles cannot be renamed')) - if 'file' in options: -+ # ensure operator has permission to update a certprofile -+ if not ldap.can_write(dn, 'ipacertprofilestoreissued'): -+ raise errors.ACIError(info=_( -+ "Insufficient privilege to modify a certificate profile.")) -+ - with self.api.Backend.ra_certprofile as profile_api: - profile_api.disable_profile(keys[0]) - try: --- -2.7.4 - diff --git a/SOURCES/0150-ipapython.ipautil.run-Add-option-to-set-umask-before.patch b/SOURCES/0150-ipapython.ipautil.run-Add-option-to-set-umask-before.patch new file mode 100644 index 0000000..bc31a32 --- /dev/null +++ b/SOURCES/0150-ipapython.ipautil.run-Add-option-to-set-umask-before.patch @@ -0,0 +1,85 @@ +From 68d97e2beca1ee3b398fc5f0d3ed70aa8b69e732 Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Tue, 11 Apr 2017 17:35:30 +0200 +Subject: [PATCH] ipapython.ipautil.run: Add option to set umask before + executing command + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipapython/ipautil.py | 43 +++++++++++++++++++++++-------------------- + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index cd66328e6c9a0f69e6f83582a9d288ac239c5be3..317fc225b722ad3ce2f4b9d92822b4f19d49adb9 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -309,7 +309,7 @@ class _RunResult(collections.namedtuple('_RunResult', + def run(args, stdin=None, raiseonerr=True, nolog=(), env=None, + capture_output=False, skip_output=False, cwd=None, + runas=None, suplementary_groups=[], +- capture_error=False, encoding=None, redirect_output=False): ++ capture_error=False, encoding=None, redirect_output=False, umask=None): + """ + Execute an external command. + +@@ -345,6 +345,7 @@ def run(args, stdin=None, raiseonerr=True, nolog=(), env=None, + error_output, and (if it's not bytes) stdin. + If None, the current encoding according to locale is used. + :param redirect_output: Redirect (error) output to standard (error) output. ++ :param umask: Set file-creation mask before running the command. + + :return: An object with these attributes: + +@@ -416,25 +417,27 @@ def run(args, stdin=None, raiseonerr=True, nolog=(), env=None, + root_logger.debug('Starting external process') + root_logger.debug('args=%s' % arg_string) + +- preexec_fn = None +- if runas is not None: +- pent = pwd.getpwnam(runas) +- +- suplementary_gids = [ +- grp.getgrnam(group).gr_gid for group in suplementary_groups +- ] +- +- root_logger.debug('runas=%s (UID %d, GID %s)', runas, +- pent.pw_uid, pent.pw_gid) +- if suplementary_groups: +- for group, gid in zip(suplementary_groups, suplementary_gids): +- root_logger.debug('suplementary_group=%s (GID %d)', group, gid) +- +- preexec_fn = lambda: ( +- os.setgroups(suplementary_gids), +- os.setregid(pent.pw_gid, pent.pw_gid), +- os.setreuid(pent.pw_uid, pent.pw_uid), +- ) ++ def preexec_fn(): ++ if runas is not None: ++ pent = pwd.getpwnam(runas) ++ ++ suplementary_gids = [ ++ grp.getgrnam(group).gr_gid for group in suplementary_groups ++ ] ++ ++ root_logger.debug('runas=%s (UID %d, GID %s)', runas, ++ pent.pw_uid, pent.pw_gid) ++ if suplementary_groups: ++ for group, gid in zip(suplementary_groups, suplementary_gids): ++ root_logger.debug('suplementary_group=%s (GID %d)', ++ group, gid) ++ ++ os.setgroups(suplementary_gids) ++ os.setregid(pent.pw_gid, pent.pw_gid) ++ os.setreuid(pent.pw_uid, pent.pw_uid) ++ ++ if umask: ++ os.umask(umask) + + try: + p = subprocess.Popen(args, stdin=p_in, stdout=p_out, stderr=p_err, +-- +2.9.4 + diff --git a/SOURCES/0151-certs-do-not-export-keys-world-readable-in-install_k.patch b/SOURCES/0151-certs-do-not-export-keys-world-readable-in-install_k.patch new file mode 100644 index 0000000..b12e21d --- /dev/null +++ b/SOURCES/0151-certs-do-not-export-keys-world-readable-in-install_k.patch @@ -0,0 +1,33 @@ +From 9e724963967a79fd171e79d2353ec7b655f13c47 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 11 May 2017 07:00:42 +0000 +Subject: [PATCH] certs: do not export keys world-readable in + install_key_from_p12 + +Make sure the exported private key files are readable only by the owner. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipaserver/install/certs.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 17b9ebad4a128e292e453af44ca9d63cfb1e6ea2..06a7e2143964484fa45106ca381043eb440dc5b1 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -73,7 +73,8 @@ def install_key_from_p12(p12_fname, p12_passwd, pem_fname): + pwd = ipautil.write_tmp_file(p12_passwd) + ipautil.run([paths.OPENSSL, "pkcs12", "-nodes", "-nocerts", + "-in", p12_fname, "-out", pem_fname, +- "-passin", "file:" + pwd.name]) ++ "-passin", "file:" + pwd.name], ++ umask=0o077) + + + def export_pem_p12(pkcs12_fname, pkcs12_pwd_fname, nickname, pem_fname): +-- +2.9.4 + diff --git a/SOURCES/0151-password-policy-Add-explicit-default-password-policy.patch b/SOURCES/0151-password-policy-Add-explicit-default-password-policy.patch deleted file mode 100644 index 22ac7ff..0000000 --- a/SOURCES/0151-password-policy-Add-explicit-default-password-policy.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 018266f9dcc06cedcfe679ed32870dd3eda2ece7 Mon Sep 17 00:00:00 2001 -From: David Kupka -Date: Thu, 29 Sep 2016 15:59:34 +0200 -Subject: [PATCH] password policy: Add explicit default password policy for - hosts and services - -Set explicitly krbPwdPolicyReference attribute to all hosts (entries in -cn=computers,cn=accounts), services (entries in cn=services,cn=accounts) and -Kerberos services (entries in cn=$REALM,cn=kerberos). This is done using DS's -CoS so no attributes are really added. - -The default policies effectively disable any enforcement or lockout for hosts -and services. Since hosts and services use keytabs passwords enforcements -doesn't make much sense. Also the lockout policy could be used for easy and -cheap DoS. - -https://fedorahosted.org/freeipa/ticket/6561 - -Reviewed-By: Pavel Vomacka ---- - install/updates/20-default_password_policy.update | 133 ++++++++++++++++++++++ - install/updates/Makefile.am | 1 + - ipaserver/install/service.py | 1 + - 3 files changed, 135 insertions(+) - create mode 100644 install/updates/20-default_password_policy.update - -diff --git a/install/updates/20-default_password_policy.update b/install/updates/20-default_password_policy.update -new file mode 100644 -index 0000000000000000000000000000000000000000..b1f9754a98e9c4b9cb8558e96f7195ea87c2f1ce ---- /dev/null -+++ b/install/updates/20-default_password_policy.update -@@ -0,0 +1,133 @@ -+# Default password policies for hosts, services and Kerberos services -+# Setting all attributes to zero effectively disables any password policy -+# We can do this because hosts and services uses keytabs instead of passwords -+ -+# hosts -+dn: cn=Default Host Password Policy,cn=computers,cn=accounts,$SUFFIX -+default:objectClass: krbPwdPolicy -+default:objectClass: nsContainer -+default:objectClass: top -+default:cn: Default Host Password Policy -+default:krbMinPwdLife: 0 -+default:krbPwdMinDiffChars: 0 -+default:krbPwdMinLength: 0 -+default:krbPwdHistoryLength: 0 -+default:krbMaxPwdLife: 0 -+default:krbPwdMaxFailure: 0 -+default:krbPwdFailureCountInterval: 0 -+default:krbPwdLockoutDuration: 0 -+ -+# services -+dn: cn=Default Service Password Policy,cn=services,cn=accounts,$SUFFIX -+default:objectClass: krbPwdPolicy -+default:objectClass: nsContainer -+default:objectClass: top -+default:cn: Default Service Password Policy -+default:krbMinPwdLife: 0 -+default:krbPwdMinDiffChars: 0 -+default:krbPwdMinLength: 0 -+default:krbPwdHistoryLength: 0 -+default:krbMaxPwdLife: 0 -+default:krbPwdMaxFailure: 0 -+default:krbPwdFailureCountInterval: 0 -+default:krbPwdLockoutDuration: 0 -+ -+# kerberos policy container -+# this is necessary to avoid mixing the Kerberos sevice password policy -+# with group-membership based user password policies -+dn: cn=Kerberos Service Password Policy,cn=$REALM,cn=kerberos,$SUFFIX -+default:objectClass: nsContainer -+default:objectClass: top -+default:cn: Kerberos Service Password Policy -+ -+# kerberos services -+dn: cn=Default Kerberos Service Password Policy,cn=Kerberos Service Password Policy,cn=$REALM,cn=kerberos,$SUFFIX -+default:objectClass: krbPwdPolicy -+default:objectClass: nsContainer -+default:objectClass: top -+default:cn: Default Kerberos Service Password Policy -+default:krbMinPwdLife: 0 -+default:krbPwdMinDiffChars: 0 -+default:krbPwdMinLength: 0 -+default:krbPwdHistoryLength: 0 -+default:krbMaxPwdLife: 0 -+default:krbPwdMaxFailure: 0 -+default:krbPwdFailureCountInterval: 0 -+default:krbPwdLockoutDuration: 0 -+ -+# default password policies for hosts, services and kerberos services -+# cosPriority is set intentionally to higher number than FreeIPA API allows -+# to set to ensure that these password policies have always lower priority -+# than any defined by user. -+ -+# hosts -+dn: cn=cosTemplates,cn=computers,cn=accounts,$SUFFIX -+default:objectclass: top -+default:objectclass: nsContainer -+default:cn: cosTemplates -+ -+dn: cn=Default Password Policy,cn=cosTemplates,cn=computers,cn=accounts,$SUFFIX -+default:objectclass: top -+default:objectclass: cosTemplate -+default:objectclass: extensibleObject -+default:objectclass: krbContainer -+default:cn: Default Password Policy -+default:cosPriority: 10000000000 -+default:krbPwdPolicyReference: cn=Default Host Password Policy,cn=computers,cn=accounts,$SUFFIX -+ -+dn: cn=Default Password Policy,cn=computers,cn=accounts,$SUFFIX -+default:description: Default Password Policy for Hosts -+default:objectClass: top -+default:objectClass: ldapsubentry -+default:objectClass: cosSuperDefinition -+default:objectClass: cosPointerDefinition -+default:cosTemplateDn: cn=Default Password Policy,cn=cosTemplates,cn=computers,cn=accounts,$SUFFIX -+default:cosAttribute: krbPwdPolicyReference default -+ -+# services -+dn: cn=cosTemplates,cn=services,cn=accounts,$SUFFIX -+default:objectclass: top -+default:objectclass: nsContainer -+default:cn: cosTemplates -+ -+dn: cn=Default Password Policy,cn=cosTemplates,cn=services,cn=accounts,$SUFFIX -+default:objectclass: top -+default:objectclass: cosTemplate -+default:objectclass: extensibleObject -+default:objectclass: krbContainer -+default:cn: Default Password Policy -+default:cosPriority: 10000000000 -+default:krbPwdPolicyReference: cn=Default Service Password Policy,cn=services,cn=accounts,$SUFFIX -+ -+dn: cn=Default Password Policy,cn=services,cn=accounts,$SUFFIX -+default:description: Default Password Policy for Services -+default:objectClass: top -+default:objectClass: ldapsubentry -+default:objectClass: cosSuperDefinition -+default:objectClass: cosPointerDefinition -+default:cosTemplateDn: cn=Default Password Policy,cn=cosTemplates,cn=services,cn=accounts,$SUFFIX -+default:cosAttribute: krbPwdPolicyReference default -+ -+# kerberos services -+dn: cn=cosTemplates,cn=$REALM,cn=kerberos,$SUFFIX -+default:objectclass: top -+default:objectclass: nsContainer -+default:cn: cosTemplates -+ -+dn: cn=Default Password Policy,cn=cosTemplates,cn=$REALM,cn=kerberos,$SUFFIX -+default:objectclass: top -+default:objectclass: cosTemplate -+default:objectclass: extensibleObject -+default:objectclass: krbContainer -+default:cn: Default Password Policy -+default:cosPriority: 10000000000 -+default:krbPwdPolicyReference: cn=Default Kerberos Service Password Policy,cn=Kerberos Service Password Policy,cn=$REALM,cn=kerberos,$SUFFIX -+ -+dn: cn=Default Password Policy,cn=$REALM,cn=kerberos,$SUFFIX -+default:description: Default Password Policy for Kerberos Services -+default:objectClass: top -+default:objectClass: ldapsubentry -+default:objectClass: cosSuperDefinition -+default:objectClass: cosPointerDefinition -+default:cosTemplateDn: cn=Default Password Policy,cn=cosTemplates,cn=$REALM,cn=kerberos,$SUFFIX -+default:cosAttribute: krbPwdPolicyReference default -diff --git a/install/updates/Makefile.am b/install/updates/Makefile.am -index 455fd209d171888dc94a7f708dc5fa1743f62bf4..310ae39c3b659cbe897380f572824acb26009574 100644 ---- a/install/updates/Makefile.am -+++ b/install/updates/Makefile.am -@@ -23,6 +23,7 @@ app_DATA = \ - 20-winsync_index.update \ - 20-idoverride_index.update \ - 20-uuid.update \ -+ 20-default_password_policy.update \ - 21-replicas_container.update \ - 21-ca_renewal_container.update \ - 21-certstore_container.update \ -diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py -index 057cd3d4b512513a4e3a8f228dc5f07f31fd84e0..6bb2e76f64ac11abc426c70c645cfb042be474c2 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -252,6 +252,7 @@ class Service(object): - # There is no service in the wrong location, nothing to do. - # This can happen when installing a replica - return None -+ entry.pop('krbpwdpolicyreference', None) # don't copy virtual attr - newdn = DN(('krbprincipalname', principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix) - hostdn = DN(('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix) - self.admin_conn.delete_entry(entry) --- -2.7.4 - diff --git a/SOURCES/0152-certs-do-not-export-CA-certs-in-install_pem_from_p12.patch b/SOURCES/0152-certs-do-not-export-CA-certs-in-install_pem_from_p12.patch new file mode 100644 index 0000000..90d2d3e --- /dev/null +++ b/SOURCES/0152-certs-do-not-export-CA-certs-in-install_pem_from_p12.patch @@ -0,0 +1,33 @@ +From b66796bcd888e0204955913e642d8e45937843dd Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:12:36 +0000 +Subject: [PATCH] certs: do not export CA certs in install_pem_from_p12 + +This fixes `kdc.crt` containing the full chain rather than just the KDC +certificate in CA-less server install. + +https://pagure.io/freeipa/issue/6831 +https://pagure.io/freeipa/issue/6869 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipaserver/install/certs.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py +index 06a7e2143964484fa45106ca381043eb440dc5b1..02c479d92511fcf4043e7d6798c85cf8256c3299 100644 +--- a/ipaserver/install/certs.py ++++ b/ipaserver/install/certs.py +@@ -64,7 +64,7 @@ def get_cert_nickname(cert): + + def install_pem_from_p12(p12_fname, p12_passwd, pem_fname): + pwd = ipautil.write_tmp_file(p12_passwd) +- ipautil.run([paths.OPENSSL, "pkcs12", "-nokeys", ++ ipautil.run([paths.OPENSSL, "pkcs12", "-nokeys", "-clcerts", + "-in", p12_fname, "-out", pem_fname, + "-passin", "file:" + pwd.name]) + +-- +2.9.4 + diff --git a/SOURCES/0152-ipa-kdb-search-for-password-policies-globally.patch b/SOURCES/0152-ipa-kdb-search-for-password-policies-globally.patch deleted file mode 100644 index c92f812..0000000 --- a/SOURCES/0152-ipa-kdb-search-for-password-policies-globally.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 3e27ba027208df0408c77307e403bc8382aa3395 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 15 Dec 2016 16:30:00 +0200 -Subject: [PATCH] ipa-kdb: search for password policies globally - -With the CoS templates now used to create additional password policies -per object type that are placed under the object subtrees, DAL driver -needs to search for the policies in the whole tree. - -Individual policies referenced by the krbPwdPolicyReference attribute -are always searched by their full DN and with the base scope. However, -when KDC asks a DAL driver to return a password policy by name, we don't -have any specific base to search. The original code did search by the -realm subtree. - -Fixes https://fedorahosted.org/freeipa/ticket/6561 - -Reviewed-By: Martin Babinsky ---- - daemons/ipa-kdb/ipa_kdb_pwdpolicy.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c b/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c -index 076314a12840881a340763ab5693131aaccafec6..0c810af98f7a37b76afc4ca40b29441d9793f12f 100644 ---- a/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c -+++ b/daemons/ipa-kdb/ipa_kdb_pwdpolicy.c -@@ -163,7 +163,7 @@ krb5_error_code ipadb_get_pwd_policy(krb5_context kcontext, char *name, - } - - kerr = ipadb_simple_search(ipactx, -- ipactx->realm_base, LDAP_SCOPE_SUBTREE, -+ ipactx->base, LDAP_SCOPE_SUBTREE, - src_filter, std_pwdpolicy_attrs, &res); - if (kerr) { - goto done; --- -2.7.4 - diff --git a/SOURCES/0153-Set-up-DS-TLS-on-replica-in-CA-less-topology.patch b/SOURCES/0153-Set-up-DS-TLS-on-replica-in-CA-less-topology.patch deleted file mode 100644 index caf5574..0000000 --- a/SOURCES/0153-Set-up-DS-TLS-on-replica-in-CA-less-topology.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 762573b429c4465aabde8d1a7d8b3bdaa1c3b15b Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Tue, 20 Dec 2016 23:29:22 +1000 -Subject: [PATCH] Set up DS TLS on replica in CA-less topology - -Fixes: https://fedorahosted.org/freeipa/ticket/6226 -Reviewed-By: Tomas Krizek ---- - ipaserver/install/dsinstance.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py -index c93b3b4ff58c4102a9de448247966ad3dd8e4e7c..1249a86d2c4c83eb9426885bfed8910aa3274d21 100644 ---- a/ipaserver/install/dsinstance.py -+++ b/ipaserver/install/dsinstance.py -@@ -382,7 +382,9 @@ class DsInstance(service.Service): - - if self.promote: - self.step("creating DS keytab", self.__get_ds_keytab) -- if self.ca_is_configured: -+ if self.pkcs12_info: -+ self.step("configuring ssl for ds instance", self.__enable_ssl) -+ else: - self.step("retrieving DS Certificate", self.__get_ds_cert) - self.step("restarting directory server", self.__restart_instance) - --- -2.9.3 - diff --git a/SOURCES/0153-server-install-fix-KDC-certificate-validation-in-CA-.patch b/SOURCES/0153-server-install-fix-KDC-certificate-validation-in-CA-.patch new file mode 100644 index 0000000..039d3c5 --- /dev/null +++ b/SOURCES/0153-server-install-fix-KDC-certificate-validation-in-CA-.patch @@ -0,0 +1,203 @@ +From 5301e86fccfde6ab444a2c600a412487318fbd13 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:14:27 +0000 +Subject: [PATCH] server install: fix KDC certificate validation in CA-less + +Verify that the provided certificate has the extended key usage and subject +alternative name required for KDC. + +https://pagure.io/freeipa/issue/6831 +https://pagure.io/freeipa/issue/6869 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipapython/certdb.py | 42 ++++++++++++++++++++++++++++++ + ipaserver/install/installutils.py | 24 +++++++++++------ + ipaserver/install/server/install.py | 11 ++++++-- + ipaserver/install/server/replicainstall.py | 11 ++++++-- + 4 files changed, 76 insertions(+), 12 deletions(-) + +diff --git a/ipapython/certdb.py b/ipapython/certdb.py +index 1ee2603653452577476cf413e6af951cd29c273e..114c58340253141706afa461ecaf87797562ca1d 100644 +--- a/ipapython/certdb.py ++++ b/ipapython/certdb.py +@@ -24,14 +24,17 @@ import pwd + import grp + import re + import tempfile ++from tempfile import NamedTemporaryFile + import shutil + import base64 + from cryptography.hazmat.primitives import serialization ++import cryptography.x509 + from nss import nss + from nss.error import NSPRError + + from ipapython.dn import DN + from ipapython.ipa_log_manager import root_logger ++from ipapython.kerberos import Principal + from ipapython import ipautil + from ipalib import x509 # pylint: disable=ipa-forbidden-import + +@@ -182,6 +185,38 @@ def unparse_trust_flags(trust_flags): + return trust_flags + + ++def verify_kdc_cert_validity(kdc_cert, ca_certs, realm): ++ pem_kdc_cert = kdc_cert.public_bytes(serialization.Encoding.PEM) ++ pem_ca_certs = '\n'.join( ++ cert.public_bytes(serialization.Encoding.PEM) for cert in ca_certs) ++ ++ with NamedTemporaryFile() as kdc_file, NamedTemporaryFile() as ca_file: ++ kdc_file.write(pem_kdc_cert) ++ kdc_file.flush() ++ ca_file.write(pem_ca_certs) ++ ca_file.flush() ++ ++ try: ++ ipautil.run( ++ [OPENSSL, 'verify', '-CAfile', ca_file.name, kdc_file.name]) ++ eku = kdc_cert.extensions.get_extension_for_class( ++ cryptography.x509.ExtendedKeyUsage) ++ list(eku.value).index( ++ cryptography.x509.ObjectIdentifier(x509.EKU_PKINIT_KDC)) ++ except (ipautil.CalledProcessError, ++ cryptography.x509.ExtensionNotFound, ++ ValueError): ++ raise ValueError("invalid for a KDC") ++ ++ principal = str(Principal(['krbtgt', realm], realm)) ++ gns = x509.process_othernames(x509.get_san_general_names(kdc_cert)) ++ for gn in gns: ++ if isinstance(gn, x509.KRB5PrincipalName) and gn.name == principal: ++ break ++ else: ++ raise ValueError("invalid for realm %s" % realm) ++ ++ + class NSSDatabase(object): + """A general-purpose wrapper around a NSS cert database + +@@ -707,3 +742,10 @@ class NSSDatabase(object): + finally: + del certdb, cert + nss.nss_shutdown() ++ ++ def verify_kdc_cert_validity(self, nickname, realm): ++ nicknames = self.get_trust_chain(nickname) ++ certs = [self.get_cert(nickname) for nickname in nicknames] ++ certs = [x509.load_certificate(cert, x509.DER) for cert in certs] ++ ++ verify_kdc_cert_validity(certs[-1], certs[:-1], realm) +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 5bce9894780bd920db11196b925492a7fe8f22d0..d2283af20485fd5d66bfd3cc49059d08d1802575 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -1001,7 +1001,7 @@ def handle_error(error, log_file_name=None): + + + def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files, +- host_name): ++ host_name=None, realm_name=None): + """ + Load and verify server certificate and private key from multiple files + +@@ -1066,13 +1066,21 @@ def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files, + "CA certificate %s in %s is not valid: %s" % + (subject, ", ".join(cert_files), e)) + +- # Check server validity +- try: +- nssdb.verify_server_cert_validity(key_nickname, host_name) +- except ValueError as e: +- raise ScriptError( +- "The server certificate in %s is not valid: %s" % +- (", ".join(cert_files), e)) ++ if host_name is not None: ++ try: ++ nssdb.verify_server_cert_validity(key_nickname, host_name) ++ except ValueError as e: ++ raise ScriptError( ++ "The server certificate in %s is not valid: %s" % ++ (", ".join(cert_files), e)) ++ ++ if realm_name is not None: ++ try: ++ nssdb.verify_kdc_cert_validity(key_nickname, realm_name) ++ except ValueError as e: ++ raise ScriptError( ++ "The KDC certificate in %s is not valid: %s" % ++ (", ".join(cert_files), e)) + + out_file = tempfile.NamedTemporaryFile() + out_password = ipautil.ipa_generate_password() +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index c1bdce6c8459dfeabd0096d105e535ec4ee56a2a..03380b8d0e9150224b014a1a174d7ea81ccdcf00 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -520,12 +520,12 @@ def install_check(installer): + if options.pkinit_pin is None: + raise ScriptError( + "Kerberos KDC private key unlock password required") +- pkinit_pkcs12_file, pkinit_pin, _pkinit_ca_cert = load_pkcs12( ++ pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12( + cert_files=options.pkinit_cert_files, + key_password=options.pkinit_pin, + key_nickname=options.pkinit_cert_name, + ca_cert_files=options.ca_cert_files, +- host_name=host_name) ++ realm_name=realm_name) + pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin) + + if (options.http_cert_files and options.dirsrv_cert_files and +@@ -534,6 +534,13 @@ def install_check(installer): + "Apache Server SSL certificate and Directory Server SSL " + "certificate are not signed by the same CA certificate") + ++ if (options.http_cert_files and ++ options.pkinit_cert_files and ++ http_ca_cert != pkinit_ca_cert): ++ raise ScriptError( ++ "Apache Server SSL certificate and PKINIT KDC " ++ "certificate are not signed by the same CA certificate") ++ + if not options.dm_password: + dm_password = read_dm_password() + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 66d7ba44645aed69b12f0e5ea14f5080492fe5ef..6f71f0b51812943fea3fb1c576a0174c739a070b 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1069,12 +1069,12 @@ def promote_check(installer): + if options.pkinit_pin is None: + raise ScriptError( + "Kerberos KDC private key unlock password required") +- pkinit_pkcs12_file, pkinit_pin, _pkinit_ca_cert = load_pkcs12( ++ pkinit_pkcs12_file, pkinit_pin, pkinit_ca_cert = load_pkcs12( + cert_files=options.pkinit_cert_files, + key_password=options.pkinit_pin, + key_nickname=options.pkinit_cert_name, + ca_cert_files=options.ca_cert_files, +- host_name=config.host_name) ++ realm_name=config.realm_name) + pkinit_pkcs12_info = (pkinit_pkcs12_file.name, pkinit_pin) + + if (options.http_cert_files and options.dirsrv_cert_files and +@@ -1083,6 +1083,13 @@ def promote_check(installer): + "Server SSL certificate are not signed by the same" + " CA certificate") + ++ if (options.http_cert_files and ++ options.pkinit_cert_files and ++ http_ca_cert != pkinit_ca_cert): ++ raise RuntimeError("Apache Server SSL certificate and PKINIT KDC " ++ "certificate are not signed by the same CA " ++ "certificate") ++ + installutils.verify_fqdn(config.host_name, options.no_host_dns) + installutils.verify_fqdn(config.master_host_name, options.no_host_dns) + +-- +2.9.4 + diff --git a/SOURCES/0154-replica-install-respect-pkinit-cert-file.patch b/SOURCES/0154-replica-install-respect-pkinit-cert-file.patch new file mode 100644 index 0000000..c0673f4 --- /dev/null +++ b/SOURCES/0154-replica-install-respect-pkinit-cert-file.patch @@ -0,0 +1,56 @@ +From c1b49645c22b91aff51a29e715e29c5df7a0892a Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Thu, 11 May 2017 07:40:40 +0000 +Subject: [PATCH] replica install: respect --pkinit-cert-file + +When --pkinit-cert-file is used, make sure the certificate and key is +actually passed to `KrbInstance`. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/replicainstall.py | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 6f71f0b51812943fea3fb1c576a0174c739a070b..b30133ffa22d410452ae04624d49db209175bed9 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -113,12 +113,13 @@ def install_replica_ds(config, options, ca_is_configured, remote_api, + return ds + + +-def install_krb(config, setup_pkinit=False, promote=False): ++def install_krb(config, setup_pkinit=False, pkcs12_info=None, promote=False): + krb = krbinstance.KrbInstance() + + # pkinit files +- pkcs12_info = make_pkcs12_info(config.dir, "pkinitcert.p12", +- "pkinit_pin.txt") ++ if pkcs12_info is None: ++ pkcs12_info = make_pkcs12_info(config.dir, "pkinitcert.p12", ++ "pkinit_pin.txt") + + krb.create_replica(config.realm_name, + config.master_host_name, config.host_name, +@@ -1350,6 +1351,7 @@ def install(installer): + cafile = installer._ca_file + dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info + http_pkcs12_info = installer._http_pkcs12_info ++ pkinit_pkcs12_info = installer._pkinit_pkcs12_info + + remote_api = installer._remote_api + conn = remote_api.Backend.ldap2 +@@ -1430,6 +1432,7 @@ def install(installer): + krb = install_krb( + config, + setup_pkinit=not options.no_pkinit, ++ pkcs12_info=pkinit_pkcs12_info, + promote=promote) + + # we now need to enable ssl on the ds +-- +2.9.4 + diff --git a/SOURCES/0154-wait_for_entry-use-only-DN-as-parameter.patch b/SOURCES/0154-wait_for_entry-use-only-DN-as-parameter.patch deleted file mode 100644 index f159361..0000000 --- a/SOURCES/0154-wait_for_entry-use-only-DN-as-parameter.patch +++ /dev/null @@ -1,63 +0,0 @@ -From a9a9d67637c394ca1490e8e7df790c06b3480c56 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Wed, 18 Jan 2017 12:55:13 +0100 -Subject: [PATCH] wait_for_entry: use only DN as parameter - -Using the whole entry is not needed as parameter because only DN is used -and it prevents easier usage of this function - -https://fedorahosted.org/freeipa/ticket/6588 - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/install/dogtaginstance.py | 2 +- - ipaserver/install/replication.py | 6 ++---- - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py -index b65628277d9e361a3ab5674dfd2689e258b1887b..2a2ab6fc7f90514013b5a6f368739c2f1706ed9b 100644 ---- a/ipaserver/install/dogtaginstance.py -+++ b/ipaserver/install/dogtaginstance.py -@@ -470,7 +470,7 @@ class DogtagInstance(service.Service): - port=389, - protocol='ldap') - master_conn.do_sasl_gssapi_bind() -- replication.wait_for_entry(master_conn, entry) -+ replication.wait_for_entry(master_conn, entry.dn) - del master_conn - - def __remove_admin_from_group(self, group): -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 5f03ddeadfc515255509a1f49d3b38687e561b9f..be4de6dd0037a028bcaf1743be74a80855ba3541 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -150,7 +150,7 @@ def wait_for_task(conn, dn): - return exit_code - - --def wait_for_entry(connection, entry, timeout=7200, attr='', quiet=True): -+def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True): - """Wait for entry and/or attr to show up""" - - filter = "(objectclass=*)" -@@ -160,8 +160,6 @@ def wait_for_entry(connection, entry, timeout=7200, attr='', quiet=True): - attrlist.append(attr) - timeout += int(time.time()) - -- dn = entry.dn -- - if not quiet: - sys.stdout.write("Waiting for %s %s:%s " % (connection, dn, attr)) - sys.stdout.flush() -@@ -732,7 +730,7 @@ class ReplicationManager(object): - # that we will have to set the memberof fixup task - self.need_memberof_fixup = True - -- wait_for_entry(a_conn, entry) -+ wait_for_entry(a_conn, entry.dn) - - def needs_memberof_fixup(self): - return self.need_memberof_fixup --- -2.9.3 - diff --git a/SOURCES/0155-Wait-until-HTTPS-principal-entry-is-replicated-to-re.patch b/SOURCES/0155-Wait-until-HTTPS-principal-entry-is-replicated-to-re.patch deleted file mode 100644 index 7c63b72..0000000 --- a/SOURCES/0155-Wait-until-HTTPS-principal-entry-is-replicated-to-re.patch +++ /dev/null @@ -1,45 +0,0 @@ -From ea3848ae6729fda734ec60167129f4cae5253a44 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Wed, 18 Jan 2017 13:56:24 +0100 -Subject: [PATCH] Wait until HTTPS principal entry is replicated to replica - -Without HTTP principal the steps later fails. - -https://fedorahosted.org/freeipa/ticket/6588 - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/install/server/replicainstall.py | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index f54ff7da06c57b9c8251429cbdacc5c300805f84..2a1c290351d8ce1dade5eea2f67539659555af2e 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -36,7 +36,7 @@ from ipaserver.install import ( - from ipaserver.install.installutils import ( - create_replica_config, ReplicaConfig, load_pkcs12, is_ipa_configured) - from ipaserver.install.replication import ( -- ReplicationManager, replica_conn_check) -+ ReplicationManager, replica_conn_check, wait_for_entry) - import SSSDConfig - from subprocess import CalledProcessError - from binascii import hexlify -@@ -86,6 +86,14 @@ def install_http_certs(config, fstore, remote_api): - config.master_host_name, - paths.IPA_KEYTAB, - force_service_add=True) -+ dn = DN( -+ ('krbprincipalname', principal), -+ api.env.container_service, api.env.basedn -+ ) -+ conn = ipaldap.IPAdmin(realm=config.realm_name, ldapi=True) -+ conn.do_external_bind() -+ wait_for_entry(conn, dn) -+ conn.unbind() - - # Obtain certificate for the HTTP service - nssdir = certs.NSS_DIR --- -2.9.3 - diff --git a/SOURCES/0155-cacert-manage-support-PKINIT.patch b/SOURCES/0155-cacert-manage-support-PKINIT.patch new file mode 100644 index 0000000..5c59888 --- /dev/null +++ b/SOURCES/0155-cacert-manage-support-PKINIT.patch @@ -0,0 +1,74 @@ +From 7aca75a7142eba58d9cb3ab5d40f3224e53e2243 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:17:32 +0000 +Subject: [PATCH] cacert manage: support PKINIT + +Allow installing 3rd party CA certificates trusted to issue PKINIT KDC +and/or client certificates. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + install/tools/man/ipa-cacert-manage.1 | 2 +- + ipaserver/install/ipa_cacert_manage.py | 21 +++++++++++++++++---- + 2 files changed, 18 insertions(+), 5 deletions(-) + +diff --git a/install/tools/man/ipa-cacert-manage.1 b/install/tools/man/ipa-cacert-manage.1 +index e36258d0f96aa1050fe88b05f4fe9a1a8f9a7978..03172814ffb603b656952ce5e9ad6af9c8238ab3 100644 +--- a/install/tools/man/ipa-cacert-manage.1 ++++ b/install/tools/man/ipa-cacert-manage.1 +@@ -90,7 +90,7 @@ File containing the IPA CA certificate and the external CA certificate chain. Th + Nickname for the certificate. + .TP + \fB\-t\fR \fITRUST_FLAGS\fR, \fB\-\-trust\-flags\fR=\fITRUST_FLAGS\fR +-Trust flags for the certificate in certutil format. Trust flags are of the form "X,Y,Z" where X is for SSL, Y is for S/MIME, and Z is for code signing. Use ",," for no explicit trust. ++Trust flags for the certificate in certutil format. Trust flags are of the form "A,B,C" or "A,B,C,D" where A is for SSL, B is for S/MIME, C is for code signing, and D is for PKINIT. Use ",," for no explicit trust. + .sp + The supported trust flags are: + .RS +diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py +index d28a5966f054141819463cdb1dfef48ee1e46e92..e88e8b63ae94759ac835f3b3b31b0735d68a67b0 100644 +--- a/ipaserver/install/ipa_cacert_manage.py ++++ b/ipaserver/install/ipa_cacert_manage.py +@@ -28,6 +28,7 @@ from ipalib.install import certmonger, certstore + from ipapython import admintool, ipautil + from ipapython.certdb import (EMPTY_TRUST_FLAGS, + EXTERNAL_CA_TRUST_FLAGS, ++ TrustFlags, + parse_trust_flags) + from ipapython.dn import DN + from ipaplatform.paths import paths +@@ -363,12 +364,24 @@ class CACertManage(admintool.AdminTool): + "http://www.freeipa.org/page/Troubleshooting for " + "troubleshooting guide)" % e) + +- trust_flags = options.trust_flags +- if ((set(trust_flags) - set(',CPTcgpuw')) or +- len(trust_flags.split(',')) != 3): ++ trust_flags = options.trust_flags.split(',') ++ if (set(options.trust_flags) - set(',CPTcgpuw') or ++ len(trust_flags) not in [3, 4]): + raise admintool.ScriptError("Invalid trust flags") + +- trust_flags = parse_trust_flags(trust_flags) ++ extra_flags = trust_flags[3:] ++ extra_usages = set() ++ if extra_flags: ++ if 'C' in extra_flags[0]: ++ extra_usages.add(x509.EKU_PKINIT_KDC) ++ if 'T' in extra_flags[0]: ++ extra_usages.add(x509.EKU_PKINIT_CLIENT_AUTH) ++ ++ trust_flags = parse_trust_flags(','.join(trust_flags[:3])) ++ trust_flags = TrustFlags(trust_flags.has_key, ++ trust_flags.trusted, ++ trust_flags.ca, ++ trust_flags.usages | extra_usages) + + try: + certstore.put_ca_cert_nss( +-- +2.9.4 + diff --git a/SOURCES/0156-Use-proper-logging-for-error-messages.patch b/SOURCES/0156-Use-proper-logging-for-error-messages.patch deleted file mode 100644 index 624d1ea..0000000 --- a/SOURCES/0156-Use-proper-logging-for-error-messages.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 999042579802d0443307ed18e8bb0b993c102c95 Mon Sep 17 00:00:00 2001 -From: Martin Basti -Date: Wed, 18 Jan 2017 17:08:19 +0100 -Subject: [PATCH] Use proper logging for error messages - -https://fedorahosted.org/freeipa/ticket/6588r - -Reviewed-By: Stanislav Laznicka ---- - ipaserver/install/replication.py | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index be4de6dd0037a028bcaf1743be74a80855ba3541..1f437dad4ed850ebfd59fe9f72a5127df8f56f3e 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -171,7 +171,7 @@ def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True): - except errors.NotFound: - pass # no entry yet - except Exception as e: # badness -- print("\nError reading entry", dn, e) -+ root_logger.error("Error reading entry %s: %s", dn, e) - break - if not entry: - if not quiet: -@@ -180,11 +180,13 @@ def wait_for_entry(connection, dn, timeout=7200, attr='', quiet=True): - time.sleep(1) - - if not entry and int(time.time()) > timeout: -- print("\nwait_for_entry timeout for %s for %s" % (connection, dn)) -+ root_logger.error( -+ "wait_for_entry timeout for %s for %s", connection, dn) - elif entry and not quiet: -- print("\nThe waited for entry is:", entry) -+ root_logger.error("The waited for entry is: %s", entry) - elif not entry: -- print("\nError: could not read entry %s from %s" % (dn, connection)) -+ root_logger.error( -+ "Error: could not read entry %s from %s", dn, connection) - - - class ReplicationManager(object): --- -2.9.3 - diff --git a/SOURCES/0156-server-certinstall-support-PKINIT.patch b/SOURCES/0156-server-certinstall-support-PKINIT.patch new file mode 100644 index 0000000..82dcce4 --- /dev/null +++ b/SOURCES/0156-server-certinstall-support-PKINIT.patch @@ -0,0 +1,163 @@ +From 96afd05dda2ce502994b6c9ceae819d79d96a666 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Wed, 3 May 2017 06:18:05 +0000 +Subject: [PATCH] server certinstall: support PKINIT + +Allow replacing the KDC certificate. + +https://pagure.io/freeipa/issue/6831 + +Reviewed-By: Stanislav Laznicka +Reviewed-By: Martin Babinsky +--- + install/tools/man/ipa-server-certinstall.1 | 5 ++- + ipaserver/install/ipa_server_certinstall.py | 70 +++++++++++++++++++++++++++-- + 2 files changed, 70 insertions(+), 5 deletions(-) + +diff --git a/install/tools/man/ipa-server-certinstall.1 b/install/tools/man/ipa-server-certinstall.1 +index d23bbd490e2b0454b8fb908e22f33c7a611c8874..35cd8c6c711119d7c782c6a89ac78b4894cec073 100644 +--- a/install/tools/man/ipa-server-certinstall.1 ++++ b/install/tools/man/ipa-server-certinstall.1 +@@ -22,7 +22,7 @@ ipa\-server\-certinstall \- Install new SSL server certificates + .SH "SYNOPSIS" + ipa\-server\-certinstall [\fIOPTION\fR]... FILE... + .SH "DESCRIPTION" +-Replace the current SSL Directory and/or Apache server certificate(s) with the certificate in the specified files. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. ++Replace the current Directory server SSL certificate, Apache server SSL certificate and/or Kerberos KDC certificate with the certificate in the specified files. The files are accepted in PEM and DER certificate, PKCS#7 certificate chain, PKCS#8 and raw private key and PKCS#12 formats. + + PKCS#12 is a file format used to safely transport SSL certificates and public/private keypairs. + +@@ -37,6 +37,9 @@ Install the certificate on the Directory Server + \fB\-w\fR, \fB\-\-http\fR + Install the certificate in the Apache Web Server + .TP ++\fB\-k\fR, \fB\-\-kdc\fR ++Install the certificate in the Kerberos KDC ++.TP + \fB\-\-pin\fR=\fIPIN\fR + The password to unlock the private key + .TP +diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py +index 9f2cd9573a156949ae979e7b69fbd23adaf2feb8..a14a84f188c62170c8ac11f823ebba60609e4cc7 100644 +--- a/ipaserver/install/ipa_server_certinstall.py ++++ b/ipaserver/install/ipa_server_certinstall.py +@@ -21,12 +21,17 @@ + import os + import os.path + import pwd ++import tempfile + import optparse # pylint: disable=deprecated-module + ++from ipalib import x509 ++from ipalib.install import certmonger + from ipaplatform.constants import constants + from ipaplatform.paths import paths + from ipapython import admintool +-from ipapython.certdb import get_ca_nickname, NSSDatabase ++from ipapython.certdb import (get_ca_nickname, ++ NSSDatabase, ++ verify_kdc_cert_validity) + from ipapython.dn import DN + from ipalib import api, errors + from ipaserver.install import certs, dsinstance, installutils +@@ -35,7 +40,7 @@ from ipaserver.install import certs, dsinstance, installutils + class ServerCertInstall(admintool.AdminTool): + command_name = 'ipa-server-certinstall' + +- usage = "%prog <-d|-w> [options] ..." ++ usage = "%prog <-d|-w|-k> [options] ..." + + description = "Install new SSL server certificates." + +@@ -52,6 +57,10 @@ class ServerCertInstall(admintool.AdminTool): + dest="http", action="store_true", default=False, + help="install certificate for the http server") + parser.add_option( ++ "-k", "--kdc", ++ dest="kdc", action="store_true", default=False, ++ help="install PKINIT certificate for the KDC") ++ parser.add_option( + "--pin", + dest="pin", metavar="PIN", sensitive=True, + help="The password of the PKCS#12 file") +@@ -73,8 +82,9 @@ class ServerCertInstall(admintool.AdminTool): + + installutils.check_server_configuration() + +- if not self.options.dirsrv and not self.options.http: +- self.option_parser.error("you must specify dirsrv and/or http") ++ if not any((self.options.dirsrv, self.options.http, self.options.kdc)): ++ self.option_parser.error( ++ "you must specify dirsrv, http and/or kdc") + + if not self.args: + self.option_parser.error("you must provide certificate filename") +@@ -108,6 +118,9 @@ class ServerCertInstall(admintool.AdminTool): + if self.options.http: + self.install_http_cert() + ++ if self.options.kdc: ++ self.install_kdc_cert() ++ + api.Backend.ldap2.disconnect() + + def install_dirsrv_cert(self): +@@ -161,6 +174,55 @@ class ServerCertInstall(admintool.AdminTool): + os.chown(os.path.join(dirname, 'key3.db'), 0, pent.pw_gid) + os.chown(os.path.join(dirname, 'secmod.db'), 0, pent.pw_gid) + ++ def install_kdc_cert(self): ++ ca_cert_file = paths.CA_BUNDLE_PEM ++ pkcs12_file, pin, ca_cert = installutils.load_pkcs12( ++ cert_files=self.args, ++ key_password=self.options.pin, ++ key_nickname=self.options.cert_name, ++ ca_cert_files=[ca_cert_file], ++ realm_name=api.env.realm) ++ ++ cdb = certs.CertDB(api.env.realm, nssdir=paths.IPA_NSSDB_DIR) ++ ++ # Check that the ca_cert is known and trusted ++ with tempfile.NamedTemporaryFile() as temp: ++ certs.install_pem_from_p12(pkcs12_file.name, pin, temp.name) ++ ++ kdc_cert = x509.load_certificate_from_file(temp.name) ++ ca_certs = x509.load_certificate_list_from_file(ca_cert_file) ++ ++ try: ++ verify_kdc_cert_validity(kdc_cert, ca_certs, api.env.realm) ++ except ValueError as e: ++ raise admintool.ScriptError( ++ "Peer's certificate issuer is not trusted (%s). " ++ "Please run ipa-cacert-manage install and ipa-certupdate " ++ "to install the CA certificate." % str(e)) ++ ++ try: ++ ca_enabled = api.Command.ca_is_enabled()['result'] ++ if ca_enabled: ++ certmonger.stop_tracking(certfile=paths.KDC_CERT) ++ ++ certs.install_pem_from_p12(pkcs12_file.name, pin, paths.KDC_CERT) ++ certs.install_key_from_p12(pkcs12_file.name, pin, paths.KDC_KEY) ++ ++ if ca_enabled: ++ # Start tracking only if the cert was issued by IPA CA ++ # Retrieve IPA CA ++ ipa_ca_cert = cdb.get_cert_from_db( ++ get_ca_nickname(api.env.realm), ++ pem=False) ++ # And compare with the CA which signed this certificate ++ if ca_cert == ipa_ca_cert: ++ certmonger.start_tracking( ++ (paths.KDC_CERT, paths.KDC_KEY), ++ storage='FILE', ++ profile='KDCs_PKINIT_Certs') ++ except RuntimeError as e: ++ raise admintool.ScriptError(str(e)) ++ + def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb): + # create a temp nssdb + with NSSDatabase() as tempnssdb: +-- +2.9.4 + diff --git a/SOURCES/0157-Do-not-configure-PKI-ajp-redirection-to-use-1.patch b/SOURCES/0157-Do-not-configure-PKI-ajp-redirection-to-use-1.patch deleted file mode 100644 index c853ae2..0000000 --- a/SOURCES/0157-Do-not-configure-PKI-ajp-redirection-to-use-1.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 036d6fbf3d2af9f805f28f03679afc6ae1c25282 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Fri, 17 Feb 2017 15:59:57 +0100 -Subject: [PATCH] Do not configure PKI ajp redirection to use "::1" - -When ipa-server-install configures PKI, it provides a configuration file -with the parameter pki_ajp_host set to ::1. This parameter is used to configure -Tomcat redirection in /etc/pki/pki-tomcat/server.xml: - -ie all requests to port 8009 are redirected to port 8443 on address ::1. - -If the /etc/hosts config file does not define ::1 for localhost, then AJP -redirection fails and replica install is not able to request a certificate -for the replica. - -Since PKI has been fixed (see PKI ticket 2570) to configure by default the AJP -redirection with "localhost", FreeIPA does not need any more to override -this setting. -The code now depends on pki 10.3.5-11 which provides the fix in the template -and the upgrade. - -https://fedorahosted.org/freeipa/ticket/6575 - -Reviewed-By: Tomas Krizek ---- - freeipa.spec.in | 4 ++-- - ipaserver/install/cainstance.py | 4 ---- - 2 files changed, 2 insertions(+), 6 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index dba59edc2dc1c6dd12017fbc5c9a6f7bb385e7c3..d5eb76ac3c13fbbfc645bd3e42e72e3e17b4d68c 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -159,8 +159,8 @@ Requires(post): systemd-units - Requires: selinux-policy >= %{selinux_policy_version} - Requires(post): selinux-policy-base >= %{selinux_policy_version} - Requires: slapi-nis >= %{slapi_nis_version} --Requires: pki-ca >= 10.3.4 --Requires: pki-kra >= 10.3.4 -+Requires: pki-ca >= 10.3.5-11 -+Requires: pki-kra >= 10.3.5-11 - Requires(preun): python systemd-units - Requires(postun): python systemd-units - Requires: zip -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 6c57aadfcdc2864f8cdc84c16556dce7163737fc..3e0d5fb40356ccf5f8053fb1c8af11c547c4d19c 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -577,10 +577,6 @@ class CAInstance(DogtagInstance): - config.set("CA", "pki_external_ca_cert_chain_path", cert_chain_file.name) - config.set("CA", "pki_external_step_two", "True") - -- # PKI IPv6 Configuration -- config.add_section("Tomcat") -- config.set("Tomcat", "pki_ajp_host", "::1") -- - # Generate configuration file - with open(cfg_file, "wb") as f: - config.write(f) --- -2.9.3 - diff --git a/SOURCES/0157-ipa-ca-install-append-CA-cert-chain-into-etc-ipa-ca..patch b/SOURCES/0157-ipa-ca-install-append-CA-cert-chain-into-etc-ipa-ca..patch new file mode 100644 index 0000000..d2ba8e1 --- /dev/null +++ b/SOURCES/0157-ipa-ca-install-append-CA-cert-chain-into-etc-ipa-ca..patch @@ -0,0 +1,41 @@ +From ceb0d5c2a4a8e8fae271e5a37ee32f58a2d36273 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 16 May 2017 17:24:09 +0200 +Subject: [PATCH] ipa-ca-install: append CA cert chain into /etc/ipa/ca.crt + +ipa-ca-install currently overwrites /etc/ipa/ca.crt with the CA chain +retrieved from Dogtag. It should instead append the new certs, otherwise +the CA that signed dirsrv and httpd certificates is removed and ipa tools +fail. +A consequence is that ipa-kra-install fails. +This is a regression introduced by 5ab85b36. + +https://pagure.io/freeipa/issue/6925 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/cainstance.py | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py +index b8c8cc4fc4532fc2c911ec174d363f8280ce863b..b0e9e8757ec3e3c0d03ed930743ef5a1253b864a 100644 +--- a/ipaserver/install/cainstance.py ++++ b/ipaserver/install/cainstance.py +@@ -793,6 +793,14 @@ class CAInstance(DogtagInstance): + # Get list of PEM certificates + certlist = x509.pkcs7_to_pems(data, x509.DER) + ++ # We need to append the certs to the existing file, so start by ++ # reading the file ++ if ipautil.file_exists(paths.IPA_CA_CRT): ++ ca_certs = x509.load_certificate_list_from_file(paths.IPA_CA_CRT) ++ ca_certs = [cert.public_bytes(serialization.Encoding.PEM) ++ for cert in ca_certs] ++ certlist.extend(ca_certs) ++ + # We have all the certificates in certlist, write them to a PEM file + for path in [paths.IPA_CA_CRT, + paths.KDC_CA_BUNDLE_PEM, +-- +2.9.4 + diff --git a/SOURCES/0158-added-ssl-verification-using-IPA-trust-anchor.patch b/SOURCES/0158-added-ssl-verification-using-IPA-trust-anchor.patch deleted file mode 100644 index 23c6c40..0000000 --- a/SOURCES/0158-added-ssl-verification-using-IPA-trust-anchor.patch +++ /dev/null @@ -1,27 +0,0 @@ -From c9e05427f20f79a8304a9874ae6793a0b5f54987 Mon Sep 17 00:00:00 2001 -From: Thorsten Scherf -Date: Fri, 24 Feb 2017 11:53:46 +0100 -Subject: [PATCH] added ssl verification using IPA trust anchor - -https://fedorahosted.org/freeipa/ticket/6686 - -Reviewed-By: Christian Heimes ---- - ipapython/secrets/client.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ipapython/secrets/client.py b/ipapython/secrets/client.py -index d9cc7d0f5b066dfd8efba480feb5f271ed1ebe83..f2f14af694df4468b3eedaac0fc762787b62e623 100644 ---- a/ipapython/secrets/client.py -+++ b/ipapython/secrets/client.py -@@ -94,6 +94,7 @@ class CustodiaClient(object): - - # Perform request - r = requests.get(url, headers=headers, -+ verify=paths.IPA_CA_CRT, - params={'type': 'kem', 'value': request}) - r.raise_for_status() - reply = r.json() --- -2.9.3 - diff --git a/SOURCES/0158-ca-cert-show-check-certificate_out-in-options.patch b/SOURCES/0158-ca-cert-show-check-certificate_out-in-options.patch new file mode 100644 index 0000000..e02a510 --- /dev/null +++ b/SOURCES/0158-ca-cert-show-check-certificate_out-in-options.patch @@ -0,0 +1,73 @@ +From c1258d68268bc93536ba66921d65a2550bdf475e Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Tue, 9 May 2017 17:45:20 +0200 +Subject: [PATCH] ca/cert-show: check certificate_out in options + +If --certificate-out was specified on the command line, it will appear +among the options. If it was empty, it will be None. + +This check was done properly in the ca plugin. Lets' just unify how this +is handled and improve user experience by announcing which option causes +the failure. + +https://pagure.io/freeipa/issue/6885 + +Reviewed-By: Fraser Tweedale +Reviewed-By: Jan Cholasta +--- + ipaclient/plugins/ca.py | 8 ++++++-- + ipaclient/plugins/cert.py | 12 +++++++++--- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/ipaclient/plugins/ca.py b/ipaclient/plugins/ca.py +index fcdf484635c7611d905f28629a380a0152c7bde1..fe9c55f4c07b4682de1ad882b6c5651dafece716 100644 +--- a/ipaclient/plugins/ca.py ++++ b/ipaclient/plugins/ca.py +@@ -4,7 +4,7 @@ + + import base64 + from ipaclient.frontend import MethodOverride +-from ipalib import util, x509, Str ++from ipalib import errors, util, x509, Str + from ipalib.plugable import Registry + from ipalib.text import _ + +@@ -26,7 +26,11 @@ class WithCertOutArgs(MethodOverride): + filename = None + if 'certificate_out' in options: + filename = options.pop('certificate_out') +- util.check_writable_file(filename) ++ try: ++ util.check_writable_file(filename) ++ except errors.FileError as e: ++ raise errors.ValidationError(name='certificate-out', ++ error=str(e)) + + result = super(WithCertOutArgs, self).forward(*keys, **options) + if filename: +diff --git a/ipaclient/plugins/cert.py b/ipaclient/plugins/cert.py +index 9ec6970b18d0cdc3863259faee3a697f63799c3f..93cd3cef1a14925bc0795b32e97e44d69897be5c 100644 +--- a/ipaclient/plugins/cert.py ++++ b/ipaclient/plugins/cert.py +@@ -50,9 +50,15 @@ class CertRetrieveOverride(MethodOverride): + ) + + def forward(self, *args, **options): +- certificate_out = options.pop('certificate_out', None) +- if certificate_out is not None: +- util.check_writable_file(certificate_out) ++ if 'certificate_out' in options: ++ certificate_out = options.pop('certificate_out') ++ try: ++ util.check_writable_file(certificate_out) ++ except errors.FileError as e: ++ raise errors.ValidationError(name='certificate-out', ++ error=str(e)) ++ else: ++ certificate_out = None + + result = super(CertRetrieveOverride, self).forward(*args, **options) + +-- +2.9.4 + diff --git a/SOURCES/0159-Fix-rare-race-condition-with-missing-ccache-file.patch b/SOURCES/0159-Fix-rare-race-condition-with-missing-ccache-file.patch new file mode 100644 index 0000000..b30af31 --- /dev/null +++ b/SOURCES/0159-Fix-rare-race-condition-with-missing-ccache-file.patch @@ -0,0 +1,47 @@ +From 341d5790afb01e9d99c73ba336103e38e2b30091 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 22 May 2017 10:56:41 -0400 +Subject: [PATCH] Fix rare race condition with missing ccache file + +In some circumstances the ccache file may disappear while +mod_auth_gssapi still has a valid cookie and the client is performing a +json server call. + +This may lead to credentials getting sourced from the keytab. +Make sure we enforce what GSS NAME we want to resolve so HTTP creds are +never mistakenly sourced. + +Ticket: #6972 + +Signed-off-by: Simo Sorce +Reviewed-By: Alexander Bokovoy +--- + ipaserver/rpcserver.py | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 4cde2815a0fe9332d67c84b531f573ff88b1a302..32f286148bbdf294f941116b4bdca85714a52837 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -777,8 +777,17 @@ class jsonserver_session(jsonserver, KerberosSession): + self.debug('no ccache, need login') + return self.need_login(start_response) + ++ # If we have a ccache, make sure we have a GSS_NAME and use ++ # it to resolve the ccache name (Issue: 6972 ) ++ principal = environ.get('GSS_NAME') ++ if principal is None: ++ self.debug('no GSS Name, need login') ++ return self.need_login(start_response) ++ gss_name = gssapi.Name(principal, gssapi.NameType.kerberos_principal) ++ + # Redirect to login if Kerberos credentials are expired +- creds = get_credentials_if_valid(ccache_name=ccache_name) ++ creds = get_credentials_if_valid(name=gss_name, ++ ccache_name=ccache_name) + if not creds: + self.debug('ccache expired, deleting session, need login') + # The request is finished with the ccache, destroy it. +-- +2.9.4 + diff --git a/SOURCES/0159-ca-correctly-authorise-ca-del-ca-enable-and-ca-disab.patch b/SOURCES/0159-ca-correctly-authorise-ca-del-ca-enable-and-ca-disab.patch deleted file mode 100644 index e8a7344..0000000 --- a/SOURCES/0159-ca-correctly-authorise-ca-del-ca-enable-and-ca-disab.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 61156c5157ec3f8982f4f6efdbf8dfa281cb5a11 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Fri, 13 Jan 2017 20:33:45 +1000 -Subject: [PATCH] ca: correctly authorise ca-del, ca-enable and ca-disable - -CAs consist of a FreeIPA and a corresponding Dogtag object. When -executing ca-del, ca-enable and ca-disable, changes are made to the -Dogtag object. In the case of ca-del, the corresponding FreeIPA -object is deleted after the Dogtag CA is deleted. - -These operations were not correctly authorised; the FreeIPA -permissions are not checked before the Dogtag operations are -executed. This allows any user to delete, enable or disable a -lightweight CA (except the main IPA CA, for which there are -additional check to prevent deletion or disablement). - -Add the proper authorisation checks to the ca-del, ca-enable and -ca-disable commands. - -https://pagure.io/freeipa/issue/6713 - -Reviewed-By: Jan Cholasta ---- - ipaserver/plugins/ca.py | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py -index 966ae2b1bdb4bb0207dfa58f0e9c951bc930f766..b642a5d1d6e03b415ba562491e8a38569b116563 100644 ---- a/ipaserver/plugins/ca.py -+++ b/ipaserver/plugins/ca.py -@@ -192,6 +192,12 @@ class ca_del(LDAPDelete): - def pre_callback(self, ldap, dn, *keys, **options): - ca_enabled_check() - -+ # ensure operator has permission to delete CA -+ # before contacting Dogtag -+ if not ldap.can_delete(dn): -+ raise errors.ACIError(info=_( -+ "Insufficient privilege to delete a CA.")) -+ - if keys[0] == IPA_CA_CN: - raise errors.ProtectedEntryError( - label=_("CA"), --- -2.9.3 - diff --git a/SOURCES/0160-Remove-pkinit-anonymous-command.patch b/SOURCES/0160-Remove-pkinit-anonymous-command.patch new file mode 100644 index 0000000..9bd28fe --- /dev/null +++ b/SOURCES/0160-Remove-pkinit-anonymous-command.patch @@ -0,0 +1,176 @@ +From 2eb94f86872ee7ea191dc3e44fcb3d5a4683ae67 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 10 May 2017 15:54:21 +0200 +Subject: [PATCH] Remove pkinit-anonymous command + +Ever since from v4.5, FreeIPA expects at least some kind of +anonymous PKINIT to work. The pkinit-anonymous command was supposed +to enable/disable anonymous pkinit by locking/unlocking the +anonymous principal. We can't allow this for FreeIPA to work +so we are removing the command as it was never supported anyway. + +https://pagure.io/freeipa/issue/6936 + +Reviewed-By: Martin Babinsky +--- + API.txt | 6 --- + VERSION.m4 | 4 +- + ipaserver/plugins/pkinit.py | 94 ++------------------------------------------- + 3 files changed, 6 insertions(+), 98 deletions(-) + +diff --git a/API.txt b/API.txt +index 7594157384511c1317738dafb41361676a2a0fd7..4e6754afe2deab5c963577f1e1363f1123a31a86 100644 +--- a/API.txt ++++ b/API.txt +@@ -3736,11 +3736,6 @@ command: ping/1 + args: 0,1,1 + option: Str('version?') + output: Output('summary', type=[, ]) +-command: pkinit_anonymous/1 +-args: 1,1,1 +-arg: Str('action') +-option: Str('version?') +-output: Output('result') + command: plugins/1 + args: 0,3,3 + option: Flag('all', autofill=True, cli_name='all', default=True) +@@ -6803,7 +6798,6 @@ default: permission_remove_member/1 + default: permission_show/1 + default: ping/1 + default: pkinit/1 +-default: pkinit_anonymous/1 + default: plugins/1 + default: privilege/1 + default: privilege_add/1 +diff --git a/VERSION.m4 b/VERSION.m4 +index 31e7c1d6e7054d3b4ef1d9dfaf349d2959f8330a..e10ee3cad6f5a6e023ea3cb9ec20591b7caae0bd 100644 +--- a/VERSION.m4 ++++ b/VERSION.m4 +@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000) + # # + ######################################################## + define(IPA_API_VERSION_MAJOR, 2) +-define(IPA_API_VERSION_MINOR, 224) +-# Last change: Add rename option to sudorule objects ++define(IPA_API_VERSION_MINOR, 226) ++# Last change: Remove the pkinit-anonymous command + + + ######################################################## +diff --git a/ipaserver/plugins/pkinit.py b/ipaserver/plugins/pkinit.py +index b6b3f38828e86e6e677fadc9c4a638b2eee5171f..e49b31091d676865fa7f023be8edc3cdef9d6d2c 100644 +--- a/ipaserver/plugins/pkinit.py ++++ b/ipaserver/plugins/pkinit.py +@@ -1,52 +1,14 @@ +-# Authors: +-# Simo Sorce + # +-# Copyright (C) 2010 Red Hat +-# see file 'COPYING' for use and warranty information ++# Copyright (C) 2017 FreeIPA Contributors see COPYING for license + # +-# 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 . + +-from ipalib import api, errors +-from ipalib import Str +-from ipalib import Object, Command ++from ipalib import Object + from ipalib import _ + from ipalib.plugable import Registry +-from ipalib.constants import ANON_USER +-from ipapython.dn import DN +- +-__doc__ = _(""" +-Kerberos pkinit options +- +-Enable or disable anonymous pkinit using the principal +-WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with +-pkinit support. +- +-EXAMPLES: +- +- Enable anonymous pkinit: +- ipa pkinit-anonymous enable +- +- Disable anonymous pkinit: +- ipa pkinit-anonymous disable +- +-For more information on anonymous pkinit see: +- +-http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit +-""") + + register = Registry() + ++ + @register() + class pkinit(Object): + """ +@@ -54,52 +16,4 @@ class pkinit(Object): + """ + object_name = _('pkinit') + +- label=_('PKINIT') +- +- +-def valid_arg(ugettext, action): +- """ +- Accepts only Enable/Disable. +- """ +- a = action.lower() +- if a != 'enable' and a != 'disable': +- raise errors.ValidationError( +- name='action', +- error=_('Unknown command %s') % action +- ) +- +-@register() +-class pkinit_anonymous(Command): +- __doc__ = _('Enable or Disable Anonymous PKINIT.') +- +- princ_name = '%s@%s' % (ANON_USER, api.env.realm) +- default_dn = DN(('krbprincipalname', princ_name), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn) +- +- takes_args = ( +- Str('action', valid_arg), +- ) +- +- def execute(self, action, **options): +- ldap = self.api.Backend.ldap2 +- set_lock = False +- lock = None +- +- entry_attrs = ldap.get_entry(self.default_dn, ['nsaccountlock']) +- +- if 'nsaccountlock' in entry_attrs: +- lock = entry_attrs['nsaccountlock'][0].lower() +- +- if action.lower() == 'enable': +- if lock == 'true': +- set_lock = True +- lock = None +- elif action.lower() == 'disable': +- if lock != 'true': +- set_lock = True +- lock = 'TRUE' +- +- if set_lock: +- entry_attrs['nsaccountlock'] = lock +- ldap.update_entry(entry_attrs) +- +- return dict(result=True) ++ label = _('PKINIT') +-- +2.9.4 + diff --git a/SOURCES/0160-compat-fix-Any-params-in-batch-and-dnsrecord.patch b/SOURCES/0160-compat-fix-Any-params-in-batch-and-dnsrecord.patch deleted file mode 100644 index 16257b5..0000000 --- a/SOURCES/0160-compat-fix-Any-params-in-batch-and-dnsrecord.patch +++ /dev/null @@ -1,129 +0,0 @@ -From e5311fbfd5ad83671c61473d7acf4ddaf157e994 Mon Sep 17 00:00:00 2001 -From: Jan Cholasta -Date: Thu, 23 Feb 2017 13:04:19 +0000 -Subject: [PATCH] compat: fix `Any` params in `batch` and `dnsrecord` - -The `methods` argument of `batch` and `dnsrecords` attribute of `dnsrecord` -were incorrectly defined as `Str` instead of `Any`. - -https://fedorahosted.org/freeipa/ticket/6647 - -Reviewed-By: Martin Basti ---- - ipaclient/remote_plugins/2_114/batch.py | 2 +- - ipaclient/remote_plugins/2_114/dns.py | 2 +- - ipaclient/remote_plugins/2_156/batch.py | 2 +- - ipaclient/remote_plugins/2_156/dns.py | 2 +- - ipaclient/remote_plugins/2_164/batch.py | 2 +- - ipaclient/remote_plugins/2_164/dns.py | 2 +- - ipaclient/remote_plugins/2_49/batch.py | 2 +- - ipaclient/remote_plugins/2_49/dns.py | 2 +- - 8 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/ipaclient/remote_plugins/2_114/batch.py b/ipaclient/remote_plugins/2_114/batch.py -index 4a613b677bedda447a07d3d0bdc10d38762ccc61..2709e5907f18f254f7e605beff9a7f3c9a2ae18d 100644 ---- a/ipaclient/remote_plugins/2_114/batch.py -+++ b/ipaclient/remote_plugins/2_114/batch.py -@@ -50,7 +50,7 @@ class batch(Command): - NO_CLI = True - - takes_args = ( -- parameters.Str( -+ parameters.Any( - 'methods', - required=False, - multivalue=True, -diff --git a/ipaclient/remote_plugins/2_114/dns.py b/ipaclient/remote_plugins/2_114/dns.py -index 5d91dbcb37fcb42cb67ab76a1871fd3df6217cf8..acb8a658204fb18b088766f947f82839f053cbf3 100644 ---- a/ipaclient/remote_plugins/2_114/dns.py -+++ b/ipaclient/remote_plugins/2_114/dns.py -@@ -326,7 +326,7 @@ class dnsrecord(Object): - 'dnsclass', - required=False, - ), -- parameters.Str( -+ parameters.Any( - 'dnsrecords', - required=False, - label=_(u'Records'), -diff --git a/ipaclient/remote_plugins/2_156/batch.py b/ipaclient/remote_plugins/2_156/batch.py -index 4a613b677bedda447a07d3d0bdc10d38762ccc61..2709e5907f18f254f7e605beff9a7f3c9a2ae18d 100644 ---- a/ipaclient/remote_plugins/2_156/batch.py -+++ b/ipaclient/remote_plugins/2_156/batch.py -@@ -50,7 +50,7 @@ class batch(Command): - NO_CLI = True - - takes_args = ( -- parameters.Str( -+ parameters.Any( - 'methods', - required=False, - multivalue=True, -diff --git a/ipaclient/remote_plugins/2_156/dns.py b/ipaclient/remote_plugins/2_156/dns.py -index 39a0b269533481bcb5b193ad8a463a48146e5275..bbfaa9fd0fb2b582430a5c85761af206d53884f9 100644 ---- a/ipaclient/remote_plugins/2_156/dns.py -+++ b/ipaclient/remote_plugins/2_156/dns.py -@@ -326,7 +326,7 @@ class dnsrecord(Object): - 'dnsclass', - required=False, - ), -- parameters.Str( -+ parameters.Any( - 'dnsrecords', - required=False, - label=_(u'Records'), -diff --git a/ipaclient/remote_plugins/2_164/batch.py b/ipaclient/remote_plugins/2_164/batch.py -index 4a613b677bedda447a07d3d0bdc10d38762ccc61..2709e5907f18f254f7e605beff9a7f3c9a2ae18d 100644 ---- a/ipaclient/remote_plugins/2_164/batch.py -+++ b/ipaclient/remote_plugins/2_164/batch.py -@@ -50,7 +50,7 @@ class batch(Command): - NO_CLI = True - - takes_args = ( -- parameters.Str( -+ parameters.Any( - 'methods', - required=False, - multivalue=True, -diff --git a/ipaclient/remote_plugins/2_164/dns.py b/ipaclient/remote_plugins/2_164/dns.py -index b07a94f1942e3913d6d169b61d84a3b3db268671..244be87f32db6664e5264038b97bc53b704ff166 100644 ---- a/ipaclient/remote_plugins/2_164/dns.py -+++ b/ipaclient/remote_plugins/2_164/dns.py -@@ -326,7 +326,7 @@ class dnsrecord(Object): - 'dnsclass', - required=False, - ), -- parameters.Str( -+ parameters.Any( - 'dnsrecords', - required=False, - label=_(u'Records'), -diff --git a/ipaclient/remote_plugins/2_49/batch.py b/ipaclient/remote_plugins/2_49/batch.py -index a1f351d332d56c959bf8632cb218de8540f45005..67e5978e634b71735c1940086a80943d967ff1f6 100644 ---- a/ipaclient/remote_plugins/2_49/batch.py -+++ b/ipaclient/remote_plugins/2_49/batch.py -@@ -50,7 +50,7 @@ class batch(Command): - NO_CLI = True - - takes_args = ( -- parameters.Str( -+ parameters.Any( - 'methods', - required=False, - multivalue=True, -diff --git a/ipaclient/remote_plugins/2_49/dns.py b/ipaclient/remote_plugins/2_49/dns.py -index 07cef75c2a97c07a77a9ffa3997ec6fa431e3151..4b543a2c2539f7b67467b0a38ab8013a1ebe0840 100644 ---- a/ipaclient/remote_plugins/2_49/dns.py -+++ b/ipaclient/remote_plugins/2_49/dns.py -@@ -256,7 +256,7 @@ class dnsrecord(Object): - label=_(u'Class'), - doc=_(u'DNS class'), - ), -- parameters.Str( -+ parameters.Any( - 'dnsrecords', - required=False, - label=_(u'Records'), --- -2.9.3 - diff --git a/SOURCES/0161-krb5-make-sure-KDC-certificate-is-readable.patch b/SOURCES/0161-krb5-make-sure-KDC-certificate-is-readable.patch new file mode 100644 index 0000000..20e9312 --- /dev/null +++ b/SOURCES/0161-krb5-make-sure-KDC-certificate-is-readable.patch @@ -0,0 +1,108 @@ +From 131fbeff0397aa4e98bab8a22f0a1d366f223f05 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 22 May 2017 22:36:18 +0300 +Subject: [PATCH] krb5: make sure KDC certificate is readable + +When requesting certificate for KDC profile, make sure its public part +is actually readable to others. + +Fixes https://pagure.io/freeipa/issue/6973 + +Reviewed-By: Simo Sorce +Reviewed-By: Jan Cholasta +--- + install/restart_scripts/renew_kdc_cert | 4 ---- + ipalib/install/certmonger.py | 12 +++++++++--- + ipaserver/install/krbinstance.py | 3 ++- + 3 files changed, 11 insertions(+), 8 deletions(-) + +diff --git a/install/restart_scripts/renew_kdc_cert b/install/restart_scripts/renew_kdc_cert +index 9247920874fc9540ac3421dd59fd902cc195243f..14902893f0e61e31f798fa39737a6ed9d31de111 100755 +--- a/install/restart_scripts/renew_kdc_cert ++++ b/install/restart_scripts/renew_kdc_cert +@@ -3,19 +3,15 @@ + # Copyright (C) 2017 FreeIPA Contributors see COPYING for license + # + +-import os + import syslog + import traceback + + from ipaplatform import services +-from ipaplatform.paths import paths + from ipaserver.install import certs + + + def main(): + with certs.renewal_lock: +- os.chmod(paths.KDC_CERT, 0o644) +- + try: + if services.knownservices.krb5kdc.is_running(): + syslog.syslog(syslog.LOG_NOTICE, 'restarting krb5kdc') +diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py +index 5709853ffebdbf58929b9a935e906ae67341bea8..ad031a738f4397d230ed131bde6ac7ddb7ef6fdb 100644 +--- a/ipalib/install/certmonger.py ++++ b/ipalib/install/certmonger.py +@@ -302,7 +302,7 @@ def add_subject(request_id, subject): + def request_and_wait_for_cert( + certpath, subject, principal, nickname=None, passwd_fname=None, + dns=None, ca='IPA', profile=None, +- pre_command=None, post_command=None, storage='NSSDB'): ++ pre_command=None, post_command=None, storage='NSSDB', perms=None): + """ + Execute certmonger to request a server certificate. + +@@ -310,7 +310,7 @@ def request_and_wait_for_cert( + """ + reqId = request_cert(certpath, subject, principal, nickname, + passwd_fname, dns, ca, profile, +- pre_command, post_command, storage) ++ pre_command, post_command, storage, perms) + state = wait_for_request(reqId, api.env.startup_timeout) + ca_error = get_request_value(reqId, 'ca-error') + if state != 'MONITORING' or ca_error: +@@ -321,12 +321,14 @@ def request_and_wait_for_cert( + def request_cert( + certpath, subject, principal, nickname=None, passwd_fname=None, + dns=None, ca='IPA', profile=None, +- pre_command=None, post_command=None, storage='NSSDB'): ++ pre_command=None, post_command=None, storage='NSSDB', perms=None): + """ + Execute certmonger to request a server certificate. + + ``dns`` + A sequence of DNS names to appear in SAN request extension. ++ ``perms`` ++ A tuple of (cert, key) permissions in e.g., (0644,0660) + """ + if storage == 'FILE': + certfile, keyfile = certpath +@@ -367,6 +369,10 @@ def request_cert( + post_command = certmonger_cmd_template % (post_command) + request_parameters['cert-postsave-command'] = post_command + ++ if perms: ++ request_parameters['key-perms'] = perms[0] ++ request_parameters['cert-perms'] = perms[1] ++ + result = cm.obj_if.add_request(request_parameters) + try: + if result[0]: +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index 1692e0b2badb23c18386346a552c83881018cf60..a1053d55ccaae17bef93547c036fb9d08d296f0b 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -432,7 +432,8 @@ class KrbInstance(service.Service): + dns=self.fqdn, + storage='FILE', + profile=KDC_PROFILE, +- post_command='renew_kdc_cert') ++ post_command='renew_kdc_cert', ++ perms=(0o644, 0o600)) + except dbus.DBusException as e: + # if the certificate is already tracked, ignore the error + name = e.get_dbus_name() +-- +2.9.4 + diff --git a/SOURCES/0162-Change-python-cryptography-to-python2-cryptography.patch b/SOURCES/0162-Change-python-cryptography-to-python2-cryptography.patch new file mode 100644 index 0000000..ac26a93 --- /dev/null +++ b/SOURCES/0162-Change-python-cryptography-to-python2-cryptography.patch @@ -0,0 +1,41 @@ +From a2747fd0b73818babe82a81c07a098124830b85d Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Fri, 19 May 2017 16:32:28 +0200 +Subject: [PATCH] Change python-cryptography to python2-cryptography + +Package name is python2-cryptography and even that it Provides +python-cryptography package, it causes problems during update of IPA +on RHEL - python2-cryptography is not updated. After changing required package +name to python2-cryptography upgrade on RHEL works well. + +Fixes: https://pagure.io/freeipa/issue/6749 +Reviewed-By: Martin Babinsky +--- + freeipa.spec.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 790e5838e0ba45ea9bbfe3bc3a1bd40c0bd3ac1a..2cbaa60df0db021a4a1ce10af383cd6a15e1e57c 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -164,7 +164,7 @@ BuildRequires: python3-wheel + %if 0%{?with_lint} + BuildRequires: samba-python + # 1.4: the version where Certificate.serial changed to .serial_number +-BuildRequires: python-cryptography >= 1.4 ++BuildRequires: python2-cryptography >= 1.4 + BuildRequires: python-gssapi >= 1.2.0 + BuildRequires: pylint >= 1.6 + # workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1096506 +@@ -645,7 +645,7 @@ Requires: keyutils + Requires: pyOpenSSL + Requires: python >= 2.7.9 + Requires: python-nss >= 0.16 +-Requires: python-cryptography >= 1.4 ++Requires: python2-cryptography >= 1.4 + Requires: python-netaddr + Requires: python-libipa_hbac + Requires: python-qrcode-core >= 5.0.0 +-- +2.9.4 + diff --git a/SOURCES/0163-Allow-for-multivalued-server-attributes.patch b/SOURCES/0163-Allow-for-multivalued-server-attributes.patch new file mode 100644 index 0000000..f6fc013 --- /dev/null +++ b/SOURCES/0163-Allow-for-multivalued-server-attributes.patch @@ -0,0 +1,270 @@ +From a3801d66f5cf3f08062c3aa67a7b33d13fae56b7 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 11 May 2017 15:55:53 +0200 +Subject: [PATCH] Allow for multivalued server attributes + +In order to achieve the task, the following changes were required: + +* vectorize the base class for server attributes +* add a child class that enforces single-value attributes. It still + accepts/returns single-value lists in order to not break Liskov + substitution principle +* Existing attributes inherit from the child class + +https://pagure.io/freeipa/issue/6937 + +Reviewed-By: Jan Cholasta +Reviewed-By: Stanislav Laznicka +--- + ipaserver/plugins/serverroles.py | 4 +- + ipaserver/servroles.py | 109 +++++++++++++++++++--------- + ipatests/test_ipaserver/test_serverroles.py | 10 +-- + 3 files changed, 79 insertions(+), 44 deletions(-) + +diff --git a/ipaserver/plugins/serverroles.py b/ipaserver/plugins/serverroles.py +index e22eadd7b163469cc9fc4472640aa64d21c9d38f..e81635c3315cc3fca84450f43fb7df883aae57d9 100644 +--- a/ipaserver/plugins/serverroles.py ++++ b/ipaserver/plugins/serverroles.py +@@ -136,9 +136,7 @@ class serverroles(Backend): + + for name, attr in assoc_attributes.items(): + attr_value = attr.get(self.api) +- +- if attr_value is not None: +- result.update({name: attr_value}) ++ result.update({name: attr_value}) + + return result + +diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py +index cf4599995118c589a5b51236c68e13f14ac1257b..84fed1046b3b46dc9f5f8bbe6e03354725f1136c 100644 +--- a/ipaserver/servroles.py ++++ b/ipaserver/servroles.py +@@ -277,29 +277,33 @@ class ServerAttribute(LDAPBasedProperty): + try: + entries = ldap2.get_entries(search_base, filter=search_filter) + except errors.EmptyResult: +- return ++ return [] + +- master_cn = entries[0].dn[1]['cn'] ++ master_cns = {e.dn[1]['cn'] for e in entries} + + associated_role_providers = set( + self._get_assoc_role_providers(api_instance)) + +- if master_cn not in associated_role_providers: ++ if not master_cns.issubset(associated_role_providers): + raise errors.ValidationError( + name=self.name, + error=_("all masters must have %(role)s role enabled" % + {'role': self.associated_role.name}) + ) + +- return master_cn ++ return sorted(master_cns) + +- def _get_master_dn(self, api_instance, server): +- return DN(('cn', server), api_instance.env.container_masters, +- api_instance.env.basedn) ++ def _get_master_dns(self, api_instance, servers): ++ return [ ++ DN(('cn', server), api_instance.env.container_masters, ++ api_instance.env.basedn) for server in servers] ++ ++ def _get_masters_service_entries(self, ldap, master_dns): ++ service_dns = [ ++ DN(('cn', self.associated_service_name), master_dn) for master_dn ++ in master_dns] + +- def _get_masters_service_entry(self, ldap, master_dn): +- service_dn = DN(('cn', self.associated_service_name), master_dn) +- return ldap.get_entry(service_dn) ++ return [ldap.get_entry(service_dn) for service_dn in service_dns] + + def _add_attribute_to_svc_entry(self, ldap, service_entry): + """ +@@ -341,65 +345,98 @@ class ServerAttribute(LDAPBasedProperty): + r[u'server_server'] for r in self.associated_role.status( + api_instance) if r[u'status'] == ENABLED] + +- def _remove(self, api_instance, master): ++ def _remove(self, api_instance, masters): + """ +- remove attribute from the master ++ remove attribute from one or more masters + + :param api_instance: API instance +- :param master: master FQDN ++ :param master: list or iterable containing master FQDNs + """ + + ldap = api_instance.Backend.ldap2 + +- master_dn = self._get_master_dn(api_instance, master) +- service_entry = self._get_masters_service_entry(ldap, master_dn) +- self._remove_attribute_from_svc_entry(ldap, service_entry) ++ master_dns = self._get_master_dns(api_instance, masters) ++ service_entries = self._get_masters_service_entries(ldap, master_dns) ++ ++ for service_entry in service_entries: ++ self._remove_attribute_from_svc_entry(ldap, service_entry) + +- def _add(self, api_instance, master): ++ def _add(self, api_instance, masters): + """ + add attribute to the master + :param api_instance: API instance +- :param master: master FQDN ++ :param master: iterable containing master FQDNs + + :raises: * errors.ValidationError if the associated role is not enabled + on the master + """ + +- assoc_role_providers = self._get_assoc_role_providers(api_instance) ++ assoc_role_providers = set( ++ self._get_assoc_role_providers(api_instance)) ++ masters_set = set(masters) + ldap = api_instance.Backend.ldap2 + +- if master not in assoc_role_providers: ++ masters_without_role = masters_set - assoc_role_providers ++ ++ if masters_without_role: + raise errors.ValidationError( +- name=master, ++ name=', '.join(sorted(masters_without_role)), + error=_("must have %(role)s role enabled" % + {'role': self.associated_role.name}) + ) + +- master_dn = self._get_master_dn(api_instance, master) +- service_entry = self._get_masters_service_entry(ldap, master_dn) +- self._add_attribute_to_svc_entry(ldap, service_entry) ++ master_dns = self._get_master_dns(api_instance, masters) ++ service_entries = self._get_masters_service_entries(ldap, master_dns) ++ for service_entry in service_entries: ++ self._add_attribute_to_svc_entry(ldap, service_entry) + +- def set(self, api_instance, master): ++ def set(self, api_instance, masters): + """ +- set the attribute on master ++ set the attribute on masters + + :param api_instance: API instance +- :param master: FQDN of the new master ++ :param masters: an interable with FQDNs of the new masters + +- the attribute is automatically unset from previous master if present ++ the attribute is automatically unset from previous masters if present + + :raises: errors.EmptyModlist if the new masters is the same as +- the original on ++ the original ones + """ +- old_master = self.get(api_instance) ++ old_masters = self.get(api_instance) + +- if old_master == master: ++ if sorted(old_masters) == sorted(masters): + raise errors.EmptyModlist + +- self._add(api_instance, master) ++ if old_masters: ++ self._remove(api_instance, old_masters) ++ ++ self._add(api_instance, masters) ++ ++ ++class SingleValuedServerAttribute(ServerAttribute): ++ """ ++ Base class for server attributes that are forced to be single valued ++ ++ this means that `get` method will return a one-element list, and `set` ++ method will accept only one-element list ++ """ ++ ++ def set(self, api_instance, masters): ++ if len(masters) > 1: ++ raise errors.ValidationError( ++ name=self.attr_name, ++ error=_("must be enabled only on a single master")) ++ ++ super(SingleValuedServerAttribute, self).set(api_instance, masters) ++ ++ def get(self, api_instance): ++ masters = super(SingleValuedServerAttribute, self).get(api_instance) ++ num_masters = len(masters) ++ ++ if num_masters > 1: ++ raise errors.SingleMatchExpected(found=num_masters) + +- if old_master is not None: +- self._remove(api_instance, old_master) ++ return masters + + + _Service = namedtuple('Service', ['name', 'enabled']) +@@ -574,14 +611,14 @@ role_instances = ( + ) + + attribute_instances = ( +- ServerAttribute( ++ SingleValuedServerAttribute( + u"ca_renewal_master_server", + u"CA renewal master", + u"ca_server_server", + u"CA", + u"caRenewalMaster", + ), +- ServerAttribute( ++ SingleValuedServerAttribute( + u"dnssec_key_master_server", + u"DNSSec key master", + u"dns_server_server", +diff --git a/ipatests/test_ipaserver/test_serverroles.py b/ipatests/test_ipaserver/test_serverroles.py +index d8844df3007f076532a34d625379ab552ef45363..e671272783d8d71c2ee56074459433b98b79dd0a 100644 +--- a/ipatests/test_ipaserver/test_serverroles.py ++++ b/ipatests/test_ipaserver/test_serverroles.py +@@ -706,7 +706,7 @@ class TestServerAttributes(object): + actual_attr_masters = self.config_retrieve( + assoc_role, mock_api)[attr_name] + +- assert actual_attr_masters == fqdn ++ assert actual_attr_masters == [fqdn] + + def test_set_attribute_on_the_same_provider_raises_emptymodlist( + self, mock_api, mock_masters): +@@ -727,7 +727,7 @@ class TestServerAttributes(object): + non_ca_fqdn = mock_masters.get_fqdn('trust-controller-dns') + + with pytest.raises(errors.ValidationError): +- self.config_update(mock_api, **{attr_name: non_ca_fqdn}) ++ self.config_update(mock_api, **{attr_name: [non_ca_fqdn]}) + + def test_set_unknown_attribute_on_master_raises_notfound( + self, mock_api, mock_masters): +@@ -735,7 +735,7 @@ class TestServerAttributes(object): + fqdn = mock_masters.get_fqdn('trust-controller-ca') + + with pytest.raises(errors.NotFound): +- self.config_update(mock_api, **{attr_name: fqdn}) ++ self.config_update(mock_api, **{attr_name: [fqdn]}) + + def test_set_ca_renewal_master_on_other_ca_and_back(self, mock_api, + mock_masters): +@@ -747,7 +747,7 @@ class TestServerAttributes(object): + other_ca_server = mock_masters.get_fqdn('trust-controller-ca') + + for host in (other_ca_server, original_renewal_master): +- self.config_update(mock_api, **{attr_name: host}) ++ self.config_update(mock_api, **{attr_name: [host]}) + + assert ( +- self.config_retrieve(role_name, mock_api)[attr_name] == host) ++ self.config_retrieve(role_name, mock_api)[attr_name] == [host]) +-- +2.9.4 + diff --git a/SOURCES/0164-Refactor-the-role-attribute-member-reporting-code.patch b/SOURCES/0164-Refactor-the-role-attribute-member-reporting-code.patch new file mode 100644 index 0000000..c234e58 --- /dev/null +++ b/SOURCES/0164-Refactor-the-role-attribute-member-reporting-code.patch @@ -0,0 +1,179 @@ +From 352b1bc2735e8571bd4bf3a46f599834c6b0aefa Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Tue, 16 May 2017 17:29:39 +0200 +Subject: [PATCH] Refactor the role/attribute member reporting code + +The `config` object now hosts a generic method for updating the config +entry for desired server role configuration (if not empty). The +duplicated code in dns/trust/vaultconfig commands was replaced by a call +to a common method. + +https://pagure.io/freeipa/issue/6937 + +Reviewed-By: Jan Cholasta +Reviewed-By: Stanislav Laznicka +--- + ipaserver/plugins/config.py | 24 ++++++++++++++++-------- + ipaserver/plugins/dns.py | 16 ++++------------ + ipaserver/plugins/trust.py | 22 ++++------------------ + ipaserver/plugins/vault.py | 6 +++--- + 4 files changed, 27 insertions(+), 41 deletions(-) + +diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py +index b50e7a4691bd76bfaf7c332cd89b0f1bf55bac46..c88cb99b47ac746f8e18cf189708d457b535416a 100644 +--- a/ipaserver/plugins/config.py ++++ b/ipaserver/plugins/config.py +@@ -267,15 +267,21 @@ class config(LDAPObject): + def get_dn(self, *keys, **kwargs): + return DN(('cn', 'ipaconfig'), ('cn', 'etc'), api.env.basedn) + +- def show_servroles_attributes(self, entry_attrs, **options): ++ def update_entry_with_role_config(self, role_name, entry_attrs): ++ backend = self.api.Backend.serverroles ++ ++ role_config = backend.config_retrieve(role_name) ++ for key, value in role_config.items(): ++ if value: ++ entry_attrs.update({key: value}) ++ ++ ++ def show_servroles_attributes(self, entry_attrs, *roles, **options): + if options.get('raw', False): + return + +- backend = self.api.Backend.serverroles +- +- for role in ("CA server", "IPA master", "NTP server"): +- config = backend.config_retrieve(role) +- entry_attrs.update(config) ++ for role in roles: ++ self.update_entry_with_role_config(role, entry_attrs) + + def gather_trusted_domains(self): + """ +@@ -525,7 +531,8 @@ class config_mod(LDAPUpdate): + keys, options, exc, call_func, *call_args, **call_kwargs) + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): +- self.obj.show_servroles_attributes(entry_attrs, **options) ++ self.obj.show_servroles_attributes( ++ entry_attrs, "CA server", "IPA master", "NTP server", **options) + return dn + + +@@ -534,5 +541,6 @@ class config_show(LDAPRetrieve): + __doc__ = _('Show the current configuration.') + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): +- self.obj.show_servroles_attributes(entry_attrs, **options) ++ self.obj.show_servroles_attributes( ++ entry_attrs, "CA server", "IPA master", "NTP server", **options) + return dn +diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py +index 47ac963a0ae26fcaa81e70a8143bd7d0c172d20e..f0e6c48f06313def57cdd6a4c7114357c9d8de8a 100644 +--- a/ipaserver/plugins/dns.py ++++ b/ipaserver/plugins/dns.py +@@ -4184,16 +4184,6 @@ class dnsconfig(LDAPObject): + if is_config_empty: + result['summary'] = unicode(_('Global DNS configuration is empty')) + +- def show_servroles_attributes(self, entry_attrs, **options): +- if options.get('raw', False): +- return +- +- backend = self.api.Backend.serverroles +- entry_attrs.update( +- backend.config_retrieve("DNS server") +- ) +- +- + @register() + class dnsconfig_mod(LDAPUpdate): + __doc__ = _('Modify global DNS configuration.') +@@ -4247,7 +4237,8 @@ class dnsconfig_mod(LDAPUpdate): + return result + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): +- self.obj.show_servroles_attributes(entry_attrs, **options) ++ self.api.Object.config.show_servroles_attributes( ++ entry_attrs, "DNS server", **options) + return dn + + +@@ -4261,7 +4252,8 @@ class dnsconfig_show(LDAPRetrieve): + return result + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): +- self.obj.show_servroles_attributes(entry_attrs, **options) ++ self.api.Object.config.show_servroles_attributes( ++ entry_attrs, "DNS server", **options) + return dn + + +diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py +index 0829f8c714f15c4384a89e18ba29e417405c249c..075b39dcc33a79f3e73e8e1e9e31ebbef17618fe 100644 +--- a/ipaserver/plugins/trust.py ++++ b/ipaserver/plugins/trust.py +@@ -1278,22 +1278,6 @@ class trustconfig(LDAPObject): + + entry_attrs['ipantfallbackprimarygroup'] = [groupdn[0][0].value] + +- def show_servroles(self, entry_attrs, **options): +- if options.get('raw', False): +- return +- +- backend = self.api.Backend.serverroles +- +- adtrust_agents = backend.config_retrieve( +- "AD trust agent" +- ) +- adtrust_controllers = backend.config_retrieve( +- "AD trust controller" +- ) +- +- entry_attrs.update(adtrust_agents) +- entry_attrs.update(adtrust_controllers) +- + + @register() + class trustconfig_mod(LDAPUpdate): +@@ -1314,7 +1298,8 @@ class trustconfig_mod(LDAPUpdate): + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + self.obj._convert_groupdn(entry_attrs, options) +- self.obj.show_servroles(entry_attrs, **options) ++ self.api.Object.config.show_servroles_attributes( ++ entry_attrs, "AD trust agent", "AD trust controller", **options) + return dn + + +@@ -1333,7 +1318,8 @@ class trustconfig_show(LDAPRetrieve): + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): + self.obj._convert_groupdn(entry_attrs, options) +- self.obj.show_servroles(entry_attrs, **options) ++ self.api.Object.config.show_servroles_attributes( ++ entry_attrs, "AD trust agent", "AD trust controller", **options) + + return dn + +diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py +index d46aca821d2ec94a38dd7cc930f26038d5d80a90..d05a240c39bc1b47f1eba19cb893ab7408b35fa8 100644 +--- a/ipaserver/plugins/vault.py ++++ b/ipaserver/plugins/vault.py +@@ -997,9 +997,9 @@ class vaultconfig_show(Retrieve): + with self.api.Backend.kra.get_client() as kra_client: + transport_cert = kra_client.system_certs.get_transport_cert() + config = {'transport_cert': transport_cert.binary} +- config.update( +- self.api.Backend.serverroles.config_retrieve("KRA server") +- ) ++ ++ self.api.Object.config.show_servroles_attributes( ++ config, "KRA server", **options) + + return { + 'result': config, +-- +2.9.4 + diff --git a/SOURCES/0165-Add-an-attribute-reporting-client-PKINIT-capable-ser.patch b/SOURCES/0165-Add-an-attribute-reporting-client-PKINIT-capable-ser.patch new file mode 100644 index 0000000..4c9a12e --- /dev/null +++ b/SOURCES/0165-Add-an-attribute-reporting-client-PKINIT-capable-ser.patch @@ -0,0 +1,275 @@ +From 48f20550f175503cb226bac47c570a2ff3e79be1 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 12 May 2017 15:15:37 +0200 +Subject: [PATCH] Add an attribute reporting client PKINIT-capable servers + +A new multi-valued server attribute `pkinit_server` was added which +reports IPA masters that have PKINIT configuration usable by clients. + +The existing tests were modified to allow for testing the new attribute. + +https://pagure.io/freeipa/issue/6937 + +Reviewed-By: Jan Cholasta +Reviewed-By: Stanislav Laznicka +--- + ipaserver/servroles.py | 7 ++ + ipatests/test_ipaserver/test_serverroles.py | 109 +++++++++++++--------------- + 2 files changed, 59 insertions(+), 57 deletions(-) + +diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py +index 84fed1046b3b46dc9f5f8bbe6e03354725f1136c..f6e79338b9187aa741fe45b9fae42476cc65f724 100644 +--- a/ipaserver/servroles.py ++++ b/ipaserver/servroles.py +@@ -625,4 +625,11 @@ attribute_instances = ( + u"DNSSEC", + u"dnssecKeyMaster", + ), ++ ServerAttribute( ++ u"pkinit_server_server", ++ u"PKINIT enabled server", ++ u"ipa_master_server", ++ u"KDC", ++ u"pkinitEnabled" ++ ) + ) +diff --git a/ipatests/test_ipaserver/test_serverroles.py b/ipatests/test_ipaserver/test_serverroles.py +index e671272783d8d71c2ee56074459433b98b79dd0a..b373a4d32f60e5ef48bcf07ac29162516113e8a8 100644 +--- a/ipatests/test_ipaserver/test_serverroles.py ++++ b/ipatests/test_ipaserver/test_serverroles.py +@@ -58,7 +58,7 @@ _adtrust_agents = DN( + + + master_data = { +- 'ca-dns-dnssec-keymaster': { ++ 'ca-dns-dnssec-keymaster-pkinit-server': { + 'services': { + 'CA': { + 'enabled': True, +@@ -72,14 +72,19 @@ master_data = { + 'DNSSEC': { + 'enabled': True, + 'config': ['DNSSecKeyMaster'] ++ }, ++ 'KDC': { ++ 'enabled': True, ++ 'config': ['pkinitEnabled'] + } + }, + 'expected_roles': { + 'enabled': ['IPA master', 'CA server', 'DNS server'] + }, +- 'expected_attributes': {'DNS server': 'dnssec_key_master_server'} ++ 'expected_attributes': {'DNS server': 'dnssec_key_master_server', ++ 'IPA master': 'pkinit_server_server'} + }, +- 'ca-kra-renewal-master': { ++ 'ca-kra-renewal-master-pkinit-server': { + 'services': { + 'CA': { + 'enabled': True, +@@ -88,11 +93,16 @@ master_data = { + 'KRA': { + 'enabled': True, + }, ++ 'KDC': { ++ 'enabled': True, ++ 'config': ['pkinitEnabled'] ++ }, + }, + 'expected_roles': { + 'enabled': ['IPA master', 'CA server', 'KRA server'] + }, +- 'expected_attributes': {'CA server': 'ca_renewal_master_server'} ++ 'expected_attributes': {'CA server': 'ca_renewal_master_server', ++ 'IPA master': 'pkinit_server_server'} + }, + 'dns-trust-agent': { + 'services': { +@@ -234,7 +244,7 @@ class MockMasterTopology(object): + no_members=True, + raw=True)['result']} + +- self.existing_attributes = self._check_test_host_attributes() ++ self.original_dns_configs = self._remove_test_host_attrs() + + def iter_domain_data(self): + MasterData = namedtuple('MasterData', +@@ -287,7 +297,6 @@ class MockMasterTopology(object): + pass + + def _add_svc_entries(self, master_dn, svc_desc): +- self._add_ipamaster_services(master_dn) + for name in svc_desc: + svc_dn = self.get_service_dn(name, master_dn) + svc_mods = svc_desc[name] +@@ -298,6 +307,8 @@ class MockMasterTopology(object): + enabled=svc_mods['enabled'], + other_config=svc_mods.get('config', None))) + ++ self._add_ipamaster_services(master_dn) ++ + def _remove_svc_master_entries(self, master_dn): + try: + entries = self.ldap.connection.search_s( +@@ -317,7 +328,11 @@ class MockMasterTopology(object): + """ + for svc_name in self.ipamaster_services: + svc_dn = self.get_service_dn(svc_name, master_dn) +- self.ldap.add_entry(str(svc_dn), _make_service_entry_mods()) ++ try: ++ self.api.Backend.ldap2.get_entry(svc_dn) ++ except errors.NotFound: ++ self.ldap.add_entry( ++ str(svc_dn), _make_service_entry_mods()) + + def _add_members(self, dn, fqdn, member_attrs): + _entry, attrs = self.ldap.connection.search_s( +@@ -376,57 +391,36 @@ class MockMasterTopology(object): + except (ldap.NO_SUCH_OBJECT, ldap.NO_SUCH_ATTRIBUTE): + pass + +- def _check_test_host_attributes(self): +- existing_attributes = set() +- +- for service, value, attr_name in ( +- ('CA', 'caRenewalMaster', 'ca renewal master'), +- ('DNSSEC', 'DNSSecKeyMaster', 'dnssec key master')): ++ def _remove_test_host_attrs(self): ++ original_dns_configs = [] + +- svc_dn = DN(('cn', service), self.test_master_dn) ++ for attr_name in ( ++ 'caRenewalMaster', 'dnssecKeyMaster', 'pkinitEnabled'): + try: +- svc_entry = self.api.Backend.ldap2.get_entry(svc_dn) ++ svc_entry = self.api.Backend.ldap2.find_entry_by_attr( ++ 'ipaConfigString', attr_name, 'ipaConfigObject', ++ base_dn=self.test_master_dn) + except errors.NotFound: + continue + else: +- config_string_val = svc_entry.get('ipaConfigString', []) ++ original_dns_configs.append( ++ (svc_entry.dn, list(svc_entry.get('ipaConfigString', []))) ++ ) ++ svc_entry[u'ipaConfigString'].remove(attr_name) ++ self.api.Backend.ldap2.update_entry(svc_entry) + +- if value in config_string_val: +- existing_attributes.add(attr_name) +- +- return existing_attributes +- +- def _remove_ca_renewal_master(self): +- if 'ca renewal master' not in self.existing_attributes: +- return ++ return original_dns_configs + +- ca_dn = DN(('cn', 'CA'), self.test_master_dn) +- ca_entry = self.api.Backend.ldap2.get_entry(ca_dn) +- +- config_string_val = ca_entry.get('ipaConfigString', []) +- try: +- config_string_val.remove('caRenewalMaster') +- except KeyError: +- return +- +- ca_entry.update({'ipaConfigString': config_string_val}) +- self.api.Backend.ldap2.update_entry(ca_entry) +- +- def _restore_ca_renewal_master(self): +- if 'ca renewal master' not in self.existing_attributes: +- return +- +- ca_dn = DN(('cn', 'CA'), self.test_master_dn) +- ca_entry = self.api.Backend.ldap2.get_entry(ca_dn) +- +- config_string_val = ca_entry.get('ipaConfigString', []) +- config_string_val.append('caRenewalMaster') +- +- ca_entry.update({'ipaConfigString': config_string_val}) +- self.api.Backend.ldap2.update_entry(ca_entry) ++ def _restore_test_host_attrs(self): ++ for dn, config in self.original_dns_configs: ++ try: ++ svc_entry = self.api.Backend.ldap2.get_entry(dn) ++ svc_entry['ipaConfigString'] = config ++ self.api.Backend.ldap2.update_entry(svc_entry) ++ except (errors.NotFound, errors.EmptyModlist): ++ continue + + def setup_data(self): +- self._remove_ca_renewal_master() + for master_data in self.iter_domain_data(): + # create host + self._add_host_entry(master_data.fqdn) +@@ -449,7 +443,6 @@ class MockMasterTopology(object): + ) + + def teardown_data(self): +- self._restore_ca_renewal_master() + for master_data in self.iter_domain_data(): + # first remove the master entries and service containers + self._remove_svc_master_entries(master_data.dn) +@@ -466,6 +459,8 @@ class MockMasterTopology(object): + # finally remove host entry + self._del_host_entry(master_data.fqdn) + ++ self._restore_test_host_attrs() ++ + + @pytest.fixture(scope='module') + def mock_api(request): +@@ -665,14 +660,14 @@ class TestServerRoleStatusRetrieval(object): + + def test_unknown_role_status_raises_notfound(self, mock_api, mock_masters): + unknown_role = 'IAP maestr' +- fqdn = mock_masters.get_fqdn('ca-dns-dnssec-keymaster') ++ fqdn = mock_masters.get_fqdn('ca-dns-dnssec-keymaster-pkinit-server') + with pytest.raises(errors.NotFound): + mock_api.Backend.serverroles.server_role_retrieve( + fqdn, unknown_role) + + def test_no_servrole_queries_all_roles_on_server(self, mock_api, + mock_masters): +- master_name = 'ca-dns-dnssec-keymaster' ++ master_name = 'ca-dns-dnssec-keymaster-pkinit-server' + enabled_roles = master_data[master_name]['expected_roles']['enabled'] + result = self.find_role(None, mock_api, mock_masters, + master=master_name) +@@ -688,7 +683,7 @@ class TestServerRoleStatusRetrieval(object): + invalid_substr = 'fwfgbb' + + assert (not self.find_role(invalid_substr, mock_api, mock_masters, +- 'ca-dns-dnssec-keymaster')) ++ 'ca-dns-dnssec-keymaster-pkinit-server')) + + + class TestServerAttributes(object): +@@ -706,7 +701,7 @@ class TestServerAttributes(object): + actual_attr_masters = self.config_retrieve( + assoc_role, mock_api)[attr_name] + +- assert actual_attr_masters == [fqdn] ++ assert fqdn in actual_attr_masters + + def test_set_attribute_on_the_same_provider_raises_emptymodlist( + self, mock_api, mock_masters): +@@ -744,10 +739,10 @@ class TestServerAttributes(object): + original_renewal_master = self.config_retrieve( + role_name, mock_api)[attr_name] + +- other_ca_server = mock_masters.get_fqdn('trust-controller-ca') ++ other_ca_server = [mock_masters.get_fqdn('trust-controller-ca')] + + for host in (other_ca_server, original_renewal_master): +- self.config_update(mock_api, **{attr_name: [host]}) ++ self.config_update(mock_api, **{attr_name: host}) + + assert ( +- self.config_retrieve(role_name, mock_api)[attr_name] == [host]) ++ self.config_retrieve(role_name, mock_api)[attr_name] == host) +-- +2.9.4 + diff --git a/SOURCES/0166-Add-the-list-of-PKINIT-servers-as-a-virtual-attribut.patch b/SOURCES/0166-Add-the-list-of-PKINIT-servers-as-a-virtual-attribut.patch new file mode 100644 index 0000000..486d553 --- /dev/null +++ b/SOURCES/0166-Add-the-list-of-PKINIT-servers-as-a-virtual-attribut.patch @@ -0,0 +1,34 @@ +From 095e8387572432749cf4231f7af67b9d5b597440 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 12 May 2017 15:27:36 +0200 +Subject: [PATCH] Add the list of PKINIT servers as a virtual attribute to + global config + +https://pagure.io/freeipa/issue/6937 + +Reviewed-By: Jan Cholasta +Reviewed-By: Stanislav Laznicka +--- + ipaserver/plugins/config.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py +index c88cb99b47ac746f8e18cf189708d457b535416a..df6bd466afa937be96722a570385fb5b3419830d 100644 +--- a/ipaserver/plugins/config.py ++++ b/ipaserver/plugins/config.py +@@ -256,6 +256,12 @@ class config(LDAPObject): + flags={'virtual_attribute', 'no_create'} + ), + Str( ++ 'pkinit_server_server*', ++ label=_('IPA master capable of PKINIT'), ++ doc=_('IPA master which can process PKINIT requests'), ++ flags={'virtual_attribute', 'no_create', 'no_update'} ++ ), ++ Str( + 'ipadomainresolutionorder?', + cli_name='domain_resolution_order', + label=_('Domain resolution order'), +-- +2.9.4 + diff --git a/SOURCES/0167-Add-pkinit-status-command.patch b/SOURCES/0167-Add-pkinit-status-command.patch new file mode 100644 index 0000000..c40c1ef --- /dev/null +++ b/SOURCES/0167-Add-pkinit-status-command.patch @@ -0,0 +1,201 @@ +From 5012843d350b7a39b78e4eb7cab6cff98cae59d5 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 12 May 2017 17:25:30 +0200 +Subject: [PATCH] Add `pkinit-status` command + +This command is a more streamlined reporting tool for PKINIT feature +status in the FreeIPA topology. It prints out whether PKINIT is enabled +or disabled on individual masters in a topology. If a`--server` is +specified, it reports status for an individual server. If `--status` is +specified, it searches for all servers that have PKINIT enabled or +disabled. + +https://pagure.io/freeipa/issue/6937 + +Reviewed-By: Jan Cholasta +Reviewed-By: Stanislav Laznicka +--- + API.txt | 15 ++++++ + VERSION.m4 | 4 +- + ipaserver/plugins/pkinit.py | 109 +++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 125 insertions(+), 3 deletions(-) + +diff --git a/API.txt b/API.txt +index 4e6754afe2deab5c963577f1e1363f1123a31a86..6511ad8d1cb4dc9079628fc058312f31aaec624d 100644 +--- a/API.txt ++++ b/API.txt +@@ -3736,6 +3736,20 @@ command: ping/1 + args: 0,1,1 + option: Str('version?') + output: Output('summary', type=[, ]) ++command: pkinit_status/1 ++args: 1,7,4 ++arg: Str('criteria?') ++option: Flag('all', autofill=True, cli_name='all', default=False) ++option: Flag('raw', autofill=True, cli_name='raw', default=False) ++option: Str('server_server?', autofill=False, cli_name='server') ++option: Int('sizelimit?', autofill=False) ++option: StrEnum('status?', autofill=False, cli_name='status', values=[u'enabled', u'disabled']) ++option: Int('timelimit?', autofill=False) ++option: Str('version?') ++output: Output('count', type=[]) ++output: ListOfEntries('result') ++output: Output('summary', type=[, ]) ++output: Output('truncated', type=[]) + command: plugins/1 + args: 0,3,3 + option: Flag('all', autofill=True, cli_name='all', default=True) +@@ -6798,6 +6812,7 @@ default: permission_remove_member/1 + default: permission_show/1 + default: ping/1 + default: pkinit/1 ++default: pkinit_status/1 + default: plugins/1 + default: privilege/1 + default: privilege_add/1 +diff --git a/VERSION.m4 b/VERSION.m4 +index e10ee3cad6f5a6e023ea3cb9ec20591b7caae0bd..8aa3ef03f352cd176579c5d5848ed9550f22105d 100644 +--- a/VERSION.m4 ++++ b/VERSION.m4 +@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000) + # # + ######################################################## + define(IPA_API_VERSION_MAJOR, 2) +-define(IPA_API_VERSION_MINOR, 226) +-# Last change: Remove the pkinit-anonymous command ++define(IPA_API_VERSION_MINOR, 227) ++# Last change: Add `pkinit-status` command + + + ######################################################## +diff --git a/ipaserver/plugins/pkinit.py b/ipaserver/plugins/pkinit.py +index e49b31091d676865fa7f023be8edc3cdef9d6d2c..970f955c54bc489765d2565255e8805138a35307 100644 +--- a/ipaserver/plugins/pkinit.py ++++ b/ipaserver/plugins/pkinit.py +@@ -3,11 +3,33 @@ + # + + from ipalib import Object +-from ipalib import _ ++from ipalib import _, ngettext ++from ipalib.crud import Search ++from ipalib.parameters import Int, Str, StrEnum + from ipalib.plugable import Registry + + register = Registry() + ++__doc__ = _(""" ++Kerberos PKINIT feature status reporting tools. ++ ++Report IPA masters on which Kerberos PKINIT is enabled or disabled ++ ++EXAMPLES: ++ List PKINIT status on all masters: ++ ipa pkinit-status ++ ++ Check PKINIT status on `ipa.example.com`: ++ ipa pkinit-status --server ipa.example.com ++ ++ List all IPA masters with disabled PKINIT: ++ ipa pkinit-status --status='disabled' ++ ++For more info about PKINIT support see: ++ ++https://www.freeipa.org/page/V4/Kerberos_PKINIT ++""") ++ + + @register() + class pkinit(Object): +@@ -17,3 +39,88 @@ class pkinit(Object): + object_name = _('pkinit') + + label = _('PKINIT') ++ ++ takes_params = ( ++ Str( ++ 'server_server?', ++ cli_name='server', ++ label=_('Server name'), ++ doc=_('IPA server hostname'), ++ ), ++ StrEnum( ++ 'status?', ++ cli_name='status', ++ label=_('PKINIT status'), ++ doc=_('Whether PKINIT is enabled or disabled'), ++ values=(u'enabled', u'disabled'), ++ flags={'virtual_attribute', 'no_create', 'no_update'} ++ ) ++ ) ++ ++ ++@register() ++class pkinit_status(Search): ++ __doc__ = _('Report PKINIT status on the IPA masters') ++ ++ msg_summary = ngettext('%(count)s server matched', ++ '%(count)s servers matched', 0) ++ ++ takes_options = Search.takes_options + ( ++ Int( ++ 'timelimit?', ++ label=_('Time Limit'), ++ doc=_('Time limit of search in seconds (0 is unlimited)'), ++ flags=['no_display'], ++ minvalue=0, ++ autofill=False, ++ ), ++ Int( ++ 'sizelimit?', ++ label=_('Size Limit'), ++ doc=_('Maximum number of entries returned (0 is unlimited)'), ++ flags=['no_display'], ++ minvalue=0, ++ autofill=False, ++ ), ++ ) ++ ++ def get_pkinit_status(self, server, status): ++ backend = self.api.Backend.serverroles ++ ipa_master_config = backend.config_retrieve("IPA master") ++ ++ if server is not None: ++ servers = [server] ++ else: ++ servers = ipa_master_config['ipa_master_server'] ++ ++ pkinit_servers = ipa_master_config['pkinit_server_server'] ++ ++ for s in servers: ++ pkinit_status = { ++ u'server_server': s, ++ u'status': ( ++ u'enabled' if s in pkinit_servers else u'disabled' ++ ) ++ } ++ if status is not None and pkinit_status[u'status'] != status: ++ continue ++ ++ yield pkinit_status ++ ++ def execute(self, *keys, **options): ++ if keys: ++ return dict( ++ result=[], ++ count=0, ++ truncated=False ++ ) ++ ++ server = options.get('server_server', None) ++ status = options.get('status', None) ++ ++ if server is not None: ++ self.api.Object.server_role.ensure_master_exists(server) ++ ++ result = sorted(self.get_pkinit_status(server, status)) ++ ++ return dict(result=result, count=len(result), truncated=False) +-- +2.9.4 + diff --git a/SOURCES/0168-test_serverroles-Get-rid-of-MockLDAP-and-use-ldap2-i.patch b/SOURCES/0168-test_serverroles-Get-rid-of-MockLDAP-and-use-ldap2-i.patch new file mode 100644 index 0000000..5347e9a --- /dev/null +++ b/SOURCES/0168-test_serverroles-Get-rid-of-MockLDAP-and-use-ldap2-i.patch @@ -0,0 +1,238 @@ +From e0f1082c7664235a298bbb1d574549917a00e8a0 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Thu, 18 May 2017 16:20:13 +0200 +Subject: [PATCH] test_serverroles: Get rid of MockLDAP and use ldap2 instead + +The test fixture haphazardly intermixed MockLDAP and ldap2 calls in +setup and teardown code, greatly hampering extension of the code and +also porting efforts to Python 3. Get rid of MockLDAP and use ldap2 for +all LDAP operations. + +https://pagure.io/freeipa/issue/6937 + +Reviewed-By: Jan Cholasta +Reviewed-By: Stanislav Laznicka +--- + ipatests/test_ipaserver/test_serverroles.py | 109 +++++++++++++--------------- + 1 file changed, 51 insertions(+), 58 deletions(-) + +diff --git a/ipatests/test_ipaserver/test_serverroles.py b/ipatests/test_ipaserver/test_serverroles.py +index b373a4d32f60e5ef48bcf07ac29162516113e8a8..985c750b64f109e0a83686f31ddb3b8d4171072d 100644 +--- a/ipatests/test_ipaserver/test_serverroles.py ++++ b/ipatests/test_ipaserver/test_serverroles.py +@@ -14,40 +14,39 @@ import pytest + from ipaplatform.paths import paths + from ipalib import api, create_api, errors + from ipapython.dn import DN +-from ipatests.util import MockLDAP + + +-def _make_service_entry_mods(enabled=True, other_config=None): ++def _make_service_entry(ldap_backend, dn, enabled=True, other_config=None): + mods = { +- b'objectClass': [b'top', b'nsContainer', b'ipaConfigObject'], ++ 'objectClass': ['top', 'nsContainer', 'ipaConfigObject'], + } + if enabled: +- mods.update({b'ipaConfigString': [b'enabledService']}) ++ mods.update({'ipaConfigString': ['enabledService']}) + + if other_config is not None: +- mods.setdefault(b'ipaConfigString', []) +- mods[b'ipaConfigString'].extend(other_config) ++ mods.setdefault('ipaConfigString', []) ++ mods['ipaConfigString'].extend(other_config) + +- return mods ++ return ldap_backend.make_entry(dn, **mods) + + +-def _make_master_entry_mods(ca=False): ++def _make_master_entry(ldap_backend, dn, ca=False): + mods = { +- b'objectClass': [ +- b'top', +- b'nsContainer', +- b'ipaReplTopoManagedServer', +- b'ipaSupportedDomainLevelConfig', +- b'ipaConfigObject', ++ 'objectClass': [ ++ 'top', ++ 'nsContainer', ++ 'ipaReplTopoManagedServer', ++ 'ipaSupportedDomainLevelConfig', ++ 'ipaConfigObject', + ], +- b'ipaMaxDomainLevel': [b'1'], +- b'ipaMinDomainLevel': [b'0'], +- b'ipaReplTopoManagedsuffix': [str(api.env.basedn)] ++ 'ipaMaxDomainLevel': ['1'], ++ 'ipaMinDomainLevel': ['0'], ++ 'ipaReplTopoManagedsuffix': [str(api.env.basedn)] + } + if ca: +- mods[b'ipaReplTopoManagedsuffix'].append(b'o=ipaca') ++ mods['ipaReplTopoManagedsuffix'].append('o=ipaca') + +- return mods ++ return ldap_backend.make_entry(dn, **mods) + + _adtrust_agents = DN( + ('cn', 'adtrust agents'), +@@ -235,7 +234,7 @@ class MockMasterTopology(object): + ('cn', self.api.env.host), self.api.env.container_masters, + self.api.env.basedn) + +- self.ldap = MockLDAP() ++ self.ldap = self.api.Backend.ldap2 + + self.existing_masters = { + m['cn'][0] for m in self.api.Command.server_find( +@@ -302,8 +301,9 @@ class MockMasterTopology(object): + svc_mods = svc_desc[name] + + self.ldap.add_entry( +- str(svc_dn), +- _make_service_entry_mods( ++ _make_service_entry( ++ self.ldap, ++ svc_dn, + enabled=svc_mods['enabled'], + other_config=svc_mods.get('config', None))) + +@@ -311,16 +311,16 @@ class MockMasterTopology(object): + + def _remove_svc_master_entries(self, master_dn): + try: +- entries = self.ldap.connection.search_s( +- str(master_dn), ldap.SCOPE_SUBTREE ++ entries = self.ldap.get_entries( ++ master_dn, ldap.SCOPE_SUBTREE + ) +- except ldap.NO_SUCH_OBJECT: ++ except errors.NotFound: + return + + if entries: +- entries.sort(key=lambda x: len(x[0]), reverse=True) +- for entry_dn, _attrs in entries: +- self.ldap.del_entry(str(entry_dn)) ++ entries.sort(key=lambda x: len(x.dn), reverse=True) ++ for entry in entries: ++ self.ldap.delete_entry(entry) + + def _add_ipamaster_services(self, master_dn): + """ +@@ -329,19 +329,14 @@ class MockMasterTopology(object): + for svc_name in self.ipamaster_services: + svc_dn = self.get_service_dn(svc_name, master_dn) + try: +- self.api.Backend.ldap2.get_entry(svc_dn) ++ self.ldap.get_entry(svc_dn) + except errors.NotFound: +- self.ldap.add_entry( +- str(svc_dn), _make_service_entry_mods()) ++ self.ldap.add_entry(_make_service_entry(self.ldap, svc_dn)) + + def _add_members(self, dn, fqdn, member_attrs): +- _entry, attrs = self.ldap.connection.search_s( +- str(dn), ldap.SCOPE_SUBTREE)[0] +- mods = [] +- value = attrs.get('member', []) +- mod_op = ldap.MOD_REPLACE +- if not value: +- mod_op = ldap.MOD_ADD ++ entry_attrs = self.ldap.get_entry(dn) ++ ++ value = entry_attrs.get('member', []) + + for a in member_attrs: + +@@ -352,20 +347,18 @@ class MockMasterTopology(object): + result = self._add_service_entry(a, fqdn)['result'] + value.append(str(result['dn'])) + +- mods.append( +- (mod_op, 'member', value) +- ) +- +- self.ldap.connection.modify_s(str(dn), mods) ++ entry_attrs['member'] = value ++ self.ldap.update_entry(entry_attrs) + + def _remove_members(self, dn, fqdn, member_attrs): +- _entry, attrs = self.ldap.connection.search_s( +- str(dn), ldap.SCOPE_SUBTREE)[0] +- mods = [] ++ entry_attrs = self.ldap.get_entry(dn) ++ ++ value = set(entry_attrs.get('member', [])) ++ ++ if not value: ++ return ++ + for a in member_attrs: +- value = set(attrs.get('member', [])) +- if not value: +- continue + + if a == 'host': + try: +@@ -382,13 +375,11 @@ class MockMasterTopology(object): + pass + self._del_service_entry(a, fqdn) + +- mods.append( +- (ldap.MOD_REPLACE, 'member', list(value)) +- ) ++ entry_attrs['member'] = list(value) + + try: +- self.ldap.connection.modify_s(str(dn), mods) +- except (ldap.NO_SUCH_OBJECT, ldap.NO_SUCH_ATTRIBUTE): ++ self.ldap.update_entry(entry_attrs) ++ except (errors.NotFound, errors.EmptyModlist): + pass + + def _remove_test_host_attrs(self): +@@ -397,7 +388,7 @@ class MockMasterTopology(object): + for attr_name in ( + 'caRenewalMaster', 'dnssecKeyMaster', 'pkinitEnabled'): + try: +- svc_entry = self.api.Backend.ldap2.find_entry_by_attr( ++ svc_entry = self.ldap.find_entry_by_attr( + 'ipaConfigString', attr_name, 'ipaConfigObject', + base_dn=self.test_master_dn) + except errors.NotFound: +@@ -407,7 +398,7 @@ class MockMasterTopology(object): + (svc_entry.dn, list(svc_entry.get('ipaConfigString', []))) + ) + svc_entry[u'ipaConfigString'].remove(attr_name) +- self.api.Backend.ldap2.update_entry(svc_entry) ++ self.ldap.update_entry(svc_entry) + + return original_dns_configs + +@@ -416,7 +407,7 @@ class MockMasterTopology(object): + try: + svc_entry = self.api.Backend.ldap2.get_entry(dn) + svc_entry['ipaConfigString'] = config +- self.api.Backend.ldap2.update_entry(svc_entry) ++ self.ldap.update_entry(svc_entry) + except (errors.NotFound, errors.EmptyModlist): + continue + +@@ -427,7 +418,9 @@ class MockMasterTopology(object): + + # create master + self.ldap.add_entry( +- str(master_data.dn), _make_master_entry_mods( ++ _make_master_entry( ++ self.ldap, ++ master_data.dn, + ca='CA' in master_data.services)) + + # now add service entries +-- +2.9.4 + diff --git a/SOURCES/0169-only-stop-disable-simple-service-if-it-is-installed.patch b/SOURCES/0169-only-stop-disable-simple-service-if-it-is-installed.patch new file mode 100644 index 0000000..46467f9 --- /dev/null +++ b/SOURCES/0169-only-stop-disable-simple-service-if-it-is-installed.patch @@ -0,0 +1,54 @@ +From 2a20fbe381dd8a740e05833dd8d2b5440ce84812 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Tue, 23 May 2017 16:35:01 +0200 +Subject: [PATCH] only stop/disable simple service if it is installed + +The SimpleServiceInstance uninstaller assument that the service to +uninstall was always present on the system. This may not be valid in +some cases (e.g. containerized deployments) and thus we need to change +the service state only when we know that the unit file exists. + +https://pagure.io/freeipa/issue/6977 + +Reviewed-By: Martin Basti +--- + ipaserver/install/service.py | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py +index 1aa49ed25b25366afd2bb17073b4b214c231d54b..0523e914aa7debf6aaa82ddcce9b7b26c1833cd3 100644 +--- a/ipaserver/install/service.py ++++ b/ipaserver/install/service.py +@@ -674,18 +674,21 @@ class SimpleServiceInstance(Service): + else: + self.ldap_enable(self.gensvc_name, self.fqdn, None, self.suffix) + ++ def is_installed(self): ++ return self.service.is_installed() ++ + def uninstall(self): + if self.is_configured(): + self.print_msg("Unconfiguring %s" % self.service_name) + +- self.stop() +- self.disable() +- + running = self.restore_state("running") + enabled = self.restore_state("enabled") + +- # restore the original state of service +- if running: +- self.start() +- if enabled: +- self.enable() ++ if self.is_installed(): ++ self.stop() ++ self.disable() ++ ++ if running: ++ self.start() ++ if enabled: ++ self.enable() +-- +2.9.4 + diff --git a/SOURCES/0170-Fix-index-definition-for-ipaAnchorUUID.patch b/SOURCES/0170-Fix-index-definition-for-ipaAnchorUUID.patch new file mode 100644 index 0000000..33d73e3 --- /dev/null +++ b/SOURCES/0170-Fix-index-definition-for-ipaAnchorUUID.patch @@ -0,0 +1,33 @@ +From de0ed1b49c84edebb65f31ff18e0b4bb4e0d794c Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Wed, 24 May 2017 18:00:14 +0300 +Subject: [PATCH] Fix index definition for ipaAnchorUUID + +Fixes https://pagure.io/freeipa/issue/6975 + +Reviewed-By: Martin Basti +--- + install/updates/20-idoverride_index.update | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/install/updates/20-idoverride_index.update b/install/updates/20-idoverride_index.update +index bfc9c6e235fb7a4300fd755e53fc2154e01573a2..63d622f1f0fb7d6e49df7fde65a33bc21ab0c4a0 100644 +--- a/install/updates/20-idoverride_index.update ++++ b/install/updates/20-idoverride_index.update +@@ -11,9 +11,12 @@ only: nsIndexType: eq + only: nsIndexType: pres + + dn: cn=ipaAnchorUUID,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config +-default:cn: ipaOriginalUid ++default:cn: ipaAnchorUUID + default:ObjectClass: top + default:ObjectClass: nsIndex + default:nsSystemIndex: false + only: nsIndexType: eq + only: nsIndexType: pres ++ ++dn: cn=ipaAnchorUUID,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config ++remove:cn: ipaOriginalUid +-- +2.9.4 + diff --git a/SOURCES/0171-httpinstance-wait-until-the-service-entry-is-replica.patch b/SOURCES/0171-httpinstance-wait-until-the-service-entry-is-replica.patch new file mode 100644 index 0000000..068834e --- /dev/null +++ b/SOURCES/0171-httpinstance-wait-until-the-service-entry-is-replica.patch @@ -0,0 +1,126 @@ +From 07469b2cc7bd1478836a1c755b301dbf9234d61a Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 22 May 2017 08:15:14 +0000 +Subject: [PATCH] httpinstance: wait until the service entry is replicated + +Wait until the local HTTP service entry is replicated to the remote master +before requesting the server certificate. + +This prevents a replication conflict between the service entry added +locally and service entry added remotely when requesting the certificate. + +https://pagure.io/freeipa/issue/6867 + +Reviewed-By: Martin Babinsky +Reviewed-By: Martin Basti +--- + ipaserver/install/httpinstance.py | 29 +++++++++++++++++++++++++++-- + ipaserver/install/server/install.py | 4 ++-- + ipaserver/install/server/replicainstall.py | 5 +++-- + 3 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index c76a1a4e484c5777ced92761916c1c586e8b2d5d..12fdddccc26b0c1132bcdca7fe2249a85997892e 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -32,9 +32,11 @@ import six + from augeas import Augeas + + from ipalib.install import certmonger ++from ipapython import ipaldap + from ipapython.certdb import (IPA_CA_TRUST_FLAGS, + EXTERNAL_CA_TRUST_FLAGS, + TRUSTED_PEER_TRUST_FLAGS) ++from ipaserver.install import replication + from ipaserver.install import service + from ipaserver.install import certs + from ipaserver.install import installutils +@@ -127,12 +129,15 @@ class HTTPInstance(service.Service): + + subject_base = ipautil.dn_attribute_property('_subject_base') + +- def create_instance(self, realm, fqdn, domain_name, pkcs12_info=None, ++ def create_instance(self, realm, fqdn, domain_name, dm_password=None, ++ pkcs12_info=None, + subject_base=None, auto_redirect=True, ca_file=None, +- ca_is_configured=None, promote=False): ++ ca_is_configured=None, promote=False, ++ master_fqdn=None): + self.fqdn = fqdn + self.realm = realm + self.domain = domain_name ++ self.dm_password = dm_password + self.suffix = ipautil.realm_to_suffix(self.realm) + self.pkcs12_info = pkcs12_info + self.dercert = None +@@ -148,6 +153,7 @@ class HTTPInstance(service.Service): + if ca_is_configured is not None: + self.ca_is_configured = ca_is_configured + self.promote = promote ++ self.master_fqdn = master_fqdn + + self.step("stopping httpd", self.__stop) + self.step("setting mod_nss port to 443", self.__set_mod_nss_port) +@@ -577,3 +583,22 @@ class HTTPInstance(service.Service): + db = certs.CertDB(self.realm, nssdir=paths.HTTPD_ALIAS_DIR) + db.track_server_cert(self.cert_nickname, self.principal, + db.passwd_fname, 'restart_httpd') ++ ++ def request_service_keytab(self): ++ super(HTTPInstance, self).request_service_keytab() ++ ++ if self.master_fqdn is not None: ++ service_dn = DN(('krbprincipalname', self.principal), ++ api.env.container_service, ++ self.suffix) ++ ++ ldap_uri = ipaldap.get_ldap_uri(self.master_fqdn) ++ with ipaldap.LDAPClient(ldap_uri, ++ start_tls=not self.promote, ++ cacert=paths.IPA_CA_CRT) as remote_ldap: ++ if self.promote: ++ remote_ldap.gssapi_bind() ++ else: ++ remote_ldap.simple_bind(ipaldap.DIRMAN_DN, ++ self.dm_password) ++ replication.wait_for_entry(remote_ldap, service_dn, timeout=60) +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 03380b8d0e9150224b014a1a174d7ea81ccdcf00..9dcf903f4582740f007c049fae3ec247ddf52aef 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -830,13 +830,13 @@ def install(installer): + http = httpinstance.HTTPInstance(fstore) + if options.http_cert_files: + http.create_instance( +- realm_name, host_name, domain_name, ++ realm_name, host_name, domain_name, dm_password, + pkcs12_info=http_pkcs12_info, subject_base=options.subject_base, + auto_redirect=not options.no_ui_redirect, + ca_is_configured=setup_ca) + else: + http.create_instance( +- realm_name, host_name, domain_name, ++ realm_name, host_name, domain_name, dm_password, + subject_base=options.subject_base, + auto_redirect=not options.no_ui_redirect, + ca_is_configured=setup_ca) +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index b30133ffa22d410452ae04624d49db209175bed9..20eaf98397101b49c751c325afc0591e0babcc18 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -163,9 +163,10 @@ def install_http(config, auto_redirect, ca_is_configured, ca_file, + http = httpinstance.HTTPInstance() + http.create_instance( + config.realm_name, config.host_name, config.domain_name, +- pkcs12_info, auto_redirect=auto_redirect, ca_file=ca_file, ++ config.dirman_password, pkcs12_info, ++ auto_redirect=auto_redirect, ca_file=ca_file, + ca_is_configured=ca_is_configured, promote=promote, +- subject_base=config.subject_base) ++ subject_base=config.subject_base, master_fqdn=config.master_host_name) + + return http + +-- +2.9.4 + diff --git a/SOURCES/0172-kdc.key-should-not-be-visible-to-all.patch b/SOURCES/0172-kdc.key-should-not-be-visible-to-all.patch new file mode 100644 index 0000000..abb5411 --- /dev/null +++ b/SOURCES/0172-kdc.key-should-not-be-visible-to-all.patch @@ -0,0 +1,34 @@ +From f6cac267e99c6f47ca6b78568182a82d48a6bb4c Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 31 May 2017 14:14:34 +0200 +Subject: [PATCH] kdc.key should not be visible to all + +While the world certainly is interested in our privates, we +should not just go ahead and show it to them. + +https://pagure.io/freeipa/issue/6973 + +Reviewed-By: Martin Babinsky +Reviewed-By: Alexander Bokovoy +--- + ipalib/install/certmonger.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py +index ad031a738f4397d230ed131bde6ac7ddb7ef6fdb..c286996ee2318e241b4af190d1a01f42e28aa9f3 100644 +--- a/ipalib/install/certmonger.py ++++ b/ipalib/install/certmonger.py +@@ -370,8 +370,8 @@ def request_cert( + request_parameters['cert-postsave-command'] = post_command + + if perms: +- request_parameters['key-perms'] = perms[0] +- request_parameters['cert-perms'] = perms[1] ++ request_parameters['cert-perms'] = perms[0] ++ request_parameters['key-perms'] = perms[1] + + result = cm.obj_if.add_request(request_parameters) + try: +-- +2.9.4 + diff --git a/SOURCES/0173-ipa-kdb-reload-certificate-mapping-rules-periodicall.patch b/SOURCES/0173-ipa-kdb-reload-certificate-mapping-rules-periodicall.patch new file mode 100644 index 0000000..659dcea --- /dev/null +++ b/SOURCES/0173-ipa-kdb-reload-certificate-mapping-rules-periodicall.patch @@ -0,0 +1,221 @@ +From 3a946e38a911fdfb1575135c41128f41ab44324c Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 26 May 2017 18:19:48 +0200 +Subject: [PATCH] ipa-kdb: reload certificate mapping rules periodically + +With this patch the certificate mapping rules are reloaded every 5 +minutes. + +Resolves https://pagure.io/freeipa/issue/6963 + +Reviewed-By: David Kupka +--- + daemons/ipa-kdb/ipa_kdb_certauth.c | 153 ++++++++++++++++++++----------------- + 1 file changed, 81 insertions(+), 72 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_certauth.c b/daemons/ipa-kdb/ipa_kdb_certauth.c +index a53a2ce4e7ceb06ec8de117cdbca2666fdb5a97a..dbe7a0443700784d2b8dbb1fb9196d6249e5522a 100644 +--- a/daemons/ipa-kdb/ipa_kdb_certauth.c ++++ b/daemons/ipa-kdb/ipa_kdb_certauth.c +@@ -58,6 +58,8 @@ + #define CERTMAP_FILTER "(&("OBJECTCLASS"="IPA_OC_CERTMAP_RULE")" \ + "("IPA_ENABLED_FLAG"="IPA_TRUE_VALUE"))" + ++#define DEFAULT_CERTMAP_LIFETIME 300 ++ + #ifndef discard_const + #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) + #endif +@@ -67,6 +69,7 @@ struct krb5_certauth_moddata_st { + char *local_domain; + struct sss_certmap_ctx *sss_certmap_ctx; + struct ipadb_context *ipactx; ++ time_t valid_until; + }; + + void ipa_certmap_debug(void *private, +@@ -133,95 +136,101 @@ static krb5_error_code ipa_get_init_data(krb5_context kcontext, + } + + if (ipactx->certauth_moddata == NULL) { +- ret = asprintf(&basedn, "cn=certmap,%s", ipactx->base); +- if (ret == -1) { +- return ENOMEM; +- } ++ ipactx->certauth_moddata = moddata_out; + +- kerr = ipadb_simple_search(ipactx,basedn, LDAP_SCOPE_SUBTREE, +- CERTMAP_FILTER, discard_const(certmap_attrs), +- &result); +- if (kerr != 0 && kerr != KRB5_KDB_NOENTRY) { +- goto done; ++ if (ipactx->realm != NULL) { ++ ipactx->certauth_moddata->local_domain = strdup(ipactx->realm); ++ if (ipactx->certauth_moddata->local_domain == NULL) { ++ free(ipactx->certauth_moddata); ++ ipactx->certauth_moddata = NULL; ++ ret = ENOMEM; ++ goto done; ++ } + } + +- ret = sss_certmap_init(NULL, ipa_certmap_debug, NULL, &ctx); ++ ipactx->certauth_moddata->ipactx = ipactx; ++ ++ } ++ ++ ret = asprintf(&basedn, "cn=certmap,%s", ipactx->base); ++ if (ret == -1) { ++ return ENOMEM; ++ } ++ ++ kerr = ipadb_simple_search(ipactx,basedn, LDAP_SCOPE_SUBTREE, ++ CERTMAP_FILTER, discard_const(certmap_attrs), ++ &result); ++ if (kerr != 0 && kerr != KRB5_KDB_NOENTRY) { ++ goto done; ++ } ++ ++ ret = sss_certmap_init(NULL, ipa_certmap_debug, NULL, &ctx); ++ if (ret != 0) { ++ return ret; ++ } ++ ++ if (kerr == KRB5_KDB_NOENTRY) { ++ ret = sss_certmap_add_rule(ctx, SSS_CERTMAP_MIN_PRIO, ++ NULL, NULL, NULL); + if (ret != 0) { +- return ret; ++ goto done; + } +- +- if (kerr == KRB5_KDB_NOENTRY) { +- ret = sss_certmap_add_rule(ctx, SSS_CERTMAP_MIN_PRIO, +- NULL, NULL, NULL); +- if (ret != 0) { ++ } else { ++ lc = ipactx->lcontext; ++ ++ for (le = ldap_first_entry(lc, result); le; ++ le = ldap_next_entry(lc, le)) { ++ prio = SSS_CERTMAP_MIN_PRIO; ++ ret = ipadb_ldap_attr_to_uint32(lc, le, IPA_CERTMAP_PRIORITY, ++ &prio); ++ if (ret != 0 && ret != ENOENT) { + goto done; + } +- } else { +- lc = ipactx->lcontext; +- +- for (le = ldap_first_entry(lc, result); le; +- le = ldap_next_entry(lc, le)) { +- prio = SSS_CERTMAP_MIN_PRIO; +- ret = ipadb_ldap_attr_to_uint32(lc, le, IPA_CERTMAP_PRIORITY, +- &prio); +- if (ret != 0 && ret != ENOENT) { +- goto done; +- } +- +- free(map_rule); +- map_rule = NULL; +- ret = ipadb_ldap_attr_to_str(lc, le, IPA_CERTMAP_MAPRULE, +- &map_rule); +- if (ret != 0 && ret != ENOENT) { +- goto done; +- } + +- free(match_rule); +- match_rule = NULL; +- ret = ipadb_ldap_attr_to_str(lc, le, IPA_CERTMAP_MATCHRULE, +- &match_rule); +- if (ret != 0 && ret != ENOENT) { +- goto done; +- } ++ free(map_rule); ++ map_rule = NULL; ++ ret = ipadb_ldap_attr_to_str(lc, le, IPA_CERTMAP_MAPRULE, ++ &map_rule); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; ++ } + +- if (domains != NULL) { +- for (c = 0; domains[c] != NULL; c++) { +- free(domains[c]); +- } +- free(domains); +- domains = NULL; +- } +- ret = ipadb_ldap_attr_to_strlist(lc, le, IPA_ASSOCIATED_DOMAIN, +- &domains); +- if (ret != 0 && ret != ENOENT) { +- goto done; +- } ++ free(match_rule); ++ match_rule = NULL; ++ ret = ipadb_ldap_attr_to_str(lc, le, IPA_CERTMAP_MATCHRULE, ++ &match_rule); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; ++ } + +- ret = sss_certmap_add_rule(ctx, prio, match_rule, map_rule, +- (const char **) domains); +- if (ret != 0) { +- goto done; ++ if (domains != NULL) { ++ for (c = 0; domains[c] != NULL; c++) { ++ free(domains[c]); + } ++ free(domains); ++ domains = NULL; ++ } ++ ret = ipadb_ldap_attr_to_strlist(lc, le, IPA_ASSOCIATED_DOMAIN, ++ &domains); ++ if (ret != 0 && ret != ENOENT) { ++ goto done; + } +- } +- +- ipactx->certauth_moddata = moddata_out; + +- if (ipactx->realm != NULL) { +- ipactx->certauth_moddata->local_domain = strdup(ipactx->realm); +- if (ipactx->certauth_moddata->local_domain == NULL) { +- free(ipactx->certauth_moddata); +- ipactx->certauth_moddata = NULL; +- ret = ENOMEM; ++ ret = sss_certmap_add_rule(ctx, prio, match_rule, map_rule, ++ (const char **) domains); ++ if (ret != 0) { + goto done; + } + } +- +- ipactx->certauth_moddata->sss_certmap_ctx = ctx; +- ipactx->certauth_moddata->ipactx = ipactx; +- + } + ++ sss_certmap_free_ctx(ipactx->certauth_moddata->sss_certmap_ctx); ++ ipactx->certauth_moddata->sss_certmap_ctx = ctx; ++ ipactx->certauth_moddata->valid_until = time(NULL) ++ + DEFAULT_CERTMAP_LIFETIME; ++ krb5_klog_syslog(LOG_DEBUG, ++ "Successfully updates certificate mapping rules."); ++ + ret = 0; + + done: +@@ -266,7 +275,7 @@ static krb5_error_code ipa_certauth_authorize(krb5_context context, + return KRB5_PLUGIN_NO_HANDLE; + } + +- if (moddata->sss_certmap_ctx == NULL) { ++ if (moddata->sss_certmap_ctx == NULL || time(NULL) > moddata->valid_until) { + kerr = ipa_get_init_data(context, moddata); + if (kerr != 0) { + krb5_klog_syslog(LOG_ERR, "Failed to init certmapping data"); +-- +2.9.4 + diff --git a/SOURCES/0174-Avoid-possible-endless-recursion-in-RPC-call.patch b/SOURCES/0174-Avoid-possible-endless-recursion-in-RPC-call.patch new file mode 100644 index 0000000..887f87a --- /dev/null +++ b/SOURCES/0174-Avoid-possible-endless-recursion-in-RPC-call.patch @@ -0,0 +1,127 @@ +From 0367e6dd66d47a78484e12e76119d9662356bf48 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Fri, 26 May 2017 08:37:36 +0200 +Subject: [PATCH] Avoid possible endless recursion in RPC call + +This commit removes recursion in RPCClient.forward() which may lack +end condition. + +https://pagure.io/freeipa/issue/6796 + +Reviewed-By: Florence Blanc-Renaud +--- + ipalib/rpc.py | 95 +++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 54 insertions(+), 41 deletions(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index e23ca3d061645b2695a9e0deaa0b7d666f986e0e..297ed80414fae3d8b27558567425fec704f3e862 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -1088,50 +1088,63 @@ class RPCClient(Connectible): + :param kw: Keyword arguments to pass to remote command. + """ + server = getattr(context, 'request_url', None) +- self.log.info("Forwarding '%s' to %s server '%s'", +- name, self.protocol, server) + command = getattr(self.conn, name) + params = [args, kw] +- try: +- return self._call_command(command, params) +- except Fault as e: +- e = decode_fault(e) +- self.debug('Caught fault %d from server %s: %s', e.faultCode, +- server, e.faultString) +- if e.faultCode in errors_by_code: +- error = errors_by_code[e.faultCode] +- raise error(message=e.faultString) +- raise UnknownError( +- code=e.faultCode, +- error=e.faultString, +- server=server, +- ) +- except SSLError as e: +- raise NetworkError(uri=server, error=str(e)) +- except ProtocolError as e: +- # By catching a 401 here we can detect the case where we have +- # a single IPA server and the session is invalid. Otherwise +- # we always have to do a ping(). +- session_cookie = getattr(context, 'session_cookie', None) +- if session_cookie and e.errcode == 401: +- # Unauthorized. Remove the session and try again. +- delattr(context, 'session_cookie') +- try: +- principal = getattr(context, 'principal', None) +- delete_persistent_client_session_data(principal) +- except Exception as e: +- # This shouldn't happen if we have a session but it isn't fatal. +- pass + +- # Create a new serverproxy with the non-session URI +- serverproxy = self.create_connection(os.environ.get('KRB5CCNAME'), self.env.verbose, self.env.fallback, self.env.delegate) +- setattr(context, self.id, Connection(serverproxy, self.disconnect)) +- return self.forward(name, *args, **kw) +- raise NetworkError(uri=server, error=e.errmsg) +- except socket.error as e: +- raise NetworkError(uri=server, error=str(e)) +- except (OverflowError, TypeError) as e: +- raise XMLRPCMarshallError(error=str(e)) ++ # we'll be trying to connect multiple times with a new session cookie ++ # each time should we be getting UNAUTHORIZED error from the server ++ max_tries = 5 ++ for try_num in range(0, max_tries): ++ self.log.info("[try %d]: Forwarding '%s' to %s server '%s'", ++ try_num+1, name, self.protocol, server) ++ try: ++ return self._call_command(command, params) ++ except Fault as e: ++ e = decode_fault(e) ++ self.debug('Caught fault %d from server %s: %s', e.faultCode, ++ server, e.faultString) ++ if e.faultCode in errors_by_code: ++ error = errors_by_code[e.faultCode] ++ raise error(message=e.faultString) ++ raise UnknownError( ++ code=e.faultCode, ++ error=e.faultString, ++ server=server, ++ ) ++ except ProtocolError as e: ++ # By catching a 401 here we can detect the case where we have ++ # a single IPA server and the session is invalid. Otherwise ++ # we always have to do a ping(). ++ session_cookie = getattr(context, 'session_cookie', None) ++ if session_cookie and e.errcode == 401: ++ # Unauthorized. Remove the session and try again. ++ delattr(context, 'session_cookie') ++ try: ++ principal = getattr(context, 'principal', None) ++ delete_persistent_client_session_data(principal) ++ except Exception as e: ++ # This shouldn't happen if we have a session ++ # but it isn't fatal. ++ self.debug("Error trying to remove persisent session " ++ "data: {err}".format(err=e)) ++ ++ # Create a new serverproxy with the non-session URI ++ serverproxy = self.create_connection( ++ os.environ.get('KRB5CCNAME'), self.env.verbose, ++ self.env.fallback, self.env.delegate) ++ ++ setattr(context, self.id, ++ Connection(serverproxy, self.disconnect)) ++ # try to connect again with the new session cookie ++ continue ++ raise NetworkError(uri=server, error=e.errmsg) ++ except (SSLError, socket.error) as e: ++ raise NetworkError(uri=server, error=str(e)) ++ except (OverflowError, TypeError) as e: ++ raise XMLRPCMarshallError(error=str(e)) ++ raise NetworkError( ++ uri=server, ++ error=_("Exceeded number of tries to forward a request.")) + + + class xmlclient(RPCClient): +-- +2.9.4 + diff --git a/SOURCES/0175-rpc-preparations-for-recursion-fix.patch b/SOURCES/0175-rpc-preparations-for-recursion-fix.patch new file mode 100644 index 0000000..156557c --- /dev/null +++ b/SOURCES/0175-rpc-preparations-for-recursion-fix.patch @@ -0,0 +1,103 @@ +From ae8d12b2f764fa49bebf263ec646709900d90a6b Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Wed, 31 May 2017 15:45:19 +0200 +Subject: [PATCH] rpc: preparations for recursion fix + +Made several improvements to coding style: + - same use of KerberosError throughout the module + - removed some unused variables + - moved code from try-except blocks if it didn't have to be there + - preparations for putting most of RPCClient.create_connection() + to loop + +https://pagure.io/freeipa/issue/6796 + +Reviewed-By: Florence Blanc-Renaud +--- + ipalib/rpc.py | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index 297ed80414fae3d8b27558567425fec704f3e862..b12ce4c5365299332587ad0d2990ca30070217bf 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -52,7 +52,7 @@ from six.moves import urllib + from ipalib.backend import Connectible + from ipalib.constants import LDAP_GENERALIZED_TIME_FORMAT + from ipalib.errors import (public_errors, UnknownError, NetworkError, +- KerberosError, XMLRPCMarshallError, JSONError) ++ XMLRPCMarshallError, JSONError) + from ipalib import errors, capabilities + from ipalib.request import context, Connection + from ipapython.ipa_log_manager import root_logger +@@ -653,7 +653,7 @@ class KerbTransport(SSLTransport): + except (TypeError, UnicodeError): + pass + if not token: +- raise KerberosError( ++ raise errors.KerberosError( + message=u"No valid Negotiate header in server response") + token = self._sec_context.step(token=token) + if self._sec_context.complete: +@@ -979,8 +979,10 @@ class RPCClient(Connectible): + delegate = self.api.env.delegate + if ca_certfile is None: + ca_certfile = self.api.env.tls_ca_cert ++ context.ca_certfile = ca_certfile ++ ++ rpc_uri = self.env[self.env_rpc_uri_key] + try: +- rpc_uri = self.env[self.env_rpc_uri_key] + principal = get_principal(ccache_name=ccache) + stored_principal = getattr(context, 'principal', None) + if principal != stored_principal: +@@ -996,12 +998,14 @@ class RPCClient(Connectible): + except (errors.CCacheError, ValueError): + # No session key, do full Kerberos auth + pass +- context.ca_certfile = ca_certfile + urls = self.get_url_list(rpc_uri) + serverproxy = None + for url in urls: +- kw = dict(allow_none=True, encoding='UTF-8') +- kw['verbose'] = verbose ++ kw = { ++ 'allow_none': True, ++ 'encoding': 'UTF-8', ++ 'verbose': verbose ++ } + if url.startswith('https://'): + if delegate: + transport_class = DelegatedKerbTransport +@@ -1036,21 +1040,24 @@ class RPCClient(Connectible): + ) + # We don't care about the response, just that we got one + break +- except KerberosError as krberr: ++ except errors.KerberosError: + # kerberos error on one server is likely on all +- raise errors.KerberosError(message=unicode(krberr)) ++ raise + except ProtocolError as e: + if hasattr(context, 'session_cookie') and e.errcode == 401: + # Unauthorized. Remove the session and try again. + delattr(context, 'session_cookie') + try: + delete_persistent_client_session_data(principal) +- except Exception as e: ++ except Exception: + # This shouldn't happen if we have a session but it isn't fatal. + pass +- return self.create_connection(ccache, verbose, fallback, delegate) ++ return self.create_connection( ++ ccache, verbose, fallback, delegate) + if not fallback: + raise ++ else: ++ self.log.info('Connection to %s failed with %s', url, e) + serverproxy = None + except Exception as e: + if not fallback: +-- +2.9.4 + diff --git a/SOURCES/0176-rpc-avoid-possible-recursion-in-create_connection.patch b/SOURCES/0176-rpc-avoid-possible-recursion-in-create_connection.patch new file mode 100644 index 0000000..885522f --- /dev/null +++ b/SOURCES/0176-rpc-avoid-possible-recursion-in-create_connection.patch @@ -0,0 +1,175 @@ +From f5f7cbc63f9235ce040687cdf102aeaef69ab422 Mon Sep 17 00:00:00 2001 +From: Stanislav Laznicka +Date: Thu, 1 Jun 2017 09:00:15 +0200 +Subject: [PATCH] rpc: avoid possible recursion in create_connection + +There was a recursion in RPCClient.create_connection() which under rare +circumstances would not have an ending condition. This commit removes +it and cleans up the code a bit as well. + +https://pagure.io/freeipa/issue/6796 + +Reviewed-By: Florence Blanc-Renaud +--- + ipalib/rpc.py | 140 +++++++++++++++++++++++++++++++--------------------------- + 1 file changed, 74 insertions(+), 66 deletions(-) + +diff --git a/ipalib/rpc.py b/ipalib/rpc.py +index b12ce4c5365299332587ad0d2990ca30070217bf..e3b8d67d69c084ad1a43390b5f93061826a27e1d 100644 +--- a/ipalib/rpc.py ++++ b/ipalib/rpc.py +@@ -999,77 +999,85 @@ class RPCClient(Connectible): + # No session key, do full Kerberos auth + pass + urls = self.get_url_list(rpc_uri) +- serverproxy = None ++ ++ proxy_kw = { ++ 'allow_none': True, ++ 'encoding': 'UTF-8', ++ 'verbose': verbose ++ } ++ + for url in urls: +- kw = { +- 'allow_none': True, +- 'encoding': 'UTF-8', +- 'verbose': verbose +- } +- if url.startswith('https://'): +- if delegate: +- transport_class = DelegatedKerbTransport ++ # should we get ProtocolError (=> error in HTTP response) and ++ # 401 (=> Unauthorized), we'll be re-trying with new session ++ # cookies several times ++ for _try_num in range(0, 5): ++ if url.startswith('https://'): ++ if delegate: ++ transport_class = DelegatedKerbTransport ++ else: ++ transport_class = KerbTransport + else: +- transport_class = KerbTransport +- else: +- transport_class = LanguageAwareTransport +- kw['transport'] = transport_class(protocol=self.protocol, +- service='HTTP', ccache=ccache) +- self.log.info('trying %s' % url) +- setattr(context, 'request_url', url) +- serverproxy = self.server_proxy_class(url, **kw) +- if len(urls) == 1: +- # if we have only 1 server and then let the +- # main requester handle any errors. This also means it +- # must handle a 401 but we save a ping. +- return serverproxy +- try: +- command = getattr(serverproxy, 'ping') ++ transport_class = LanguageAwareTransport ++ proxy_kw['transport'] = transport_class( ++ protocol=self.protocol, service='HTTP', ccache=ccache) ++ self.log.info('trying %s' % url) ++ setattr(context, 'request_url', url) ++ serverproxy = self.server_proxy_class(url, **proxy_kw) ++ if len(urls) == 1: ++ # if we have only 1 server and then let the ++ # main requester handle any errors. This also means it ++ # must handle a 401 but we save a ping. ++ return serverproxy + try: +- command([], {}) +- except Fault as e: +- e = decode_fault(e) +- if e.faultCode in errors_by_code: +- error = errors_by_code[e.faultCode] +- raise error(message=e.faultString) +- else: +- raise UnknownError( +- code=e.faultCode, +- error=e.faultString, +- server=url, +- ) +- # We don't care about the response, just that we got one +- break +- except errors.KerberosError: +- # kerberos error on one server is likely on all +- raise +- except ProtocolError as e: +- if hasattr(context, 'session_cookie') and e.errcode == 401: +- # Unauthorized. Remove the session and try again. +- delattr(context, 'session_cookie') ++ command = getattr(serverproxy, 'ping') + try: +- delete_persistent_client_session_data(principal) +- except Exception: +- # This shouldn't happen if we have a session but it isn't fatal. +- pass +- return self.create_connection( +- ccache, verbose, fallback, delegate) +- if not fallback: ++ command([], {}) ++ except Fault as e: ++ e = decode_fault(e) ++ if e.faultCode in errors_by_code: ++ error = errors_by_code[e.faultCode] ++ raise error(message=e.faultString) ++ else: ++ raise UnknownError( ++ code=e.faultCode, ++ error=e.faultString, ++ server=url, ++ ) ++ # We don't care about the response, just that we got one ++ return serverproxy ++ except errors.KerberosError: ++ # kerberos error on one server is likely on all + raise +- else: +- self.log.info('Connection to %s failed with %s', url, e) +- serverproxy = None +- except Exception as e: +- if not fallback: +- raise +- else: +- self.log.info('Connection to %s failed with %s', url, e) +- serverproxy = None +- +- if serverproxy is None: +- raise NetworkError(uri=_('any of the configured servers'), +- error=', '.join(urls)) +- return serverproxy ++ except ProtocolError as e: ++ if hasattr(context, 'session_cookie') and e.errcode == 401: ++ # Unauthorized. Remove the session and try again. ++ delattr(context, 'session_cookie') ++ try: ++ delete_persistent_client_session_data(principal) ++ except Exception: ++ # This shouldn't happen if we have a session but ++ # it isn't fatal. ++ pass ++ # try the same url once more with a new session cookie ++ continue ++ if not fallback: ++ raise ++ else: ++ self.log.info( ++ 'Connection to %s failed with %s', url, e) ++ # try the next url ++ break ++ except Exception as e: ++ if not fallback: ++ raise ++ else: ++ self.log.info( ++ 'Connection to %s failed with %s', url, e) ++ # try the next url ++ break ++ # finished all tries but no serverproxy was found ++ raise NetworkError(uri=_('any of the configured servers'), ++ error=', '.join(urls)) + + def destroy_connection(self): + conn = getattr(context, self.id, None) +-- +2.9.4 + diff --git a/SOURCES/0177-Changing-cert-find-to-do-not-use-only-primary-key-to.patch b/SOURCES/0177-Changing-cert-find-to-do-not-use-only-primary-key-to.patch new file mode 100644 index 0000000..ee9e062 --- /dev/null +++ b/SOURCES/0177-Changing-cert-find-to-do-not-use-only-primary-key-to.patch @@ -0,0 +1,102 @@ +From d5af6b5e3ee50f97db730a4097c46baf07e09002 Mon Sep 17 00:00:00 2001 +From: Felipe Volpone +Date: Thu, 1 Jun 2017 16:53:11 -0300 +Subject: [PATCH] Changing cert-find to do not use only primary key to search + in LDAP. + +In service.py the primary key is krbCanonicalName, which we +don't want to use to do searchs. Now, cert-find uses primary +key or a specified attribute to do searches in LDAP, instead +of using only a primary key. + +https://pagure.io/freeipa/issue/6948 + +Reviewed-By: Martin Babinsky +Reviewed-By: Jan Cholasta +Reviewed-By: Fraser Tweedale +--- + ipaserver/plugins/cert.py | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py +index 68402679cf0320e9c664ea89276f6c4332730a15..bb11713317abad55577b1c280253ab5d6d68c508 100644 +--- a/ipaserver/plugins/cert.py ++++ b/ipaserver/plugins/cert.py +@@ -981,8 +981,8 @@ class cert(BaseCertObject): + param = param.clone(flags=param.flags - {'no_search'}) + yield param + +- for owner in self._owners(): +- yield owner.primary_key.clone_rename( ++ for owner, search_key in self._owners(): ++ yield search_key.clone_rename( + 'owner_{0}'.format(owner.name), + required=False, + multivalue=True, +@@ -992,15 +992,22 @@ class cert(BaseCertObject): + ) + + def _owners(self): +- for name in ('user', 'host', 'service'): +- yield self.api.Object[name] ++ for obj_name, search_key in [('user', None), ++ ('host', None), ++ ('service', 'krbprincipalname')]: ++ obj = self.api.Object[obj_name] ++ if search_key is None: ++ pkey = obj.primary_key ++ else: ++ pkey = obj.params[search_key] ++ yield obj, pkey + + def _fill_owners(self, obj): + dns = obj.pop('owner', None) + if dns is None: + return + +- for owner in self._owners(): ++ for owner, _search_key in self._owners(): + container_dn = DN(owner.container_dn, self.api.env.basedn) + name = 'owner_' + owner.name + for dn in dns: +@@ -1264,8 +1271,8 @@ class cert_find(Search, CertMethod): + option = option.clone(default=None, autofill=None) + yield option + +- for owner in self.obj._owners(): +- yield owner.primary_key.clone_rename( ++ for owner, search_key in self.obj._owners(): ++ yield search_key.clone_rename( + '{0}'.format(owner.name), + required=False, + multivalue=True, +@@ -1276,7 +1283,7 @@ class cert_find(Search, CertMethod): + owner.object_name_plural), + label=owner.object_name, + ) +- yield owner.primary_key.clone_rename( ++ yield search_key.clone_rename( + 'no_{0}'.format(owner.name), + required=False, + multivalue=True, +@@ -1395,7 +1402,7 @@ class cert_find(Search, CertMethod): + ldap = self.api.Backend.ldap2 + + filters = [] +- for owner in self.obj._owners(): ++ for owner, search_key in self.obj._owners(): + for prefix, rule in (('', ldap.MATCH_ALL), + ('no_', ldap.MATCH_NONE)): + try: +@@ -1411,7 +1418,7 @@ class cert_find(Search, CertMethod): + filters.append(filter) + + filter = ldap.make_filter_from_attr( +- owner.primary_key.name, ++ search_key.name, + value, + rule) + filters.append(filter) +-- +2.9.4 + diff --git a/SOURCES/0178-ipa-kdb-add-pkinit-authentication-indicator-in-case-.patch b/SOURCES/0178-ipa-kdb-add-pkinit-authentication-indicator-in-case-.patch new file mode 100644 index 0000000..3a78753 --- /dev/null +++ b/SOURCES/0178-ipa-kdb-add-pkinit-authentication-indicator-in-case-.patch @@ -0,0 +1,101 @@ +From 5e052107dcb70630c1cccee191ae5317a43ec2cf Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 4 Jun 2017 22:49:13 +0300 +Subject: [PATCH] ipa-kdb: add pkinit authentication indicator in case of a + successful certauth + +We automatically add 'otp' and 'radius' authentication indicators when +pre-authentication with OTP or RADIUS did succeed. Do the same for +certauth-based pre-authentication (PKINIT). + +A default PKINIT configuration does not add any authentication +indicators unless 'pkinit_indicator = pkinit' is set in kdc.conf. +Unfortunately, modifying kdc.conf automatically is a bit more +complicated than modifying krb5.conf. Given that we have 'otp' and +'radius' authentication indicators also defined in the code not in the +kdc.conf, this change is following an established trend. + +SSSD certauth interface does not provide additional information about +which rule(s) succeeded in matching the incoming certificate. Thus, +there is not much information we can automatically provide in the +indicator. It would be good to generate indicators that include some +information from the certmapping rules in future but for now a single +'pkinit' indicator is enough. + +Fixes https://pagure.io/freeipa/issue/6736 + +Reviewed-By: Simo Sorce +--- + daemons/ipa-kdb/ipa_kdb_certauth.c | 36 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 34 insertions(+), 2 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_certauth.c b/daemons/ipa-kdb/ipa_kdb_certauth.c +index dbe7a0443700784d2b8dbb1fb9196d6249e5522a..da9a9cb87feca68ee591da70a3239dc86749bae5 100644 +--- a/daemons/ipa-kdb/ipa_kdb_certauth.c ++++ b/daemons/ipa-kdb/ipa_kdb_certauth.c +@@ -267,6 +267,7 @@ static krb5_error_code ipa_certauth_authorize(krb5_context context, + int ret; + size_t c; + char *principal = NULL; ++ char **auth_inds = NULL; + LDAPMessage *res = NULL; + krb5_error_code kerr; + LDAPMessage *lentry; +@@ -350,6 +351,20 @@ static krb5_error_code ipa_certauth_authorize(krb5_context context, + goto done; + } + ++ /* Associate authentication indicator "pkinit" with the successful match. ++ * SSSD interface doesn't give us a clue which rule did match ++ * so there is nothing more to add here. */ ++ auth_inds = calloc(2, sizeof(char *)); ++ if (auth_inds != NULL) { ++ ret = asprintf(&auth_inds[0], "pkinit"); ++ if (ret != -1) { ++ auth_inds[1] = NULL; ++ *authinds_out = auth_inds; ++ } else { ++ free(auth_inds); ++ } ++ } ++ + /* TODO: add more tests ? */ + + ret = 0; +@@ -384,6 +399,24 @@ static void ipa_certauth_fini(krb5_context context, + return; + } + ++static void ipa_certauth_free_indicator(krb5_context context, ++ krb5_certauth_moddata moddata, ++ char **authinds) ++{ ++ size_t i = 0; ++ ++ if ((authinds == NULL) || (moddata == NULL)) { ++ return; ++ } ++ ++ for(i=0; authinds[i]; i++) { ++ free(authinds[i]); ++ authinds[i] = NULL; ++ } ++ ++ free(authinds); ++} ++ + + krb5_error_code certauth_ipakdb_initvt(krb5_context context, + int maj_ver, int min_ver, +@@ -401,7 +434,6 @@ krb5_error_code certauth_ipakdb_initvt(krb5_context context, + vt->authorize = ipa_certauth_authorize; + vt->init = ipa_certauth_init; + vt->fini = ipa_certauth_fini; +- /* currently we do not return authentication indicators */ +- vt->free_ind = NULL; ++ vt->free_ind = ipa_certauth_free_indicator; + return 0; + } +-- +2.9.4 + diff --git a/SOURCES/0179-fix-incorrect-suffix-handling-in-topology-checks.patch b/SOURCES/0179-fix-incorrect-suffix-handling-in-topology-checks.patch new file mode 100644 index 0000000..e42bb98 --- /dev/null +++ b/SOURCES/0179-fix-incorrect-suffix-handling-in-topology-checks.patch @@ -0,0 +1,49 @@ +From 6d44c0c1455442ffd61ad532635c109b92ca96d1 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 26 May 2017 12:23:51 +0200 +Subject: [PATCH] fix incorrect suffix handling in topology checks + +When trying to delete a partially removed master entry lacking +'iparepltopomanagedsuffix' attribute, the code that tries to retrieve +tha value for further computations passes None and causes unhandled +internal errors. + +If the attribute is empty or not present, we should return empty list +instead as to not break calling cod attribute, the code that tries to +retrieve tha value for further computations passes None and causes +unhandled internal errors. We should return empty list instead. + +https://pagure.io/freeipa/issue/6965 + +Reviewed-By: Felipe Volpone +--- + ipaserver/topology.py | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/ipaserver/topology.py b/ipaserver/topology.py +index 385da29a66fb7276c55e9aac5c8c266b897721a7..2b6b0835473097eeec673230fab338bef41b8c49 100644 +--- a/ipaserver/topology.py ++++ b/ipaserver/topology.py +@@ -72,12 +72,15 @@ def get_topology_connection_errors(graph): + + def map_masters_to_suffixes(masters): + masters_to_suffix = {} ++ managed_suffix_attr = 'iparepltopomanagedsuffix_topologysuffix' + + for master in masters: +- try: +- managed_suffixes = master.get( +- 'iparepltopomanagedsuffix_topologysuffix') +- except KeyError: ++ if managed_suffix_attr not in master: ++ continue ++ ++ managed_suffixes = master[managed_suffix_attr] ++ ++ if managed_suffixes is None: + continue + + for suffix_name in managed_suffixes: +-- +2.9.4 + diff --git a/SOURCES/0180-server-certinstall-update-KDC-master-entry.patch b/SOURCES/0180-server-certinstall-update-KDC-master-entry.patch new file mode 100644 index 0000000..5fa9aca --- /dev/null +++ b/SOURCES/0180-server-certinstall-update-KDC-master-entry.patch @@ -0,0 +1,45 @@ +From 82af886e17905b8bdaadf8fc2b8214ad85a94470 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 5 Jun 2017 12:35:52 +0000 +Subject: [PATCH] server certinstall: update KDC master entry + +After the KDC certificate is installed, add the PKINIT enabled flag to the +KDC master entry. + +https://pagure.io/freeipa/issue/7000 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/ipa_server_certinstall.py | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py +index a14a84f188c62170c8ac11f823ebba60609e4cc7..9c8f6e81a802e1a87bab1fd15f729e10676fe3a3 100644 +--- a/ipaserver/install/ipa_server_certinstall.py ++++ b/ipaserver/install/ipa_server_certinstall.py +@@ -34,7 +34,7 @@ from ipapython.certdb import (get_ca_nickname, + verify_kdc_cert_validity) + from ipapython.dn import DN + from ipalib import api, errors +-from ipaserver.install import certs, dsinstance, installutils ++from ipaserver.install import certs, dsinstance, installutils, krbinstance + + + class ServerCertInstall(admintool.AdminTool): +@@ -223,6 +223,13 @@ class ServerCertInstall(admintool.AdminTool): + except RuntimeError as e: + raise admintool.ScriptError(str(e)) + ++ krb = krbinstance.KrbInstance() ++ krb.init_info( ++ realm_name=api.env.realm, ++ host_name=api.env.host, ++ ) ++ krb.pkinit_enable() ++ + def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb): + # create a temp nssdb + with NSSDatabase() as tempnssdb: +-- +2.9.4 + diff --git a/SOURCES/0181-pkinit-manage-introduce-ipa-pkinit-manage.patch b/SOURCES/0181-pkinit-manage-introduce-ipa-pkinit-manage.patch new file mode 100644 index 0000000..9662a62 --- /dev/null +++ b/SOURCES/0181-pkinit-manage-introduce-ipa-pkinit-manage.patch @@ -0,0 +1,259 @@ +From d224655e4b1e218bac19dff5a10bf3e0d83edcb0 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 5 Jun 2017 12:41:02 +0000 +Subject: [PATCH] pkinit manage: introduce ipa-pkinit-manage + +Add the ipa-pkinit-manage tool to allow enabling / disabling PKINIT after +the initial server install. + +https://pagure.io/freeipa/issue/7000 + +Reviewed-By: Martin Babinsky +--- + freeipa.spec.in | 2 + + install/tools/Makefile.am | 1 + + install/tools/ipa-pkinit-manage | 8 +++ + install/tools/man/Makefile.am | 1 + + install/tools/man/ipa-pkinit-manage.1 | 34 +++++++++++++ + ipaserver/install/ipa_pkinit_manage.py | 93 ++++++++++++++++++++++++++++++++++ + ipaserver/install/krbinstance.py | 24 +++++++++ + 7 files changed, 163 insertions(+) + create mode 100755 install/tools/ipa-pkinit-manage + create mode 100644 install/tools/man/ipa-pkinit-manage.1 + create mode 100644 ipaserver/install/ipa_pkinit_manage.py + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 2cbaa60df0db021a4a1ce10af383cd6a15e1e57c..ae77a9a23645c1490c32195203e2c4f665783a80 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -1184,6 +1184,7 @@ fi + %{_sbindir}/ipa-advise + %{_sbindir}/ipa-cacert-manage + %{_sbindir}/ipa-winsync-migrate ++%{_sbindir}/ipa-pkinit-manage + %{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit + %{_libexecdir}/certmonger/ipa-server-guard + %dir %{_libexecdir}/ipa +@@ -1247,6 +1248,7 @@ fi + %{_mandir}/man1/ipa-otptoken-import.1* + %{_mandir}/man1/ipa-cacert-manage.1* + %{_mandir}/man1/ipa-winsync-migrate.1* ++%{_mandir}/man1/ipa-pkinit-manage.1* + + + %files -n python2-ipaserver +diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am +index 493e5ff4a8290be8ef076135104a85f8315b7842..47ecc14d7320336315c16587956c4965387853d9 100644 +--- a/install/tools/Makefile.am ++++ b/install/tools/Makefile.am +@@ -28,6 +28,7 @@ dist_sbin_SCRIPTS = \ + ipa-advise \ + ipa-cacert-manage \ + ipa-winsync-migrate \ ++ ipa-pkinit-manage \ + $(NULL) + + appdir = $(libexecdir)/ipa/ +diff --git a/install/tools/ipa-pkinit-manage b/install/tools/ipa-pkinit-manage +new file mode 100755 +index 0000000000000000000000000000000000000000..5b2413bd7cdc97632f82a77e18f3424a2ff63309 +--- /dev/null ++++ b/install/tools/ipa-pkinit-manage +@@ -0,0 +1,8 @@ ++#! /usr/bin/python2 -E ++# ++# Copyright (C) 2017 FreeIPA Contributors see COPYING for license ++# ++ ++from ipaserver.install.ipa_pkinit_manage import PKINITManage ++ ++PKINITManage.run_cli() +diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am +index 0d06ec7306b0cc1e656dac244bcb2c480b0ae61e..2dac9ac716352847aeb0d1fd3c6375ede956c751 100644 +--- a/install/tools/man/Makefile.am ++++ b/install/tools/man/Makefile.am +@@ -27,6 +27,7 @@ dist_man1_MANS = \ + ipa-otptoken-import.1 \ + ipa-cacert-manage.1 \ + ipa-winsync-migrate.1 \ ++ ipa-pkinit-manage.1 \ + $(NULL) + + dist_man8_MANS = \ +diff --git a/install/tools/man/ipa-pkinit-manage.1 b/install/tools/man/ipa-pkinit-manage.1 +new file mode 100644 +index 0000000000000000000000000000000000000000..5018ce8aa3f89470453d9cfc590a0c5f44f78f3c +--- /dev/null ++++ b/install/tools/man/ipa-pkinit-manage.1 +@@ -0,0 +1,34 @@ ++.\" ++.\" Copyright (C) 2017 FreeIPA Contributors see COPYING for license ++.\" ++.TH "ipa-pkinit-manage" "1" "Jun 05 2017" "FreeIPA" "FreeIPA Manual Pages" ++.SH "NAME" ++ipa\-pkinit\-manage \- Enables or disables PKINIT ++.SH "SYNOPSIS" ++ipa\-pkinit\-manage [options] ++.SH "DESCRIPTION" ++Run the command with the \fBenable\fR option to enable PKINIT. ++ ++Run the command with the \fBdisable\fR option to disable PKINIT. ++ ++Run the command with the \fBstatus\fR to determine the current status of PKINIT. ++.SH "OPTIONS" ++.TP ++\fB\-\-version\fR ++Show the program's version and exit. ++.TP ++\fB\-h\fR, \fB\-\-help\fR ++Show the help for this program. ++.TP ++\fB\-v\fR, \fB\-\-verbose\fR ++Print debugging information. ++.TP ++\fB\-q\fR, \fB\-\-quiet\fR ++Output only errors. ++.TP ++\fB\-\-log\-file\fR=\fIFILE\fR ++Log to the given file. ++.SH "EXIT STATUS" ++0 if the command was successful ++ ++1 if an error occurred +diff --git a/ipaserver/install/ipa_pkinit_manage.py b/ipaserver/install/ipa_pkinit_manage.py +new file mode 100644 +index 0000000000000000000000000000000000000000..428c0e3476b4dbd13a9ee5a40a42447f9fa95f2d +--- /dev/null ++++ b/ipaserver/install/ipa_pkinit_manage.py +@@ -0,0 +1,93 @@ ++# ++# Copyright (C) 2017 FreeIPA Contributors see COPYING for license ++# ++ ++from __future__ import print_function ++ ++from ipalib import api ++from ipaplatform.paths import paths ++from ipapython.admintool import AdminTool ++from ipaserver.install.krbinstance import KrbInstance, is_pkinit_enabled ++ ++ ++class PKINITManage(AdminTool): ++ command_name = "ipa-pkinit-manage" ++ usage = "%prog " ++ description = "Manage PKINIT." ++ ++ def validate_options(self): ++ super(PKINITManage, self).validate_options(needs_root=True) ++ ++ option_parser = self.option_parser ++ ++ if not self.args: ++ option_parser.error("action not specified") ++ elif len(self.args) > 1: ++ option_parser.error("too many arguments") ++ ++ action = self.args[0] ++ if action not in {'enable', 'disable', 'status'}: ++ option_parser.error("unrecognized action '{}'".format(action)) ++ ++ def run(self): ++ api.bootstrap(in_server=True, confdir=paths.ETC_IPA) ++ api.finalize() ++ ++ api.Backend.ldap2.connect() ++ try: ++ action = self.args[0] ++ if action == 'enable': ++ self.enable() ++ elif action == 'disable': ++ self.disable() ++ elif action == 'status': ++ self.status() ++ finally: ++ api.Backend.ldap2.disconnect() ++ ++ return 0 ++ ++ def _setup(self, setup_pkinit): ++ config = api.Command.config_show()['result'] ++ ca_enabled = api.Command.ca_is_enabled()['result'] ++ ++ krb = KrbInstance() ++ krb.init_info( ++ realm_name=api.env.realm, ++ host_name=api.env.host, ++ setup_pkinit=setup_pkinit, ++ subject_base=config['ipacertificatesubjectbase'][0], ++ ) ++ ++ if bool(is_pkinit_enabled()) is not bool(setup_pkinit): ++ try: ++ krb.stop_tracking_certs() ++ except RuntimeError as e: ++ if ca_enabled: ++ self.log.warning( ++ "Failed to stop tracking certificates: %s", e) ++ ++ krb.enable_ssl() ++ ++ if setup_pkinit: ++ krb.pkinit_enable() ++ else: ++ krb.pkinit_disable() ++ ++ def enable(self): ++ if not api.Command.ca_is_enabled()['result']: ++ self.log.error("Cannot enable PKINIT in CA-less deployment") ++ self.log.error("Use ipa-server-certinstall to install KDC " ++ "certificate manually") ++ raise RuntimeError("Cannot enable PKINIT in CA-less deployment") ++ ++ self._setup(True) ++ ++ def disable(self): ++ self._setup(False) ++ ++ def status(self): ++ if is_pkinit_enabled(): ++ print("PKINIT is enabled") ++ else: ++ print("PKINIT is disabled") +diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py +index a1053d55ccaae17bef93547c036fb9d08d296f0b..6b51e65d1ec985bfc01f167aea3fe3ca11c7ec29 100644 +--- a/ipaserver/install/krbinstance.py ++++ b/ipaserver/install/krbinstance.py +@@ -451,6 +451,30 @@ class KrbInstance(service.Service): + service.set_service_entry_config( + 'KDC', self.fqdn, [PKINIT_ENABLED], self.suffix) + ++ def pkinit_disable(self): ++ """ ++ unadvertise enabled PKINIT feature in master's KDC entry in LDAP ++ """ ++ ldap = api.Backend.ldap2 ++ dn = DN(('cn', 'KDC'), ++ ('cn', self.fqdn), ++ ('cn', 'masters'), ++ ('cn', 'ipa'), ++ ('cn', 'etc'), ++ self.suffix) ++ ++ entry = ldap.get_entry(dn, ['ipaConfigString']) ++ ++ config = entry.setdefault('ipaConfigString', []) ++ config = [value for value in config ++ if value.lower() != PKINIT_ENABLED.lower()] ++ entry['ipaConfigString'][:] = config ++ ++ try: ++ ldap.update_entry(entry) ++ except errors.EmptyModlist: ++ pass ++ + def _install_pkinit_ca_bundle(self): + ca_certs = certstore.get_ca_certs(self.api.Backend.ldap2, + self.api.env.basedn, +-- +2.9.4 + diff --git a/SOURCES/0182-server-upgrade-do-not-enable-PKINIT-by-default.patch b/SOURCES/0182-server-upgrade-do-not-enable-PKINIT-by-default.patch new file mode 100644 index 0000000..5d539d4 --- /dev/null +++ b/SOURCES/0182-server-upgrade-do-not-enable-PKINIT-by-default.patch @@ -0,0 +1,42 @@ +From 1ab5b1a4cdcab8b913f42488ae642a9f0ef77d92 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Mon, 5 Jun 2017 12:42:52 +0000 +Subject: [PATCH] server upgrade: do not enable PKINIT by default + +Enabling PKINIT often fails during server upgrade when requesting the KDC +certificate. + +Now that PKINIT can be enabled post-install using ipa-pkinit-manage, avoid +the upgrade failure by not enabling PKINIT by default. + +https://pagure.io/freeipa/issue/7000 + +Reviewed-By: Martin Babinsky +--- + ipaserver/install/server/upgrade.py | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index db86353165809c57d1ac27bf762393721231fefd..b1f59d3e29d69bffc11935ec22d4b5f510293355 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1519,14 +1519,8 @@ def add_default_caacl(ca): + def setup_pkinit(krb): + root_logger.info("[Setup PKINIT]") + +- pkinit_is_enabled = krbinstance.is_pkinit_enabled() +- ca_is_enabled = api.Command.ca_is_enabled()['result'] +- +- if not pkinit_is_enabled: +- if ca_is_enabled: +- krb.issue_ipa_ca_signed_pkinit_certs() +- else: +- krb.issue_selfsigned_pkinit_certs() ++ if not krbinstance.is_pkinit_enabled(): ++ krb.issue_selfsigned_pkinit_certs() + + aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD, + loadpath=paths.USR_SHARE_IPA_DIR) +-- +2.9.4 + diff --git a/SOURCES/0183-Turn-off-OCSP-check.patch b/SOURCES/0183-Turn-off-OCSP-check.patch new file mode 100644 index 0000000..6556af5 --- /dev/null +++ b/SOURCES/0183-Turn-off-OCSP-check.patch @@ -0,0 +1,196 @@ +From ea2fc433d3f72364340919345805c667ce0d7524 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Thu, 1 Jun 2017 09:56:16 +0200 +Subject: [PATCH] Turn off OCSP check + +The OCSP check was previously turned on but it introduced several +issues. Therefore the check will be turned off by default. + +For turning on should be used ipa advise command with correct recipe. +The solution is tracked here: https://pagure.io/freeipa/issue/6982 + +Fixes: https://pagure.io/freeipa/issue/6981 +Reviewed-By: Martin Babinsky +--- + install/restart_scripts/restart_httpd | 15 +----------- + ipaserver/install/httpinstance.py | 43 +++++++++++++++++++---------------- + ipaserver/install/server/upgrade.py | 25 +++----------------- + 3 files changed, 28 insertions(+), 55 deletions(-) + +diff --git a/install/restart_scripts/restart_httpd b/install/restart_scripts/restart_httpd +index cd7f12024ea3cab16e9c664687cd854e666c9570..d1684812904a9d32842a0ca548ec6b9df5a5a0b7 100644 +--- a/install/restart_scripts/restart_httpd ++++ b/install/restart_scripts/restart_httpd +@@ -21,24 +21,11 @@ + + import syslog + import traceback +-from ipalib import api + from ipaplatform import services +-from ipaplatform.paths import paths +-from ipapython.certdb import TRUSTED_PEER_TRUST_FLAGS +-from ipaserver.install import certs, installutils ++from ipaserver.install import certs + + + def _main(): +- +- api.bootstrap(in_server=True, context='restart', confdir=paths.ETC_IPA) +- api.finalize() +- +- db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) +- nickname = installutils.get_directive(paths.HTTPD_NSS_CONF, "NSSNickname") +- +- # Add trust flag which set certificate trusted for SSL connections. +- db.trust_root_cert(nickname, TRUSTED_PEER_TRUST_FLAGS) +- + syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd') + + try: +diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py +index 12fdddccc26b0c1132bcdca7fe2249a85997892e..f637b97db8f21ddbc00c4f70e18e836d300b2f33 100644 +--- a/ipaserver/install/httpinstance.py ++++ b/ipaserver/install/httpinstance.py +@@ -34,8 +34,7 @@ from augeas import Augeas + from ipalib.install import certmonger + from ipapython import ipaldap + from ipapython.certdb import (IPA_CA_TRUST_FLAGS, +- EXTERNAL_CA_TRUST_FLAGS, +- TRUSTED_PEER_TRUST_FLAGS) ++ EXTERNAL_CA_TRUST_FLAGS) + from ipaserver.install import replication + from ipaserver.install import service + from ipaserver.install import certs +@@ -74,6 +73,10 @@ NSS_CIPHER_SUITE = [ + ] + NSS_CIPHER_REVISION = '20160129' + ++OCSP_DIRECTIVE = 'NSSOCSP' ++ ++NSS_OCSP_ENABLED = 'nss_ocsp_enabled' ++ + + def httpd_443_configured(): + """ +@@ -163,7 +166,7 @@ class HTTPInstance(service.Service): + 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("enabling mod_nss OCSP", self.enable_mod_nss_ocsp) ++ self.step("disabling mod_nss OCSP", self.disable_mod_nss_ocsp) + self.step("adding URL rewriting rules", self.__add_include) + self.step("configuring httpd", self.__configure_http) + self.step("setting up httpd keytab", self.request_service_keytab) +@@ -270,7 +273,12 @@ class HTTPInstance(service.Service): + installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRenegotiation', 'on', False) + installutils.set_directive(paths.HTTPD_NSS_CONF, 'NSSRequireSafeNegotiation', 'on', False) + +- def enable_mod_nss_ocsp(self): ++ def disable_mod_nss_ocsp(self): ++ if sysupgrade.get_upgrade_state('http', NSS_OCSP_ENABLED) is None: ++ self.__disable_mod_nss_ocsp() ++ sysupgrade.set_upgrade_state('http', NSS_OCSP_ENABLED, False) ++ ++ def __disable_mod_nss_ocsp(self): + aug = Augeas(flags=Augeas.NO_LOAD | Augeas.NO_MODL_AUTOLOAD) + + aug.set('/augeas/load/Httpd/lens', 'Httpd.lns') +@@ -278,22 +286,21 @@ class HTTPInstance(service.Service): + aug.load() + + path = '/files{}/VirtualHost'.format(paths.HTTPD_NSS_CONF) ++ ocsp_path = '{}/directive[.="{}"]'.format(path, OCSP_DIRECTIVE) ++ ocsp_arg = '{}/arg'.format(ocsp_path) ++ ocsp_comment = '{}/#comment[.="{}"]'.format(path, OCSP_DIRECTIVE) + +- ocsp_comment = aug.get( +- '{}/#comment[.=~regexp("NSSOCSP .*")]'.format(path)) +- ocsp_dir = aug.get('{}/directive[.="NSSOCSP"]'.format(path)) ++ ocsp_dir = aug.get(ocsp_path) + +- if ocsp_dir is None and ocsp_comment is not None: +- # Directive is missing, comment is present +- aug.set('{}/#comment[.=~regexp("NSSOCSP .*")]'.format(path), +- 'NSSOCSP') +- aug.rename('{}/#comment[.="NSSOCSP"]'.format(path), 'directive') +- elif ocsp_dir is None: +- # Directive is missing and comment is missing +- aug.set('{}/directive[last()+1]'.format(path), "NSSOCSP") ++ # there is NSSOCSP directive in nss.conf file, comment it ++ # otherwise just do nothing ++ if ocsp_dir is not None: ++ ocsp_state = aug.get(ocsp_arg) ++ aug.remove(ocsp_arg) ++ aug.rename(ocsp_path, '#comment') ++ aug.set(ocsp_comment, '{} {}'.format(OCSP_DIRECTIVE, ocsp_state)) ++ aug.save() + +- aug.set('{}/directive[. = "NSSOCSP"]/arg'.format(path), 'on') +- aug.save() + + def set_mod_nss_cipher_suite(self): + ciphers = ','.join(NSS_CIPHER_SUITE) +@@ -412,8 +419,6 @@ class HTTPInstance(service.Service): + self.__set_mod_nss_nickname(nickname) + self.add_cert_to_service() + +- db.trust_root_cert(nickname, TRUSTED_PEER_TRUST_FLAGS) +- + else: + if not self.promote: + ca_args = [ +diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py +index b1f59d3e29d69bffc11935ec22d4b5f510293355..732776f2cf513a4bb11d8f3f0dfaac78217e460f 100644 +--- a/ipaserver/install/server/upgrade.py ++++ b/ipaserver/install/server/upgrade.py +@@ -1395,24 +1395,6 @@ def fix_trust_flags(): + sysupgrade.set_upgrade_state('http', 'fix_trust_flags', True) + + +-def fix_server_cert_trust_flags(): +- root_logger.info( +- '[Fixing server certificate trust flags in %s]' % +- paths.HTTPD_ALIAS_DIR) +- +- if sysupgrade.get_upgrade_state('http', 'fix_serv_cert_trust_flags'): +- root_logger.info("Trust flags already processed") +- return +- +- db = certs.CertDB(api.env.realm, nssdir=paths.HTTPD_ALIAS_DIR) +- sc_nickname = installutils.get_directive(paths.HTTPD_NSS_CONF, +- "NSSNickname") +- # Add trust flag which set certificate trusted for SSL connections. +- db.trust_root_cert(sc_nickname, certdb.TRUSTED_PEER_TRUST_FLAGS) +- +- sysupgrade.set_upgrade_state('http', 'fix_serv_cert_trust_flags', True) +- +- + def update_mod_nss_protocol(http): + root_logger.info('[Updating mod_nss protocol versions]') + +@@ -1425,9 +1407,9 @@ def update_mod_nss_protocol(http): + sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True) + + +-def enable_mod_nss_ocsp(http): ++def disable_mod_nss_ocsp(http): + root_logger.info('[Updating mod_nss enabling OCSP]') +- http.enable_mod_nss_ocsp() ++ http.disable_mod_nss_ocsp() + + + def update_mod_nss_cipher_suite(http): +@@ -1721,9 +1703,8 @@ def upgrade_configuration(): + update_ipa_httpd_service_conf(http) + update_mod_nss_protocol(http) + update_mod_nss_cipher_suite(http) +- enable_mod_nss_ocsp(http) ++ disable_mod_nss_ocsp(http) + fix_trust_flags() +- fix_server_cert_trust_flags() + update_http_keytab(http) + http.configure_gssproxy() + http.start() +-- +2.9.4 + diff --git a/SOURCES/0184-Only-warn-when-specified-server-IP-addresses-don-t-m.patch b/SOURCES/0184-Only-warn-when-specified-server-IP-addresses-don-t-m.patch new file mode 100644 index 0000000..ae6ebbf --- /dev/null +++ b/SOURCES/0184-Only-warn-when-specified-server-IP-addresses-don-t-m.patch @@ -0,0 +1,244 @@ +From a04defc43419906675107e483f0f2f3153685c8d Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 31 May 2017 15:50:05 +0200 +Subject: [PATCH] Only warn when specified server IP addresses don't match intf + +In containers local addresses differ from public addresses and we need +a way to provide only public address to installers. + +https://pagure.io/freeipa/issue/2715 +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: Tomas Krizek +--- + ipaclient/install/client.py | 4 +- + ipalib/install/hostname.py | 2 +- + ipalib/util.py | 14 +++++++ + ipapython/ipautil.py | 62 ++++++++++++++++-------------- + ipaserver/install/dns.py | 1 + + ipaserver/install/installutils.py | 4 +- + ipaserver/install/server/install.py | 2 + + ipaserver/install/server/replicainstall.py | 2 + + 8 files changed, 59 insertions(+), 32 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 6f10f5258747881b9af8c6b70b499f9ff7d577ff..41dae3004d1f4836e79c2048ae0a12f722595ca0 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -41,6 +41,7 @@ from ipalib.util import ( + broadcast_ip_address_warning, + network_ip_address_warning, + normalize_hostname, ++ no_matching_interface_for_ip_address_warning, + verify_host_resolvable, + ) + from ipaplatform import services +@@ -1300,6 +1301,7 @@ def update_dns(server, hostname, options): + + network_ip_address_warning(update_ips) + broadcast_ip_address_warning(update_ips) ++ no_matching_interface_for_ip_address_warning(update_ips) + + update_txt = "debug\n" + update_txt += ipautil.template_str(DELETE_TEMPLATE_A, +@@ -1445,7 +1447,7 @@ def check_ip_addresses(options): + if options.ip_addresses: + for ip in options.ip_addresses: + try: +- ipautil.CheckedIPAddress(ip, match_local=True) ++ ipautil.CheckedIPAddress(ip) + except ValueError as e: + root_logger.error(e) + return False +diff --git a/ipalib/install/hostname.py b/ipalib/install/hostname.py +index 74c569d972df9975d677762b5769b2bf84dfddf0..5422ba6390ce13aa40f34938ed777d8821e8231b 100644 +--- a/ipalib/install/hostname.py ++++ b/ipalib/install/hostname.py +@@ -34,7 +34,7 @@ class HostNameInstallInterface(service.ServiceInstallInterface): + def ip_addresses(self, values): + for value in values: + try: +- CheckedIPAddress(value, match_local=True) ++ CheckedIPAddress(value) + except Exception as e: + raise ValueError("invalid IP address {0}: {1}".format( + value, e)) +diff --git a/ipalib/util.py b/ipalib/util.py +index 713fc107e9374eefe7805bc4e1abc40b6d150c32..1bd8495a49b010e7a3ac926dad516ab5f8219b39 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -1128,3 +1128,17 @@ def broadcast_ip_address_warning(addr_list): + # print + print("WARNING: IP address {} might be broadcast address".format( + ip), file=sys.stderr) ++ ++ ++def no_matching_interface_for_ip_address_warning(addr_list): ++ for ip in addr_list: ++ if not ip.get_matching_interface(): ++ root_logger.warning( ++ "No network interface matches the IP address %s", ip) ++ # fixme: once when loggers will be fixed, we can remove this ++ # print ++ print( ++ "WARNING: No network interface matches the IP address " ++ "{}".format(ip), ++ file=sys.stderr ++ ) +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 317fc225b722ad3ce2f4b9d92822b4f19d49adb9..a277ed87473f3c591f34fcc00e1159f3bbfe3e9b 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -161,34 +161,7 @@ class CheckedIPAddress(UnsafeIPAddress): + raise ValueError("cannot use multicast IP address {}".format(addr)) + + if match_local: +- if self.version == 4: +- family = netifaces.AF_INET +- elif self.version == 6: +- family = netifaces.AF_INET6 +- else: +- raise ValueError( +- "Unsupported address family ({})".format(self.version) +- ) +- +- iface = None +- for interface in netifaces.interfaces(): +- for ifdata in netifaces.ifaddresses(interface).get(family, []): +- +- # link-local addresses contain '%suffix' that causes parse +- # errors in IPNetwork +- ifaddr = ifdata['addr'].split(u'%', 1)[0] +- +- ifnet = netaddr.IPNetwork('{addr}/{netmask}'.format( +- addr=ifaddr, +- netmask=ifdata['netmask'] +- )) +- if ifnet == self._net or ( +- self._net is None and ifnet.ip == self): +- self._net = ifnet +- iface = interface +- break +- +- if iface is None: ++ if not self.get_matching_interface(): + raise ValueError('no network interface matches the IP address ' + 'and netmask {}'.format(addr)) + +@@ -218,6 +191,39 @@ class CheckedIPAddress(UnsafeIPAddress): + def is_broadcast_addr(self): + return self.version == 4 and self == self._net.broadcast + ++ def get_matching_interface(self): ++ """Find matching local interface for address ++ :return: Interface name or None if no interface has this address ++ """ ++ if self.version == 4: ++ family = netifaces.AF_INET ++ elif self.version == 6: ++ family = netifaces.AF_INET6 ++ else: ++ raise ValueError( ++ "Unsupported address family ({})".format(self.version) ++ ) ++ ++ iface = None ++ for interface in netifaces.interfaces(): ++ for ifdata in netifaces.ifaddresses(interface).get(family, []): ++ ++ # link-local addresses contain '%suffix' that causes parse ++ # errors in IPNetwork ++ ifaddr = ifdata['addr'].split(u'%', 1)[0] ++ ++ ifnet = netaddr.IPNetwork('{addr}/{netmask}'.format( ++ addr=ifaddr, ++ netmask=ifdata['netmask'] ++ )) ++ if ifnet == self._net or ( ++ self._net is None and ifnet.ip == self): ++ self._net = ifnet ++ iface = interface ++ break ++ ++ return iface ++ + + def valid_ip(addr): + return netaddr.valid_ipv4(addr) or netaddr.valid_ipv6(addr) +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index 0dddf2a6427f3f939171d755bfe2b1f05cfafa67..090b79493652566a433da248fa7fd9e33dd2cb72 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -266,6 +266,7 @@ def install_check(standalone, api, replica, options, hostname): + + util.network_ip_address_warning(ip_addresses) + util.broadcast_ip_address_warning(ip_addresses) ++ util.no_matching_interface_for_ip_address_warning(ip_addresses) + + if not options.forward_policy: + # user did not specify policy, derive it: default is 'first' but +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index d2283af20485fd5d66bfd3cc49059d08d1802575..3521d555914714351160213df60ed9167ac6e370 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -276,7 +276,7 @@ def read_ip_addresses(): + if not ip: + break + try: +- ip_parsed = ipautil.CheckedIPAddress(ip, match_local=True) ++ ip_parsed = ipautil.CheckedIPAddress(ip) + except Exception as e: + print("Error: Invalid IP Address %s: %s" % (ip, e)) + continue +@@ -585,7 +585,7 @@ def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses): + if len(hostaddr): + for ha in hostaddr: + try: +- ips.append(ipautil.CheckedIPAddress(ha, match_local=True)) ++ ips.append(ipautil.CheckedIPAddress(ha, match_local=False)) + except ValueError as e: + root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e)) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 9dcf903f4582740f007c049fae3ec247ddf52aef..7eb291e07c00e0407ce534c3d4088e6f6378260f 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -29,6 +29,7 @@ from ipalib.util import ( + validate_domain_name, + network_ip_address_warning, + broadcast_ip_address_warning, ++ no_matching_interface_for_ip_address_warning, + ) + import ipaclient.install.ntpconf + from ipaserver.install import ( +@@ -617,6 +618,7 @@ def install_check(installer): + # check addresses here, dns module is doing own check + network_ip_address_warning(ip_addresses) + broadcast_ip_address_warning(ip_addresses) ++ no_matching_interface_for_ip_address_warning(ip_addresses) + + if options.setup_adtrust: + adtrust.install_check(False, options, api) +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 20eaf98397101b49c751c325afc0591e0babcc18..6620f0222f9d38112ce0d0fd72381e5673921cba 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -35,6 +35,7 @@ from ipalib.config import Env + from ipalib.util import ( + network_ip_address_warning, + broadcast_ip_address_warning, ++ no_matching_interface_for_ip_address_warning, + ) + from ipaclient.install.client import configure_krb5_conf, purge_host_keytab + from ipaserver.install import ( +@@ -1285,6 +1286,7 @@ def promote_check(installer): + # check addresses here, dns module is doing own check + network_ip_address_warning(config.ips) + broadcast_ip_address_warning(config.ips) ++ no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: + adtrust.install_check(False, options, remote_api) +-- +2.9.4 + diff --git a/SOURCES/0185-ipa-kdb-use-canonical-principal-in-certauth-plugin.patch b/SOURCES/0185-ipa-kdb-use-canonical-principal-in-certauth-plugin.patch new file mode 100644 index 0000000..4fa3e14 --- /dev/null +++ b/SOURCES/0185-ipa-kdb-use-canonical-principal-in-certauth-plugin.patch @@ -0,0 +1,33 @@ +From 25033eb499af95f458bd975eddd954c4b6a086ff Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 1 Jun 2017 18:17:53 +0200 +Subject: [PATCH] ipa-kdb: use canonical principal in certauth plugin + +Currently the certauth plugin use the unmodified principal from the +request to lookup the user. This might fail if e.g. enterprise +principals are use. With this patch the canonical principal form the kdc +entry is used. + +Resolves https://pagure.io/freeipa/issue/6993 + +Reviewed-By: David Kupka +--- + daemons/ipa-kdb/ipa_kdb_certauth.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_certauth.c b/daemons/ipa-kdb/ipa_kdb_certauth.c +index da9a9cb87feca68ee591da70a3239dc86749bae5..66c2d08cbb9d23a8891b9cb6ca238925530eb40c 100644 +--- a/daemons/ipa-kdb/ipa_kdb_certauth.c ++++ b/daemons/ipa-kdb/ipa_kdb_certauth.c +@@ -284,7 +284,7 @@ static krb5_error_code ipa_certauth_authorize(krb5_context context, + } + } + +- ret = krb5_unparse_name(context, princ, &principal); ++ ret = krb5_unparse_name(context, db_entry->princ, &principal); + if (ret != 0) { + ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; + goto done; +-- +2.9.4 + diff --git a/SOURCES/0186-Bump-version-of-python-gssapi.patch b/SOURCES/0186-Bump-version-of-python-gssapi.patch new file mode 100644 index 0000000..546067e --- /dev/null +++ b/SOURCES/0186-Bump-version-of-python-gssapi.patch @@ -0,0 +1,66 @@ +From b117507de5cc68282b156a8e4751ef2cb5db74a9 Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Wed, 7 Jun 2017 10:11:39 +0200 +Subject: [PATCH] Bump version of python-gssapi + +Complete fixing of the bug requires fix on python-gssapi side. +That fix is included in version 1.2.0-5. + +Fixes: https://pagure.io/freeipa/issue/6796 +Reviewed-By: Martin Basti +--- + freeipa.spec.in | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index ae77a9a23645c1490c32195203e2c4f665783a80..d7f8d11ec553cfe299937e1e5f8cc27caed32b08 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -165,7 +165,7 @@ BuildRequires: python3-wheel + BuildRequires: samba-python + # 1.4: the version where Certificate.serial changed to .serial_number + BuildRequires: python2-cryptography >= 1.4 +-BuildRequires: python-gssapi >= 1.2.0 ++BuildRequires: python-gssapi >= 1.2.0-5 + BuildRequires: pylint >= 1.6 + # workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1096506 + BuildRequires: python2-polib +@@ -282,7 +282,7 @@ Requires: mod_session + # 0.9.9: https://github.com/adelton/mod_lookup_identity/pull/3 + Requires: mod_lookup_identity >= 0.9.9 + Requires: python-ldap >= 2.4.15 +-Requires: python-gssapi >= 1.2.0 ++Requires: python-gssapi >= 1.2.0-5 + Requires: acl + Requires: systemd-units >= 38 + Requires(pre): shadow-utils +@@ -349,7 +349,7 @@ Requires: python2-ipaclient = %{version}-%{release} + Requires: python-custodia >= 0.3.1 + Requires: python-ldap >= 2.4.15 + Requires: python-lxml +-Requires: python-gssapi >= 1.2.0 ++Requires: python-gssapi >= 1.2.0-5 + Requires: python-sssdconfig + Requires: python-pyasn1 + Requires: dbus-python +@@ -502,7 +502,7 @@ Requires: certmonger >= 0.78 + Requires: nss-tools + Requires: bind-utils + Requires: oddjob-mkhomedir +-Requires: python-gssapi >= 1.2.0 ++Requires: python-gssapi >= 1.2.0-5 + Requires: libsss_autofs + Requires: autofs + Requires: libnfsidmap +@@ -639,7 +639,7 @@ Provides: python2-ipaplatform = %{version}-%{release} + %{?python_provide:%python_provide python2-ipaplatform} + %{!?python_provide:Provides: python-ipaplatform = %{version}-%{release}} + Requires: %{name}-common = %{version}-%{release} +-Requires: python-gssapi >= 1.2.0 ++Requires: python-gssapi >= 1.2.0-5 + Requires: gnupg + Requires: keyutils + Requires: pyOpenSSL +-- +2.9.4 + diff --git a/SOURCES/0187-Add-code-to-be-able-to-set-default-kinit-lifetime.patch b/SOURCES/0187-Add-code-to-be-able-to-set-default-kinit-lifetime.patch new file mode 100644 index 0000000..438cf23 --- /dev/null +++ b/SOURCES/0187-Add-code-to-be-able-to-set-default-kinit-lifetime.patch @@ -0,0 +1,84 @@ +From 1e37dbe2c41ff0339873cd2347cb90c39a59d8ed Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 5 Jun 2017 09:50:22 -0400 +Subject: [PATCH] Add code to be able to set default kinit lifetime + +This is done by setting the kinit_lifetime option in default.conf +to a value that can be passed in with the -l option syntax of kinit. + +https://pagure.io/freeipa/issue/7001 + +Signed-off-by: Simo Sorce +Reviewed-By: Pavel Vomacka +Reviewed-By: Alexander Bokovoy +--- + ipalib/constants.py | 1 + + ipalib/install/kinit.py | 5 ++++- + ipaserver/rpcserver.py | 3 ++- + pylint_plugins.py | 1 + + 4 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/ipalib/constants.py b/ipalib/constants.py +index f8a194c1f559db9aeffef058578d700cde41fd0b..5adff97fbd6ad8ab4cfa5322481be2d9056f925a 100644 +--- a/ipalib/constants.py ++++ b/ipalib/constants.py +@@ -153,6 +153,7 @@ DEFAULT_CONFIG = ( + ('session_auth_duration', '20 minutes'), + # How a session expiration is computed, see SessionManager.set_session_expiration_time() + ('session_duration_type', 'inactivity_timeout'), ++ ('kinit_lifetime', None), + + # Debugging: + ('verbose', 0), +diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py +index 73471f103eabfe39580c8fbd0665157f635fa5c5..91ea5132aa1cb1e192af46b4896d55670e375f7a 100644 +--- a/ipalib/install/kinit.py ++++ b/ipalib/install/kinit.py +@@ -63,7 +63,7 @@ def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1): + + def kinit_password(principal, password, ccache_name, config=None, + armor_ccache_name=None, canonicalize=False, +- enterprise=False): ++ enterprise=False, lifetime=None): + """ + perform interactive kinit as principal using password. If using FAST for + web-based authentication, use armor_ccache_path to specify http service +@@ -76,6 +76,9 @@ def kinit_password(principal, password, ccache_name, config=None, + % armor_ccache_name) + args.extend(['-T', armor_ccache_name]) + ++ if lifetime: ++ args.extend(['-l', lifetime]) ++ + if canonicalize: + root_logger.debug("Requesting principal canonicalization") + args.append('-C') +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 32f286148bbdf294f941116b4bdca85714a52837..2990df25985eab63d4bcfc8edf7f2b12da3e9832 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -969,7 +969,8 @@ class login_password(Backend, KerberosSession): + password, + ccache_name, + armor_ccache_name=armor_path, +- enterprise=True) ++ enterprise=True, ++ lifetime=self.api.env.kinit_lifetime) + + if armor_path: + self.debug('Cleanup the armor ccache') +diff --git a/pylint_plugins.py b/pylint_plugins.py +index db80efeba8824eb221d988bb494400da173675a9..550f269b308b6c5b21cb13404040aa0934381f0e 100644 +--- a/pylint_plugins.py ++++ b/pylint_plugins.py +@@ -67,6 +67,7 @@ fake_api_env = {'env': [ + 'realm', + 'session_auth_duration', + 'session_duration_type', ++ 'kinit_lifetime', + ]} + + # this is due ipaserver.rpcserver.KerberosSession where api is undefined +-- +2.9.4 + diff --git a/SOURCES/0188-Revert-setting-sessionMaxAge-for-old-clients.patch b/SOURCES/0188-Revert-setting-sessionMaxAge-for-old-clients.patch new file mode 100644 index 0000000..4f69baa --- /dev/null +++ b/SOURCES/0188-Revert-setting-sessionMaxAge-for-old-clients.patch @@ -0,0 +1,44 @@ +From f231d5ceb283723c42f6c15210c76f28324c2e15 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Tue, 6 Jun 2017 09:04:58 -0400 +Subject: [PATCH] Revert setting sessionMaxAge for old clients + +Older clients have issues properly parsing cookies and the sessionMaxAge +setting is one of those that breaks them. +Comment out the setting and add a comment that explains why it is not +set by default. + +https://pagure.io/freeipa/issue/7001 + +Signed-off-by: Simo Sorce +Reviewed-By: Pavel Vomacka +Reviewed-By: Alexander Bokovoy +--- + install/conf/ipa.conf | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf +index a7ca5ce715e55960b8edd307cdbe41dcbd6b29ca..01bf9a4f97fc0cf197c0ad12743affa597b54911 100644 +--- a/install/conf/ipa.conf ++++ b/install/conf/ipa.conf +@@ -1,5 +1,5 @@ + # +-# VERSION 26 - DO NOT REMOVE THIS LINE ++# VERSION 27 - DO NOT REMOVE THIS LINE + # + # This file may be overwritten on upgrades. + # +@@ -77,7 +77,9 @@ WSGIScriptReloading Off + Session On + SessionCookieName ipa_session path=/ipa;httponly;secure; + SessionHeader IPASESSION +- SessionMaxAge 1800 ++ # Uncomment the following to have shorter sessions, but beware this may break ++ # old IPA client tols that incorrectly parse cookies. ++ # SessionMaxAge 1800 + GssapiSessionKey file:/etc/httpd/alias/ipasession.key + + GssapiImpersonate On +-- +2.9.4 + diff --git a/SOURCES/0189-Extend-the-advice-printing-code-by-some-useful-abstr.patch b/SOURCES/0189-Extend-the-advice-printing-code-by-some-useful-abstr.patch new file mode 100644 index 0000000..71fe9f8 --- /dev/null +++ b/SOURCES/0189-Extend-the-advice-printing-code-by-some-useful-abstr.patch @@ -0,0 +1,93 @@ +From 17f988f0524ff682a95fe6a4be55b49ea7a0a419 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Mon, 5 Jun 2017 16:59:25 +0200 +Subject: [PATCH] Extend the advice printing code by some useful abstractions + +The advise printing code was augmented by methods that simplify +generating bash snippets that report errors or failed commands. + +https://pagure.io/freeipa/issue/6982 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/advise/base.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 61 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/advise/base.py b/ipaserver/advise/base.py +index 40dabd0426719c5a791fee5be81a998e1c45854b..ba412b872472580cd32baf2a326a14edb951cab1 100644 +--- a/ipaserver/advise/base.py ++++ b/ipaserver/advise/base.py +@@ -94,8 +94,67 @@ class _AdviceOutput(object): + if self.options.verbose: + self.comment('DEBUG: ' + line) + +- def command(self, line): +- self.content.append(line) ++ def command(self, line, indent_spaces=0): ++ self.content.append( ++ '{}{}'.format(self._format_indent(indent_spaces), line)) ++ ++ def _format_indent(self, num_spaces): ++ return ' ' * num_spaces ++ ++ def echo_error(self, error_message, indent_spaces=0): ++ self.command( ++ self._format_error(error_message), indent_spaces=indent_spaces) ++ ++ def _format_error(self, error_message): ++ return 'echo "{}" >&2'.format(error_message) ++ ++ def exit_on_failed_command(self, command_to_run, ++ error_message_lines, indent_spaces=0): ++ self.command(command_to_run, indent_spaces=indent_spaces) ++ self.exit_on_predicate( ++ '[ "$?" -ne "0" ]', ++ error_message_lines, ++ indent_spaces=indent_spaces) ++ ++ def exit_on_nonroot_euid(self): ++ self.exit_on_predicate( ++ '[ "$(id -u)" -ne "0" ]', ++ ["This script has to be run as root user"] ++ ) ++ ++ def exit_on_predicate(self, predicate, error_message_lines, ++ indent_spaces=0): ++ commands_to_run = [ ++ self._format_error(error_message_line) ++ for error_message_line in error_message_lines] ++ ++ commands_to_run.append('exit 1') ++ self.commands_on_predicate( ++ predicate, ++ commands_to_run, ++ indent_spaces=indent_spaces) ++ ++ def commands_on_predicate(self, predicate, commands_to_run_when_true, ++ commands_to_run_when_false=None, ++ indent_spaces=0): ++ if_command = 'if {}'.format(predicate) ++ self.command(if_command, indent_spaces=indent_spaces) ++ self.command('then', indent_spaces=indent_spaces) ++ ++ indented_block_spaces = indent_spaces + 2 ++ ++ for command_to_run_when_true in commands_to_run_when_true: ++ self.command( ++ command_to_run_when_true, indent_spaces=indented_block_spaces) ++ ++ if commands_to_run_when_false is not None: ++ self.command("else", indent_spaces=indent_spaces) ++ for command_to_run_when_false in commands_to_run_when_false: ++ self.command( ++ command_to_run_when_false, ++ indent_spaces=indented_block_spaces) ++ ++ self.command('fi', indent_spaces=indent_spaces) + + + class Advice(Plugin): +-- +2.9.4 + diff --git a/SOURCES/0190-Prepare-advise-plugin-for-smart-card-auth-configurat.patch b/SOURCES/0190-Prepare-advise-plugin-for-smart-card-auth-configurat.patch new file mode 100644 index 0000000..b17a1e6 --- /dev/null +++ b/SOURCES/0190-Prepare-advise-plugin-for-smart-card-auth-configurat.patch @@ -0,0 +1,293 @@ +From f16d9533c7917a8a57a9148dee61df3b12a5e767 Mon Sep 17 00:00:00 2001 +From: Martin Babinsky +Date: Fri, 2 Jun 2017 18:36:29 +0200 +Subject: [PATCH] Prepare advise plugin for smart card auth configuration + +The plugin contains recipes for configuring Smart Card authentication +on FreeIPA server and enrolled client. + +https://www.freeipa.org/page/V4/Smartcard_authentication_ipa-advise_recipes +https://pagure.io/freeipa/issue/6982 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/advise/plugins/smart_card_auth.py | 266 ++++++++++++++++++++++++++++ + 1 file changed, 266 insertions(+) + create mode 100644 ipaserver/advise/plugins/smart_card_auth.py + +diff --git a/ipaserver/advise/plugins/smart_card_auth.py b/ipaserver/advise/plugins/smart_card_auth.py +new file mode 100644 +index 0000000000000000000000000000000000000000..5859e350939fdba0a8b258de5285dd10c7b3bc23 +--- /dev/null ++++ b/ipaserver/advise/plugins/smart_card_auth.py +@@ -0,0 +1,266 @@ ++# ++# Copyright (C) 2017 FreeIPA Contributors see COPYING for license ++# ++ ++from ipalib.plugable import Registry ++from ipaplatform.paths import paths ++from ipaserver.advise.base import Advice ++from ipaserver.install.httpinstance import NSS_OCSP_ENABLED ++ ++register = Registry() ++ ++ ++@register() ++class config_server_for_smart_card_auth(Advice): ++ """ ++ Configures smart card authentication via Kerberos (PKINIT) and for WebUI ++ """ ++ ++ description = ("Instructions for enabling Smart Card authentication on " ++ " a single FreeIPA server. Includes Apache configuration, " ++ "enabling PKINIT on KDC and configuring WebUI to accept " ++ "Smart Card auth requests. To enable the feature in the " ++ "whole topology you have to run the script on each master") ++ ++ nss_conf = paths.HTTPD_NSS_CONF ++ nss_ocsp_directive = 'NSSOCSP' ++ nss_nickname_directive = 'NSSNickname' ++ ++ def get_info(self): ++ self.log.exit_on_nonroot_euid() ++ self.check_ccache_not_empty() ++ self.check_hostname_is_in_masters() ++ self.resolve_ipaca_records() ++ self.enable_nss_ocsp() ++ self.mark_httpd_cert_as_trusted() ++ self.restart_httpd() ++ self.record_httpd_ocsp_status() ++ self.check_and_enable_pkinit() ++ self.enable_ok_to_auth_as_delegate_on_http_principal() ++ ++ def check_ccache_not_empty(self): ++ self.log.comment('Check whether the credential cache is not empty') ++ self.log.exit_on_failed_command( ++ 'klist', ++ [ ++ "Credential cache is empty", ++ 'Use kinit as privileged user to obtain Kerberos credentials' ++ ]) ++ ++ def check_hostname_is_in_masters(self): ++ self.log.comment('Check whether the host is IPA master') ++ self.log.exit_on_failed_command( ++ 'ipa server-find $(hostname -f)', ++ ["This script can be run on IPA master only"]) ++ ++ def resolve_ipaca_records(self): ++ ipa_domain_name = self.api.env.domain ++ ++ self.log.comment('make sure bind-utils are installed so that we can ' ++ 'dig for ipa-ca records') ++ self.log.exit_on_failed_command( ++ 'yum install -y bind-utils', ++ ['Failed to install bind-utils']) ++ ++ self.log.comment('make sure ipa-ca records are resolvable, ' ++ 'otherwise error out and instruct') ++ self.log.comment('the user to update the DNS infrastructure') ++ self.log.command('ipaca_records=$(dig +short ' ++ 'ipa-ca.{})'.format(ipa_domain_name)) ++ ++ self.log.exit_on_predicate( ++ '[ -z "$ipaca_records" ]', ++ [ ++ 'Can not resolve ipa-ca records for ${domain_name}', ++ 'Please make sure to update your DNS infrastructure with ', ++ 'ipa-ca record pointing to IP addresses of IPA CA masters' ++ ]) ++ ++ def enable_nss_ocsp(self): ++ self.log.comment('look for the OCSP directive in nss.conf') ++ self.log.comment(' if it is present, switch it on') ++ self.log.comment( ++ 'if it is absent, append it to the end of VirtualHost section') ++ predicate = self._interpolate_ocsp_directive_file_into_command( ++ "grep -q '{directive} ' {filename}") ++ ++ self.log.commands_on_predicate( ++ predicate, ++ [ ++ self._interpolate_ocsp_directive_file_into_command( ++ " sed -i.ipabkp -r " ++ "'s/^#*[[:space:]]*{directive}[[:space:]]+(on|off)$" ++ "/{directive} on/' {filename}") ++ ], ++ commands_to_run_when_false=[ ++ self._interpolate_ocsp_directive_file_into_command( ++ " sed -i.ipabkp '/<\/VirtualHost>/i {directive} on' " ++ "{filename}") ++ ] ++ ) ++ ++ def _interpolate_ocsp_directive_file_into_command(self, fmt_line): ++ return self._format_command( ++ fmt_line, self.nss_ocsp_directive, self.nss_conf) ++ ++ def _format_command(self, fmt_line, directive, filename): ++ return fmt_line.format(directive=directive, filename=filename) ++ ++ def mark_httpd_cert_as_trusted(self): ++ self.log.comment( ++ 'mark the HTTP certificate as trusted peer to avoid ' ++ 'chicken-egg startup issue') ++ self.log.command( ++ self._interpolate_nssnickname_directive_file_into_command( ++ "http_cert_nick=$(grep '{directive}' {filename} |" ++ " cut -f 2 -d ' ')")) ++ ++ self.log.exit_on_failed_command( ++ 'certutil -M -n $http_cert_nick -d "{}" -t "Pu,u,u"'.format( ++ paths.HTTPD_ALIAS_DIR), ++ ['Can not set trust flags on HTTP certificate']) ++ ++ def _interpolate_nssnickname_directive_file_into_command(self, fmt_line): ++ return self._format_command( ++ fmt_line, self.nss_nickname_directive, self.nss_conf) ++ ++ def restart_httpd(self): ++ self.log.comment('finally restart apache') ++ self.log.command('systemctl restart httpd') ++ ++ def record_httpd_ocsp_status(self): ++ self.log.comment('store the OCSP upgrade state') ++ self.log.command( ++ "python -c 'from ipaserver.install import sysupgrade; " ++ "sysupgrade.set_upgrade_state(\"httpd\", " ++ "\"{}\", True)'".format(NSS_OCSP_ENABLED)) ++ ++ def check_and_enable_pkinit(self): ++ self.log.comment('check whether PKINIT is configured on the master') ++ self.log.command( ++ "if ipa-pkinit-manage status | grep -q 'enabled'") ++ self.log.command('then') ++ self.log.command(' echo "PKINIT already enabled"') ++ self.log.command('else') ++ self.log.exit_on_failed_command( ++ 'ipa-pkinit-manage enable', ++ ['Failed to issue PKINIT certificates to local KDC'], ++ indent_spaces=2) ++ self.log.command('fi') ++ ++ def enable_ok_to_auth_as_delegate_on_http_principal(self): ++ self.log.comment('Enable OK-AS-DELEGATE flag on the HTTP principal') ++ self.log.comment('This enables smart card login to WebUI') ++ self.log.command( ++ 'output=$(ipa service-mod HTTP/$(hostname -f) ' ++ '--ok-to-auth-as-delegate=True 2>&1)') ++ self.log.exit_on_predicate( ++ '[ "$?" -ne "0" -a ' ++ '-z "$(echo $output | grep \'no modifications\')" ]', ++ ["Failed to set OK_AS_AUTH_AS_DELEGATE flag on HTTP principal"] ++ ) ++ ++ ++@register() ++class config_client_for_smart_card_auth(Advice): ++ """ ++ Configures smart card authentication on FreeIPA client ++ """ ++ smart_card_ca_cert_variable_name = "SC_CA_CERT" ++ ++ description = ("Instructions for enabling Smart Card authentication on " ++ " a single FreeIPA client. Configures Smart Card daemon, " ++ "set the system-wide trust store and configures SSSD to " ++ "allow smart card logins to desktop") ++ ++ opensc_module_name = "OpenSC" ++ pkcs11_shared_lib = '/usr/lib64/opensc-pkcs11.so' ++ smart_card_service_file = 'pcscd.service' ++ smart_card_socket = 'pcscd.socket' ++ systemwide_nssdb = paths.NSS_DB_DIR ++ ++ def get_info(self): ++ self.log.exit_on_nonroot_euid() ++ self.check_and_set_ca_cert_path() ++ self.check_and_remove_pam_pkcs11() ++ self.install_opensc_and_dconf_packages() ++ self.start_enable_smartcard_daemon() ++ self.add_pkcs11_module_to_systemwide_db() ++ self.upload_smartcard_ca_certificate_to_systemwide_db() ++ self.run_authconfig_to_configure_smart_card_auth() ++ self.restart_sssd() ++ ++ def check_and_set_ca_cert_path(self): ++ ca_path_variable = self.smart_card_ca_cert_variable_name ++ self.log.command("{}=$1".format(ca_path_variable)) ++ self.log.exit_on_predicate( ++ '[ -z "${}" ]'.format(ca_path_variable), ++ ['You need to provide the path to the PEM file containing CA ' ++ 'signing the Smart Cards'] ++ ) ++ self.log.exit_on_predicate( ++ '[ ! -f "${}" ]'.format(ca_path_variable), ++ ['Invalid CA certificate filename: ${}'.format(ca_path_variable), ++ 'Please check that the path exists and is a valid file'] ++ ) ++ ++ def check_and_remove_pam_pkcs11(self): ++ self.log.command('rpm -qi pam_pkcs11 > /dev/null') ++ self.log.commands_on_predicate( ++ '[ "$?" -eq "0" ]', ++ [ ++ 'yum remove -y pam_pkcs11' ++ ] ++ ) ++ ++ def install_opensc_and_dconf_packages(self): ++ self.log.comment( ++ 'authconfig often complains about missing dconf, ' ++ 'install it explicitly') ++ self.log.exit_on_failed_command( ++ 'yum install -y {} dconf'.format(self.opensc_module_name.lower()), ++ ['Could not install OpenSC package'] ++ ) ++ ++ def start_enable_smartcard_daemon(self): ++ self.log.command( ++ 'systemctl start {service} {socket} ' ++ '&& systemctl enable {service} {socket}'.format( ++ service=self.smart_card_service_file, ++ socket=self.smart_card_socket)) ++ ++ def add_pkcs11_module_to_systemwide_db(self): ++ module_name = self.opensc_module_name ++ nssdb = self.systemwide_nssdb ++ shared_lib = self.pkcs11_shared_lib ++ ++ self.log.commands_on_predicate( ++ 'modutil -dbdir {} -list | grep -q {}'.format( ++ nssdb, module_name), ++ [ ++ 'echo "{} PKCS#11 module already configured"'.format( ++ module_name) ++ ], ++ commands_to_run_when_false=[ ++ 'echo "" | modutil -dbdir {} -add "{}" -libfile {}'.format( ++ nssdb, module_name, shared_lib), ++ ] ++ ) ++ ++ def upload_smartcard_ca_certificate_to_systemwide_db(self): ++ self.log.command( ++ 'certutil -d {} -A -i ${} -n "Smart Card CA" -t CT,C,C'.format( ++ self.systemwide_nssdb, self.smart_card_ca_cert_variable_name ++ ) ++ ) ++ ++ def run_authconfig_to_configure_smart_card_auth(self): ++ self.log.exit_on_failed_command( ++ 'authconfig --enablesmartcard --smartcardmodule=sssd --updateall', ++ [ ++ 'Failed to configure Smart Card authentication in SSSD' ++ ] ++ ) ++ ++ def restart_sssd(self): ++ self.log.command('systemctl restart sssd.service') +-- +2.9.4 + diff --git a/SOURCES/0191-trust-mod-allow-modifying-list-of-UPNs-of-a-trusted-.patch b/SOURCES/0191-trust-mod-allow-modifying-list-of-UPNs-of-a-trusted-.patch new file mode 100644 index 0000000..80a1388 --- /dev/null +++ b/SOURCES/0191-trust-mod-allow-modifying-list-of-UPNs-of-a-trusted-.patch @@ -0,0 +1,93 @@ +From 4df20255c1738526696ea72af6fc70e9c6aa6694 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 12 Jun 2017 11:05:06 +0300 +Subject: [PATCH] trust-mod: allow modifying list of UPNs of a trusted forest + +There are two ways for maintaining user principal names (UPNs) in Active +Directory: + - associate UPN suffixes with the forest root and then allow for each + user account to choose UPN suffix for logon + - directly modify userPrincipalName attribute in LDAP + +Both approaches lead to the same result: AD DC accepts user@UPN-Suffix +as a proper principal in AS-REQ and TGS-REQ. + +The latter (directly modify userPrincipalName) case has a consequence +that this UPN suffix is not visible via netr_DsRGetForestTrustInformation +DCE RPC call. As result, FreeIPA KDC will not know that a particular UPN +suffix does belong to a trusted Active Directory forest. As result, SSSD +will not be able to authenticate and validate this user from a trusted +Active Directory forest. + +This is especially true for one-word UPNs which otherwise wouldn't work +properly on Kerberos level for both FreeIPA and Active Directory. + +Administrators are responsible for amending the list of UPNs associated +with the forest in this case. With this commit, an option is added to +'ipa trust-mod' that allows specifying arbitrary UPN suffixes to a +trusted forest root. + +As with all '-mod' commands, the change replaces existing UPNs when +applied, so administrators are responsible to specify all of them: + + ipa trust-mod ad.test --upn-suffixes={existing.upn,another_upn,new} + +Fixes: https://pagure.io/freeipa/issue/7015 +Reviewed-By: Martin Babinsky +--- + API.txt | 3 ++- + VERSION.m4 | 4 ++-- + ipaserver/plugins/trust.py | 3 ++- + 3 files changed, 6 insertions(+), 4 deletions(-) + +diff --git a/API.txt b/API.txt +index 6511ad8d1cb4dc9079628fc058312f31aaec624d..86229156adfba829a46b6a831ad6843cc1a17d6a 100644 +--- a/API.txt ++++ b/API.txt +@@ -5769,11 +5769,12 @@ output: ListOfEntries('result') + output: Output('summary', type=[, ]) + output: Output('truncated', type=[]) + command: trust_mod/1 +-args: 1,9,3 ++args: 1,10,3 + arg: Str('cn', cli_name='realm') + option: Str('addattr*', cli_name='addattr') + option: Flag('all', autofill=True, cli_name='all', default=False) + option: Str('delattr*', cli_name='delattr') ++option: Str('ipantadditionalsuffixes*', autofill=False, cli_name='upn_suffixes') + option: Str('ipantsidblacklistincoming*', autofill=False, cli_name='sid_blacklist_incoming') + option: Str('ipantsidblacklistoutgoing*', autofill=False, cli_name='sid_blacklist_outgoing') + option: Flag('raw', autofill=True, cli_name='raw', default=False) +diff --git a/VERSION.m4 b/VERSION.m4 +index 8aa3ef03f352cd176579c5d5848ed9550f22105d..25aaa1dd0e3c2868e63300dec7fe9228f1ebcb43 100644 +--- a/VERSION.m4 ++++ b/VERSION.m4 +@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000) + # # + ######################################################## + define(IPA_API_VERSION_MAJOR, 2) +-define(IPA_API_VERSION_MINOR, 227) +-# Last change: Add `pkinit-status` command ++define(IPA_API_VERSION_MINOR, 228) ++# Last change: Expose ipaNTAdditionalSuffixes in trust-mod + + + ######################################################## +diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py +index 075b39dcc33a79f3e73e8e1e9e31ebbef17618fe..d0bbfbc47ca65c9c5229685fc9d202c293fe41cd 100644 +--- a/ipaserver/plugins/trust.py ++++ b/ipaserver/plugins/trust.py +@@ -553,8 +553,9 @@ class trust(LDAPObject): + flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, + ), + Str('ipantadditionalsuffixes*', ++ cli_name='upn_suffixes', + label=_('UPN suffixes'), +- flags={'no_create', 'no_update', 'no_search'}, ++ flags={'no_create', 'no_search'}, + ), + ) + +-- +2.9.4 + diff --git a/SOURCES/0192-WebUI-add-support-for-changing-trust-UPN-suffixes.patch b/SOURCES/0192-WebUI-add-support-for-changing-trust-UPN-suffixes.patch new file mode 100644 index 0000000..2e188cd --- /dev/null +++ b/SOURCES/0192-WebUI-add-support-for-changing-trust-UPN-suffixes.patch @@ -0,0 +1,32 @@ +From 4ec1a4fd564bff73c37810bd5326c9382e3a26bf Mon Sep 17 00:00:00 2001 +From: Pavel Vomacka +Date: Mon, 12 Jun 2017 13:18:44 +0200 +Subject: [PATCH] WebUI: add support for changing trust UPN suffixes + +It is now possible to change UPN suffixes in WebUI. This change +allows another way to changing UPN suffixes for AD users. + +https://pagure.io/freeipa/issue/7015 + +Reviewed-By: Alexander Bokovoy +--- + install/ui/src/freeipa/trust.js | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/install/ui/src/freeipa/trust.js b/install/ui/src/freeipa/trust.js +index 39e79ebef1c1fb3cb730d9304c46862ec0d0e651..ff019cab3070312b90e14e08a9070c353b1e7f71 100644 +--- a/install/ui/src/freeipa/trust.js ++++ b/install/ui/src/freeipa/trust.js +@@ -147,8 +147,7 @@ return { + fields: [ + { + $type: 'multivalued', +- name: 'ipantadditionalsuffixes', +- read_only: true ++ name: 'ipantadditionalsuffixes' + } + ] + }, +-- +2.9.4 + diff --git a/SOURCES/0193-kra-promote-Get-ticket-before-calling-custodia.patch b/SOURCES/0193-kra-promote-Get-ticket-before-calling-custodia.patch new file mode 100644 index 0000000..9e09b32 --- /dev/null +++ b/SOURCES/0193-kra-promote-Get-ticket-before-calling-custodia.patch @@ -0,0 +1,59 @@ +From efd08380bbdda59a63afd584bc4c0ef3426b14ce Mon Sep 17 00:00:00 2001 +From: David Kupka +Date: Wed, 14 Jun 2017 15:39:58 +0200 +Subject: [PATCH] kra: promote: Get ticket before calling custodia + +When installing second (or consequent) KRA instance keys are retrieved +using custodia. Custodia checks that the keys are synchronized in +master's directory server and the check uses GSSAPI and therefore fails +if there's no ticket in ccache. + +https://pagure.io/freeipa/issue/7020 + +Reviewed-By: Stanislav Laznicka +--- + ipaserver/install/kra.py | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/ipaserver/install/kra.py b/ipaserver/install/kra.py +index f3454061280661d7b0fc2899142da9dc8783841a..3545b301a977f4b7e7801ca1ef87d594bb3ba54f 100644 +--- a/ipaserver/install/kra.py ++++ b/ipaserver/install/kra.py +@@ -10,6 +10,7 @@ import os + import shutil + + from ipalib import api ++from ipalib.install.kinit import kinit_keytab + from ipaplatform import services + from ipaplatform.paths import paths + from ipapython import certdb +@@ -84,13 +85,19 @@ def install(api, replica_config, options): + return + krafile = os.path.join(replica_config.dir, 'kracert.p12') + if options.promote: +- custodia = custodiainstance.CustodiaInstance( +- replica_config.host_name, +- replica_config.realm_name) +- custodia.get_kra_keys( +- replica_config.kra_host_name, +- krafile, +- replica_config.dirman_password) ++ with ipautil.private_ccache(): ++ ccache = os.environ['KRB5CCNAME'] ++ kinit_keytab( ++ 'host/{env.host}@{env.realm}'.format(env=api.env), ++ paths.KRB5_KEYTAB, ++ ccache) ++ custodia = custodiainstance.CustodiaInstance( ++ replica_config.host_name, ++ replica_config.realm_name) ++ custodia.get_kra_keys( ++ replica_config.kra_host_name, ++ krafile, ++ replica_config.dirman_password) + else: + cafile = os.path.join(replica_config.dir, 'cacert.p12') + if not ipautil.file_exists(cafile): +-- +2.9.4 + diff --git a/SOURCES/0194-Fix-local-IP-address-validation.patch b/SOURCES/0194-Fix-local-IP-address-validation.patch new file mode 100644 index 0000000..154d20c --- /dev/null +++ b/SOURCES/0194-Fix-local-IP-address-validation.patch @@ -0,0 +1,45 @@ +From 935029c3192221c480c88b870a507cfac4c4b954 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Tue, 13 Jun 2017 17:03:30 +0200 +Subject: [PATCH] Fix local IP address validation + +Previously bf9886a84393d1d1546db7e49b102e08a16a83e7 match_local has +undesirable side effect that CheckedIPAddress object has set self._net +from local interface. + +However with the recent changes, match_local is usually set to False, +thus this side effect stops happening and default mask per address class +is used. This causes validation error because mask on interface and mask +used for provided IP addresses differ (reporducible only with classless +masks). + +FreeIPA should compare only IP addresses with local addresses without masks + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/ipautil.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index a277ed87473f3c591f34fcc00e1159f3bbfe3e9b..647ee833ae33f246de6d6b13703fac6e20eef7bc 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -216,10 +216,10 @@ class CheckedIPAddress(UnsafeIPAddress): + addr=ifaddr, + netmask=ifdata['netmask'] + )) +- if ifnet == self._net or ( +- self._net is None and ifnet.ip == self): +- self._net = ifnet ++ ++ if ifnet.ip == self: + iface = interface ++ self._net = ifnet + break + + return iface +-- +2.9.4 + diff --git a/SOURCES/0195-ipa-dns-install-remove-check-for-local-ip-address.patch b/SOURCES/0195-ipa-dns-install-remove-check-for-local-ip-address.patch new file mode 100644 index 0000000..adf7bf9 --- /dev/null +++ b/SOURCES/0195-ipa-dns-install-remove-check-for-local-ip-address.patch @@ -0,0 +1,32 @@ +From 09fad2745b3f49192d6d43550ccb82145f223be0 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 14:45:03 +0200 +Subject: [PATCH] ipa-dns-install: remove check for local ip address + +This check was forgotten and will be removed now. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + install/tools/ipa-dns-install | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install +index 5bd0ba6d77335d9fa32ea4269422cb3dd1cfca4a..cb6c5d887f101135ca593ea6d4ed0caf51478a4c 100755 +--- a/install/tools/ipa-dns-install ++++ b/install/tools/ipa-dns-install +@@ -47,7 +47,9 @@ def parse_options(): + default=False, help="print debugging information") + parser.add_option("--ip-address", dest="ip_addresses", metavar="IP_ADDRESS", + default=[], action="append", +- type="ip", ip_local=True, help="Master Server IP Address. This option can be used multiple times") ++ type="ip", ++ help="Master Server IP Address. This option can be used " ++ "multiple times") + parser.add_option("--forwarder", dest="forwarders", action="append", + type="ip", help="Add a DNS forwarder. This option can be used multiple times") + parser.add_option("--no-forwarders", dest="no_forwarders", action="store_true", +-- +2.9.4 + diff --git a/SOURCES/0196-refactor-CheckedIPAddress-class.patch b/SOURCES/0196-refactor-CheckedIPAddress-class.patch new file mode 100644 index 0000000..7c1d745 --- /dev/null +++ b/SOURCES/0196-refactor-CheckedIPAddress-class.patch @@ -0,0 +1,88 @@ +From 8d88b50c3f79e054a039d123fdaf6aa3a5339135 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 14:47:23 +0200 +Subject: [PATCH] refactor CheckedIPAddress class + +Make methods without side effects (setting mask) + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/ipautil.py | 29 ++++++++++++++++++++++------- + 1 file changed, 22 insertions(+), 7 deletions(-) + +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 647ee833ae33f246de6d6b13703fac6e20eef7bc..2c020e3ecbf4d8b969511a6dd9b36ee955ba1f15 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -62,6 +62,12 @@ PROTOCOL_NAMES = { + socket.SOCK_DGRAM: 'udp' + } + ++InterfaceDetails = collections.namedtuple( ++ 'InterfaceDetails', [ ++ 'name', # interface name ++ 'ifnet' # network details of interface ++ ]) ++ + + class UnsafeIPAddress(netaddr.IPAddress): + """Any valid IP address with or without netmask.""" +@@ -161,9 +167,12 @@ class CheckedIPAddress(UnsafeIPAddress): + raise ValueError("cannot use multicast IP address {}".format(addr)) + + if match_local: +- if not self.get_matching_interface(): ++ intf_details = self.get_matching_interface() ++ if not intf_details: + raise ValueError('no network interface matches the IP address ' + 'and netmask {}'.format(addr)) ++ else: ++ self.set_ip_net(intf_details.ifnet) + + if self._net is None: + if self.version == 4: +@@ -193,7 +202,8 @@ class CheckedIPAddress(UnsafeIPAddress): + + def get_matching_interface(self): + """Find matching local interface for address +- :return: Interface name or None if no interface has this address ++ :return: InterfaceDetails named tuple or None if no interface has ++ this address + """ + if self.version == 4: + family = netifaces.AF_INET +@@ -204,7 +214,6 @@ class CheckedIPAddress(UnsafeIPAddress): + "Unsupported address family ({})".format(self.version) + ) + +- iface = None + for interface in netifaces.interfaces(): + for ifdata in netifaces.ifaddresses(interface).get(family, []): + +@@ -218,11 +227,17 @@ class CheckedIPAddress(UnsafeIPAddress): + )) + + if ifnet.ip == self: +- iface = interface +- self._net = ifnet +- break ++ return InterfaceDetails(interface, ifnet) + +- return iface ++ def set_ip_net(self, ifnet): ++ """Set IP Network details for this address. IPNetwork is valid only ++ locally, so this should be set only for local IP addresses ++ ++ :param ifnet: netaddr.IPNetwork object with information about IP ++ network where particula address belongs locally ++ """ ++ assert isinstance(ifnet, netaddr.IPNetwork) ++ self._net = ifnet + + + def valid_ip(addr): +-- +2.9.4 + diff --git a/SOURCES/0197-CheckedIPAddress-remove-match_local-param.patch b/SOURCES/0197-CheckedIPAddress-remove-match_local-param.patch new file mode 100644 index 0000000..6ed40b5 --- /dev/null +++ b/SOURCES/0197-CheckedIPAddress-remove-match_local-param.patch @@ -0,0 +1,141 @@ +From c4482f0441e610c077d550c10b9525f97ea2f984 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 14:54:43 +0200 +Subject: [PATCH] CheckedIPAddress: remove match_local param + +This parameter is unused in code. We are no longer testing if IP address +matches an interface in constructor. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/config.py | 5 ++--- + ipapython/ipautil.py | 10 +--------- + ipaserver/install/installutils.py | 2 +- + ipaserver/plugins/dns.py | 4 ++-- + ipaserver/plugins/host.py | 2 +- + ipatests/test_ipapython/test_ipautil.py | 3 +-- + 6 files changed, 8 insertions(+), 18 deletions(-) + +diff --git a/ipapython/config.py b/ipapython/config.py +index 9db2dcd4dbf3ed0fbe3e3166c3f0c5bae0f1716b..6349892fe88757629129f464401efce64e30f058 100644 +--- a/ipapython/config.py ++++ b/ipapython/config.py +@@ -68,10 +68,9 @@ class IPAFormatter(IndentedHelpFormatter): + def check_ip_option(option, opt, value): + from ipapython.ipautil import CheckedIPAddress + +- ip_local = option.ip_local is True + ip_netmask = option.ip_netmask is True + try: +- return CheckedIPAddress(value, parse_netmask=ip_netmask, match_local=ip_local) ++ return CheckedIPAddress(value, parse_netmask=ip_netmask) + except Exception as e: + raise OptionValueError("option %s: invalid IP address %s: %s" % (opt, value, e)) + +@@ -86,7 +85,7 @@ class IPAOption(Option): + optparse.Option subclass with support of options labeled as + security-sensitive such as passwords. + """ +- ATTRS = Option.ATTRS + ["sensitive", "ip_local", "ip_netmask"] ++ ATTRS = Option.ATTRS + ["sensitive", "ip_netmask"] + TYPES = Option.TYPES + ("ip", "dn") + TYPE_CHECKER = copy(Option.TYPE_CHECKER) + TYPE_CHECKER["ip"] = check_ip_option +diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py +index 2c020e3ecbf4d8b969511a6dd9b36ee955ba1f15..5a6bf5a27d5a6e25c51fbaa6e2b1167652e2735d 100644 +--- a/ipapython/ipautil.py ++++ b/ipapython/ipautil.py +@@ -135,7 +135,7 @@ class CheckedIPAddress(UnsafeIPAddress): + + Reserved or link-local addresses are never accepted. + """ +- def __init__(self, addr, match_local=False, parse_netmask=True, ++ def __init__(self, addr, parse_netmask=True, + allow_loopback=False, allow_multicast=False): + try: + super(CheckedIPAddress, self).__init__(addr) +@@ -166,14 +166,6 @@ class CheckedIPAddress(UnsafeIPAddress): + if not allow_multicast and self.is_multicast(): + raise ValueError("cannot use multicast IP address {}".format(addr)) + +- if match_local: +- intf_details = self.get_matching_interface() +- if not intf_details: +- raise ValueError('no network interface matches the IP address ' +- 'and netmask {}'.format(addr)) +- else: +- self.set_ip_net(intf_details.ifnet) +- + if self._net is None: + if self.version == 4: + self._net = netaddr.IPNetwork( +diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py +index 3521d555914714351160213df60ed9167ac6e370..01930c4de6f0edd16b31aeba1c926fe581e9635b 100644 +--- a/ipaserver/install/installutils.py ++++ b/ipaserver/install/installutils.py +@@ -585,7 +585,7 @@ def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses): + if len(hostaddr): + for ha in hostaddr: + try: +- ips.append(ipautil.CheckedIPAddress(ha, match_local=False)) ++ ips.append(ipautil.CheckedIPAddress(ha)) + except ValueError as e: + root_logger.warning("Invalid IP address %s for %s: %s", ha, host_name, unicode(e)) + +diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py +index f0e6c48f06313def57cdd6a4c7114357c9d8de8a..f01baf515525c43824eddf06abc7af9fef228efe 100644 +--- a/ipaserver/plugins/dns.py ++++ b/ipaserver/plugins/dns.py +@@ -567,7 +567,7 @@ def add_records_for_host_validation(option_name, host, domain, ip_addresses, che + for ip_address in ip_addresses: + try: + ip = CheckedIPAddress( +- ip_address, match_local=False, allow_multicast=True) ++ ip_address, allow_multicast=True) + except Exception as e: + raise errors.ValidationError(name=option_name, error=unicode(e)) + +@@ -599,7 +599,7 @@ def add_records_for_host(host, domain, ip_addresses, add_forward=True, add_rever + + for ip_address in ip_addresses: + ip = CheckedIPAddress( +- ip_address, match_local=False, allow_multicast=True) ++ ip_address, allow_multicast=True) + + if add_forward: + add_forward_record(domain, host, unicode(ip)) +diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py +index 1e1f9d82dfdfcf9e7fef65ce729cd8ee7b76e605..364e5be6002eeb9c5e6b4c594b71f38169598227 100644 +--- a/ipaserver/plugins/host.py ++++ b/ipaserver/plugins/host.py +@@ -245,7 +245,7 @@ def validate_ipaddr(ugettext, ipaddr): + Verify that we have either an IPv4 or IPv6 address. + """ + try: +- CheckedIPAddress(ipaddr, match_local=False) ++ CheckedIPAddress(ipaddr) + except Exception as e: + return unicode(e) + return None +diff --git a/ipatests/test_ipapython/test_ipautil.py b/ipatests/test_ipapython/test_ipautil.py +index 6427935b162b087c55e069cb2a576a7379cbe7a7..9c351bd0ed9cd96488ac74deadf97996668a75d2 100644 +--- a/ipatests/test_ipapython/test_ipautil.py ++++ b/ipatests/test_ipapython/test_ipautil.py +@@ -30,11 +30,10 @@ from ipapython import ipautil + + pytestmark = pytest.mark.tier0 + +- + def make_ipaddress_checker(addr, words=None, prefixlen=None): + def check_ipaddress(): + try: +- ip = ipautil.CheckedIPAddress(addr, match_local=False) ++ ip = ipautil.CheckedIPAddress(addr) + assert ip.words == words and ip.prefixlen == prefixlen + except Exception: + assert words is None and prefixlen is None +-- +2.9.4 + diff --git a/SOURCES/0198-Remove-ip_netmask-from-option-parser.patch b/SOURCES/0198-Remove-ip_netmask-from-option-parser.patch new file mode 100644 index 0000000..38924ef --- /dev/null +++ b/SOURCES/0198-Remove-ip_netmask-from-option-parser.patch @@ -0,0 +1,44 @@ +From dd004f9393f0543c556d417d27b9f652b6fe4c99 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Wed, 14 Jun 2017 15:02:21 +0200 +Subject: [PATCH] Remove ip_netmask from option parser + +ipa-dns-install uses ip_netmask=False --> parse_netmask=False, other installers uses default (parse_netmask=True). +Use this consistent accross all installers. + +Also this option is unused (and shouldn't be used). + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipapython/config.py | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/ipapython/config.py b/ipapython/config.py +index 6349892fe88757629129f464401efce64e30f058..19abfc51ee354d2971be836fa6bad70eea3a6720 100644 +--- a/ipapython/config.py ++++ b/ipapython/config.py +@@ -68,9 +68,8 @@ class IPAFormatter(IndentedHelpFormatter): + def check_ip_option(option, opt, value): + from ipapython.ipautil import CheckedIPAddress + +- ip_netmask = option.ip_netmask is True + try: +- return CheckedIPAddress(value, parse_netmask=ip_netmask) ++ return CheckedIPAddress(value) + except Exception as e: + raise OptionValueError("option %s: invalid IP address %s: %s" % (opt, value, e)) + +@@ -85,7 +84,7 @@ class IPAOption(Option): + optparse.Option subclass with support of options labeled as + security-sensitive such as passwords. + """ +- ATTRS = Option.ATTRS + ["sensitive", "ip_netmask"] ++ ATTRS = Option.ATTRS + ["sensitive"] + TYPES = Option.TYPES + ("ip", "dn") + TYPE_CHECKER = copy(Option.TYPE_CHECKER) + TYPE_CHECKER["ip"] = check_ip_option +-- +2.9.4 + diff --git a/SOURCES/0199-replica-install-add-missing-check-for-non-local-IP-a.patch b/SOURCES/0199-replica-install-add-missing-check-for-non-local-IP-a.patch new file mode 100644 index 0000000..a47f9c4 --- /dev/null +++ b/SOURCES/0199-replica-install-add-missing-check-for-non-local-IP-a.patch @@ -0,0 +1,29 @@ +From 56c6b8432a50c7b857303ffc4345c75171e0ac92 Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 15 Jun 2017 10:26:03 +0200 +Subject: [PATCH] replica install: add missing check for non-local IP address + +Add missing warning for used non-local IP address. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipaserver/install/server/replicainstall.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 6620f0222f9d38112ce0d0fd72381e5673921cba..9e328bf83bbdb2883ba823cb098b70eeaa078403 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -854,6 +854,7 @@ def install_check(installer): + # check addresses here, dns module is doing own check + network_ip_address_warning(config.ips) + broadcast_ip_address_warning(config.ips) ++ no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: + adtrust.install_check(False, options, remote_api) +-- +2.9.4 + diff --git a/SOURCES/0200-Remove-network-and-broadcast-address-warnings.patch b/SOURCES/0200-Remove-network-and-broadcast-address-warnings.patch new file mode 100644 index 0000000..c5d440d --- /dev/null +++ b/SOURCES/0200-Remove-network-and-broadcast-address-warnings.patch @@ -0,0 +1,146 @@ +From 52be5b4d693febdc1fa1fe9d54b1d052a09c347f Mon Sep 17 00:00:00 2001 +From: Martin Basti +Date: Thu, 15 Jun 2017 10:27:55 +0200 +Subject: [PATCH] Remove network and broadcast address warnings + +We cannot reliably determine when an IP Address is network or broadcast. +We allowed to use non-local IP addresses due container use cases, we +don't know subnets of used IP addresses. + +https://pagure.io/freeipa/issue/4317 + +Reviewed-By: David Kupka +--- + ipaclient/install/client.py | 4 ---- + ipalib/util.py | 20 -------------------- + ipaserver/install/dns.py | 2 -- + ipaserver/install/server/install.py | 4 ---- + ipaserver/install/server/replicainstall.py | 10 +--------- + 5 files changed, 1 insertion(+), 39 deletions(-) + +diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py +index 41dae3004d1f4836e79c2048ae0a12f722595ca0..6242c19636168a5b2922f6f6f0e8bc8aa9b4bc80 100644 +--- a/ipaclient/install/client.py ++++ b/ipaclient/install/client.py +@@ -38,8 +38,6 @@ from ipalib.install.kinit import kinit_keytab, kinit_password + from ipalib.install.service import enroll_only, prepare_only + from ipalib.rpc import delete_persistent_client_session_data + from ipalib.util import ( +- broadcast_ip_address_warning, +- network_ip_address_warning, + normalize_hostname, + no_matching_interface_for_ip_address_warning, + verify_host_resolvable, +@@ -1299,8 +1297,6 @@ def update_dns(server, hostname, options): + root_logger.info("Failed to determine this machine's ip address(es).") + return + +- network_ip_address_warning(update_ips) +- broadcast_ip_address_warning(update_ips) + no_matching_interface_for_ip_address_warning(update_ips) + + update_txt = "debug\n" +diff --git a/ipalib/util.py b/ipalib/util.py +index 1bd8495a49b010e7a3ac926dad516ab5f8219b39..31e73230da49a47e8e0fbcba9934f13cef16460e 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -1110,26 +1110,6 @@ def check_principal_realm_in_trust_namespace(api_instance, *keys): + 'namespace')) + + +-def network_ip_address_warning(addr_list): +- for ip in addr_list: +- if ip.is_network_addr(): +- root_logger.warning("IP address %s might be network address", ip) +- # fixme: once when loggers will be fixed, we can remove this +- # print +- print("WARNING: IP address {} might be network address".format(ip), +- file=sys.stderr) +- +- +-def broadcast_ip_address_warning(addr_list): +- for ip in addr_list: +- if ip.is_broadcast_addr(): +- root_logger.warning("IP address %s might be broadcast address", ip) +- # fixme: once when loggers will be fixed, we can remove this +- # print +- print("WARNING: IP address {} might be broadcast address".format( +- ip), file=sys.stderr) +- +- + def no_matching_interface_for_ip_address_warning(addr_list): + for ip in addr_list: + if not ip.get_matching_interface(): +diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py +index 090b79493652566a433da248fa7fd9e33dd2cb72..1c1aac06a18fe3c1f63b5881c7887f6a4cfc9ac2 100644 +--- a/ipaserver/install/dns.py ++++ b/ipaserver/install/dns.py +@@ -264,8 +264,6 @@ def install_check(standalone, api, replica, options, hostname): + ip_addresses = get_server_ip_address(hostname, options.unattended, + True, options.ip_addresses) + +- util.network_ip_address_warning(ip_addresses) +- util.broadcast_ip_address_warning(ip_addresses) + util.no_matching_interface_for_ip_address_warning(ip_addresses) + + if not options.forward_policy: +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index 7eb291e07c00e0407ce534c3d4088e6f6378260f..dced253e7f039dc9d66466bf8bcd777e53919f54 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -27,8 +27,6 @@ from ipalib import api, errors, x509 + from ipalib.constants import DOMAIN_LEVEL_0 + from ipalib.util import ( + validate_domain_name, +- network_ip_address_warning, +- broadcast_ip_address_warning, + no_matching_interface_for_ip_address_warning, + ) + import ipaclient.install.ntpconf +@@ -616,8 +614,6 @@ def install_check(installer): + options.ip_addresses) + + # check addresses here, dns module is doing own check +- network_ip_address_warning(ip_addresses) +- broadcast_ip_address_warning(ip_addresses) + no_matching_interface_for_ip_address_warning(ip_addresses) + + if options.setup_adtrust: +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index 9e328bf83bbdb2883ba823cb098b70eeaa078403..4f28de25bd0adf958187c19edf90de4ba57dd98e 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -32,11 +32,7 @@ from ipaplatform.tasks import tasks + from ipaplatform.paths import paths + from ipalib import api, constants, create_api, errors, rpc, x509 + from ipalib.config import Env +-from ipalib.util import ( +- network_ip_address_warning, +- broadcast_ip_address_warning, +- no_matching_interface_for_ip_address_warning, +-) ++from ipalib.util import no_matching_interface_for_ip_address_warning + from ipaclient.install.client import configure_krb5_conf, purge_host_keytab + from ipaserver.install import ( + adtrust, bindinstance, ca, certs, dns, dsinstance, httpinstance, +@@ -852,8 +848,6 @@ def install_check(installer): + options.ip_addresses) + + # check addresses here, dns module is doing own check +- network_ip_address_warning(config.ips) +- broadcast_ip_address_warning(config.ips) + no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: +@@ -1285,8 +1279,6 @@ def promote_check(installer): + False, options.ip_addresses) + + # check addresses here, dns module is doing own check +- network_ip_address_warning(config.ips) +- broadcast_ip_address_warning(config.ips) + no_matching_interface_for_ip_address_warning(config.ips) + + if options.setup_adtrust: +-- +2.9.4 + diff --git a/SOURCES/0201-ipa-sam-replace-encode_nt_key-with-E_md4hash.patch b/SOURCES/0201-ipa-sam-replace-encode_nt_key-with-E_md4hash.patch new file mode 100644 index 0000000..06623f1 --- /dev/null +++ b/SOURCES/0201-ipa-sam-replace-encode_nt_key-with-E_md4hash.patch @@ -0,0 +1,80 @@ +From 4504cb10cb7bf489be5ce221358b237afc1e52ca Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 16 Jun 2017 16:26:41 +0200 +Subject: [PATCH] ipa-sam: replace encode_nt_key() with E_md4hash() + +Since ipa-sam is running as part of smbd is it safe to use the +E_md4hash() from Samba. This way ipa-sam does not depend on other crypto +libraries which might depend on other rules like e.g. FIPS mode. + +Resolves https://pagure.io/freeipa/issue/7026 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Stanislav Laznicka +--- + daemons/ipa-sam/ipa_sam.c | 27 ++------------------------- + 1 file changed, 2 insertions(+), 25 deletions(-) + +diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c +index 6a29e8e10b4299356b9ead76276eecc8083791a3..59d92f37c9b7104c2fba5bd530b4dbff3ca675db 100644 +--- a/daemons/ipa-sam/ipa_sam.c ++++ b/daemons/ipa-sam/ipa_sam.c +@@ -110,6 +110,7 @@ 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 */ ++bool E_md4hash(const char *passwd, uint8_t p16[16]); /* available in libcliauth-samba4.so */ + + #define LDAP_OBJ_SAMBASAMACCOUNT "ipaNTUserAttrs" + #define LDAP_OBJ_TRUSTED_DOMAIN "ipaNTTrustedDomain" +@@ -2836,11 +2837,7 @@ static bool init_sam_from_td(struct samu *user, struct pdb_trusted_domain *td, + struct dom_sid *g_sid; + char *name; + char *trustpw = NULL; +- char *trustpw_utf8 = NULL; +- char *tmp_str = NULL; +- int ret; + uint8_t nt_key[16]; +- size_t converted_size; + bool res; + char *sid_str; + enum idmap_error_code err; +@@ -2899,19 +2896,7 @@ static bool init_sam_from_td(struct samu *user, struct pdb_trusted_domain *td, + return false; + } + +- if (!push_utf8_talloc(user, &trustpw_utf8, trustpw, &converted_size)) { +- res = false; +- goto done; +- } +- +- tmp_str = talloc_strdup_upper(user, trustpw); +- if (tmp_str == NULL) { +- res = false; +- goto done; +- } +- +- ret = encode_nt_key(trustpw_utf8, nt_key); +- if (ret != 0) { ++ if (!E_md4hash(trustpw, nt_key)) { + res = false; + goto done; + } +@@ -2927,14 +2912,6 @@ done: + memset(trustpw, 0, strlen(trustpw)); + talloc_free(trustpw); + } +- if (trustpw_utf8 != NULL) { +- memset(trustpw_utf8, 0, strlen(trustpw_utf8)); +- talloc_free(trustpw_utf8); +- } +- if (tmp_str != NULL) { +- memset(tmp_str, 0, strlen(tmp_str)); +- talloc_free(tmp_str); +- } + + return res; + } +-- +2.9.4 + diff --git a/SOURCES/0202-ipa_pwd_extop-do-not-generate-NT-hashes-in-FIPS-mode.patch b/SOURCES/0202-ipa_pwd_extop-do-not-generate-NT-hashes-in-FIPS-mode.patch new file mode 100644 index 0000000..32a5ffe --- /dev/null +++ b/SOURCES/0202-ipa_pwd_extop-do-not-generate-NT-hashes-in-FIPS-mode.patch @@ -0,0 +1,102 @@ +From 84be5dc9e72fbf4c85b6f061da94a4316c90d65e Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 16 Jun 2017 17:49:44 +0200 +Subject: [PATCH] ipa_pwd_extop: do not generate NT hashes in FIPS mode + +In FIPS mode NT hashes (aka md4) are not allowed. If FIPS more is +detected we disable NT hashes even is the are allowed by IPA +configuration. + +Resolves https://pagure.io/freeipa/issue/7026 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Stanislav Laznicka +--- + daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c | 53 ++++++++++++++++++------ + 1 file changed, 40 insertions(+), 13 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +index 761f7a8e3e9ee539f97797c98b8719ad752bdcf1..5efadac5b1fd57e5f91a886224fa2f1ab88305ac 100644 +--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c ++++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/common.c +@@ -46,6 +46,8 @@ + /* Type of connection for this operation;*/ + #define LDAP_EXTOP_PASSMOD_CONN_SECURE + ++#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled" ++ + /* Uncomment the following #undef FOR TESTING: + * allows non-SSL connections to use the password change extended op */ + /* #undef LDAP_EXTOP_PASSMOD_CONN_SECURE */ +@@ -62,6 +64,27 @@ static const char *ipapwd_def_encsalts[] = { + NULL + }; + ++static bool fips_enabled(void) ++{ ++ int fd; ++ ssize_t len; ++ char buf[8]; ++ ++ fd = open(PROC_SYS_FIPS, O_RDONLY); ++ if (fd != -1) { ++ len = read(fd, buf, sizeof(buf)); ++ close(fd); ++ /* Assume FIPS in enabled if PROC_SYS_FIPS contains a non-0 value ++ * similar to the is_fips_enabled() check in ++ * ipaplatform/redhat/tasks.py */ ++ if (!(len == 2 && buf[0] == '0' && buf[1] == '\n')) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + static struct ipapwd_krbcfg *ipapwd_getConfig(void) + { + krb5_error_code krberr; +@@ -232,23 +255,27 @@ static struct ipapwd_krbcfg *ipapwd_getConfig(void) + + /* get the ipa etc/ipaConfig entry */ + config->allow_nt_hash = false; +- ret = ipapwd_getEntry(ipa_etc_config_dn, &config_entry, NULL); +- if (ret != LDAP_SUCCESS) { +- LOG_FATAL("No config Entry?\n"); +- goto free_and_error; ++ if (fips_enabled()) { ++ LOG("FIPS mode is enabled, NT hashes are not allowed.\n"); + } else { +- tmparray = slapi_entry_attr_get_charray(config_entry, +- "ipaConfigString"); +- for (i = 0; tmparray && tmparray[i]; i++) { +- if (strcasecmp(tmparray[i], "AllowNThash") == 0) { +- config->allow_nt_hash = true; +- continue; ++ ret = ipapwd_getEntry(ipa_etc_config_dn, &config_entry, NULL); ++ if (ret != LDAP_SUCCESS) { ++ LOG_FATAL("No config Entry?\n"); ++ goto free_and_error; ++ } else { ++ tmparray = slapi_entry_attr_get_charray(config_entry, ++ "ipaConfigString"); ++ for (i = 0; tmparray && tmparray[i]; i++) { ++ if (strcasecmp(tmparray[i], "AllowNThash") == 0) { ++ config->allow_nt_hash = true; ++ continue; ++ } + } ++ if (tmparray) slapi_ch_array_free(tmparray); + } +- if (tmparray) slapi_ch_array_free(tmparray); +- } + +- slapi_entry_free(config_entry); ++ slapi_entry_free(config_entry); ++ } + + return config; + +-- +2.9.4 + diff --git a/SOURCES/0203-Make-sure-we-check-ccaches-in-all-rpcserver-paths.patch b/SOURCES/0203-Make-sure-we-check-ccaches-in-all-rpcserver-paths.patch new file mode 100644 index 0000000..c246344 --- /dev/null +++ b/SOURCES/0203-Make-sure-we-check-ccaches-in-all-rpcserver-paths.patch @@ -0,0 +1,126 @@ +From 8c6cafb9d331d15cb224820c3bc254c84b49a0c7 Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Thu, 22 Jun 2017 10:57:25 -0400 +Subject: [PATCH] Make sure we check ccaches in all rpcserver paths + +We need to verify the ccache is avcailable in all cases or finalize +will cause us to acquire creds with the keytab which is not what we +want. + +Ticket #7037 + +Signed-off-by: Simo Sorce +Reviewed-By: Stanislav Laznicka +--- + ipaserver/rpcserver.py | 72 +++++++++++++++++++++++++++----------------------- + 1 file changed, 39 insertions(+), 33 deletions(-) + +diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py +index 2990df25985eab63d4bcfc8edf7f2b12da3e9832..9efe3c1f4b9e0114a02e8e04aafc76c3bc04c6f1 100644 +--- a/ipaserver/rpcserver.py ++++ b/ipaserver/rpcserver.py +@@ -592,6 +592,41 @@ class KerberosSession(HTTP_Status): + needing this do not share a common base class. + ''' + ++ def need_login(self, start_response): ++ status = '401 Unauthorized' ++ headers = [] ++ response = b'' ++ ++ self.debug('%s need login', status) ++ ++ start_response(status, headers) ++ return [response] ++ ++ def get_environ_creds(self, environ): ++ # If we have a ccache ... ++ ccache_name = environ.get('KRB5CCNAME') ++ if ccache_name is None: ++ self.debug('no ccache, need login') ++ return ++ ++ # ... make sure we have a name ... ++ principal = environ.get('GSS_NAME') ++ if principal is None: ++ self.debug('no Principal Name, need login') ++ return ++ ++ # ... and use it to resolve the ccache name (Issue: 6972 ) ++ gss_name = gssapi.Name(principal, gssapi.NameType.kerberos_principal) ++ ++ # Fail if Kerberos credentials are expired or missing ++ creds = get_credentials_if_valid(name=gss_name, ++ ccache_name=ccache_name) ++ if not creds: ++ self.debug('ccache expired or invalid, deleting session, need login') ++ return ++ ++ return ccache_name ++ + + def finalize_kerberos_acquisition(self, who, ccache_name, environ, start_response, headers=None): + if headers is None: +@@ -754,43 +789,15 @@ class jsonserver_session(jsonserver, KerberosSession): + def _on_finalize(self): + super(jsonserver_session, self)._on_finalize() + +- def need_login(self, start_response): +- status = '401 Unauthorized' +- headers = [] +- response = b'' +- +- self.debug('jsonserver_session: %s need login', status) +- +- start_response(status, headers) +- return [response] +- + def __call__(self, environ, start_response): + ''' + ''' + + self.debug('WSGI jsonserver_session.__call__:') + +- ccache_name = environ.get('KRB5CCNAME') +- + # Redirect to login if no Kerberos credentials ++ ccache_name = self.get_environ_creds(environ) + if ccache_name is None: +- self.debug('no ccache, need login') +- return self.need_login(start_response) +- +- # If we have a ccache, make sure we have a GSS_NAME and use +- # it to resolve the ccache name (Issue: 6972 ) +- principal = environ.get('GSS_NAME') +- if principal is None: +- self.debug('no GSS Name, need login') +- return self.need_login(start_response) +- gss_name = gssapi.Name(principal, gssapi.NameType.kerberos_principal) +- +- # Redirect to login if Kerberos credentials are expired +- creds = get_credentials_if_valid(name=gss_name, +- ccache_name=ccache_name) +- if not creds: +- self.debug('ccache expired, deleting session, need login') +- # The request is finished with the ccache, destroy it. + return self.need_login(start_response) + + # Store the ccache name in the per-thread context +@@ -828,11 +835,10 @@ class KerberosLogin(Backend, KerberosSession): + def __call__(self, environ, start_response): + self.debug('WSGI KerberosLogin.__call__:') + +- # Get the ccache created by mod_auth_gssapi +- user_ccache_name=environ.get('KRB5CCNAME') ++ # Redirect to login if no Kerberos credentials ++ user_ccache_name = self.get_environ_creds(environ) + if user_ccache_name is None: +- return self.internal_error(environ, start_response, +- 'login_kerberos: KRB5CCNAME not defined in HTTP request environment') ++ return self.need_login(start_response) + + return self.finalize_kerberos_acquisition('login_kerberos', user_ccache_name, environ, start_response) + +-- +2.9.4 + diff --git a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch new file mode 100644 index 0000000..96e6e1f --- /dev/null +++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch @@ -0,0 +1,999 @@ +From dd5b62fb629724f7fd96939684abf5a31769118c Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 14 Mar 2017 15:48:07 +0000 +Subject: [PATCH] Change branding to IPA and Identity Management + +--- + client/man/default.conf.5 | 2 +- + client/man/ipa-certupdate.1 | 2 +- + client/man/ipa-client-automount.1 | 2 +- + client/man/ipa-client-install.1 | 2 +- + client/man/ipa-getkeytab.1 | 4 +- + client/man/ipa-join.1 | 2 +- + client/man/ipa-rmkeytab.1 | 2 +- + client/man/ipa.1 | 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/share/schema.d/README | 4 +- + install/tools/ipa-adtrust-install | 4 +- + install/tools/ipa-replica-conncheck | 2 +- + install/tools/man/ipa-adtrust-install.1 | 2 +- + install/tools/man/ipa-advise.1 | 4 +- + install/tools/man/ipa-backup.1 | 2 +- + install/tools/man/ipa-ca-install.1 | 2 +- + install/tools/man/ipa-cacert-manage.1 | 2 +- + install/tools/man/ipa-compat-manage.1 | 2 +- + install/tools/man/ipa-csreplica-manage.1 | 2 +- + install/tools/man/ipa-dns-install.1 | 4 +- + install/tools/man/ipa-kra-install.1 | 2 +- + install/tools/man/ipa-ldap-updater.1 | 2 +- + install/tools/man/ipa-managed-entries.1 | 2 +- + install/tools/man/ipa-nis-manage.1 | 2 +- + install/tools/man/ipa-otptoken-import.1 | 2 +- + install/tools/man/ipa-replica-conncheck.1 | 2 +- + install/tools/man/ipa-replica-install.1 | 6 +- + install/tools/man/ipa-replica-manage.1 | 2 +- + install/tools/man/ipa-replica-prepare.1 | 2 +- + install/tools/man/ipa-restore.1 | 2 +- + install/tools/man/ipa-server-certinstall.1 | 2 +- + install/tools/man/ipa-server-install.1 | 4 +- + install/tools/man/ipa-server-upgrade.1 | 2 +- + install/tools/man/ipactl.8 | 2 +- + install/ui/css/patternfly.css | 2 +- + install/ui/index.html | 2 +- + install/ui/less/brand.less | 103 ++++++++++++++--------------- + install/ui/less/patternfly.less | 48 ++++++++++++++ + install/ui/reset_password.html | 2 +- + install/ui/src/freeipa/widgets/App.js | 2 +- + install/ui/sync_otp.html | 2 +- + ipaserver/advise/plugins/legacy_clients.py | 8 +-- + ipaserver/install/dns.py | 2 +- + ipaserver/install/ipa_kra_install.py | 4 +- + ipaserver/install/server/install.py | 2 +- + ipaserver/install/server/replicainstall.py | 2 +- + 51 files changed, 163 insertions(+), 118 deletions(-) + +diff --git a/client/man/default.conf.5 b/client/man/default.conf.5 +index 35ce6bb9f871365ffbc74b66be46d49fdcb3f7ad..b519d15bca9b7ddf8d22a776fa4f4a8c7fac0ca8 100644 +--- a/client/man/default.conf.5 ++++ b/client/man/default.conf.5 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "default.conf" "5" "Feb 21 2011" "FreeIPA" "FreeIPA Manual Pages" ++.TH "default.conf" "5" "Feb 21 2011" "IPA" "IPA Manual Pages" + .SH "NAME" + default.conf \- IPA configuration file + .SH "SYNOPSIS" +diff --git a/client/man/ipa-certupdate.1 b/client/man/ipa-certupdate.1 +index d95790a366aac4635e32bbc6bc81773bb9a52e68..431b395a907b6978d9e0dba9870ed0bd0c54f07b 100644 +--- a/client/man/ipa-certupdate.1 ++++ b/client/man/ipa-certupdate.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Jan Cholasta + .\" +-.TH "ipa-certupdate" "1" "Jul 2 2014" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-certupdate" "1" "Jul 2 2014" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-certupdate \- Update local IPA certificate databases with certificates from the server + .SH "SYNOPSIS" +diff --git a/client/man/ipa-client-automount.1 b/client/man/ipa-client-automount.1 +index 8b9989dec7a2e31f9ccbc0b79d336449bea9e70d..72562ab9582e987cde387583ba033464526899e2 100644 +--- a/client/man/ipa-client-automount.1 ++++ b/client/man/ipa-client-automount.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "ipa-client-automount" "1" "May 25 2012" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-client-automount" "1" "May 25 2012" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-client\-automount \- Configure automount and NFS for IPA + .SH "SYNOPSIS" +diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 +index 319952cb6ffe82339b578e8d7fe3eb7a83d53169..e631b89c6774b8ea43f5156293fee137c79dbb98 100644 +--- a/client/man/ipa-client-install.1 ++++ b/client/man/ipa-client-install.1 +@@ -1,7 +1,7 @@ + .\" A man page for ipa-client-install + .\" Copyright (C) 2008-2016 FreeIPA Contributors see COPYING for license + .\" +-.TH "ipa-client-install" "1" "Dec 19 2016" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-client-install" "1" "Dec 19 2016" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-client\-install \- Configure an IPA client + .SH "SYNOPSIS" +diff --git a/client/man/ipa-getkeytab.1 b/client/man/ipa-getkeytab.1 +index 08f6ec40d362b88a974e6ec735ed37c271e01882..3db48cc9204908dc63fdee6b3917331da43cd424 100644 +--- a/client/man/ipa-getkeytab.1 ++++ b/client/man/ipa-getkeytab.1 +@@ -17,7 +17,7 @@ + .\" Author: Karl MacMillan + .\" Author: Simo Sorce + .\" +-.TH "ipa-getkeytab" "1" "Oct 10 2007" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-getkeytab" "1" "Oct 10 2007" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-getkeytab \- Get a keytab for a Kerberos principal + .SH "SYNOPSIS" +@@ -112,7 +112,7 @@ GSSAPI or EXTERNAL. + \fB\-r\fR + Retrieve mode. Retrieve an existing key from the server instead of generating a + new one. This is incompatibile with the \-\-password option, and will work only +-against a FreeIPA server more recent than version 3.3. The user requesting the ++against a IPA server more recent than version 3.3. The user requesting the + keytab must have access to the keys for this operation to succeed. + .SH "EXAMPLES" + Add and retrieve a keytab for the NFS service principal on +diff --git a/client/man/ipa-join.1 b/client/man/ipa-join.1 +index d881607842bb0227c2da863bd1674db01530e910..30b667558ba3105cf320896ef40b0661a18066f5 100644 +--- a/client/man/ipa-join.1 ++++ b/client/man/ipa-join.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "ipa-join" "1" "Oct 8 2009" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-join" "1" "Oct 8 2009" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-join \- Join a machine to an IPA realm and get a keytab for the host service principal + .SH "SYNOPSIS" +diff --git a/client/man/ipa-rmkeytab.1 b/client/man/ipa-rmkeytab.1 +index 53f775439dbdb5a4b9dfee7fe6c7277fce10893c..2c8218c94996b1411637a7c53f2f5bc5612f3ea3 100644 +--- a/client/man/ipa-rmkeytab.1 ++++ b/client/man/ipa-rmkeytab.1 +@@ -17,7 +17,7 @@ + .\" Author: Rob Crittenden + .\" + .\" +-.TH "ipa-rmkeytab" "1" "Oct 30 2009" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-rmkeytab" "1" "Oct 30 2009" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-rmkeytab \- Remove a kerberos principal from a keytab + .SH "SYNOPSIS" +diff --git a/client/man/ipa.1 b/client/man/ipa.1 +index b843e7ba71ff400fa0712ba491b85e8b34f8a09f..0bd10a7edf8849dc6a77f364d662ee5841054d41 100644 +--- a/client/man/ipa.1 ++++ b/client/man/ipa.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Pavel Zuna + .\" +-.TH "ipa" "1" "Apr 29 2016" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa" "1" "Apr 29 2016" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa \- IPA command\-line interface + .SH "SYNOPSIS" +diff --git a/install/html/browserconfig.html b/install/html/browserconfig.html +index 9c5cf68211281723e12b518f346aac43c1541cdc..14c4ca1f98a60cd8dfe486f8b942fcf9ae9de4c0 100644 +--- a/install/html/browserconfig.html ++++ b/install/html/browserconfig.html +@@ -2,7 +2,7 @@ + + + +- IPA: Identity Policy Audit ++ Identity Management + + + +