diff --git a/.gitignore b/.gitignore index 2d2eb03..0e4e65c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -SOURCES/freeipa-4.6.5.tar.gz +SOURCES/freeipa-4.6.6.tar.gz SOURCES/header-logo.png SOURCES/login-screen-background.jpg SOURCES/product-name.png diff --git a/.ipa.metadata b/.ipa.metadata index 298fd0e..0dfcd18 100644 --- a/.ipa.metadata +++ b/.ipa.metadata @@ -1,4 +1,4 @@ -45d419f50412d016d194fb0e02a54251b26a7b35 SOURCES/freeipa-4.6.5.tar.gz +2ed9f8319600bb22b7b252b1ed787883173d9ca4 SOURCES/freeipa-4.6.6.tar.gz 77c318cf1f4fc25cf847de0692a77859a767c0e3 SOURCES/header-logo.png 8727245558422bf966d60677568925f081b8e299 SOURCES/login-screen-background.jpg af82b7b7d327bd683c7d062a6f15713ea91ebedf SOURCES/product-name.png diff --git a/SOURCES/0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch b/SOURCES/0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch deleted file mode 100644 index 836750c..0000000 --- a/SOURCES/0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 5fb390bc2aed0f460e96c0e98dd57ecf01aec01c Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 21 Mar 2019 13:59:32 +0100 -Subject: [PATCH] Coverity: fix issue in ipa_extdom_extop.c - -Coverity found the following issue: -Error: BAD_COMPARE (CWE-697): [#def1] -freeipa-4.6.5/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c:121: null_misuse: Comparing pointer "threadnumber" against "NULL" using anything besides "==" or "!=" is likely to be incorrect. - -The comparison is using the pointer while it should use the pointed value. - -Fixes: https://pagure.io/freeipa/issue/7884 -Reviewed-By: Christian Heimes ---- - daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -index 3abaa411d2873dedb27ac83bc53d82677577e5b5..10d3f86ebad920fb9c051aa428cbd675b682f14a 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -@@ -118,7 +118,7 @@ static int ipa_get_threadnumber(Slapi_ComponentId *plugin_id, size_t *threadnumb - *threadnumber = slapi_entry_attr_get_uint(search_entries[0], - NSSLAPD_THREADNUMBER); - -- if (threadnumber <= 0) { -+ if (*threadnumber <= 0) { - LOG_FATAL("No thread number found.\n"); - ret = LDAP_OPERATIONS_ERROR; - goto done; --- -2.20.1 - diff --git a/SOURCES/0001-extdom-unify-error-code-handling.patch b/SOURCES/0001-extdom-unify-error-code-handling.patch new file mode 100644 index 0000000..b2f6f72 --- /dev/null +++ b/SOURCES/0001-extdom-unify-error-code-handling.patch @@ -0,0 +1,352 @@ +From 574a615e61ca74b08e2bd7e1e820757f88150418 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 14 Jun 2019 11:13:54 +0200 +Subject: [PATCH 1/2] extdom: unify error code handling especially + LDAP_NO_SUCH_OBJECT + +A return code LDAP_NO_SUCH_OBJECT will tell SSSD on the IPA client to +remove the searched object from the cache. As a consequence +LDAP_NO_SUCH_OBJECT should only be returned if the object really does +not exists otherwise the data of existing objects might be removed form +the cache of the clients causing unexpected behaviour like +authentication errors. + +Currently some code-paths use LDAP_NO_SUCH_OBJECT as default error code. +With this patch LDAP_NO_SUCH_OBJECT is only returned if the related +lookup functions return ENOENT. Timeout related error code will lead to +LDAP_TIMELIMIT_EXCEEDED and LDAP_OPERATIONS_ERROR is used as default +error code. + +Fixes: https://pagure.io/freeipa/issue/8044 +Reviewed-By: Alexander Bokovoy +--- + .../ipa-extdom-extop/back_extdom_sss_idmap.c | 4 +- + .../ipa-extdom-extop/ipa_extdom_common.c | 77 ++++++++++++++----- + .../ipa-extdom-extop/ipa_extdom_extop.c | 2 + + 3 files changed, 61 insertions(+), 22 deletions(-) + +diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c +index 89c58ca2d..64b90e3ae 100644 +--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c ++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c +@@ -47,10 +47,10 @@ static enum nss_status __convert_sss_nss2nss_status(int errcode) { + return NSS_STATUS_SUCCESS; + case ENOENT: + return NSS_STATUS_NOTFOUND; +- case ETIME: +- /* fall-through */ + case ERANGE: + return NSS_STATUS_TRYAGAIN; ++ case ETIME: ++ /* fall-through */ + case ETIMEDOUT: + /* fall-through */ + default: +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 1b93dce18..134b62377 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 +@@ -523,7 +523,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, + if (strcasecmp(locat+1, domain_name) == 0 ) { + locat[0] = '\0'; + } else { +- ret = LDAP_NO_SUCH_OBJECT; ++ ret = LDAP_INVALID_SYNTAX; + goto done; + } + } +@@ -568,10 +568,12 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, + ret = getgrgid_r_wrapper(ctx, + groups[c], &grp, &buf, &buf_len); + if (ret != 0) { +- if (ret == ENOMEM || ret == ERANGE) { +- ret = LDAP_OPERATIONS_ERROR; +- } else { ++ if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ } else { ++ ret = LDAP_OPERATIONS_ERROR; + } + goto done; + } +@@ -634,7 +636,7 @@ int pack_ber_group(enum response_types response_type, + if (strcasecmp(locat+1, domain_name) == 0 ) { + locat[0] = '\0'; + } else { +- ret = LDAP_NO_SUCH_OBJECT; ++ ret = LDAP_INVALID_SYNTAX; + goto done; + } + } +@@ -836,6 +838,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, + || id_type == SSS_ID_TYPE_BOTH)) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + set_err_msg(req, "Failed to lookup SID by UID"); + ret = LDAP_OPERATIONS_ERROR; +@@ -847,10 +851,12 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, + } else { + ret = getpwuid_r_wrapper(ctx, uid, &pwd, &buf, &buf_len); + if (ret != 0) { +- if (ret == ENOMEM || ret == ERANGE) { +- ret = LDAP_OPERATIONS_ERROR; +- } else { ++ if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ } else { ++ ret = LDAP_OPERATIONS_ERROR; + } + goto done; + } +@@ -862,6 +868,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, + set_err_msg(req, "Failed to read original data"); + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + ret = LDAP_OPERATIONS_ERROR; + } +@@ -907,6 +915,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, + if (ret != 0 || id_type != SSS_ID_TYPE_GID) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + set_err_msg(req, "Failed to lookup SID by GID"); + ret = LDAP_OPERATIONS_ERROR; +@@ -918,10 +928,12 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, + } else { + ret = getgrgid_r_wrapper(ctx, gid, &grp, &buf, &buf_len); + if (ret != 0) { +- if (ret == ENOMEM || ret == ERANGE) { +- ret = LDAP_OPERATIONS_ERROR; +- } else { ++ if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ } else { ++ ret = LDAP_OPERATIONS_ERROR; + } + goto done; + } +@@ -933,6 +945,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, + set_err_msg(req, "Failed to read original data"); + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + ret = LDAP_OPERATIONS_ERROR; + } +@@ -976,6 +990,8 @@ static int handle_cert_request(struct ipa_extdom_ctx *ctx, + if (ret != 0) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + set_err_msg(req, "Failed to lookup name by certificate"); + ret = LDAP_OPERATIONS_ERROR; +@@ -1020,6 +1036,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, + if (ret != 0) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + set_err_msg(req, "Failed to lookup name by SID"); + ret = LDAP_OPERATIONS_ERROR; +@@ -1057,10 +1075,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, + case SSS_ID_TYPE_BOTH: + ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len); + if (ret != 0) { +- if (ret == ENOMEM || ret == ERANGE) { +- ret = LDAP_OPERATIONS_ERROR; +- } else { ++ if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ } else { ++ ret = LDAP_OPERATIONS_ERROR; + } + goto done; + } +@@ -1072,6 +1092,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, + set_err_msg(req, "Failed to read original data"); + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + ret = LDAP_OPERATIONS_ERROR; + } +@@ -1089,10 +1111,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, + case SSS_ID_TYPE_GID: + ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len); + if (ret != 0) { +- if (ret == ENOMEM || ret == ERANGE) { +- ret = LDAP_OPERATIONS_ERROR; +- } else { ++ if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ } else { ++ ret = LDAP_OPERATIONS_ERROR; + } + goto done; + } +@@ -1104,6 +1128,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, + set_err_msg(req, "Failed to read original data"); + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + ret = LDAP_OPERATIONS_ERROR; + } +@@ -1167,6 +1193,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, + if (ret != 0) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + set_err_msg(req, "Failed to lookup SID by name"); + ret = LDAP_OPERATIONS_ERROR; +@@ -1190,6 +1218,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, + set_err_msg(req, "Failed to read original data"); + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + ret = LDAP_OPERATIONS_ERROR; + } +@@ -1205,6 +1235,9 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, + } else if (ret == ENOMEM || ret == ERANGE) { + ret = LDAP_OPERATIONS_ERROR; + goto done; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ goto done; + } else { /* no user entry found */ + /* according to the getpwnam() man page there are a couple of + * error codes which can indicate that the user was not found. To +@@ -1212,10 +1245,12 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, + * errors. */ + ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len); + if (ret != 0) { +- if (ret == ENOMEM || ret == ERANGE) { +- ret = LDAP_OPERATIONS_ERROR; +- } else { ++ if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; ++ } else { ++ ret = LDAP_OPERATIONS_ERROR; + } + goto done; + } +@@ -1226,6 +1261,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, + || id_type == SSS_ID_TYPE_BOTH)) { + if (ret == ENOENT) { + ret = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == ETIMEDOUT || ret == ETIME) { ++ ret = LDAP_TIMELIMIT_EXCEEDED; + } else { + set_err_msg(req, "Failed to read original data"); + ret = LDAP_OPERATIONS_ERROR; +diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c +index 10d3f86eb..48fcecc1e 100644 +--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c ++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c +@@ -242,6 +242,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb) + if (ret != LDAP_SUCCESS) { + if (ret == LDAP_NO_SUCH_OBJECT) { + rc = LDAP_NO_SUCH_OBJECT; ++ } else if (ret == LDAP_TIMELIMIT_EXCEEDED) { ++ rc = LDAP_TIMELIMIT_EXCEEDED; + } else { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Failed to handle the request.\n"; +-- +2.21.0 + + +From 387ed98e59ba4df8d3fd435cfc84f055970c064e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 19 Aug 2019 10:15:50 +0300 +Subject: [PATCH 2/2] ipa-extdom-extop: test timed out getgrgid_r + +Simulate getgrgid_r() timeout when packing list of groups user is a +member of in pack_ber_user(). + +Related: https://pagure.io/freeipa/issue/8044 +Reviewed-By: Alexander Bokovoy +--- + .../ipa_extdom_cmocka_tests.c | 29 +++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c +index 29699cfa3..1fa4c6af8 100644 +--- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c ++++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c +@@ -493,6 +493,34 @@ void test_set_err_msg(void **state) + #define TEST_SID "S-1-2-3-4" + #define TEST_DOMAIN_NAME "DOMAIN" + ++/* Always time out for test */ ++static ++enum nss_status getgrgid_r_timeout(gid_t gid, struct group *result, ++ char *buffer, size_t buflen, int *errnop) { ++ return NSS_STATUS_UNAVAIL; ++} ++ ++void test_pack_ber_user_timeout(void **state) ++{ ++ int ret; ++ struct berval *resp_val = NULL; ++ struct test_data *test_data; ++ enum nss_status (*oldgetgrgid_r)(gid_t gid, struct group *result, ++ char *buffer, size_t buflen, int *errnop); ++ ++ test_data = (struct test_data *) *state; ++ ++ oldgetgrgid_r = test_data->ctx->nss_ctx->getgrgid_r; ++ test_data->ctx->nss_ctx->getgrgid_r = getgrgid_r_timeout; ++ ++ ret = pack_ber_user(test_data->ctx, RESP_USER_GROUPLIST, ++ TEST_DOMAIN_NAME, "member001", 12345, 54321, ++ "gecos", "homedir", "shell", NULL, &resp_val); ++ test_data->ctx->nss_ctx->getgrgid_r = oldgetgrgid_r; ++ assert_int_equal(ret, LDAP_TIMELIMIT_EXCEEDED); ++ ber_bvfree(resp_val); ++} ++ + char res_sid[] = {0x30, 0x0e, 0x0a, 0x01, 0x01, 0x04, 0x09, 0x53, 0x2d, 0x31, \ + 0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34}; + char res_nam[] = {0x30, 0x13, 0x0a, 0x01, 0x02, 0x30, 0x0e, 0x04, 0x06, 0x44, \ +@@ -614,6 +642,7 @@ void test_decode(void **state) + int main(int argc, const char *argv[]) + { + const struct CMUnitTest tests[] = { ++ cmocka_unit_test(test_pack_ber_user_timeout), + cmocka_unit_test(test_getpwnam_r_wrapper), + cmocka_unit_test(test_getpwuid_r_wrapper), + cmocka_unit_test(test_getgrnam_r_wrapper), +-- +2.21.0 + diff --git a/SOURCES/0002-Use-unicode-strings-for-Python-2-version.patch b/SOURCES/0002-Use-unicode-strings-for-Python-2-version.patch new file mode 100644 index 0000000..394dd1b --- /dev/null +++ b/SOURCES/0002-Use-unicode-strings-for-Python-2-version.patch @@ -0,0 +1,26 @@ +From 56b3c4cf7cab07410e026ce695667a2aa0c4ce2d Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Fri, 23 Aug 2019 11:49:53 +0300 +Subject: [PATCH] Use unicode strings for Python 2 version + +Related: https://pagure.io/freeipa/issue/6951 +--- + ipaserver/install/adtrustinstance.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py +index 804a04530..67dadf9b9 100644 +--- a/ipaserver/install/adtrustinstance.py ++++ b/ipaserver/install/adtrustinstance.py +@@ -131,7 +131,7 @@ def map_Guests_to_nobody(): + + + def get_idmap_range(realm): +- idrange = api.Command.idrange_show('{}_id_range'.format(realm))['result'] ++ idrange = api.Command.idrange_show(u'{}_id_range'.format(realm))['result'] + range_start = int(idrange['ipabaseid'][0]) + range_size = int(idrange['ipaidrangesize'][0]) + range_fmt = '{} - {}'.format(range_start, range_start + range_size) +-- +2.21.0 + diff --git a/SOURCES/0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch b/SOURCES/0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch deleted file mode 100644 index ba1a806..0000000 --- a/SOURCES/0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch +++ /dev/null @@ -1,361 +0,0 @@ -From 4b853e8c2f57034c9a72b96fc028e66aa3175a07 Mon Sep 17 00:00:00 2001 -From: Serhii Tsymbaliuk -Date: Tue, 12 Feb 2019 10:44:33 +0100 -Subject: [PATCH] Web UI (topology graph): Show FQDN for nodes if they have no - common DNS zone - -It allows to avoid confusion with identical short hostnames. - -There are two cases implemented: -- no common DNS zone: graph shows FQDN for all nodes -- all nodes have one common DNS zone: graph shows DN relatively to the common zone - -https://pagure.io/freeipa/issue/7206 - -Reviewed-By: Florence Blanc-Renaud ---- - install/ui/src/freeipa/topology.js | 64 +++++++++ - install/ui/src/freeipa/topology_graph.js | 3 +- - install/ui/test/all_tests.html | 4 +- - install/ui/test/index.html | 1 + - install/ui/test/topology_tests.html | 25 ++++ - install/ui/test/topology_tests.js | 158 +++++++++++++++++++++++ - 6 files changed, 252 insertions(+), 3 deletions(-) - create mode 100644 install/ui/test/topology_tests.html - create mode 100644 install/ui/test/topology_tests.js - -diff --git a/install/ui/src/freeipa/topology.js b/install/ui/src/freeipa/topology.js -index e98cb1e0ace1874056d3affa98c9518509f90558..fd7a2833abc04ffe7c3f8405bde4df0e6b942349 100644 ---- a/install/ui/src/freeipa/topology.js -+++ b/install/ui/src/freeipa/topology.js -@@ -1374,6 +1374,33 @@ topology.TopologyGraphWidget = declare([Stateful, Evented], { - return deferred.promise; - }, - -+ _find_common_domain: function(nodes) { -+ if (nodes.length < 2) { -+ return ''; -+ } -+ -+ var common_labels = null; -+ -+ for (var i=0, l=nodes.length; i 1 && common_domain.length > 0) { -+ node.caption = node.id.substring( -+ 0, node.id.length - common_domain.length - 1 -+ ); -+ } else { -+ node.caption = node.id; -+ } -+ } -+ - if (!this.graph) { - this.graph = new topology_graph.TopoGraph({ - nodes: data.nodes, -diff --git a/install/ui/src/freeipa/topology_graph.js b/install/ui/src/freeipa/topology_graph.js -index 9f549133b516dbfe471080714845b457fd62ab1a..b736a22f63aa9a5685ac5840f60f9e2c89fb4525 100644 ---- a/install/ui/src/freeipa/topology_graph.js -+++ b/install/ui/src/freeipa/topology_graph.js -@@ -180,7 +180,6 @@ topology_graph.TopoGraph = declare([Evented], { - this._target_node = null; - this.restart(); - }, -- - _create_svg: function(container) { - var self = this; - -@@ -804,7 +803,7 @@ topology_graph.TopoGraph = declare([Evented], { - .attr('class', 'id') - .attr('fill', '#002235') - .text(function(d) { -- return d.id.split('.')[0]; -+ return d.caption; - }); - - // remove old nodes -diff --git a/install/ui/test/all_tests.html b/install/ui/test/all_tests.html -index cdb04b395a878db4338da7458b8f52f13514ead9..f85ae3390a923ad3083779e1ddfcdca6afa2377e 100644 ---- a/install/ui/test/all_tests.html -+++ b/install/ui/test/all_tests.html -@@ -26,7 +26,8 @@ - 'test/utils_tests', - 'test/build_tests', - 'test/binding_tests', -- ], function(om, ipa, details, entity, as, nav, cert, aci, wid, ip, ut, bt, bi){ -+ 'test/topology_tests', -+ ], function(om, ipa, details, entity, as, nav, cert, aci, wid, ip, ut, bt, bi, topo){ - om(); - ipa(); - details(); -@@ -40,6 +41,7 @@ - ut(); - bt(); - bi(); -+ topo(); - }); - - -diff --git a/install/ui/test/index.html b/install/ui/test/index.html -index 89af3211cd9791ee3055ca85ddae6afdf5b9edcf..0fd5b83d696e7e368f5ca7d726c5e4301b05acfe 100644 ---- a/install/ui/test/index.html -+++ b/install/ui/test/index.html -@@ -37,6 +37,7 @@ -
  • Utils Test Suite -
  • Build Test Suite -
  • Binding Test Suite -+
  • Topology Test Suite - - - -diff --git a/install/ui/test/topology_tests.html b/install/ui/test/topology_tests.html -new file mode 100644 -index 0000000000000000000000000000000000000000..29ca44ddcc004efbdad9860276906b7111bb40b0 ---- /dev/null -+++ b/install/ui/test/topology_tests.html -@@ -0,0 +1,25 @@ -+ -+ -+ -+ Topology Test Suite -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+

    Topology Test Suite

    -+

    -+
    -+

    -+
      -+
      -+ -+ -diff --git a/install/ui/test/topology_tests.js b/install/ui/test/topology_tests.js -new file mode 100644 -index 0000000000000000000000000000000000000000..6458a83f2794969e2916899975707b6c554ac314 ---- /dev/null -+++ b/install/ui/test/topology_tests.js -@@ -0,0 +1,158 @@ -+/** -+ * Copyright (C) 2019 FreeIPA Contributors see COPYING for license -+ */ -+ -+define([ -+ 'freeipa/ipa', -+ 'freeipa/topology', -+ 'freeipa/jquery'], -+ function(IPA, topology, $) { -+ return function() { -+ -+var widget; -+ -+function inject_data(widget, data) { -+ widget._get_data = function() { -+ return data; -+ }; -+} -+ -+QUnit.module('topology', { -+ beforeEach: function(assert) { -+ widget = new topology.TopologyGraphWidget( -+ topology.topology_graph_facet_spec -+ ); -+ widget.render(); -+ } -+}); -+ -+QUnit.test('Testing TopoGraph nodes', function(assert) { -+ var nodes = [ -+ { id: 'master.ipa.test' }, -+ { id: 'replica.ipa.test' } -+ ]; -+ -+ var suffixes = [ -+ { cn: ['ca'] }, -+ { cn: ['domain'] } -+ ]; -+ -+ inject_data(widget, { nodes: nodes, links: [], suffixes: suffixes }); -+ -+ widget.update(); -+ -+ assert.ok($('circle.node', widget.el).length === nodes.length, -+ 'Checking rendered nodes count'); -+ -+ assert.ok($('text.id:eq(0)', widget.el).text() === 'master', -+ 'Checking "master" node label'); -+ assert.ok($('text.id:eq(1)', widget.el).text() === 'replica', -+ 'Checking "replica" node label'); -+ -+ assert.ok($('text.suffix:eq(0)', widget.el).text() === 'ca', -+ 'Checking "ca" suffix'); -+ assert.ok($('text.suffix:eq(1)', widget.el).text() === 'domain', -+ 'Checking "domain" suffix'); -+}); -+ -+QUnit.test('Testing TopoGraph links', function(assert) { -+ var nodes = [ -+ { id: 'master.ipa.test', targets: { 'replica.ipa.test': [] } }, -+ { id: 'replica.ipa.test' } -+ ]; -+ -+ var suffixes = [ -+ { cn: ['ca'] }, -+ { cn: ['domain'] } -+ ]; -+ -+ var links = [{ -+ source: 0, -+ target: 1, -+ left: false, -+ right: true, -+ suffix: suffixes[0] -+ }]; -+ -+ inject_data(widget, { nodes: nodes, links: links, suffixes: suffixes }); -+ widget.update(); -+ -+ assert.ok($('circle.node', widget.el).length === nodes.length, -+ 'Checking rendered nodes count'); -+ -+ var rendered_links = $('path.link', widget.el).not('.dragline'); -+ assert.ok(rendered_links.length === 1, -+ 'Checking right direction link is rendered'); -+ -+ var marker = rendered_links.first().css('marker-end'); -+ assert.ok(marker && marker !== 'none', -+ 'Checking right direction link has proper marker'); -+ -+ links.push({ -+ source: 0, -+ target: 1, -+ left: true, -+ right: false, -+ suffix: suffixes[1] -+ }) -+ -+ inject_data(widget, { -+ nodes: nodes, -+ links: links, -+ suffixes: suffixes -+ }); -+ widget.update(); -+ -+ rendered_links = $('path.link', widget.el).not('.dragline') -+ assert.ok(rendered_links.length === 2, -+ 'Checking left direction link is rendered'); -+ -+ marker = rendered_links.last().css('marker-start'); -+ assert.ok(marker && marker !== 'none', -+ 'Checking left direction link has proper marker'); -+}); -+ -+QUnit.test('Testing TopoGraph for multiple DNS zones', function(assert) { -+ var nodes = [ -+ { id: 'master.ipa.zone1' }, -+ { id: 'replica.ipa.zone1' }, -+ { id: 'master.ipa.zone2' }, -+ { id: 'master.ipa.zone1.common' }, -+ { id: 'replica.ipa.zone2.common' }, -+ ]; -+ -+ var suffixes = [ -+ { cn: ['ca'] }, -+ { cn: ['domain'] } -+ ]; -+ -+ inject_data(widget, { nodes: nodes, links: [], suffixes: suffixes }); -+ widget.update(); -+ -+ $('text.id', widget.el).each(function(i) { -+ assert.ok($(this).text() === nodes[i].id, -+ 'Checking node label "' + $(this).text() + '" is FQDN'); -+ }); -+ -+ nodes = nodes.filter(function(node) { return /\.common$/.test(node.id) }); -+ -+ inject_data(widget, { nodes: nodes, links: [], suffixes: suffixes }); -+ widget.update(); -+ -+ $('text.id', widget.el).each(function(i) { -+ assert.ok($(this).text().indexOf('common') < 0, -+ 'Checking node label "' + $(this).text() + '" is relative'); -+ }); -+}); -+ -+QUnit.test('Testing TopoGraph with one node', function(assert) { -+ var node = { id: 'master.ipa.test' }; -+ -+ inject_data(widget, { nodes: [node], links: [], suffixes: [] }); -+ widget.update(); -+ -+ assert.ok($('text.id:eq(0)', widget.el).text() === node.id, -+ 'Checking node label is FQDN'); -+}); -+ -+};}); --- -2.20.1 - diff --git a/SOURCES/0003-ipa-replica-manage-fix-force-sync.patch b/SOURCES/0003-ipa-replica-manage-fix-force-sync.patch deleted file mode 100644 index 60b4fbe..0000000 --- a/SOURCES/0003-ipa-replica-manage-fix-force-sync.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 6c72f4241c70200d3d6637c254c07504aa19cdc9 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 25 Mar 2019 14:22:59 +0100 -Subject: [PATCH] ipa-replica-manage: fix force-sync - -ipa-replica-manage force-sync --from is performing a wrong check -that may result in the tool looping on "No status yet". - -force-sync is adding a nsds5replicaupdateschedule attribute to the -replication agreement in order to force replication to wake up. Note that -this is not a re-initialization (re init drops the current db and reloads -the entire db). - -In a second step, force-sync is checking the replication agreement by reading -nsds5BeginReplicaRefresh, nsds5ReplicaLastInitStatus, -nsds5ReplicaLastInitStart and nsds5ReplicaLastInitEnd. This is a wrong -test as force-sync is not an init operation and does not touch these -attributes. - -The tool should call wait_for_repl_update rather than wait_for_repl_init. -This way, the check is done on the replication agreement attributes -nsds5replicaUpdateInProgress, nsds5ReplicaLastUpdateStatus, -nsds5ReplicaLastUpdateStart and nsds5ReplicaLastUpdateEnd. - -Fixes: https://pagure.io/freeipa/issue/7886 ---- - install/tools/ipa-replica-manage | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage -index cffed58b79f3e2cc41f8cf45b066f3843da01915..2a875b8fa58390c704d36b7d355ac79181021c35 100755 ---- a/install/tools/ipa-replica-manage -+++ b/install/tools/ipa-replica-manage -@@ -1246,7 +1246,7 @@ def force_sync(realm, thishost, fromhost, dirman_passwd, nolookup=False): - repl = replication.ReplicationManager(realm, fromhost, dirman_passwd) - repl.force_sync(repl.conn, thishost) - agreement = repl.get_replication_agreement(thishost) -- repl.wait_for_repl_init(repl.conn, agreement.dn) -+ repl.wait_for_repl_update(repl.conn, agreement.dn) - ds.replica_manage_time_skew(prevent=True) - - def show_DNA_ranges(hostname, master, realm, dirman_passwd, nextrange=False, --- -2.20.1 - diff --git a/SOURCES/0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch b/SOURCES/0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch new file mode 100644 index 0000000..2b19a07 --- /dev/null +++ b/SOURCES/0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch @@ -0,0 +1,76 @@ +From 5cceb47667c0665629bb474f73be1d2d8f1e1b5b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 19 Feb 2019 12:30:40 +0100 +Subject: [PATCH] ipa_sam: remove dependency to talloc_strackframe.h +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Recent Samba versions removed some header files which did include +non-public APIs. As a result talloc_strackframe.h and memory.h (for +SAFE_FREE) are not available anymore. This patch replaces the use of the +non-public APIs with public ones. + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +Reviewed-By: François Cami +(cherry picked from commit d1f5ed64e16d65b9df45cc0eac7d2724dcae7b67) +--- + daemons/ipa-sam/ipa_sam.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c +index 2251f3ddc..755f44d68 100644 +--- a/daemons/ipa-sam/ipa_sam.c ++++ b/daemons/ipa-sam/ipa_sam.c +@@ -19,7 +19,6 @@ + #include + #include + #include +-#include + + #ifndef _SAMBA_UTIL_H_ + bool trim_string(char *s, const char *front, const char *back); +@@ -881,9 +880,13 @@ static bool ipasam_uid_to_sid(struct pdb_methods *methods, uid_t uid, + struct dom_sid *user_sid = NULL; + int rc; + enum idmap_error_code err; +- TALLOC_CTX *tmp_ctx = talloc_stackframe(); + struct unixid id; + ++ TALLOC_CTX *tmp_ctx = talloc_new(priv); ++ if (tmp_ctx == NULL) { ++ goto done; ++ } ++ + /* Fast fail if we get a request for uidNumber=0 because it currently + * will never exist in the directory + * Saves an expensive LDAP call of which failure will never be cached +@@ -968,9 +971,13 @@ static bool ipasam_gid_to_sid(struct pdb_methods *methods, gid_t gid, + size_t c; + int rc; + enum idmap_error_code err; +- TALLOC_CTX *tmp_ctx = talloc_stackframe(); + struct unixid id; + ++ TALLOC_CTX *tmp_ctx = talloc_new(priv); ++ if (tmp_ctx == NULL) { ++ goto done; ++ } ++ + filter = talloc_asprintf(tmp_ctx, + "(|(&(gidNumber=%u)" + "(objectClass=%s))" +@@ -3749,7 +3756,8 @@ static void ipasam_free_private_data(void **vp) + (*ipasam_state)->result = NULL; + } + if ((*ipasam_state)->domain_dn != NULL) { +- SAFE_FREE((*ipasam_state)->domain_dn); ++ free((*ipasam_state)->domain_dn); ++ (*ipasam_state)->domain_dn = NULL; + } + + *ipasam_state = NULL; +-- +2.21.0 + diff --git a/SOURCES/0004-Remove-ZERO_STRUCT-call.patch b/SOURCES/0004-Remove-ZERO_STRUCT-call.patch new file mode 100644 index 0000000..4568d20 --- /dev/null +++ b/SOURCES/0004-Remove-ZERO_STRUCT-call.patch @@ -0,0 +1,37 @@ +From f4673e9656c16ff383cc6cf1caf523c913f2d3bd Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Thu, 7 Feb 2019 12:11:42 +0100 +Subject: [PATCH 1/2] Remove ZERO_STRUCT() call + +ipa_sam uses Samba's macro ZERO_STRUCT() to safely zero out a block in +memory. On F30 ZERO_STRUCT() is currently broken, because it uses the +undefined C11 function memset_s(). + +During investigation of the bug, it turned out that +ZERO_STRUCT(td->security_identifier) is not needed. The whole td struct +is allocated with talloc_zero(), so td->security_identifier is already +zeroed. + +See: https://bugzilla.redhat.com/show_bug.cgi?id=1672231 +Signed-off-by: Christian Heimes +Reviewed-By: Alexander Bokovoy +(cherry picked from commit 1355588768c7863234c518196f48527e119740e0) +--- + daemons/ipa-sam/ipa_sam.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c +index 755f44d68..2f78f82f9 100644 +--- a/daemons/ipa-sam/ipa_sam.c ++++ b/daemons/ipa-sam/ipa_sam.c +@@ -2266,7 +2266,6 @@ static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx, + if (dummy == NULL) { + DEBUG(9, ("Attribute %s not present.\n", + LDAP_ATTRIBUTE_TRUST_SID)); +- ZERO_STRUCT(td->security_identifier); + } else { + err = sss_idmap_sid_to_smb_sid(ipasam_state->idmap_ctx, + dummy, &sid); +-- +2.21.0 + diff --git a/SOURCES/0004-Unify-and-simplify-LDAP-service-discovery.patch b/SOURCES/0004-Unify-and-simplify-LDAP-service-discovery.patch deleted file mode 100644 index a90fffc..0000000 --- a/SOURCES/0004-Unify-and-simplify-LDAP-service-discovery.patch +++ /dev/null @@ -1,660 +0,0 @@ -From 04f68b7354cf1268019b08885eeb3a6915f314ef Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Thu, 12 Jul 2018 14:37:18 +0200 -Subject: [PATCH] Unify and simplify LDAP service discovery - -Move LDAP service discovery and service definitions from -ipaserver.install to ipaserver. Simplify and unify different -implementations in favor of a single implementation. - -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner ---- - install/tools/ipa-ca-install | 9 +- - install/tools/ipactl | 4 +- - ipaserver/install/cainstance.py | 3 +- - ipaserver/install/ipa_kra_install.py | 11 +- - ipaserver/install/opendnssecinstance.py | 3 +- - ipaserver/install/server/replicainstall.py | 18 +-- - ipaserver/install/service.py | 65 +---------- - ipaserver/masters.py | 123 ++++++++++++++++++++ - ipaserver/plugins/cert.py | 10 +- - ipaserver/plugins/dogtag.py | 99 ++++------------ - ipaserver/servroles.py | 9 +- - ipatests/test_ipaserver/test_serverroles.py | 3 +- - 12 files changed, 192 insertions(+), 165 deletions(-) - create mode 100644 ipaserver/masters.py - -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index f78f43d94981d29939a247f3c492c5e7340298ea..dcdbe884f15b13b92ec68a11d9f00e3e28771b42 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -34,6 +34,7 @@ from ipaserver.install.installutils import check_creds, ReplicaConfig - from ipaserver.install import dsinstance, ca - from ipaserver.install import cainstance, service - from ipaserver.install import custodiainstance -+from ipaserver.masters import find_providing_server - from ipapython import version - from ipalib import api - from ipalib.constants import DOMAIN_LEVEL_0 -@@ -211,8 +212,9 @@ def install_replica(safe_options, options, filename): - config.subject_base = attrs.get('ipacertificatesubjectbase')[0] - - if config.ca_host_name is None: -- config.ca_host_name = \ -- service.find_providing_server('CA', api.Backend.ldap2, api.env.ca_host) -+ config.ca_host_name = find_providing_server( -+ 'CA', api.Backend.ldap2, [api.env.ca_host] -+ ) - - options.realm_name = config.realm_name - options.domain_name = config.domain_name -@@ -299,7 +301,8 @@ def promote(safe_options, options, filename): - paths.KRB5_KEYTAB, - ccache) - -- ca_host = service.find_providing_server('CA', api.Backend.ldap2) -+ ca_host = find_providing_server('CA', api.Backend.ldap2) -+ - if ca_host is None: - install_master(safe_options, options) - else: -diff --git a/install/tools/ipactl b/install/tools/ipactl -index ade91f7f75dab4fdf3b7fa73d2624a7395bc2a53..2767a26d1b70337d37dbcd87c707919579fe7e29 100755 ---- a/install/tools/ipactl -+++ b/install/tools/ipactl -@@ -224,9 +224,9 @@ def get_config(dirsrv): - svc_list.append([order, name]) - - ordered_list = [] -- for (order, svc) in sorted(svc_list): -+ for order, svc in sorted(svc_list): - if svc in service.SERVICE_LIST: -- ordered_list.append(service.SERVICE_LIST[svc][0]) -+ ordered_list.append(service.SERVICE_LIST[svc].systemd_name) - return ordered_list - - def get_config_from_file(): -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index e101087ac2d738eb95cc643bfb12faaf5e65f0be..f424e7cd76d24a5a633a4f4babf3e112537be92c 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -71,6 +71,7 @@ from ipaserver.install import replication - from ipaserver.install import sysupgrade - from ipaserver.install.dogtaginstance import DogtagInstance - from ipaserver.plugins import ldap2 -+from ipaserver.masters import ENABLED_SERVICE - - logger = logging.getLogger(__name__) - -@@ -1304,7 +1305,7 @@ class CAInstance(DogtagInstance): - config = ['caRenewalMaster'] - else: - config = [] -- self._ldap_enable(u'enabledService', "CA", self.fqdn, basedn, config) -+ self._ldap_enable(ENABLED_SERVICE, "CA", self.fqdn, basedn, config) - - def setup_lightweight_ca_key_retrieval(self): - if sysupgrade.get_upgrade_state('dogtag', 'setup_lwca_key_retrieval'): -diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py -index b536685f5f1f3fccab07fd37aa001958e2d38420..19260ac7f23a7c6f3a6328d4f146510a186b706e 100644 ---- a/ipaserver/install/ipa_kra_install.py -+++ b/ipaserver/install/ipa_kra_install.py -@@ -41,6 +41,7 @@ from ipaserver.install.installutils import create_replica_config - from ipaserver.install import dogtaginstance - from ipaserver.install import kra - from ipaserver.install.installutils import ReplicaConfig -+from ipaserver.masters import find_providing_server - - logger = logging.getLogger(__name__) - -@@ -206,8 +207,14 @@ class KRAInstaller(KRAInstall): - config.subject_base = attrs.get('ipacertificatesubjectbase')[0] - - if config.kra_host_name is None: -- config.kra_host_name = service.find_providing_server( -- 'KRA', api.Backend.ldap2, api.env.ca_host) -+ config.kra_host_name = find_providing_server( -+ 'KRA', api.Backend.ldap2, [api.env.ca_host] -+ ) -+ if config.kra_host_name is None: -+ # all CA/KRA servers are down or unreachable. -+ raise admintool.ScriptError( -+ "Failed to find an active KRA server!" -+ ) - custodia = custodiainstance.get_custodia_instance( - config, custodiainstance.CustodiaModes.KRA_PEER) - else: -diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py -index 0337bb22fea44f95ee9077423136353a991325db..d6725dff11599a8755a29b6707dc7b451258629f 100644 ---- a/ipaserver/install/opendnssecinstance.py -+++ b/ipaserver/install/opendnssecinstance.py -@@ -15,6 +15,7 @@ from subprocess import CalledProcessError - from ipalib.install import sysrestore - from ipaserver.install import service - from ipaserver.install import installutils -+from ipaserver.masters import ENABLED_SERVICE - from ipapython.dn import DN - from ipapython import ipautil - from ipaplatform import services -@@ -45,7 +46,7 @@ def get_dnssec_key_masters(conn): - filter_attrs = { - u'cn': u'DNSSEC', - u'objectclass': u'ipaConfigObject', -- u'ipaConfigString': [KEYMASTER, u'enabledService'], -+ u'ipaConfigString': [KEYMASTER, ENABLED_SERVICE], - } - only_masters_f = conn.make_filter(filter_attrs, rules=conn.MATCH_ALL) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index b221e1291f973e7255263a39cfd680af1321598d..37ecbe4146fa908c30fb708037fcaa47af1a258b 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -46,6 +46,7 @@ from ipaserver.install.installutils import ( - validate_mask) - from ipaserver.install.replication import ( - ReplicationManager, replica_conn_check) -+from ipaserver.masters import find_providing_servers, find_providing_server - import SSSDConfig - from subprocess import CalledProcessError - -@@ -1257,9 +1258,10 @@ def promote_check(installer): - if subject_base is not None: - config.subject_base = DN(subject_base) - -- # Find if any server has a CA -- ca_host = service.find_providing_server( -- 'CA', conn, config.ca_host_name) -+ # Find any server with a CA -+ ca_host = find_providing_server( -+ 'CA', conn, [config.ca_host_name] -+ ) - if ca_host is not None: - config.ca_host_name = ca_host - ca_enabled = True -@@ -1280,14 +1282,16 @@ def promote_check(installer): - "custom certificates.") - raise ScriptError(rval=3) - -- kra_host = service.find_providing_server( -- 'KRA', conn, config.kra_host_name) -+ # Find any server with a KRA -+ kra_host = find_providing_server( -+ 'KRA', conn, [config.kra_host_name] -+ ) - if kra_host is not None: - config.kra_host_name = kra_host - kra_enabled = True - else: - if options.setup_kra: -- logger.error("There is no KRA server in the domain, " -+ logger.error("There is no active KRA server in the domain, " - "can't setup a KRA clone") - raise ScriptError(rval=3) - kra_enabled = False -@@ -1577,7 +1581,7 @@ def install(installer): - # Enable configured services and update DNS SRV records - service.enable_services(config.host_name) - api.Command.dns_update_system_records() -- ca_servers = service.find_providing_servers('CA', api.Backend.ldap2, api) -+ ca_servers = find_providing_servers('CA', api.Backend.ldap2, api=api) - api.Backend.ldap2.disconnect() - - # Everything installed properly, activate ipa service. -diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py -index baefc0076990e67e56dfa68da48b56f4cd55849f..a030801175491f65dc83aa9d42afdb1dfdb65b0f 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -38,34 +38,15 @@ from ipapython import kerberos - from ipalib import api, errors - from ipaplatform import services - from ipaplatform.paths import paths -+from ipaserver.masters import ( -+ CONFIGURED_SERVICE, ENABLED_SERVICE, SERVICE_LIST -+) - - logger = logging.getLogger(__name__) - - if six.PY3: - unicode = str - --# The service name as stored in cn=masters,cn=ipa,cn=etc. In the tuple --# the first value is the *nix service name, the second the start order. --SERVICE_LIST = { -- 'KDC': ('krb5kdc', 10), -- 'KPASSWD': ('kadmin', 20), -- 'DNS': ('named', 30), -- 'HTTP': ('httpd', 40), -- 'KEYS': ('ipa-custodia', 41), -- 'NTP': ('ntpd', 45), -- 'CA': ('pki-tomcatd', 50), -- 'KRA': ('pki-tomcatd', 51), -- 'ADTRUST': ('smb', 60), -- 'EXTID': ('winbind', 70), -- 'OTPD': ('ipa-otpd', 80), -- 'DNSKeyExporter': ('ipa-ods-exporter', 90), -- 'DNSSEC': ('ods-enforcerd', 100), -- 'DNSKeySync': ('ipa-dnskeysyncd', 110), --} -- --CONFIGURED_SERVICE = u'configuredService' --ENABLED_SERVICE = u'enabledService' -- - - def print_msg(message, output_fd=sys.stdout): - logger.debug("%s", message) -@@ -117,44 +98,6 @@ def add_principals_to_group(admin_conn, group, member_attr, principals): - pass - - --def find_providing_servers(svcname, conn, api): -- """ -- Find servers that provide the given service. -- -- :param svcname: The service to find -- :param conn: a connection to the LDAP server -- :return: list of host names (possibly empty) -- -- """ -- dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -- query_filter = conn.make_filter({'objectClass': 'ipaConfigObject', -- 'ipaConfigString': ENABLED_SERVICE, -- 'cn': svcname}, rules='&') -- try: -- entries, _trunc = conn.find_entries(filter=query_filter, base_dn=dn) -- except errors.NotFound: -- return [] -- else: -- return [entry.dn[1].value for entry in entries] -- -- --def find_providing_server(svcname, conn, host_name=None, api=api): -- """ -- Find a server that provides the given service. -- -- :param svcname: The service to find -- :param conn: a connection to the LDAP server -- :param host_name: the preferred server -- :return: the selected host name -- -- """ -- servers = find_providing_servers(svcname, conn, api) -- if len(servers) == 0: -- return None -- if host_name in servers: -- return host_name -- return servers[0] -- - - def case_insensitive_attr_has_value(attr, value): - """ -@@ -618,7 +561,7 @@ class Service(object): - - def _ldap_enable(self, value, name, fqdn, ldap_suffix, config): - extra_config_opts = [ -- ' '.join([u'startOrder', unicode(SERVICE_LIST[name][1])]) -+ u'startOrder {}'.format(SERVICE_LIST[name].startorder), - ] - extra_config_opts.extend(config) - -diff --git a/ipaserver/masters.py b/ipaserver/masters.py -new file mode 100644 -index 0000000000000000000000000000000000000000..171c3abe0d6eea5aa6bcc642815eceae3ae885e7 ---- /dev/null -+++ b/ipaserver/masters.py -@@ -0,0 +1,123 @@ -+# -+# Copyright (C) 2018 FreeIPA Contributors see COPYING for license -+# -+"""Helpers services in for cn=masters,cn=ipa,cn=etc -+""" -+ -+from __future__ import absolute_import -+ -+import collections -+import logging -+import random -+ -+from ipapython.dn import DN -+from ipalib import api -+from ipalib import errors -+ -+logger = logging.getLogger(__name__) -+ -+# constants for ipaConfigString -+CONFIGURED_SERVICE = u'configuredService' -+ENABLED_SERVICE = u'enabledService' -+ -+# The service name as stored in cn=masters,cn=ipa,cn=etc. The values are: -+# 0: systemd service name -+# 1: start order for system service -+# 2: LDAP server entry CN, also used as SERVICE_LIST key -+service_definition = collections.namedtuple( -+ "service_definition", -+ "systemd_name startorder service_entry" -+) -+ -+SERVICES = [ -+ service_definition('krb5kdc', 10, 'KDC'), -+ service_definition('kadmin', 20, 'KPASSWD'), -+ service_definition('named', 30, 'DNS'), -+ service_definition('httpd', 40, 'HTTP'), -+ service_definition('ipa-custodia', 41, 'KEYS'), -+ service_definition('ntpd', 45, 'NTP'), -+ service_definition('pki-tomcatd', 50, 'CA'), -+ service_definition('pki-tomcatd', 51, 'KRA'), -+ service_definition('smb', 60, 'ADTRUST'), -+ service_definition('winbind', 70, 'EXTID'), -+ service_definition('ipa-otpd', 80, 'OTPD'), -+ service_definition('ipa-ods-exporter', 90, 'DNSKeyExporter'), -+ service_definition('ods-enforcerd', 100, 'DNSSEC'), -+ service_definition('ipa-dnskeysyncd', 110, 'DNSKeySync'), -+] -+ -+SERVICE_LIST = {s.service_entry: s for s in SERVICES} -+ -+ -+def find_providing_servers(svcname, conn=None, preferred_hosts=(), api=api): -+ """Find servers that provide the given service. -+ -+ :param svcname: The service to find -+ :param preferred_hosts: preferred servers -+ :param conn: a connection to the LDAP server -+ :param api: ipalib.API instance -+ :return: list of host names in randomized order (possibly empty) -+ -+ Preferred servers are moved to the front of the list if and only if they -+ are found as providing servers. -+ """ -+ assert isinstance(preferred_hosts, (tuple, list)) -+ if svcname not in SERVICE_LIST: -+ raise ValueError("Unknown service '{}'.".format(svcname)) -+ if conn is None: -+ conn = api.Backend.ldap2 -+ -+ dn = DN(api.env.container_masters, api.env.basedn) -+ query_filter = conn.make_filter( -+ { -+ 'objectClass': 'ipaConfigObject', -+ 'ipaConfigString': ENABLED_SERVICE, -+ 'cn': svcname -+ }, -+ rules='&' -+ ) -+ try: -+ entries, _trunc = conn.find_entries( -+ filter=query_filter, -+ attrs_list=[], -+ base_dn=dn -+ ) -+ except errors.NotFound: -+ return [] -+ -+ # unique list of host names, DNS is case insensitive -+ servers = list(set(entry.dn[1].value.lower() for entry in entries)) -+ # shuffle the list like DNS SRV would randomize it -+ random.shuffle(servers) -+ # Move preferred hosts to front -+ for host_name in reversed(preferred_hosts): -+ host_name = host_name.lower() -+ try: -+ servers.remove(host_name) -+ except ValueError: -+ # preferred server not found, log and ignore -+ logger.warning( -+ "Lookup failed: Preferred host %s does not provide %s.", -+ host_name, svcname -+ ) -+ else: -+ servers.insert(0, host_name) -+ return servers -+ -+ -+def find_providing_server(svcname, conn=None, preferred_hosts=(), api=api): -+ """Find a server that provides the given service. -+ -+ :param svcname: The service to find -+ :param conn: a connection to the LDAP server -+ :param host_name: the preferred server -+ :param api: ipalib.API instance -+ :return: the selected host name or None -+ """ -+ servers = find_providing_servers( -+ svcname, conn=conn, preferred_hosts=preferred_hosts, api=api -+ ) -+ if not servers: -+ return None -+ else: -+ return servers[0] -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index da77f507cb2307eeec63acd0ab9d58c985ea8fe2..ff750e9d38ff98e0e1fa1c2eee5a3d0719da94bf 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -55,6 +55,7 @@ from ipalib import output - from ipapython import dnsutil, kerberos - from ipapython.dn import DN - from ipaserver.plugins.service import normalize_principal, validate_realm -+from ipaserver.masters import ENABLED_SERVICE, CONFIGURED_SERVICE - - try: - import pyhbac -@@ -297,19 +298,14 @@ def caacl_check(principal, ca, profile_id): - def ca_kdc_check(api_instance, hostname): - master_dn = api_instance.Object.server.get_dn(unicode(hostname)) - kdc_dn = DN(('cn', 'KDC'), master_dn) -- -+ wanted = {ENABLED_SERVICE, CONFIGURED_SERVICE} - try: - kdc_entry = api_instance.Backend.ldap2.get_entry( - kdc_dn, ['ipaConfigString']) -- -- ipaconfigstring = {val.lower() for val in kdc_entry['ipaConfigString']} -- -- if 'enabledservice' not in ipaconfigstring \ -- and 'configuredservice' not in ipaconfigstring: -+ if not wanted.intersection(kdc_entry['ipaConfigString']): - raise errors.NotFound( - reason=_("enabledService/configuredService not in " - "ipaConfigString kdc entry")) -- - except errors.NotFound: - raise errors.ACIError( - info=_("Host '%(hostname)s' is not an active KDC") -diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py -index 5a44f00c583cd4bae8211a511f907c4e179bb3f6..17e2225688c0c3878ef22e5979c65e30f971b5b3 100644 ---- a/ipaserver/plugins/dogtag.py -+++ b/ipaserver/plugins/dogtag.py -@@ -255,6 +255,7 @@ from ipalib import Backend, api - from ipapython.dn import DN - import ipapython.cookie - from ipapython import dogtag, ipautil, certdb -+from ipaserver.masters import find_providing_server - - if api.env.in_server: - import pki -@@ -1208,56 +1209,6 @@ def parse_updateCRL_xml(doc): - return response - - --def host_has_service(host, ldap2, service='CA'): -- """ -- :param host: A host which might be a master for a service. -- :param ldap2: connection to the local database -- :param service: The service for which the host might be a master. -- :return: (true, false) -- -- Check if a specified host is a master for a specified service. -- """ -- base_dn = DN(('cn', host), ('cn', 'masters'), ('cn', 'ipa'), -- ('cn', 'etc'), api.env.basedn) -- filter_attrs = { -- 'objectClass': 'ipaConfigObject', -- 'cn': service, -- 'ipaConfigString': 'enabledService', -- } -- query_filter = ldap2.make_filter(filter_attrs, rules='&') -- try: -- ent, _trunc = ldap2.find_entries(filter=query_filter, base_dn=base_dn) -- if len(ent): -- return True -- except Exception: -- pass -- return False -- -- --def select_any_master(ldap2, service='CA'): -- """ -- :param ldap2: connection to the local database -- :param service: The service for which we're looking for a master. -- :return: host as str -- -- Select any host which is a master for a specified service. -- """ -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- api.env.basedn) -- filter_attrs = { -- 'objectClass': 'ipaConfigObject', -- 'cn': service, -- 'ipaConfigString': 'enabledService',} -- query_filter = ldap2.make_filter(filter_attrs, rules='&') -- try: -- ent, _trunc = ldap2.find_entries(filter=query_filter, base_dn=base_dn) -- if len(ent): -- entry = random.choice(ent) -- return entry.dn[1].value -- except Exception: -- pass -- return None -- - #------------------------------------------------------------------------------- - - from ipalib import Registry, errors, SkipPluginModule -@@ -1265,7 +1216,6 @@ if api.env.ra_plugin != 'dogtag': - # In this case, abort loading this plugin module... - raise SkipPluginModule(reason='dogtag not selected as RA plugin') - import os --import random - from ipaserver.plugins import rabase - from ipalib.constants import TYPE_ERROR - from ipalib import _ -@@ -1330,17 +1280,19 @@ class RestClient(Backend): - 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"): -- 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"): -- object.__setattr__(self, '_ca_host', api.env.host) -- else: -- 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 -+ preferred = [api.env.ca_host] -+ if api.env.host != api.env.ca_host: -+ preferred.append(api.env.host) -+ ca_host = find_providing_server( -+ 'CA', conn=self.api.Backend.ldap2, preferred_hosts=preferred, -+ api=self.api -+ ) -+ if ca_host is None: -+ # TODO: need during installation, CA is not yet set as enabled -+ ca_host = api.env.ca_host -+ # object is locked, need to use __setattr__() -+ object.__setattr__(self, '_ca_host', ca_host) -+ return ca_host - - def __enter__(self): - """Log into the REST API""" -@@ -2082,9 +2034,7 @@ class kra(Backend): - """ - - def __init__(self, api, kra_port=443): -- - self.kra_port = kra_port -- - super(kra, self).__init__(api) - - @property -@@ -2095,17 +2045,18 @@ class kra(Backend): - - Select our KRA host. - """ -- ldap2 = self.api.Backend.ldap2 -- if host_has_service(api.env.ca_host, ldap2, "KRA"): -- return api.env.ca_host -+ preferred = [api.env.ca_host] - if api.env.host != api.env.ca_host: -- if host_has_service(api.env.host, ldap2, "KRA"): -- return api.env.host -- host = select_any_master(ldap2, "KRA") -- if host: -- return host -- else: -- return api.env.ca_host -+ preferred.append(api.env.host) -+ -+ kra_host = find_providing_server( -+ 'KRA', self.api.Backend.ldap2, preferred_hosts=preferred, -+ api=self.api -+ ) -+ if kra_host is None: -+ # TODO: need during installation, KRA is not yet set as enabled -+ kra_host = api.env.ca_host -+ return kra_host - - @contextlib.contextmanager - def get_client(self): -diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py -index 994a59e35bb5d3a007e3d63bb273ba9ea552407d..af4e63710136a15e1673210c3e2207658698fbb5 100644 ---- a/ipaserver/servroles.py -+++ b/ipaserver/servroles.py -@@ -79,7 +79,7 @@ import six - - from ipalib import _, errors - from ipapython.dn import DN -- -+from ipaserver.masters import ENABLED_SERVICE - - if six.PY3: - unicode = str -@@ -483,11 +483,8 @@ class ServiceBasedRole(BaseServerRole): - :param entry: LDAPEntry of the service - :returns: True if the service entry is enabled, False otherwise - """ -- enabled_value = 'enabledservice' -- ipaconfigstring_values = set( -- e.lower() for e in entry.get('ipaConfigString', [])) -- -- return enabled_value in ipaconfigstring_values -+ ipaconfigstring_values = set(entry.get('ipaConfigString', [])) -+ return ENABLED_SERVICE in ipaconfigstring_values - - def _get_services_by_masters(self, entries): - """ -diff --git a/ipatests/test_ipaserver/test_serverroles.py b/ipatests/test_ipaserver/test_serverroles.py -index 76f1378ed5a94069cdef918d577e3658b78ecc43..e1bf0254dddfe03ade4fe72419b609de8e95b79a 100644 ---- a/ipatests/test_ipaserver/test_serverroles.py -+++ b/ipatests/test_ipaserver/test_serverroles.py -@@ -16,6 +16,7 @@ import pytest - from ipaplatform.paths import paths - from ipalib import api, create_api, errors - from ipapython.dn import DN -+from ipaserver.masters import ENABLED_SERVICE - - pytestmark = pytest.mark.needs_ipaapi - -@@ -25,7 +26,7 @@ def _make_service_entry(ldap_backend, dn, enabled=True, other_config=None): - 'objectClass': ['top', 'nsContainer', 'ipaConfigObject'], - } - if enabled: -- mods.update({'ipaConfigString': ['enabledService']}) -+ mods.update({'ipaConfigString': [ENABLED_SERVICE]}) - - if other_config is not None: - mods.setdefault('ipaConfigString', []) --- -2.20.1 - diff --git a/SOURCES/0005-Use-api.env.container_masters.patch b/SOURCES/0005-Use-api.env.container_masters.patch deleted file mode 100644 index 97a8b44..0000000 --- a/SOURCES/0005-Use-api.env.container_masters.patch +++ /dev/null @@ -1,252 +0,0 @@ -From 3283ba88cdd7821a430132dec23a788ea4241f76 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Wed, 27 Mar 2019 11:03:00 +0100 -Subject: [PATCH] Use api.env.container_masters - -Replace occurences of ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc') -with api.env.container_masters. - -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner ---- - ipaserver/install/bindinstance.py | 3 +-- - ipaserver/install/cainstance.py | 7 +++---- - ipaserver/install/dns.py | 4 ++-- - ipaserver/install/ipa_backup.py | 3 ++- - ipaserver/install/ipa_restore.py | 3 ++- - ipaserver/install/krbinstance.py | 6 +----- - ipaserver/install/plugins/ca_renewal_master.py | 3 +-- - ipaserver/install/replication.py | 3 +-- - ipaserver/install/server/upgrade.py | 4 ++-- - ipaserver/install/service.py | 11 +++++------ - ipaserver/plugins/baseldap.py | 2 +- - ipaserver/plugins/domainlevel.py | 13 +++---------- - 12 files changed, 24 insertions(+), 38 deletions(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index c175ca4f23b4f4440e1acaac2495276388daf3ae..6156ecdfbd1a62d5b1e0a26db47ef2b9a9448bc1 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -862,8 +862,7 @@ class BindInstance(service.Service): - - def __add_others(self): - entries = api.Backend.ldap2.get_entries( -- DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- self.suffix), -+ DN(api.env.container_masters, self.suffix), - api.Backend.ldap2.SCOPE_ONELEVEL, None, ['dn']) - - for entry in entries: -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index f424e7cd76d24a5a633a4f4babf3e112537be92c..2946b5cc2b4b8b708a060aa79d1b7ab0e7b4e651 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1173,8 +1173,8 @@ class CAInstance(DogtagInstance): - if fqdn is None: - fqdn = api.env.host - -- dn = DN(('cn', 'CA'), ('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), -- ('cn', 'etc'), api.env.basedn) -+ dn = DN(('cn', 'CA'), ('cn', fqdn), api.env.container_masters, -+ api.env.basedn) - renewal_filter = '(ipaConfigString=caRenewalMaster)' - try: - api.Backend.ldap2.get_entries(base_dn=dn, filter=renewal_filter, -@@ -1188,8 +1188,7 @@ class CAInstance(DogtagInstance): - if fqdn is None: - fqdn = api.env.host - -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- api.env.basedn) -+ base_dn = DN(api.env.container_masters, api.env.basedn) - filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))' - try: - entries = api.Backend.ldap2.get_entries( -diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py -index b17848a80c4300ed74aedc1e29a0dedbee79e6d9..930e038e4d7629563d2cea39fe581987dd0edfef 100644 ---- a/ipaserver/install/dns.py -+++ b/ipaserver/install/dns.py -@@ -98,8 +98,8 @@ def _disable_dnssec(): - api.env.basedn) - - conn = api.Backend.ldap2 -- dn = DN(('cn', 'DNSSEC'), ('cn', api.env.host), ('cn', 'masters'), -- ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ dn = DN(('cn', 'DNSSEC'), ('cn', api.env.host), -+ api.env.container_masters, api.env.basedn) - try: - entry = conn.get_entry(dn) - except errors.NotFound: -diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py -index 789955a67dfc255285a2c82d9a8060495c3469e2..cef01d30454ea1adb8bf9c68f428b9555f1b9557 100644 ---- a/ipaserver/install/ipa_backup.py -+++ b/ipaserver/install/ipa_backup.py -@@ -576,7 +576,8 @@ class Backup(admintool.AdminTool): - config.set('ipa', 'ipa_version', str(version.VERSION)) - config.set('ipa', 'version', '1') - -- dn = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ dn = DN(('cn', api.env.host), api.env.container_masters, -+ api.env.basedn) - services_cns = [] - try: - conn = self.get_connection() -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index 8b2f5bef7c9b1b8e2e2bae4e88850cf18b67b889..bd065a038db4d523048f0566f65458402d801e18 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -507,7 +507,8 @@ class Restore(admintool.AdminTool): - master, e) - continue - -- master_dn = DN(('cn', master), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ master_dn = DN(('cn', master), api.env.container_masters, -+ api.env.basedn) - try: - services = repl.conn.get_entries(master_dn, - repl.conn.SCOPE_ONELEVEL) -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index aa9243dc69674a00f2e1bcdc3e71d44ae8862fbe..319eeb82bcbe61acd70b2943982b6fec6fa33f92 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -470,11 +470,7 @@ class KrbInstance(service.Service): - 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'), -+ dn = DN(('cn', 'KDC'), ('cn', self.fqdn), api.env.container_masters, - self.suffix) - - entry = ldap.get_entry(dn, ['ipaConfigString']) -diff --git a/ipaserver/install/plugins/ca_renewal_master.py b/ipaserver/install/plugins/ca_renewal_master.py -index 618f51244019c2a77a9d0a93437f95c037f1a728..259bd5a991d39adb9f30fe5b22e59c7eef09cfc6 100644 ---- a/ipaserver/install/plugins/ca_renewal_master.py -+++ b/ipaserver/install/plugins/ca_renewal_master.py -@@ -46,8 +46,7 @@ class update_ca_renewal_master(Updater): - return False, [] - - ldap = self.api.Backend.ldap2 -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- self.api.env.basedn) -+ base_dn = DN(self.api.env.container_masters, self.api.env.basedn) - dn = DN(('cn', 'CA'), ('cn', self.api.env.host), base_dn) - filter = '(&(cn=CA)(ipaConfigString=caRenewalMaster))' - try: -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 70629b4528f033908c584bfaf0793cfa4ce259d4..8644b9ff618d28614a319d6da6a2041fea3c1c1f 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -1419,8 +1419,7 @@ class ReplicationManager(object): - - # delete master entry with all active services - try: -- dn = DN(('cn', replica), ('cn', 'masters'), ('cn', 'ipa'), -- ('cn', 'etc'), self.suffix) -+ dn = DN(('cn', replica), api.env.container_masters, self.suffix) - entries = self.conn.get_entries(dn, ldap.SCOPE_SUBTREE) - if entries: - entries.sort(key=lambda x: len(x.dn), reverse=True) -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index 57c70ea9250bf6fcf027665304e02cc6def8e442..f4389d37909fc0b5aed960638de67243906b634d 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1244,8 +1244,8 @@ def uninstall_dogtag_9(ds, http): - logger.debug('Dogtag is version 10 or above') - return - -- dn = DN(('cn', 'CA'), ('cn', api.env.host), ('cn', 'masters'), -- ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ dn = DN(('cn', 'CA'), ('cn', api.env.host), api.env.container_masters, -+ api.env.basedn) - try: - api.Backend.ldap2.delete_entry(dn) - except ipalib.errors.PublicError as e: -diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py -index a030801175491f65dc83aa9d42afdb1dfdb65b0f..261eedc85be24478b99e5ae8886aec7bc23a80ed 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -134,8 +134,7 @@ def set_service_entry_config(name, fqdn, config_values, - assert isinstance(ldap_suffix, DN) - - entry_name = DN( -- ('cn', name), ('cn', fqdn), ('cn', 'masters'), -- ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) -+ ('cn', name), ('cn', fqdn), api.env.container_masters, ldap_suffix) - - # enable disabled service - try: -@@ -577,8 +576,8 @@ class Service(object): - def ldap_disable(self, name, fqdn, ldap_suffix): - assert isinstance(ldap_suffix, DN) - -- entry_dn = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'), -- ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) -+ entry_dn = DN(('cn', name), ('cn', fqdn), api.env.container_masters, -+ ldap_suffix) - search_kw = {'ipaConfigString': ENABLED_SERVICE} - filter = api.Backend.ldap2.make_filter(search_kw) - try: -@@ -611,8 +610,8 @@ class Service(object): - logger.debug("service %s startup entry disabled", name) - - def ldap_remove_service_container(self, name, fqdn, ldap_suffix): -- entry_dn = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'), -- ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) -+ entry_dn = DN(('cn', name), ('cn', fqdn), -+ self.api.env.container_masters, ldap_suffix) - try: - api.Backend.ldap2.delete_entry(entry_dn) - except errors.NotFound: -diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py -index 08ddc6d10d6431f51296bca9ae28aca8fa8586b2..25449b5aec72cbdbfb57527aa834cc69291398d6 100644 ---- a/ipaserver/plugins/baseldap.py -+++ b/ipaserver/plugins/baseldap.py -@@ -497,7 +497,7 @@ def host_is_master(ldap, fqdn): - - Raises an exception if a master, otherwise returns nothing. - """ -- master_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ master_dn = DN(('cn', fqdn), api.env.container_masters, api.env.basedn) - try: - ldap.get_entry(master_dn, ['objectclass']) - raise errors.ValidationError(name='hostname', error=_('An IPA master host cannot be deleted or disabled')) -diff --git a/ipaserver/plugins/domainlevel.py b/ipaserver/plugins/domainlevel.py -index 306ca0a6d147b2c0dc7a91ee1aefc0e7a5c98048..0d36dc08c07612dc565417a66ab9c467eb7f0555 100644 ---- a/ipaserver/plugins/domainlevel.py -+++ b/ipaserver/plugins/domainlevel.py -@@ -72,25 +72,18 @@ def check_conflict_entries(ldap, api, desired_value): - except errors.NotFound: - pass - -+ - def get_master_entries(ldap, api): - """ - Returns list of LDAPEntries representing IPA masters. - """ -- -- container_masters = DN( -- ('cn', 'masters'), -- ('cn', 'ipa'), -- ('cn', 'etc'), -- api.env.basedn -- ) -- -+ dn = DN(api.env.container_masters, api.env.basedn) - masters, _dummy = ldap.find_entries( - filter="(cn=*)", -- base_dn=container_masters, -+ base_dn=dn, - scope=ldap.SCOPE_ONELEVEL, - paged_search=True, # we need to make sure to get all of them - ) -- - return masters - - --- -2.20.1 - diff --git a/SOURCES/0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch b/SOURCES/0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch new file mode 100644 index 0000000..56ee540 --- /dev/null +++ b/SOURCES/0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch @@ -0,0 +1,158 @@ +From 9cb4436694d2fa5f7a56fa774e5283f0b46cc18f Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 31 Mar 2019 12:37:21 +0300 +Subject: [PATCH 2/2] ipasam: use SID formatting calls to libsss_idmap + +Samba 4.10 moved away to private libraries two functions we used to +convert a binary SID structre to strings: + - sid_talloc_string() + - sid_string_dbg() + +We already used libsss_idmap to convert textual representation of SIDs +to a binary one, use the reverse function too. + +libsss_idmap code operates on talloc structures, so we need to adopt a +bit a place where sid_string_dbg() was used because it assumed a static +buffer was provided by sid_string_dbg(). + +Finally, sid_talloc_string()'s replacement moves allocated memory to the +right context so that a memory will be freed earlier. Our SSSD idmap +context is a long-living one while in all cases where we were using +sid_talloc_string() we free the context much earlier. + +Resolves: https://pagure.io/freeipa/issue/7893 +Reviewed-By: Christian Heimes +(cherry picked from commit 137af1d2c38925404dc92f70321ac0f5fb1cf5eb) +--- + daemons/ipa-sam/ipa_sam.c | 52 ++++++++++++++++++++++++++++----------- + 1 file changed, 37 insertions(+), 15 deletions(-) + +diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c +index 2f78f82f9..851cbc39a 100644 +--- a/daemons/ipa-sam/ipa_sam.c ++++ b/daemons/ipa-sam/ipa_sam.c +@@ -104,8 +104,6 @@ enum ndr_err_code ndr_pull_trustAuthInOutBlob(struct ndr_pull *ndr, int ndr_flag + bool sid_check_is_builtin(const struct dom_sid *sid); /* available in libpdb.so */ + /* available in libpdb.so, renamed from sid_check_is_domain() in c43505b621725c9a754f0ee98318d451b093f2ed */ + bool sid_linearize(char *outbuf, size_t len, const struct dom_sid *sid); /* available in libsmbconf.so */ +-char *sid_string_talloc(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); /* available in libsmbconf.so */ +-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 */ +@@ -261,6 +259,18 @@ static bool sid_compose(struct dom_sid *dst, const struct dom_sid *dom_sid, + return true; + } + ++static char *sid_talloc_string(struct sss_idmap_ctx *ctx, void *final_ctx, const struct dom_sid *dom_sid) ++{ ++ enum idmap_error_code ret; ++ char *result = NULL; ++ ret = sss_idmap_smb_sid_to_sid(ctx, discard_const(dom_sid), &result); ++ if (ret != IDMAP_SUCCESS) { ++ return NULL; ++ } ++ ++ return talloc_move(final_ctx, &result); ++} ++ + static bool is_null_sid(const struct dom_sid *sid) + { + size_t c; +@@ -519,8 +529,18 @@ static bool ldapsam_extract_rid_from_entry(LDAP *ldap_struct, + } + + if (dom_sid_compare_domain(sid, domain_sid) != 0) { +- DEBUG(10, ("SID %s is not in expected domain %s\n", +- str, sid_string_dbg(domain_sid))); ++ char *debug_domain_sid = NULL; ++ err = sss_idmap_smb_sid_to_sid(idmap_ctx, ++ discard_const(domain_sid), ++ &debug_domain_sid); ++ if (err != IDMAP_SUCCESS) { ++ DEBUG(10, ("SID %s is not in expected domain.\n", ++ str)); ++ } else { ++ DEBUG(10, ("SID %s is not in expected domain %s\n", ++ str, debug_domain_sid)); ++ talloc_free(debug_domain_sid); ++ } + res = false; + goto done; + } +@@ -589,7 +609,7 @@ static NTSTATUS ldapsam_lookup_rids(struct pdb_methods *methods, + allsids = talloc_asprintf_append_buffer( + allsids, "(%s=%s)", + LDAP_ATTRIBUTE_SID, +- sid_string_talloc(mem_ctx, &sid)); ++ sid_talloc_string(ipasam_state->idmap_ctx, mem_ctx, &sid)); + if (allsids == NULL) { + goto done; + } +@@ -790,7 +810,8 @@ static bool ldapsam_sid_to_id(struct pdb_methods *methods, + filter = talloc_asprintf(mem_ctx, + "(&(%s=%s)" + "(|(objectClass=%s)(objectClass=%s)))", +- LDAP_ATTRIBUTE_SID, sid_string_talloc(mem_ctx, sid), ++ LDAP_ATTRIBUTE_SID, ++ sid_talloc_string(priv->idmap_ctx, mem_ctx, sid), + LDAP_OBJ_GROUPMAP, LDAP_OBJ_SAMBASAMACCOUNT); + if (filter == NULL) { + DEBUG(5, ("talloc_asprintf failed\n")); +@@ -936,7 +957,7 @@ static bool ipasam_uid_to_sid(struct pdb_methods *methods, uid_t uid, + err = sss_idmap_sid_to_smb_sid(priv->idmap_ctx, + user_sid_string, &user_sid); + if (err != IDMAP_SUCCESS) { +- DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n", ++ DEBUG(3, ("Error creating sid structure for sid '%s'\n", + user_sid_string)); + goto done; + } +@@ -1052,7 +1073,7 @@ found: + err = sss_idmap_sid_to_smb_sid(priv->idmap_ctx, + group_sid_string, &group_sid); + if (err != IDMAP_SUCCESS) { +- DEBUG(3, ("Error calling sid_string_talloc for sid '%s'\n", ++ DEBUG(3, ("Error creating sid structure for sid '%s'\n", + group_sid_string)); + goto done; + } +@@ -1595,11 +1616,11 @@ static bool ipasam_search_grouptype(struct pdb_methods *methods, + state->base = talloc_strdup(search, ipasam_state->base_dn); + state->connection = ipasam_state->ldap_state; + state->scope = LDAP_SCOPE_SUBTREE; +- state->filter = talloc_asprintf(search, "(&(objectclass=%s)" +- "(%s=%s*))", +- LDAP_OBJ_GROUPMAP, +- LDAP_ATTRIBUTE_SID, +- sid_string_talloc(search, sid)); ++ state->filter = talloc_asprintf(search, "(&(objectclass=%s)(%s=%s*))", ++ LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, ++ sid_talloc_string( ++ ipasam_state->idmap_ctx, ++ search, sid)); + state->attrs = talloc_attrs(search, "cn", LDAP_ATTRIBUTE_SID, + "displayName", "description", + NULL); +@@ -2412,7 +2433,7 @@ static NTSTATUS ipasam_get_trusted_domain_by_sid(struct pdb_methods *methods, + char *sid_str; + bool ok; + +- sid_str = sid_string_talloc(mem_ctx, sid); ++ sid_str = sid_talloc_string(ipasam_state->idmap_ctx, mem_ctx, sid); + if (sid_str == NULL) { + return NT_STATUS_NO_MEMORY; + } +@@ -2593,7 +2614,8 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods, + if (!is_null_sid(&td->security_identifier)) { + smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, + LDAP_ATTRIBUTE_TRUST_SID, +- sid_string_talloc(tmp_ctx, &td->security_identifier)); ++ sid_talloc_string(ipasam_state->idmap_ctx, ++ tmp_ctx, &td->security_identifier)); + } + + if (td->trust_type != 0) { +-- +2.21.0 + diff --git a/SOURCES/0006-Consolidate-container_masters-queries.patch b/SOURCES/0006-Consolidate-container_masters-queries.patch deleted file mode 100644 index ad86b7f..0000000 --- a/SOURCES/0006-Consolidate-container_masters-queries.patch +++ /dev/null @@ -1,316 +0,0 @@ -From 406a70cb9e481fb194bbbc67461f3cfd3c97a108 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Wed, 27 Mar 2019 11:30:40 +0100 -Subject: [PATCH] Consolidate container_masters queries - -Replace manual queries of container_masters with new APIs get_masters() -and is_service_enabled(). - -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner ---- - ipaserver/install/bindinstance.py | 8 ++--- - ipaserver/install/ipa_restore.py | 12 ++------ - ipaserver/masters.py | 51 +++++++++++++++++++++++++++++++ - ipaserver/plugins/cert.py | 15 +++------ - ipaserver/plugins/dns.py | 49 ++++------------------------- - ipaserver/plugins/user.py | 15 ++------- - ipaserver/plugins/vault.py | 12 ++------ - 7 files changed, 70 insertions(+), 92 deletions(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 6156ecdfbd1a62d5b1e0a26db47ef2b9a9448bc1..940667db9c40559d5369188395bb18f2d1eac025 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -40,6 +40,7 @@ from ipaserver.dns_data_management import ( - from ipaserver.install import installutils - from ipaserver.install import service - from ipaserver.install import sysupgrade -+from ipaserver.masters import get_masters - from ipapython import ipautil - from ipapython import dnsutil - from ipapython.dnsutil import DNSName -@@ -1037,13 +1038,8 @@ class BindInstance(service.Service): - cname_fqdn[cname] = fqdn - - # get FQDNs of all IPA masters -- ldap = self.api.Backend.ldap2 - try: -- entries = ldap.get_entries( -- DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- self.api.env.basedn), -- ldap.SCOPE_ONELEVEL, None, ['cn']) -- masters = set(e['cn'][0] for e in entries) -+ masters = set(get_masters(self.api.Backend.ldap2)) - except errors.NotFound: - masters = set() - -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index bd065a038db4d523048f0566f65458402d801e18..c7e996bbe284a7eb2d03fbedb4798d3b15f3dcc0 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -41,6 +41,7 @@ from ipaserver.install.replication import (wait_for_task, ReplicationManager, - get_cs_replication_manager) - from ipaserver.install import installutils - from ipaserver.install import dsinstance, httpinstance, cainstance, krbinstance -+from ipaserver.masters import get_masters - from ipapython import ipaldap - import ipapython.errors - from ipaplatform.constants import constants -@@ -485,16 +486,7 @@ class Restore(admintool.AdminTool): - logger.error('Unable to get connection, skipping disabling ' - 'agreements: %s', e) - return -- masters = [] -- dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -- try: -- entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL) -- except Exception as e: -- raise admintool.ScriptError( -- "Failed to read master data: %s" % e) -- else: -- masters = [ent.single_value['cn'] for ent in entries] -- -+ masters = get_masters(conn) - for master in masters: - if master == api.env.host: - continue -diff --git a/ipaserver/masters.py b/ipaserver/masters.py -index 171c3abe0d6eea5aa6bcc642815eceae3ae885e7..6fa8f02332ceaa10ec30aa5142912f351fb58936 100644 ---- a/ipaserver/masters.py -+++ b/ipaserver/masters.py -@@ -121,3 +121,54 @@ def find_providing_server(svcname, conn=None, preferred_hosts=(), api=api): - return None - else: - return servers[0] -+ -+ -+def get_masters(conn=None, api=api): -+ """Get all master hostnames -+ -+ :param conn: a connection to the LDAP server -+ :param api: ipalib.API instance -+ :return: list of hostnames -+ """ -+ if conn is None: -+ conn = api.Backend.ldap2 -+ -+ dn = DN(api.env.container_masters, api.env.basedn) -+ entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL, None, ['cn']) -+ return list(e['cn'][0] for e in entries) -+ -+ -+def is_service_enabled(svcname, conn=None, api=api): -+ """Check if service is enabled on any master -+ -+ The check function only looks for presence of service entries. It -+ ignores enabled/hidden flags. -+ -+ :param svcname: The service to find -+ :param conn: a connection to the LDAP server -+ :param api: ipalib.API instance -+ :return: True/False -+ """ -+ if svcname not in SERVICE_LIST: -+ raise ValueError("Unknown service '{}'.".format(svcname)) -+ if conn is None: -+ conn = api.Backend.ldap2 -+ -+ dn = DN(api.env.container_masters, api.env.basedn) -+ query_filter = conn.make_filter( -+ { -+ 'objectClass': 'ipaConfigObject', -+ 'cn': svcname -+ }, -+ rules='&' -+ ) -+ try: -+ conn.find_entries( -+ filter=query_filter, -+ attrs_list=[], -+ base_dn=dn -+ ) -+ except errors.NotFound: -+ return False -+ else: -+ return True -diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py -index ff750e9d38ff98e0e1fa1c2eee5a3d0719da94bf..36a7a859292b2ddb9dd721e2bf786c6be130f323 100644 ---- a/ipaserver/plugins/cert.py -+++ b/ipaserver/plugins/cert.py -@@ -55,7 +55,9 @@ from ipalib import output - from ipapython import dnsutil, kerberos - from ipapython.dn import DN - from ipaserver.plugins.service import normalize_principal, validate_realm --from ipaserver.masters import ENABLED_SERVICE, CONFIGURED_SERVICE -+from ipaserver.masters import ( -+ ENABLED_SERVICE, CONFIGURED_SERVICE, is_service_enabled -+) - - try: - import pyhbac -@@ -1908,14 +1910,5 @@ class ca_is_enabled(Command): - has_output = output.standard_value - - def execute(self, *args, **options): -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- self.api.env.basedn) -- filter = '(&(objectClass=ipaConfigObject)(cn=CA))' -- try: -- self.api.Backend.ldap2.find_entries( -- base_dn=base_dn, filter=filter, attrs_list=[]) -- except errors.NotFound: -- result = False -- else: -- result = True -+ result = is_service_enabled('CA', conn=self.api.Backend.ldap2) - return dict(result=result, value=pkey_to_value(None, options)) -diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py -index 3c006c5701a426cc03971c9e3361dfd091770241..d6baa2fc1769701ac62b8c6d686fbed74ea3f002 100644 ---- a/ipaserver/plugins/dns.py -+++ b/ipaserver/plugins/dns.py -@@ -86,6 +86,7 @@ from ipaserver.dns_data_management import ( - IPASystemRecords, - IPADomainIsNotManagedByIPAError, - ) -+from ipaserver.masters import find_providing_servers, is_service_enabled - - if six.PY3: - unicode = str -@@ -1593,19 +1594,7 @@ def dnssec_installed(ldap): - :param ldap: ldap connection - :return: True if DNSSEC was installed, otherwise False - """ -- dn = DN(api.env.container_masters, api.env.basedn) -- -- filter_attrs = { -- u'cn': u'DNSSEC', -- u'objectclass': u'ipaConfigObject', -- } -- only_masters_f = ldap.make_filter(filter_attrs, rules=ldap.MATCH_ALL) -- -- try: -- ldap.find_entries(filter=only_masters_f, base_dn=dn) -- except errors.NotFound: -- return False -- return True -+ return is_service_enabled('DNSSEC', conn=ldap) - - - def default_zone_update_policy(zone): -@@ -3191,24 +3180,9 @@ class dnsrecord(LDAPObject): - return cliname - - def get_dns_masters(self): -- ldap = self.api.Backend.ldap2 -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) -- ldap_filter = '(&(objectClass=ipaConfigObject)(cn=DNS))' -- dns_masters = [] -- -- try: -- entries = ldap.find_entries(filter=ldap_filter, base_dn=base_dn)[0] -- -- for entry in entries: -- try: -- master = entry.dn[1]['cn'] -- dns_masters.append(master) -- except (IndexError, KeyError): -- pass -- except errors.NotFound: -- return [] -- -- return dns_masters -+ return find_providing_servers( -+ 'DNS', self.api.Backend.ldap2, preferred_hosts=[api.env.host] -+ ) - - def get_record_entry_attrs(self, entry_attrs): - entry_attrs = entry_attrs.copy() -@@ -4077,19 +4051,8 @@ class dns_is_enabled(Command): - NO_CLI = True - has_output = output.standard_value - -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -- filter = '(&(objectClass=ipaConfigObject)(cn=DNS))' -- - def execute(self, *args, **options): -- ldap = self.api.Backend.ldap2 -- dns_enabled = False -- -- try: -- ldap.find_entries(filter=self.filter, base_dn=self.base_dn) -- dns_enabled = True -- except errors.EmptyResult: -- dns_enabled = False -- -+ dns_enabled = is_service_enabled('DNS', conn=self.api.Backend.ldap2) - return dict(result=dns_enabled, value=pkey_to_value(None, options)) - - -diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py -index 1aa19ab3c2763983b2216e332013b45df1a4a496..980385dc83e93ec4a65726077b34917e21115efa 100644 ---- a/ipaserver/plugins/user.py -+++ b/ipaserver/plugins/user.py -@@ -69,6 +69,7 @@ from ipapython.dn import DN - from ipapython.ipaldap import LDAPClient - from ipapython.ipautil import ipa_generate_password, TMP_PWD_ENTROPY_BITS - from ipalib.capabilities import client_has_capability -+from ipaserver.masters import get_masters - - if six.PY3: - unicode = str -@@ -1105,21 +1106,11 @@ class user_status(LDAPQuery): - attr_list = ['krbloginfailedcount', 'krblastsuccessfulauth', 'krblastfailedauth', 'nsaccountlock'] - - disabled = False -- masters = [] -- # Get list of masters -- try: -- masters, _truncated = ldap.find_entries( -- None, ['*'], DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn), -- ldap.SCOPE_ONELEVEL -- ) -- except errors.NotFound: -- # If this happens we have some pretty serious problems -- logger.error('No IPA masters found!') -+ masters = get_masters(ldap) - - entries = [] - count = 0 -- for master in masters: -- host = master['cn'][0] -+ for host in masters: - if host == api.env.host: - other_ldap = self.obj.backend - else: -diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py -index 682f6bea74df024bd28e15157c9b809888d08c38..a2603217cc3b79c6ec891b4deadeea91364eeeb9 100644 ---- a/ipaserver/plugins/vault.py -+++ b/ipaserver/plugins/vault.py -@@ -34,6 +34,7 @@ from .service import normalize_principal, validate_realm - from ipalib import _, ngettext - from ipapython import kerberos - from ipapython.dn import DN -+from ipaserver.masters import is_service_enabled - - if api.env.in_server: - import pki.account -@@ -1220,14 +1221,5 @@ class kra_is_enabled(Command): - has_output = output.standard_value - - def execute(self, *args, **options): -- base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), -- self.api.env.basedn) -- filter = '(&(objectClass=ipaConfigObject)(cn=KRA))' -- try: -- self.api.Backend.ldap2.find_entries( -- base_dn=base_dn, filter=filter, attrs_list=[]) -- except errors.NotFound: -- result = False -- else: -- result = True -+ result = is_service_enabled('KRA', conn=self.api.Backend.ldap2) - return dict(result=result, value=pkey_to_value(None, options)) --- -2.20.1 - diff --git a/SOURCES/0006-user-stage-transfer-all-attributes-from-preserved-to.patch b/SOURCES/0006-user-stage-transfer-all-attributes-from-preserved-to.patch new file mode 100644 index 0000000..a5276e5 --- /dev/null +++ b/SOURCES/0006-user-stage-transfer-all-attributes-from-preserved-to.patch @@ -0,0 +1,104 @@ +From 5731aa2850d150a90ad84ce5492cd5d8b154e413 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 23 Jul 2019 09:31:53 +0200 +Subject: [PATCH] user-stage: transfer all attributes from preserved to stage + user + +The user-stage command is internally implemented as: +- user_show(all=True) in order to read the user attributes +- loop on the attributes defined as possible to add using stageuser-add and +transform them into new options for stageuser_add (for instance stageuser-add +provides the option --shell for the attribute loginshell, but there is no +option for the attribute businesscategory). +- call stageuser_add in order to create a new entry in the active users subtree +- user-del to remove the previous entry in the staged users subtree + +The issue is in the 2nd step. Only the attributes with a stageuser-add option +are processed. +The logic of the code should be slightly modified, so that all the attributes +read in the first step are processed: +- if they correspond to an option of stageuser-add, process them like it's +currently done. For instance if the entry contains displayname, then it +should be processed as --displayName=value in the stageuser-add cmd +- if they do not correspond to an option of stageuser-add, add them with +--setattr== + +Note that some attributes may need to be filtered, for instance user-show +returns has_password or has_keytab, which do not correspond to attributes +in the LDAP entry. + +Fixes: https://pagure.io/freeipa/issue/7597 +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/plugins/user.py | 44 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) + +diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py +index 980385dc83e93ec4a65726077b34917e21115efa..fbf7b11789c58377366f187211c4e403d0cf7ffe 100644 +--- a/ipaserver/plugins/user.py ++++ b/ipaserver/plugins/user.py +@@ -919,7 +919,29 @@ class user_stage(LDAPMultiQuery): + has_output = output.standard_multi_delete + msg_summary = _('Staged user account "%(value)s"') + ++ # when moving from preserved to stage, some attributes may be ++ # present in the preserved entry but cannot be provided to ++ # stageuser_add ++ # For instance: dn and uid are derived from LOGIN argument ++ # has_keytab, has_password, preserved are virtual attributes ++ # ipauniqueid, krbcanonicalname, sshpubkeyfp, krbextradata ++ # are automatically generated ++ # ipacertmapdata can only be provided with user_add_certmapdata ++ ignore_attrs = [u'dn', u'uid', ++ u'has_keytab', u'has_password', u'preserved', ++ u'ipauniqueid', u'krbcanonicalname', ++ u'sshpubkeyfp', u'krbextradata', ++ u'ipacertmapdata', ++ u'nsaccountlock'] ++ + def execute(self, *keys, **options): ++ ++ def _build_setattr_arg(key, val): ++ if isinstance(val, bytes): ++ return u"{}={}".format(key, val.decode('UTF-8')) ++ else: ++ return u"{}={}".format(key, val) ++ + staged = [] + failed = [] + +@@ -940,8 +962,30 @@ class user_stage(LDAPMultiQuery): + value = value[0] + new_options[param.name] = value + ++ # Some attributes may not be accessible through the Command ++ # options and need to be added with --setattr ++ set_attr = [] ++ for userkey in user.keys(): ++ if userkey in new_options or userkey in self.ignore_attrs: ++ continue ++ value = user[userkey] ++ ++ if isinstance(value, (list, tuple)): ++ for val in value: ++ set_attr.append(_build_setattr_arg(userkey, val)) ++ else: ++ set_attr.append(_build_setattr_arg(userkey, val)) ++ if set_attr: ++ new_options[u'setattr'] = set_attr ++ + try: + self.api.Command.stageuser_add(*single_keys, **new_options) ++ # special handling for certmapdata ++ certmapdata = user.get(u'ipacertmapdata') ++ if certmapdata: ++ self.api.Command.stageuser_add_certmapdata( ++ *single_keys, ++ ipacertmapdata=certmapdata) + try: + self.api.Command.user_del(*multi_keys, preserve=False) + except errors.ExecutionError: +-- +2.20.1 + diff --git a/SOURCES/0007-Replace-hard-coded-paths-with-path-constants.patch b/SOURCES/0007-Replace-hard-coded-paths-with-path-constants.patch deleted file mode 100644 index c84eb02..0000000 --- a/SOURCES/0007-Replace-hard-coded-paths-with-path-constants.patch +++ /dev/null @@ -1,570 +0,0 @@ -From f4995135a97531819503632e72f9910101f5ce61 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Wed, 7 Feb 2018 17:18:07 +0100 -Subject: [PATCH] Replace hard-coded paths with path constants - -Several run() calls used hard-coded paths rather than pre-defined paths -from ipaplatform.paths. The patch fixes all places that I was able to -find with a simple search. - -The fix simplifies Darix's port of freeIPA on openSuSE. - -Signed-off-by: Christian Heimes -Reviewed-By: Rob Crittenden -(cherry picked from commit 2391c75e3d7efcdc5c2f49defa5138fc7e6def06) - -Reviewed-By: Christian Heimes ---- - client/ipa-client-automount | 2 +- - install/tools/ipa-adtrust-install | 2 +- - install/tools/ipa-ca-install | 2 +- - install/tools/ipa-dns-install | 2 +- - ipaclient/install/client.py | 10 ++++---- - ipaplatform/base/paths.py | 8 +++++++ - ipapython/kernel_keyring.py | 24 +++++++++++++------ - ipaserver/install/adtrustinstance.py | 6 +++-- - ipaserver/install/installutils.py | 17 +++++++++---- - ipaserver/install/ipa_backup.py | 6 ++--- - ipaserver/install/ipa_restore.py | 4 ++-- - ipaserver/install/krbinstance.py | 2 +- - ipatests/pytest_ipa/integration/__init__.py | 3 ++- - ipatests/test_integration/test_caless.py | 2 +- - ipatests/test_ipapython/test_ipautil.py | 15 ++++++------ - .../test_caacl_profile_enforcement.py | 3 ++- - ipatests/test_xmlrpc/test_cert_plugin.py | 2 +- - 17 files changed, 70 insertions(+), 40 deletions(-) - -diff --git a/client/ipa-client-automount b/client/ipa-client-automount -index ee55d655c9531c8fb7baebd0e7a99f3db484f7db..6c2816c410642967e95a7b1eb60583600a7f5fb0 100755 ---- a/client/ipa-client-automount -+++ b/client/ipa-client-automount -@@ -92,7 +92,7 @@ def wait_for_sssd(): - time.sleep(1) - while n < 10 and not found: - try: -- ipautil.run(["getent", "passwd", "admin@%s" % api.env.realm]) -+ ipautil.run([paths.GETENT, "passwd", "admin@%s" % api.env.realm]) - found = True - except Exception: - time.sleep(1) -diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install -index a870d136e242affe6627cd4c44a173a80a9ab1c6..9dbfadb6fae193e2f4a54b3a0e226e0a6b1fd26f 100755 ---- a/install/tools/ipa-adtrust-install -+++ b/install/tools/ipa-adtrust-install -@@ -110,7 +110,7 @@ def read_admin_password(admin_name): - - def ensure_admin_kinit(admin_name, admin_password): - try: -- ipautil.run(['kinit', admin_name], stdin=admin_password+'\n') -+ ipautil.run([paths.KINIT, admin_name], stdin=admin_password+'\n') - except ipautil.CalledProcessError: - print("There was error to automatically re-kinit your admin user " - "ticket.") -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index dcdbe884f15b13b92ec68a11d9f00e3e28771b42..55182dc30e4736618f749e78db161fc7eefe37ac 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -352,7 +352,7 @@ def main(): - api.Backend.ldap2.disconnect() - - # execute ipactl to refresh services status -- ipautil.run(['ipactl', 'start', '--ignore-service-failures'], -+ ipautil.run([paths.IPACTL, 'start', '--ignore-service-failures'], - raiseonerr=False) - - -diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install -index 32a17d223ae2bdd9a1ded62defcc272a40d2627b..0e76a5ab93bd37c2f0c9c5ea4894023588697782 100755 ---- a/install/tools/ipa-dns-install -+++ b/install/tools/ipa-dns-install -@@ -151,7 +151,7 @@ def main(): - # Services are enabled in dns_installer.install() - - # execute ipactl to refresh services status -- ipautil.run(['ipactl', 'start', '--ignore-service-failures'], -+ ipautil.run([paths.IPACTL, 'start', '--ignore-service-failures'], - raiseonerr=False) - - api.Backend.ldap2.disconnect() -diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py -index 80b572ce9b5a250c0c32a1d7fcd06ec53af32984..babebfc667c5a096fb2e0238de444ffa3ce62b77 100644 ---- a/ipaclient/install/client.py -+++ b/ipaclient/install/client.py -@@ -1125,7 +1125,7 @@ def configure_sshd_config(fstore, options): - ) - - for candidate in candidates: -- args = ['sshd', '-t', '-f', os.devnull] -+ args = [paths.SSHD, '-t', '-f', os.devnull] - for item in candidate.items(): - args.append('-o') - args.append('%s=%s' % item) -@@ -1157,7 +1157,7 @@ def configure_automount(options): - logger.info('\nConfiguring automount:') - - args = [ -- 'ipa-client-automount', '--debug', '-U', '--location', -+ paths.IPA_CLIENT_AUTOMOUNT, '--debug', '-U', '--location', - options.location - ] - -@@ -2615,7 +2615,7 @@ def _install(options): - subject_base = DN(subject_base) - - if options.principal is not None: -- run(["kdestroy"], raiseonerr=False, env=env) -+ run([paths.KDESTROY], raiseonerr=False, env=env) - - # Obtain the TGT. We do it with the temporary krb5.conf, so that - # only the KDC we're installing under is contacted. -@@ -2954,7 +2954,7 @@ def _install(options): - # Particulary, SSSD might take longer than 6-8 seconds. - while n < 10 and not found: - try: -- ipautil.run(["getent", "passwd", user]) -+ ipautil.run([paths.GETENT, "passwd", user]) - found = True - except Exception as e: - time.sleep(1) -@@ -3036,7 +3036,7 @@ def uninstall(options): - statestore = sysrestore.StateFile(paths.IPA_CLIENT_SYSRESTORE) - - try: -- run(["ipa-client-automount", "--uninstall", "--debug"]) -+ run([paths.IPA_CLIENT_AUTOMOUNT, "--uninstall", "--debug"]) - except Exception as e: - logger.error( - "Unconfigured automount client failed: %s", str(e)) -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index f1327daa11840bb9416cb0a12f2b5a1300b0374b..435d1b7de9083ee74e80da6fef5c3e3cdad654bb 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -25,6 +25,8 @@ This base platform module exports default filesystem paths. - class BasePathNamespace(object): - BASH = "/bin/bash" - BIN_HOSTNAMECTL = "/bin/hostnamectl" -+ ECHO = "/bin/echo" -+ GZIP = "/usr/bin/gzip" - LS = "/bin/ls" - SH = "/bin/sh" - SYSTEMCTL = "/bin/systemctl" -@@ -160,8 +162,10 @@ class BasePathNamespace(object): - GPG = "/usr/bin/gpg" - GPG_AGENT = "/usr/bin/gpg-agent" - IPA_GETCERT = "/usr/bin/ipa-getcert" -+ KADMIN_LOCAL = '/usr/sbin/kadmin.local' - KDESTROY = "/usr/bin/kdestroy" - KINIT = "/usr/bin/kinit" -+ KLIST = "/usr/bin/klist" - BIN_KVNO = "/usr/bin/kvno" - LDAPMODIFY = "/usr/bin/ldapmodify" - LDAPPASSWD = "/usr/bin/ldappasswd" -@@ -207,6 +211,7 @@ class BasePathNamespace(object): - GROUPADD = "/usr/sbin/groupadd" - USERMOD = "/usr/sbin/usermod" - HTTPD = "/usr/sbin/httpd" -+ IPA_CLIENT_AUTOMOUNT = "/usr/sbin/ipa-client-automount" - IPA_CLIENT_INSTALL = "/usr/sbin/ipa-client-install" - IPA_DNS_INSTALL = "/usr/sbin/ipa-dns-install" - SBIN_IPA_JOIN = "/usr/sbin/ipa-join" -@@ -362,6 +367,9 @@ class BasePathNamespace(object): - IF_INET6 = '/proc/net/if_inet6' - AUTHCONFIG = None - IPA_SERVER_UPGRADE = '/usr/sbin/ipa-server-upgrade' -+ KEYCTL = '/usr/bin/keyctl' -+ GETENT = '/usr/bin/getent' -+ SSHD = '/usr/sbin/sshd' - - - paths = BasePathNamespace() -diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py -index 4b7010e32e90a52fefb0ebbd4fec930ae82b7ea6..6ae1e74493810fa25093fe134447dd4ba0f5da74 100644 ---- a/ipapython/kernel_keyring.py -+++ b/ipapython/kernel_keyring.py -@@ -23,6 +23,7 @@ import os - import six - - from ipapython.ipautil import run -+from ipaplatform.paths import paths - - # NOTE: Absolute path not required for keyctl since we reset the environment - # in ipautil.run. -@@ -35,34 +36,38 @@ from ipapython.ipautil import run - KEYRING = '@s' - KEYTYPE = 'user' - -+ - def dump_keys(): - """ - Dump all keys - """ -- result = run(['keyctl', 'list', KEYRING], raiseonerr=False, -+ result = run([paths.KEYCTL, 'list', KEYRING], raiseonerr=False, - capture_output=True) - return result.output - -+ - 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, six.string_types) -- result = run(['keyctl', 'search', KEYRING, KEYTYPE, key], -+ result = run([paths.KEYCTL, 'search', KEYRING, KEYTYPE, key], - raiseonerr=False, capture_output=True) - if result.returncode: - raise ValueError('key %s not found' % key) - return result.raw_output.rstrip() - -+ - def get_persistent_key(key): - assert isinstance(key, six.string_types) -- result = run(['keyctl', 'get_persistent', KEYRING, key], -+ result = run([paths.KEYCTL, 'get_persistent', KEYRING, key], - raiseonerr=False, capture_output=True) - if result.returncode: - raise ValueError('persistent key %s not found' % key) - return result.raw_output.rstrip() - -+ - def is_persistent_keyring_supported(): - uid = os.geteuid() - try: -@@ -72,6 +77,7 @@ def is_persistent_keyring_supported(): - - return True - -+ - def has_key(key): - """ - Returns True/False whether the key exists in the keyring. -@@ -83,6 +89,7 @@ def has_key(key): - except ValueError: - return False - -+ - def read_key(key): - """ - Read the keyring and return the value for key. -@@ -91,13 +98,14 @@ def read_key(key): - """ - assert isinstance(key, six.string_types) - real_key = get_real_key(key) -- result = run(['keyctl', 'pipe', real_key], raiseonerr=False, -+ result = run([paths.KEYCTL, 'pipe', real_key], raiseonerr=False, - capture_output=True) - if result.returncode: - raise ValueError('keyctl pipe failed: %s' % result.error_log) - - return result.raw_output - -+ - def update_key(key, value): - """ - Update the keyring data. If they key doesn't exist it is created. -@@ -106,13 +114,14 @@ def update_key(key, value): - assert isinstance(value, bytes) - if has_key(key): - real_key = get_real_key(key) -- result = run(['keyctl', 'pupdate', real_key], stdin=value, -+ result = run([paths.KEYCTL, 'pupdate', real_key], stdin=value, - raiseonerr=False) - if result.returncode: - raise ValueError('keyctl pupdate failed: %s' % result.error_log) - else: - add_key(key, value) - -+ - def add_key(key, value): - """ - Add a key to the kernel keyring. -@@ -121,18 +130,19 @@ def add_key(key, value): - assert isinstance(value, bytes) - if has_key(key): - raise ValueError('key %s already exists' % key) -- result = run(['keyctl', 'padd', KEYTYPE, key, KEYRING], -+ result = run([paths.KEYCTL, 'padd', KEYTYPE, key, KEYRING], - stdin=value, raiseonerr=False) - if result.returncode: - raise ValueError('keyctl padd failed: %s' % result.error_log) - -+ - def del_key(key): - """ - Remove a key from the keyring - """ - assert isinstance(key, six.string_types) - real_key = get_real_key(key) -- result = run(['keyctl', 'unlink', real_key, KEYRING], -+ result = run([paths.KEYCTL, 'unlink', real_key, KEYRING], - raiseonerr=False) - if result.returncode: - raise ValueError('keyctl unlink failed: %s' % result.error_log) -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index 1f875c26fe909428ebf2e9c2acc9a8ad70de9a72..e787fccb9482809b180012ed8e7be2e5a6494f93 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -555,8 +555,10 @@ class ADTRUSTInstance(service.Service): - def clean_samba_keytab(self): - if os.path.exists(self.keytab): - try: -- ipautil.run(["ipa-rmkeytab", "--principal", self.principal, -- "-k", self.keytab]) -+ ipautil.run([ -+ paths.IPA_RMKEYTAB, "--principal", self.principal, -+ "-k", self.keytab -+ ]) - except ipautil.CalledProcessError as e: - if e.returncode != 5: - logger.critical("Failed to remove old key for %s", -diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py -index 005fbeef37309ee3891e82ac0727adb031213da6..e110a5c3fc3e214736cb650f6da8a330eaa665a2 100644 ---- a/ipaserver/install/installutils.py -+++ b/ipaserver/install/installutils.py -@@ -599,19 +599,26 @@ def get_directive(filename, directive, separator=' '): - fd.close() - return None - -+ - def kadmin(command): -- return ipautil.run(["kadmin.local", "-q", command, -- "-x", "ipa-setup-override-restrictions"], -- capture_output=True, -- capture_error=True) -+ return ipautil.run( -+ [ -+ paths.KADMIN_LOCAL, "-q", command, -+ "-x", "ipa-setup-override-restrictions" -+ ], -+ capture_output=True, -+ capture_error=True -+ ) - - - def kadmin_addprinc(principal): - return kadmin("addprinc -randkey " + principal) - -+ - def kadmin_modprinc(principal, options): - return kadmin("modprinc " + options + " " + principal) - -+ - def create_keytab(path, principal): - try: - if os.path.isfile(path): -@@ -832,7 +839,7 @@ def expand_replica_info(filename, password): - tarfile = top_dir+"/files.tar" - dir_path = top_dir + "/realm_info" - decrypt_file(filename, tarfile, password, top_dir) -- ipautil.run(["tar", "xf", tarfile, "-C", top_dir]) -+ ipautil.run([paths.TAR, "xf", tarfile, "-C", top_dir]) - os.remove(tarfile) - - return top_dir, dir_path -diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py -index cef01d30454ea1adb8bf9c68f428b9555f1b9557..db4b28c6deebd833855c32c5ff832dad3e5c741e 100644 ---- a/ipaserver/install/ipa_backup.py -+++ b/ipaserver/install/ipa_backup.py -@@ -314,7 +314,7 @@ class Backup(admintool.AdminTool): - dirsrv.stop(capture_output=False) - else: - logger.info('Stopping IPA services') -- run(['ipactl', 'stop']) -+ run([paths.IPACTL, 'stop']) - - instance = installutils.realm_to_serverid(api.env.realm) - if os.path.exists(paths.VAR_LIB_SLAPD_INSTANCE_DIR_TEMPLATE % -@@ -336,7 +336,7 @@ class Backup(admintool.AdminTool): - dirsrv.start(capture_output=False) - else: - logger.info('Starting IPA service') -- run(['ipactl', 'start']) -+ run([paths.IPACTL, 'start']) - - # Compress after services are restarted to minimize - # the unavailability window -@@ -549,7 +549,7 @@ class Backup(admintool.AdminTool): - # Compress the archive. This is done separately, since 'tar' cannot - # append to a compressed archive. - if self.tarfile: -- result = run(['gzip', self.tarfile], raiseonerr=False) -+ result = run([paths.GZIP, self.tarfile], raiseonerr=False) - if result.returncode != 0: - raise admintool.ScriptError( - 'gzip returned non-zero code %d ' -diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py -index c7e996bbe284a7eb2d03fbedb4798d3b15f3dcc0..4941831585f473c4937b23b3f59d8ff99a654b0e 100644 ---- a/ipaserver/install/ipa_restore.py -+++ b/ipaserver/install/ipa_restore.py -@@ -386,7 +386,7 @@ class Restore(admintool.AdminTool): - dirsrv.start(capture_output=False) - else: - logger.info('Stopping IPA services') -- result = run(['ipactl', 'stop'], raiseonerr=False) -+ result = run([paths.IPACTL, 'stop'], raiseonerr=False) - if result.returncode not in [0, 6]: - logger.warning('Stopping IPA failed: %s', result.error_log) - -@@ -426,7 +426,7 @@ class Restore(admintool.AdminTool): - gssproxy = services.service('gssproxy', api) - gssproxy.reload_or_restart() - logger.info('Starting IPA services') -- run(['ipactl', 'start']) -+ run([paths.IPACTL, 'start']) - logger.info('Restarting SSSD') - sssd = services.service('sssd', api) - sssd.restart() -diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py -index 319eeb82bcbe61acd70b2943982b6fec6fa33f92..139803ffbe26a6197535e66b63ba566c2a917e01 100644 ---- a/ipaserver/install/krbinstance.py -+++ b/ipaserver/install/krbinstance.py -@@ -346,7 +346,7 @@ class KrbInstance(service.Service): - MIN_KRB5KDC_WITH_WORKERS = "1.9" - cpus = os.sysconf('SC_NPROCESSORS_ONLN') - workers = False -- result = ipautil.run(['klist', '-V'], -+ result = ipautil.run([paths.KLIST, '-V'], - raiseonerr=False, capture_output=True) - if result.returncode == 0: - verstr = result.output.split()[-1] -diff --git a/ipatests/pytest_ipa/integration/__init__.py b/ipatests/pytest_ipa/integration/__init__.py -index fb9990a15b8e28dbe27f2b9275e4877e00f25755..7c1eb2232e2362b8f691329d9a022391a0e79d91 100644 ---- a/ipatests/pytest_ipa/integration/__init__.py -+++ b/ipatests/pytest_ipa/integration/__init__.py -@@ -31,6 +31,7 @@ import pytest - from pytest_multihost import make_multihost_fixture - - from ipapython import ipautil -+from ipaplatform.paths import paths - from ipatests.test_util import yield_fixture - from .config import Config - from .env_config import get_global_config -@@ -150,7 +151,7 @@ def collect_logs(name, logs_dict, logfile_dir=None, beakerlib_plugin=None): - # delete from remote - host.run_command(['rm', '-f', tmpname]) - # Unpack on the local side -- ipautil.run(['tar', 'xJvf', 'logs.tar.xz'], cwd=dirname, -+ ipautil.run([paths.TAR, 'xJvf', 'logs.tar.xz'], cwd=dirname, - raiseonerr=False) - os.unlink(tarname) - -diff --git a/ipatests/test_integration/test_caless.py b/ipatests/test_integration/test_caless.py -index f93bdc976e03e23536c4cb2dc7401d44ddddcea1..ff8d95caa6fed00d3876f1d08e2170a9587a6d86 100644 ---- a/ipatests/test_integration/test_caless.py -+++ b/ipatests/test_integration/test_caless.py -@@ -336,7 +336,7 @@ class CALessBase(IntegrationTest): - with open(cert_fname) as cert: - chain.write(cert.read()) - -- ipautil.run(["openssl", "pkcs12", "-export", "-out", filename, -+ ipautil.run([paths.OPENSSL, "pkcs12", "-export", "-out", filename, - "-inkey", key_fname, "-in", certchain_fname, "-passin", - "pass:" + cls.cert_password, "-passout", "pass:" + - password, "-name", nickname], cwd=cls.cert_dir) -diff --git a/ipatests/test_ipapython/test_ipautil.py b/ipatests/test_ipapython/test_ipautil.py -index e15b4f948e8c6f927ee5594780609dace0345d28..88b591e5cb173799c2d5dffddadcfe65958b7c6b 100644 ---- a/ipatests/test_ipapython/test_ipautil.py -+++ b/ipatests/test_ipapython/test_ipautil.py -@@ -30,6 +30,7 @@ import pytest - import six - import tempfile - -+from ipaplatform.paths import paths - from ipalib.constants import IPAAPI_USER - from ipapython import ipautil - -@@ -419,7 +420,7 @@ class TestTimeParser(object): - - - def test_run(): -- result = ipautil.run(['echo', 'foo\x02bar'], -+ result = ipautil.run([paths.ECHO, 'foo\x02bar'], - capture_output=True, - capture_error=True) - assert result.returncode == 0 -@@ -430,7 +431,7 @@ def test_run(): - - - def test_run_no_capture_output(): -- result = ipautil.run(['echo', 'foo\x02bar']) -+ result = ipautil.run([paths.ECHO, 'foo\x02bar']) - assert result.returncode == 0 - assert result.output is None - assert result.raw_output == b'foo\x02bar\n' -@@ -439,13 +440,13 @@ def test_run_no_capture_output(): - - - def test_run_bytes(): -- result = ipautil.run(['echo', b'\x01\x02'], capture_output=True) -+ result = ipautil.run([paths.ECHO, b'\x01\x02'], capture_output=True) - assert result.returncode == 0 - assert result.raw_output == b'\x01\x02\n' - - - def test_run_decode(): -- result = ipautil.run(['echo', u'á'.encode('utf-8')], -+ result = ipautil.run([paths.ECHO, u'á'.encode('utf-8')], - encoding='utf-8', capture_output=True) - assert result.returncode == 0 - if six.PY3: -@@ -457,11 +458,11 @@ def test_run_decode(): - def test_run_decode_bad(): - if six.PY3: - with pytest.raises(UnicodeDecodeError): -- ipautil.run(['echo', b'\xa0\xa1'], -+ ipautil.run([paths.ECHO, b'\xa0\xa1'], - capture_output=True, - encoding='utf-8') - else: -- result = ipautil.run(['echo', '\xa0\xa1'], -+ result = ipautil.run([paths.ECHO, '\xa0\xa1'], - capture_output=True, - encoding='utf-8') - assert result.returncode == 0 -@@ -469,7 +470,7 @@ def test_run_decode_bad(): - - - def test_backcompat(): -- result = out, err, rc = ipautil.run(['echo', 'foo\x02bar'], -+ result = out, err, rc = ipautil.run([paths.ECHO, 'foo\x02bar'], - capture_output=True, - capture_error=True) - assert rc is result.returncode -diff --git a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py -index 931f7aff344859ee62e8e195a5fa76a1b4807eb1..6ed6cbf34c62bb83b6ebaf84cc3b105d6f76aea6 100644 ---- a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py -+++ b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py -@@ -18,6 +18,7 @@ from cryptography.hazmat.primitives import hashes, serialization - from cryptography.hazmat.primitives.asymmetric import rsa - - from ipalib import api, errors -+from ipaplatform.paths import paths - from ipatests.util import ( - prepare_config, unlock_principal_password, change_principal, - host_keytab) -@@ -50,7 +51,7 @@ def generate_user_csr(username, domain=None): - username=username) - - with tempfile.NamedTemporaryFile(mode='w') as csr_file: -- run(['openssl', 'req', '-new', '-key', CERT_RSA_PRIVATE_KEY_PATH, -+ run([paths.OPENSSL, 'req', '-new', '-key', CERT_RSA_PRIVATE_KEY_PATH, - '-out', csr_file.name, - '-config', prepare_config( - CERT_OPENSSL_CONFIG_TEMPLATE, csr_values)]) -diff --git a/ipatests/test_xmlrpc/test_cert_plugin.py b/ipatests/test_xmlrpc/test_cert_plugin.py -index 9001e7f0989764a904275d11c5d96afc53322054..16f2058b1a9a38ec76479a184a23214275f5f551 100644 ---- a/ipatests/test_xmlrpc/test_cert_plugin.py -+++ b/ipatests/test_xmlrpc/test_cert_plugin.py -@@ -176,7 +176,7 @@ class test_cert(BaseCert): - result = api.Command.cert_show(sn, out=unicode(self.certfile)) - with open(self.certfile, "rb") as f: - pem_cert = f.read().decode('ascii') -- result = run(['openssl', 'x509', '-text'], -+ result = run([paths.OPENSSL, 'x509', '-text'], - stdin=pem_cert, capture_output=True) - assert _EXP_CRL_URI in result.output - assert _EXP_OCSP_URI in result.output --- -2.20.1 - diff --git a/SOURCES/0007-xmlrpc-test-add-test-for-preserved-stage-user.patch b/SOURCES/0007-xmlrpc-test-add-test-for-preserved-stage-user.patch new file mode 100644 index 0000000..b82f87b --- /dev/null +++ b/SOURCES/0007-xmlrpc-test-add-test-for-preserved-stage-user.patch @@ -0,0 +1,128 @@ +From bcfbeef0ca7f69ff50f40990e783d58fb9a83d30 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Fri, 26 Jul 2019 15:44:58 +0200 +Subject: [PATCH] xmlrpc test: add test for preserved > stage user + +When moving a preserved user to the stage area, check that the +custom attributes are not lost ( = the attr for which there is +no specific user_stage option). + +Test scenario: +- add a stage user with --setattr "businesscategory=value" +- activate the user, check that businesscategory is still present +- delete (preserve) the user, check that attr is still present +- stage the user, check that attr is still present + +Related: https://pagure.io/freeipa/issue/7597 +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipatests/test_xmlrpc/test_stageuser_plugin.py | 64 +++++++++++++++++++ + .../test_xmlrpc/tracker/stageuser_plugin.py | 5 +- + 2 files changed, 67 insertions(+), 2 deletions(-) + +diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py +index 9a869259d06a65722f019a19405baf53c03917e1..cc6a3b1a880acab1ffba06061be6eae229f80237 100644 +--- a/ipatests/test_xmlrpc/test_stageuser_plugin.py ++++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py +@@ -128,6 +128,17 @@ def stageduser_notposix(request): + return tracker.make_fixture(request) + + ++@pytest.fixture(scope='class') ++def stageduser_customattr(request): ++ tracker = StageUserTracker(u'customattr', u'customattr', u'customattr', ++ setattr=u'businesscategory=BusinessCat') ++ tracker.track_create() ++ tracker.attrs.update( ++ businesscategory=[u'BusinessCat'] ++ ) ++ return tracker.make_fixture(request) ++ ++ + @pytest.fixture(scope='class') + def user(request): + tracker = UserTracker(u'auser1', u'active', u'user') +@@ -573,6 +584,59 @@ class TestPreserved(XMLRPC_test): + stageduser.delete() + + ++@pytest.mark.tier1 ++class TestCustomAttr(XMLRPC_test): ++ """Test for pagure ticket 7597 ++ ++ When a staged user is activated, preserved and finally staged again, ++ the custom attributes are lost. ++ """ ++ def test_stageduser_customattr(self, stageduser_customattr): ++ # Create a staged user with attributes not accessible ++ # through the options ++ # --setattr is needed here ++ command = stageduser_customattr.make_create_command() ++ result = command() ++ stageduser_customattr.check_create(result, [u'businesscategory']) ++ ++ # Activate the staged user ++ user_customattr = UserTracker( ++ stageduser_customattr.uid, stageduser_customattr.givenname, ++ stageduser_customattr.sn) ++ user_customattr.create_from_staged(stageduser_customattr) ++ user_customattr.attrs[u'businesscategory'] = [u'BusinessCat'] ++ ++ command = stageduser_customattr.make_activate_command() ++ result = command() ++ user_customattr.check_activate(result) ++ ++ # Check that the user contains businesscategory ++ command = user_customattr.make_retrieve_command(all=True) ++ result = command() ++ assert 'BusinessCat' in result['result'][u'businesscategory'] ++ ++ # delete the user with --preserve ++ command = user_customattr.make_delete_command(no_preserve=False, ++ preserve=True) ++ result = command() ++ user_customattr.check_delete(result) ++ ++ # Check that the preserved user contains businesscategory ++ command = user_customattr.make_retrieve_command(all=True) ++ result = command() ++ assert 'BusinessCat' in result['result'][u'businesscategory'] ++ ++ # Move the user from preserved to stage ++ command = user_customattr.make_stage_command() ++ result = command() ++ stageduser_customattr.check_restore_preserved(result) ++ ++ # Check that the stage user contains businesscategory ++ command = stageduser_customattr.make_retrieve_command(all=True) ++ result = command() ++ assert 'BusinessCat' in result['result'][u'businesscategory'] ++ ++ + @pytest.mark.tier1 + class TestManagers(XMLRPC_test): + def test_staged_manager(self, user, stageduser): +diff --git a/ipatests/test_xmlrpc/tracker/stageuser_plugin.py b/ipatests/test_xmlrpc/tracker/stageuser_plugin.py +index c2ab1d35c0b64980eae37f75db081b948c992b00..7609664ab4f3dc3d17b33c9ba4fa855f61a8b106 100644 +--- a/ipatests/test_xmlrpc/tracker/stageuser_plugin.py ++++ b/ipatests/test_xmlrpc/tracker/stageuser_plugin.py +@@ -176,12 +176,13 @@ class StageUserTracker(KerberosAliasMixin, Tracker): + + self.exists = True + +- def check_create(self, result): ++ def check_create(self, result, extra_keys=()): + """ Check 'stageuser-add' command result """ ++ expected = self.filter_attrs(self.create_keys | set(extra_keys)) + assert_deepequal(dict( + value=self.uid, + summary=u'Added stage user "%s"' % self.uid, +- result=self.filter_attrs(self.create_keys), ++ result=self.filter_attrs(expected), + ), result) + + def check_delete(self, result): +-- +2.20.1 + diff --git a/SOURCES/0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch b/SOURCES/0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch new file mode 100644 index 0000000..216c128 --- /dev/null +++ b/SOURCES/0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch @@ -0,0 +1,31 @@ +From 6672b67ee145db6ed368b50a49bec00f49eccf91 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Thu, 1 Aug 2019 13:53:44 -0400 +Subject: [PATCH] Don't return SSH keys with ipa host-find --pkey-only + +This was introduced in 14ee02dcbd6cbb6c221ac7526e471a9fc58fcc82 + +https://pagure.io/freeipa/issue/8029 + +Reviewed-By: Alexander Bokovoy +--- + ipaserver/plugins/host.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py +index c74a3e58f8af6b33e284ba54b5763a684d91bac3..d6172599d30ec0b2c7b475e59dec22e111e79328 100644 +--- a/ipaserver/plugins/host.py ++++ b/ipaserver/plugins/host.py +@@ -1050,7 +1050,8 @@ class host_find(LDAPSearch): + (filter, hosts_filter), ldap.MATCH_ALL + ) + +- add_sshpubkey_to_attrs_pre(self.context, attrs_list) ++ if not options.get('pkey_only', False): ++ add_sshpubkey_to_attrs_pre(self.context, attrs_list) + + return (filter.replace('locality', 'l'), base_dn, scope) + +-- +2.20.1 + diff --git a/SOURCES/0008-Support-Samba-4.9.patch b/SOURCES/0008-Support-Samba-4.9.patch deleted file mode 100644 index cccdcce..0000000 --- a/SOURCES/0008-Support-Samba-4.9.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 9650b233bdbda82bcbb447a3fc94523655cabc39 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 21 Sep 2018 10:57:23 +0300 -Subject: [PATCH] Support Samba 4.9 - -Samba 4.9 became a bit more strict about creating a local NT token and a -failure to resolve or create BUILTIN\Guests group will cause a rejection -of the connection for a successfully authenticated one. - -Add a default mapping of the nobody group to BUILTIN\Guests. - -BUILTIN\Guests is a special group SID that is added to the NT token for -authenticated users. - -For real guests there is 'guest account' option in smb.conf which -defaults to 'nobody' user. - -This was implicit behavior before as 'guest account = nobody' by -default would pick up 'nobody' group as well. - -Fixes: https://pagure.io/freeipa/issue/7705 -Reviewed-By: Rob Crittenden -(cherry picked from commit 703497532abe4189835d0a02b32f9919c889bc1c) - -Reviewed-By: Christian Heimes ---- - .../updates/90-post_upgrade_plugins.update | 1 + - ipaserver/install/adtrustinstance.py | 14 +++++++++++++ - ipaserver/install/plugins/adtrust.py | 20 ++++++++++++++++++- - 3 files changed, 34 insertions(+), 1 deletion(-) - -diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update -index bbc3e29422fc0f139c2ca68a7033863e4c25f8cf..4e9378d9b567842e1cc9a8eeae819a931810895d 100644 ---- a/install/updates/90-post_upgrade_plugins.update -+++ b/install/updates/90-post_upgrade_plugins.update -@@ -19,6 +19,7 @@ plugin: update_fix_duplicate_cacrt_in_ldap - plugin: update_upload_cacrt - # update_ra_cert_store has to be executed after update_ca_renewal_master - plugin: update_ra_cert_store -+plugin: update_mapping_Guests_to_nobody - - # last - # DNS version 1 -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index e787fccb9482809b180012ed8e7be2e5a6494f93..d6b8f5cfa66c0cfbc6d47906703fc09c3e961a53 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -120,6 +120,15 @@ def make_netbios_name(s): - return ''.join([c for c in s.split('.')[0].upper() \ - if c in ALLOWED_NETBIOS_CHARS])[:15] - -+ -+def map_Guests_to_nobody(): -+ env = {'LC_ALL': 'C'} -+ args = [paths.NET, 'groupmap', 'add', 'sid=S-1-5-32-546', -+ 'unixgroup=nobody', 'type=builtin'] -+ -+ logger.debug("Map BUILTIN\\Guests to a group 'nobody'") -+ ipautil.run(args, env=env, raiseonerr=False, capture_error=True) -+ - class ADTRUSTInstance(service.Service): - - ATTR_SID = "ipaNTSecurityIdentifier" -@@ -532,6 +541,9 @@ class ADTRUSTInstance(service.Service): - tmp_conf.flush() - ipautil.run([paths.NET, "conf", "import", tmp_conf.name]) - -+ def __map_Guests_to_nobody(self): -+ map_Guests_to_nobody() -+ - def __setup_group_membership(self): - # Add the CIFS and host principals to the 'adtrust agents' group - # as 389-ds only operates with GroupOfNames, we have to use -@@ -833,6 +845,8 @@ class ADTRUSTInstance(service.Service): - self.__create_samba_domain_object) - self.step("creating samba config registry", self.__write_smb_registry) - self.step("writing samba config file", self.__write_smb_conf) -+ self.step("map BUILTIN\\Guests to nobody group", -+ self.__map_Guests_to_nobody) - self.step("adding cifs Kerberos principal", - self.request_service_keytab) - self.step("adding cifs and host Kerberos principals to the adtrust agents group", \ -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index bec5a09c1c129b1129f31e3df59a2fa87aac0691..1f50bef891770c53a9086c7aa36d0ee1f088fbe6 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -23,7 +23,8 @@ from ipalib import Registry, errors - from ipalib import Updater - from ipapython.dn import DN - from ipaserver.install import sysupgrade --from ipaserver.install.adtrustinstance import ADTRUSTInstance -+from ipaserver.install.adtrustinstance import ( -+ ADTRUSTInstance, map_Guests_to_nobody) - - logger = logging.getLogger(__name__) - -@@ -382,3 +383,20 @@ class update_tdo_gidnumber(Updater): - return False, () - - return False, () -+ -+ -+@register() -+class update_mapping_Guests_to_nobody(Updater): -+ """ -+ Map BUILTIN\\Guests group to nobody -+ -+ Samba 4.9 became more strict on availability of builtin Guests group -+ """ -+ def execute(self, **options): -+ # First, see if trusts are enabled on the server -+ if not self.api.Command.adtrust_is_enabled()['result']: -+ logger.debug('AD Trusts are not enabled on this server') -+ return False, [] -+ -+ map_Guests_to_nobody() -+ return False, [] --- -2.20.1 - diff --git a/SOURCES/0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch b/SOURCES/0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch deleted file mode 100644 index 78963c4..0000000 --- a/SOURCES/0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch +++ /dev/null @@ -1,196 +0,0 @@ -From fd9e724513e4c574cfa3f2498fbdae0682ccb9a9 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 19 Mar 2019 10:23:20 +0200 -Subject: [PATCH] Add design page for one-way trust to AD with shared secret - -(cherry picked from commit b3911ade55eec139e07f8b4ea83612f1b2794857) - -Reviewed-By: Christian Heimes ---- - .../oneway-trust-with-shared-secret.md | 174 ++++++++++++++++++ - 1 file changed, 174 insertions(+) - create mode 100644 doc/designs/adtrust/oneway-trust-with-shared-secret.md - -diff --git a/doc/designs/adtrust/oneway-trust-with-shared-secret.md b/doc/designs/adtrust/oneway-trust-with-shared-secret.md -new file mode 100644 -index 0000000000000000000000000000000000000000..dc58a08941acea447f9234107ebcba775351089e ---- /dev/null -+++ b/doc/designs/adtrust/oneway-trust-with-shared-secret.md -@@ -0,0 +1,174 @@ -+# One-way trust with shared secret -+ -+## Overview -+ -+FreeIPA does support trust to an Active Directory forest. The trust can be -+established using administrative credentials from the forest root domain or -+using a so-called shared secret. In the latter case no administrative access is -+given to the remote side of the trust and each administrator performs their -+configuration separately: FreeIPA administrator configures IPA side, Active -+Directory administrator adds IPA forest as a trusted one on the Active -+Directory side. -+ -+For trust to be active, one needs to validate it. Validation process includes a -+sequences of DCE RPC calls that force a domain controller on the trusted side -+to establish a so-called "secure channel" to a remote domain controller in the -+trusting domain. This is an administrative operation and requires -+administrative privileges to activate. If trust was established using a shared -+secret, IPA side will lack ability to initiate a validation process. -+ -+At the same time, FreeIPA 4.6 or earlier versions do not include functionality -+to allow a remote validation from Active Directory to happen before trust -+objects are created and SSSD can retrieve information from the Active Directory -+side. Unfortunately, the latter is not possible until trust is validated. -+ -+The purpose of this design is to extend FreeIPA setup to allow trust validation -+to be initiated from Windows UI in case a shared secret is used to create a -+trust agreement. -+ -+## Use Cases -+ -+As a FreeIPA administrator, I'd like to establish a trust between an Active -+Directory forest and a FreeIPA deployment using a shared secret. As FreeIPA -+administrator, I have no administrative access to Active Directory and would -+like to delegate the operation to create trust on Active Directory side to my -+counterpart in Active Directory forest. -+ -+ -+## How to Use -+ -+ -+1. Establish a one-way trust with a shared secret on IPA side: -+ `ipa trust-add --shared-secret` -+ -+2. On Windows side, open Active Directory Domain and Trusts tool -+ * Open properties for the Windows forest -+ * Choose 'Trusts' tab and press 'New trust' button there -+ * Navigate through the trust wizard by entering: -+ * IPA forest name, then 'next' -+ * Choose 'Forest trust' on the Trust Type page -+ * Choose 'One-way: incoming' on the Direction of Trust page -+ * Choose 'This domain only' on the Sides of Trust page -+ * Enter the same shared secret one was using in step (1) with 'ipa trust-add' -+ * Complete trust wizard -+ -+3. Going back to the trust properties, one can now validate the trust from Windows side. -+ -+One limitation is that it is not possible to retrieve forest trust information -+about IPA realm by Active Directory domain controllers due to the fact that -+Samba configuration used by IPA does not support a remote query for this -+information. It is only available when Samba is used in Samba AD configuration. -+ -+TODO: check whether it is possible to force to set forest trust information -+from IPA side after both sides of trust are were configured. -+ -+## Design -+ -+There are two important parts of the solution. On IPA side, there is a module -+to allow Samba to look up trusted domains and user/group information in IPA -+LDAP. On the other side, there is support for POSIX identities of trusted -+domain objects in SSSD. -+ -+### FreeIPA module for Samba passdb interface -+ -+FreeIPA provides a special module for Samba, `ipasam`, that looks up -+information about trusted domains and user/group in FreeIPA LDAP. The module -+also maintains trust-related information when trust is created via DCE RPC -+interfaces. -+ -+When trust is created, `ipasam` module needs to create a set of Kerberos -+principals to allow Kerberos KDC to issue cross-realm ticket granting tickets. -+These principals will have the same keys as trusted domain objects on Active -+Directory level. -+ -+When a secure channel is established between two domain controllers from -+separate trusted domains, both DCs rely on the trusted domain object account -+credentials to be the same on both sides. However, since Samba has to perform -+SMB to POSIX translation when running in POSIX environment, it also needs to -+have a POSIX identity associated with the trusted domain object account. -+ -+As result, `ipasam` module needs to maintain POSIX attributes for the trusted -+domain object account, along with Kerberos principals associated with the -+trust. -+ -+### SSSD -+ -+When Windows successfully authenticates to Samba, Samba needs a POSIX identity -+to run `smbd` processes as the authenticated 'user'. `smbd` and `winbindd` -+processes use standard system calls to resolve authenticated user to a system -+one (`getpwnam_r()`) and if the call fails, whole Windows request is rejected. -+ -+Given that trusted domain object accounts are associated with the cross-realm -+Kerberos principals, they are located in a special subtree in FreeIPA LDAP: -+`cn=trusts,$SUFFIX`. However, SSSD does not look by default in this subtree for -+users. By default, SSSD configuration for user accounts looks in -+`cn=users,cn=accounts,$SUFFIX` for `id_provider = ipa` and will not be able to -+see trusted domain object accounts. -+ -+Thus, to allow Windows to successfully validate a one-way shared incoming trust -+to FreeIPA, SSSD needs to resolve trusted domain object accounts as POSIX users -+on IPA master side. -+ -+ -+## Implementation -+ -+### FreeIPA `ipasam` module -+ -+`ipasam` module needs to create and maintain POSIX identities of the trusted -+domain object accounts. -+ -+Following objects and their aliases are created and maintained by `ipasam` -+module. In the description below `REMOTE` means Kerberos realm of the Active -+Directory forest's root domain (e.g. `AD.EXAMPLE.COM`), `REMOTE-FLAT` is -+NetBIOS name of the Active Directory forest's root domain (e.g. `AD`). -+Correspondingly, `LOCAL` means FreeIPA Kerberos realm (e.g. `IPA.EXAMPLE.COM`) -+and `LOCAL-FLAT` is the NetBIOS name of the FreeIPA primary domain (e.g. -+`IPA`). -+ -+ Principal | Description -+ --------- | ----------- -+ krbtgt/REMOTE@LOCAL | Cross-realm principal representing Active Directory forest root domain -+ REMOTE-FLAT$@LOCAL | Trusted domain object account for the Active Directory forest root domain -+ krbtgt/REMOTE-FLAT@LOCAL | Alias to REMOTE-FLAT$ TDO -+ krbtgt/LOCAL@REMOTE | Cross-realm principal representing IPA domain in Active Directory forest to allow crross-realm TGT issuance from IPA KDC side -+ LOCAL-FLAT$@REMOTE | Trusted domain object account for IPA domain in Active Directory forest -+ krbtgt/LOCAL-FLAT@REMOTE | Alias to LOCAL-FLAT$ -+ -+For inbound trust `ipasam` module creates following principals: -+ * `krbtgt/LOCAL@REMOTE`, enabled by default -+ * `LOCAL-FLAT$@REMOTE`, used by SSSD to talk to Active Directory domain -+ controllers, with canonical name set to `LOCAL-FLAT$` because Kerberos KDC -+ must use this salt when issuing tickets for this principal. The use of this -+ principal is disabled on IPA side (IPA KDC does not issue tickets in this name) -+ --- we only retrieve a keytab for the principal in SSSD. -+ -+For outbound trust `ipasam` module creates following principals: -+ * `krbtgt/REMOTE@LOCAL`, enabled by default. -+ * `REMOTE-FLAT$@LOCAL`, enabled by default. Used by a remote AD DC to -+ authenticate against Samba on IPA master. This principal will have POSIX -+ identity associated. -+ -+ -+### SSSD -+ -+In IPA master mode, SSSD needs to start look into `cn=trusts,$SUFFIX` subtree -+in addition to `cn=users,cn=accounts,$SUFFIX` subtree to find trusted domain -+object accounts. This can be achieved either by explicitly adding a second -+search base to `ldap_search_user_base` option in the `[domain/...]` section or -+by automatically expanding a list of search bases when running in the IPA -+master mode. The latter is already implemented in SSSD 1.16.3 and 2.1.0 with -+https://pagure.io/SSSD/sssd/c/14faec9cd9437ef116ae054412d25ec2e820e409 -+ -+ -+Feature Management -+------------------ -+ -+We already allow to create a shared secret-based trust to Active Directory. No -+functional change is needed in either Web UI or CLI. -+ -+Upgrade -+------- -+ -+During upgrade POSIX identities need to be created for existing trust -+agreements. -+ --- -2.20.1 - diff --git a/SOURCES/0009-check-for-single-label-domains-only-during-server-in.patch b/SOURCES/0009-check-for-single-label-domains-only-during-server-in.patch new file mode 100644 index 0000000..81a8177 --- /dev/null +++ b/SOURCES/0009-check-for-single-label-domains-only-during-server-in.patch @@ -0,0 +1,112 @@ +From 12d456a12d0029833059fe28d3bb1cea338fef16 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Thu, 5 Sep 2019 15:49:05 +0200 +Subject: [PATCH] check for single-label domains only during server install + +The fix for https://pagure.io/freeipa/issue/7207 and +https://pagure.io/freeipa/issue/7598 added checks against single-label +domains in client, server and replica installs. This prevents client +enrollment to existing topologies with single-label domain. + +This commit removes those fixes on ipa-4-6 branch. Server installation +with single-label domain will still be refused, but client enrollment +will succeed. + +Fixes: https://pagure.io/freeipa/issue/8058 +Reviewed-By: Francois Cami +--- + ipalib/util.py | 5 +++-- + ipaserver/install/server/install.py | 16 ++++++++-------- + ipaserver/plugins/config.py | 2 +- + ipaserver/plugins/realmdomains.py | 2 +- + 4 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/ipalib/util.py b/ipalib/util.py +index 1aa94d97b440110fe55584048d468b9c014ec67b..8b6ec564aa6299a6dd149e9afa1bdc04ac770bf2 100644 +--- a/ipalib/util.py ++++ b/ipalib/util.py +@@ -406,14 +406,15 @@ def validate_dns_label(dns_label, allow_underscore=False, allow_slash=False): + + def validate_domain_name( + domain_name, allow_underscore=False, +- allow_slash=False, entity='domain' ++ allow_slash=False, entity='domain', ++ check_sld=False + ): + if domain_name.endswith('.'): + domain_name = domain_name[:-1] + + domain_name = domain_name.split(".") + +- if len(domain_name) < 2: ++ if check_sld and len(domain_name) < 2: + raise ValueError(_( + 'single label {}s are not supported'.format(entity))) + +diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py +index c1e593e467cdb856a4ab3251ee103f3da3386a82..5ea4f2e1cc80c995997888aaf44f500524beb796 100644 +--- a/ipaserver/install/server/install.py ++++ b/ipaserver/install/server/install.py +@@ -471,25 +471,25 @@ def install_check(installer): + domain_name = read_domain_name(host_name[host_name.find(".")+1:], + not installer.interactive) + logger.debug("read domain_name: %s\n", domain_name) +- try: +- validate_domain_name(domain_name) +- except ValueError as e: +- raise ScriptError("Invalid domain name: %s" % unicode(e)) + else: + domain_name = options.domain_name + + domain_name = domain_name.lower() ++ try: ++ validate_domain_name(domain_name, check_sld=True) ++ except ValueError as e: ++ raise ScriptError("Invalid domain name: %s" % unicode(e)) + + if not options.realm_name: + realm_name = read_realm_name(domain_name, not installer.interactive) + logger.debug("read realm_name: %s\n", realm_name) + +- try: +- validate_domain_name(realm_name, entity="realm") +- except ValueError as e: +- raise ScriptError("Invalid realm name: {}".format(unicode(e))) + else: + realm_name = options.realm_name.upper() ++ try: ++ validate_domain_name(realm_name, entity="realm", check_sld=True) ++ except ValueError as e: ++ raise ScriptError("Invalid realm name: {}".format(unicode(e))) + + if not options.subject_base: + options.subject_base = installutils.default_subject_base(realm_name) +diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py +index 58b48935c2c7471ff2ce0bb3f5ce92a9fb47a503..b6349f03b7347b696c4e38480440a31db6757de8 100644 +--- a/ipaserver/plugins/config.py ++++ b/ipaserver/plugins/config.py +@@ -400,7 +400,7 @@ class config(LDAPObject): + ) + + try: +- validate_domain_name(domain) ++ validate_domain_name(domain, check_sld=True) + except ValueError as e: + raise errors.ValidationError( + name=attr_name, +diff --git a/ipaserver/plugins/realmdomains.py b/ipaserver/plugins/realmdomains.py +index 80c5c298372f1c3f773150622c708f0286cc87a2..414dfae5090c4cd2e694bdfd3839a39783dd95fc 100644 +--- a/ipaserver/plugins/realmdomains.py ++++ b/ipaserver/plugins/realmdomains.py +@@ -59,7 +59,7 @@ def _domain_name_normalizer(d): + + def _domain_name_validator(ugettext, value): + try: +- validate_domain_name(value, allow_slash=False) ++ validate_domain_name(value, allow_slash=False, check_sld=True) + except ValueError as e: + return unicode(e) + return None +-- +2.20.1 + diff --git a/SOURCES/0010-Don-t-configure-KEYRING-ccache-in-containers.patch b/SOURCES/0010-Don-t-configure-KEYRING-ccache-in-containers.patch new file mode 100644 index 0000000..f417ec0 --- /dev/null +++ b/SOURCES/0010-Don-t-configure-KEYRING-ccache-in-containers.patch @@ -0,0 +1,166 @@ +From 7e9d17ca027b377c54288eb06ead7602a2a5136b Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 12 Dec 2018 17:32:06 +0100 +Subject: [PATCH] Don't configure KEYRING ccache in containers + +Kernel keyrings are not namespaced yet. Keyrings can leak into other +containers. Therefore keyrings should not be used in containerized +environment. + +Don't configure Kerberos to use KEYRING ccache backen when a container +environment is detected by systemd-detect-virt --container. + +Fixes: https://pagure.io/freeipa/issue/7807 +Signed-off-by: Christian Heimes +Reviewed-By: Rob Crittenden +Reviewed-By: Tibor Dudlak +Reviewed-By: Oleg Kozlov +Reviewed-By: Florence Blanc-Renaud +--- + ipaplatform/base/paths.py | 1 + + ipaplatform/base/tasks.py | 8 +++++++ + ipaplatform/redhat/tasks.py | 21 ++++++++++++++++ + ipapython/kernel_keyring.py | 10 +++++++- + ipatests/test_ipaplatform/test_tasks.py | 32 +++++++++++++++++++++++++ + 5 files changed, 71 insertions(+), 1 deletion(-) + create mode 100644 ipatests/test_ipaplatform/test_tasks.py + +diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py +index 435d1b7de9083ee74e80da6fef5c3e3cdad654bb..0395e40b7fb624cd6f625a0cd959c4a216731f6d 100644 +--- a/ipaplatform/base/paths.py ++++ b/ipaplatform/base/paths.py +@@ -30,6 +30,7 @@ class BasePathNamespace(object): + LS = "/bin/ls" + SH = "/bin/sh" + SYSTEMCTL = "/bin/systemctl" ++ SYSTEMD_DETECT_VIRT = "/bin/systemd-detect-virt" + TAR = "/bin/tar" + AUTOFS_LDAP_AUTH_CONF = "/etc/autofs_ldap_auth.conf" + ETC_DIRSRV = "/etc/dirsrv" +diff --git a/ipaplatform/base/tasks.py b/ipaplatform/base/tasks.py +index cd0427197aaecde0139781a564be443e59f3f9df..49c39e99b475cef2945354b2aaadf20239421d34 100644 +--- a/ipaplatform/base/tasks.py ++++ b/ipaplatform/base/tasks.py +@@ -116,6 +116,14 @@ class BaseTaskNamespace(object): + + raise NotImplementedError() + ++ def detect_container(self): ++ """Check if running inside a container ++ ++ :returns: container runtime or None ++ :rtype: str, None ++ """ ++ raise NotImplementedError ++ + def restore_hostname(self, fstore, statestore): + """ + Restores the original hostname as backed up in the +diff --git a/ipaplatform/redhat/tasks.py b/ipaplatform/redhat/tasks.py +index 9ce0d8375c88cb3281149ef82c975d14f150e5a4..8f6dc9a0370c59a3d4a33e8699bbc8c228ca0e1d 100644 +--- a/ipaplatform/redhat/tasks.py ++++ b/ipaplatform/redhat/tasks.py +@@ -30,6 +30,7 @@ import os + import socket + import traceback + import errno ++import subprocess + import sys + + from ctypes.util import find_library +@@ -168,6 +169,26 @@ class RedHatTaskNamespace(BaseTaskNamespace): + "resolution to 'lo' interface. You might need to enable IPv6 " + "on the interface 'lo' in sysctl.conf.") + ++ def detect_container(self): ++ """Check if running inside a container ++ ++ :returns: container runtime or None ++ :rtype: str, None ++ """ ++ try: ++ output = subprocess.check_output( ++ [paths.SYSTEMD_DETECT_VIRT, '--container'], ++ stderr=subprocess.STDOUT ++ ) ++ except subprocess.CalledProcessError as e: ++ if e.returncode == 1: ++ # No container runtime detected ++ return None ++ else: ++ raise ++ else: ++ return output.decode('utf-8').strip() ++ + def restore_pre_ipa_client_configuration(self, fstore, statestore, + was_sssd_installed, + was_sssd_configured): +diff --git a/ipapython/kernel_keyring.py b/ipapython/kernel_keyring.py +index 6ae1e74493810fa25093fe134447dd4ba0f5da74..cd47108e5846bc2f78e45f222bdfbd0ca11b7d81 100644 +--- a/ipapython/kernel_keyring.py ++++ b/ipapython/kernel_keyring.py +@@ -24,6 +24,7 @@ import six + + from ipapython.ipautil import run + from ipaplatform.paths import paths ++from ipaplatform.tasks import tasks + + # NOTE: Absolute path not required for keyctl since we reset the environment + # in ipautil.run. +@@ -68,7 +69,14 @@ def get_persistent_key(key): + return result.raw_output.rstrip() + + +-def is_persistent_keyring_supported(): ++def is_persistent_keyring_supported(check_container=True): ++ """Returns True if the kernel persistent keyring is supported. ++ ++ If check_container is True and a containerized environment is detected, ++ return False. There is no support for keyring namespace isolation yet. ++ """ ++ if check_container and tasks.detect_container() is not None: ++ return False + uid = os.geteuid() + try: + get_persistent_key(str(uid)) +diff --git a/ipatests/test_ipaplatform/test_tasks.py b/ipatests/test_ipaplatform/test_tasks.py +new file mode 100644 +index 0000000000000000000000000000000000000000..524490c78defb6ce14bf76ea296a9a33db0cbf0a +--- /dev/null ++++ b/ipatests/test_ipaplatform/test_tasks.py +@@ -0,0 +1,32 @@ ++# ++# Copyright (C) 2017 FreeIPA Contributors see COPYING for license ++# ++from __future__ import absolute_import ++ ++import os ++ ++from ipaplatform.tasks import tasks ++ ++ ++def test_detect_container(): ++ container = None ++ # naive detection, may fail for OpenVZ and other container runtimes ++ if os.path.isfile('/run/systemd/container'): ++ with open('/run/systemd/container') as f: ++ container = f.read().strip() ++ elif os.geteuid() == 0: ++ with open('/proc/1/environ') as f: ++ environ = f.read() ++ for item in environ.split('\x00'): ++ if not item: ++ continue ++ k, v = item.split('=', 1) ++ if k == 'container': ++ container = v ++ ++ detected = tasks.detect_container() ++ if container == 'oci': ++ # systemd doesn't know about podman ++ assert detected in {'container-other', container} ++ else: ++ assert detected == container +-- +2.20.1 + diff --git a/SOURCES/0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch b/SOURCES/0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch deleted file mode 100644 index f07f1a1..0000000 --- a/SOURCES/0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 58478231b10a670bc8c8bf5a1a41a5e3cb075b3f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 22 Mar 2019 18:50:30 +0200 -Subject: [PATCH] trust: allow trust agents to read POSIX identities of trust - -SSSD and Samba on IPA masters need to be able to look up POSIX -attributes of trusted domain objects in order to allow Active Directory -domain controllers from trusted forests to connect to LSA and NETLOGON -pipes. - -We only have access to read POSIX attributes in cn=accounts,$SUFFIX -subtree rather than whole $SUFFIX. Thus, add an ACI to trusts subtree. - -Fixes: https://pagure.io/freeipa/issue/6077 -(cherry picked from commit 8908b5085179d07cff45ebb11d498b872d28eee7) - -Reviewed-By: Christian Heimes ---- - install/updates/60-trusts.update | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/install/updates/60-trusts.update b/install/updates/60-trusts.update -index 04c85ba77389b12415849ed81b8131c07b1c7a32..90201e1b4bfc01509da722303cb975a970131fb5 100644 ---- a/install/updates/60-trusts.update -+++ b/install/updates/60-trusts.update -@@ -33,6 +33,7 @@ add:aci: (target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || - replace:aci:(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)::(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";) - replace:aci:(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)::(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";) - add:aci: (target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";) -+add:aci: (targetattr = "cn || createtimestamp || description || displayname || entryusn || gecos || gidnumber || givenname || homedirectory || ipantsecurityidentifier || loginshell || modifytimestamp || objectclass || uid || uidnumber")(targetfilter = "(objectclass=posixaccount)")(version 3.0;acl "Allow reading POSIX information about trusted domain objects";allow (compare,read,search) groupdn = "ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";) - - # Samba user should be able to read NT passwords to authenticate - # Add ipaNTHash to global ACIs, leave DNS tree out of global allow access rule --- -2.20.1 - diff --git a/SOURCES/0011-Add-container-environment-check-to-replicainstall.patch b/SOURCES/0011-Add-container-environment-check-to-replicainstall.patch new file mode 100644 index 0000000..5eba40e --- /dev/null +++ b/SOURCES/0011-Add-container-environment-check-to-replicainstall.patch @@ -0,0 +1,34 @@ +From 734a39d52cf738bfce7ad97deab74f368387a83b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= +Date: Tue, 10 Sep 2019 18:54:53 +0200 +Subject: [PATCH] Add container environment check to replicainstall + +Inside the container environment master's IP address +does not resolve to its name. + +Resolves: https://pagure.io/freeipa/issue/6210 +Reviewed-By: Rob Crittenden +--- + ipaserver/install/server/replicainstall.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index e13b7f18c4d4df7efde50ac9cb7d2f71bfa765cc..bd82a9d1483545d478e790a727e48eaa9ac22cfc 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1134,7 +1134,11 @@ def promote_check(installer): + "certificate") + + installutils.verify_fqdn(config.host_name, options.no_host_dns) +- installutils.verify_fqdn(config.master_host_name, options.no_host_dns) ++ # Inside the container environment master's IP address does not ++ # resolve to its name. See https://pagure.io/freeipa/issue/6210 ++ container_environment = tasks.detect_container() is not None ++ installutils.verify_fqdn(config.master_host_name, options.no_host_dns, ++ local_hostname=not container_environment) + + ccache = os.environ['KRB5CCNAME'] + kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env), +-- +2.20.1 + diff --git a/SOURCES/0011-trusts-add-support-for-one-way-shared-secret-trust.patch b/SOURCES/0011-trusts-add-support-for-one-way-shared-secret-trust.patch deleted file mode 100644 index 9e03c88..0000000 --- a/SOURCES/0011-trusts-add-support-for-one-way-shared-secret-trust.patch +++ /dev/null @@ -1,416 +0,0 @@ -From 4be3de451c8b2a6314c29df43e5ade17f39d8777 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 22 Mar 2019 18:56:52 +0200 -Subject: [PATCH] trusts: add support for one-way shared secret trust - -Refactor ipa-sam code to generate principals with additional POSIX -information so that FreeIPA is capable to establish trust when using a -shared secret from Active Directory domain controller side. - -Trust verification process from Samba AD DC or Microsoft Windows AD DC -side requires us to have a working local TDO object with POSIX -attributes so that smbd would be able to map incoming authenticated -Kerberos principal for the TDO to a local POSIX account. - -Note that FreeIPA stores TDO objects in a subtree of cn=trusts,$SUFFIX -and thus SSSD is not able to see these POSIX accounts unless -specifically instructed to do so via multiple search bases. The support -for automatically enabling cn=trusts,$SUFFIX search base in IPA server -mode was added to SSSD 1.16.3 and 2.1.0 with the commit -https://pagure.io/SSSD/sssd/c/14faec9cd9437ef116ae054412d25ec2e820e409 - -Fixes: https://pagure.io/freeipa/issue/6077 -(cherry picked from commit f30f7e380ef9d327ced3e1b0e5c800a8b1069097) - -Reviewed-By: Christian Heimes ---- - daemons/ipa-sam/ipa_sam.c | 232 +++++++++++++++++++++++++++++--------- - 1 file changed, 179 insertions(+), 53 deletions(-) - -diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c -index 675a511f0febf13cc5e00b547c18a050ac534f2e..3cf878c3f99774f7715f776c31d70e2950f9451c 100644 ---- a/daemons/ipa-sam/ipa_sam.c -+++ b/daemons/ipa-sam/ipa_sam.c -@@ -140,6 +140,7 @@ bool E_md4hash(const char *passwd, uint8_t p16[16]); /* available in libcliauth- - #define LDAP_ATTRIBUTE_OBJECTCLASS "objectClass" - #define LDAP_ATTRIBUTE_HOME_DRIVE "ipaNTHomeDirectoryDrive" - #define LDAP_ATTRIBUTE_HOME_PATH "ipaNTHomeDirectory" -+#define LDAP_ATTRIBUTE_HOMEDIRECTORY "homeDirectory" - #define LDAP_ATTRIBUTE_LOGON_SCRIPT "ipaNTLogonScript" - #define LDAP_ATTRIBUTE_PROFILE_PATH "ipaNTProfilePath" - #define LDAP_ATTRIBUTE_SID_BLACKLIST_INCOMING "ipaNTSIDBlacklistIncoming" -@@ -1797,9 +1798,10 @@ done: - #define KRB_PRINC_CREATE_DISABLED 0x00000001 - #define KRB_PRINC_CREATE_AGENT_PERMISSION 0x00000002 - -+ - static bool set_krb_princ(struct ipasam_private *ipasam_state, - TALLOC_CTX *mem_ctx, -- const char *princ, const char *saltprinc, -+ const char *princ, const char *alias, - const char *pwd, - const char *base_dn, - uint32_t create_flags) -@@ -1857,14 +1859,15 @@ static bool set_krb_princ(struct ipasam_private *ipasam_state, - LDAP_ATTRIBUTE_KRB_CANONICAL, princ); - smbldap_set_mod(&mods, LDAP_MOD_ADD, - LDAP_ATTRIBUTE_KRB_PRINCIPAL, princ); -- if (saltprinc) { -- smbldap_set_mod(&mods, LDAP_MOD_ADD, -- LDAP_ATTRIBUTE_KRB_PRINCIPAL, saltprinc); -- } -+ if (alias) { -+ smbldap_set_mod(&mods, LDAP_MOD_ADD, -+ LDAP_ATTRIBUTE_KRB_PRINCIPAL, alias); -+ } - - if ((create_flags & KRB_PRINC_CREATE_DISABLED)) { -- smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, -- LDAP_ATTRIBUTE_KRB_TICKET_FLAGS, __TALLOC_STRING_LINE2__(IPASAM_DISALLOW_ALL_TIX)); -+ smbldap_set_mod(&mods, LDAP_MOD_ADD, -+ LDAP_ATTRIBUTE_KRB_TICKET_FLAGS, -+ __TALLOC_STRING_LINE2__(IPASAM_DISALLOW_ALL_TIX)); - } - - if ((create_flags & KRB_PRINC_CREATE_AGENT_PERMISSION)) { -@@ -1877,18 +1880,19 @@ static bool set_krb_princ(struct ipasam_private *ipasam_state, - smbldap_set_mod(&mods, LDAP_MOD_ADD, - LDAP_ATTRIBUTE_OBJECTCLASS, - LDAP_OBJ_IPAOPALLOW); -- smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, -- LDAP_ATTRIBUTE_IPAOPALLOW, agent_dn); -+ smbldap_set_mod(&mods, LDAP_MOD_ADD, -+ LDAP_ATTRIBUTE_IPAOPALLOW, -+ agent_dn); - agent_dn = talloc_asprintf(mem_ctx, LDAP_CN_ADTRUST_ADMINS",%s", ipasam_state->base_dn); - if (agent_dn == NULL) { - DEBUG(1, ("error configuring cross realm principal data for trust admins!\n")); - return false; - } -- smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, -- LDAP_ATTRIBUTE_IPAOPALLOW, agent_dn); -+ smbldap_set_mod(&mods, LDAP_MOD_ADD, -+ LDAP_ATTRIBUTE_IPAOPALLOW, -+ agent_dn); - } - -- - if (entry == NULL) { - ret = smbldap_add(ipasam_state->ldap_state, dn, mods); - } else { -@@ -1899,7 +1903,7 @@ static bool set_krb_princ(struct ipasam_private *ipasam_state, - return false; - } - -- ret = set_cross_realm_pw(ipasam_state, saltprinc ? saltprinc : princ, pwd); -+ ret = set_cross_realm_pw(ipasam_state, princ, pwd); - if (ret != 0) { - DEBUG(1, ("set_cross_realm_pw failed.\n")); - return false; -@@ -1941,18 +1945,21 @@ enum princ_mod { - }; - - static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state, -- const char *domain, const char *pwd, -+ const char *domain, const char *flat_name, -+ const char *pwd_incoming, -+ const char *pwd_outgoing, - uint32_t trust_direction, - enum princ_mod mod) - { - char *trusted_dn; - char *princ_l; - char *princ_r; -- char *princ_tdo; -- char *saltprinc_tdo; -+ char *princ_r_tdo, *princ_l_tdo; - char *remote_realm; - bool ok; -+ int failed = 0; - TALLOC_CTX *tmp_ctx; -+ const char *r_tdo_alias, *l_tdo_alias; - - tmp_ctx = talloc_new(NULL); - if (tmp_ctx == NULL) { -@@ -1967,46 +1974,111 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state, - - trusted_dn = trusted_domain_dn(tmp_ctx, ipasam_state, domain); - -- princ_l = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", remote_realm, -- ipasam_state->realm); -- princ_r = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", -- ipasam_state->realm, remote_realm); -+ princ_l = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", -+ remote_realm, ipasam_state->realm); -+ princ_l_tdo = talloc_asprintf(tmp_ctx, "%s$@%s", -+ flat_name, ipasam_state->realm); -+ l_tdo_alias = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", -+ flat_name, ipasam_state->realm); - -- princ_tdo = talloc_asprintf(tmp_ctx, "%s$@%s", -- ipasam_state->flat_name, remote_realm); -+ princ_r = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", -+ ipasam_state->realm, remote_realm); -+ princ_r_tdo = talloc_asprintf(tmp_ctx, "%s$@%s", -+ ipasam_state->flat_name, remote_realm); - -- saltprinc_tdo = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", -+ r_tdo_alias = talloc_asprintf(tmp_ctx, "krbtgt/%s@%s", - ipasam_state->flat_name, remote_realm); - -- if (trusted_dn == NULL || princ_l == NULL || -- princ_r == NULL || princ_tdo == NULL || saltprinc_tdo == NULL) { -+ if (trusted_dn == NULL || princ_l == NULL || princ_l_tdo == NULL || -+ l_tdo_alias == NULL || princ_r == NULL || princ_r_tdo == NULL || -+ r_tdo_alias == NULL) { - ok = false; - goto done; - } - - switch (mod) { - case SET_PRINC: -- /* Create Kerberos principal for inbound trust, enabled by default */ -- ok = set_krb_princ(ipasam_state, tmp_ctx, princ_r, NULL, pwd, trusted_dn, KRB_PRINC_CREATE_DEFAULT); -- /* Create Kerberos principal corresponding to TDO in AD for SSSD usage, disabled by default */ -- ok |= set_krb_princ(ipasam_state, tmp_ctx, princ_tdo, saltprinc_tdo, pwd, trusted_dn, -- KRB_PRINC_CREATE_DISABLED | KRB_PRINC_CREATE_AGENT_PERMISSION); -- if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) { -- /* Create Kerberos principal for outbound trust, enabled by default */ -- ok |= set_krb_princ(ipasam_state, tmp_ctx, princ_l, NULL, pwd, trusted_dn, KRB_PRINC_CREATE_DEFAULT); -+ /* We must use two sets by two principals here because -+ * they are used for different needs and must have -+ * different salts */ -+ -+ failed = 0; -+ /* INBOUND TRUST */ -+ if ((trust_direction & LSA_TRUST_DIRECTION_INBOUND) != 0) { -+ /* First: krbtgt/@, enabled by default -+ * in case of the inboud trust */ -+ failed += !set_krb_princ(ipasam_state, tmp_ctx, princ_r, NULL, -+ pwd_outgoing, trusted_dn, -+ KRB_PRINC_CREATE_DEFAULT); -+ -+ /* Second: @ is only used -+ * for SSSD to be able to talk to AD DCs but it has to -+ * have canonical name set to $ because -+ * this is the salt used by AD DCs when using this -+ * principal, otherwise authentication will fail. -+ * -+ * *disable* use of this principal on our side as it is -+ * only used to retrieve trusted domain credentials by -+ * AD Trust Agents across the IPA topology */ -+ failed += !set_krb_princ(ipasam_state, tmp_ctx, -+ r_tdo_alias, princ_r_tdo, -+ pwd_incoming, trusted_dn, -+ (KRB_PRINC_CREATE_DISABLED | -+ KRB_PRINC_CREATE_AGENT_PERMISSION)); -+ -+ ok = (failed == 0); -+ if (!ok) { -+ goto done; -+ } - } -- if (!ok) { -- goto done; -+ -+ failed = 0; -+ /* OUTBOUND TRUST */ -+ if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) { -+ /* First: krbtgt/@, enabled by default */ -+ failed += !set_krb_princ(ipasam_state, tmp_ctx, -+ princ_l, NULL, -+ pwd_outgoing, trusted_dn, -+ KRB_PRINC_CREATE_DEFAULT); -+ -+ /* Second: $@, enabled by default -+ * as it is used for a remote DC to authenticate against IPA Samba -+ * -+ * A local account for the outbound trust must have -+ * POSIX and SMB identities associated with our domain but we associate -+ * them with the trust domain object itself */ -+ failed += !set_krb_princ(ipasam_state, tmp_ctx, -+ princ_l_tdo, l_tdo_alias, -+ pwd_incoming, trusted_dn, -+ KRB_PRINC_CREATE_DEFAULT); -+ -+ ok = (failed == 0); -+ if (!ok) { -+ goto done; -+ } - } - break; - case DEL_PRINC: -- ok = del_krb_princ(ipasam_state, tmp_ctx, princ_r, trusted_dn); -- ok |= del_krb_princ(ipasam_state, tmp_ctx, princ_tdo, trusted_dn); -- if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) { -- ok |= del_krb_princ(ipasam_state, tmp_ctx, princ_l, trusted_dn); -+ failed = 0; -+ if ((trust_direction & LSA_TRUST_DIRECTION_INBOUND) != 0) { -+ failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_r, trusted_dn); -+ failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_r_tdo, trusted_dn); -+ -+ ok = (failed == 0); -+ if (!ok) { -+ goto done; -+ } - } -- if (!ok) { -- goto done; -+ -+ failed = 0; -+ if ((trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) != 0) { -+ failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_l, trusted_dn); -+ failed += !del_krb_princ(ipasam_state, tmp_ctx, princ_l_tdo, trusted_dn); -+ -+ ok = (failed == 0); -+ if (!ok) { -+ goto done; -+ } - } - break; - default: -@@ -2022,16 +2094,22 @@ done: - } - - static bool set_cross_realm_princs(struct ipasam_private *ipasam_state, -- const char *domain, const char *pwd, uint32_t trust_direction) -+ const char *domain, const char* flat_name, -+ const char *pwd_incoming, const char *pwd_outgoing, -+ uint32_t trust_direction) - { -- return handle_cross_realm_princs(ipasam_state, domain, pwd, trust_direction, SET_PRINC); -+ return handle_cross_realm_princs(ipasam_state, domain, flat_name, -+ pwd_incoming, -+ pwd_outgoing, -+ trust_direction, SET_PRINC); - } - - static bool del_cross_realm_princs(struct ipasam_private *ipasam_state, -- const char *domain) -+ const char *domain, const char *flat_name) - { - uint32_t trust_direction = LSA_TRUST_DIRECTION_INBOUND | LSA_TRUST_DIRECTION_OUTBOUND; -- return handle_cross_realm_princs(ipasam_state, domain, NULL, trust_direction, DEL_PRINC); -+ return handle_cross_realm_princs(ipasam_state, domain, flat_name, -+ NULL, NULL, trust_direction, DEL_PRINC); - } - - static bool get_trusted_domain_int(struct ipasam_private *ipasam_state, -@@ -2439,8 +2517,8 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods, - int ret, i, count; - NTSTATUS status; - TALLOC_CTX *tmp_ctx; -- char *trustpw; -- char *sid; -+ char *trustpw_incoming, *trustpw_outgoing; -+ char *sid, *tda_name; - char **in_blacklist = NULL; - char **out_blacklist = NULL; - uint32_t enctypes, trust_offset; -@@ -2465,6 +2543,8 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods, - LDAP_OBJ_TRUSTED_DOMAIN); - smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, "objectClass", - LDAP_OBJ_ID_OBJECT); -+ smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, "objectClass", -+ LDAP_OBJ_POSIXACCOUNT); - } - - if (entry != NULL) { -@@ -2477,12 +2557,23 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods, - smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, - LDAP_ATTRIBUTE_GIDNUMBER, - ipasam_state->fallback_primary_group_gid_str); -+ smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, -+ LDAP_ATTRIBUTE_HOMEDIRECTORY, -+ "/dev/null"); - } - - if (td->netbios_name != NULL) { -+ tda_name = talloc_asprintf(tmp_ctx, "%s$", td->netbios_name); -+ if (!tda_name) { -+ status = NT_STATUS_UNSUCCESSFUL; -+ goto done; -+ } - smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, - LDAP_ATTRIBUTE_FLAT_NAME, - td->netbios_name); -+ smbldap_make_mod(priv2ld(ipasam_state), entry, &mods, -+ LDAP_ATTRIBUTE_UID, -+ tda_name); - } - - if (td->domain_name != NULL) { -@@ -2618,13 +2709,38 @@ static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods, - - if (entry == NULL) { /* FIXME: allow password updates here */ - status = get_trust_pwd(tmp_ctx, &td->trust_auth_incoming, -- &trustpw, NULL); -+ &trustpw_incoming, NULL); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } -- res = set_cross_realm_princs(ipasam_state, td->domain_name, -- trustpw, td->trust_direction); -- memset(trustpw, 0, strlen(trustpw)); -+ status = get_trust_pwd(tmp_ctx, &td->trust_auth_outgoing, -+ &trustpw_outgoing, NULL); -+ if (!NT_STATUS_IS_OK(status)) { -+ goto done; -+ } -+ res = set_cross_realm_princs(ipasam_state, td->domain_name, td->netbios_name, -+ trustpw_incoming, trustpw_outgoing, -+ td->trust_direction); -+ { -+ /* Replace memset() use by an explicit loop to avoid -+ * both compile time and link time optimisations. -+ * We could have used memset_s() from C++11 but it is -+ * currently not implemented by GCC or glibc. -+ */ -+ volatile char *p = (void *) trustpw_incoming; -+ volatile char *q = (void *) trustpw_outgoing; -+ size_t plen = strlen(trustpw_incoming); -+ size_t qlen = strlen(trustpw_outgoing); -+ -+ while (plen--) { -+ *p++ = '\0'; -+ } -+ -+ while (qlen--) { -+ *q++ = '\0'; -+ } -+ } -+ - if (!res) { - DEBUG(1, ("error writing cross realm principals!\n")); - status = NT_STATUS_UNSUCCESSFUL; -@@ -2693,7 +2809,7 @@ static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods, - talloc_get_type_abort(methods->private_data, struct ipasam_private); - LDAPMessage *entry = NULL; - char *dn; -- const char *domain_name; -+ const char *domain_name, *flat_name; - TALLOC_CTX *tmp_ctx; - NTSTATUS status; - -@@ -2731,7 +2847,17 @@ static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods, - goto done; - } - -- if (!del_cross_realm_princs(ipasam_state, domain_name)) { -+ flat_name = get_single_attribute(tmp_ctx, priv2ld(ipasam_state), entry, -+ LDAP_ATTRIBUTE_FLAT_NAME); -+ if (flat_name == NULL) { -+ DEBUG(1, ("Attribute %s not present.\n", -+ LDAP_ATTRIBUTE_FLAT_NAME)); -+ status = NT_STATUS_INVALID_PARAMETER; -+ goto done; -+ } -+ -+ -+ if (!del_cross_realm_princs(ipasam_state, domain_name, flat_name)) { - DEBUG(1, ("error deleting cross realm principals!\n")); - status = NT_STATUS_UNSUCCESSFUL; - goto done; --- -2.20.1 - diff --git a/SOURCES/0012-add-default-access-control-when-migrating-trust-obje.patch b/SOURCES/0012-add-default-access-control-when-migrating-trust-obje.patch new file mode 100644 index 0000000..bad7801 --- /dev/null +++ b/SOURCES/0012-add-default-access-control-when-migrating-trust-obje.patch @@ -0,0 +1,55 @@ +From 06eb54e3e8e645a64d915602a64834cc26bc8924 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Tue, 10 Sep 2019 13:39:39 +0300 +Subject: [PATCH] add default access control when migrating trust objects + +It looks like for some cases we do not have proper set up keytab +retrieval configuration in the old trusted domain object. This mostly +affects two-way trust cases. In such cases, create default configuration +as ipasam would have created when trust was established. + +Resolves: https://pagure.io/freeipa/issue/8067 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/install/plugins/adtrust.py | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py +index 12596d5bfe71c16a2cb87acb755a88051676e3e5..0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -28,6 +28,9 @@ logger = logging.getLogger(__name__) + register = Registry() + + DEFAULT_ID_RANGE_SIZE = 200000 ++trust_read_keys_template = \ ++ ["cn=adtrust agents,cn=sysaccounts,cn=etc,{basedn}", ++ "cn=trust admins,cn=groups,cn=accounts,{basedn}"] + + + @register() +@@ -575,8 +578,15 @@ class update_tdo_to_new_layout(Updater): + 'krbprincipalkey') + entry_data['krbextradata'] = en.single_value.get( + 'krbextradata') +- entry_data['ipaAllowedToPerform;read_keys'] = en.get( +- 'ipaAllowedToPerform;read_keys', []) ++ read_keys = en.get('ipaAllowedToPerform;read_keys', []) ++ if not read_keys: ++ # Old style, no ipaAllowedToPerform;read_keys in the entry, ++ # use defaults that ipasam should have set when creating a ++ # trust ++ read_keys = list(map( ++ lambda x: x.format(basedn=self.api.env.basedn), ++ trust_read_keys_template)) ++ entry_data['ipaAllowedToPerform;read_keys'] = read_keys + + entry.update(entry_data) + try: +-- +2.20.1 + diff --git a/SOURCES/0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch b/SOURCES/0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch deleted file mode 100644 index d6a0c1e..0000000 --- a/SOURCES/0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch +++ /dev/null @@ -1,443 +0,0 @@ -From baf93c9bdfcb761ab469efdb2a1ba4ae8485f165 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 22 Mar 2019 19:02:16 +0200 -Subject: [PATCH] upgrade: upgrade existing trust agreements to new layout - -Existing trust agreements will lack required Kerberos principals and -POSIX attributes expected to allow Active Directory domain controllers -to query IPA master over LSA and NETLOGON RPC pipes. - -Upgrade code is split into two parts: - - upgrade trusted domain object to have proper POSIX attributes - - generate required Kerberos principals for AD DC communication - -Fixes: https://pagure.io/freeipa/issue/6077 -(cherry picked from commit 090e09df130f27fb30a986529ef0944383e668e1) - -Reviewed-By: Christian Heimes ---- - ipaserver/install/plugins/adtrust.py | 371 ++++++++++++++++++++++++--- - 1 file changed, 329 insertions(+), 42 deletions(-) - -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index 1f50bef891770c53a9086c7aa36d0ee1f088fbe6..1461e000dc855a21665eb5ea0cfe4a47df419344 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -1,30 +1,27 @@ --# Authors: --# Martin Kosek --# --# Copyright (C) 2012 Red Hat --# see file 'COPYING' for use and warranty information --# --# This program is free software; you can redistribute it and/or modify --# it under the terms of the GNU General Public License as published by --# the Free Software Foundation, either version 3 of the License, or --# (at your option) any later version. --# --# This program is distributed in the hope that it will be useful, --# but WITHOUT ANY WARRANTY; without even the implied warranty of --# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --# GNU General Public License for more details. --# --# You should have received a copy of the GNU General Public License --# along with this program. If not, see . -+# Copyright (C) 2012-2019 FreeIPA Contributors see COPYING for license - -+from __future__ import absolute_import - import logging - - from ipalib import Registry, errors - from ipalib import Updater - from ipapython.dn import DN -+from ipapython import ipautil -+from ipaplatform.paths import paths - from ipaserver.install import sysupgrade - from ipaserver.install.adtrustinstance import ( - ADTRUSTInstance, map_Guests_to_nobody) -+from ipaserver.dcerpc_common import TRUST_BIDIRECTIONAL -+ -+try: -+ from samba.ndr import ndr_unpack -+ from samba.dcerpc import lsa, drsblobs -+except ImportError: -+ # If samba.ndr is not available, this machine is not provisioned -+ # for serving a trust to Active Directory. As result, it does -+ # not matter what ndr_unpack does but we save on pylint checks -+ def ndr_unpack(x): -+ raise NotImplementedError - - logger = logging.getLogger(__name__) - -@@ -325,6 +322,28 @@ class update_sids(Updater): - return False, () - - -+def get_gidNumber(ldap, env): -+ # Read the gidnumber of the fallback group and returns a list with it -+ dn = DN(('cn', ADTRUSTInstance.FALLBACK_GROUP_NAME), -+ env.container_group, -+ env.basedn) -+ -+ try: -+ entry = ldap.get_entry(dn, ['gidnumber']) -+ gidNumber = entry.get('gidnumber') -+ except errors.NotFound: -+ logger.error("%s not found", -+ ADTRUSTInstance.FALLBACK_GROUP_NAME) -+ return None -+ -+ if gidNumber is None: -+ logger.error("%s does not have a gidnumber", -+ ADTRUSTInstance.FALLBACK_GROUP_NAME) -+ return None -+ -+ return gidNumber -+ -+ - @register() - class update_tdo_gidnumber(Updater): - """ -@@ -340,43 +359,55 @@ class update_tdo_gidnumber(Updater): - logger.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, -- self.api.env.basedn) -- -- try: -- entry = ldap.get_entry(dn, ['gidnumber']) -- gidNumber = entry.get('gidnumber') -- except errors.NotFound: -- logger.error("%s not found", -- ADTRUSTInstance.FALLBACK_GROUP_NAME) -- return False, () -- -+ gidNumber = get_gidNumber(ldap, self.api.env) - if not gidNumber: - logger.error("%s does not have a gidnumber", - ADTRUSTInstance.FALLBACK_GROUP_NAME) - return False, () - -- # For each trusted domain object, add gidNumber -+ # For each trusted domain object, add posix attributes -+ # to allow use of a trusted domain account by AD DCs -+ # to authenticate against our Samba instance - 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']) -+ filter="(&(objectclass=ipaNTTrustedDomain)" -+ "(objectclass=ipaIDObject))", -+ attrs_list=['gidnumber', 'uidnumber', 'objectclass', -+ 'ipantsecurityidentifier', -+ 'ipaNTTrustDirection' -+ 'uid', 'cn', 'ipantflatname']) - 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) -- logger.debug("Added gidnumber %s to %s", -- gidNumber, tdo.dn) -- except Exception: -- logger.warning( -- "Failed to add gidnumber to %s", tdo.dn) -+ tdo['gidnumber'] = gidNumber -+ -+ # Generate uidNumber and ipaNTSecurityIdentifier if -+ # uidNumber is missing. We rely on sidgen plugin here -+ # to generate ipaNTSecurityIdentifier. -+ if not tdo.get('uidnumber'): -+ tdo['uidnumber'] = ['-1'] -+ -+ if 'posixAccount' not in tdo.get('objectclass'): -+ tdo['objectclass'].extend(['posixAccount']) -+ # Based on the flat name of a TDO, -+ # add user name FLATNAME$ (note dollar sign) -+ # to allow SSSD to map this TDO to a POSIX account -+ if not tdo.get('uid'): -+ tdo['uid'] = ["{flatname}$".format( -+ flatname=tdo.single_value['ipantflatname'])] -+ if not tdo.get('homedirectory'): -+ tdo['homedirectory'] = ['/dev/null'] -+ -+ # Store resulted entry -+ try: -+ ldap.update_entry(tdo) -+ except errors.ExecutionError as e: -+ logger.warning( -+ "Failed to update trusted domain object %s", tdo.dn) -+ logger.debug("Exception during TDO update: %s", str(e)) - - except errors.NotFound: - logger.debug("No trusted domain object to update") -@@ -400,3 +431,259 @@ class update_mapping_Guests_to_nobody(Updater): - - map_Guests_to_nobody() - return False, [] -+ -+ -+@register() -+class update_tdo_to_new_layout(Updater): -+ """ -+ Transform trusted domain objects into a new layout -+ -+ There are now two Kerberos principals per direction of trust: -+ -+ INBOUND: -+ - krbtgt/@, enabled by default -+ -+ - @, disabled by default on our side -+ as it is only used by SSSD to retrieve TDO creds when operating -+ as an AD Trust agent across IPA topology -+ -+ OUTBOUND: -+ - krbtgt/@, enabled by default -+ -+ - @, enabled by default and -+ used by remote trusted DCs to authenticate against us -+ -+ This principal also has krbtgt/@ defined -+ as a Kerberos principal alias. This is due to how Kerberos -+ key salt is derived for cross-realm principals on AD side -+ -+ Finally, Samba requires account to also possess POSIX -+ and SMB identities. We ensure this by making the trusted domain object to -+ be this account with 'uid' and 'cn' attributes being '' -+ and uidNumber/gidNumber generated automatically. Also, we ensure the -+ trusted domain object is given a SID. -+ -+ The update to POSIX/SMB identities is done through -+ the update plugin update_tdo_gidnumber. -+ """ -+ tgt_principal_template = "krbtgt/{remote}@{local}" -+ nbt_principal_template = "{nbt}$@{realm}" -+ trust_filter = \ -+ "(&(objectClass=ipaNTTrustedDomain)(objectClass=ipaIDObject))" -+ trust_attrs = ("ipaNTFlatName", "ipaNTTrustPartner", "ipaNTTrustDirection", -+ "cn", "ipaNTTrustAttributes", "ipaNTAdditionalSuffixes", -+ "ipaNTTrustedDomainSID", "ipaNTTrustType", -+ "ipaNTTrustAuthIncoming", "ipaNTTrustAuthOutgoing") -+ change_password_template = \ -+ "change_password -pw {password} " \ -+ "-e aes256-cts-hmac-sha1-96,aes128-cts-hmac-sha1-96 " \ -+ "{principal}" -+ -+ KRB_PRINC_CREATE_DEFAULT = 0x00000000 -+ KRB_PRINC_CREATE_DISABLED = 0x00000001 -+ KRB_PRINC_CREATE_AGENT_PERMISSION = 0x00000002 -+ KRB_PRINC_CREATE_IDENTITY = 0x00000004 -+ KRB_PRINC_MUST_EXIST = 0x00000008 -+ -+ # This is a flag for krbTicketFlags attribute -+ # to disallow creating any tickets using this principal -+ KRB_DISALLOW_ALL_TIX = 0x00000040 -+ -+ def retrieve_trust_password(self, packed): -+ # The structure of the trust secret is described at -+ # https://github.com/samba-team/samba/blob/master/ -+ # librpc/idl/drsblobs.idl#L516-L569 -+ # In our case in LDAP TDO object stores -+ # `struct trustAuthInOutBlob` that has `count` and -+ # the `current` of `AuthenticationInformationArray` struct -+ # which has own `count` and `array` of `AuthenticationInformation` -+ # structs that have `AuthType` field which should be equal to -+ # `LSA_TRUST_AUTH_TYPE_CLEAR`. -+ # Then AuthInfo field would contain a password as an array of bytes -+ assert(packed.count != 0) -+ assert(packed.current.count != 0) -+ assert(packed.current.array[0].AuthType == lsa.TRUST_AUTH_TYPE_CLEAR) -+ clear_value = packed.current.array[0].AuthInfo.password -+ -+ return ''.join(map(chr, clear_value)) -+ -+ def set_krb_principal(self, principals, password, trustdn, flags=None): -+ -+ ldap = self.api.Backend.ldap2 -+ -+ if isinstance(principals, (list, tuple)): -+ trust_principal = principals[0] -+ aliases = principals[1:] -+ else: -+ trust_principal = principals -+ aliases = [] -+ -+ try: -+ entry = ldap.get_entry( -+ DN(('krbprincipalname', trust_principal), trustdn)) -+ dn = entry.dn -+ action = ldap.update_entry -+ logger.debug("Updating Kerberos principal entry for %s", -+ trust_principal) -+ except errors.NotFound: -+ # For a principal that must exist, we re-raise the exception -+ # to let the caller to handle this situation -+ if flags & self.KRB_PRINC_MUST_EXIST: -+ raise -+ -+ dn = DN(('krbprincipalname', trust_principal), trustdn) -+ entry = ldap.make_entry(dn) -+ logger.debug("Adding Kerberos principal entry for %s", -+ trust_principal) -+ action = ldap.add_entry -+ -+ entry_data = { -+ 'objectclass': -+ ['krbPrincipal', 'krbPrincipalAux', -+ 'krbTicketPolicyAux', 'top'], -+ 'krbcanonicalname': [trust_principal], -+ 'krbprincipalname': [trust_principal], -+ } -+ -+ entry_data['krbprincipalname'].extend(aliases) -+ -+ if flags & self.KRB_PRINC_CREATE_DISABLED: -+ flg = int(entry.single_value.get('krbticketflags', 0)) -+ entry_data['krbticketflags'] = flg | self.KRB_DISALLOW_ALL_TIX -+ -+ if flags & self.KRB_PRINC_CREATE_AGENT_PERMISSION: -+ entry_data['objectclass'].extend(['ipaAllowedOperations']) -+ -+ entry.update(entry_data) -+ try: -+ action(entry) -+ except errors.EmptyModlist: -+ logger.debug("No update was required for Kerberos principal %s", -+ trust_principal) -+ -+ # If entry existed, no need to set Kerberos keys on it -+ if action == ldap.update_entry: -+ logger.debug("No need to update Kerberos keys for " -+ "existing Kerberos principal %s", -+ trust_principal) -+ return -+ -+ # Now that entry is updated, set its Kerberos keys. -+ # -+ # It would be a complication to use ipa-getkeytab LDAP extended control -+ # here because we would need to encode the request in ASN.1 sequence -+ # and we don't have the code to do so exposed in Python bindings. -+ # Instead, as we run on IPA master, we can use kadmin.local for that -+ # directly. -+ # We pass the command as a stdin to both avoid shell interpolation -+ # of the passwords and also to avoid its exposure to other processes -+ # Since we don't want to record the output, make also a redacted log -+ change_password = self.change_password_template.format( -+ password=password, -+ principal=trust_principal) -+ -+ redacted = self.change_password_template.format( -+ password='', -+ principal=trust_principal) -+ logger.debug("Updating Kerberos keys for %s with the following " -+ "kadmin command:\n\t%s", trust_principal, redacted) -+ -+ ipautil.run([paths.KADMIN_LOCAL, "-x", -+ "ipa-setup-override-restrictions"], -+ stdin=change_password, skip_output=True) -+ -+ def execute(self, **options): -+ # First, see if trusts are enabled on the server -+ if not self.api.Command.adtrust_is_enabled()['result']: -+ logger.debug('AD Trusts are not enabled on this server') -+ return False, [] -+ -+ ldap = self.api.Backend.ldap2 -+ gidNumber = get_gidNumber(ldap, self.api.env) -+ if gidNumber is None: -+ return False, [] -+ -+ result = self.api.Command.trustconfig_show()['result'] -+ our_nbt_name = result.get('ipantflatname', [None])[0] -+ if not our_nbt_name: -+ return False, [] -+ -+ trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn -+ -+ trusts = ldap.get_entries( -+ base_dn=trusts_dn, -+ scope=ldap.SCOPE_ONELEVEL, -+ filter=self.trust_filter, -+ attrs_list=self.trust_attrs) -+ -+ # For every trust, retrieve its principals and convert -+ for t_entry in trusts: -+ t_dn = t_entry.dn -+ logger.debug('Processing trust domain object %s', str(t_dn)) -+ t_realm = t_entry.single_value.get('ipaNTTrustPartner').upper() -+ direction = int(t_entry.single_value.get('ipaNTTrustDirection')) -+ passwd_incoming = self.retrieve_trust_password( -+ ndr_unpack(drsblobs.trustAuthInOutBlob, -+ t_entry.single_value.get('ipaNTTrustAuthIncoming'))) -+ passwd_outgoing = self.retrieve_trust_password( -+ ndr_unpack(drsblobs.trustAuthInOutBlob, -+ t_entry.single_value.get('ipaNTTrustAuthOutgoing'))) -+ # For outbound and inbound trusts, process four principals total -+ if (direction & TRUST_BIDIRECTIONAL) == TRUST_BIDIRECTIONAL: -+ # 1. OUTBOUND: krbtgt/@ must exist -+ trust_principal = self.tgt_principal_template.format( -+ remote=t_realm, local=self.api.env.realm) -+ try: -+ self.set_krb_principal(trust_principal, -+ passwd_outgoing, -+ t_dn, -+ flags=self.KRB_PRINC_CREATE_DEFAULT) -+ except errors.NotFound: -+ # It makes no sense to convert this one, skip the trust -+ # completely, better to re-establish one -+ logger.error( -+ "Broken trust to AD: %s not found, " -+ "please re-establish the trust to %s", -+ trust_principal, t_realm) -+ continue -+ -+ # 2. Create @ -+ nbt_name = t_entry.single_value.get('ipaNTFlatName') -+ nbt_principal = self.nbt_principal_template.format( -+ nbt=nbt_name, realm=self.api.env.realm) -+ tgt_principal = self.tgt_principal_template.format( -+ remote=nbt_name, local=self.api.env.realm) -+ self.set_krb_principal([nbt_principal, tgt_principal], -+ passwd_incoming, -+ t_dn, -+ flags=self.KRB_PRINC_CREATE_DEFAULT) -+ -+ # 3. INBOUND: krbtgt/@ must exist -+ trust_principal = self.tgt_principal_template.format( -+ remote=self.api.env.realm, local=t_realm) -+ try: -+ self.set_krb_principal(trust_principal, passwd_outgoing, -+ t_dn, -+ flags=self.KRB_PRINC_CREATE_DEFAULT) -+ except errors.NotFound: -+ # It makes no sense to convert this one, skip the trust -+ # completely, better to re-establish one -+ logger.error( -+ "Broken trust to AD: %s not found, " -+ "please re-establish the trust to %s", -+ trust_principal, t_realm) -+ continue -+ -+ # 4. Create @, disabled -+ nbt_principal = self.nbt_principal_template.format( -+ nbt=our_nbt_name, realm=t_realm) -+ tgt_principal = self.tgt_principal_template.format( -+ remote=our_nbt_name, local=t_realm) -+ self.set_krb_principal([nbt_principal, tgt_principal], -+ passwd_incoming, -+ t_dn, -+ flags=self.KRB_PRINC_CREATE_DEFAULT | -+ self.KRB_PRINC_CREATE_AGENT_PERMISSION | -+ self.KRB_PRINC_CREATE_DISABLED) -+ -+ return False, [] --- -2.20.1 - diff --git a/SOURCES/0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch b/SOURCES/0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch new file mode 100644 index 0000000..6868b4c --- /dev/null +++ b/SOURCES/0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch @@ -0,0 +1,105 @@ +From 847e3d053fc5243a9fce7af673cb138983a3255c Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 12 Sep 2019 11:21:51 +0300 +Subject: [PATCH] adtrust: add default read_keys permission for TDO objects + +If trusted domain object (TDO) is lacking ipaAllowedToPerform;read_keys +attribute values, it cannot be used by SSSD to retrieve TDO keys and the +whole communication with Active Directory domain controllers will not be +possible. + +This seems to affect trusts which were created before +ipaAllowedToPerform;read_keys permission granting was introduced +(FreeIPA 4.2). Add back the default setting for the permissions which +grants access to trust agents and trust admins. + +Resolves: https://pagure.io/freeipa/issue/8067 + +Signed-off-by: Alexander Bokovoy +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + .../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 6cd87a4226e34839ba7625fa03893cd8fb902386..e3afb3423ccaf1598bc0a0e982a5264781fd81a4 100644 +--- a/install/updates/90-post_upgrade_plugins.update ++++ b/install/updates/90-post_upgrade_plugins.update +@@ -12,6 +12,7 @@ plugin: update_default_range + plugin: update_default_trust_view + plugin: update_tdo_gidnumber + plugin: update_tdo_to_new_layout ++plugin: update_tdo_default_read_keys_permissions + 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 0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b..fca83aa6df2cc3fafca91f2ed55339dba016a1fa 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -727,3 +727,59 @@ class update_tdo_to_new_layout(Updater): + self.KRB_PRINC_CREATE_DISABLED) + + return False, [] ++ ++ ++@register() ++class update_tdo_default_read_keys_permissions(Updater): ++ trust_filter = \ ++ "(&(objectClass=krbPrincipal)(krbPrincipalName=krbtgt/{nbt}@*))" ++ ++ 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']: ++ logger.debug('AD Trusts are not enabled on this server') ++ return False, [] ++ ++ result = self.api.Command.trustconfig_show()['result'] ++ our_nbt_name = result.get('ipantflatname', [None])[0] ++ if not our_nbt_name: ++ return False, [] ++ ++ trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn ++ trust_filter = self.trust_filter.format(nbt=our_nbt_name) ++ ++ # We might be in a situation when no trusts exist yet ++ # In such case there is nothing to upgrade but we have to catch ++ # an exception or it will abort the whole upgrade process ++ try: ++ tdos = ldap.get_entries( ++ base_dn=trusts_dn, ++ scope=ldap.SCOPE_SUBTREE, ++ filter=trust_filter, ++ attrs_list=['*']) ++ except errors.EmptyResult: ++ tdos = [] ++ ++ for tdo in tdos: ++ updates = dict() ++ oc = tdo.get('objectClass', []) ++ if 'ipaAllowedOperations' not in oc: ++ updates['objectClass'] = oc + ['ipaAllowedOperations'] ++ ++ read_keys = tdo.get('ipaAllowedToPerform;read_keys', []) ++ if not read_keys: ++ read_keys_values = list(map( ++ lambda x: x.format(basedn=self.api.env.basedn), ++ trust_read_keys_template)) ++ updates['ipaAllowedToPerform;read_keys'] = read_keys_values ++ ++ tdo.update(updates) ++ try: ++ ldap.update_entry(tdo) ++ except errors.EmptyModlist: ++ logger.debug("No update was required for TDO %s", ++ tdo.single_value.get('krbCanonicalName')) ++ ++ return False, [] +-- +2.20.1 + diff --git a/SOURCES/0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch b/SOURCES/0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch deleted file mode 100644 index 86aebcf..0000000 --- a/SOURCES/0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 25166da75410026b9b634535caacb7747cd88cd1 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Fri, 22 Mar 2019 19:08:33 +0200 -Subject: [PATCH] upgrade: add trust upgrade to actual upgrade code - -Fixes: https://pagure.io/freeipa/issue/6077 -(cherry picked from commit f51f90e4b4bac032e076ab0f6cb3dfecb5ae12ce) - -Reviewed-By: Christian Heimes ---- - install/updates/90-post_upgrade_plugins.update | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update -index 4e9378d9b567842e1cc9a8eeae819a931810895d..a9f5f6a924d330b924d9adb8b7eee728258f27c6 100644 ---- a/install/updates/90-post_upgrade_plugins.update -+++ b/install/updates/90-post_upgrade_plugins.update -@@ -11,6 +11,7 @@ plugin: update_sids - plugin: update_default_range - plugin: update_default_trust_view - plugin: update_tdo_gidnumber -+plugin: update_tdo_to_new_layout - plugin: update_ca_renewal_master - plugin: update_idrange_type - plugin: update_pacs --- -2.20.1 - diff --git a/SOURCES/0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch b/SOURCES/0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch new file mode 100644 index 0000000..4f0f10f --- /dev/null +++ b/SOURCES/0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch @@ -0,0 +1,38 @@ +From 78c4838bcf3528018b06d73d1b82bde7f575f2db Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Mon, 16 Sep 2019 09:38:19 -0400 +Subject: [PATCH] Disable deprecated-lambda check in adtrust upgrade code + +It is interesting that we don't have this problem with newer +Python and pylint versions. Ignoring to try to keep the code +more in line with newer releases. + +Reviewed-By: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/install/plugins/adtrust.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py +index fca83aa6df2cc3fafca91f2ed55339dba016a1fa..950b7b9c82f1b0e115675ff8093d1bd02e913ae2 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -583,6 +583,7 @@ class update_tdo_to_new_layout(Updater): + # Old style, no ipaAllowedToPerform;read_keys in the entry, + # use defaults that ipasam should have set when creating a + # trust ++ # pylint: disable=deprecated-lambda + read_keys = list(map( + lambda x: x.format(basedn=self.api.env.basedn), + trust_read_keys_template)) +@@ -770,6 +771,7 @@ class update_tdo_default_read_keys_permissions(Updater): + + read_keys = tdo.get('ipaAllowedToPerform;read_keys', []) + if not read_keys: ++ # pylint: disable=deprecated-lambda + read_keys_values = list(map( + lambda x: x.format(basedn=self.api.env.basedn), + trust_read_keys_template)) +-- +2.20.1 + diff --git a/SOURCES/0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch b/SOURCES/0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch deleted file mode 100644 index b2e2e77..0000000 --- a/SOURCES/0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 8cdf6a3dd64d36f40a9107dad2ab2d9a470f58b5 Mon Sep 17 00:00:00 2001 -From: amitkuma -Date: Tue, 16 Jan 2018 17:34:08 +0530 -Subject: [PATCH] RFE: ipa client should setup openldap for GSSAPI - -The IPA client installer currently edits /etc/openldap/ldap.conf, setting up -the client to consume LDAP data from IPA. It currently sets: -URI -BASE -TLS_CACERT - -This PR makes ipa-client to add this AV pair: -SASL_MECH GSSAPI - -Resolves: https://pagure.io/freeipa/issue/7366 -Reviewed-By: Christian Heimes -Reviewed-By: Florence Blanc-Renaud -Reviewed-By: Christian Heimes ---- - ipaclient/install/client.py | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py -index babebfc667c5a096fb2e0238de444ffa3ce62b77..ca404ab80fd1586e7098950545a343fa6812ca39 100644 ---- a/ipaclient/install/client.py -+++ b/ipaclient/install/client.py -@@ -523,8 +523,12 @@ def configure_openldap_conf(fstore, cli_basedn, cli_server): - { - 'name': 'comment', - 'type': 'comment', -- 'value': ' URI, BASE and TLS_CACERT have been added if they ' -- 'were not set.' -+ 'value': ' URI, BASE, TLS_CACERT and SASL_MECH' -+ }, -+ { -+ 'name': 'comment', -+ 'type': 'comment', -+ 'value': ' have been added if they were not set.' - }, - { - 'name': 'comment', -@@ -575,6 +579,12 @@ def configure_openldap_conf(fstore, cli_basedn, cli_server): - 'type': 'option', - 'value': paths.IPA_CA_CRT - }, -+ { -+ 'action': 'addifnotset', -+ 'name': 'SASL_MECH', -+ 'type': 'option', -+ 'value': 'GSSAPI' -+ }, - ] - - target_fname = paths.OPENLDAP_LDAP_CONF --- -2.20.1 - diff --git a/SOURCES/0015-Add-uniqueness-constraint-on-CA-ACL-name.patch b/SOURCES/0015-Add-uniqueness-constraint-on-CA-ACL-name.patch deleted file mode 100644 index f689e9b..0000000 --- a/SOURCES/0015-Add-uniqueness-constraint-on-CA-ACL-name.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 4145fbdb5428b11274344cfc97eb2fe5ba9537a5 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 7 Dec 2017 12:52:54 +1100 -Subject: [PATCH] Add uniqueness constraint on CA ACL name - -It is possible to add caacl entries with same "name" (cn). The -command is supposed to prevent this but direct LDAP operations allow -it and doing that will cause subsequent errors. - -Enable the DS uniqueness constraint plugin for the cn attribute in -CA ACL entries. - -Fixes: https://pagure.io/freeipa/issue/7304 -Reviewed-By: Alexander Bokovoy -Reviewed-By: Christian Heimes ---- - install/updates/10-uniqueness.update | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/install/updates/10-uniqueness.update b/install/updates/10-uniqueness.update -index 050bfd55ec2e6a09c44700ae40757ee1d72c136f..77facba195cb5a1564818010f97afdd15d65a274 100644 ---- a/install/updates/10-uniqueness.update -+++ b/install/updates/10-uniqueness.update -@@ -92,3 +92,20 @@ add:uniqueness-across-all-subtrees: on - dn: cn=ipaUniqueID uniqueness,cn=plugins,cn=config - add:uniqueness-exclude-subtrees: cn=staged users,cn=accounts,cn=provisioning,$SUFFIX - add:uniqueness-across-all-subtrees: on -+ -+dn: cn=caacl name uniqueness,cn=plugins,cn=config -+default:objectClass: top -+default:objectClass: nsSlapdPlugin -+default:objectClass: extensibleObject -+default:cn: caacl name uniqueness -+default:nsslapd-pluginDescription: Enforce unique attribute values -+default:nsslapd-pluginPath: libattr-unique-plugin -+default:nsslapd-pluginInitfunc: NSUniqueAttr_Init -+default:nsslapd-pluginType: preoperation -+default:nsslapd-pluginEnabled: on -+default:uniqueness-attribute-name: cn -+default:uniqueness-subtrees: cn=caacls,cn=ca,$SUFFIX -+default:nsslapd-plugin-depends-on-type: database -+default:nsslapd-pluginId: NSUniqueAttr -+default:nsslapd-pluginVersion: 1.1.0 -+default:nsslapd-pluginVendor: Fedora Project --- -2.20.1 - diff --git a/SOURCES/0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch b/SOURCES/0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch new file mode 100644 index 0000000..0dd39f3 --- /dev/null +++ b/SOURCES/0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch @@ -0,0 +1,49 @@ +From 480f8a40e9ff8d7f344faac1a9af64972cf2288a Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Thu, 5 Sep 2019 13:00:27 -0400 +Subject: [PATCH] Fix segfault in ipadb_parse_ldap_entry() + +lcontext may be NULL here, probably due to a restarted 389ds. Based on +a patch by Rob Crittenden. + +Signed-off-by: Robbie Harwood +Reviewed-By: Alexander Bokovoy +--- + daemons/ipa-kdb/ipa_kdb_principals.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index b27612258bbe198154dea5b5d79e551caf9857d1..0fe8e396b9bc011b77b183851389f6c57c70a2c9 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -21,7 +21,9 @@ + */ + + #include "ipa_kdb.h" ++#include "ipa_krb5.h" + #include ++#include + + /* + * During TGS request search by ipaKrbPrincipalName (case-insensitive) +@@ -554,6 +556,17 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, + return KRB5_KDB_DBNOTINITED; + } + lcontext = ipactx->lcontext; ++ if (!lcontext) { ++ krb5_klog_syslog(LOG_INFO, ++ "No LDAP connection in ipadb_parse_ldap_entry(); retrying...\n"); ++ ret = ipadb_get_connection(ipactx); ++ if (ret != 0) { ++ krb5_klog_syslog(LOG_ERR, ++ "No LDAP connection on retry in ipadb_parse_ldap_entry()!\n"); ++ kerr = KRB5_KDB_INTERNAL_ERROR; ++ goto done; ++ } ++ } + + entry->magic = KRB5_KDB_MAGIC_NUMBER; + entry->len = KRB5_KDB_V1_BASE_LENGTH; +-- +2.20.1 + diff --git a/SOURCES/0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch b/SOURCES/0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch deleted file mode 100644 index 99f519e..0000000 --- a/SOURCES/0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch +++ /dev/null @@ -1,69 +0,0 @@ -From dfb0b27748aebb307fa3ab72aa1c43a71da1d78e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= -Date: Fri, 9 Nov 2018 17:30:32 +0100 -Subject: [PATCH] Add sysadm_r to default SELinux user map order -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It is a standard SELinux user role included in RHEL (like -user_r, staff_r, guest_r) and used quite often. - -Fixes: https://pagure.io/freeipa/issue/7658 -Signed-off-by: François Cami -Reviewed-By: Rob Crittenden -Reviewed-By: Christian Heimes ---- - install/share/bootstrap-template.ldif | 2 +- - install/ui/test/data/ipa_init.json | 2 +- - ipatests/test_xmlrpc/test_config_plugin.py | 8 ++++++-- - 3 files changed, 8 insertions(+), 4 deletions(-) - -diff --git a/install/share/bootstrap-template.ldif b/install/share/bootstrap-template.ldif -index 1b80794e66a5986d049195885ae1c9d6380eec81..6cd17e37ef147169b65709a56b0fa7312889c262 100644 ---- a/install/share/bootstrap-template.ldif -+++ b/install/share/bootstrap-template.ldif -@@ -425,7 +425,7 @@ 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 -+ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$sysadm_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 - ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023 - - dn: cn=cosTemplates,cn=accounts,$SUFFIX -diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json -index dd4b84cc920408ec8fa0bb92e9d6debc67cede7e..52f6ab191e05b314fcbeaa4786230e5ae2ebea4b 100644 ---- a/install/ui/test/data/ipa_init.json -+++ b/install/ui/test/data/ipa_init.json -@@ -863,7 +863,7 @@ - "ipausers" - ], - "ipaselinuxusermaporder" : [ -- "guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023" -+ "guest_u:s0$xguest_u:s0$user_u:s0$staff_u:s0-s0:c0.c1023$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023" - ], - "ca_renewal_master_server" : [ - "vm.example.com" -diff --git a/ipatests/test_xmlrpc/test_config_plugin.py b/ipatests/test_xmlrpc/test_config_plugin.py -index a277eab7eeb44590f982510564e92935c444c744..bd5a62acbed6a6c29bbf5fcbd041ef59bb0363bd 100644 ---- a/ipatests/test_xmlrpc/test_config_plugin.py -+++ b/ipatests/test_xmlrpc/test_config_plugin.py -@@ -148,8 +148,12 @@ class test_config(Declarative): - - dict( - desc='Try to set new selinux order and invalid default user', -- command=('config_mod', [], -- dict(ipaselinuxusermaporder=u'xguest_u:s0$guest_u:s0$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023', -+ command=( -+ 'config_mod', [], -+ dict( -+ ipaselinuxusermaporder=u'xguest_u:s0$guest_u:s0' -+ u'$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023' -+ u'$sysadm_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023', - ipaselinuxusermapdefault=u'unknown_u:s0')), - expected=errors.ValidationError(name='ipaselinuxusermapdefault', - error='SELinux user map default user not in order list'), --- -2.20.1 - diff --git a/SOURCES/0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch b/SOURCES/0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch new file mode 100644 index 0000000..c375293 --- /dev/null +++ b/SOURCES/0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch @@ -0,0 +1,42 @@ +From 24f33237eda1fddd82010b88fe1e8033a4c27976 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Fri, 20 Sep 2019 15:36:36 -0400 +Subject: [PATCH] ipa-restore: Restore ownership and perms on 389-ds log + directory + +Previously it would end up being owned by root:root mode 0755 +instead of dirsrv:dirsrv mode 0770. + +https://pagure.io/freeipa/issue/7725 + +Signed-off-by: Rob Crittenden +Reviewed-By: Florence Blanc-Renaud +Reviewed-By: Florence Blanc-Renaud +--- + ipaserver/install/ipa_restore.py | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py +index 4941831585f473c4937b23b3f59d8ff99a654b0e..917f516c8fa414b23dcb451c9105c59e0afeec51 100644 +--- a/ipaserver/install/ipa_restore.py ++++ b/ipaserver/install/ipa_restore.py +@@ -592,11 +592,15 @@ class Restore(admintool.AdminTool): + logger.info("Waiting for LDIF to finish") + wait_for_task(conn, dn) + else: ++ template_dir = paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % instance + try: +- os.makedirs(paths.VAR_LOG_DIRSRV_INSTANCE_TEMPLATE % instance) ++ os.makedirs(template_dir) + except OSError as e: + pass + ++ os.chown(template_dir, pent.pw_uid, pent.pw_gid) ++ os.chmod(template_dir, 0o770) ++ + args = [paths.LDIF2DB, + '-Z', instance, + '-i', ldiffile, +-- +2.20.1 + diff --git a/SOURCES/0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch b/SOURCES/0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch deleted file mode 100644 index ae49738..0000000 --- a/SOURCES/0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 853b56f4096734c47a26cf11767a7d6d582b11eb Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Mon, 25 Jun 2018 17:04:16 -0400 -Subject: [PATCH] Extend CALessBase::installer_server to accept extra_args - -Allow callers to pass abitrary extra arguments to the installer. - -This is useful when using a CALess installation in order to -speed up tests that require a full install but do not require -a full PKI. - -Reviewed-By: Rob Crittenden -Reviewed-By: Alexander Bokovoy -Reviewed-By: Christian Heimes ---- - ipatests/test_integration/test_caless.py | 16 +++++++++++----- - 1 file changed, 11 insertions(+), 5 deletions(-) - -diff --git a/ipatests/test_integration/test_caless.py b/ipatests/test_integration/test_caless.py -index ff8d95caa6fed00d3876f1d08e2170a9587a6d86..1ebe8fa368b88e949c0bd30bfc3999bf15c4df66 100644 ---- a/ipatests/test_integration/test_caless.py -+++ b/ipatests/test_integration/test_caless.py -@@ -171,7 +171,7 @@ class CALessBase(IntegrationTest): - http_pin=_DEFAULT, dirsrv_pin=_DEFAULT, pkinit_pin=None, - root_ca_file='root.pem', pkinit_pkcs12_exists=False, - pkinit_pkcs12='server-kdc.p12', unattended=True, -- stdin_text=None): -+ stdin_text=None, extra_args=None): - """Install a CA-less server - - Return value is the remote ipa-server-install command -@@ -179,10 +179,16 @@ class CALessBase(IntegrationTest): - if host is None: - host = cls.master - -- extra_args = ['--http-cert-file', http_pkcs12, -- '--dirsrv-cert-file', dirsrv_pkcs12, -- '--ca-cert-file', root_ca_file, -- '--ip-address', host.ip] -+ std_args = [ -+ '--http-cert-file', http_pkcs12, -+ '--dirsrv-cert-file', dirsrv_pkcs12, -+ '--ca-cert-file', root_ca_file, -+ '--ip-address', host.ip -+ ] -+ if extra_args: -+ extra_args.extend(std_args) -+ else: -+ extra_args = std_args - - if http_pin is _DEFAULT: - http_pin = cls.cert_password --- -2.20.1 - diff --git a/SOURCES/0017-replica-install-enforce-server-arg.patch b/SOURCES/0017-replica-install-enforce-server-arg.patch new file mode 100644 index 0000000..014e04f --- /dev/null +++ b/SOURCES/0017-replica-install-enforce-server-arg.patch @@ -0,0 +1,123 @@ +From 6953cecad70fc183ca4a8eddc467a7efa7ff83d3 Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Mon, 9 Sep 2019 12:58:48 +0200 +Subject: [PATCH] replica install: enforce --server arg + +When the --server option is provided to ipa-replica-install (1-step +install), make sure that the server offers all the required roles +(CA, KRA). If it's not the case, refuse the installation. + +Note that the --server option is ignored when promoting from client to +replica (2-step install with ipa-client-install and ipa-replica-install), +meaning that the existing behavior is not changed in this use case: +by default the host specified in default.conf as server is used for +enrollment, but if it does not provide a required role, another host can +be picked for CA or KRA setup. + +Fixes: https://pagure.io/freeipa/issue/7566 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Rob Crittenden +Reviewed-By: Mohammad Rizwan Yusuf +Reviewed-By: Rob Crittenden +Reviewed-By: Mohammad Rizwan Yusuf +--- + install/tools/man/ipa-replica-install.1 | 4 ++- + ipaserver/install/server/replicainstall.py | 36 ++++++++++++++++++++-- + 2 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 +index a1284135ac67de2b67b322aec3f6bbfb05f1a8ec..12764b8994a04bf56e80492bdcc66578a1f991e0 100644 +--- a/install/tools/man/ipa-replica-install.1 ++++ b/install/tools/man/ipa-replica-install.1 +@@ -51,7 +51,7 @@ One Time Password for joining a machine to the IPA realm. + Path to host keytab. + .TP + \fB\-\-server\fR +-The fully qualified domain name of the IPA server to enroll to. ++The fully qualified domain name of the IPA server to enroll to. The IPA server must provide the CA role if \fB\-\-setup-ca\fR option is specified, and the KRA role if \fB\-\-setup-kra\fR option is specified. + .TP + \fB\-n\fR, \fB\-\-domain\fR=\fIDOMAIN\fR + The primary DNS domain of an existing IPA deployment, e.g. example.com. +@@ -281,3 +281,5 @@ path. + 1 if an error occurred + + 3 if the host exists in the IPA server or a replication agreement to the remote master already exists ++ ++4 if the remote master specified for enrollment does not provide required services such as CA or KRA +diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py +index bd82a9d1483545d478e790a727e48eaa9ac22cfc..14e8b2c3a76525c6ec2a16ca26fa032aab694a59 100644 +--- a/ipaserver/install/server/replicainstall.py ++++ b/ipaserver/install/server/replicainstall.py +@@ -1024,6 +1024,8 @@ def promote_check(installer): + print("IPA client is already configured on this system, ignoring " + "the --domain, --server, --realm, --hostname, --password " + "and --keytab options.") ++ # Make sure options.server is not used ++ options.server = None + + sstore = sysrestore.StateFile(paths.SYSRESTORE) + +@@ -1269,8 +1271,15 @@ def promote_check(installer): + config.subject_base = DN(subject_base) + + # Find any server with a CA ++ # The order of preference is ++ # 1. the first server specified in --server, if any ++ # 2. the server specified in the config file ++ # 3. any other ++ preferred_cas = [config.ca_host_name] ++ if options.server: ++ preferred_cas.insert(0, options.server) + ca_host = find_providing_server( +- 'CA', conn, [config.ca_host_name] ++ 'CA', conn, preferred_cas + ) + if ca_host is not None: + config.ca_host_name = ca_host +@@ -1279,6 +1288,14 @@ def promote_check(installer): + logger.error("Certificates could not be provided when " + "CA is present on some master.") + raise ScriptError(rval=3) ++ if options.setup_ca and options.server and \ ++ ca_host != options.server: ++ # Installer was provided with a specific master ++ # but this one doesn't provide CA ++ logger.error("The specified --server %s does not provide CA, " ++ "please provide a server with the CA role", ++ options.server) ++ raise ScriptError(rval=4) + else: + if options.setup_ca: + logger.error("The remote master does not have a CA " +@@ -1293,12 +1310,27 @@ def promote_check(installer): + raise ScriptError(rval=3) + + # Find any server with a KRA ++ # The order of preference is ++ # 1. the first server specified in --server, if any ++ # 2. the server specified in the config file ++ # 3. any other ++ preferred_kras = [config.kra_host_name] ++ if options.server: ++ preferred_kras.insert(0, options.server) + kra_host = find_providing_server( +- 'KRA', conn, [config.kra_host_name] ++ 'KRA', conn, preferred_kras + ) + if kra_host is not None: + config.kra_host_name = kra_host + kra_enabled = True ++ if options.setup_kra and options.server and \ ++ kra_host != options.server: ++ # Installer was provided with a specific master ++ # but this one doesn't provide KRA ++ logger.error("The specified --server %s does not provide KRA, " ++ "please provide a server with the KRA role", ++ options.server) ++ raise ScriptError(rval=4) + else: + if options.setup_kra: + logger.error("There is no active KRA server in the domain, " +-- +2.20.1 + diff --git a/SOURCES/0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch b/SOURCES/0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch new file mode 100644 index 0000000..01c3822 --- /dev/null +++ b/SOURCES/0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch @@ -0,0 +1,94 @@ +From 349014688322df67509f44d51f232237e2a7ca7d Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 2 Aug 2019 15:55:20 -0400 +Subject: [PATCH] Log INFO message when LDAP connection fails on startup + +Since krb5_klog_syslog() always needs parameters from syslog.h, move the +include into ipa_krb5.h. + +Signed-off-by: Robbie Harwood +Reviewed-By: Christian Heimes +Reviewed-By: Rob Crittenden +--- + daemons/ipa-kdb/ipa_kdb.c | 6 ++++-- + daemons/ipa-kdb/ipa_kdb_audit_as.c | 1 - + daemons/ipa-kdb/ipa_kdb_certauth.c | 1 - + daemons/ipa-kdb/ipa_kdb_mspac.c | 1 - + util/ipa_krb5.h | 1 + + 5 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c +index c90f8d9caf247874c6bda58eb33c7733c4709b02..0dcc74263263423da6b1f4d8441ee149bce24c58 100644 +--- a/daemons/ipa-kdb/ipa_kdb.c ++++ b/daemons/ipa-kdb/ipa_kdb.c +@@ -24,6 +24,7 @@ + #include + + #include "ipa_kdb.h" ++#include "ipa_krb5.h" + + #define IPADB_GLOBAL_CONFIG_CACHE_TIME 60 + +@@ -586,8 +587,9 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext, + + ret = ipadb_get_connection(ipactx); + if (ret != 0) { +- /* not a fatal failure, as the LDAP server may be temporarily down */ +- /* TODO: spam syslog with this error */ ++ /* Not a fatal failure, as the LDAP server may be temporarily down. */ ++ krb5_klog_syslog(LOG_INFO, ++ "Didn't connect to LDAP on startup: %d", ret); + } + + kerr = krb5_db_set_context(kcontext, ipactx); +diff --git a/daemons/ipa-kdb/ipa_kdb_audit_as.c b/daemons/ipa-kdb/ipa_kdb_audit_as.c +index c68a67aa2a0ca9a2dc9e7a2d39c60d8b105fcc06..77748a75d6b16ee4d080a5f53213cc58c81660dc 100644 +--- a/daemons/ipa-kdb/ipa_kdb_audit_as.c ++++ b/daemons/ipa-kdb/ipa_kdb_audit_as.c +@@ -20,7 +20,6 @@ + * along with this program. If not, see . + */ + +-#include + #include "ipa_kdb.h" + #include "ipa_pwd.h" + +diff --git a/daemons/ipa-kdb/ipa_kdb_certauth.c b/daemons/ipa-kdb/ipa_kdb_certauth.c +index 82589f2f92096400b2f586a65eec962229c3daf7..47911aa3ded56efe4d47acb78d94ccdbcdca7339 100644 +--- a/daemons/ipa-kdb/ipa_kdb_certauth.c ++++ b/daemons/ipa-kdb/ipa_kdb_certauth.c +@@ -39,7 +39,6 @@ + + #include + //#include +-#include + #include + + #include "ipa_krb5.h" +diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c +index 329a5c11586ccd7004dd17e503133f9fda7e8395..74cbb77cccb45188f7bd8a1a33085f8ef964930f 100644 +--- a/daemons/ipa-kdb/ipa_kdb_mspac.c ++++ b/daemons/ipa-kdb/ipa_kdb_mspac.c +@@ -25,7 +25,6 @@ + #include "ipa_kdb.h" + #include "ipa_mspac.h" + #include +-#include + #include + #include "util/time.h" + #include "gen_ndr/ndr_krb5pac.h" +diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h +index 60a8ced5d8a63532254b3703801d2aeb9ff45892..b039c1a7f3d0bc215376f8f1dd2ac93e75a0c626 100644 +--- a/util/ipa_krb5.h ++++ b/util/ipa_krb5.h +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + struct krb_key_salt { + krb5_enctype enctype; +-- +2.20.1 + diff --git a/SOURCES/0018-Skip-zone-overlap-check-with-auto-reverse.patch b/SOURCES/0018-Skip-zone-overlap-check-with-auto-reverse.patch deleted file mode 100644 index 1251db9..0000000 --- a/SOURCES/0018-Skip-zone-overlap-check-with-auto-reverse.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 85bc681683a8a5d71b9cfaf9c70e0f388732f285 Mon Sep 17 00:00:00 2001 -From: Justin Stephenson -Date: Wed, 27 Dec 2017 16:32:47 -0500 -Subject: [PATCH] Skip zone overlap check with auto-reverse - -Skip the existing reverse zone overlap check during DNS installation -when both --auto-reverse and --allow-zone-overlap arguments are -provided. - -https://pagure.io/freeipa/issue/7239 - -Reviewed-By: Rob Crittenden -Reviewed-By: Alexander Bokovoy -Reviewed-By: Christian Heimes ---- - ipaserver/install/bindinstance.py | 18 ++-- - .../test_integration/test_installation.py | 95 +++++++++++++++++++ - 2 files changed, 105 insertions(+), 8 deletions(-) - -diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py -index 940667db9c40559d5369188395bb18f2d1eac025..4de2c6442175a64f4048a93b2006a6d5c6b2a045 100644 ---- a/ipaserver/install/bindinstance.py -+++ b/ipaserver/install/bindinstance.py -@@ -304,7 +304,7 @@ def read_reverse_zone(default, ip_address, allow_zone_overlap=False): - return normalize_zone(zone) - - --def get_auto_reverse_zones(ip_addresses): -+def get_auto_reverse_zones(ip_addresses, allow_zone_overlap=False): - auto_zones = [] - for ip in ip_addresses: - if ipautil.reverse_record_exists(ip): -@@ -312,12 +312,13 @@ def get_auto_reverse_zones(ip_addresses): - logger.info("Reverse record for IP address %s already exists", ip) - continue - default_reverse = get_reverse_zone_default(ip) -- try: -- dnsutil.check_zone_overlap(default_reverse) -- except ValueError: -- logger.info("Reverse zone %s for IP address %s already exists", -- default_reverse, ip) -- continue -+ if not allow_zone_overlap: -+ try: -+ dnsutil.check_zone_overlap(default_reverse) -+ except ValueError: -+ logger.info("Reverse zone %s for IP address %s already exists", -+ default_reverse, ip) -+ continue - auto_zones.append((ip, default_reverse)) - return auto_zones - -@@ -488,7 +489,8 @@ def check_reverse_zones(ip_addresses, reverse_zones, options, unattended, - ips_missing_reverse.append(ip) - - # create reverse zone for IP addresses that does not have one -- for (ip, rz) in get_auto_reverse_zones(ips_missing_reverse): -+ for (ip, rz) in get_auto_reverse_zones(ips_missing_reverse, -+ options.allow_zone_overlap): - if options.auto_reverse: - logger.info("Reverse zone %s will be created", rz) - checked_reverse_zones.append(rz) -diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py -index 4cd8a3e33927b7522e9b2a8908a8c179daaa1280..7e6c728102e29753ec7b56cedea734dd18b8bb8c 100644 ---- a/ipatests/test_integration/test_installation.py -+++ b/ipatests/test_integration/test_installation.py -@@ -9,6 +9,7 @@ installed. - - from __future__ import absolute_import - -+import os - import pytest - from ipalib.constants import DOMAIN_LEVEL_0 - from ipaplatform.constants import constants -@@ -16,9 +17,46 @@ from ipaplatform.paths import paths - from ipatests.pytest_ipa.integration.env_config import get_global_config - from ipatests.test_integration.base import IntegrationTest - from ipatests.pytest_ipa.integration import tasks -+from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup - - config = get_global_config() - -+ -+def create_broken_resolv_conf(master): -+ # Force a broken resolv.conf to simulate a bad response to -+ # reverse zone lookups -+ master.run_command([ -+ '/usr/bin/mv', -+ paths.RESOLV_CONF, -+ '%s.sav' % paths.RESOLV_CONF -+ ]) -+ -+ contents = "# Set as broken by ipatests\nnameserver 127.0.0.2\n" -+ master.put_file_contents(paths.RESOLV_CONF, contents) -+ -+ -+def restore_resolv_conf(master): -+ if os.path.exists('%s.sav' % paths.RESOLV_CONF): -+ master.run_command([ -+ '/usr/bin/mv', -+ '%s.sav' % paths.RESOLV_CONF, -+ paths.RESOLV_CONF -+ ]) -+ -+ -+def server_install_setup(func): -+ def wrapped(*args): -+ master = args[0].master -+ create_broken_resolv_conf(master) -+ try: -+ func(*args) -+ finally: -+ tasks.uninstall_master(master, clean=False) -+ restore_resolv_conf(master) -+ ipa_certs_cleanup(master) -+ return wrapped -+ -+ - class InstallTestBase1(IntegrationTest): - - num_replicas = 3 -@@ -226,6 +264,63 @@ class TestInstallWithCA_DNS2(InstallTestBase2): - super(TestInstallWithCA_DNS2, self).test_replica2_ipa_kra_install() - - -+class TestInstallWithCA_DNS3(CALessBase): -+ """ -+ Test an install with a bad DNS resolver configured to force a -+ timeout trying to verify the existing zones. In the case of a reverse -+ zone it is skipped unless --allow-zone-overlap is set regardless of -+ the value of --auto-reverse. Confirm that --allow-zone-overlap -+ lets the reverse zone be created. -+ -+ ticket 7239 -+ """ -+ -+ @server_install_setup -+ def test_number_of_zones(self): -+ """There should be two zones: one forward, one reverse""" -+ -+ self.create_pkcs12('ca1/server') -+ self.prepare_cacert('ca1') -+ -+ self.install_server(extra_args=['--allow-zone-overlap']) -+ -+ result = self.master.run_command([ -+ 'ipa', 'dnszone-find']) -+ -+ assert "in-addr.arpa." in result.stdout_text -+ -+ assert "returned 2" in result.stdout_text -+ -+ -+class TestInstallWithCA_DNS4(CALessBase): -+ """ -+ Test an install with a bad DNS resolver configured to force a -+ timeout trying to verify the existing zones. In the case of a reverse -+ zone it is skipped unless --allow-zone-overlap is set regardless of -+ the value of --auto-reverse. Confirm that without --allow-reverse-zone -+ only the forward zone is created. -+ -+ ticket 7239 -+ """ -+ -+ @server_install_setup -+ def test_number_of_zones(self): -+ """There should be one zone, a forward because rev timed-out""" -+ -+ self.create_pkcs12('ca1/server') -+ self.prepare_cacert('ca1') -+ -+ # no zone overlap by default -+ self.install_server() -+ -+ result = self.master.run_command([ -+ 'ipa', 'dnszone-find']) -+ -+ assert "in-addr.arpa." not in result.stdout_text -+ -+ assert "returned 1" in result.stdout_text -+ -+ - @pytest.mark.cs_acceptance - class TestInstallWithCA_KRA_DNS1(InstallTestBase1): - --- -2.20.1 - diff --git a/SOURCES/0019-Add-hidden-replica-feature.patch b/SOURCES/0019-Add-hidden-replica-feature.patch deleted file mode 100644 index 9048ce4..0000000 --- a/SOURCES/0019-Add-hidden-replica-feature.patch +++ /dev/null @@ -1,390 +0,0 @@ -From fc64de3f833ab63f2b2ee8984db95866b3f718a7 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Fri, 22 Mar 2019 15:14:06 +0100 -Subject: [PATCH] Add hidden replica feature - -A hidden replica is a replica that does not advertise its services via -DNS SRV records, ipa-ca DNS entry, or LDAP. Clients do not auto-select a -hidden replica, but are still free to explicitly connect to it. - -Fixes: https://pagure.io/freeipa/issue/7892 -Co-authored-by: Francois Cami : -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - API.txt | 2 +- - install/tools/ipactl | 12 ++++- - ipaserver/install/server/__init__.py | 7 +++ - ipaserver/install/server/replicainstall.py | 11 ++++- - ipaserver/install/service.py | 57 +++++++++++++++++----- - ipaserver/masters.py | 46 ++++++++++++----- - ipaserver/plugins/serverrole.py | 2 +- - ipaserver/servroles.py | 27 +++++++--- - 8 files changed, 131 insertions(+), 33 deletions(-) - -diff --git a/API.txt b/API.txt -index b9dc35fb5752ce04f58aa8c4c3e89c7299f34cd7..2135300183e3dc2126309e8f892e79fe6b5178fb 100644 ---- a/API.txt -+++ b/API.txt -@@ -4443,7 +4443,7 @@ option: Flag('raw', autofill=True, cli_name='raw', default=False) - option: Str('role_servrole?', autofill=False, cli_name='role') - option: Str('server_server?', autofill=False, cli_name='server') - option: Int('sizelimit?', autofill=False) --option: StrEnum('status?', autofill=False, cli_name='status', default=u'enabled', values=[u'enabled', u'configured', u'absent']) -+option: StrEnum('status?', autofill=False, cli_name='status', default=u'enabled', values=[u'enabled', u'configured', u'hidden', u'absent']) - option: Int('timelimit?', autofill=False) - option: Str('version?') - output: Output('count', type=[]) -diff --git a/install/tools/ipactl b/install/tools/ipactl -index 2767a26d1b70337d37dbcd87c707919579fe7e29..f40ea5a6df74f04ec7e6e8959d731553651a81d3 100755 ---- a/install/tools/ipactl -+++ b/install/tools/ipactl -@@ -29,6 +29,7 @@ import ldapurl - from ipaserver.install import service, installutils - from ipaserver.install.dsinstance import config_dirname - from ipaserver.install.installutils import is_ipa_configured, ScriptError -+from ipaserver.masters import ENABLED_SERVICE, HIDDEN_SERVICE - from ipalib import api, errors - from ipapython.ipaldap import LDAPClient - from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket -@@ -162,7 +163,16 @@ def version_check(): - - def get_config(dirsrv): - base = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -- srcfilter = '(ipaConfigString=enabledService)' -+ srcfilter = LDAPClient.combine_filters( -+ [ -+ LDAPClient.make_filter({'objectClass': 'ipaConfigObject'}), -+ LDAPClient.make_filter( -+ {'ipaConfigString': [ENABLED_SERVICE, HIDDEN_SERVICE]}, -+ rules=LDAPClient.MATCH_ANY -+ ), -+ ], -+ rules=LDAPClient.MATCH_ALL -+ ) - attrs = ['cn', 'ipaConfigString'] - if not dirsrv.is_running(): - raise IpactlError("Failed to get list of services to probe status:\n" + -diff --git a/ipaserver/install/server/__init__.py b/ipaserver/install/server/__init__.py -index b6c01d0971b827dc1547adcfff48fbcb545f4b18..f20b3dac4c7f79454a2b8871409319578ee2eb9e 100644 ---- a/ipaserver/install/server/__init__.py -+++ b/ipaserver/install/server/__init__.py -@@ -240,6 +240,13 @@ class ServerInstallInterface(ServerCertificateInstallInterface, - ) - master_password = master_install_only(master_password) - -+ hidden_replica = knob( -+ None, -+ cli_names='--hidden-replica', -+ description="Install a hidden replica", -+ ) -+ hidden_replica = replica_install_only(hidden_replica) -+ - domain_level = knob( - int, constants.MAX_DOMAIN_LEVEL, - description="IPA domain level", -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 37ecbe4146fa908c30fb708037fcaa47af1a258b..7178238bfb996f987b5e3beaebe05fa104ada089 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1055,6 +1055,7 @@ def promote_check(installer): - config.setup_kra = options.setup_kra - config.dir = installer._top_dir - config.basedn = api.env.basedn -+ config.hidden_replica = options.hidden_replica - - http_pkcs12_file = None - http_pkcs12_info = None -@@ -1579,8 +1580,16 @@ def install(installer): - remove_replica_info_dir(installer) - - # Enable configured services and update DNS SRV records -- service.enable_services(config.host_name) -+ if options.hidden_replica: -+ # Set services to hidden -+ service.hide_services(config.host_name) -+ else: -+ # Enable configured services -+ service.enable_services(config.host_name) -+ # update DNS SRV records. Although it's only really necessary in -+ # enabled-service case, also perform update in hidden replica case. - api.Command.dns_update_system_records() -+ - ca_servers = find_providing_servers('CA', api.Backend.ldap2, api=api) - api.Backend.ldap2.disconnect() - -diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py -index 261eedc85be24478b99e5ae8886aec7bc23a80ed..6d7997c559f8d748f00dd9df28371c53bc12ee21 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -39,7 +39,7 @@ from ipalib import api, errors - from ipaplatform import services - from ipaplatform.paths import paths - from ipaserver.masters import ( -- CONFIGURED_SERVICE, ENABLED_SERVICE, SERVICE_LIST -+ CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE, SERVICE_LIST - ) - - logger = logging.getLogger(__name__) -@@ -180,7 +180,7 @@ def set_service_entry_config(name, fqdn, config_values, - - - def enable_services(fqdn): -- """Change all configured services to enabled -+ """Change all services to enabled state - - Server.ldap_configure() only marks a service as configured. Services - are enabled at the very end of installation. -@@ -189,15 +189,46 @@ def enable_services(fqdn): - - :param fqdn: hostname of server - """ -+ _set_services_state(fqdn, ENABLED_SERVICE) -+ -+ -+def hide_services(fqdn): -+ """Change all services to hidden state -+ -+ Note: DNS records must be updated with dns_update_system_records, too. -+ -+ :param fqdn: hostname of server -+ """ -+ _set_services_state(fqdn, HIDDEN_SERVICE) -+ -+ -+def _set_services_state(fqdn, dest_state): -+ """Change all services of a host -+ -+ :param fqdn: hostname of server -+ :param dest_state: destination state -+ """ - ldap2 = api.Backend.ldap2 - search_base = DN(('cn', fqdn), api.env.container_masters, api.env.basedn) -- search_filter = ldap2.make_filter( -- { -- 'objectClass': 'ipaConfigObject', -- 'ipaConfigString': CONFIGURED_SERVICE -- }, -- rules='&' -+ -+ source_states = { -+ CONFIGURED_SERVICE.lower(), -+ ENABLED_SERVICE.lower(), -+ HIDDEN_SERVICE.lower() -+ } -+ source_states.remove(dest_state.lower()) -+ -+ search_filter = ldap2.combine_filters( -+ [ -+ ldap2.make_filter({'objectClass': 'ipaConfigObject'}), -+ ldap2.make_filter( -+ {'ipaConfigString': list(source_states)}, -+ rules=ldap2.MATCH_ANY -+ ), -+ ], -+ rules=ldap2.MATCH_ALL - ) -+ - entries = ldap2.get_entries( - search_base, - filter=search_filter, -@@ -208,10 +239,10 @@ def enable_services(fqdn): - name = entry['cn'] - cfgstrings = entry.setdefault('ipaConfigString', []) - for value in list(cfgstrings): -- if value.lower() == CONFIGURED_SERVICE.lower(): -+ if value.lower() in source_states: - cfgstrings.remove(value) -- if not case_insensitive_attr_has_value(cfgstrings, ENABLED_SERVICE): -- cfgstrings.append(ENABLED_SERVICE) -+ if not case_insensitive_attr_has_value(cfgstrings, dest_state): -+ cfgstrings.append(dest_state) - - try: - ldap2.update_entry(entry) -@@ -221,7 +252,9 @@ def enable_services(fqdn): - logger.exception("failed to set service %s config values", name) - raise - else: -- logger.debug("Enabled service %s for %s", name, fqdn) -+ logger.debug( -+ "Set service %s for %s to %s", name, fqdn, dest_state -+ ) - - - class Service(object): -diff --git a/ipaserver/masters.py b/ipaserver/masters.py -index 6fa8f02332ceaa10ec30aa5142912f351fb58936..76c1a9594d8b5f88c503a08b84a17e14ac320df3 100644 ---- a/ipaserver/masters.py -+++ b/ipaserver/masters.py -@@ -19,6 +19,7 @@ logger = logging.getLogger(__name__) - # constants for ipaConfigString - CONFIGURED_SERVICE = u'configuredService' - ENABLED_SERVICE = u'enabledService' -+HIDDEN_SERVICE = u'hiddenService' - - # The service name as stored in cn=masters,cn=ipa,cn=etc. The values are: - # 0: systemd service name -@@ -68,30 +69,53 @@ def find_providing_servers(svcname, conn=None, preferred_hosts=(), api=api): - conn = api.Backend.ldap2 - - dn = DN(api.env.container_masters, api.env.basedn) -- query_filter = conn.make_filter( -- { -- 'objectClass': 'ipaConfigObject', -- 'ipaConfigString': ENABLED_SERVICE, -- 'cn': svcname -- }, -- rules='&' -+ -+ query_filter = conn.combine_filters( -+ [ -+ conn.make_filter( -+ { -+ 'objectClass': 'ipaConfigObject', -+ 'cn': svcname -+ }, -+ rules=conn.MATCH_ALL, -+ ), -+ conn.make_filter( -+ { -+ 'ipaConfigString': [ENABLED_SERVICE, HIDDEN_SERVICE] -+ }, -+ rules=conn.MATCH_ANY -+ ), -+ ], -+ rules=conn.MATCH_ALL - ) -+ - try: - entries, _trunc = conn.find_entries( - filter=query_filter, -- attrs_list=[], -+ attrs_list=['ipaConfigString'], - base_dn=dn - ) - except errors.NotFound: - return [] - -- # unique list of host names, DNS is case insensitive -- servers = list(set(entry.dn[1].value.lower() for entry in entries)) -+ # DNS is case insensitive -+ preferred_hosts = list(host_name.lower() for host_name in preferred_hosts) -+ servers = [] -+ for entry in entries: -+ servername = entry.dn[1].value.lower() -+ cfgstrings = entry.get('ipaConfigString', []) -+ # always consider enabled services -+ if ENABLED_SERVICE in cfgstrings: -+ servers.append(servername) -+ # use hidden services on preferred hosts -+ elif HIDDEN_SERVICE in cfgstrings and servername in preferred_hosts: -+ servers.append(servername) -+ # unique list of host names -+ servers = list(set(servers)) - # shuffle the list like DNS SRV would randomize it - random.shuffle(servers) - # Move preferred hosts to front - for host_name in reversed(preferred_hosts): -- host_name = host_name.lower() - try: - servers.remove(host_name) - except ValueError: -diff --git a/ipaserver/plugins/serverrole.py b/ipaserver/plugins/serverrole.py -index 199978000ce8cf783bda50c46b7c9fa109f70ad6..1f6d2dca518d374d7bd07e96019610e3ef6430be 100644 ---- a/ipaserver/plugins/serverrole.py -+++ b/ipaserver/plugins/serverrole.py -@@ -70,7 +70,7 @@ class server_role(Object): - cli_name='status', - label=_('Role status'), - doc=_('Status of the role'), -- values=(u'enabled', u'configured', u'absent'), -+ values=(u'enabled', u'configured', u'hidden', u'absent'), - default=u'enabled', - flags={'virtual_attribute', 'no_create', 'no_update'} - ) -diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py -index af4e63710136a15e1673210c3e2207658698fbb5..02a22e77dbb615f735660c53d1b2eb7da022591d 100644 ---- a/ipaserver/servroles.py -+++ b/ipaserver/servroles.py -@@ -79,7 +79,7 @@ import six - - from ipalib import _, errors - from ipapython.dn import DN --from ipaserver.masters import ENABLED_SERVICE -+from ipaserver.masters import ENABLED_SERVICE, HIDDEN_SERVICE - - if six.PY3: - unicode = str -@@ -87,6 +87,7 @@ if six.PY3: - - ENABLED = u'enabled' - CONFIGURED = u'configured' -+HIDDEN = u'hidden' - ABSENT = u'absent' - - -@@ -190,6 +191,7 @@ class BaseServerRole(LDAPBasedProperty): - :returns: * 'enabled' if the role is enabled on the master - * 'configured' if it is not enabled but has - been configured by installer -+ * 'hidden' if the role is not advertised - * 'absent' otherwise - """ - ldap2 = api_instance.Backend.ldap2 -@@ -442,7 +444,7 @@ class SingleValuedServerAttribute(ServerAttribute): - return masters - - --_Service = namedtuple('Service', ['name', 'enabled']) -+_Service = namedtuple('Service', ['name', 'enabled', 'hidden']) - - - class ServiceBasedRole(BaseServerRole): -@@ -470,8 +472,9 @@ class ServiceBasedRole(BaseServerRole): - entry_cn = entry['cn'][0] - - enabled = self._is_service_enabled(entry) -+ hidden = self._is_service_hidden(entry) - -- return _Service(name=entry_cn, enabled=enabled) -+ return _Service(name=entry_cn, enabled=enabled, hidden=hidden) - - def _is_service_enabled(self, entry): - """ -@@ -486,6 +489,15 @@ class ServiceBasedRole(BaseServerRole): - ipaconfigstring_values = set(entry.get('ipaConfigString', [])) - return ENABLED_SERVICE in ipaconfigstring_values - -+ def _is_service_hidden(self, entry): -+ """Determine if service is hidden -+ -+ :param entry: LDAPEntry of the service -+ :returns: True if the service entry is enabled, False otherwise -+ """ -+ ipaconfigstring_values = set(entry.get('ipaConfigString', [])) -+ return HIDDEN_SERVICE in ipaconfigstring_values -+ - def _get_services_by_masters(self, entries): - """ - given list of entries, return a dictionary keyed by master FQDNs which -@@ -509,9 +521,12 @@ class ServiceBasedRole(BaseServerRole): - except ValueError: - continue - -- status = ( -- ENABLED if all(s.enabled for s in services) else -- CONFIGURED) -+ if all(s.enabled for s in services): -+ status = ENABLED -+ elif all(s.hidden for s in services): -+ status = HIDDEN -+ else: -+ status = CONFIGURED - - result.append(self.create_role_status_dict(master, status)) - --- -2.20.1 - diff --git a/SOURCES/0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch b/SOURCES/0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch new file mode 100644 index 0000000..f5cb38f --- /dev/null +++ b/SOURCES/0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch @@ -0,0 +1,30 @@ +From e3206de9fb0d25691b35568723ad67a60ca01165 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 4 Sep 2019 13:48:14 -0400 +Subject: [PATCH] Fix NULL pointer dereference in maybe_require_preauth() + +ipadb_get_global_config() is permitted to return NULL. + +Signed-off-by: Robbie Harwood +Reviewed-By: Christian Heimes +Reviewed-By: Rob Crittenden +--- + daemons/ipa-kdb/ipa_kdb_principals.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c +index 0fe8e396b9bc011b77b183851389f6c57c70a2c9..259a0d2563f4b9c038b041781b2580fe72d7ed7e 100644 +--- a/daemons/ipa-kdb/ipa_kdb_principals.c ++++ b/daemons/ipa-kdb/ipa_kdb_principals.c +@@ -1070,7 +1070,7 @@ static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx, + struct ipadb_e_data *ied; + + config = ipadb_get_global_config(ipactx); +- if (config->disable_preauth_for_spns) { ++ if (config && config->disable_preauth_for_spns) { + ied = (struct ipadb_e_data *)entry->e_data; + if (ied && ied->ipa_user != true) { + /* not a user, assume SPN */ +-- +2.20.1 + diff --git a/SOURCES/0020-Handle-missing-LWCA-certificate-or-chain.patch b/SOURCES/0020-Handle-missing-LWCA-certificate-or-chain.patch new file mode 100644 index 0000000..81001b4 --- /dev/null +++ b/SOURCES/0020-Handle-missing-LWCA-certificate-or-chain.patch @@ -0,0 +1,196 @@ +From f830f450c0c5818090eba9f9f0e0cec5551a1cef Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Thu, 30 May 2019 20:57:10 +1000 +Subject: [PATCH] Handle missing LWCA certificate or chain + +If lightweight CA key replication has not completed, requests for +the certificate or chain will return 404**. This can occur in +normal operation, and should be a temporary condition. Detect this +case and handle it by simply omitting the 'certificate' and/or +'certificate_out' fields in the response, and add a warning message +to the response. + +Also update the client-side plugin that handles the +--certificate-out option. Because the CLI will automatically print +the warning message, if the expected field is missing from the +response, just ignore it and continue processing. + +** after the Dogtag NullPointerException gets fixed! + +Part of: https://pagure.io/freeipa/issue/7964 + +Reviewed-By: Christian Heimes +Reviewed-By: Fraser Tweedale +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaclient/plugins/ca.py | 19 +++++++++++--- + ipalib/messages.py | 9 +++++++ + ipaserver/plugins/ca.py | 57 +++++++++++++++++++++++++++++++---------- + 3 files changed, 68 insertions(+), 17 deletions(-) + +diff --git a/ipaclient/plugins/ca.py b/ipaclient/plugins/ca.py +index f0e7d5ced0d3d9318e34aba84cbc37cf42b9410d..ab47ae85df398e1dc40191691a26639eb3772493 100644 +--- a/ipaclient/plugins/ca.py ++++ b/ipaclient/plugins/ca.py +@@ -33,13 +33,24 @@ class WithCertOutArgs(MethodOverride): + error=str(e)) + + result = super(WithCertOutArgs, self).forward(*keys, **options) ++ + if filename: ++ # if result certificate / certificate_chain not present in result, ++ # it means Dogtag did not provide it (probably due to LWCA key ++ # replication lag or failure. The server transmits a warning ++ # message in this case, which the client automatically prints. ++ # So in this section we just ignore it and move on. ++ certs = None + if options.get('chain', False): +- certs = result['result']['certificate_chain'] ++ if 'certificate_chain' in result['result']: ++ certs = result['result']['certificate_chain'] + else: +- certs = [base64.b64decode(result['result']['certificate'])] +- certs = (x509.load_der_x509_certificate(cert) for cert in certs) +- x509.write_certificate_list(certs, filename) ++ if 'certificate' in result['result']: ++ certs = [base64.b64decode(result['result']['certificate'])] ++ if certs: ++ x509.write_certificate_list( ++ (x509.load_der_x509_certificate(cert) for cert in certs), ++ filename) + + return result + +diff --git a/ipalib/messages.py b/ipalib/messages.py +index 9e2c990d6db8ee41daf3fba6085eed8355dccbe7..646662795648b5a44a5ce25b7610982d5500cfac 100644 +--- a/ipalib/messages.py ++++ b/ipalib/messages.py +@@ -487,6 +487,15 @@ class FailedToAddHostDNSRecords(PublicMessage): + "%(reason)s") + + ++class LightweightCACertificateNotAvailable(PublicMessage): ++ """ ++ **13031** Certificate is not available ++ """ ++ errno = 13031 ++ type = "error" ++ format = _("The certificate for %(ca)s is not available on this server.") ++ ++ + def iter_messages(variables, base): + """Return a tuple with all subclasses + """ +diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py +index 88e7ec2a9f50a3c4f90947c8e3d38e327627a878..c8f1630c65d55ee9e820ea50ef34e08f92c66f4a 100644 +--- a/ipaserver/plugins/ca.py ++++ b/ipaserver/plugins/ca.py +@@ -6,7 +6,7 @@ import base64 + + import six + +-from ipalib import api, errors, output, Bytes, DNParam, Flag, Str ++from ipalib import api, errors, messages, output, Bytes, DNParam, Flag, Str + from ipalib.constants import IPA_CA_CN + from ipalib.plugable import Registry + from ipapython.dn import ATTR_NAME_BY_OID +@@ -163,28 +163,53 @@ class ca(LDAPObject): + + + def set_certificate_attrs(entry, options, want_cert=True): ++ """ ++ Set certificate attributes into the entry. Depending on ++ options, this may contact Dogtag to retrieve certificate or ++ chain. If the retrieval fails with 404 (which can occur under ++ normal operation due to lightweight CA key replication delay), ++ return a message object that should be set in the response. ++ ++ """ + try: + ca_id = entry['ipacaid'][0] + except KeyError: +- return ++ return None + full = options.get('all', False) + want_chain = options.get('chain', False) + + want_data = want_cert or want_chain or full + if not want_data: +- return ++ return None ++ ++ msg = None + + with api.Backend.ra_lightweight_ca as ca_api: + if want_cert or full: +- der = ca_api.read_ca_cert(ca_id) +- entry['certificate'] = base64.b64encode(der).decode('ascii') ++ try: ++ der = ca_api.read_ca_cert(ca_id) ++ entry['certificate'] = base64.b64encode(der).decode('ascii') ++ except errors.HTTPRequestError as e: ++ if e.status == 404: # pylint: disable=no-member ++ msg = messages.LightweightCACertificateNotAvailable( ++ ca=entry['cn'][0]) ++ else: ++ raise e + + if want_chain or full: +- pkcs7_der = ca_api.read_ca_chain(ca_id) +- certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER) +- ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs] +- entry['certificate_chain'] = ders +- ++ try: ++ pkcs7_der = ca_api.read_ca_chain(ca_id) ++ certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER) ++ ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs] ++ entry['certificate_chain'] = ders ++ except errors.HTTPRequestError as e: ++ if e.status == 404: # pylint: disable=no-member ++ msg = messages.LightweightCACertificateNotAvailable( ++ ca=entry['cn'][0]) ++ else: ++ raise e ++ ++ return msg + + @register() + class ca_find(LDAPSearch): +@@ -198,7 +223,9 @@ class ca_find(LDAPSearch): + result = super(ca_find, self).execute(*keys, **options) + if not options.get('pkey_only', False): + for entry in result['result']: +- set_certificate_attrs(entry, options, want_cert=False) ++ msg = set_certificate_attrs(entry, options, want_cert=False) ++ if msg: ++ self.add_message(msg) + return result + + +@@ -220,7 +247,9 @@ class ca_show(LDAPRetrieve): + def execute(self, *keys, **options): + ca_enabled_check(self.api) + result = super(ca_show, self).execute(*keys, **options) +- set_certificate_attrs(result['result'], options) ++ msg = set_certificate_attrs(result['result'], options) ++ if msg: ++ self.add_message(msg) + return result + + +@@ -284,7 +313,9 @@ class ca_add(LDAPCreate): + return dn + + def post_callback(self, ldap, dn, entry_attrs, *keys, **options): +- set_certificate_attrs(entry_attrs, options) ++ msg = set_certificate_attrs(entry_attrs, options) ++ if msg: ++ self.add_message(msg) + return dn + + +-- +2.20.1 + diff --git a/SOURCES/0020-ipatests-Exercise-hidden-replica-feature.patch b/SOURCES/0020-ipatests-Exercise-hidden-replica-feature.patch deleted file mode 100644 index fbb0dc9..0000000 --- a/SOURCES/0020-ipatests-Exercise-hidden-replica-feature.patch +++ /dev/null @@ -1,150 +0,0 @@ -From f643289f42a0d537da2e8ab6be4727d0bc679690 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Fran=C3=A7ois=20Cami?= -Date: Fri, 22 Mar 2019 19:29:01 +0100 -Subject: [PATCH] ipatests: Exercise hidden replica feature - -A hidden replica is a replica that does not advertise its services via -DNS SRV records, ipa-ca DNS entry, or LDAP. Clients do not auto-select a -hidden replica, but are still free to explicitly connect to it. - -Fixes: https://pagure.io/freeipa/issue/7892 -Co-authored-by: Francois Cami -Signed-off-by: Francois Cami -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - .../test_replica_promotion.py | 114 ++++++++++++++++++ - 1 file changed, 114 insertions(+) - -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index 6608b23f7fb37948d54c21c88d572527356e7335..80890bf05cb242fe09af77aa27b411ac6194e2d6 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -17,6 +17,10 @@ from ipatests.pytest_ipa.integration.env_config import get_global_config - from ipalib.constants import ( - DOMAIN_LEVEL_0, DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, IPA_CA_NICKNAME) - from ipaplatform.paths import paths -+from ipatests.test_integration.test_backup_and_restore import backup -+from ipatests.test_integration.test_dns_locations import ( -+ resolve_records_from_server -+) - - config = get_global_config() - -@@ -795,3 +799,113 @@ class TestReplicaInForwardZone(IntegrationTest): - # Restore /etc/hosts on master and replica - restore_etc_hosts(master) - restore_etc_hosts(replica) -+ -+ -+class TestHiddenReplicaPromotion(IntegrationTest): -+ """ -+ Test hidden replica features -+ """ -+ -+ topology = 'star' -+ num_replicas = 1 -+ -+ @classmethod -+ def install(cls, mh): -+ tasks.install_master(cls.master, setup_dns=True, setup_kra=True) -+ -+ @replicas_cleanup -+ def test_hidden_replica_install(self): -+ self.replicas[0].run_command([ -+ 'ipa-client-install', -+ '-p', 'admin', -+ '-w', self.master.config.admin_password, -+ '--domain', self.master.domain.name, -+ '--realm', self.master.domain.realm, -+ '--server', self.master.hostname, -+ '-U' -+ ]) -+ self.replicas[0].run_command([ -+ 'ipa-replica-install', '-w', -+ self.master.config.admin_password, -+ '-n', self.master.domain.name, -+ '-r', self.master.domain.realm, -+ '--server', self.master.hostname, -+ '--setup-ca', -+ '--setup-dns', '--no-forwarders', -+ '--hidden-replica', -+ '--setup-kra', -+ '-U' -+ ]) -+ expected_txt = 'hidden' -+ result = self.replicas[0].run_command([ -+ 'ipa', 'ipa server-role-find', -+ '--server', self.replicas[0].hostname -+ ]) -+ assert expected_txt in result.stdout -+ dnsrecords = { -+ '.'.join(('_kerberos._udp', self.master.domain.name)): 'SRV', -+ '.'.join(('_kerberos._tcp', self.master.domain.name)): 'SRV', -+ '.'.join(('_ldap._tcp', self.master.domain.name)): 'SRV', -+ self.master.domain.name: 'NS' -+ } -+ nameserver = self.master.ip -+ results = [] -+ for record in dnsrecords: -+ srvr = resolve_records_from_server( -+ record, dnsrecords[record], nameserver -+ ) -+ results.extend(re.findall( -+ '|'.join((self.master.hostname, self.replicas[0].hostname)), -+ srvr) -+ ) -+ assert self.master.hostname in results -+ assert self.replicas[0].hostname not in results -+ -+ def test_hidden_replica_promote(self): -+ self.replicas[0].run_command([ -+ 'ipa', 'server-mod', '--state=enabled' -+ ]) -+ unexpected_txt = 'hidden' -+ result = self.replicas[0].run_command([ -+ 'ipa', 'ipa server-role-find', -+ '--server', self.replicas[0].hostname -+ ]) -+ assert unexpected_txt not in result.stdout -+ -+ def test_hidden_replica_demote(self): -+ self.replicas[0].run_command([ -+ 'ipa', 'server-mod', '--state=hidden' -+ ]) -+ expected_txt = 'hidden' -+ result = self.replicas[0].run_command([ -+ 'ipa', 'ipa server-role-find', -+ '--server', self.replicas[0].hostname -+ ]) -+ assert expected_txt in result.stdout -+ -+ def test_hidden_replica_backup_and_restore(self): -+ """ -+ Exercises backup+restore and hidden replica uninstall -+ """ -+ # set expectations -+ expected_txt = 'hidden' -+ result = self.replicas[0].run_command([ -+ 'ipa', 'ipa server-role-find', -+ '--server', self.replicas[0].hostname -+ ]) -+ assert expected_txt in result.stdout -+ # backup -+ backup_path = backup(self.replicas[0]) -+ # uninstall -+ result = self.replicas[0].run_command([ -+ 'ipa-server-uninstall', '-U', 'hidden-replica' -+ ]) -+ # restore -+ dirman_password = self.master.config.dirman_password -+ self.replicas[0].run_command( -+ ['ipa-restore', backup_path], stdin_text=dirman_password + '\nyes' -+ ) -+ # check that the resulting server can be promoted to enabled -+ self.replicas[0].run_command([ -+ 'ipa', 'server-mod', '--state=enabled' -+ ]) --- -2.20.1 - diff --git a/SOURCES/0021-Fix-CustodiaClient-ccache-handling.patch b/SOURCES/0021-Fix-CustodiaClient-ccache-handling.patch new file mode 100644 index 0000000..ca91578 --- /dev/null +++ b/SOURCES/0021-Fix-CustodiaClient-ccache-handling.patch @@ -0,0 +1,275 @@ +From 384225411c41c74157eccbe1ae8d1800026f413e Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 12 Jun 2019 22:02:52 +0200 +Subject: [PATCH] Fix CustodiaClient ccache handling + +A CustodiaClient object has to the process environment a bit, e.g. set +up GSSAPI credentials. To reuse the credentials in libldap connections, +it is also necessary to set up a custom ccache store and to set the +environment variable KRBCCNAME temporarily. + +Fixes: https://pagure.io/freeipa/issue/7964 +Co-Authored-By: Fraser Tweedale +Signed-off-by: Christian Heimes +Reviewed-By: Christian Heimes +Reviewed-By: Fraser Tweedale +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + install/tools/ipa-pki-retrieve-key | 33 ++++--- + ipaserver/secrets/client.py | 143 ++++++++++++++++------------- + 2 files changed, 100 insertions(+), 76 deletions(-) + +diff --git a/install/tools/ipa-pki-retrieve-key b/install/tools/ipa-pki-retrieve-key +index 5056682c3cdaa734be2dadcffd7de0b2d80afaf9..192022b9b40f076e88fd95d5cc8cf8305901dcf5 100755 +--- a/install/tools/ipa-pki-retrieve-key ++++ b/install/tools/ipa-pki-retrieve-key +@@ -2,9 +2,8 @@ + + from __future__ import print_function + ++import argparse + import os +-import sys +-import traceback + + from ipalib import constants + from ipalib.config import Env +@@ -16,27 +15,37 @@ def main(): + env = Env() + env._finalize() + +- keyname = "ca_wrapped/" + sys.argv[1] +- servername = sys.argv[2] ++ parser = argparse.ArgumentParser("ipa-pki-retrieve-key") ++ parser.add_argument("keyname", type=str) ++ parser.add_argument("servername", type=str) ++ ++ args = parser.parse_args() ++ keyname = "ca_wrapped/{}".format(args.keyname) + + service = constants.PKI_GSSAPI_SERVICE_NAME + client_keyfile = os.path.join(paths.PKI_TOMCAT, service + '.keys') + client_keytab = os.path.join(paths.PKI_TOMCAT, service + '.keytab') + ++ for filename in [client_keyfile, client_keytab]: ++ if not os.access(filename, os.R_OK): ++ parser.error( ++ "File '{}' missing or not readable.\n".format(filename) ++ ) ++ + # pylint: disable=no-member + client = CustodiaClient( +- client_service='%s@%s' % (service, env.host), server=servername, +- realm=env.realm, ldap_uri="ldaps://" + env.host, +- keyfile=client_keyfile, keytab=client_keytab, +- ) ++ client_service="{}@{}".format(service, env.host), ++ server=args.servername, ++ realm=env.realm, ++ ldap_uri="ldaps://" + env.host, ++ keyfile=client_keyfile, ++ keytab=client_keytab, ++ ) + + # Print the response JSON to stdout; it is already in the format + # that Dogtag's ExternalProcessKeyRetriever expects + print(client.fetch_key(keyname, store=False)) + + +-try: ++if __name__ == '__main__': + main() +-except BaseException: +- traceback.print_exc() +- sys.exit(1) +diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py +index 16e7856185aa9786007d3b7f8be0652f70fb4518..40df6c4e69cd673dd8e3c36fbf33f2cda8544a67 100644 +--- a/ipaserver/secrets/client.py ++++ b/ipaserver/secrets/client.py +@@ -1,93 +1,106 @@ + # Copyright (C) 2015 IPA Project Contributors, see COPYING for license + + from __future__ import print_function, absolute_import ++ ++import contextlib ++import os ++from base64 import b64encode ++ ++ + # pylint: disable=relative-import + from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC + # pylint: enable=relative-import + from jwcrypto.common import json_decode + from jwcrypto.jwk import JWK ++from ipalib.krb_utils import krb5_format_service_principal_name + from ipaserver.secrets.kem import IPAKEMKeys +-from ipaserver.secrets.store import iSecStore ++from ipaserver.secrets.store import IPASecStore + from ipaplatform.paths import paths +-from base64 import b64encode +-import ldapurl + import gssapi +-import os +-import urllib3 + import requests + + +-class CustodiaClient(object): +- +- def _client_keys(self): +- return self.ikk.server_keys +- +- def _server_keys(self, server, realm): +- principal = 'host/%s@%s' % (server, realm) +- sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG))) +- ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC))) +- return (sk, ek) +- +- def _ldap_uri(self, realm): +- dashrealm = '-'.join(realm.split('.')) +- socketpath = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % (dashrealm,) +- return 'ldapi://' + ldapurl.ldapUrlEscape(socketpath) +- +- def _keystore(self, realm, ldap_uri, auth_type): +- config = dict() +- if ldap_uri is None: +- config['ldap_uri'] = self._ldap_uri(realm) +- else: +- config['ldap_uri'] = ldap_uri +- if auth_type is not None: +- config['auth_type'] = auth_type ++@contextlib.contextmanager ++def ccache_env(ccache): ++ """Temporarily set KRB5CCNAME environment variable ++ """ ++ orig_ccache = os.environ.get('KRB5CCNAME') ++ os.environ['KRB5CCNAME'] = ccache ++ try: ++ yield ++ finally: ++ os.environ.pop('KRB5CCNAME', None) ++ if orig_ccache is not None: ++ os.environ['KRB5CCNAME'] = orig_ccache + +- return iSecStore(config) + +- def __init__( +- self, client_service, keyfile, keytab, server, realm, +- ldap_uri=None, auth_type=None): ++class CustodiaClient(object): ++ def __init__(self, client_service, keyfile, keytab, server, realm, ++ ldap_uri=None, auth_type=None): ++ if client_service.endswith(realm) or "@" not in client_service: ++ raise ValueError( ++ "Client service name must be a GSS name (service@host), " ++ "not '{}'.".format(client_service) ++ ) + self.client_service = client_service + self.keytab = keytab +- +- # Init creds immediately to make sure they are valid. Creds +- # can also be re-inited by _auth_header to avoid expiry. +- # +- self.creds = self.init_creds() +- +- self.service_name = gssapi.Name('HTTP@%s' % (server,), +- gssapi.NameType.hostbased_service) + self.server = server ++ self.realm = realm ++ self.ldap_uri = ldap_uri ++ self.auth_type = auth_type ++ self.service_name = gssapi.Name( ++ 'HTTP@{}'.format(server), gssapi.NameType.hostbased_service ++ ) ++ self.keystore = IPASecStore() ++ # use in-process MEMORY ccache. Handler process don't need a TGT. ++ token = b64encode(os.urandom(8)).decode('ascii') ++ self.ccache = 'MEMORY:Custodia_{}'.format(token) ++ ++ with ccache_env(self.ccache): ++ # Init creds immediately to make sure they are valid. Creds ++ # can also be re-inited by _auth_header to avoid expiry. ++ self.creds = self._init_creds() ++ ++ self.ikk = IPAKEMKeys( ++ {'server_keys': keyfile, 'ldap_uri': ldap_uri} ++ ) ++ self.kemcli = KEMClient( ++ self._server_keys(), self._client_keys() ++ ) + +- self.ikk = IPAKEMKeys({'server_keys': keyfile, 'ldap_uri': ldap_uri}) +- +- self.kemcli = KEMClient(self._server_keys(server, realm), +- self._client_keys()) +- +- self.keystore = self._keystore(realm, ldap_uri, auth_type) +- +- # FIXME: Remove warnings about missing subjAltName for the +- # requests module +- urllib3.disable_warnings() ++ def _client_keys(self): ++ return self.ikk.server_keys + +- def init_creds(self): +- name = gssapi.Name(self.client_service, +- gssapi.NameType.hostbased_service) +- store = {'client_keytab': self.keytab, +- 'ccache': 'MEMORY:Custodia_%s' % b64encode( +- os.urandom(8)).decode('ascii')} ++ def _server_keys(self): ++ principal = krb5_format_service_principal_name( ++ 'host', self.server, self.realm ++ ) ++ sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG))) ++ ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC))) ++ return sk, ek ++ ++ def _init_creds(self): ++ name = gssapi.Name( ++ self.client_service, gssapi.NameType.hostbased_service ++ ) ++ store = { ++ 'client_keytab': self.keytab, ++ 'ccache': self.ccache ++ } + return gssapi.Credentials(name=name, store=store, usage='initiate') + + def _auth_header(self): +- if not self.creds or self.creds.lifetime < 300: +- self.creds = self.init_creds() +- ctx = gssapi.SecurityContext(name=self.service_name, creds=self.creds) ++ if self.creds.lifetime < 300: ++ self.creds = self._init_creds() ++ ctx = gssapi.SecurityContext( ++ name=self.service_name, ++ creds=self.creds ++ ) + authtok = ctx.step() + return {'Authorization': 'Negotiate %s' % b64encode( + authtok).decode('ascii')} + + def fetch_key(self, keyname, store=True): +- + # Prepare URL + url = 'https://%s/ipa/keys/%s' % (self.server, keyname) + +@@ -99,9 +112,11 @@ class CustodiaClient(object): + headers = self._auth_header() + + # Perform request +- r = requests.get(url, headers=headers, +- verify=paths.IPA_CA_CRT, +- params={'type': 'kem', 'value': 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.20.1 + diff --git a/SOURCES/0021-Simplify-and-improve-tests.patch b/SOURCES/0021-Simplify-and-improve-tests.patch deleted file mode 100644 index 699780f..0000000 --- a/SOURCES/0021-Simplify-and-improve-tests.patch +++ /dev/null @@ -1,212 +0,0 @@ -From a88af3d2f21b6a949885981aa82ff87a1336f40c Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 25 Mar 2019 08:17:28 +0100 -Subject: [PATCH] Simplify and improve tests - -Move tests for DNS and roles into helper methods to make them reusable. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - .../test_replica_promotion.py | 147 +++++++++--------- - 1 file changed, 70 insertions(+), 77 deletions(-) - -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index 80890bf05cb242fe09af77aa27b411ac6194e2d6..a4f3e402ce5d6f74af4bd6fed9376f0f039f297a 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -19,8 +19,11 @@ from ipalib.constants import ( - from ipaplatform.paths import paths - from ipatests.test_integration.test_backup_and_restore import backup - from ipatests.test_integration.test_dns_locations import ( -- resolve_records_from_server -+ resolve_records_from_server, IPA_DEFAULT_MASTER_SRV_REC - ) -+from ipapython.dnsutil import DNSName -+from ipalib.constants import IPA_CA_RECORD -+ - - config = get_global_config() - -@@ -802,110 +805,100 @@ class TestReplicaInForwardZone(IntegrationTest): - - - class TestHiddenReplicaPromotion(IntegrationTest): -+ """Test hidden replica features - """ -- Test hidden replica features -- """ -- - topology = 'star' - num_replicas = 1 - - @classmethod - def install(cls, mh): - tasks.install_master(cls.master, setup_dns=True, setup_kra=True) -+ tasks.install_replica( -+ cls.master, cls.replicas[0], -+ setup_dns=True, setup_kra=True, -+ extra_args=('--hidden-replica',) -+ ) - -- @replicas_cleanup -- def test_hidden_replica_install(self): -- self.replicas[0].run_command([ -- 'ipa-client-install', -- '-p', 'admin', -- '-w', self.master.config.admin_password, -- '--domain', self.master.domain.name, -- '--realm', self.master.domain.realm, -- '--server', self.master.hostname, -- '-U' -- ]) -- self.replicas[0].run_command([ -- 'ipa-replica-install', '-w', -- self.master.config.admin_password, -- '-n', self.master.domain.name, -- '-r', self.master.domain.realm, -- '--server', self.master.hostname, -- '--setup-ca', -- '--setup-dns', '--no-forwarders', -- '--hidden-replica', -- '--setup-kra', -- '-U' -- ]) -- expected_txt = 'hidden' -- result = self.replicas[0].run_command([ -- 'ipa', 'ipa server-role-find', -- '--server', self.replicas[0].hostname -- ]) -- assert expected_txt in result.stdout -- dnsrecords = { -- '.'.join(('_kerberos._udp', self.master.domain.name)): 'SRV', -- '.'.join(('_kerberos._tcp', self.master.domain.name)): 'SRV', -- '.'.join(('_ldap._tcp', self.master.domain.name)): 'SRV', -- self.master.domain.name: 'NS' -- } -- nameserver = self.master.ip -- results = [] -- for record in dnsrecords: -- srvr = resolve_records_from_server( -- record, dnsrecords[record], nameserver -- ) -- results.extend(re.findall( -- '|'.join((self.master.hostname, self.replicas[0].hostname)), -- srvr) -+ def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()): -+ domain = DNSName(self.master.domain.name).make_absolute() -+ rset = [ -+ (rname, 'SRV') -+ for rname, _port in IPA_DEFAULT_MASTER_SRV_REC -+ ] -+ rset.append((DNSName(IPA_CA_RECORD), 'A')) -+ -+ for rname, rtype in rset: -+ name_abs = rname.derelativize(domain) -+ query = resolve_records_from_server( -+ name_abs, rtype, self.master.ip - ) -- assert self.master.hostname in results -- assert self.replicas[0].hostname not in results -+ txt = query.to_text() -+ for host in hosts_expected: -+ value = host.hostname if rtype == 'SRV' else host.ip -+ assert value in txt -+ for host in hosts_unexpected: -+ value = host.hostname if rtype == 'SRV' else host.ip -+ assert value not in txt -+ -+ def _check_server_role(self, host, status): -+ roles = [u'IPA master', u'CA server', u'KRA server', u'DNS server'] -+ for role in roles: -+ result = self.master.run_command([ -+ 'ipa', 'server-role-find', -+ '--server', host.hostname, -+ '--role', role -+ ]) -+ expected = 'Role status: {}'.format(status) -+ assert expected in result.stdout_text -+ -+ def test_hidden_replica_install(self): -+ # TODO: check that all services are running on hidden replica -+ self._check_server_role(self.master, 'enabled') -+ self._check_server_role(self.replicas[0], 'hidden') -+ self._check_dnsrecords([self.master], [self.replicas[0]]) - - def test_hidden_replica_promote(self): - self.replicas[0].run_command([ -- 'ipa', 'server-mod', '--state=enabled' -+ 'ipa', 'server-state', -+ self.replicas[0].hostname, '--state=enabled' - ]) -- unexpected_txt = 'hidden' -+ self._check_server_role(self.replicas[0], 'enabled') -+ self._check_dnsrecords([self.master, self.replicas[0]]) - result = self.replicas[0].run_command([ -- 'ipa', 'ipa server-role-find', -- '--server', self.replicas[0].hostname -- ]) -- assert unexpected_txt not in result.stdout -+ 'ipa', 'server-state', -+ self.replicas[0].hostname, '--state=enabled' -+ ], raiseonerr=False) -+ assert result.returncode == 1 -+ assert 'no modifications to be performed' in result.stderr_text - - def test_hidden_replica_demote(self): - self.replicas[0].run_command([ -- 'ipa', 'server-mod', '--state=hidden' -+ 'ipa', 'server-state', -+ self.replicas[0].hostname, '--state=hidden' - ]) -- expected_txt = 'hidden' -- result = self.replicas[0].run_command([ -- 'ipa', 'ipa server-role-find', -- '--server', self.replicas[0].hostname -- ]) -- assert expected_txt in result.stdout -+ self._check_server_role(self.replicas[0], 'hidden') -+ self._check_dnsrecords([self.master], [self.replicas[0]]) - - def test_hidden_replica_backup_and_restore(self): -+ """Exercises backup+restore and hidden replica uninstall - """ -- Exercises backup+restore and hidden replica uninstall -- """ -- # set expectations -- expected_txt = 'hidden' -- result = self.replicas[0].run_command([ -- 'ipa', 'ipa server-role-find', -- '--server', self.replicas[0].hostname -- ]) -- assert expected_txt in result.stdout -+ self._check_server_role(self.replicas[0], 'hidden') - # backup - backup_path = backup(self.replicas[0]) - # uninstall -- result = self.replicas[0].run_command([ -- 'ipa-server-uninstall', '-U', 'hidden-replica' -- ]) -+ tasks.uninstall_replica(self.master, self.replicas[0]) - # restore - dirman_password = self.master.config.dirman_password - self.replicas[0].run_command( -- ['ipa-restore', backup_path], stdin_text=dirman_password + '\nyes' -+ ['ipa-restore', backup_path], -+ stdin_text=dirman_password + '\nyes' - ) -+ # check that role is still hidden -+ self._check_server_role(self.replicas[0], 'hidden') -+ self._check_dnsrecords([self.master], [self.replicas[0]]) - # check that the resulting server can be promoted to enabled - self.replicas[0].run_command([ -- 'ipa', 'server-mod', '--state=enabled' -+ 'ipa', 'server-mod', self.replicas[0].hostname, '--state=enabled' - ]) -+ self._check_server_role(self.replicas[0], 'enabled') -+ self._check_dnsrecords([self.master, self.replicas[0]]) --- -2.20.1 - diff --git a/SOURCES/0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch b/SOURCES/0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch new file mode 100644 index 0000000..db4220c --- /dev/null +++ b/SOURCES/0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch @@ -0,0 +1,43 @@ +From 531b0b66a74b100986ba086fc134fb5f2e587c69 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 19 Jun 2019 19:11:39 +1000 +Subject: [PATCH] CustodiaClient: use ldapi when ldap_uri not specified + +Reinstate ldap_uri selection behaviour that was lost during the +refactor in the previous commit. This is required because, on the +ipa-4-7 branch at least, the IPASecStore needs to use LDAPI to set +the Directory Manager passphrase digest. Use LDAPI when the +ldap_uri has not been explicity specified. + +Part of: https://pagure.io/freeipa/issue/7964 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/secrets/client.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py +index 40df6c4e69cd673dd8e3c36fbf33f2cda8544a67..4c03ef8e4140dd507156d88941600a234b71184e 100644 +--- a/ipaserver/secrets/client.py ++++ b/ipaserver/secrets/client.py +@@ -13,6 +13,7 @@ from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC + from jwcrypto.common import json_decode + from jwcrypto.jwk import JWK + from ipalib.krb_utils import krb5_format_service_principal_name ++from ipaserver.install.installutils import realm_to_ldapi_uri + from ipaserver.secrets.kem import IPAKEMKeys + from ipaserver.secrets.store import IPASecStore + from ipaplatform.paths import paths +@@ -46,7 +47,7 @@ class CustodiaClient(object): + self.keytab = keytab + self.server = server + self.realm = realm +- self.ldap_uri = ldap_uri ++ self.ldap_uri = ldap_uri or realm_to_ldapi_uri(realm) + self.auth_type = auth_type + self.service_name = gssapi.Name( + 'HTTP@{}'.format(server), gssapi.NameType.hostbased_service +-- +2.20.1 + diff --git a/SOURCES/0022-Implement-server-state-state-enabled-hidden.patch b/SOURCES/0022-Implement-server-state-state-enabled-hidden.patch deleted file mode 100644 index 6b4b812..0000000 --- a/SOURCES/0022-Implement-server-state-state-enabled-hidden.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 483fea9c199d76f1e759241ad32c990f5e0eaabc Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 25 Mar 2019 08:36:53 +0100 -Subject: [PATCH] Implement server-state --state=enabled/hidden - -server-state modified the hidden / enabled flags of all configured -services of a server. Since the command does not directly modify the -server LDAP entry, the command has to be implemented as a dedicated plugin. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - API.txt | 9 ++++++ - ipaserver/plugins/server.py | 58 +++++++++++++++++++++++++++++++++++-- - 2 files changed, 65 insertions(+), 2 deletions(-) - -diff --git a/API.txt b/API.txt -index 2135300183e3dc2126309e8f892e79fe6b5178fb..222e30915ccc1fb4a6f3ce228669453f346fdde4 100644 ---- a/API.txt -+++ b/API.txt -@@ -4471,6 +4471,14 @@ option: Str('version?') - output: Entry('result') - output: Output('summary', type=[, ]) - output: PrimaryKey('value') -+command: server_state/1 -+args: 1,2,3 -+arg: Str('cn', cli_name='name') -+option: StrEnum('state', values=[u'enabled', u'hidden']) -+option: Str('version?') -+output: Output('result', type=[]) -+output: Output('summary', type=[, ]) -+output: PrimaryKey('value') - command: service_add/1 - args: 1,13,3 - arg: Principal('krbcanonicalname', cli_name='canonical_principal') -@@ -6900,6 +6908,7 @@ default: server_role/1 - default: server_role_find/1 - default: server_role_show/1 - default: server_show/1 -+default: server_state/1 - default: service/1 - default: service_add/1 - default: service_add_cert/1 -diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py -index e265883e3637938e3df5ecf132f4add62413a997..0d144d13bca66b65de64328139fd7126eea24c89 100644 ---- a/ipaserver/plugins/server.py -+++ b/ipaserver/plugins/server.py -@@ -12,7 +12,7 @@ import ldap - import time - - from ipalib import api, crud, errors, messages --from ipalib import Int, Flag, Str, DNSNameParam -+from ipalib import Int, Flag, Str, StrEnum, DNSNameParam - from ipalib.plugable import Registry - from .baseldap import ( - LDAPSearch, -@@ -28,8 +28,9 @@ from ipaplatform import services - from ipapython.dn import DN - from ipapython.dnsutil import DNSName - from ipaserver import topology --from ipaserver.servroles import ENABLED -+from ipaserver.servroles import ENABLED, HIDDEN - from ipaserver.install import bindinstance, dnskeysyncinstance -+from ipaserver.install.service import hide_services, enable_services - - __doc__ = _(""" - IPA servers -@@ -949,3 +950,56 @@ class server_conncheck(crud.PKQuery): - messages.ExternalCommandOutput(line=line)) - - return result -+ -+ -+@register() -+class server_state(crud.PKQuery): -+ __doc__ = _("Set enabled/hidden state of a server.") -+ -+ takes_options = ( -+ StrEnum( -+ 'state', -+ values=(u'enabled', u'hidden'), -+ label=_('State'), -+ doc=_('Server state'), -+ flags={'virtual_attribute', 'no_create', 'no_search'}, -+ ), -+ ) -+ -+ msg_summary = _('Changed server state of "%(value)s".') -+ -+ has_output = output.standard_boolean -+ -+ def execute(self, *keys, **options): -+ fqdn = keys[0] -+ if options['state'] == u'enabled': -+ to_status = ENABLED -+ from_status = HIDDEN -+ else: -+ to_status = HIDDEN -+ from_status = ENABLED -+ -+ roles = self.api.Command.server_role_find( -+ server_server=fqdn, -+ status=from_status, -+ include_master=True, -+ )['result'] -+ from_roles = [r[u'role_servrole'] for r in roles] -+ if not from_roles: -+ # no server role is in source status -+ raise errors.EmptyModlist -+ -+ if to_status == ENABLED: -+ enable_services(fqdn) -+ else: -+ hide_services(fqdn) -+ -+ # update system roles -+ result = self.api.Command.dns_update_system_records() -+ if not result.get('value'): -+ self.add_message(messages.AutomaticDNSRecordsUpdateFailed()) -+ -+ return { -+ 'value': fqdn, -+ 'result': True, -+ } --- -2.20.1 - diff --git a/SOURCES/0023-Consider-hidden-servers-as-role-provider.patch b/SOURCES/0023-Consider-hidden-servers-as-role-provider.patch deleted file mode 100644 index d847594..0000000 --- a/SOURCES/0023-Consider-hidden-servers-as-role-provider.patch +++ /dev/null @@ -1,45 +0,0 @@ -From d5538488447a42110c2b6f77ffdc80d4c6e0e61e Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 25 Mar 2019 15:58:07 +0100 -Subject: [PATCH] Consider hidden servers as role provider - -Hidden services are now considered as associated role providers, too. This -fixes the issue of: - - invalid 'PKINIT enabled server': all masters must have IPA - master role enabled - -and similar issues with CA and DNS. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - ipaserver/servroles.py | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py -index 02a22e77dbb615f735660c53d1b2eb7da022591d..9c963be53527bb955ebf2b8cec7960f0d90717a4 100644 ---- a/ipaserver/servroles.py -+++ b/ipaserver/servroles.py -@@ -338,12 +338,13 @@ class ServerAttribute(LDAPBasedProperty): - ldap.update_entry(service_entry) - - def _get_assoc_role_providers(self, api_instance): -- """ -- get list of all servers on which the associated role is enabled -+ """get list of all servers on which the associated role is enabled -+ -+ Consider a hidden server as a valid provider for a role. - """ - return [ - r[u'server_server'] for r in self.associated_role.status( -- api_instance) if r[u'status'] == ENABLED] -+ api_instance) if r[u'status'] in {ENABLED, HIDDEN}] - - def _remove(self, api_instance, masters): - """ --- -2.20.1 - diff --git a/SOURCES/0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch b/SOURCES/0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch new file mode 100644 index 0000000..66f78ae --- /dev/null +++ b/SOURCES/0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch @@ -0,0 +1,41 @@ +From 457131218990e7c6a9de21de0e3fb9e9ecf6a6fe Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Tue, 30 Jul 2019 16:21:35 +1000 +Subject: [PATCH] CustodiaClient: fix IPASecStore config on ipa-4-7 + +The backport of a Custodia client fix for f30 and related refactors +and improvements, to the ipa-4-7 branch, had no conflicts. But +there is a change on newer branches that broke the backport. The +running of Custodia handlers in separate processes simplified the +configuration of the ISecStore. For ipa-4-7 we need to continue to +explicitly configure it, so restore the old configuration behaviour. + +Part of: https://pagure.io/freeipa/issue/7964 + +Reviewed-By: Alexander Bokovoy +Reviewed-By: Rob Crittenden +--- + ipaserver/secrets/client.py | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py +index 4c03ef8e4140dd507156d88941600a234b71184e..2363b081dbbf3671e8147497bb52811825bdf1a4 100644 +--- a/ipaserver/secrets/client.py ++++ b/ipaserver/secrets/client.py +@@ -52,7 +52,12 @@ class CustodiaClient(object): + self.service_name = gssapi.Name( + 'HTTP@{}'.format(server), gssapi.NameType.hostbased_service + ) +- self.keystore = IPASecStore() ++ ++ config = {'ldap_uri': self.ldap_uri} ++ if auth_type is not None: ++ config['auth_type'] = auth_type ++ self.keystore = IPASecStore(config) ++ + # use in-process MEMORY ccache. Handler process don't need a TGT. + token = b64encode(os.urandom(8)).decode('ascii') + self.ccache = 'MEMORY:Custodia_{}'.format(token) +-- +2.20.1 + diff --git a/SOURCES/0024-Bump-krb5-min-version.patch b/SOURCES/0024-Bump-krb5-min-version.patch new file mode 100644 index 0000000..4da8584 --- /dev/null +++ b/SOURCES/0024-Bump-krb5-min-version.patch @@ -0,0 +1,34 @@ +From fc937b3b5ecc2743546cd2e0fa0193c390113579 Mon Sep 17 00:00:00 2001 +From: Fraser Tweedale +Date: Wed, 25 Sep 2019 16:43:25 +1000 +Subject: [PATCH] Bump krb5 min version + +krb5-1.15.1-36 introduced a ccache behavioural change that broke +lightweight CA key replication. The preceding commits (backported +from the ipa-4-7 branch) fix this issue but this commit ensure that +the correct version of krb5 is used with the updated FreeIPA code. + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1755223 +Reviewed-By: Rob Crittenden +--- + freeipa.spec.in | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/freeipa.spec.in b/freeipa.spec.in +index 4cca8b5159e8e38f79bad8df8af76ac7b8ed5387..0f96778f758cb21c01e31ff35e70c79f020aa2d3 100644 +--- a/freeipa.spec.in ++++ b/freeipa.spec.in +@@ -49,8 +49,8 @@ + + %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 ++# 1.15.1-36: https://bugzilla.redhat.com/show_bug.cgi?id=1755223 ++%global krb5_version 1.15.1-36 + # 0.7.16: https://github.com/drkjam/netaddr/issues/71 + %global python_netaddr_version 0.7.5-8 + # Require 4.7.0 which brings Python 3 bindings +-- +2.20.1 + diff --git a/SOURCES/0024-Improve-config-show-to-show-hidden-servers.patch b/SOURCES/0024-Improve-config-show-to-show-hidden-servers.patch deleted file mode 100644 index e2e34f5..0000000 --- a/SOURCES/0024-Improve-config-show-to-show-hidden-servers.patch +++ /dev/null @@ -1,246 +0,0 @@ -From ae9ab0545ff06b60df4b66c0ebccb7baa79b8898 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 25 Mar 2019 15:59:51 +0100 -Subject: [PATCH] Improve config-show to show hidden servers - -config-show only used to show enabled servers. Now also show hidden -servers on separate lines. Additionally include information about -KRA and DNS servers. - -The augmented config-show output makes it easier to diagnose a cluster -and simplifies sanity checks. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - ipaserver/plugins/config.py | 56 +++++++++++++++++-- - ipaserver/plugins/serverroles.py | 25 ++++++--- - ipaserver/servroles.py | 6 ++ - .../test_replica_promotion.py | 23 ++++++++ - 4 files changed, 97 insertions(+), 13 deletions(-) - -diff --git a/ipaserver/plugins/config.py b/ipaserver/plugins/config.py -index fff58ac656f4fad3491dfa9f95c22b7d54a6da56..58b48935c2c7471ff2ce0bb3f5ce92a9fb47a503 100644 ---- a/ipaserver/plugins/config.py -+++ b/ipaserver/plugins/config.py -@@ -249,6 +249,18 @@ class config(LDAPObject): - doc=_('List of all IPA masters'), - flags={'virtual_attribute', 'no_create', 'no_update'} - ), -+ Str( -+ 'ipa_master_hidden_server*', -+ label=_('Hidden IPA masters'), -+ doc=_('List of all hidden IPA masters'), -+ flags={'virtual_attribute', 'no_create', 'no_update'} -+ ), -+ 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( - 'ca_server_server*', - label=_('IPA CA servers'), -@@ -261,6 +273,12 @@ class config(LDAPObject): - doc=_('IPA servers with enabled NTP'), - flags={'virtual_attribute', 'no_create', 'no_update'} - ), -+ Str( -+ 'ca_server_hidden_server*', -+ label=_('Hidden IPA CA servers'), -+ doc=_('Hidden IPA servers configured as certificate authority'), -+ flags={'virtual_attribute', 'no_create', 'no_update'} -+ ), - Str( - 'ca_renewal_master_server?', - label=_('IPA CA renewal master'), -@@ -268,9 +286,15 @@ 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'), -+ 'kra_server_server*', -+ label=_('IPA KRA servers'), -+ doc=_('IPA servers configured as key recovery agent'), -+ flags={'virtual_attribute', 'no_create', 'no_update'} -+ ), -+ Str( -+ 'kra_server_hidden_server*', -+ label=_('Hidden IPA KRA servers'), -+ doc=_('Hidden IPA servers configured as key recovery agent'), - flags={'virtual_attribute', 'no_create', 'no_update'} - ), - Str( -@@ -279,7 +303,25 @@ class config(LDAPObject): - label=_('Domain resolution order'), - doc=_('colon-separated list of domains used for short name' - ' qualification') -- ) -+ ), -+ Str( -+ 'dns_server_server*', -+ label=_('IPA DNS servers'), -+ doc=_('IPA servers configured as domain name server'), -+ flags={'virtual_attribute', 'no_create', 'no_update'} -+ ), -+ Str( -+ 'dns_server_hidden_server*', -+ label=_('Hidden IPA DNS servers'), -+ doc=_('Hidden IPA servers configured as domain name server'), -+ flags={'virtual_attribute', 'no_create', 'no_update'} -+ ), -+ Str( -+ 'dnssec_key_master_server?', -+ label=_('IPA DNSSec key master'), -+ doc=_('DNSec key master'), -+ flags={'virtual_attribute', 'no_create', 'no_update'} -+ ), - ) - - def get_dn(self, *keys, **kwargs): -@@ -560,7 +602,8 @@ class config_mod(LDAPUpdate): - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - self.obj.show_servroles_attributes( -- entry_attrs, "CA server", "IPA master", "NTP server", **options) -+ entry_attrs, "CA server", "KRA server", "IPA master", -+ "NTP server", "DNS server", **options) - return dn - - -@@ -570,5 +613,6 @@ class config_show(LDAPRetrieve): - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): - self.obj.show_servroles_attributes( -- entry_attrs, "CA server", "IPA master", "NTP server", **options) -+ entry_attrs, "CA server", "KRA server", "IPA master", -+ "NTP server", "DNS server", **options) - return dn -diff --git a/ipaserver/plugins/serverroles.py b/ipaserver/plugins/serverroles.py -index 0abf48ae5295be5f622bf8c90d32e7adff5e6cf7..5bba84972a5828b6c7230d0d0d858e6683e5986b 100644 ---- a/ipaserver/plugins/serverroles.py -+++ b/ipaserver/plugins/serverroles.py -@@ -45,7 +45,9 @@ import six - from ipalib import errors, _ - from ipalib.backend import Backend - from ipalib.plugable import Registry --from ipaserver.servroles import (attribute_instances, ENABLED, role_instances) -+from ipaserver.servroles import ( -+ attribute_instances, ENABLED, HIDDEN, role_instances -+) - from ipaserver.servroles import SingleValuedServerAttribute - - -@@ -81,17 +83,26 @@ class serverroles(Backend): - raise errors.NotFound( - reason=_("{role}: role not found".format(role=role_name))) - -- def _get_enabled_masters(self, role_name): -+ def _get_masters(self, role_name, include_hidden): - result = {} - role = self._get_role(role_name) -+ role_states = role.status(self.api, server=None) - - enabled_masters = [ -- r[u'server_server'] for r in role.status(self.api, server=None) if -- r[u'status'] == ENABLED] -- -+ r[u'server_server'] for r in role_states if -+ r[u'status'] == ENABLED -+ ] - if enabled_masters: - result.update({role.attr_name: enabled_masters}) - -+ if include_hidden and role.attr_name_hidden is not None: -+ hidden_masters = [ -+ r[u'server_server'] for r in role_states if -+ r[u'status'] == HIDDEN -+ ] -+ if hidden_masters: -+ result.update({role.attr_name_hidden: hidden_masters}) -+ - return result - - def _get_assoc_attributes(self, role_name): -@@ -131,8 +142,8 @@ class serverroles(Backend): - return self._get_role(role_servrole).status( - self.api, server=server_server) - -- def config_retrieve(self, servrole): -- result = self._get_enabled_masters(servrole) -+ def config_retrieve(self, servrole, include_hidden=True): -+ result = self._get_masters(servrole, include_hidden=include_hidden) - - try: - assoc_attributes = self._get_assoc_attributes(servrole) -diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py -index 9c963be53527bb955ebf2b8cec7960f0d90717a4..0988cbdd7eac599ef26c89a015523b2d92e9502f 100644 ---- a/ipaserver/servroles.py -+++ b/ipaserver/servroles.py -@@ -104,6 +104,12 @@ class LDAPBasedProperty(object): - def __init__(self, attr_name, name): - self.attr_name = attr_name - self.name = name -+ # for hidden services, insert hidden before '_server' suffix -+ if attr_name.endswith(u'_server'): -+ parts = attr_name.rsplit(u'_', 1) -+ self.attr_name_hidden = u'{}_hidden_server'.format(parts[0]) -+ else: -+ self.attr_name_hidden = None - - - @six.add_metaclass(abc.ABCMeta) -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index a4f3e402ce5d6f74af4bd6fed9376f0f039f297a..3be2ea95fa2325edfc74cbb902ce0a5966aa82d7 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -851,11 +851,32 @@ class TestHiddenReplicaPromotion(IntegrationTest): - expected = 'Role status: {}'.format(status) - assert expected in result.stdout_text - -+ def _check_config(self, enabled=(), hidden=()): -+ enabled = {host.hostname for host in enabled} -+ hidden = {host.hostname for host in hidden} -+ services = [ -+ 'IPA masters', 'IPA CA servers', 'IPA KRA servers', -+ 'IPA DNS servers' -+ ] -+ -+ result = self.master.run_command(['ipa', 'config-show']) -+ values = {} -+ for line in result.stdout_text.split('\n'): -+ if ':' not in line: -+ continue -+ k, v = line.split(':', 1) -+ values[k.strip()] = {item.strip() for item in v.split(',')} -+ -+ for service in services: -+ assert values[service] == enabled -+ assert values['Hidden {}'.format(service)] == hidden -+ - def test_hidden_replica_install(self): - # TODO: check that all services are running on hidden replica - self._check_server_role(self.master, 'enabled') - self._check_server_role(self.replicas[0], 'hidden') - self._check_dnsrecords([self.master], [self.replicas[0]]) -+ self._check_config([self.master], [self.replicas[0]]) - - def test_hidden_replica_promote(self): - self.replicas[0].run_command([ -@@ -864,6 +885,8 @@ class TestHiddenReplicaPromotion(IntegrationTest): - ]) - self._check_server_role(self.replicas[0], 'enabled') - self._check_dnsrecords([self.master, self.replicas[0]]) -+ self._check_config([self.master, self.replicas[0]]) -+ - result = self.replicas[0].run_command([ - 'ipa', 'server-state', - self.replicas[0].hostname, '--state=enabled' --- -2.20.1 - diff --git a/SOURCES/0025-More-test-fixes.patch b/SOURCES/0025-More-test-fixes.patch deleted file mode 100644 index f1559ca..0000000 --- a/SOURCES/0025-More-test-fixes.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 9c62af973d71cabaf8d93216717468385ac2abbe Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 25 Mar 2019 18:36:19 +0100 -Subject: [PATCH] More test fixes - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - .../test_integration/test_replica_promotion.py | 18 +++++++++++++----- - 1 file changed, 13 insertions(+), 5 deletions(-) - -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index 3be2ea95fa2325edfc74cbb902ce0a5966aa82d7..9ce0074ea0df276b4800b306530d04c8274ece69 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -843,7 +843,7 @@ class TestHiddenReplicaPromotion(IntegrationTest): - def _check_server_role(self, host, status): - roles = [u'IPA master', u'CA server', u'KRA server', u'DNS server'] - for role in roles: -- result = self.master.run_command([ -+ result = self.replicas[0].run_command([ - 'ipa', 'server-role-find', - '--server', host.hostname, - '--role', role -@@ -859,7 +859,7 @@ class TestHiddenReplicaPromotion(IntegrationTest): - 'IPA DNS servers' - ] - -- result = self.master.run_command(['ipa', 'config-show']) -+ result = self.replicas[0].run_command(['ipa', 'config-show']) - values = {} - for line in result.stdout_text.split('\n'): - if ':' not in line: -@@ -868,8 +868,9 @@ class TestHiddenReplicaPromotion(IntegrationTest): - values[k.strip()] = {item.strip() for item in v.split(',')} - - for service in services: -- assert values[service] == enabled -- assert values['Hidden {}'.format(service)] == hidden -+ hservice = 'Hidden {}'.format(service) -+ assert values.get(service, set()) == enabled -+ assert values.get(hservice, set()) == hidden - - def test_hidden_replica_install(self): - # TODO: check that all services are running on hidden replica -@@ -909,19 +910,26 @@ class TestHiddenReplicaPromotion(IntegrationTest): - # backup - backup_path = backup(self.replicas[0]) - # uninstall -- tasks.uninstall_replica(self.master, self.replicas[0]) -+ tasks.uninstall_master(self.replicas[0]) - # restore - dirman_password = self.master.config.dirman_password - self.replicas[0].run_command( - ['ipa-restore', backup_path], - stdin_text=dirman_password + '\nyes' - ) -+ # give replication some time -+ time.sleep(5) -+ - # check that role is still hidden -+ tasks.kinit_admin(self.replicas[0]) -+ self._check_config([self.master], [self.replicas[0]]) - self._check_server_role(self.replicas[0], 'hidden') - self._check_dnsrecords([self.master], [self.replicas[0]]) -+ - # check that the resulting server can be promoted to enabled - self.replicas[0].run_command([ - 'ipa', 'server-mod', self.replicas[0].hostname, '--state=enabled' - ]) -+ self._check_config([self.master, self.replicas[0]]) - self._check_server_role(self.replicas[0], 'enabled') - self._check_dnsrecords([self.master, self.replicas[0]]) --- -2.20.1 - diff --git a/SOURCES/0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch b/SOURCES/0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch new file mode 100644 index 0000000..a60d5d6 --- /dev/null +++ b/SOURCES/0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch @@ -0,0 +1,44 @@ +From 5badb4233cb59a6045e544576ebabff94c02131e Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Wed, 16 Oct 2019 17:02:38 +0200 +Subject: [PATCH] ipa-backup: fix python2 issue with os.mkdir + +Python2 and python3 have different interfaces for os.mkdir: +python2: os.mkdir(path[, mode]) +python3: os.mkdir(path, mode=0o777, *, dir_fd=None) + +ipa-backup is using the python3 format, which breaks deployments using +python2. The fix consists in using os.mkdir(path, 0o700) instead of +os.mkdir(path, mode=0o700). + +Fixes: https://pagure.io/freeipa/issue/8099 +Reviewed-By: Alexander Bokovoy +--- + ipaserver/install/ipa_backup.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py +index 96f3d7e1c6abdc6a4f3080810a8ea3bd8211d16b..496bbd8925972a6e1dbdd00c01b62f2e2c4398d6 100644 +--- a/ipaserver/install/ipa_backup.py ++++ b/ipaserver/install/ipa_backup.py +@@ -289,7 +289,7 @@ class Backup(admintool.AdminTool): + os.chown(self.top_dir, pent.pw_uid, pent.pw_gid) + os.chmod(self.top_dir, 0o750) + self.dir = os.path.join(self.top_dir, "ipa") +- os.mkdir(self.dir, mode=0o750) ++ os.mkdir(self.dir, 0o750) + os.chown(self.dir, pent.pw_uid, pent.pw_gid) + self.tarfile = None + +@@ -663,7 +663,7 @@ class Backup(admintool.AdminTool): + filename = os.path.join(backup_dir, "ipa-full.tar") + + try: +- os.mkdir(backup_dir, mode=0o700) ++ os.mkdir(backup_dir, 0o700) + except (OSError, IOError) as e: + raise admintool.ScriptError( + 'Could not create backup directory: %s' % e +-- +2.20.1 + diff --git a/SOURCES/0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch b/SOURCES/0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch new file mode 100644 index 0000000..31d5953 --- /dev/null +++ b/SOURCES/0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch @@ -0,0 +1,43 @@ +From 5701d4f75c780d778fccefdb1ec911d4f1fccd8e Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Sun, 17 Nov 2019 19:37:03 +0200 +Subject: [PATCH] Do not run trust upgrade code if master lacks Samba bindings + +If a replica has no Samba bindings but there are trust agreements +configured on some trust controller, skip trust upgrade code on this +replica. + +Resolves: https://pagure.io/freeipa/issue/8001 +Signed-off-by: Alexander Bokovoy +Reviewed-By: Thomas Woerner +--- + ipaserver/install/plugins/adtrust.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py +index 950b7b9c82f1b0e115675ff8093d1bd02e913ae2..c0de12eca903a6635f4b53b0806a0ba07170b7c6 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -23,6 +23,8 @@ except ImportError: + def ndr_unpack(x): + raise NotImplementedError + ++ drsblobs = None ++ + logger = logging.getLogger(__name__) + + register = Registry() +@@ -633,6 +635,10 @@ class update_tdo_to_new_layout(Updater): + logger.debug('AD Trusts are not enabled on this server') + return False, [] + ++ # If we have no Samba bindings, this master is not a trust controller ++ if drsblobs is None: ++ return False, [] ++ + ldap = self.api.Backend.ldap2 + gidNumber = get_gidNumber(ldap, self.api.env) + if gidNumber is None: +-- +2.23.0 + diff --git a/SOURCES/0026-Don-t-allow-to-hide-last-server-for-a-role.patch b/SOURCES/0026-Don-t-allow-to-hide-last-server-for-a-role.patch deleted file mode 100644 index 53e180e..0000000 --- a/SOURCES/0026-Don-t-allow-to-hide-last-server-for-a-role.patch +++ /dev/null @@ -1,118 +0,0 @@ -From ec58278fa7fc6d0b5ae8340c4054005a7864086f Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Tue, 26 Mar 2019 13:10:23 +0100 -Subject: [PATCH] Don't allow to hide last server for a role - -DNSSec key master and CA renewal master can't be hidden. There must be -at least one enabled server available for each role, too. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - ipaserver/plugins/server.py | 30 ++++++++++++++++++ - .../test_replica_promotion.py | 31 +++++++++++++++++++ - 2 files changed, 61 insertions(+) - -diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py -index 0d144d13bca66b65de64328139fd7126eea24c89..bfd1406ff826aea97195aa08ca35018e35cac18c 100644 ---- a/ipaserver/plugins/server.py -+++ b/ipaserver/plugins/server.py -@@ -970,6 +970,35 @@ class server_state(crud.PKQuery): - - has_output = output.standard_boolean - -+ def _check_hide_server(self, fqdn): -+ result = self.api.Command.config_show()['result'] -+ err = [] -+ # single value entries -+ if result.get("ca_renewal_master_server") == fqdn: -+ err.append(_("Cannot hide CA renewal master.")) -+ if result.get("dnssec_key_master_server") == fqdn: -+ err.append(_("Cannot hide DNSSec key master.")) -+ # multi value entries, only fail if we are the last one -+ checks = [ -+ ("ca_server_server", "CA"), -+ ("dns_server_server", "DNS"), -+ ("ipa_master_server", "IPA"), -+ ("kra_server_server", "KRA"), -+ ] -+ for key, name in checks: -+ values = result.get(key, []) -+ if values == [fqdn]: # fqdn is the only entry -+ err.append( -+ _("Cannot hide last enabled %(name)s server.") % { -+ 'name': name -+ } -+ ) -+ if err: -+ raise errors.ValidationError( -+ name=fqdn, -+ error=' '.join(str(e) for e in err) -+ ) -+ - def execute(self, *keys, **options): - fqdn = keys[0] - if options['state'] == u'enabled': -@@ -992,6 +1021,7 @@ class server_state(crud.PKQuery): - if to_status == ENABLED: - enable_services(fqdn) - else: -+ self._check_hide_server(fqdn) - hide_services(fqdn) - - # update system roles -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index 9ce0074ea0df276b4800b306530d04c8274ece69..bf028bf7dc58abb6455ba1659f2d19bede69daa2 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -812,7 +812,15 @@ class TestHiddenReplicaPromotion(IntegrationTest): - - @classmethod - def install(cls, mh): -+ # master with DNSSEC master - tasks.install_master(cls.master, setup_dns=True, setup_kra=True) -+ cls.master.run_command([ -+ "ipa-dns-install", -+ "--dnssec-master", -+ "--forwarder", cls.master.config.dns_forwarder, -+ "-U", -+ ]) -+ # hidden replica with CA and DNS - tasks.install_replica( - cls.master, cls.replicas[0], - setup_dns=True, setup_kra=True, -@@ -879,6 +887,29 @@ class TestHiddenReplicaPromotion(IntegrationTest): - self._check_dnsrecords([self.master], [self.replicas[0]]) - self._check_config([self.master], [self.replicas[0]]) - -+ def test_hide_master_fails(self): -+ # verify state -+ self._check_config([self.master], [self.replicas[0]]) -+ # nothing to do -+ result = self.master.run_command([ -+ 'ipa', 'server-state', -+ self.master.hostname, '--state=enabled' -+ ], raiseonerr=False) -+ assert result.returncode == 1 -+ assert "no modifications to be performed" in result.stderr_text -+ # hiding the last master fails -+ result = self.master.run_command([ -+ 'ipa', 'server-state', -+ self.master.hostname, '--state=hidden' -+ ], raiseonerr=False) -+ assert result.returncode == 1 -+ keys = [ -+ "CA renewal master", "DNSSec key master", "CA server", -+ "KRA server", "DNS server", "IPA server" -+ ] -+ for key in keys: -+ assert key in result.stderr_text -+ - def test_hidden_replica_promote(self): - self.replicas[0].run_command([ - 'ipa', 'server-state', --- -2.20.1 - diff --git a/SOURCES/0027-Make-sure-to-have-storage-space-for-tag.patch b/SOURCES/0027-Make-sure-to-have-storage-space-for-tag.patch new file mode 100644 index 0000000..b994893 --- /dev/null +++ b/SOURCES/0027-Make-sure-to-have-storage-space-for-tag.patch @@ -0,0 +1,39 @@ +From 3384e4b799409eb669a779406cabbb1ed1bf783f Mon Sep 17 00:00:00 2001 +From: Simo Sorce +Date: Mon, 16 Sep 2019 11:12:25 -0400 +Subject: [PATCH] Make sure to have storage space for tag + +ber_scanf expects a pointer to a ber_tag_t to return the tag pointed at +by "t", if that is not provided the pointer will be store in whatever +memory location is pointed by the stack at that time causeing a crash. + +Note that this is effectively unused code because in ipa-kdb the only +party that can write a key_data structure to be stored is te kdb_driver +itself and we never encode these s2kparam data. + +But we need to handle this for future proofing. + +Fixes #8071 + +Signed-off-by: Simo Sorce +Reviewed-By: Christian Heimes +--- + util/ipa_krb5.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c +index a27cd4a4e538c738c6ab2157a4daabf8fea7661c..c09c3daa505655f2e5292a79c03683faa75ad244 100644 +--- a/util/ipa_krb5.c ++++ b/util/ipa_krb5.c +@@ -554,7 +554,7 @@ int ber_decode_krb5_key_data(struct berval *encoded, int *m_kvno, + retag = ber_peek_tag(be, &setlen); + if (retag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2)) { + /* not supported yet, skip */ +- retag = ber_scanf(be, "t[x]}"); ++ retag = ber_scanf(be, "t[x]}", &tag); + } else { + retag = ber_scanf(be, "}"); + } +-- +2.23.0 + diff --git a/SOURCES/0027-Synchronize-hidden-state-from-IPA-master-role.patch b/SOURCES/0027-Synchronize-hidden-state-from-IPA-master-role.patch deleted file mode 100644 index ba3a6c8..0000000 --- a/SOURCES/0027-Synchronize-hidden-state-from-IPA-master-role.patch +++ /dev/null @@ -1,118 +0,0 @@ -From d0327f33d3bc426db5c8dd86666e680da6a44b61 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Tue, 26 Mar 2019 13:27:35 +0100 -Subject: [PATCH] Synchronize hidden state from IPA master role - -ipa-{adtrust|ca|dns|kra}-install on a hidden replica also installs the -new service as hidden service. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - install/tools/ipa-adtrust-install | 2 +- - install/tools/ipa-ca-install | 2 +- - ipaserver/install/ipa_kra_install.py | 2 +- - ipaserver/install/service.py | 22 +++++++++++++++++++ - .../test_replica_promotion.py | 4 +++- - 5 files changed, 28 insertions(+), 4 deletions(-) - -diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install -index 9dbfadb6fae193e2f4a54b3a0e226e0a6b1fd26f..19bd21866119b4a23f5a6a02cc8ea37c8f5d36ea 100755 ---- a/install/tools/ipa-adtrust-install -+++ b/install/tools/ipa-adtrust-install -@@ -213,7 +213,7 @@ def main(): - adtrust.install(True, options, fstore, api) - - # Enable configured services and update DNS SRV records -- service.enable_services(api.env.host) -+ service.sync_services_state(api.env.host) - api.Command.dns_update_system_records() - - print(""" -diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install -index 55182dc30e4736618f749e78db161fc7eefe37ac..dda7a0527b07695c51140c437a2699c8634f2724 100755 ---- a/install/tools/ipa-ca-install -+++ b/install/tools/ipa-ca-install -@@ -347,7 +347,7 @@ def main(): - api.Backend.ldap2.connect() - - # Enable configured services and update DNS SRV records -- service.enable_services(api.env.host) -+ service.sync_services_state(api.env.host) - api.Command.dns_update_system_records() - api.Backend.ldap2.disconnect() - -diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py -index 19260ac7f23a7c6f3a6328d4f146510a186b706e..006bc92bec581e1983f11bfd75498b5484f2567a 100644 ---- a/ipaserver/install/ipa_kra_install.py -+++ b/ipaserver/install/ipa_kra_install.py -@@ -239,6 +239,6 @@ class KRAInstaller(KRAInstall): - api.Backend.ldap2.connect() - - # Enable configured services and update DNS SRV records -- service.enable_services(api.env.host) -+ service.sync_services_state(api.env.host) - api.Command.dns_update_system_records() - api.Backend.ldap2.disconnect() -diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py -index 6d7997c559f8d748f00dd9df28371c53bc12ee21..8948f64c2ec2db4cd013699e07dd94d5dba6c043 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -41,6 +41,7 @@ from ipaplatform.paths import paths - from ipaserver.masters import ( - CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE, SERVICE_LIST - ) -+from ipaserver.servroles import HIDDEN - - logger = logging.getLogger(__name__) - -@@ -202,6 +203,27 @@ def hide_services(fqdn): - _set_services_state(fqdn, HIDDEN_SERVICE) - - -+def sync_services_state(fqdn): -+ """Synchronize services state from IPA master role state -+ -+ Hide all services if the IPA master role state is in hidden state. -+ Otherwise enable all services. -+ -+ :param fqdn: hostname of server -+ """ -+ result = api.Command.server_role_find( -+ server_server=fqdn, -+ role_servrole='IPA master', -+ status=HIDDEN -+ ) -+ if result['count']: -+ # one hidden server role -+ hide_services(fqdn) -+ else: -+ # IPA master is either enabled or configured, enable all -+ enable_services(fqdn) -+ -+ - def _set_services_state(fqdn, dest_state): - """Change all services of a host - -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index bf028bf7dc58abb6455ba1659f2d19bede69daa2..df71972a2ba3ad503011a558295bd38f587faf44 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -823,9 +823,11 @@ class TestHiddenReplicaPromotion(IntegrationTest): - # hidden replica with CA and DNS - tasks.install_replica( - cls.master, cls.replicas[0], -- setup_dns=True, setup_kra=True, -+ setup_dns=True, setup_kra=False, - extra_args=('--hidden-replica',) - ) -+ # manually install KRA to verify that hidden state is synced -+ tasks.install_kra(cls.replicas[0]) - - def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()): - domain = DNSName(self.master.domain.name).make_absolute() --- -2.20.1 - diff --git a/SOURCES/0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch b/SOURCES/0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch new file mode 100644 index 0000000..80fd778 --- /dev/null +++ b/SOURCES/0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch @@ -0,0 +1,147 @@ +From 4b391a87700b3bee23a241e6ede28d19fcfca3d3 Mon Sep 17 00:00:00 2001 +From: Rob Crittenden +Date: Tue, 2 Jul 2019 13:44:48 -0400 +Subject: [PATCH] CVE-2019-10195: Don't log passwords embedded in commands in + calls using batch + +A raw batch request was fully logged which could expose parameters +we don't want logged, like passwords. + +Override _repr_iter to use the individual commands to log the +values so that values are properly obscured. + +In case of errors log the full value on when the server is in +debug mode. + +Reported by Jamison Bennett from Cloudera + +Signed-off-by: Rob Crittenden +Reviewed-by: Florence Blanc-Renaud +--- + ipaserver/plugins/batch.py | 96 ++++++++++++++++++++++++++++---------- + 1 file changed, 72 insertions(+), 24 deletions(-) + +diff --git a/ipaserver/plugins/batch.py b/ipaserver/plugins/batch.py +index 2794db895a014a6129654889289815d4286cf7f4..9df367d16234d1840a2e5297cdd5c3c59fa4828f 100644 +--- a/ipaserver/plugins/batch.py ++++ b/ipaserver/plugins/batch.py +@@ -92,35 +92,82 @@ class batch(Command): + Output('results', (list, tuple), doc='') + ) + ++ def _validate_request(self, request): ++ """ ++ Check that an individual request in a batch is parseable and the ++ commands exists. ++ """ ++ if 'method' not in request: ++ raise errors.RequirementError(name='method') ++ if 'params' not in request: ++ raise errors.RequirementError(name='params') ++ name = request['method'] ++ if (name not in self.api.Command or ++ isinstance(self.api.Command[name], Local)): ++ raise errors.CommandError(name=name) ++ ++ # If params are not formated as a tuple(list, dict) ++ # the following lines will raise an exception ++ # that triggers an internal server error ++ # Raise a ConversionError instead to report the issue ++ # to the client ++ try: ++ a, kw = request['params'] ++ newkw = dict((str(k), v) for k, v in kw.items()) ++ api.Command[name].args_options_2_params(*a, **newkw) ++ except (AttributeError, ValueError, TypeError): ++ raise errors.ConversionError( ++ name='params', ++ error=_(u'must contain a tuple (list, dict)')) ++ except Exception as e: ++ raise errors.ConversionError( ++ name='params', ++ error=str(e)) ++ ++ def _repr_iter(self, **params): ++ """ ++ Iterate through the request and use the Command _repr_intr so ++ that sensitive information (passwords) is not exposed. ++ ++ In case of a malformatted request redact the entire thing. ++ """ ++ exceptions = False ++ for arg in (params.get('methods', [])): ++ try: ++ self._validate_request(arg) ++ except Exception: ++ # redact the whole request since we don't know what's in it ++ exceptions = True ++ yield u'********' ++ continue ++ ++ name = arg['method'] ++ a, kw = arg['params'] ++ newkw = dict((str(k), v) for k, v in kw.items()) ++ param = api.Command[name].args_options_2_params( ++ *a, **newkw) ++ ++ yield '{}({})'.format( ++ api.Command[name].name, ++ ', '.join(api.Command[name]._repr_iter(**param)) ++ ) ++ ++ if exceptions: ++ logger.debug('batch: %s', ++ ', '.join(super(batch, self)._repr_iter(**params))) ++ + def execute(self, methods=None, **options): + results = [] + for arg in (methods or []): + params = dict() + name = None + try: +- if 'method' not in arg: +- raise errors.RequirementError(name='method') +- if 'params' not in arg: +- raise errors.RequirementError(name='params') ++ self._validate_request(arg) + name = arg['method'] +- if (name not in self.api.Command or +- isinstance(self.api.Command[name], Local)): +- raise errors.CommandError(name=name) +- +- # If params are not formated as a tuple(list, dict) +- # the following lines will raise an exception +- # that triggers an internal server error +- # Raise a ConversionError instead to report the issue +- # to the client +- try: +- a, kw = arg['params'] +- newkw = dict((str(k), v) for k, v in kw.items()) +- params = api.Command[name].args_options_2_params( +- *a, **newkw) +- except (AttributeError, ValueError, TypeError): +- raise errors.ConversionError( +- name='params', +- error=_(u'must contain a tuple (list, dict)')) ++ a, kw = arg['params'] ++ newkw = dict((str(k), v) for k, v in kw.items()) ++ params = api.Command[name].args_options_2_params( ++ *a, **newkw) + newkw.setdefault('version', options['version']) + + result = api.Command[name](*a, **newkw) +@@ -132,8 +179,9 @@ class batch(Command): + ) + result['error']=None + except Exception as e: +- if isinstance(e, errors.RequirementError) or \ +- isinstance(e, errors.CommandError): ++ if (isinstance(e, errors.RequirementError) or ++ isinstance(e, errors.CommandError) or ++ isinstance(e, errors.ConversionError)): + logger.info( + '%s: batch: %s', + context.principal, # pylint: disable=no-member +-- +2.23.0 + diff --git a/SOURCES/0028-Test-replica-installation-from-hidden-replica.patch b/SOURCES/0028-Test-replica-installation-from-hidden-replica.patch deleted file mode 100644 index 35e9db8..0000000 --- a/SOURCES/0028-Test-replica-installation-from-hidden-replica.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 4850c91e063ddc0968a451ba9654c587f29a73d8 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Tue, 26 Mar 2019 16:43:55 +0100 -Subject: [PATCH] Test replica installation from hidden replica - -Exercise ipa-replica-install with a hidden replica as source server and -creation of replication agreements between a hidden and an enabled -replica. - -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - ipatests/pytest_ipa/integration/tasks.py | 22 ++++-- - .../test_replica_promotion.py | 73 +++++++++++++++---- - 2 files changed, 74 insertions(+), 21 deletions(-) - -diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py -index 1f0509189d2e3b3ad7402dd042d61e4ad4f97ed5..46506e4eee09dd1981777c8facef7c1938e07605 100644 ---- a/ipatests/pytest_ipa/integration/tasks.py -+++ b/ipatests/pytest_ipa/integration/tasks.py -@@ -691,28 +691,38 @@ def sync_time(host, server): - host.run_command(['ntpdate', server.hostname]) - - --def connect_replica(master, replica, domain_level=None): -+def connect_replica(master, replica, domain_level=None, -+ database=DOMAIN_SUFFIX_NAME): - if domain_level is None: - domain_level = master.config.domain_level - if domain_level == DOMAIN_LEVEL_0: -- replica.run_command(['ipa-replica-manage', 'connect', master.hostname]) -+ if database == DOMAIN_SUFFIX_NAME: -+ cmd = 'ipa-replica-manage' -+ else: -+ cmd = 'ipa-csreplica-manage' -+ replica.run_command([cmd, 'connect', master.hostname]) - else: - kinit_admin(master) -- master.run_command(["ipa", "topologysegment-add", DOMAIN_SUFFIX_NAME, -+ master.run_command(["ipa", "topologysegment-add", database, - "%s-to-%s" % (master.hostname, replica.hostname), - "--leftnode=%s" % master.hostname, - "--rightnode=%s" % replica.hostname - ]) - - --def disconnect_replica(master, replica, domain_level=None): -+def disconnect_replica(master, replica, domain_level=None, -+ database=DOMAIN_SUFFIX_NAME): - if domain_level is None: - domain_level = master.config.domain_level - if domain_level == DOMAIN_LEVEL_0: -- replica.run_command(['ipa-replica-manage', 'disconnect', master.hostname]) -+ if database == DOMAIN_SUFFIX_NAME: -+ cmd = 'ipa-replica-manage' -+ else: -+ cmd = 'ipa-csreplica-manage' -+ replica.run_command([cmd, 'disconnect', master.hostname]) - else: - kinit_admin(master) -- master.run_command(["ipa", "topologysegment-del", DOMAIN_SUFFIX_NAME, -+ master.run_command(["ipa", "topologysegment-del", database, - "%s-to-%s" % (master.hostname, replica.hostname), - "--continue" - ]) -diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py -index df71972a2ba3ad503011a558295bd38f587faf44..f9cc3d833072666fed348795c414e3840615ac70 100644 ---- a/ipatests/test_integration/test_replica_promotion.py -+++ b/ipatests/test_integration/test_replica_promotion.py -@@ -15,7 +15,8 @@ from ipatests.pytest_ipa.integration.tasks import ( - assert_error, replicas_cleanup) - from ipatests.pytest_ipa.integration.env_config import get_global_config - from ipalib.constants import ( -- DOMAIN_LEVEL_0, DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, IPA_CA_NICKNAME) -+ DOMAIN_LEVEL_0, DOMAIN_LEVEL_1, DOMAIN_SUFFIX_NAME, IPA_CA_NICKNAME, -+ CA_SUFFIX_NAME) - from ipaplatform.paths import paths - from ipatests.test_integration.test_backup_and_restore import backup - from ipatests.test_integration.test_dns_locations import ( -@@ -807,8 +808,8 @@ class TestReplicaInForwardZone(IntegrationTest): - class TestHiddenReplicaPromotion(IntegrationTest): - """Test hidden replica features - """ -- topology = 'star' -- num_replicas = 1 -+ topology = None -+ num_replicas = 2 - - @classmethod - def install(cls, mh): -@@ -850,8 +851,12 @@ class TestHiddenReplicaPromotion(IntegrationTest): - value = host.hostname if rtype == 'SRV' else host.ip - assert value not in txt - -- def _check_server_role(self, host, status): -- roles = [u'IPA master', u'CA server', u'KRA server', u'DNS server'] -+ def _check_server_role(self, host, status, kra=True, dns=True): -+ roles = [u'IPA master', u'CA server'] -+ if kra: -+ roles.append(u'KRA server') -+ if dns: -+ roles.append(u'DNS server') - for role in roles: - result = self.replicas[0].run_command([ - 'ipa', 'server-role-find', -@@ -936,6 +941,52 @@ class TestHiddenReplicaPromotion(IntegrationTest): - self._check_server_role(self.replicas[0], 'hidden') - self._check_dnsrecords([self.master], [self.replicas[0]]) - -+ def test_replica_from_hidden(self): -+ # install a replica from a hidden replica -+ self._check_server_role(self.replicas[0], 'hidden') -+ tasks.install_replica( -+ master=self.replicas[0], -+ replica=self.replicas[1], -+ setup_dns=True -+ ) -+ self._check_server_role(self.replicas[0], 'hidden') -+ self._check_server_role( -+ self.replicas[1], 'enabled', kra=False, dns=False -+ ) -+ self._check_dnsrecords( -+ [self.master, self.replicas[1]], [self.replicas[0]] -+ ) -+ # hide the new replica -+ self.replicas[0].run_command([ -+ 'ipa', 'server-state', -+ self.replicas[1].hostname, '--state=hidden' -+ ]) -+ # and establish replication agreements from master -+ tasks.connect_replica( -+ master=self.master, -+ replica=self.replicas[1], -+ ) -+ tasks.connect_replica( -+ master=self.master, -+ replica=self.replicas[1], -+ database=CA_SUFFIX_NAME, -+ ) -+ # remove replication agreements again -+ tasks.disconnect_replica( -+ master=self.master, -+ replica=self.replicas[1], -+ ) -+ tasks.disconnect_replica( -+ master=self.master, -+ replica=self.replicas[1], -+ database=CA_SUFFIX_NAME, -+ ) -+ # and uninstall -+ tasks.uninstall_replica( -+ master=self.replicas[0], -+ replica=self.replicas[1], -+ ) -+ - def test_hidden_replica_backup_and_restore(self): - """Exercises backup+restore and hidden replica uninstall - """ -@@ -950,19 +1001,11 @@ class TestHiddenReplicaPromotion(IntegrationTest): - ['ipa-restore', backup_path], - stdin_text=dirman_password + '\nyes' - ) -+ - # give replication some time - time.sleep(5) -- -- # check that role is still hidden - tasks.kinit_admin(self.replicas[0]) -- self._check_config([self.master], [self.replicas[0]]) -- self._check_server_role(self.replicas[0], 'hidden') -- self._check_dnsrecords([self.master], [self.replicas[0]]) - -- # check that the resulting server can be promoted to enabled -- self.replicas[0].run_command([ -- 'ipa', 'server-mod', self.replicas[0].hostname, '--state=enabled' -- ]) -+ # FIXME: restore turns hidden replica into enabled replica - self._check_config([self.master, self.replicas[0]]) - self._check_server_role(self.replicas[0], 'enabled') -- self._check_dnsrecords([self.master, self.replicas[0]]) --- -2.20.1 - diff --git a/SOURCES/0029-Add-design-draft.patch b/SOURCES/0029-Add-design-draft.patch deleted file mode 100644 index 6dff1da..0000000 --- a/SOURCES/0029-Add-design-draft.patch +++ /dev/null @@ -1,179 +0,0 @@ -From 451eb489193538c9ead259919669b3ca3658cbd8 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Tue, 26 Mar 2019 16:45:02 +0100 -Subject: [PATCH] Add design draft - -The design draft explains implementation details, limitations, and API -changes for the new feature. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - doc/designs/hidden-replicas.md | 153 +++++++++++++++++++++++++++++++++ - 1 file changed, 153 insertions(+) - create mode 100644 doc/designs/hidden-replicas.md - -diff --git a/doc/designs/hidden-replicas.md b/doc/designs/hidden-replicas.md -new file mode 100644 -index 0000000000000000000000000000000000000000..1abc73612cbf2e5636d7076b5c6f50eb0ecbce4c ---- /dev/null -+++ b/doc/designs/hidden-replicas.md -@@ -0,0 +1,153 @@ -+# Hidden replicas -+ -+**TECH PREVIEW** -+ -+## Overview -+ -+A hidden replica is an IPA master server that is not advertised to -+clients or other masters. Hidden replicas have all services running -+and available, but none of the services has any DNS SRV records or -+enabled LDAP server roles. This makes hidden replicas invisible for -+service discovery. -+ -+* IPA clients and SSSD ignore hidden replicas and don't consider them -+ during installation or daily operations. -+* Kerberos clients with ``dns_lookup_kdc = True`` do not auto-discover -+ hidden replicas. -+* Certmonger does not use a hidden replica to renew certificates. -+* Masters without a CA or KRA instance never use CA or KRA services -+ of a hidden replica. -+ -+By default, only services on a hidden replica use other services on -+the same machine, e.g. local LDAP and Kerberos services. -+ -+## Limitations -+ -+It's critical to understand that hidden replicas have limitations. Most -+importantly, hidden replicas are just concealed, but not isolated and -+secluded. Other machines merely don't see hidden replicas, when they -+use standard mechanisms to discover IPA servers. Other machines are -+able to find hidden replicas if they know what to look for. Any machine -+is able to use services on a hidden replica, when they are explicitly -+configured to do so. -+ -+* Hidden replicas are neither firewalled nor do they have any ACLs in -+ place to prevent connections from other machines. All IPA TCP and -+ UDP ports must be open for at least all other IPA servers. -+* There must be at least one regular, non-hidden server available and -+ online for each service (IPA master, DNS, CA, KRA). If DNS locations -+ are used, there should be at least one regular replica in each -+ location. -+* As of now, a hidden replica cannot be a *CA renewal master* or -+ a *DNSSEC key master*. The restriction may be lifted in the future. -+* Hard-coded server names and explicit configurations like -+ ``ipa-client-install --server=$HOST``, SSSD config, or ``ca_host`` -+ setting in ``/etc/ipa/default.conf`` override auto-discovery. -+* The process of demoting a regular replica to hidden replica or -+ promotion from hidden to regular replica is not instantaneous. It -+ takes a while until the changes have been replicated and cached -+ settings are refreshed. -+ -+## Use Cases -+ -+Hidden replicas are primarily designed for dedicated services that may -+otherwise disrupt clients. For example a full backup requires a -+complete shutdown of all IPA services. Since a hidden replica is not -+used by any clients by default, a temporary shutdown does not affect -+clients. -+ -+Other use cases include operations that put a high load on the IPA -+API or LDAP server, like mass imports or extensive queries. -+ -+## How to Use -+ -+### installation of a hidden replica -+ -+A new hidden replica can be installed with -+``ipa-replica-install --hidden-replica``. -+ -+### demotion / promotion of hidden replicas -+ -+A new command ``ipa server-state`` can be used to modify the state of a -+replica. An existing replica can be demoted to a hidden replica by -+executing ``ipa server-state $HOST --state=hidden``. The command -+``ipa server-state $HOST --state=enable`` turns a hidden replica -+into an enabled, visible replica. -+ -+A *CA renewal master* or *DNSSEC key master* can't be demoted to hidden -+replica. First the services must be moved to another replica with -+``ipa-dns-install --dnssec-master`` and -+``ipa config-mod --ca-renewal-master-server=$HOST``. -+ -+### query status -+ -+The ``ipa config-show`` command now shows additional information about -+DNS and KRA as well as hidden servers: -+ -+``` -+$ ipa config-show -+ ... -+ IPA masters: server1.ipa.example -+ Hidden IPA masters: hidden1.ipa.example -+ IPA master capable of PKINIT: hidden1.ipa.example, server1.ipa.example -+ IPA CA servers: server1.ipa.example -+ Hidden IPA CA servers: hidden1.ipa.example -+ IPA CA renewal master: server1.ipa.example -+ IPA KRA servers: server1.ipa.example -+ Hidden IPA KRA servers: hidden1.ipa.example -+ IPA DNS servers: server1.ipa.example -+ Hidden IPA DNS servers: hidden1.ipa.example -+ IPA DNSSec key master: server1.ipa.example -+$ ipa server-role-find --server=hidden1.ipa.example --include-master -+---------------------- -+6 server roles matched -+---------------------- -+ Server name: hidden1.ipa.example -+ Role name: AD trust agent -+ Role status: absent -+ -+ Server name: hidden1.ipa.example -+ Role name: AD trust controller -+ Role status: absent -+ -+ Server name: hidden1.ipa.example -+ Role name: CA server -+ Role status: hidden -+ -+ Server name: hidden1.ipa.example -+ Role name: DNS server -+ Role status: hidden -+ -+ Server name: hidden1.ipa.example -+ Role name: IPA master -+ Role status: hidden -+ -+ Server name: hidden1.ipa.example -+ Role name: KRA server -+ Role status: hidden -+---------------------------- -+Number of entries returned 6 -+---------------------------- -+``` -+ -+## Implementation -+ -+The status of a service is stored in LDAP inside the -+``cn=masters,cn=ipa,cn=etc,$SUFFIX`` subtree. The subtree contains -+entries for each IPA master. Each entry holds a bunch of sub entries -+for services. For example -+``cn=CA,cn=hidden1.ipa.example,cn=masters,cn=ipa,cn=etc,$SUFFIX`` is -+the container for the *CA* service on the IPA master -+*hidden1.ipa.example*. During the installation process the service -+entries are created with multi-valued attribute ``ipaConfigString`` -+set to ``configuredService``. At the end of the installation, -+``configuredService`` is either replaced with ``enabledService`` for a -+standard, enabled, and visible replica. Or it is set to -+``hiddenService`` for hidden, unadvertised replicas. -+ -+Auto-discovery ignores any and all hidden services. The -+``dns-update-system-records`` does not create SRV records for hidden -+services. The ``find_providing_servers`` API ignores hidden services -+except for preferred hosts. CA and KRA service discovery use the -+current host or explicit ``ca_host`` option from -+``/etc/ipa/default.conf`` as preferred host. --- -2.20.1 - diff --git a/SOURCES/0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch b/SOURCES/0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch new file mode 100644 index 0000000..422aaed --- /dev/null +++ b/SOURCES/0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch @@ -0,0 +1,110 @@ +From 4fd15ef7c4059e8010e54b014795f20ba459fc3f Mon Sep 17 00:00:00 2001 +From: Florence Blanc-Renaud +Date: Tue, 3 Dec 2019 12:56:22 +0100 +Subject: [PATCH] trust upgrade: ensure that host is member of adtrust agents + +After an upgrade, the group cn=adtrust agents may be missing some members. +Each ad trust controller must appear twice as member: +- krbprincipalname=cifs/hostname@realm,cn=services,cn=accounts,basedn +- fqdn=hostname,cn=computers,cn=accounts,basedn + +Add an upgrade plugin that builds a list of hostnames from the cifs +principals and adds if needed fqdn=hostname... + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1778777 +Signed-off-by: Florence Blanc-Renaud +Reviewed-By: Alexander Bokovoy +Reviewed-By: Alexander Bokovoy +--- + .../updates/90-post_upgrade_plugins.update | 1 + + ipaserver/install/plugins/adtrust.py | 55 +++++++++++++++++++ + 2 files changed, 56 insertions(+) + +diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update +index e3afb3423ccaf1598bc0a0e982a5264781fd81a4..4ba8b845276c60c719fe8fcef9c457aa2deba61f 100644 +--- a/install/updates/90-post_upgrade_plugins.update ++++ b/install/updates/90-post_upgrade_plugins.update +@@ -13,6 +13,7 @@ plugin: update_default_trust_view + plugin: update_tdo_gidnumber + plugin: update_tdo_to_new_layout + plugin: update_tdo_default_read_keys_permissions ++plugin: update_adtrust_agents_members + 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 c0de12eca903a6635f4b53b0806a0ba07170b7c6..dd6c25e9f14b161bda3bce5cc8ed260fae109db4 100644 +--- a/ipaserver/install/plugins/adtrust.py ++++ b/ipaserver/install/plugins/adtrust.py +@@ -8,9 +8,11 @@ from ipalib import Updater + from ipapython.dn import DN + from ipapython import ipautil + from ipaplatform.paths import paths ++from ipaserver.install import service + from ipaserver.install import sysupgrade + from ipaserver.install.adtrustinstance import ( + ADTRUSTInstance, map_Guests_to_nobody) ++ + from ipaserver.dcerpc_common import TRUST_BIDIRECTIONAL + + try: +@@ -791,3 +793,56 @@ class update_tdo_default_read_keys_permissions(Updater): + tdo.single_value.get('krbCanonicalName')) + + return False, [] ++ ++ ++@register() ++class update_adtrust_agents_members(Updater): ++ """ Ensure that each adtrust agent is a member of the adtrust agents group ++ ++ cn=adtrust agents,cn=sysaccounts,cn=etc,$BASEDN must contain: ++ - member: krbprincipalname=cifs/master@realm,cn=services,cn=accounts,base ++ - member: fqdn=master,cn=computers,cn=accounts,base ++ """ ++ 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']: ++ logger.debug('AD Trusts are not enabled on this server') ++ return False, [] ++ ++ agents_dn = DN( ++ ('cn', 'adtrust agents'), ('cn', 'sysaccounts'), ++ ('cn', 'etc'), self.api.env.basedn) ++ ++ try: ++ agents_entry = ldap.get_entry(agents_dn, ['member']) ++ except errors.NotFound: ++ logger.error("No adtrust agents group found") ++ return False, [] ++ ++ # Build a list of agents from the cifs/.. members ++ agents_list = [] ++ members = agents_entry.get('member', []) ++ suffix = '@{}'.format(self.api.env.realm).lower() ++ ++ for amember in members: ++ if amember[0].attr.lower() == 'krbprincipalname': ++ # Extract krbprincipalname=cifs/hostname@realm from the DN ++ value = amember[0].value ++ if (value.lower().startswith('cifs/') and ++ value.lower().endswith(suffix)): ++ # 5 = length of 'cifs/' ++ hostname = value[5:-len(suffix)] ++ agents_list.append(DN(('fqdn', hostname), ++ self.api.env.container_host, ++ self.api.env.basedn)) ++ ++ # Add the fqdn=hostname... to the group ++ service.add_principals_to_group( ++ ldap, ++ agents_dn, ++ "member", ++ agents_list) ++ ++ return False, [] +-- +2.23.0 + diff --git a/SOURCES/0030-Don-t-fail-if-config-show-does-not-return-servers.patch b/SOURCES/0030-Don-t-fail-if-config-show-does-not-return-servers.patch deleted file mode 100644 index 3358ee3..0000000 --- a/SOURCES/0030-Don-t-fail-if-config-show-does-not-return-servers.patch +++ /dev/null @@ -1,60 +0,0 @@ -From a9b0d9b109d0f35adbf45ef8d158f276014c7c8b Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Tue, 26 Mar 2019 20:09:27 +0100 -Subject: [PATCH] Don't fail if config-show does not return servers - -When uninstalling a cluster and only hidden servers are left, -config-show can return a result set without ipa_master_server entry. - -Fixes: https://pagure.io/freeipa/issue/7892 -Signed-off-by: Christian Heimes -Reviewed-By: Thomas Woerner -Reviewed-By: Francois Cami ---- - ipaserver/install/ca.py | 2 +- - ipaserver/plugins/pkinit.py | 2 +- - ipaserver/plugins/server.py | 2 +- - 3 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py -index 716f3b3dc1fc81438b74d4fa393f7f17d6d2a802..09b3c09e758775de77cdf4ac5cae755183aa8f8c 100644 ---- a/ipaserver/install/ca.py -+++ b/ipaserver/install/ca.py -@@ -106,7 +106,7 @@ def uninstall_check(options): - - # skip the checks if the host is the last master - ipa_config = api.Command.config_show()['result'] -- ipa_masters = ipa_config['ipa_master_server'] -+ ipa_masters = ipa_config.get('ipa_master_server', []) - if len(ipa_masters) <= 1: - return - -diff --git a/ipaserver/plugins/pkinit.py b/ipaserver/plugins/pkinit.py -index 8853938460073f69f6e6242c5ae5c362b3faf4f7..6d42a9af11f2079054e59416f3930fbae5b65555 100644 ---- a/ipaserver/plugins/pkinit.py -+++ b/ipaserver/plugins/pkinit.py -@@ -91,7 +91,7 @@ class pkinit_status(Search): - if server is not None: - servers = [server] - else: -- servers = ipa_master_config['ipa_master_server'] -+ servers = ipa_master_config.get('ipa_master_server', []) - - pkinit_servers = ipa_master_config.get('pkinit_server_server') - if pkinit_servers is None: -diff --git a/ipaserver/plugins/server.py b/ipaserver/plugins/server.py -index bfd1406ff826aea97195aa08ca35018e35cac18c..ee9c2ba7440dce276213bb97eaca621e1ef33efe 100644 ---- a/ipaserver/plugins/server.py -+++ b/ipaserver/plugins/server.py -@@ -482,7 +482,7 @@ class server_del(LDAPDelete): - - ipa_config = self.api.Command.config_show()['result'] - -- ipa_masters = ipa_config['ipa_master_server'] -+ ipa_masters = ipa_config.get('ipa_master_server', []) - - # skip these checks if the last master is being removed - if len(ipa_masters) <= 1: --- -2.20.1 - diff --git a/SOURCES/0031-Extract-ca_renewal-cert-update-subroutine.patch b/SOURCES/0031-Extract-ca_renewal-cert-update-subroutine.patch deleted file mode 100644 index 8044f47..0000000 --- a/SOURCES/0031-Extract-ca_renewal-cert-update-subroutine.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 474c13d1543608c8c4da06957295215bbcd5b67c Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Fri, 22 Mar 2019 13:37:45 +1100 -Subject: [PATCH] Extract ca_renewal cert update subroutine - -When the CA renewal master renews certificates that are shared -across CA replicas, it puts them in LDAP for the other CA replicas -to see. The code to create/update these entries lives in the -dogtag-ipa-ca-renew-agent renewal helper, but it will be useful for -the ipa-cert-fix program too. Extract it to a subroutine in the -cainstance module. - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - .../dogtag-ipa-ca-renew-agent-submit | 16 +----------- - ipaserver/install/cainstance.py | 26 +++++++++++++++++++ - 2 files changed, 27 insertions(+), 15 deletions(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index c33404c18c0022af6b801d25cac1eb0bec019cdf..c2ba9cb842ba835948925a8e415d1e25fe8ee139 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -270,23 +270,9 @@ def store_cert(**kwargs): - return (REJECTED, "New certificate requests not supported") - cert = x509.load_pem_x509_certificate(cert.encode('ascii')) - -- dn = DN(('cn', nickname), ('cn', 'ca_renewal'), -- ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) - try: - with ldap_connect() as conn: -- try: -- entry = conn.get_entry(dn, ['usercertificate']) -- entry['usercertificate'] = [cert] -- conn.update_entry(entry) -- except errors.NotFound: -- entry = conn.make_entry( -- dn, -- objectclass=['top', 'pkiuser', 'nscontainer'], -- cn=[nickname], -- usercertificate=[cert]) -- conn.add_entry(entry) -- except errors.EmptyModlist: -- pass -+ cainstance.update_ca_renewal_entry(conn, nickname, cert) - except Exception as e: - attempts += 1 - if attempts < 10: -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 2946b5cc2b4b8b708a060aa79d1b7ab0e7b4e651..527ad0a1f492050d452336105cc5cf3c645af693 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1711,6 +1711,32 @@ def update_authority_entry(cert): - return __update_entry_from_cert(make_filter, make_entry, cert) - - -+def update_ca_renewal_entry(conn, nickname, cert): -+ """ -+ Update the ca_renewal entry for the given nickname. -+ -+ :param conn: A *connected* LDAP handle -+ :param nickname: NSSDB nickname -+ :param cert: python-cryptography X509Certificate -+ -+ """ -+ dn = DN(('cn', nickname), ('cn', 'ca_renewal'), -+ ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ try: -+ entry = conn.get_entry(dn, ['usercertificate']) -+ entry['usercertificate'] = [cert] -+ conn.update_entry(entry) -+ except errors.NotFound: -+ entry = conn.make_entry( -+ dn, -+ objectclass=['top', 'pkiuser', 'nscontainer'], -+ cn=[nickname], -+ usercertificate=[cert]) -+ conn.add_entry(entry) -+ except errors.EmptyModlist: -+ pass -+ -+ - def ensure_ldap_profiles_container(): - ensure_entry( - DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca')), --- -2.20.1 - diff --git a/SOURCES/0032-cainstance-add-function-to-determine-ca_renewal-nick.patch b/SOURCES/0032-cainstance-add-function-to-determine-ca_renewal-nick.patch deleted file mode 100644 index df1d189..0000000 --- a/SOURCES/0032-cainstance-add-function-to-determine-ca_renewal-nick.patch +++ /dev/null @@ -1,85 +0,0 @@ -From d868e27dfe7ab9955faebf0a08be3b41971bf816 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Fri, 22 Mar 2019 15:22:21 +1100 -Subject: [PATCH] cainstance: add function to determine ca_renewal nickname - -The ipa-cert-fix program needs to know where to put shared -certificates. Extract the logic that computes the nickname from -dogtag-ipa-ca-renew-agent to new subroutine -cainstance.get_ca_renewal_nickname(). - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - .../dogtag-ipa-ca-renew-agent-submit | 16 ++---------- - ipaserver/install/cainstance.py | 26 +++++++++++++++++++ - 2 files changed, 28 insertions(+), 14 deletions(-) - -diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -index c2ba9cb842ba835948925a8e415d1e25fe8ee139..31b4a1b7fc23567e91f8aa9938ce4e0941a84a8c 100755 ---- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit -+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit -@@ -85,20 +85,8 @@ def get_nickname(): - - ca_subject_dn = ca.lookup_ca_subject(api, subject_base) - -- nickname_by_subject_dn = { -- DN(ca_subject_dn): 'caSigningCert cert-pki-ca', -- DN('CN=CA Audit', subject_base): 'auditSigningCert cert-pki-ca', -- DN('CN=OCSP Subsystem', subject_base): 'ocspSigningCert cert-pki-ca', -- DN('CN=CA Subsystem', subject_base): 'subsystemCert cert-pki-ca', -- DN('CN=KRA Audit', subject_base): 'auditSigningCert cert-pki-kra', -- DN('CN=KRA Transport Certificate', subject_base): -- 'transportCert cert-pki-kra', -- DN('CN=KRA Storage Certificate', subject_base): -- 'storageCert cert-pki-kra', -- DN('CN=IPA RA', subject_base): 'ipaCert', -- } -- -- return nickname_by_subject_dn.get(DN(subject)) -+ return cainstance.get_ca_renewal_nickname( -+ subject_base, ca_subject_dn, DN(subject)) - - - def is_replicated(): -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index 527ad0a1f492050d452336105cc5cf3c645af693..b4f6262b2c41e2da7992c403154a476aa3b82dd1 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1711,6 +1711,32 @@ def update_authority_entry(cert): - return __update_entry_from_cert(make_filter, make_entry, cert) - - -+def get_ca_renewal_nickname(subject_base, ca_subject_dn, sdn): -+ """ -+ Get the nickname for storage in the cn_renewal container. -+ -+ :param subject_base: Certificate subject base -+ :param ca_subject_dn: IPA CA subject DN -+ :param sdn: Subject DN -+ :return: string, or None if nickname cannot be determined. -+ -+ """ -+ assert isinstance(sdn, DN) -+ nickname_by_subject_dn = { -+ DN(ca_subject_dn): 'caSigningCert cert-pki-ca', -+ DN('CN=CA Audit', subject_base): 'auditSigningCert cert-pki-ca', -+ DN('CN=OCSP Subsystem', subject_base): 'ocspSigningCert cert-pki-ca', -+ DN('CN=CA Subsystem', subject_base): 'subsystemCert cert-pki-ca', -+ DN('CN=KRA Audit', subject_base): 'auditSigningCert cert-pki-kra', -+ DN('CN=KRA Transport Certificate', subject_base): -+ 'transportCert cert-pki-kra', -+ DN('CN=KRA Storage Certificate', subject_base): -+ 'storageCert cert-pki-kra', -+ DN('CN=IPA RA', subject_base): 'ipaCert', -+ } -+ return nickname_by_subject_dn.get(sdn) -+ -+ - def update_ca_renewal_entry(conn, nickname, cert): - """ - Update the ca_renewal entry for the given nickname. --- -2.20.1 - diff --git a/SOURCES/0033-constants-add-ca_renewal-container.patch b/SOURCES/0033-constants-add-ca_renewal-container.patch deleted file mode 100644 index f0d798f..0000000 --- a/SOURCES/0033-constants-add-ca_renewal-container.patch +++ /dev/null @@ -1,42 +0,0 @@ -From dc96bc41bbff6b0f596649e992df53734278e24f Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Tue, 26 Mar 2019 19:43:25 +1100 -Subject: [PATCH] constants: add ca_renewal container - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - ipalib/constants.py | 1 + - ipaserver/install/cainstance.py | 3 +-- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipalib/constants.py b/ipalib/constants.py -index 7ff9c6aed32debd609db2650420994aa32e2466c..678a708aa19b682046b570fdce1804ea58865c88 100644 ---- a/ipalib/constants.py -+++ b/ipalib/constants.py -@@ -129,6 +129,7 @@ DEFAULT_CONFIG = ( - ('container_sysaccounts', DN(('cn', 'sysaccounts'), ('cn', 'etc'))), - ('container_certmap', DN(('cn', 'certmap'))), - ('container_certmaprules', DN(('cn', 'certmaprules'), ('cn', 'certmap'))), -+ ('container_ca_renewal', DN(('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'))), - - # Ports, hosts, and URIs: - # Following values do not have any reasonable default. -diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py -index b4f6262b2c41e2da7992c403154a476aa3b82dd1..1f22d120478a6d4019663281d3191a27a5ee09ea 100644 ---- a/ipaserver/install/cainstance.py -+++ b/ipaserver/install/cainstance.py -@@ -1746,8 +1746,7 @@ def update_ca_renewal_entry(conn, nickname, cert): - :param cert: python-cryptography X509Certificate - - """ -- dn = DN(('cn', nickname), ('cn', 'ca_renewal'), -- ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) -+ dn = DN(('cn', nickname), api.env.container_ca_renewal, api.env.basedn) - try: - entry = conn.get_entry(dn, ['usercertificate']) - entry['usercertificate'] = [cert] --- -2.20.1 - diff --git a/SOURCES/0034-Add-ipa-cert-fix-tool.patch b/SOURCES/0034-Add-ipa-cert-fix-tool.patch deleted file mode 100644 index bfd021b..0000000 --- a/SOURCES/0034-Add-ipa-cert-fix-tool.patch +++ /dev/null @@ -1,363 +0,0 @@ -From 0a65f076441cfbbf659e109ea6de026504261dba Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Fri, 22 Mar 2019 16:53:53 +1100 -Subject: [PATCH] Add ipa-cert-fix tool - -The ipa-cert-fix tool wraps `pki-server cert-fix`, performing -additional certificate requests for non-Dogtag IPA certificates and -performing additional actions. In particular: - -- Run cert-fix with arguments particular to the IPA deployment. - -- Update IPA RA certificate in the ipara user entry (if renewed). - -- Add shared certificates (if renewed) to the ca_renewal LDAP - container for replication. - -- Become the CA renewal master if shared certificates were renewed. - This ensures other CA replicas, including the previous CA renewal - master if not the current host, pick up those new certificates - when Certmonger attempts to renew them. - -Fixes: https://pagure.io/freeipa/issue/7885 -Reviewed-By: Florence Blanc-Renaud ---- - freeipa.spec.in | 2 + - install/tools/Makefile.am | 1 + - install/tools/ipa-cert-fix | 8 + - ipaserver/install/ipa_cert_fix.py | 276 ++++++++++++++++++++++++++++++ - 4 files changed, 287 insertions(+) - create mode 100755 install/tools/ipa-cert-fix - create mode 100644 ipaserver/install/ipa_cert_fix.py - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 34394b5caa811bffc677da9644120c90a09b1e81..775394619ab0eb682935c0d28fe434bcf8248a01 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -995,6 +995,7 @@ install/tools/ipa-adtrust-install - install/tools/ipa-backup - install/tools/ipa-ca-install - install/tools/ipa-cacert-manage -+install/tools/ipa-cert-fix - install/tools/ipa-compat-manage - install/tools/ipa-crlgen-manage - install/tools/ipa-csreplica-manage -@@ -1383,6 +1384,7 @@ fi - %{_sbindir}/ipa-winsync-migrate - %{_sbindir}/ipa-pkinit-manage - %{_sbindir}/ipa-crlgen-manage -+%{_sbindir}/ipa-cert-fix - %{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit - %{_libexecdir}/certmonger/ipa-server-guard - %dir %{_libexecdir}/ipa -diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am -index 9dcd76762f678684b421ce4a7b7b27e673a3ff94..6cdfd109552bff2effbcfabe77ff8bf44c1c60da 100644 ---- a/install/tools/Makefile.am -+++ b/install/tools/Makefile.am -@@ -30,6 +30,7 @@ dist_sbin_SCRIPTS = \ - ipa-winsync-migrate \ - ipa-pkinit-manage \ - ipa-crlgen-manage \ -+ ipa-cert-fix \ - $(NULL) - - appdir = $(libexecdir)/ipa/ -diff --git a/install/tools/ipa-cert-fix b/install/tools/ipa-cert-fix -new file mode 100755 -index 0000000000000000000000000000000000000000..e1fc6f056a2a02ee350a2b09433be6cef46e514a ---- /dev/null -+++ b/install/tools/ipa-cert-fix -@@ -0,0 +1,8 @@ -+#! /usr/bin/python2 -E -+# -+# Copyright (C) 2019 FreeIPA Contributors see COPYING for license -+# -+ -+from ipaserver.install.ipa_cert_fix import IPACertFix -+ -+IPACertFix.run_cli() -diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py -new file mode 100644 -index 0000000000000000000000000000000000000000..3d9070eac1e7dc03840215dffeb4d73f4d3d0a47 ---- /dev/null -+++ b/ipaserver/install/ipa_cert_fix.py -@@ -0,0 +1,276 @@ -+# -+# Copyright (C) 2019 FreeIPA Contributors see COPYING for license -+# -+ -+# ipa-cert-fix performs the following steps: -+# -+# 1. Confirm running as root (AdminTool.validate_options does this) -+# -+# 2. Confirm that DS is up. -+# -+# 3. Determine which of following certs (if any) need renewing -+# - IPA RA -+# - Apache HTTPS -+# - 389 LDAPS -+# - Kerberos KDC (PKINIT) -+# -+# 4. Execute `pki-server cert-fix` with relevant options, -+# including `--extra-cert SERIAL` for each cert from #3. -+# -+# 5. Print details of renewed certificates. -+# -+# 6. Install renewed certs from #3 in relevant places -+# -+# 7. ipactl restart -+ -+from __future__ import print_function, absolute_import -+ -+import datetime -+from enum import Enum -+import logging -+import shutil -+ -+from ipalib import api -+from ipalib import x509 -+from ipaplatform.paths import paths -+from ipapython.admintool import AdminTool -+from ipapython.certdb import NSSDatabase, EMPTY_TRUST_FLAGS -+from ipapython.dn import DN -+from ipaserver.install import ca, cainstance, dsinstance, installutils -+from ipaserver.install.installutils import is_ipa_configured -+from ipapython import ipautil -+ -+msg = """ -+ WARNING -+ -+ipa-cert-fix is intended for recovery when expired certificates -+prevent the normal operation of FreeIPA. It should ONLY be used -+in such scenarios, and backup of the system, especially certificates -+and keys, is STRONGLY RECOMMENDED. -+ -+""" -+ -+logger = logging.getLogger(__name__) -+ -+ -+class IPACertType(Enum): -+ IPARA = "IPA RA" -+ HTTPS = "Apache HTTPS" -+ LDAPS = "LDAP" -+ KDC = "KDC" -+ -+ -+class IPACertFix(AdminTool): -+ command_name = "ipa-cert-fix" -+ usage = "%prog" -+ description = "Renew expired certificates." -+ -+ def validate_options(self): -+ super(IPACertFix, self).validate_options(needs_root=True) -+ -+ def run(self): -+ if not is_ipa_configured(): -+ print("IPA is not configured.") -+ return 0 # not really an error -+ -+ if not cainstance.is_ca_installed_locally(): -+ print("CA is not installed on this server.") -+ return 0 # not really an error -+ -+ try: -+ ipautil.run(['pki-server', 'cert-fix', '--help'], raiseonerr=True) -+ except ipautil.CalledProcessError: -+ print( -+ "The 'pki-server cert-fix' command is not available; " -+ "cannot proceed." -+ ) -+ return 1 -+ -+ api.bootstrap(in_server=True, confdir=paths.ETC_IPA) -+ api.finalize() -+ api.Backend.ldap2.connect() # ensure DS is up -+ -+ subject_base = dsinstance.DsInstance().find_subject_base() -+ if not subject_base: -+ raise RuntimeError("Cannot determine certificate subject base.") -+ -+ ca_subject_dn = ca.lookup_ca_subject(api, subject_base) -+ -+ now = datetime.datetime.now() + datetime.timedelta(weeks=2) -+ certs, extra_certs = expired_certs(now) -+ -+ if not certs and not extra_certs: -+ print("Nothing to do.") -+ return 0 -+ -+ print(msg) -+ -+ print_intentions(certs, extra_certs) -+ -+ response = ipautil.user_input('Enter "yes" to proceed') -+ if response.lower() != 'yes': -+ print("Not proceeding.") -+ return 0 -+ print("Proceeding.") -+ -+ run_cert_fix(certs, extra_certs) -+ -+ replicate_dogtag_certs(subject_base, ca_subject_dn, certs) -+ install_ipa_certs(subject_base, ca_subject_dn, extra_certs) -+ -+ if any(x != 'sslserver' for x in certs) \ -+ or any(x[0] is IPACertType.IPARA for x in extra_certs): -+ # we renewed a "shared" certificate, therefore we must -+ # become the renewal master -+ print("Becoming renewal master.") -+ cainstance.CAInstance().set_renewal_master() -+ -+ ipautil.run(['ipactl', 'restart'], raiseonerr=True) -+ -+ -+def expired_certs(now): -+ return expired_dogtag_certs(now), expired_ipa_certs(now) -+ -+ -+def expired_dogtag_certs(now): -+ """ -+ Determine which Dogtag certs are expired, or close to expiry. -+ -+ Return a list of (cert_id, cert) pairs. -+ -+ """ -+ certs = [] -+ db = NSSDatabase(nssdir=paths.PKI_TOMCAT_ALIAS_DIR) -+ -+ for certid, nickname in [ -+ ('sslserver', 'Server-Cert cert-pki-ca'), -+ ('subsystem', 'subsystemCert cert-pki-ca'), -+ ('ca_ocsp_signing', 'ocspSigningCert cert-pki-ca'), -+ ('ca_audit_signing', 'auditSigningCert cert-pki-ca'), -+ ('kra_transport', 'transportCert cert-pki-kra'), -+ ('kra_storage', 'storageCert cert-pki-kra'), -+ ('kra_audit_signing', 'auditSigningCert cert-pki-kra'), -+ ]: -+ try: -+ cert = db.get_cert(nickname) -+ except RuntimeError: -+ pass # unfortunately certdb doesn't give us a better exception -+ else: -+ if cert.not_valid_after <= now: -+ certs.append((certid, cert)) -+ -+ return certs -+ -+ -+def expired_ipa_certs(now): -+ """ -+ Determine which IPA certs are expired, or close to expiry. -+ -+ Return a list of (IPACertType, cert) pairs. -+ -+ """ -+ certs = [] -+ -+ # IPA RA -+ cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM) -+ if cert.not_valid_after <= now: -+ certs.append((IPACertType.IPARA, cert)) -+ -+ # Apache HTTPD -+ db = NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR) -+ cert = db.get_cert('Server-Cert') -+ if cert.not_valid_after <= now: -+ certs.append((IPACertType.HTTPS, cert)) -+ -+ # LDAPS -+ ds_dbdir = dsinstance.config_dirname( -+ installutils.realm_to_serverid(api.env.realm)) -+ db = NSSDatabase(nssdir=ds_dbdir) -+ cert = db.get_cert('Server-Cert') -+ if cert.not_valid_after <= now: -+ certs.append((IPACertType.LDAPS, cert)) -+ -+ # KDC -+ cert = x509.load_certificate_from_file(paths.KDC_CERT) -+ if cert.not_valid_after <= now: -+ certs.append((IPACertType.KDC, cert)) -+ -+ return certs -+ -+ -+def print_intentions(dogtag_certs, ipa_certs): -+ print("The following certificates will be renewed: ") -+ print() -+ -+ for certid, cert in dogtag_certs: -+ print_cert_info("Dogtag", certid, cert) -+ -+ for certtype, cert in ipa_certs: -+ print_cert_info("IPA", certtype.value, cert) -+ -+ -+def print_cert_info(context, desc, cert): -+ print("{} {} certificate:".format(context, desc)) -+ print(" Subject: {}".format(DN(cert.subject))) -+ print(" Serial: {}".format(cert.serial_number)) -+ print(" Expires: {}".format(cert.not_valid_after)) -+ print() -+ -+ -+def run_cert_fix(certs, extra_certs): -+ ldapi_path = ( -+ paths.SLAPD_INSTANCE_SOCKET_TEMPLATE -+ % '-'.join(api.env.realm.split('.')) -+ ) -+ cmd = [ -+ 'pki-server', -+ 'cert-fix', -+ '--ldapi-socket', ldapi_path, -+ '--agent-uid', 'ipara', -+ ] -+ for certid, _cert in certs: -+ cmd.extend(['--cert', certid]) -+ for _certtype, cert in extra_certs: -+ cmd.extend(['--extra-cert', str(cert.serial_number)]) -+ ipautil.run(cmd, raiseonerr=True) -+ -+ -+def replicate_dogtag_certs(subject_base, ca_subject_dn, certs): -+ for certid, _oldcert in certs: -+ cert_path = "/etc/pki/pki-tomcat/certs/{}.crt".format(certid) -+ cert = x509.load_certificate_from_file(cert_path) -+ print_cert_info("Renewed Dogtag", certid, cert) -+ replicate_cert(subject_base, ca_subject_dn, cert) -+ -+ -+def install_ipa_certs(subject_base, ca_subject_dn, certs): -+ """Print details and install renewed IPA certificates.""" -+ for certtype, oldcert in certs: -+ cert_path = "/etc/pki/pki-tomcat/certs/{}-renewed.crt" \ -+ .format(oldcert.serial_number) -+ cert = x509.load_certificate_from_file(cert_path) -+ print_cert_info("Renewed IPA", certtype.value, cert) -+ -+ if certtype is IPACertType.IPARA: -+ shutil.copyfile(cert_path, paths.RA_AGENT_PEM) -+ cainstance.update_people_entry(cert) -+ replicate_cert(subject_base, ca_subject_dn, cert) -+ elif certtype is IPACertType.HTTPS: -+ db = NSSDatabase(nssdir=paths.HTTPD_ALIAS_DIR) -+ db.delete_cert('Server-Cert') -+ db.import_pem_cert('Server-Cert', EMPTY_TRUST_FLAGS, cert_path) -+ elif certtype is IPACertType.LDAPS: -+ ds_dbdir = dsinstance.config_dirname( -+ installutils.realm_to_serverid(api.env.realm)) -+ db = NSSDatabase(nssdir=ds_dbdir) -+ db.delete_cert('Server-Cert') -+ db.import_pem_cert('Server-Cert', EMPTY_TRUST_FLAGS, cert_path) -+ elif certtype is IPACertType.KDC: -+ shutil.copyfile(cert_path, paths.KDC_CERT) -+ -+ -+def replicate_cert(subject_base, ca_subject_dn, cert): -+ nickname = cainstance.get_ca_renewal_nickname( -+ subject_base, ca_subject_dn, DN(cert.subject)) -+ if nickname: -+ cainstance.update_ca_renewal_entry(api.Backend.ldap2, nickname, cert) --- -2.20.1 - diff --git a/SOURCES/0035-ipa-cert-fix-add-man-page.patch b/SOURCES/0035-ipa-cert-fix-add-man-page.patch deleted file mode 100644 index c9cdcaf..0000000 --- a/SOURCES/0035-ipa-cert-fix-add-man-page.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 03e3540e74e7b6da68987574d65668c07d484396 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Mon, 25 Mar 2019 16:13:38 +1100 -Subject: [PATCH] ipa-cert-fix: add man page - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - freeipa.spec.in | 1 + - install/tools/man/Makefile.am | 1 + - install/tools/man/ipa-cert-fix.1 | 66 ++++++++++++++++++++++++++++++++ - 3 files changed, 68 insertions(+) - create mode 100644 install/tools/man/ipa-cert-fix.1 - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index 775394619ab0eb682935c0d28fe434bcf8248a01..a18a5b4aab335ad104f1263fa3ae8b26659c3095 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -1450,6 +1450,7 @@ fi - %{_mandir}/man1/ipa-winsync-migrate.1* - %{_mandir}/man1/ipa-pkinit-manage.1* - %{_mandir}/man1/ipa-crlgen-manage.1* -+%{_mandir}/man1/ipa-cert-fix.1* - - - %files -n python2-ipaserver -diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am -index 947e5c65f7d97734a320ee0a1979d7e890de6ed2..28fb57e87648d2a1a8904cc9d96921aa7e0f206e 100644 ---- a/install/tools/man/Makefile.am -+++ b/install/tools/man/Makefile.am -@@ -29,6 +29,7 @@ dist_man1_MANS = \ - ipa-winsync-migrate.1 \ - ipa-pkinit-manage.1 \ - ipa-crlgen-manage.1 \ -+ ipa-cert-fix.1 \ - $(NULL) - - dist_man8_MANS = \ -diff --git a/install/tools/man/ipa-cert-fix.1 b/install/tools/man/ipa-cert-fix.1 -new file mode 100644 -index 0000000000000000000000000000000000000000..3edef3118947d203d8972994d0d880850302a348 ---- /dev/null -+++ b/install/tools/man/ipa-cert-fix.1 -@@ -0,0 +1,66 @@ -+.\" -+.\" Copyright (C) 2019 FreeIPA Contributors see COPYING for license -+.\" -+.TH "ipa-cert-fix" "1" "Mar 25 2019" "FreeIPA" "FreeIPA Manual Pages" -+.SH "NAME" -+ipa\-cert\-fix \- Renew expired certificates -+.SH "SYNOPSIS" -+ipa\-cert\-fix [options] -+.SH "DESCRIPTION" -+ -+\fIipa-cert-fix\fR is a tool for recovery when expired certificates -+prevent the normal operation of FreeIPA. It should ONLY be used in -+such scenarios, and backup of the system, especially certificates -+and keys, is \fBSTRONGLY RECOMMENDED\fR. -+ -+Do not use this program unless expired certificates are inhibiting -+normal operation and renewal procedures. -+ -+To renew the IPA CA certificate, use \fIipa-cacert-manage(1)\fR. -+ -+This tool cannot renew certificates signed by external CAs. To -+install new, externally-signed HTTP, LDAP or KDC certificates, use -+\fIipa-server-certinstall(1)\fR. -+ -+\fIipa-cert-fix\fR will examine FreeIPA and Certificate System -+certificates and renew certificates that are expired, or close to -+expiry (less than two weeks). If any "shared" certificates are -+renewed, \fIipa-cert-fix\fR will set the current server to be the CA -+renewal master, and add the new shared certificate(s) to LDAP for -+replication to other CA servers. Shared certificates include all -+Dogtag system certificates except the HTTPS certificate, and the IPA -+RA certificate. -+ -+To repair certificates across multiple CA servers, first ensure that -+LDAP replication is working across the topology. Then run -+\fIipa-cert-fix\fR on one CA server. Before running -+\fIipa-cert-fix\fR on another CA server, trigger Certmonger renewals -+for shared certificates via \fIgetcert-resubmit(1)\fR (on the other -+CA server). This is to avoid unnecessary renewal of shared -+certificates. -+ -+.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 (output from child processes may still be shown). -+.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 -+ -+.SH "SEE ALSO" -+.BR ipa-cacert-manage(1) -+.BR ipa-server-certinstall(1) -+.BR getcert-resubmit(1) --- -2.20.1 - diff --git a/SOURCES/0036-ipa-cert-fix-use-customary-exit-statuses.patch b/SOURCES/0036-ipa-cert-fix-use-customary-exit-statuses.patch deleted file mode 100644 index c09450c..0000000 --- a/SOURCES/0036-ipa-cert-fix-use-customary-exit-statuses.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8bbec6c72b759767bc19681aab9c3d3d9f091b6a Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Fri, 29 Mar 2019 16:04:20 +1100 -Subject: [PATCH] ipa-cert-fix: use customary exit statuses - -It is customary to return 2 when IPA is not configured, and 1 when -other required bits are not installed or configured. Update -ipa-cert-fix exit statuses accordingly. - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/ipa_cert_fix.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py -index 3d9070eac1e7dc03840215dffeb4d73f4d3d0a47..c8ee51faea9092350c8a182ba55387ddd7b196d8 100644 ---- a/ipaserver/install/ipa_cert_fix.py -+++ b/ipaserver/install/ipa_cert_fix.py -@@ -71,11 +71,11 @@ class IPACertFix(AdminTool): - def run(self): - if not is_ipa_configured(): - print("IPA is not configured.") -- return 0 # not really an error -+ return 2 - - if not cainstance.is_ca_installed_locally(): - print("CA is not installed on this server.") -- return 0 # not really an error -+ return 1 - - try: - ipautil.run(['pki-server', 'cert-fix', '--help'], raiseonerr=True) --- -2.20.1 - diff --git a/SOURCES/0037-Show-a-notification-that-sssd-needs-restarting-after.patch b/SOURCES/0037-Show-a-notification-that-sssd-needs-restarting-after.patch deleted file mode 100644 index aaa3115..0000000 --- a/SOURCES/0037-Show-a-notification-that-sssd-needs-restarting-after.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 3c2237e481fdb2241494bd285931803335ed44dd Mon Sep 17 00:00:00 2001 -From: Oleg Kozlov -Date: Fri, 29 Mar 2019 14:35:02 +0100 -Subject: [PATCH] Show a notification that sssd needs restarting after - idrange-mod - -If the `ipa idrange-mod` command has been used show a notification that sssd.service needs restarting. It's needed for applying changes. E.g. after setup AD trust with a domain with more than 200000 objects (the highest RID > idm's default value, 200000) users with RIDs > 200000 are not able to login, the size needs to be increased via idrange-mod, but it makes an effect only after sssd restarting. - -Implementation: -Notification was implemented via passing `ipalib.messages.ServiceRestartRequired` to `add_message` method in `ipaserver.plugins.idrange.idrange_mod.post_callback`. - -Tests: -Added `messages` with sssd restart required (`ipalib.messages.ServiceRestartRequired`) to cases with idrange_mod where output is expected in `ipatests.test_xmlrpc.test_range_plugin.test_range'. - -Fixes: https://pagure.io/freeipa/issue/7708 -Reviewed-By: Alexander Bokovoy -Reviewed-By: Christian Heimes ---- - ipaplatform/base/services.py | 3 ++- - ipaserver/plugins/idrange.py | 11 ++++++++++- - ipatests/test_xmlrpc/test_range_plugin.py | 17 ++++++++++++++++- - 3 files changed, 28 insertions(+), 3 deletions(-) - -diff --git a/ipaplatform/base/services.py b/ipaplatform/base/services.py -index 9fd2a8532837c631945fa837be03c80fa42128bf..b037718f22fc36c4a01b3b0962b3f9e7a69f4b7e 100644 ---- a/ipaplatform/base/services.py -+++ b/ipaplatform/base/services.py -@@ -53,7 +53,8 @@ wellknownservices = ['certmonger', 'dirsrv', 'httpd', 'ipa', 'krb5kdc', - 'messagebus', 'nslcd', 'nscd', 'ntpd', 'portmap', - 'rpcbind', 'kadmin', 'sshd', 'autofs', 'rpcgssd', - 'rpcidmapd', 'pki_tomcatd', 'chronyd', 'domainname', -- 'named', 'ods_enforcerd', 'ods_signerd', 'gssproxy'] -+ 'named', 'ods_enforcerd', 'ods_signerd', 'gssproxy', -+ 'sssd'] - - # The common ports for these services. This is used to wait for the - # service to become available. -diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py -index ea3d1ff5662800957cde99934e9d2577e6b13ea6..364f128de4a04f484bde0def3c782e1a48be1daa 100644 ---- a/ipaserver/plugins/idrange.py -+++ b/ipaserver/plugins/idrange.py -@@ -17,13 +17,16 @@ - # 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 six - - from ipalib.plugable import Registry - from .baseldap import (LDAPObject, LDAPCreate, LDAPDelete, - LDAPRetrieve, LDAPSearch, LDAPUpdate) --from ipalib import api, Int, Str, StrEnum, _, ngettext -+from ipalib import api, Int, Str, StrEnum, _, ngettext, messages - from ipalib import errors -+from ipaplatform import services - from ipapython.dn import DN - - if six.PY3: -@@ -768,4 +771,10 @@ class idrange_mod(LDAPUpdate): - assert isinstance(dn, DN) - self.obj.handle_ipabaserid(entry_attrs, options) - self.obj.handle_iparangetype(entry_attrs, options) -+ self.add_message( -+ messages.ServiceRestartRequired( -+ service=services.knownservices['sssd'].systemd_name, -+ server=keys[0] -+ ) -+ ) - return dn -diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py -index 0a8f66b62dac9ea2e4692f0f64b1c8fbc9272fd2..2adc57ed5f5d23fe5f457ab3a5e23462f24a62fe 100644 ---- a/ipatests/test_xmlrpc/test_range_plugin.py -+++ b/ipatests/test_xmlrpc/test_range_plugin.py -@@ -21,9 +21,12 @@ - Test the `ipaserver/plugins/idrange.py` module, and XML-RPC in general. - """ - -+from __future__ import absolute_import -+ - import six - --from ipalib import api, errors -+from ipalib import api, errors, messages -+from ipaplatform import services - from ipatests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid - from ipatests.test_xmlrpc import objectclasses - from ipatests.util import MockLDAP -@@ -786,6 +789,12 @@ class test_range(Declarative): - command=('idrange_mod', [domain3range2], - dict(ipabaseid=domain3range1_base_id)), - expected=dict( -+ messages=( -+ messages.ServiceRestartRequired( -+ service=services.knownservices['sssd'].systemd_name, -+ server=domain3range2 -+ ).to_dict(), -+ ), - result=dict( - cn=[domain3range2], - ipabaseid=[unicode(domain3range1_base_id)], -@@ -851,6 +860,12 @@ class test_range(Declarative): - command=('idrange_mod', [domain2range1], - dict(ipabaserid=domain5range1_base_rid)), - expected=dict( -+ messages=( -+ messages.ServiceRestartRequired( -+ service=services.knownservices['sssd'].systemd_name, -+ server=domain2range1 -+ ).to_dict(), -+ ), - result=dict( - cn=[domain2range1], - ipabaseid=[unicode(domain2range1_base_id)], --- -2.20.1 - diff --git a/SOURCES/0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch b/SOURCES/0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch deleted file mode 100644 index cd57fe6..0000000 --- a/SOURCES/0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch +++ /dev/null @@ -1,53 +0,0 @@ -From e3c8a9b78f01e268a907bc97ad2914bf0d1236fc Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 1 Apr 2019 11:10:26 +0200 -Subject: [PATCH] ipa-server-upgrade: fix add_systemd_user_hbac - -During upgrade, the method add_systemd_user_hbac is creating -a hbacsvc and a hbacrule, but fails in python2 because of -unicode conversion errors. -The arguments should be defined as u'value'. - -Fixes: https://pagure.io/freeipa/issue/7896 -Reviewed-By: Christian Heimes ---- - ipaserver/install/server/upgrade.py | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py -index f4389d37909fc0b5aed960638de67243906b634d..ba0dfa423a3fc9560ef3c81c1d98cad39c320575 100644 ---- a/ipaserver/install/server/upgrade.py -+++ b/ipaserver/install/server/upgrade.py -@@ -1689,12 +1689,12 @@ def update_replica_config(db_suffix): - - def add_systemd_user_hbac(): - logger.info('[Create systemd-user hbac service and rule]') -- rule = 'allow_systemd-user' -- service = 'systemd-user' -+ rule = u'allow_systemd-user' -+ service = u'systemd-user' - try: - api.Command.hbacsvc_add( - service, -- description='pam_systemd and systemd user@.service' -+ description=u'pam_systemd and systemd user@.service' - ) - except ipalib.errors.DuplicateEntry: - logger.info('hbac service %s already exists', service) -@@ -1707,10 +1707,10 @@ def add_systemd_user_hbac(): - try: - api.Command.hbacrule_add( - rule, -- description=('Allow pam_systemd to run user@.service to create ' -+ description=(u'Allow pam_systemd to run user@.service to create ' - 'a system user session'), -- usercategory='all', -- hostcategory='all', -+ usercategory=u'all', -+ hostcategory=u'all', - ) - except ipalib.errors.DuplicateEntry: - logger.info('hbac rule %s already exists', rule) --- -2.20.1 - diff --git a/SOURCES/0039-ipa-setup-kra-fix-python2-parameter.patch b/SOURCES/0039-ipa-setup-kra-fix-python2-parameter.patch deleted file mode 100644 index 4f31e3a..0000000 --- a/SOURCES/0039-ipa-setup-kra-fix-python2-parameter.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 031b79d7111d6deaab05a8682014504b328614d7 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Mon, 1 Apr 2019 11:35:48 +0200 -Subject: [PATCH] ipa-setup-kra: fix python2 parameter - -ipa-setup-kra is failing in python2 with -invalid 'role_servrole': must be Unicode text -because of a unicode conversion error. - -The method api.Command.server_role_find is called with the parameter -role_servrole='IPA master' but it should rather be -role_servrole=u'IPA master' - -Fixes: https://pagure.io/freeipa/issue/7897 -Reviewed-By: Christian Heimes ---- - 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 8948f64c2ec2db4cd013699e07dd94d5dba6c043..a60cb7f63dc0673deae0839de8c2bb8dc3a905c8 100644 ---- a/ipaserver/install/service.py -+++ b/ipaserver/install/service.py -@@ -213,7 +213,7 @@ def sync_services_state(fqdn): - """ - result = api.Command.server_role_find( - server_server=fqdn, -- role_servrole='IPA master', -+ role_servrole=u'IPA master', - status=HIDDEN - ) - if result['count']: --- -2.20.1 - diff --git a/SOURCES/0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch b/SOURCES/0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch deleted file mode 100644 index 461a3af..0000000 --- a/SOURCES/0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch +++ /dev/null @@ -1,286 +0,0 @@ -From 12a079a0b599cf192c4bee8bcc37f1824f82539e Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Sun, 31 Mar 2019 10:39:05 +0300 -Subject: [PATCH] oddjob: allow to pass options to trust-fetch-domains - -Refactor com.redhat.idm.trust-fetch.domains oddjob helper to allow -passing administrative credentials and a domain controller to talk to. - -This approach allows to avoid rediscovering a domain controller in case -a user actually specified the domain controller when establishing trust. - -It also allows to pass through admin credentials if user decides to do -so. The latter will be used later to allow updating trust topology in a -similar oddjob helper. - -Resolves: https://pagure.io/freeipa/issue/7895 -Reviewed-By: Christian Heimes -(cherry picked from commit de4a9875d410c68ae4f9602b70c753a11034b31b) ---- - API.txt | 4 +- - VERSION.m4 | 4 +- - .../oddjob/com.redhat.idm.trust-fetch-domains | 91 +++++++++++-------- - .../etc/oddjobd.conf.d/oddjobd-ipa-trust.conf | 2 +- - ipaserver/plugins/trust.py | 31 ++++++- - 5 files changed, 83 insertions(+), 49 deletions(-) - -diff --git a/API.txt b/API.txt -index 222e30915ccc1fb4a6f3ce228669453f346fdde4..325df7a6ef48afbc438bcc1f7b8ca64efb229886 100644 ---- a/API.txt -+++ b/API.txt -@@ -5765,10 +5765,12 @@ output: Output('result', type=[]) - output: Output('summary', type=[, ]) - output: ListOfPrimaryKeys('value') - command: trust_fetch_domains/1 --args: 1,5,4 -+args: 1,7,4 - arg: Str('cn', cli_name='realm') - option: Flag('all', autofill=True, cli_name='all', default=False) - option: Flag('raw', autofill=True, cli_name='raw', default=False) -+option: Str('realm_admin?', cli_name='admin') -+option: Password('realm_passwd?', cli_name='password', confirm=False) - option: Str('realm_server?', cli_name='server') - option: Flag('rights', autofill=True, default=False) - option: Str('version?') -diff --git a/VERSION.m4 b/VERSION.m4 -index b1425626ca00ffbcc902c66685cb27cbb2136539..da391d8bd4dad6ae8e7418e6af54a9d481133cc8 100644 ---- a/VERSION.m4 -+++ b/VERSION.m4 -@@ -82,8 +82,8 @@ define(IPA_DATA_VERSION, 20100614120000) - # # - ######################################################## - define(IPA_API_VERSION_MAJOR, 2) --define(IPA_API_VERSION_MINOR, 230) --# Last change: Added `automember-find-orphans' command -+define(IPA_API_VERSION_MINOR, 231) -+# Last change: Added admin creds to trust-fetch-domains - - - ######################################################## -diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains -index 30150793d98011d153081477c0856618e1454ba5..1e90759e0e6e7be36745ec12f4478bfec0f0358e 100755 ---- a/install/oddjob/com.redhat.idm.trust-fetch-domains -+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains -@@ -14,11 +14,31 @@ import pwd - import six - import gssapi - --from ipalib.install.kinit import kinit_keytab -+from ipalib.install.kinit import kinit_keytab, kinit_password - - if six.PY3: - unicode = str - -+ -+def parse_options(): -+ usage = "%prog \n" -+ parser = config.IPAOptionParser(usage=usage, -+ formatter=config.IPAFormatter()) -+ -+ parser.add_option("-d", "--debug", action="store_true", dest="debug", -+ help="Display debugging information") -+ parser.add_option("-s", "--server", action="store", dest="server", -+ help="Domain controller for the Active Directory domain (optional)") -+ parser.add_option("-a", "--admin", action="store", dest="admin", -+ help="Active Directory administrator (optional)") -+ parser.add_option("-p", "--password", action="store", dest="password", -+ help="Display debugging information") -+ -+ options, args = parser.parse_args() -+ safe_options = parser.get_safe_opts(options) -+ -+ return safe_options, options, args -+ - def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): - getkeytab_args = ["/usr/sbin/ipa-getkeytab", - "-s", api.env.host, -@@ -40,7 +60,7 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): - pass - - --def get_forest_root_domain(api_instance, trusted_domain): -+def get_forest_root_domain(api_instance, trusted_domain, server=None): - """ - retrieve trusted forest root domain for given domain name - -@@ -53,25 +73,11 @@ def get_forest_root_domain(api_instance, trusted_domain): - flatname = trustconfig_show()['result']['ipantflatname'][0] - - remote_domain = dcerpc.retrieve_remote_domain( -- api_instance.env.host, flatname, trusted_domain) -+ api_instance.env.host, flatname, trusted_domain, -+ realm_server=server) - - return remote_domain.info['dns_forest'] - -- --def parse_options(): -- usage = "%prog \n" -- parser = config.IPAOptionParser(usage=usage, -- formatter=config.IPAFormatter()) -- -- parser.add_option("-d", "--debug", action="store_true", dest="debug", -- help="Display debugging information") -- -- options, args = parser.parse_args() -- safe_options = parser.get_safe_opts(options) -- -- return safe_options, options, args -- -- - if not is_ipa_configured(): - # LSB status code 6: program is not configured - raise ScriptError("IPA is not configured " + -@@ -153,32 +159,37 @@ trusted_domain = trusted_domain_entry.single_value.get('cn').lower() - # At this point if we didn't find trusted forest name, an exception will be raised - # and script will quit. This is actually intended. - --oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab' --oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper())) -+if not (options.admin and options.password): -+ oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab' -+ oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper())) - --# If keytab does not exist, retrieve it --if not os.path.isfile(oneway_keytab_name): -- retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal) -+ # If keytab does not exist, retrieve it -+ if not os.path.isfile(oneway_keytab_name): -+ retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal) - --try: -- have_ccache = False - try: -- # The keytab may have stale key material (from older trust-add run) -- cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -- if cred.lifetime > 0: -- have_ccache = True -- except gssapi.exceptions.ExpiredCredentialsError: -- pass -- if not have_ccache: -+ have_ccache = False -+ try: -+ # The keytab may have stale key material (from older trust-add run) -+ cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -+ if cred.lifetime > 0: -+ have_ccache = True -+ except gssapi.exceptions.ExpiredCredentialsError: -+ pass -+ if not have_ccache: -+ if os.path.exists(oneway_ccache_name): -+ os.unlink(oneway_ccache_name) -+ kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -+ except gssapi.exceptions.GSSError: -+ # If there was failure on using keytab, assume it is stale and retrieve again -+ retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal) - if os.path.exists(oneway_ccache_name): - os.unlink(oneway_ccache_name) - kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) --except gssapi.exceptions.GSSError: -- # If there was failure on using keytab, assume it is stale and retrieve again -- retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal) -- if os.path.exists(oneway_ccache_name): -- os.unlink(oneway_ccache_name) -- kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -+else: -+ cred = kinit_password(options.admin, options.password, -+ oneway_ccache_name, -+ canonicalize=True, enterprise=True) - - # We are done: we have ccache with TDO credentials and can fetch domains - ipa_domain = api.env.domain -@@ -186,9 +197,9 @@ os.environ['KRB5CCNAME'] = oneway_ccache_name - - # retrieve the forest root domain name and contact it to retrieve trust - # topology info --forest_root = get_forest_root_domain(api, trusted_domain) -+forest_root = get_forest_root_domain(api, trusted_domain, server=options.server) - --domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True) -+domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True, server=options.server) - trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result'] - trust.add_new_domains_from_trust(api, None, trust_domain_object, domains) - -diff --git a/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf b/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf -index 630a4e6cd4c0d3ed9ce48bf9b882b7d630f6bbf3..9f3f168a51abfdd1cb7cb8b76221bb4ec806859c 100644 ---- a/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf -+++ b/install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf -@@ -11,7 +11,7 @@ - - - - -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index 91cd1387ce058f34c2319676767d9e50f9b46ed1..bb9e0fe3303989c49cf339df6e5aeeb4ce1435cf 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -418,9 +418,19 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options): - return range_type, range_size, base_id - - --def fetch_trusted_domains_over_dbus(myapi, forest_name): -+def fetch_trusted_domains_over_dbus(myapi, *keys, **options): - if not _bindings_installed: - return -+ -+ forest_name = keys[0] -+ method_options = [] -+ if 'realm_server' in options: -+ method_options.extend(['--server', options['realm_server']]) -+ if 'realm_admin' in options: -+ method_options.extend(['--admin', options['realm_admin']]) -+ if 'realm_passwd' in options: -+ method_options.extend(['--password', options['realm_passwd']]) -+ - # Calling oddjobd-activated service via DBus has some quirks: - # - Oddjobd registers multiple canonical names on the same address - # - python-dbus only follows name owner changes when mainloop is in use -@@ -436,7 +446,8 @@ def fetch_trusted_domains_over_dbus(myapi, forest_name): - fetch_domains_method = intf.get_dbus_method( - 'fetch_domains', - dbus_interface=DBUS_IFACE_TRUST) -- (_ret, _stdout, _stderr) = fetch_domains_method(forest_name) -+ (_ret, _stdout, _stderr) = fetch_domains_method( -+ [forest_name] + method_options) - except dbus.DBusException as e: - logger.error('Failed to call %s.fetch_domains helper.' - 'DBus exception is %s.', DBUS_IFACE_TRUST, str(e)) -@@ -1760,10 +1771,20 @@ class trust_fetch_domains(LDAPRetrieve): - - has_output = output.standard_list_of_entries - takes_options = LDAPRetrieve.takes_options + ( -+ Str('realm_admin?', -+ cli_name='admin', -+ label=_("Active Directory domain administrator"), -+ ), -+ Password('realm_passwd?', -+ cli_name='password', -+ label=_("Active Directory domain administrator's password"), -+ confirm=False, -+ ), - Str('realm_server?', - cli_name='server', -- label=_('Domain controller for the Active Directory domain (optional)'), -- ), -+ label=_('Domain controller for the Active Directory domain ' -+ '(optional)'), -+ ), - ) - - def execute(self, *keys, **options): -@@ -1784,7 +1805,7 @@ class trust_fetch_domains(LDAPRetrieve): - # 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, keys[0]) -+ fetch_trusted_domains_over_dbus(self.api, *keys, **options) - result['summary'] = unicode(_('List of trust domains successfully ' - 'refreshed. Use trustdomain-find ' - 'command to list them.')) --- -2.20.1 - diff --git a/SOURCES/0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch b/SOURCES/0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch deleted file mode 100644 index f3dc8fe..0000000 --- a/SOURCES/0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch +++ /dev/null @@ -1,51 +0,0 @@ -From bb5026c5a265b78f9c889bd818ccfac9959b7d77 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 9 Oct 2018 17:21:37 +0300 -Subject: [PATCH] adtrust: define Guests mapping after creating cifs/ principal - -All Samba utilities load passdb modules from the configuration file. As -result, 'net groupmap' call would try to initialize ipasam passdb module -and that one would try to connect to LDAP using Kerberos authentication. - -We should be running it after cifs/ principal is actually created in -ipa-adtrust-install or otherwise setting up group mapping will fail. - -This only affects new installations. For older ones 'net groupmap' would -work just fine because adtrust is already configured and all principals -exist already. - -A re-run of 'ipa-server-upgrade' is a workaround too but better to fix -the initial setup. - -Related: https://pagure.io/freeipa/issue/7705 -Reviewed-By: Rob Crittenden -(cherry picked from commit 1ef0fe8bb824282c2f48417efda3a60e7c1bf580) ---- - ipaserver/install/adtrustinstance.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index d6b8f5cfa66c0cfbc6d47906703fc09c3e961a53..4141d8991cf75b60dea4ec123f0e3931bb3e6976 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -845,8 +845,6 @@ class ADTRUSTInstance(service.Service): - self.__create_samba_domain_object) - self.step("creating samba config registry", self.__write_smb_registry) - self.step("writing samba config file", self.__write_smb_conf) -- self.step("map BUILTIN\\Guests to nobody group", -- self.__map_Guests_to_nobody) - self.step("adding cifs Kerberos principal", - self.request_service_keytab) - self.step("adding cifs and host Kerberos principals to the adtrust agents group", \ -@@ -858,6 +856,8 @@ class ADTRUSTInstance(service.Service): - self.step("updating Kerberos config", self.__update_krb5_conf) - self.step("activating CLDAP plugin", self.__add_cldap_module) - self.step("activating sidgen task", self.__add_sidgen_task) -+ self.step("map BUILTIN\\Guests to nobody group", -+ self.__map_Guests_to_nobody) - self.step("configuring smbd to start on boot", self.__enable) - self.step("adding special DNS service records", \ - self.__add_dns_service_records) --- -2.20.1 - diff --git a/SOURCES/0042-net-groupmap-force-using-empty-config-when-mapping-G.patch b/SOURCES/0042-net-groupmap-force-using-empty-config-when-mapping-G.patch deleted file mode 100644 index 2b2b7ae..0000000 --- a/SOURCES/0042-net-groupmap-force-using-empty-config-when-mapping-G.patch +++ /dev/null @@ -1,56 +0,0 @@ -From dae784292fb49559de4aaee2a999c444a72ce272 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 16 Oct 2018 17:54:09 +0300 -Subject: [PATCH] net groupmap: force using empty config when mapping Guests - -When we define a group mapping for BUILTIN\Guests to 'nobody' group in -we run 'net groupmap add ...' with a default /etc/samba/smb.conf which -is now configured to use ipasam passdb module. We authenticate to LDAP -with GSSAPI in ipasam passdb module initialization. - -If GSSAPI authentication failed (KDC is offline, for example, during -server upgrade), 'net groupmap add' crashes after ~10 attempts to -re-authenticate. This is intended behavior in smbd/winbindd as they -cannot work anymore. However, for the command line tools there are -plenty of operations where passdb module is not needed. - -Additionally, GSSAPI authentication uses the default ccache in the -environment and a key from /etc/samba/samba.keytab keytab. This means -that if you'd run 'net *' as root, it will replace whatever Kerberos -tickets you have with a TGT for cifs/`hostname` and a service ticket to -ldap/`hostname` of IPA master. - -Apply a simple solution to avoid using /etc/samba/smb.conf when we -set up the group mapping by specifying '-s /dev/null' in 'net groupmap' -call. - -For upgrade code this is enough as in -a678336b8b36cdbea2512e79c09e475fdc249569 we enforce use of empty -credentials cache during upgrade to prevent tripping on individual -ccaches from KEYRING: or KCM: cache collections. - -Related: https://pagure.io/freeipa/issue/7705 -Reviewed-By: Florence Blanc-Renaud -(cherry picked from commit 3b79deae537f73ffd18e85f52e00e611543e5e45) ---- - ipaserver/install/adtrustinstance.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py -index 4141d8991cf75b60dea4ec123f0e3931bb3e6976..a21be5fba375a48fb82ea4224d00fb71c3688eb8 100644 ---- a/ipaserver/install/adtrustinstance.py -+++ b/ipaserver/install/adtrustinstance.py -@@ -123,8 +123,8 @@ def make_netbios_name(s): - - def map_Guests_to_nobody(): - env = {'LC_ALL': 'C'} -- args = [paths.NET, 'groupmap', 'add', 'sid=S-1-5-32-546', -- 'unixgroup=nobody', 'type=builtin'] -+ args = [paths.NET, '-s', '/dev/null', 'groupmap', 'add', -+ 'sid=S-1-5-32-546', 'unixgroup=nobody', 'type=builtin'] - - logger.debug("Map BUILTIN\\Guests to a group 'nobody'") - ipautil.run(args, env=env, raiseonerr=False, capture_error=True) --- -2.20.1 - diff --git a/SOURCES/0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch b/SOURCES/0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch deleted file mode 100644 index a9fd36f..0000000 --- a/SOURCES/0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 931c7fc1ada309a2d0fe832c95e5a5bf4a89edac Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 8 Apr 2019 11:43:59 +0300 -Subject: [PATCH] Bypass D-BUS interface definition deficiences for - trust-fetch-domains - -In oddjobd it is possible to pass arguments as command line or on the -stdin. We use command line to pass them but the way oddjobd registers -the D-BUS method signatures is by specifying all arguments as mandatory. - -Internally, oddjobd simply ignores if you passed less arguments than -specified in the D-BUS defition. Unfortunately, it is not possible to -specify less than maximum due to D-BUS seeing all arguments in the -list (30 is defined for the trust-fetch-domains). - -To pass options, have to pad a list of arguments to maximum with empty -strings and then filter out unneeded ones in the script. Option parser -already removes all options from the list of arguments so all we need to -do is to take our actual arguments. In case of trust-fetch-domains, it -is the name of the domain so we can only care about args[0]. - -Fixes: https://pagure.io/freeipa/issue/7903 -Signed-off-by: Alexander Bokovoy -(cherry picked from commit add6180ae5c5771b0b0f1c743df069ece4256512) - -Reviewed-By: Florence Blanc-Renaud ---- - .../oddjob/com.redhat.idm.trust-fetch-domains | 21 ++++++++++++------- - ipaserver/plugins/trust.py | 11 ++++++++-- - 2 files changed, 22 insertions(+), 10 deletions(-) - -diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains -index 1e90759e0e6e7be36745ec12f4478bfec0f0358e..029de781b2a1f94b1fd281b79aa69a1e9422dede 100755 ---- a/install/oddjob/com.redhat.idm.trust-fetch-domains -+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains -@@ -5,6 +5,7 @@ from ipaserver.install.installutils import is_ipa_configured, ScriptError - from ipapython import config, ipautil - from ipalib import api - from ipapython.dn import DN -+from ipapython.dnsutil import DNSName - from ipaplatform.constants import constants - from ipaplatform.paths import paths - import sys -@@ -37,7 +38,17 @@ def parse_options(): - options, args = parser.parse_args() - safe_options = parser.get_safe_opts(options) - -- return safe_options, options, args -+ # We only use first argument of the passed args but as D-BUS interface -+ # in oddjobd cannot expose optional, we fill in empty slots from IPA side -+ # and filter them here. -+ trusted_domain = ipautil.fsdecode(args[0]).lower() -+ -+ # Accept domain names that at least have two labels. We do not support -+ # single label Active Directory domains. This also catches empty args. -+ if len(DNSName(trusted_domain).labels) < 2: -+ # LSB status code 2: invalid or excess argument(s) -+ raise ScriptError("You must specify a valid trusted domain name", 2) -+ return safe_options, options, trusted_domain - - def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): - getkeytab_args = ["/usr/sbin/ipa-getkeytab", -@@ -87,13 +98,7 @@ if not os.getegid() == 0: - # LSB status code 4: user had insufficient privilege - raise ScriptError("You must be root to run ipactl.", 4) - --safe_options, options, args = parse_options() -- --if len(args) != 1: -- # LSB status code 2: invalid or excess argument(s) -- raise ScriptError("You must specify trusted domain name", 2) -- --trusted_domain = ipautil.fsdecode(args[0]).lower() -+safe_options, options, trusted_domain = parse_options() - - api.bootstrap(in_server=True, log=None, - context='server', confdir=paths.ETC_IPA) -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index bb9e0fe3303989c49cf339df6e5aeeb4ce1435cf..5de363bda6fdee081d3e4c98e731cecfa9585d21 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -446,8 +446,15 @@ def fetch_trusted_domains_over_dbus(myapi, *keys, **options): - fetch_domains_method = intf.get_dbus_method( - 'fetch_domains', - dbus_interface=DBUS_IFACE_TRUST) -- (_ret, _stdout, _stderr) = fetch_domains_method( -- [forest_name] + method_options) -+ # Oddjobd D-BUS method definition only accepts fixed number -+ # of arguments on the command line. Thus, we need to pass -+ # remaining ones as ''. There are 30 slots to allow for extension -+ # and the number comes from the 'arguments' definition in -+ # install/oddjob/etc/oddjobd.conf.d/oddjobd-ipa-trust.conf -+ method_arguments = [forest_name] -+ method_arguments.extend(method_options) -+ method_arguments.extend([''] * (30 - len(method_arguments))) -+ (_ret, _stdout, _stderr) = fetch_domains_method(*method_arguments) - except dbus.DBusException as e: - logger.error('Failed to call %s.fetch_domains helper.' - 'DBus exception is %s.', DBUS_IFACE_TRUST, str(e)) --- -2.20.1 - diff --git a/SOURCES/0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch b/SOURCES/0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch deleted file mode 100644 index 5abeaaa..0000000 --- a/SOURCES/0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch +++ /dev/null @@ -1,97 +0,0 @@ -From fc9648e33668afa1c61d62ad9e3b033011dd12d4 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Fri, 26 Apr 2019 18:40:05 +0200 -Subject: [PATCH] ipactl restart: fix wrong logic when checking service list - -ipactl is building a list of currently running services from -the content of /var/run/ipa/services.list, and a list of expected services -from the services configured in LDAP. - -Because CA and KRA both correspond to the same pki-tomcatd service, the -lists may contain duplicates. The code handling these duplicates is called -at the wrong place, and may result in a wrong list of services to -stop / restart / start. -The fix removes the duplicates before returning the lists, hence making sure -that there is no error when building the list of services to stop / restart -/ start. - -Fixes: https://pagure.io/freeipa/issue/7927 -Reviewed-By: Christian Heimes -Reviewed-By: Christian Heimes ---- - install/tools/ipactl | 10 ++-------- - 1 file changed, 2 insertions(+), 8 deletions(-) - -diff --git a/install/tools/ipactl b/install/tools/ipactl -index f40ea5a6df74f04ec7e6e8959d731553651a81d3..5d858b8f9dd2a213a29c50cd2c9778b57fee9e46 100755 ---- a/install/tools/ipactl -+++ b/install/tools/ipactl -@@ -237,7 +237,7 @@ def get_config(dirsrv): - for order, svc in sorted(svc_list): - if svc in service.SERVICE_LIST: - ordered_list.append(service.SERVICE_LIST[svc].systemd_name) -- return ordered_list -+ return deduplicate(ordered_list) - - def get_config_from_file(): - -@@ -263,7 +263,7 @@ def get_config_from_file(): - if svc in svc_list: - ordered_list.append(svc) - -- return ordered_list -+ return deduplicate(ordered_list) - - - def stop_services(svc_list): -@@ -325,7 +325,6 @@ def ipa_start(options): - # no service to start - return - -- svc_list = deduplicate(svc_list) - for svc in svc_list: - svchandle = services.service(svc, api=api) - try: -@@ -365,7 +364,6 @@ def ipa_stop(options): - finally: - raise IpactlError() - -- svc_list = deduplicate(svc_list) - for svc in reversed(svc_list): - svchandle = services.service(svc, api=api) - try: -@@ -452,7 +450,6 @@ def ipa_restart(options): - - if len(old_svc_list) != 0: - # we need to definitely stop some services -- old_svc_list = deduplicate(old_svc_list) - for svc in reversed(old_svc_list): - svchandle = services.service(svc, api=api) - try: -@@ -477,7 +474,6 @@ def ipa_restart(options): - - if len(svc_list) != 0: - # there are services to restart -- svc_list = deduplicate(svc_list) - for svc in svc_list: - svchandle = services.service(svc, api=api) - try: -@@ -500,7 +496,6 @@ def ipa_restart(options): - - if len(new_svc_list) != 0: - # we still need to start some services -- new_svc_list = deduplicate(new_svc_list) - for svc in new_svc_list: - svchandle = services.service(svc, api=api) - try: -@@ -552,7 +547,6 @@ def ipa_status(options): - if len(svc_list) == 0: - return - -- svc_list = deduplicate(svc_list) - for svc in svc_list: - svchandle = services.service(svc, api=api) - try: --- -2.20.1 - diff --git a/SOURCES/0045-replica-install-acknowledge-ca_host-override.patch b/SOURCES/0045-replica-install-acknowledge-ca_host-override.patch deleted file mode 100644 index e443c0e..0000000 --- a/SOURCES/0045-replica-install-acknowledge-ca_host-override.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 14dc08477429ff22acf36052367394a4b59089d0 Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Wed, 27 Mar 2019 11:53:33 +0100 -Subject: [PATCH] replica install: acknowledge ca_host override - -Fixup for commit c0fd5e39c726ef4dc12e87a2f9c08ebb32ed27fe. Only set -ca_host to source master hostname if ca_host points to the local host. -This permits users to override ca_host in /etc/ipa/default.conf when -installing a replica. - -Related: https://pagure.io/freeipa/issue/7744 -Signed-off-by: Christian Heimes -Reviewed-By: Alexander Bokovoy -Reviewed-By: Tibor Dudlak -Reviewed-By: Tibor Dudlak ---- - ipaserver/install/server/replicainstall.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index 7178238bfb996f987b5e3beaebe05fa104ada089..e13b7f18c4d4df7efde50ac9cb7d2f71bfa765cc 100644 ---- a/ipaserver/install/server/replicainstall.py -+++ b/ipaserver/install/server/replicainstall.py -@@ -1048,7 +1048,12 @@ def promote_check(installer): - config.host_name = api.env.host - config.domain_name = api.env.domain - config.master_host_name = api.env.server -- config.ca_host_name = api.env.ca_host -+ if not api.env.ca_host or api.env.ca_host == api.env.host: -+ # ca_host has not been configured explicitly, prefer source master -+ config.ca_host_name = api.env.server -+ else: -+ # default to ca_host from IPA config -+ config.ca_host_name = api.env.ca_host - config.kra_host_name = config.ca_host_name - config.ca_ds_port = 389 - config.setup_ca = options.setup_ca --- -2.20.1 - diff --git a/SOURCES/0046-ipa-console-catch-proper-exception-when-history-file.patch b/SOURCES/0046-ipa-console-catch-proper-exception-when-history-file.patch deleted file mode 100644 index 9599ec4..0000000 --- a/SOURCES/0046-ipa-console-catch-proper-exception-when-history-file.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 9fd415c73d0b70c1afadd5694269bf429fbd1aa2 Mon Sep 17 00:00:00 2001 -From: Sergey Orlov -Date: Thu, 25 Apr 2019 18:30:24 +0200 -Subject: [PATCH] ipa console: catch proper exception when history file can not - be open - -When history file could not be open we were catching OSError. This worked -for python3, as it raises FileNotFoundError, which is a subclass of -OSError. But in python2 IOError is raised when file does not exist and -as this exception was not catched, "ipa conosle" command was crashing. -As far as in pyton3 IOError and OSError have been merged -(OSError is IOError) we can safely catch only IOError. - -Fixes: https://pagure.io/freeipa/issue/7922 -Reviewed-By: Christian Heimes ---- - ipalib/cli.py | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/ipalib/cli.py b/ipalib/cli.py -index 7b2af485d94e9f98df44b24489795c45d690956c..2c74a2aaa47a2471a232d81aa6acfafd7f9f930f 100644 ---- a/ipalib/cli.py -+++ b/ipalib/cli.py -@@ -969,7 +969,7 @@ class console(frontend.Command): - history = os.path.join(api.env.dot_ipa, "console.history") - try: - readline.read_history_file(history) -- except OSError: -+ except IOError: - pass - - def save_history(): -@@ -979,7 +979,7 @@ class console(frontend.Command): - readline.set_history_length(50) - try: - readline.write_history_file(history) -- except OSError: -+ except IOError: - logger.exception("Unable to store history %s", history) - - atexit.register(save_history) --- -2.20.1 - diff --git a/SOURCES/0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch b/SOURCES/0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch deleted file mode 100644 index 26dec09..0000000 --- a/SOURCES/0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch +++ /dev/null @@ -1,48 +0,0 @@ -From dfb08e295420a9ea92776fa99cd1b7fe6a6badaa Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Sat, 11 May 2019 11:54:40 +0300 -Subject: [PATCH] upgrade: adtrust - catch empty result when retrieving list of - trusts -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Upgrade failure when ipa-server-upgrade is being run on a system with no -trust established but trust configured - -Fixes: https://pagure.io/freeipa/issue/7939 -Reviewed-By: François Cami ---- - ipaserver/install/plugins/adtrust.py | 16 +++++++++++----- - 1 file changed, 11 insertions(+), 5 deletions(-) - -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index 1461e000dc855a21665eb5ea0cfe4a47df419344..55df5cd01fd0f585d5955e700ccf20c7fc9a747f 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -610,11 +610,17 @@ class update_tdo_to_new_layout(Updater): - - trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn - -- trusts = ldap.get_entries( -- base_dn=trusts_dn, -- scope=ldap.SCOPE_ONELEVEL, -- filter=self.trust_filter, -- attrs_list=self.trust_attrs) -+ # We might be in a situation when no trusts exist yet -+ # In such case there is nothing to upgrade but we have to catch -+ # an exception or it will abort the whole upgrade process -+ try: -+ trusts = ldap.get_entries( -+ base_dn=trusts_dn, -+ scope=ldap.SCOPE_ONELEVEL, -+ filter=self.trust_filter, -+ attrs_list=self.trust_attrs) -+ except errors.EmptyResult: -+ trusts = [] - - # For every trust, retrieve its principals and convert - for t_entry in trusts: --- -2.20.1 - diff --git a/SOURCES/0048-Consider-configured-servers-as-valid.patch b/SOURCES/0048-Consider-configured-servers-as-valid.patch deleted file mode 100644 index 012a807..0000000 --- a/SOURCES/0048-Consider-configured-servers-as-valid.patch +++ /dev/null @@ -1,147 +0,0 @@ -From 750a60a989d7c1fe0872af292191889e7e23382d Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Mon, 29 Apr 2019 11:12:30 +0200 -Subject: [PATCH] Consider configured servers as valid - -Under some conditions, ipa config-show and several other commands were -failing with error message: - - ERROR: invalid 'PKINIT enabled server': all masters must have IPA master role enabled - -Amongst others the issue can be caused by a broken installation, when -some services are left in state 'configuredServices'. The problem even -block uninstallation or removal of replicas. Now configured servers are -also consider valid providers for associated roles. - -A new test verifies that config-show works with hidden and configured HTTP -service. - -Remark: The original intent of the sanity check is no longer clear to me. I -think it was used to very that all services can be started by ipactl. -Since ipactl starts hidden, configured, and enabled services, the new -logic reflect the fact, too. - -Fixes: https://pagure.io/freeipa/issue/7929 -Signed-off-by: Christian Heimes -Reviewed-By: Alexander Bokovoy ---- - ipaserver/servroles.py | 9 ++- - ipatests/test_integration/test_commands.py | 72 ++++++++++++---------- - 2 files changed, 45 insertions(+), 36 deletions(-) - -diff --git a/ipaserver/servroles.py b/ipaserver/servroles.py -index 0988cbdd7eac599ef26c89a015523b2d92e9502f..984d4bc269fffb4c667e9b8a432b1caf8d3b4f18 100644 ---- a/ipaserver/servroles.py -+++ b/ipaserver/servroles.py -@@ -346,11 +346,14 @@ class ServerAttribute(LDAPBasedProperty): - def _get_assoc_role_providers(self, api_instance): - """get list of all servers on which the associated role is enabled - -- Consider a hidden server as a valid provider for a role. -+ Consider a hidden and configured server as a valid provider for a -+ role, as all services are started. - """ - return [ -- r[u'server_server'] for r in self.associated_role.status( -- api_instance) if r[u'status'] in {ENABLED, HIDDEN}] -+ r[u'server_server'] -+ for r in self.associated_role.status(api_instance) -+ if r[u'status'] in {ENABLED, HIDDEN, CONFIGURED} -+ ] - - def _remove(self, api_instance, masters): - """ -diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py -index b172a6dd036b5cba4d117f9160ee1ada8712c949..c20213d4b6f0b9d004a8b44afa161a60c538916f 100644 ---- a/ipatests/test_integration/test_commands.py -+++ b/ipatests/test_integration/test_commands.py -@@ -24,10 +24,15 @@ from ipalib.constants import IPAAPI_USER - - from ipaplatform.paths import paths - -+from ipapython.dn import DN -+ -+from ipaserver.masters import ( -+ CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE -+) -+ - from ipatests.test_integration.base import IntegrationTest - from ipatests.pytest_ipa.integration import tasks - from ipatests.pytest_ipa.integration.create_external_ca import ExternalCA --from ipatests.test_ipalib.test_x509 import good_pkcs7, badcert - - logger = logging.getLogger(__name__) - -@@ -499,36 +504,37 @@ class TestIPACommand(IntegrationTest): - assert result.returncode != 0 - assert 'HBAC rule not found' in result.stderr_text - -- def test_ipa_cacert_manage_install(self): -- # Re-install the IPA CA -- self.master.run_command([ -- paths.IPA_CACERT_MANAGE, -- 'install', -- paths.IPA_CA_CRT]) -- -- # Test a non-existent file -- result = self.master.run_command([ -- paths.IPA_CACERT_MANAGE, -- 'install', -- '/var/run/cert_not_found'], raiseonerr=False) -- assert result.returncode == 1 -+ def test_config_show_configured_services(self): -+ # https://pagure.io/freeipa/issue/7929 -+ states = {CONFIGURED_SERVICE, ENABLED_SERVICE, HIDDEN_SERVICE} -+ dn = DN( -+ ('cn', 'HTTP'), ('cn', self.master.hostname), ('cn', 'masters'), -+ ('cn', 'ipa'), ('cn', 'etc'), -+ self.master.domain.basedn # pylint: disable=no-member -+ ) - -- cmd = self.master.run_command(['mktemp']) -- filename = cmd.stdout_text.strip() -- -- for contents in (good_pkcs7,): -- self.master.put_file_contents(filename, contents) -- result = self.master.run_command([ -- paths.IPA_CACERT_MANAGE, -- 'install', -- filename]) -- -- for contents in (badcert,): -- self.master.put_file_contents(filename, contents) -- result = self.master.run_command([ -- paths.IPA_CACERT_MANAGE, -- 'install', -- filename], raiseonerr=False) -- assert result.returncode == 1 -- -- self.master.run_command(['rm', '-f', filename]) -+ conn = self.master.ldap_connect() -+ entry = conn.get_entry(dn) # pylint: disable=no-member -+ -+ # original setting and all settings without state -+ orig_cfg = list(entry['ipaConfigString']) -+ other_cfg = [item for item in orig_cfg if item not in states] -+ -+ try: -+ # test with hidden -+ cfg = [HIDDEN_SERVICE] -+ cfg.extend(other_cfg) -+ entry['ipaConfigString'] = cfg -+ conn.update_entry(entry) # pylint: disable=no-member -+ self.master.run_command(['ipa', 'config-show']) -+ -+ # test with configured -+ cfg = [CONFIGURED_SERVICE] -+ cfg.extend(other_cfg) -+ entry['ipaConfigString'] = cfg -+ conn.update_entry(entry) # pylint: disable=no-member -+ self.master.run_command(['ipa', 'config-show']) -+ finally: -+ # reset -+ entry['ipaConfigString'] = orig_cfg -+ conn.update_entry(entry) # pylint: disable=no-member --- -2.20.1 - diff --git a/SOURCES/0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch b/SOURCES/0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch deleted file mode 100644 index 8b508d5..0000000 --- a/SOURCES/0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 3c1ac4d5c9c36c2b99ac2b1d9d86e46b563b4361 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Mon, 27 May 2019 10:00:28 +1000 -Subject: [PATCH] ipa-cert-fix: handle 'pki-server cert-fix' failure - -When DS cert is expired, 'pki-server cert-fix' will fail at the -final step (restart). When this case arises, ignore the -CalledProcessError and continue. - -We can't know for sure if the error was due to failure of final -restart, or something going wrong earlier. But if it was a more -serious failure, the next step (installing the renewed IPA-specific -certificates) will fail. - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/ipa_cert_fix.py | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py -index c8ee51faea9092350c8a182ba55387ddd7b196d8..5d5668b1d89115adcda167222ffc38a0caa690a2 100644 ---- a/ipaserver/install/ipa_cert_fix.py -+++ b/ipaserver/install/ipa_cert_fix.py -@@ -113,7 +113,17 @@ class IPACertFix(AdminTool): - return 0 - print("Proceeding.") - -- run_cert_fix(certs, extra_certs) -+ try: -+ run_cert_fix(certs, extra_certs) -+ except ipautil.CalledProcessError: -+ if any(x[0] is IPACertType.LDAPS for x in extra_certs): -+ # The DS cert was expired. This will cause -+ # 'pki-server cert-fix' to fail at the final -+ # restart. Therefore ignore the CalledProcessError -+ # and proceed to installing the IPA-specific certs. -+ pass -+ else: -+ raise # otherwise re-raise - - replicate_dogtag_certs(subject_base, ca_subject_dn, certs) - install_ipa_certs(subject_base, ca_subject_dn, extra_certs) --- -2.20.1 - diff --git a/SOURCES/0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch b/SOURCES/0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch deleted file mode 100644 index 3d80f7a..0000000 --- a/SOURCES/0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 1952fb1c90b444f7ecb0057451d5deb599df3d5f Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Mon, 27 May 2019 10:00:32 +1000 -Subject: [PATCH] ipa-cert-fix: fix spurious renewal master change - -We only want to become the renewal master if we actually renewed a -shared certificate. But there is a bug in the logic; even if the -only Dogtag certificate to be renewed is the 'sslserver' (a -non-shared certificate), the renewal master will be reset. Fix the -bug. - -A static type system would have excluded this bug. - -Part of: https://pagure.io/freeipa/issue/7885 - -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/ipa_cert_fix.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py -index 5d5668b1d89115adcda167222ffc38a0caa690a2..fff054c230c414fdf10eef1cf1b00697a63e386a 100644 ---- a/ipaserver/install/ipa_cert_fix.py -+++ b/ipaserver/install/ipa_cert_fix.py -@@ -128,7 +128,7 @@ class IPACertFix(AdminTool): - replicate_dogtag_certs(subject_base, ca_subject_dn, certs) - install_ipa_certs(subject_base, ca_subject_dn, extra_certs) - -- if any(x != 'sslserver' for x in certs) \ -+ if any(x[0] != 'sslserver' for x in certs) \ - or any(x[0] is IPACertType.IPARA for x in extra_certs): - # we renewed a "shared" certificate, therefore we must - # become the renewal master --- -2.20.1 - diff --git a/SOURCES/0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch b/SOURCES/0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch deleted file mode 100644 index b4a6a8b..0000000 --- a/SOURCES/0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 5b9d7daf27cb10101432e8a25c364dcbe92b37a4 Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 25 Jun 2019 15:22:57 +0300 -Subject: [PATCH] adtrust upgrade: fix wrong primary principal name - -Upgrade code had Kerberos principal names mixed up: instead of creating -krbtgt/LOCAL-FLAT@REMOTE and marking LOCAL-FLAT$@REMOTE as an alias to -it, it created LOCAL-FLAT$@REMOTE Kerberos principal and marked -krbtgt/LOCAL-FLAT@REMOTE as an alias. - -This differs from what Active Directory expects and what is created by -ipasam plugin when trust is established. When upgrading such deployment, -an upgrade code then unexpectedly failed. - -Resolves: https://pagure.io/freeipa/issue/7992 -Reviewed-By: Christian Heimes ---- - daemons/ipa-sam/ipa_sam.c | 12 +++++++----- - .../adtrust/oneway-trust-with-shared-secret.md | 16 +++++++++------- - ipaserver/install/plugins/adtrust.py | 4 ++-- - 3 files changed, 18 insertions(+), 14 deletions(-) - -diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c -index 3cf878c3f99774f7715f776c31d70e2950f9451c..2251f3ddcd9d5549d12b3e411245b00395c6b0d9 100644 ---- a/daemons/ipa-sam/ipa_sam.c -+++ b/daemons/ipa-sam/ipa_sam.c -@@ -2011,11 +2011,13 @@ static bool handle_cross_realm_princs(struct ipasam_private *ipasam_state, - pwd_outgoing, trusted_dn, - KRB_PRINC_CREATE_DEFAULT); - -- /* Second: @ is only used -- * for SSSD to be able to talk to AD DCs but it has to -- * have canonical name set to $ because -- * this is the salt used by AD DCs when using this -- * principal, otherwise authentication will fail. -+ /* Second: krbtgt/@ -+ * is only used for SSSD to be able to talk to -+ * AD DCs but it has to have canonical name set -+ * to krbtgt/ and alias it to -+ * because it is the salt used -+ * by AD DCs when using this principal, -+ * otherwise authentication will fail. - * - * *disable* use of this principal on our side as it is - * only used to retrieve trusted domain credentials by -diff --git a/doc/designs/adtrust/oneway-trust-with-shared-secret.md b/doc/designs/adtrust/oneway-trust-with-shared-secret.md -index dc58a08941acea447f9234107ebcba775351089e..09a940e34bb43a6e46beb85392c94423d2bfccd3 100644 ---- a/doc/designs/adtrust/oneway-trust-with-shared-secret.md -+++ b/doc/designs/adtrust/oneway-trust-with-shared-secret.md -@@ -131,16 +131,18 @@ and `LOCAL-FLAT` is the NetBIOS name of the FreeIPA primary domain (e.g. - REMOTE-FLAT$@LOCAL | Trusted domain object account for the Active Directory forest root domain - krbtgt/REMOTE-FLAT@LOCAL | Alias to REMOTE-FLAT$ TDO - krbtgt/LOCAL@REMOTE | Cross-realm principal representing IPA domain in Active Directory forest to allow crross-realm TGT issuance from IPA KDC side -- LOCAL-FLAT$@REMOTE | Trusted domain object account for IPA domain in Active Directory forest -- krbtgt/LOCAL-FLAT@REMOTE | Alias to LOCAL-FLAT$ -+ krbtgt/LOCAL-FLAT@REMOTE | Trusted domain object account for IPA domain in Active Directory forest -+ LOCAL-FLAT$@REMOTE | Alias to krbtgt/LOCAL-FLAT@REMOTE - - For inbound trust `ipasam` module creates following principals: - * `krbtgt/LOCAL@REMOTE`, enabled by default -- * `LOCAL-FLAT$@REMOTE`, used by SSSD to talk to Active Directory domain -- controllers, with canonical name set to `LOCAL-FLAT$` because Kerberos KDC -- must use this salt when issuing tickets for this principal. The use of this -- principal is disabled on IPA side (IPA KDC does not issue tickets in this name) -- --- we only retrieve a keytab for the principal in SSSD. -+ * `krbtgt/LOCAL-FLAT@REMOTE`, used by SSSD to talk to Active Directory domain -+ controllers, with canonical name set to `krbtgt/LOCAL-FLAT@REMOTE` because -+ Kerberos KDC must use this salt when issuing tickets for this principal. The -+ use of this principal is disabled on IPA side (IPA KDC does not issue tickets -+ in this name) --- we only retrieve a keytab for the principal in SSSD. SSSD -+ retrieves a keytab for this principal using `LOCAL-FLAT$@REMOTE` Principal -+ name. - - For outbound trust `ipasam` module creates following principals: - * `krbtgt/REMOTE@LOCAL`, enabled by default. -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index 55df5cd01fd0f585d5955e700ccf20c7fc9a747f..f810522b236d8c04f4a417aac8fd3717563c358e 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -680,12 +680,12 @@ class update_tdo_to_new_layout(Updater): - trust_principal, t_realm) - continue - -- # 4. Create @, disabled -+ # 4. Create krbtgt/@, disabled - nbt_principal = self.nbt_principal_template.format( - nbt=our_nbt_name, realm=t_realm) - tgt_principal = self.tgt_principal_template.format( - remote=our_nbt_name, local=t_realm) -- self.set_krb_principal([nbt_principal, tgt_principal], -+ self.set_krb_principal([tgt_principal, nbt_principal], - passwd_incoming, - t_dn, - flags=self.KRB_PRINC_CREATE_DEFAULT | --- -2.20.1 - diff --git a/SOURCES/0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch b/SOURCES/0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch deleted file mode 100644 index 62e2acc..0000000 --- a/SOURCES/0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch +++ /dev/null @@ -1,95 +0,0 @@ -From ca4e0582489a432a1f61fc75a27ef831e911f0fe Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 27 Jun 2019 11:56:08 +0300 -Subject: [PATCH] adtrust upgrade: fix wrong primary principal name, part 2 - -Second part of the trust principals upgrade - -For existing LOCAL-FLAT$@REMOTE object, convert it to -krbtgt/LOCAL-FLAT@REMOTE and add LOCAL-FLAT$@REMOTE as an alias. To do -so we need to modify an entry content a bit so it is better to remove -the old entry and create a new one instead of renaming. - -Resolves: https://pagure.io/freeipa/issue/7992 -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/plugins/adtrust.py | 36 +++++++++++++++++++++++----- - 1 file changed, 30 insertions(+), 6 deletions(-) - -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index f810522b236d8c04f4a417aac8fd3717563c358e..12596d5bfe71c16a2cb87acb755a88051676e3e5 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -513,16 +513,19 @@ class update_tdo_to_new_layout(Updater): - - if isinstance(principals, (list, tuple)): - trust_principal = principals[0] -- aliases = principals[1:] -+ alias = principals[1] - else: - trust_principal = principals -- aliases = [] -+ alias = None - -+ entry = None -+ en = None - try: - entry = ldap.get_entry( - DN(('krbprincipalname', trust_principal), trustdn)) - dn = entry.dn - action = ldap.update_entry -+ ticket_flags = int(entry.single_value.get('krbticketflags', 0)) - logger.debug("Updating Kerberos principal entry for %s", - trust_principal) - except errors.NotFound: -@@ -531,6 +534,19 @@ class update_tdo_to_new_layout(Updater): - if flags & self.KRB_PRINC_MUST_EXIST: - raise - -+ ticket_flags = 0 -+ if alias: -+ try: -+ en = ldap.get_entry( -+ DN(('krbprincipalname', alias), trustdn)) -+ ldap.delete_entry(en.dn) -+ ticket_flags = int(en.single_value.get( -+ 'krbticketflags', 0)) -+ except errors.NotFound: -+ logger.debug("Entry for alias TDO does not exist for " -+ "trusted domain object %s, skip it", -+ alias) -+ - dn = DN(('krbprincipalname', trust_principal), trustdn) - entry = ldap.make_entry(dn) - logger.debug("Adding Kerberos principal entry for %s", -@@ -545,15 +561,23 @@ class update_tdo_to_new_layout(Updater): - 'krbprincipalname': [trust_principal], - } - -- entry_data['krbprincipalname'].extend(aliases) -- - if flags & self.KRB_PRINC_CREATE_DISABLED: -- flg = int(entry.single_value.get('krbticketflags', 0)) -- entry_data['krbticketflags'] = flg | self.KRB_DISALLOW_ALL_TIX -+ entry_data['krbticketflags'] = (ticket_flags | -+ self.KRB_DISALLOW_ALL_TIX) - - if flags & self.KRB_PRINC_CREATE_AGENT_PERMISSION: - entry_data['objectclass'].extend(['ipaAllowedOperations']) - -+ if alias: -+ entry_data['krbprincipalname'].extend([alias]) -+ if en: -+ entry_data['krbprincipalkey'] = en.single_value.get( -+ 'krbprincipalkey') -+ entry_data['krbextradata'] = en.single_value.get( -+ 'krbextradata') -+ entry_data['ipaAllowedToPerform;read_keys'] = en.get( -+ 'ipaAllowedToPerform;read_keys', []) -+ - entry.update(entry_data) - try: - action(entry) --- -2.20.1 - diff --git a/SOURCES/0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch b/SOURCES/0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch deleted file mode 100644 index 781d9b6..0000000 --- a/SOURCES/0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch +++ /dev/null @@ -1,441 +0,0 @@ -From a9ff7e93de94de1c7ecaedce582d598d6a4ad30e Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 27 Jun 2019 15:17:07 +0300 -Subject: [PATCH] trust-fetch-domains: make sure we use right KDC when --server - is specified - -Since we are authenticating against AD DC before talking to it (by using -trusted domain object's credentials), we need to override krb5.conf -configuration in case --server option is specified. - -The context is a helper which is launched out of process with the help -of oddjobd. The helper takes existing trusted domain object, uses its -credentials to authenticate and then runs LSA RPC calls against that -trusted domain's domain controller. Previous code directed Samba -bindings to use the correct domain controller. However, if a DC visible -to MIT Kerberos is not reachable, we would not be able to obtain TGT and -the whole process will fail. - -trust_add.execute() was calling out to the D-Bus helper without passing -the options (e.g. --server) so there was no chance to get that option -visible by the oddjob helper. - -Also we need to make errors in the oddjob helper more visible to -error_log. Thus, move error reporting for a normal communication up from -the exception catching. - -Resolves: https://pagure.io/freeipa/issue/7895 -Signed-off-by: Alexander Bokovoy -Reviewed-By: Florence Blanc-Renaud ---- - .../oddjob/com.redhat.idm.trust-fetch-domains | 233 +++++++++++++----- - ipaserver/plugins/trust.py | 28 ++- - 2 files changed, 194 insertions(+), 67 deletions(-) - -diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains b/install/oddjob/com.redhat.idm.trust-fetch-domains -index 029de781b2a1f94b1fd281b79aa69a1e9422dede..b406201ec2baf8ee9398fc3634060b6d9a5392b0 100755 ---- a/install/oddjob/com.redhat.idm.trust-fetch-domains -+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains -@@ -8,9 +8,12 @@ from ipapython.dn import DN - from ipapython.dnsutil import DNSName - from ipaplatform.constants import constants - from ipaplatform.paths import paths -+import io - import sys - import os - import pwd -+import tempfile -+import textwrap - - import six - import gssapi -@@ -23,17 +26,38 @@ if six.PY3: - - def parse_options(): - usage = "%prog \n" -- parser = config.IPAOptionParser(usage=usage, -- formatter=config.IPAFormatter()) -- -- parser.add_option("-d", "--debug", action="store_true", dest="debug", -- help="Display debugging information") -- parser.add_option("-s", "--server", action="store", dest="server", -- help="Domain controller for the Active Directory domain (optional)") -- parser.add_option("-a", "--admin", action="store", dest="admin", -- help="Active Directory administrator (optional)") -- parser.add_option("-p", "--password", action="store", dest="password", -- help="Display debugging information") -+ parser = config.IPAOptionParser( -+ usage=usage, formatter=config.IPAFormatter() -+ ) -+ -+ parser.add_option( -+ "-d", -+ "--debug", -+ action="store_true", -+ dest="debug", -+ help="Display debugging information", -+ ) -+ parser.add_option( -+ "-s", -+ "--server", -+ action="store", -+ dest="server", -+ help="Domain controller for the Active Directory domain (optional)", -+ ) -+ parser.add_option( -+ "-a", -+ "--admin", -+ action="store", -+ dest="admin", -+ help="Active Directory administrator (optional)", -+ ) -+ parser.add_option( -+ "-p", -+ "--password", -+ action="store", -+ dest="password", -+ help="Display debugging information", -+ ) - - options, args = parser.parse_args() - safe_options = parser.get_safe_opts(options) -@@ -50,17 +74,26 @@ def parse_options(): - raise ScriptError("You must specify a valid trusted domain name", 2) - return safe_options, options, trusted_domain - -+ - def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): -- getkeytab_args = ["/usr/sbin/ipa-getkeytab", -- "-s", api.env.host, -- "-p", oneway_principal, -- "-k", oneway_keytab_name, -- "-r"] -+ getkeytab_args = [ -+ "/usr/sbin/ipa-getkeytab", -+ "-s", -+ api.env.host, -+ "-p", -+ oneway_principal, -+ "-k", -+ oneway_keytab_name, -+ "-r", -+ ] - if os.path.isfile(oneway_keytab_name): - os.unlink(oneway_keytab_name) - -- ipautil.run(getkeytab_args, env={'KRB5CCNAME': ccache_name, 'LANG': 'C'}, -- raiseonerr=False) -+ ipautil.run( -+ getkeytab_args, -+ env={"KRB5CCNAME": ccache_name, "LANG": "C"}, -+ raiseonerr=False, -+ ) - # Make sure SSSD is able to read the keytab - try: - sssd = pwd.getpwnam(constants.SSSD_USER) -@@ -72,8 +105,7 @@ def retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal): - - - def get_forest_root_domain(api_instance, trusted_domain, server=None): -- """ -- retrieve trusted forest root domain for given domain name -+ """Retrieve trusted forest root domain for given domain name - - :param api_instance: IPA API instance - :param trusted_domain: trusted domain name -@@ -81,18 +113,51 @@ def get_forest_root_domain(api_instance, trusted_domain, server=None): - :returns: forest root domain DNS name - """ - trustconfig_show = api_instance.Command.trustconfig_show -- flatname = trustconfig_show()['result']['ipantflatname'][0] -+ flatname = trustconfig_show()["result"]["ipantflatname"][0] - - remote_domain = dcerpc.retrieve_remote_domain( -- api_instance.env.host, flatname, trusted_domain, -- realm_server=server) -+ api_instance.env.host, flatname, trusted_domain, realm_server=server -+ ) -+ -+ return remote_domain.info["dns_forest"] -+ -+ -+def generate_krb5_config(realm, server): -+ """Generate override krb5 config file for trusted domain DC access -+ -+ :param realm: realm of the trusted AD domain -+ :param server: server to override KDC to -+ -+ :returns: tuple (temporary config file name, KRB5_CONFIG string) -+ """ -+ cfg = paths.KRB5_CONF -+ tcfg = None -+ if server: -+ content = textwrap.dedent(u""" -+ [realms] -+ %s = { -+ kdc = %s -+ } -+ """) % ( -+ realm.upper(), -+ server, -+ ) -+ -+ (fd, tcfg) = tempfile.mkstemp(dir="/var/run/ipa", -+ prefix="krb5conf", text=True) -+ with io.open(fd, mode='w', encoding='utf-8') as o: -+ o.write(content) -+ cfg = ":".join([tcfg, cfg]) -+ return (tcfg, cfg) - -- return remote_domain.info['dns_forest'] - - if not is_ipa_configured(): - # LSB status code 6: program is not configured -- raise ScriptError("IPA is not configured " + -- "(see man pages of ipa-server-install for help)", 6) -+ raise ScriptError( -+ "IPA is not configured " -+ + "(see man pages of ipa-server-install for help)", -+ 6, -+ ) - - if not os.getegid() == 0: - # LSB status code 4: user had insufficient privilege -@@ -100,8 +165,9 @@ if not os.getegid() == 0: - - safe_options, options, trusted_domain = parse_options() - --api.bootstrap(in_server=True, log=None, -- context='server', confdir=paths.ETC_IPA) -+api.bootstrap( -+ in_server=True, log=None, context="server", confdir=paths.ETC_IPA -+) - api.finalize() - - # Only import trust plugin after api is initialized or internal imports -@@ -121,12 +187,12 @@ from ipaserver.plugins import trust - # and retrieve our own NetBIOS domain name and use cifs/ipa.master@IPA.REALM to - # retrieve the keys to oneway_keytab_name. - --keytab_name = '/etc/samba/samba.keytab' -+keytab_name = "/etc/samba/samba.keytab" - --principal = str('cifs/' + api.env.host) -+principal = str("cifs/" + api.env.host) - --oneway_ccache_name = '/var/run/ipa/krb5cc_oddjob_trusts_fetch' --ccache_name = '/var/run/ipa/krb5cc_oddjob_trusts' -+oneway_ccache_name = "/var/run/ipa/krb5cc_oddjob_trusts_fetch" -+ccache_name = "/var/run/ipa/krb5cc_oddjob_trusts" - - # Standard sequence: - # - check if ccache exists -@@ -140,33 +206,45 @@ try: - cred = kinit_keytab(principal, keytab_name, ccache_name) - if cred.lifetime > 0: - have_ccache = True --except gssapi.exceptions.ExpiredCredentialsError: -+except (gssapi.exceptions.ExpiredCredentialsError, gssapi.raw.misc.GSSError): - pass - if not have_ccache: - # delete stale ccache and try again -- if os.path.exists(oneway_ccache_name): -+ if os.path.exists(ccache_name): - os.unlink(ccache_name) - cred = kinit_keytab(principal, keytab_name, ccache_name) - --old_ccache = os.environ.get('KRB5CCNAME') -+old_ccache = os.environ.get("KRB5CCNAME") -+old_config = os.environ.get("KRB5_CONFIG") - api.Backend.ldap2.connect(ccache_name) - - # Retrieve own NetBIOS name and trusted forest's name. - # We use script's input to retrieve the trusted forest's name to sanitize input - # for file-level access as we might need to wipe out keytab in /var/lib/sss/keytabs --own_trust_dn = DN(('cn', api.env.domain),('cn','ad'), ('cn', 'etc'), api.env.basedn) --own_trust_entry = api.Backend.ldap2.get_entry(own_trust_dn, ['ipantflatname']) --own_trust_flatname = own_trust_entry.single_value.get('ipantflatname').upper() --trusted_domain_dn = DN(('cn', trusted_domain.lower()), api.env.container_adtrusts, api.env.basedn) --trusted_domain_entry = api.Backend.ldap2.get_entry(trusted_domain_dn, ['cn']) --trusted_domain = trusted_domain_entry.single_value.get('cn').lower() -+own_trust_dn = DN( -+ ("cn", api.env.domain), ("cn", "ad"), ("cn", "etc"), api.env.basedn -+) -+own_trust_entry = api.Backend.ldap2.get_entry(own_trust_dn, ["ipantflatname"]) -+own_trust_flatname = own_trust_entry.single_value.get("ipantflatname").upper() -+trusted_domain_dn = DN( -+ ("cn", trusted_domain.lower()), api.env.container_adtrusts, api.env.basedn -+) -+trusted_domain_entry = api.Backend.ldap2.get_entry(trusted_domain_dn, ["cn"]) -+trusted_domain = trusted_domain_entry.single_value.get("cn").lower() - - # At this point if we didn't find trusted forest name, an exception will be raised - # and script will quit. This is actually intended. - -+# Generate MIT Kerberos configuration file that potentially overlays -+# the KDC to connect to for a trusted domain to allow --server option -+# to take precedence. -+cfg_file, cfg = generate_krb5_config(trusted_domain, options.server) -+ - if not (options.admin and options.password): -- oneway_keytab_name = '/var/lib/sss/keytabs/' + trusted_domain + '.keytab' -- oneway_principal = str('%s$@%s' % (own_trust_flatname, trusted_domain.upper())) -+ oneway_keytab_name = "/var/lib/sss/keytabs/" + trusted_domain + ".keytab" -+ oneway_principal = str( -+ "%s$@%s" % (own_trust_flatname, trusted_domain.upper()) -+ ) - - # If keytab does not exist, retrieve it - if not os.path.isfile(oneway_keytab_name): -@@ -176,39 +254,78 @@ if not (options.admin and options.password): - have_ccache = False - try: - # The keytab may have stale key material (from older trust-add run) -- cred = kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -+ cred = kinit_keytab( -+ oneway_principal, -+ oneway_keytab_name, -+ oneway_ccache_name, -+ config=cfg, -+ ) - if cred.lifetime > 0: - have_ccache = True -- except gssapi.exceptions.ExpiredCredentialsError: -+ except (gssapi.exceptions.ExpiredCredentialsError, gssapi.raw.misc.GSSError): - pass - if not have_ccache: - if os.path.exists(oneway_ccache_name): - os.unlink(oneway_ccache_name) -- kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -- except gssapi.exceptions.GSSError: -+ kinit_keytab( -+ oneway_principal, -+ oneway_keytab_name, -+ oneway_ccache_name, -+ config=cfg, -+ ) -+ except (gssapi.exceptions.GSSError, gssapi.raw.misc.GSSError): - # If there was failure on using keytab, assume it is stale and retrieve again - retrieve_keytab(api, ccache_name, oneway_keytab_name, oneway_principal) - if os.path.exists(oneway_ccache_name): - os.unlink(oneway_ccache_name) -- kinit_keytab(oneway_principal, oneway_keytab_name, oneway_ccache_name) -+ cred = kinit_keytab( -+ oneway_principal, -+ oneway_keytab_name, -+ oneway_ccache_name, -+ config=cfg, -+ ) - else: -- cred = kinit_password(options.admin, options.password, -- oneway_ccache_name, -- canonicalize=True, enterprise=True) -+ cred = kinit_password( -+ options.admin, -+ options.password, -+ oneway_ccache_name, -+ canonicalize=True, -+ enterprise=True, -+ config=cfg, -+ ) -+ -+if cred and cred.lifetime > 0: -+ have_ccache = True -+ -+if not have_ccache: -+ sys.exit(1) - - # We are done: we have ccache with TDO credentials and can fetch domains - ipa_domain = api.env.domain --os.environ['KRB5CCNAME'] = oneway_ccache_name -+os.environ["KRB5CCNAME"] = oneway_ccache_name -+os.environ["KRB5_CONFIG"] = cfg - - # retrieve the forest root domain name and contact it to retrieve trust - # topology info --forest_root = get_forest_root_domain(api, trusted_domain, server=options.server) -- --domains = dcerpc.fetch_domains(api, ipa_domain, forest_root, creds=True, server=options.server) --trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)['result'] --trust.add_new_domains_from_trust(api, None, trust_domain_object, domains) -+forest_root = get_forest_root_domain( -+ api, trusted_domain, server=options.server -+) -+domains = dcerpc.fetch_domains( -+ api, ipa_domain, forest_root, creds=True, server=options.server -+) - - if old_ccache: -- os.environ['KRB5CCNAME'] = old_ccache -+ os.environ["KRB5CCNAME"] = old_ccache -+ -+if old_config: -+ os.environ["KRB5_CONFIG"] = old_config -+ -+if cfg_file: -+ os.remove(cfg_file) -+ -+trust_domain_object = api.Command.trust_show(trusted_domain, raw=True)[ -+ "result" -+] -+trust.add_new_domains_from_trust(api, None, trust_domain_object, domains) - - sys.exit(0) -diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py -index 5de363bda6fdee081d3e4c98e731cecfa9585d21..676b5f645a99c40a0c944096d7c6252a4c56f983 100644 ---- a/ipaserver/plugins/trust.py -+++ b/ipaserver/plugins/trust.py -@@ -424,11 +424,11 @@ def fetch_trusted_domains_over_dbus(myapi, *keys, **options): - - forest_name = keys[0] - method_options = [] -- if 'realm_server' in options: -+ if options.get('realm_server', None): - method_options.extend(['--server', options['realm_server']]) -- if 'realm_admin' in options: -+ if options.get('realm_admin', None): - method_options.extend(['--admin', options['realm_admin']]) -- if 'realm_passwd' in options: -+ if options.get('realm_passwd', None): - method_options.extend(['--password', options['realm_passwd']]) - - # Calling oddjobd-activated service via DBus has some quirks: -@@ -458,11 +458,15 @@ def fetch_trusted_domains_over_dbus(myapi, *keys, **options): - except dbus.DBusException as e: - logger.error('Failed to call %s.fetch_domains helper.' - 'DBus exception is %s.', DBUS_IFACE_TRUST, str(e)) -- if _ret != 0: -- logger.error('Helper was called for forest %s, return code is %d', -- forest_name, _ret) -- logger.error('Standard output from the helper:\n%s---\n', _stdout) -- logger.error('Error output from the helper:\n%s--\n', _stderr) -+ _ret = 2 -+ _stdout = '' -+ _stderr = '' -+ -+ if _ret != 0: -+ logger.error('Helper fetch_domains was called for forest %s, ' -+ 'return code is %d', forest_name, _ret) -+ logger.error('Standard output from the helper:\n%s---\n', _stdout) -+ logger.error('Error output from the helper:\n%s--\n', _stderr) - raise errors.ServerCommandError( - server=myapi.env.host, - error=_('Fetching domains from trusted forest failed. ' -@@ -801,7 +805,13 @@ ipa idrange-del before retrying the command with the desired range type. - # object credentials to authenticate to AD with Kerberos, - # run DCE RPC calls to do discovery and will call - # add_new_domains_from_trust() on its own. -- fetch_trusted_domains_over_dbus(self.api, result['value']) -+ # We only pass through the realm_server option because we need -+ # to reach the specified Active Directory domain controller -+ # No need to pass through admin credentials as we have TDO -+ # credentials at this point already -+ fetch_trusted_domains_over_dbus(self.api, result['value'], -+ realm_server=options.get( -+ 'realm_server', None)) - - # Format the output into human-readable values unless `--raw` is given - self._format_trust_attrs(result, **options) --- -2.20.1 - diff --git a/SOURCES/0054-add-default-access-control-when-migrating-trust-obje.patch b/SOURCES/0054-add-default-access-control-when-migrating-trust-obje.patch deleted file mode 100644 index d4428ee..0000000 --- a/SOURCES/0054-add-default-access-control-when-migrating-trust-obje.patch +++ /dev/null @@ -1,55 +0,0 @@ -From b1cefe64e4e91966e59d81c778abc8057af4cd6f Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Tue, 10 Sep 2019 13:39:39 +0300 -Subject: [PATCH] add default access control when migrating trust objects - -It looks like for some cases we do not have proper set up keytab -retrieval configuration in the old trusted domain object. This mostly -affects two-way trust cases. In such cases, create default configuration -as ipasam would have created when trust was established. - -Resolves: https://pagure.io/freeipa/issue/8067 - -Signed-off-by: Alexander Bokovoy -Reviewed-By: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/plugins/adtrust.py | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index 12596d5bfe71c16a2cb87acb755a88051676e3e5..0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -28,6 +28,9 @@ logger = logging.getLogger(__name__) - register = Registry() - - DEFAULT_ID_RANGE_SIZE = 200000 -+trust_read_keys_template = \ -+ ["cn=adtrust agents,cn=sysaccounts,cn=etc,{basedn}", -+ "cn=trust admins,cn=groups,cn=accounts,{basedn}"] - - - @register() -@@ -575,8 +578,15 @@ class update_tdo_to_new_layout(Updater): - 'krbprincipalkey') - entry_data['krbextradata'] = en.single_value.get( - 'krbextradata') -- entry_data['ipaAllowedToPerform;read_keys'] = en.get( -- 'ipaAllowedToPerform;read_keys', []) -+ read_keys = en.get('ipaAllowedToPerform;read_keys', []) -+ if not read_keys: -+ # Old style, no ipaAllowedToPerform;read_keys in the entry, -+ # use defaults that ipasam should have set when creating a -+ # trust -+ read_keys = list(map( -+ lambda x: x.format(basedn=self.api.env.basedn), -+ trust_read_keys_template)) -+ entry_data['ipaAllowedToPerform;read_keys'] = read_keys - - entry.update(entry_data) - try: --- -2.20.1 - diff --git a/SOURCES/0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch b/SOURCES/0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch deleted file mode 100644 index baf9ee0..0000000 --- a/SOURCES/0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch +++ /dev/null @@ -1,105 +0,0 @@ -From d45545807106958d924d0b92b3e275ac75c3a6fd Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Thu, 12 Sep 2019 11:21:51 +0300 -Subject: [PATCH] adtrust: add default read_keys permission for TDO objects - -If trusted domain object (TDO) is lacking ipaAllowedToPerform;read_keys -attribute values, it cannot be used by SSSD to retrieve TDO keys and the -whole communication with Active Directory domain controllers will not be -possible. - -This seems to affect trusts which were created before -ipaAllowedToPerform;read_keys permission granting was introduced -(FreeIPA 4.2). Add back the default setting for the permissions which -grants access to trust agents and trust admins. - -Resolves: https://pagure.io/freeipa/issue/8067 - -Signed-off-by: Alexander Bokovoy -Reviewed-By: Florence Blanc-Renaud -Reviewed-By: Rob Crittenden -Reviewed-By: Florence Blanc-Renaud ---- - .../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 a9f5f6a924d330b924d9adb8b7eee728258f27c6..77b910fc26858611e44a5ba3f4f4c18f4895c95e 100644 ---- a/install/updates/90-post_upgrade_plugins.update -+++ b/install/updates/90-post_upgrade_plugins.update -@@ -12,6 +12,7 @@ plugin: update_default_range - plugin: update_default_trust_view - plugin: update_tdo_gidnumber - plugin: update_tdo_to_new_layout -+plugin: update_tdo_default_read_keys_permissions - 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 0dd2c840899abe3b51b9308d38a9d0f4d1fb2f9b..fca83aa6df2cc3fafca91f2ed55339dba016a1fa 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -727,3 +727,59 @@ class update_tdo_to_new_layout(Updater): - self.KRB_PRINC_CREATE_DISABLED) - - return False, [] -+ -+ -+@register() -+class update_tdo_default_read_keys_permissions(Updater): -+ trust_filter = \ -+ "(&(objectClass=krbPrincipal)(krbPrincipalName=krbtgt/{nbt}@*))" -+ -+ 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']: -+ logger.debug('AD Trusts are not enabled on this server') -+ return False, [] -+ -+ result = self.api.Command.trustconfig_show()['result'] -+ our_nbt_name = result.get('ipantflatname', [None])[0] -+ if not our_nbt_name: -+ return False, [] -+ -+ trusts_dn = self.api.env.container_adtrusts + self.api.env.basedn -+ trust_filter = self.trust_filter.format(nbt=our_nbt_name) -+ -+ # We might be in a situation when no trusts exist yet -+ # In such case there is nothing to upgrade but we have to catch -+ # an exception or it will abort the whole upgrade process -+ try: -+ tdos = ldap.get_entries( -+ base_dn=trusts_dn, -+ scope=ldap.SCOPE_SUBTREE, -+ filter=trust_filter, -+ attrs_list=['*']) -+ except errors.EmptyResult: -+ tdos = [] -+ -+ for tdo in tdos: -+ updates = dict() -+ oc = tdo.get('objectClass', []) -+ if 'ipaAllowedOperations' not in oc: -+ updates['objectClass'] = oc + ['ipaAllowedOperations'] -+ -+ read_keys = tdo.get('ipaAllowedToPerform;read_keys', []) -+ if not read_keys: -+ read_keys_values = list(map( -+ lambda x: x.format(basedn=self.api.env.basedn), -+ trust_read_keys_template)) -+ updates['ipaAllowedToPerform;read_keys'] = read_keys_values -+ -+ tdo.update(updates) -+ try: -+ ldap.update_entry(tdo) -+ except errors.EmptyModlist: -+ logger.debug("No update was required for TDO %s", -+ tdo.single_value.get('krbCanonicalName')) -+ -+ return False, [] --- -2.20.1 - diff --git a/SOURCES/0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch b/SOURCES/0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch deleted file mode 100644 index 5fc808c..0000000 --- a/SOURCES/0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch +++ /dev/null @@ -1,38 +0,0 @@ -From a2056fe04b9667c4c86925051b9b71c741eb9cd1 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Mon, 16 Sep 2019 09:38:19 -0400 -Subject: [PATCH] Disable deprecated-lambda check in adtrust upgrade code - -It is interesting that we don't have this problem with newer -Python and pylint versions. Ignoring to try to keep the code -more in line with newer releases. - -Reviewed-By: Rob Crittenden -Reviewed-By: Florence Blanc-Renaud ---- - ipaserver/install/plugins/adtrust.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py -index fca83aa6df2cc3fafca91f2ed55339dba016a1fa..950b7b9c82f1b0e115675ff8093d1bd02e913ae2 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -583,6 +583,7 @@ class update_tdo_to_new_layout(Updater): - # Old style, no ipaAllowedToPerform;read_keys in the entry, - # use defaults that ipasam should have set when creating a - # trust -+ # pylint: disable=deprecated-lambda - read_keys = list(map( - lambda x: x.format(basedn=self.api.env.basedn), - trust_read_keys_template)) -@@ -770,6 +771,7 @@ class update_tdo_default_read_keys_permissions(Updater): - - read_keys = tdo.get('ipaAllowedToPerform;read_keys', []) - if not read_keys: -+ # pylint: disable=deprecated-lambda - read_keys_values = list(map( - lambda x: x.format(basedn=self.api.env.basedn), - trust_read_keys_template)) --- -2.20.1 - diff --git a/SOURCES/0057-Handle-missing-LWCA-certificate-or-chain.patch b/SOURCES/0057-Handle-missing-LWCA-certificate-or-chain.patch deleted file mode 100644 index dccf25c..0000000 --- a/SOURCES/0057-Handle-missing-LWCA-certificate-or-chain.patch +++ /dev/null @@ -1,196 +0,0 @@ -From dc90e83e77f63384f072ca31d79705e26dc5d656 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Thu, 30 May 2019 20:57:10 +1000 -Subject: [PATCH] Handle missing LWCA certificate or chain - -If lightweight CA key replication has not completed, requests for -the certificate or chain will return 404**. This can occur in -normal operation, and should be a temporary condition. Detect this -case and handle it by simply omitting the 'certificate' and/or -'certificate_out' fields in the response, and add a warning message -to the response. - -Also update the client-side plugin that handles the ---certificate-out option. Because the CLI will automatically print -the warning message, if the expected field is missing from the -response, just ignore it and continue processing. - -** after the Dogtag NullPointerException gets fixed! - -Part of: https://pagure.io/freeipa/issue/7964 - -Reviewed-By: Christian Heimes -Reviewed-By: Fraser Tweedale -Reviewed-By: Alexander Bokovoy -Reviewed-By: Rob Crittenden ---- - ipaclient/plugins/ca.py | 19 +++++++++++--- - ipalib/messages.py | 9 +++++++ - ipaserver/plugins/ca.py | 57 +++++++++++++++++++++++++++++++---------- - 3 files changed, 68 insertions(+), 17 deletions(-) - -diff --git a/ipaclient/plugins/ca.py b/ipaclient/plugins/ca.py -index f0e7d5ced0d3d9318e34aba84cbc37cf42b9410d..ab47ae85df398e1dc40191691a26639eb3772493 100644 ---- a/ipaclient/plugins/ca.py -+++ b/ipaclient/plugins/ca.py -@@ -33,13 +33,24 @@ class WithCertOutArgs(MethodOverride): - error=str(e)) - - result = super(WithCertOutArgs, self).forward(*keys, **options) -+ - if filename: -+ # if result certificate / certificate_chain not present in result, -+ # it means Dogtag did not provide it (probably due to LWCA key -+ # replication lag or failure. The server transmits a warning -+ # message in this case, which the client automatically prints. -+ # So in this section we just ignore it and move on. -+ certs = None - if options.get('chain', False): -- certs = result['result']['certificate_chain'] -+ if 'certificate_chain' in result['result']: -+ certs = result['result']['certificate_chain'] - else: -- certs = [base64.b64decode(result['result']['certificate'])] -- certs = (x509.load_der_x509_certificate(cert) for cert in certs) -- x509.write_certificate_list(certs, filename) -+ if 'certificate' in result['result']: -+ certs = [base64.b64decode(result['result']['certificate'])] -+ if certs: -+ x509.write_certificate_list( -+ (x509.load_der_x509_certificate(cert) for cert in certs), -+ filename) - - return result - -diff --git a/ipalib/messages.py b/ipalib/messages.py -index 9e2c990d6db8ee41daf3fba6085eed8355dccbe7..646662795648b5a44a5ce25b7610982d5500cfac 100644 ---- a/ipalib/messages.py -+++ b/ipalib/messages.py -@@ -487,6 +487,15 @@ class FailedToAddHostDNSRecords(PublicMessage): - "%(reason)s") - - -+class LightweightCACertificateNotAvailable(PublicMessage): -+ """ -+ **13031** Certificate is not available -+ """ -+ errno = 13031 -+ type = "error" -+ format = _("The certificate for %(ca)s is not available on this server.") -+ -+ - def iter_messages(variables, base): - """Return a tuple with all subclasses - """ -diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py -index 88e7ec2a9f50a3c4f90947c8e3d38e327627a878..c8f1630c65d55ee9e820ea50ef34e08f92c66f4a 100644 ---- a/ipaserver/plugins/ca.py -+++ b/ipaserver/plugins/ca.py -@@ -6,7 +6,7 @@ import base64 - - import six - --from ipalib import api, errors, output, Bytes, DNParam, Flag, Str -+from ipalib import api, errors, messages, output, Bytes, DNParam, Flag, Str - from ipalib.constants import IPA_CA_CN - from ipalib.plugable import Registry - from ipapython.dn import ATTR_NAME_BY_OID -@@ -163,28 +163,53 @@ class ca(LDAPObject): - - - def set_certificate_attrs(entry, options, want_cert=True): -+ """ -+ Set certificate attributes into the entry. Depending on -+ options, this may contact Dogtag to retrieve certificate or -+ chain. If the retrieval fails with 404 (which can occur under -+ normal operation due to lightweight CA key replication delay), -+ return a message object that should be set in the response. -+ -+ """ - try: - ca_id = entry['ipacaid'][0] - except KeyError: -- return -+ return None - full = options.get('all', False) - want_chain = options.get('chain', False) - - want_data = want_cert or want_chain or full - if not want_data: -- return -+ return None -+ -+ msg = None - - with api.Backend.ra_lightweight_ca as ca_api: - if want_cert or full: -- der = ca_api.read_ca_cert(ca_id) -- entry['certificate'] = base64.b64encode(der).decode('ascii') -+ try: -+ der = ca_api.read_ca_cert(ca_id) -+ entry['certificate'] = base64.b64encode(der).decode('ascii') -+ except errors.HTTPRequestError as e: -+ if e.status == 404: # pylint: disable=no-member -+ msg = messages.LightweightCACertificateNotAvailable( -+ ca=entry['cn'][0]) -+ else: -+ raise e - - if want_chain or full: -- pkcs7_der = ca_api.read_ca_chain(ca_id) -- certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER) -- ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs] -- entry['certificate_chain'] = ders -- -+ try: -+ pkcs7_der = ca_api.read_ca_chain(ca_id) -+ certs = x509.pkcs7_to_certs(pkcs7_der, x509.DER) -+ ders = [cert.public_bytes(x509.Encoding.DER) for cert in certs] -+ entry['certificate_chain'] = ders -+ except errors.HTTPRequestError as e: -+ if e.status == 404: # pylint: disable=no-member -+ msg = messages.LightweightCACertificateNotAvailable( -+ ca=entry['cn'][0]) -+ else: -+ raise e -+ -+ return msg - - @register() - class ca_find(LDAPSearch): -@@ -198,7 +223,9 @@ class ca_find(LDAPSearch): - result = super(ca_find, self).execute(*keys, **options) - if not options.get('pkey_only', False): - for entry in result['result']: -- set_certificate_attrs(entry, options, want_cert=False) -+ msg = set_certificate_attrs(entry, options, want_cert=False) -+ if msg: -+ self.add_message(msg) - return result - - -@@ -220,7 +247,9 @@ class ca_show(LDAPRetrieve): - def execute(self, *keys, **options): - ca_enabled_check(self.api) - result = super(ca_show, self).execute(*keys, **options) -- set_certificate_attrs(result['result'], options) -+ msg = set_certificate_attrs(result['result'], options) -+ if msg: -+ self.add_message(msg) - return result - - -@@ -284,7 +313,9 @@ class ca_add(LDAPCreate): - return dn - - def post_callback(self, ldap, dn, entry_attrs, *keys, **options): -- set_certificate_attrs(entry_attrs, options) -+ msg = set_certificate_attrs(entry_attrs, options) -+ if msg: -+ self.add_message(msg) - return dn - - --- -2.20.1 - diff --git a/SOURCES/0058-Fix-CustodiaClient-ccache-handling.patch b/SOURCES/0058-Fix-CustodiaClient-ccache-handling.patch deleted file mode 100644 index 1d60244..0000000 --- a/SOURCES/0058-Fix-CustodiaClient-ccache-handling.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 240617674f83305b2a27899aa83f6af0caa69c9c Mon Sep 17 00:00:00 2001 -From: Christian Heimes -Date: Wed, 12 Jun 2019 22:02:52 +0200 -Subject: [PATCH] Fix CustodiaClient ccache handling - -A CustodiaClient object has to the process environment a bit, e.g. set -up GSSAPI credentials. To reuse the credentials in libldap connections, -it is also necessary to set up a custom ccache store and to set the -environment variable KRBCCNAME temporarily. - -Fixes: https://pagure.io/freeipa/issue/7964 -Co-Authored-By: Fraser Tweedale -Signed-off-by: Christian Heimes -Reviewed-By: Christian Heimes -Reviewed-By: Fraser Tweedale -Reviewed-By: Alexander Bokovoy -Reviewed-By: Rob Crittenden ---- - install/tools/ipa-pki-retrieve-key | 33 ++++--- - ipaserver/secrets/client.py | 143 ++++++++++++++++------------- - 2 files changed, 100 insertions(+), 76 deletions(-) - -diff --git a/install/tools/ipa-pki-retrieve-key b/install/tools/ipa-pki-retrieve-key -index 5056682c3cdaa734be2dadcffd7de0b2d80afaf9..192022b9b40f076e88fd95d5cc8cf8305901dcf5 100755 ---- a/install/tools/ipa-pki-retrieve-key -+++ b/install/tools/ipa-pki-retrieve-key -@@ -2,9 +2,8 @@ - - from __future__ import print_function - -+import argparse - import os --import sys --import traceback - - from ipalib import constants - from ipalib.config import Env -@@ -16,27 +15,37 @@ def main(): - env = Env() - env._finalize() - -- keyname = "ca_wrapped/" + sys.argv[1] -- servername = sys.argv[2] -+ parser = argparse.ArgumentParser("ipa-pki-retrieve-key") -+ parser.add_argument("keyname", type=str) -+ parser.add_argument("servername", type=str) -+ -+ args = parser.parse_args() -+ keyname = "ca_wrapped/{}".format(args.keyname) - - service = constants.PKI_GSSAPI_SERVICE_NAME - client_keyfile = os.path.join(paths.PKI_TOMCAT, service + '.keys') - client_keytab = os.path.join(paths.PKI_TOMCAT, service + '.keytab') - -+ for filename in [client_keyfile, client_keytab]: -+ if not os.access(filename, os.R_OK): -+ parser.error( -+ "File '{}' missing or not readable.\n".format(filename) -+ ) -+ - # pylint: disable=no-member - client = CustodiaClient( -- client_service='%s@%s' % (service, env.host), server=servername, -- realm=env.realm, ldap_uri="ldaps://" + env.host, -- keyfile=client_keyfile, keytab=client_keytab, -- ) -+ client_service="{}@{}".format(service, env.host), -+ server=args.servername, -+ realm=env.realm, -+ ldap_uri="ldaps://" + env.host, -+ keyfile=client_keyfile, -+ keytab=client_keytab, -+ ) - - # Print the response JSON to stdout; it is already in the format - # that Dogtag's ExternalProcessKeyRetriever expects - print(client.fetch_key(keyname, store=False)) - - --try: -+if __name__ == '__main__': - main() --except BaseException: -- traceback.print_exc() -- sys.exit(1) -diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py -index 16e7856185aa9786007d3b7f8be0652f70fb4518..40df6c4e69cd673dd8e3c36fbf33f2cda8544a67 100644 ---- a/ipaserver/secrets/client.py -+++ b/ipaserver/secrets/client.py -@@ -1,93 +1,106 @@ - # Copyright (C) 2015 IPA Project Contributors, see COPYING for license - - from __future__ import print_function, absolute_import -+ -+import contextlib -+import os -+from base64 import b64encode -+ -+ - # pylint: disable=relative-import - from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC - # pylint: enable=relative-import - from jwcrypto.common import json_decode - from jwcrypto.jwk import JWK -+from ipalib.krb_utils import krb5_format_service_principal_name - from ipaserver.secrets.kem import IPAKEMKeys --from ipaserver.secrets.store import iSecStore -+from ipaserver.secrets.store import IPASecStore - from ipaplatform.paths import paths --from base64 import b64encode --import ldapurl - import gssapi --import os --import urllib3 - import requests - - --class CustodiaClient(object): -- -- def _client_keys(self): -- return self.ikk.server_keys -- -- def _server_keys(self, server, realm): -- principal = 'host/%s@%s' % (server, realm) -- sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG))) -- ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC))) -- return (sk, ek) -- -- def _ldap_uri(self, realm): -- dashrealm = '-'.join(realm.split('.')) -- socketpath = paths.SLAPD_INSTANCE_SOCKET_TEMPLATE % (dashrealm,) -- return 'ldapi://' + ldapurl.ldapUrlEscape(socketpath) -- -- def _keystore(self, realm, ldap_uri, auth_type): -- config = dict() -- if ldap_uri is None: -- config['ldap_uri'] = self._ldap_uri(realm) -- else: -- config['ldap_uri'] = ldap_uri -- if auth_type is not None: -- config['auth_type'] = auth_type -+@contextlib.contextmanager -+def ccache_env(ccache): -+ """Temporarily set KRB5CCNAME environment variable -+ """ -+ orig_ccache = os.environ.get('KRB5CCNAME') -+ os.environ['KRB5CCNAME'] = ccache -+ try: -+ yield -+ finally: -+ os.environ.pop('KRB5CCNAME', None) -+ if orig_ccache is not None: -+ os.environ['KRB5CCNAME'] = orig_ccache - -- return iSecStore(config) - -- def __init__( -- self, client_service, keyfile, keytab, server, realm, -- ldap_uri=None, auth_type=None): -+class CustodiaClient(object): -+ def __init__(self, client_service, keyfile, keytab, server, realm, -+ ldap_uri=None, auth_type=None): -+ if client_service.endswith(realm) or "@" not in client_service: -+ raise ValueError( -+ "Client service name must be a GSS name (service@host), " -+ "not '{}'.".format(client_service) -+ ) - self.client_service = client_service - self.keytab = keytab -- -- # Init creds immediately to make sure they are valid. Creds -- # can also be re-inited by _auth_header to avoid expiry. -- # -- self.creds = self.init_creds() -- -- self.service_name = gssapi.Name('HTTP@%s' % (server,), -- gssapi.NameType.hostbased_service) - self.server = server -+ self.realm = realm -+ self.ldap_uri = ldap_uri -+ self.auth_type = auth_type -+ self.service_name = gssapi.Name( -+ 'HTTP@{}'.format(server), gssapi.NameType.hostbased_service -+ ) -+ self.keystore = IPASecStore() -+ # use in-process MEMORY ccache. Handler process don't need a TGT. -+ token = b64encode(os.urandom(8)).decode('ascii') -+ self.ccache = 'MEMORY:Custodia_{}'.format(token) -+ -+ with ccache_env(self.ccache): -+ # Init creds immediately to make sure they are valid. Creds -+ # can also be re-inited by _auth_header to avoid expiry. -+ self.creds = self._init_creds() -+ -+ self.ikk = IPAKEMKeys( -+ {'server_keys': keyfile, 'ldap_uri': ldap_uri} -+ ) -+ self.kemcli = KEMClient( -+ self._server_keys(), self._client_keys() -+ ) - -- self.ikk = IPAKEMKeys({'server_keys': keyfile, 'ldap_uri': ldap_uri}) -- -- self.kemcli = KEMClient(self._server_keys(server, realm), -- self._client_keys()) -- -- self.keystore = self._keystore(realm, ldap_uri, auth_type) -- -- # FIXME: Remove warnings about missing subjAltName for the -- # requests module -- urllib3.disable_warnings() -+ def _client_keys(self): -+ return self.ikk.server_keys - -- def init_creds(self): -- name = gssapi.Name(self.client_service, -- gssapi.NameType.hostbased_service) -- store = {'client_keytab': self.keytab, -- 'ccache': 'MEMORY:Custodia_%s' % b64encode( -- os.urandom(8)).decode('ascii')} -+ def _server_keys(self): -+ principal = krb5_format_service_principal_name( -+ 'host', self.server, self.realm -+ ) -+ sk = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_SIG))) -+ ek = JWK(**json_decode(self.ikk.find_key(principal, KEY_USAGE_ENC))) -+ return sk, ek -+ -+ def _init_creds(self): -+ name = gssapi.Name( -+ self.client_service, gssapi.NameType.hostbased_service -+ ) -+ store = { -+ 'client_keytab': self.keytab, -+ 'ccache': self.ccache -+ } - return gssapi.Credentials(name=name, store=store, usage='initiate') - - def _auth_header(self): -- if not self.creds or self.creds.lifetime < 300: -- self.creds = self.init_creds() -- ctx = gssapi.SecurityContext(name=self.service_name, creds=self.creds) -+ if self.creds.lifetime < 300: -+ self.creds = self._init_creds() -+ ctx = gssapi.SecurityContext( -+ name=self.service_name, -+ creds=self.creds -+ ) - authtok = ctx.step() - return {'Authorization': 'Negotiate %s' % b64encode( - authtok).decode('ascii')} - - def fetch_key(self, keyname, store=True): -- - # Prepare URL - url = 'https://%s/ipa/keys/%s' % (self.server, keyname) - -@@ -99,9 +112,11 @@ class CustodiaClient(object): - headers = self._auth_header() - - # Perform request -- r = requests.get(url, headers=headers, -- verify=paths.IPA_CA_CRT, -- params={'type': 'kem', 'value': 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.20.1 - diff --git a/SOURCES/0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch b/SOURCES/0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch deleted file mode 100644 index cceae12..0000000 --- a/SOURCES/0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 8b315055de462005b6b3a5893f7131eb8ddd2640 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Wed, 19 Jun 2019 19:11:39 +1000 -Subject: [PATCH] CustodiaClient: use ldapi when ldap_uri not specified - -Reinstate ldap_uri selection behaviour that was lost during the -refactor in the previous commit. This is required because, on the -ipa-4-7 branch at least, the IPASecStore needs to use LDAPI to set -the Directory Manager passphrase digest. Use LDAPI when the -ldap_uri has not been explicity specified. - -Part of: https://pagure.io/freeipa/issue/7964 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Rob Crittenden ---- - ipaserver/secrets/client.py | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py -index 40df6c4e69cd673dd8e3c36fbf33f2cda8544a67..4c03ef8e4140dd507156d88941600a234b71184e 100644 ---- a/ipaserver/secrets/client.py -+++ b/ipaserver/secrets/client.py -@@ -13,6 +13,7 @@ from custodia.message.kem import KEMClient, KEY_USAGE_SIG, KEY_USAGE_ENC - from jwcrypto.common import json_decode - from jwcrypto.jwk import JWK - from ipalib.krb_utils import krb5_format_service_principal_name -+from ipaserver.install.installutils import realm_to_ldapi_uri - from ipaserver.secrets.kem import IPAKEMKeys - from ipaserver.secrets.store import IPASecStore - from ipaplatform.paths import paths -@@ -46,7 +47,7 @@ class CustodiaClient(object): - self.keytab = keytab - self.server = server - self.realm = realm -- self.ldap_uri = ldap_uri -+ self.ldap_uri = ldap_uri or realm_to_ldapi_uri(realm) - self.auth_type = auth_type - self.service_name = gssapi.Name( - 'HTTP@{}'.format(server), gssapi.NameType.hostbased_service --- -2.20.1 - diff --git a/SOURCES/0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch b/SOURCES/0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch deleted file mode 100644 index 4096617..0000000 --- a/SOURCES/0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a42c4c1be12f64228f196b42f30fb57019e3943e Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Tue, 30 Jul 2019 16:21:35 +1000 -Subject: [PATCH] CustodiaClient: fix IPASecStore config on ipa-4-7 - -The backport of a Custodia client fix for f30 and related refactors -and improvements, to the ipa-4-7 branch, had no conflicts. But -there is a change on newer branches that broke the backport. The -running of Custodia handlers in separate processes simplified the -configuration of the ISecStore. For ipa-4-7 we need to continue to -explicitly configure it, so restore the old configuration behaviour. - -Part of: https://pagure.io/freeipa/issue/7964 - -Reviewed-By: Alexander Bokovoy -Reviewed-By: Rob Crittenden ---- - ipaserver/secrets/client.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/secrets/client.py b/ipaserver/secrets/client.py -index 4c03ef8e4140dd507156d88941600a234b71184e..2363b081dbbf3671e8147497bb52811825bdf1a4 100644 ---- a/ipaserver/secrets/client.py -+++ b/ipaserver/secrets/client.py -@@ -52,7 +52,12 @@ class CustodiaClient(object): - self.service_name = gssapi.Name( - 'HTTP@{}'.format(server), gssapi.NameType.hostbased_service - ) -- self.keystore = IPASecStore() -+ -+ config = {'ldap_uri': self.ldap_uri} -+ if auth_type is not None: -+ config['auth_type'] = auth_type -+ self.keystore = IPASecStore(config) -+ - # use in-process MEMORY ccache. Handler process don't need a TGT. - token = b64encode(os.urandom(8)).decode('ascii') - self.ccache = 'MEMORY:Custodia_{}'.format(token) --- -2.20.1 - diff --git a/SOURCES/0061-Bump-krb5-min-version.patch b/SOURCES/0061-Bump-krb5-min-version.patch deleted file mode 100644 index fca1a71..0000000 --- a/SOURCES/0061-Bump-krb5-min-version.patch +++ /dev/null @@ -1,34 +0,0 @@ -From b62a0a59b3a1b07d5b5868ca0061b4af9b97e203 Mon Sep 17 00:00:00 2001 -From: Fraser Tweedale -Date: Wed, 25 Sep 2019 16:43:25 +1000 -Subject: [PATCH] Bump krb5 min version - -krb5-1.15.1-36 introduced a ccache behavioural change that broke -lightweight CA key replication. The preceding commits (backported -from the ipa-4-7 branch) fix this issue but this commit ensure that -the correct version of krb5 is used with the updated FreeIPA code. - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1755223 -Reviewed-By: Rob Crittenden ---- - freeipa.spec.in | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/freeipa.spec.in b/freeipa.spec.in -index a18a5b4aab335ad104f1263fa3ae8b26659c3095..72b328a723dd86c3f84a7c86ec68f224e8880af8 100644 ---- a/freeipa.spec.in -+++ b/freeipa.spec.in -@@ -49,8 +49,8 @@ - - %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 -+# 1.15.1-36: https://bugzilla.redhat.com/show_bug.cgi?id=1755223 -+%global krb5_version 1.15.1-36 - # 0.7.16: https://github.com/drkjam/netaddr/issues/71 - %global python_netaddr_version 0.7.5-8 - # Require 4.7.0 which brings Python 3 bindings --- -2.20.1 - diff --git a/SOURCES/0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch b/SOURCES/0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch deleted file mode 100644 index c54c0a9..0000000 --- a/SOURCES/0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 542297d937d538e3353e06dd052a2e77d594dae8 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Thu, 13 Jun 2019 21:54:58 +0200 -Subject: [PATCH] DL0 replica install: fix nsDS5ReplicaBindDN config -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When setting up a 4.x replica in DL0 from a 3.x replica, the first 4.x -replica installation succeeds but if a second 4.x replica is configured, -the replication is not properly set. - -This happens because the replica setup needs to add nsDS5ReplicaBindDN: -krbprincipalname=ldap/replica@DOMAIN to the entry -cn=replica,cn=...,cn=mapping tree,cn=config in order to allow replication -(on the 3.x master, the replication manager group is not supported yet). - -The issue is that this attribute is added only when the entry -cn=replication managers,cn=sysaccounts,cn=etc,$BASEDN -does not exist. This condition is true for the first replica install but -false for the second replica install. - -The fix consists in checking if the remote server has ds version < 1.3.3 -(in this case it is a 3.x server). If it's the case, the installer -will use nsDS5ReplicaBindDN attribute with the replica krbprincipalname. -Otherwise the nsDS5ReplicaBindDN attribute will use the replication manager -group. - -Fixes: https://pagure.io/freeipa/issue/7976 -Reviewed-By: François Cami ---- - ipaserver/install/replication.py | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py -index 8644b9ff618d28614a319d6da6a2041fea3c1c1f..c188bd6f5e4d13af7b12f5e0528ee135772af7ab 100644 ---- a/ipaserver/install/replication.py -+++ b/ipaserver/install/replication.py -@@ -1730,9 +1730,14 @@ class ReplicationManager(object): - try: - conn.get_entry(self.repl_man_group_dn) - except errors.NotFound: -- self._add_replica_bind_dn(conn, my_dn) - self._add_replication_managers(conn) - -+ # On IPA 3.x masters (ds version < 1.3.3), -+ # add replica bind DN directly into the replica entry -+ vendor_version = get_ds_version(conn) -+ if vendor_version < (1, 3, 3): -+ self._add_replica_bind_dn(conn, my_dn) -+ - self._add_dn_to_replication_managers(conn, my_dn) - self._add_dn_to_replication_managers(conn, remote_dn) - --- -2.23.0 - diff --git a/SOURCES/0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch b/SOURCES/0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch deleted file mode 100644 index 5f74de1..0000000 --- a/SOURCES/0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 85d71239bb974c8d8988c753f63ec12d1b735da3 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 14 Jun 2019 11:13:54 +0200 -Subject: [PATCH] extdom: unify error code handling especially - LDAP_NO_SUCH_OBJECT - -A return code LDAP_NO_SUCH_OBJECT will tell SSSD on the IPA client to -remove the searched object from the cache. As a consequence -LDAP_NO_SUCH_OBJECT should only be returned if the object really does -not exists otherwise the data of existing objects might be removed form -the cache of the clients causing unexpected behaviour like -authentication errors. - -Currently some code-paths use LDAP_NO_SUCH_OBJECT as default error code. -With this patch LDAP_NO_SUCH_OBJECT is only returned if the related -lookup functions return ENOENT. Timeout related error code will lead to -LDAP_TIMELIMIT_EXCEEDED and LDAP_OPERATIONS_ERROR is used as default -error code. - -Fixes: https://pagure.io/freeipa/issue/8044 -Reviewed-By: Alexander Bokovoy ---- - .../ipa-extdom-extop/back_extdom_sss_idmap.c | 4 +- - .../ipa-extdom-extop/ipa_extdom_common.c | 77 ++++++++++++++----- - .../ipa-extdom-extop/ipa_extdom_extop.c | 2 + - 3 files changed, 61 insertions(+), 22 deletions(-) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c -index 89c58ca2de333b26954d916836b57aed5d7e18fb..64b90e3ae8abc40edaaed91601cdded30db35294 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/back_extdom_sss_idmap.c -@@ -47,10 +47,10 @@ static enum nss_status __convert_sss_nss2nss_status(int errcode) { - return NSS_STATUS_SUCCESS; - case ENOENT: - return NSS_STATUS_NOTFOUND; -- case ETIME: -- /* fall-through */ - case ERANGE: - return NSS_STATUS_TRYAGAIN; -+ case ETIME: -+ /* fall-through */ - case ETIMEDOUT: - /* fall-through */ - default: -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 1b93dce18671756fe9019378ce61e556697ad902..134b623773df418dc47edaf67045e5f4cfff9782 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 -@@ -523,7 +523,7 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, - if (strcasecmp(locat+1, domain_name) == 0 ) { - locat[0] = '\0'; - } else { -- ret = LDAP_NO_SUCH_OBJECT; -+ ret = LDAP_INVALID_SYNTAX; - goto done; - } - } -@@ -568,10 +568,12 @@ int pack_ber_user(struct ipa_extdom_ctx *ctx, - ret = getgrgid_r_wrapper(ctx, - groups[c], &grp, &buf, &buf_len); - if (ret != 0) { -- if (ret == ENOMEM || ret == ERANGE) { -- ret = LDAP_OPERATIONS_ERROR; -- } else { -+ if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ } else { -+ ret = LDAP_OPERATIONS_ERROR; - } - goto done; - } -@@ -634,7 +636,7 @@ int pack_ber_group(enum response_types response_type, - if (strcasecmp(locat+1, domain_name) == 0 ) { - locat[0] = '\0'; - } else { -- ret = LDAP_NO_SUCH_OBJECT; -+ ret = LDAP_INVALID_SYNTAX; - goto done; - } - } -@@ -836,6 +838,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, - || id_type == SSS_ID_TYPE_BOTH)) { - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - set_err_msg(req, "Failed to lookup SID by UID"); - ret = LDAP_OPERATIONS_ERROR; -@@ -847,10 +851,12 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, - } else { - ret = getpwuid_r_wrapper(ctx, uid, &pwd, &buf, &buf_len); - if (ret != 0) { -- if (ret == ENOMEM || ret == ERANGE) { -- ret = LDAP_OPERATIONS_ERROR; -- } else { -+ if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ } else { -+ ret = LDAP_OPERATIONS_ERROR; - } - goto done; - } -@@ -862,6 +868,8 @@ static int handle_uid_request(struct ipa_extdom_ctx *ctx, - set_err_msg(req, "Failed to read original data"); - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - ret = LDAP_OPERATIONS_ERROR; - } -@@ -907,6 +915,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, - if (ret != 0 || id_type != SSS_ID_TYPE_GID) { - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - set_err_msg(req, "Failed to lookup SID by GID"); - ret = LDAP_OPERATIONS_ERROR; -@@ -918,10 +928,12 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, - } else { - ret = getgrgid_r_wrapper(ctx, gid, &grp, &buf, &buf_len); - if (ret != 0) { -- if (ret == ENOMEM || ret == ERANGE) { -- ret = LDAP_OPERATIONS_ERROR; -- } else { -+ if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ } else { -+ ret = LDAP_OPERATIONS_ERROR; - } - goto done; - } -@@ -933,6 +945,8 @@ static int handle_gid_request(struct ipa_extdom_ctx *ctx, - set_err_msg(req, "Failed to read original data"); - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - ret = LDAP_OPERATIONS_ERROR; - } -@@ -976,6 +990,8 @@ static int handle_cert_request(struct ipa_extdom_ctx *ctx, - if (ret != 0) { - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - set_err_msg(req, "Failed to lookup name by certificate"); - ret = LDAP_OPERATIONS_ERROR; -@@ -1020,6 +1036,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - if (ret != 0) { - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - set_err_msg(req, "Failed to lookup name by SID"); - ret = LDAP_OPERATIONS_ERROR; -@@ -1057,10 +1075,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - case SSS_ID_TYPE_BOTH: - ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len); - if (ret != 0) { -- if (ret == ENOMEM || ret == ERANGE) { -- ret = LDAP_OPERATIONS_ERROR; -- } else { -+ if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ } else { -+ ret = LDAP_OPERATIONS_ERROR; - } - goto done; - } -@@ -1072,6 +1092,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - set_err_msg(req, "Failed to read original data"); - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - ret = LDAP_OPERATIONS_ERROR; - } -@@ -1089,10 +1111,12 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - case SSS_ID_TYPE_GID: - ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len); - if (ret != 0) { -- if (ret == ENOMEM || ret == ERANGE) { -- ret = LDAP_OPERATIONS_ERROR; -- } else { -+ if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ } else { -+ ret = LDAP_OPERATIONS_ERROR; - } - goto done; - } -@@ -1104,6 +1128,8 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx, - set_err_msg(req, "Failed to read original data"); - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - ret = LDAP_OPERATIONS_ERROR; - } -@@ -1167,6 +1193,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - if (ret != 0) { - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - set_err_msg(req, "Failed to lookup SID by name"); - ret = LDAP_OPERATIONS_ERROR; -@@ -1190,6 +1218,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - set_err_msg(req, "Failed to read original data"); - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - ret = LDAP_OPERATIONS_ERROR; - } -@@ -1205,6 +1235,9 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - } else if (ret == ENOMEM || ret == ERANGE) { - ret = LDAP_OPERATIONS_ERROR; - goto done; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ goto done; - } else { /* no user entry found */ - /* according to the getpwnam() man page there are a couple of - * error codes which can indicate that the user was not found. To -@@ -1212,10 +1245,12 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - * errors. */ - ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len); - if (ret != 0) { -- if (ret == ENOMEM || ret == ERANGE) { -- ret = LDAP_OPERATIONS_ERROR; -- } else { -+ if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; -+ } else { -+ ret = LDAP_OPERATIONS_ERROR; - } - goto done; - } -@@ -1226,6 +1261,8 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx, - || id_type == SSS_ID_TYPE_BOTH)) { - if (ret == ENOENT) { - ret = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == ETIMEDOUT || ret == ETIME) { -+ ret = LDAP_TIMELIMIT_EXCEEDED; - } else { - set_err_msg(req, "Failed to read original data"); - ret = LDAP_OPERATIONS_ERROR; -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -index 10d3f86ebad920fb9c051aa428cbd675b682f14a..48fcecc1eeb8f2ad6a3bc8791fe94f4ed54fe74d 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c -@@ -242,6 +242,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb) - if (ret != LDAP_SUCCESS) { - if (ret == LDAP_NO_SUCH_OBJECT) { - rc = LDAP_NO_SUCH_OBJECT; -+ } else if (ret == LDAP_TIMELIMIT_EXCEEDED) { -+ rc = LDAP_TIMELIMIT_EXCEEDED; - } else { - rc = LDAP_OPERATIONS_ERROR; - err_msg = "Failed to handle the request.\n"; --- -2.23.0 - diff --git a/SOURCES/0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch b/SOURCES/0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch deleted file mode 100644 index 265e9da..0000000 --- a/SOURCES/0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 52d90782c1a7ebe5bd984b7560d71a06fe3fb76b Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 19 Aug 2019 10:15:50 +0300 -Subject: [PATCH] ipa-extdom-extop: test timed out getgrgid_r - -Simulate getgrgid_r() timeout when packing list of groups user is a -member of in pack_ber_user(). - -Related: https://pagure.io/freeipa/issue/8044 -Reviewed-By: Alexander Bokovoy ---- - .../ipa_extdom_cmocka_tests.c | 29 +++++++++++++++++++ - 1 file changed, 29 insertions(+) - -diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -index 29699cfa390f5469d7c009388b90e68616cbf984..1fa4c6af823d290412496b5823b90873375f2769 100644 ---- a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -+++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_cmocka_tests.c -@@ -493,6 +493,34 @@ void test_set_err_msg(void **state) - #define TEST_SID "S-1-2-3-4" - #define TEST_DOMAIN_NAME "DOMAIN" - -+/* Always time out for test */ -+static -+enum nss_status getgrgid_r_timeout(gid_t gid, struct group *result, -+ char *buffer, size_t buflen, int *errnop) { -+ return NSS_STATUS_UNAVAIL; -+} -+ -+void test_pack_ber_user_timeout(void **state) -+{ -+ int ret; -+ struct berval *resp_val = NULL; -+ struct test_data *test_data; -+ enum nss_status (*oldgetgrgid_r)(gid_t gid, struct group *result, -+ char *buffer, size_t buflen, int *errnop); -+ -+ test_data = (struct test_data *) *state; -+ -+ oldgetgrgid_r = test_data->ctx->nss_ctx->getgrgid_r; -+ test_data->ctx->nss_ctx->getgrgid_r = getgrgid_r_timeout; -+ -+ ret = pack_ber_user(test_data->ctx, RESP_USER_GROUPLIST, -+ TEST_DOMAIN_NAME, "member001", 12345, 54321, -+ "gecos", "homedir", "shell", NULL, &resp_val); -+ test_data->ctx->nss_ctx->getgrgid_r = oldgetgrgid_r; -+ assert_int_equal(ret, LDAP_TIMELIMIT_EXCEEDED); -+ ber_bvfree(resp_val); -+} -+ - char res_sid[] = {0x30, 0x0e, 0x0a, 0x01, 0x01, 0x04, 0x09, 0x53, 0x2d, 0x31, \ - 0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34}; - char res_nam[] = {0x30, 0x13, 0x0a, 0x01, 0x02, 0x30, 0x0e, 0x04, 0x06, 0x44, \ -@@ -614,6 +642,7 @@ void test_decode(void **state) - int main(int argc, const char *argv[]) - { - const struct CMUnitTest tests[] = { -+ cmocka_unit_test(test_pack_ber_user_timeout), - cmocka_unit_test(test_getpwnam_r_wrapper), - cmocka_unit_test(test_getpwuid_r_wrapper), - cmocka_unit_test(test_getgrnam_r_wrapper), --- -2.23.0 - diff --git a/SOURCES/0065-Make-sure-to-have-storage-space-for-tag.patch b/SOURCES/0065-Make-sure-to-have-storage-space-for-tag.patch deleted file mode 100644 index 7ebf209..0000000 --- a/SOURCES/0065-Make-sure-to-have-storage-space-for-tag.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 61db30080726bfc4832b8516b335734a5246ac0b Mon Sep 17 00:00:00 2001 -From: Simo Sorce -Date: Mon, 16 Sep 2019 11:12:25 -0400 -Subject: [PATCH] Make sure to have storage space for tag - -ber_scanf expects a pointer to a ber_tag_t to return the tag pointed at -by "t", if that is not provided the pointer will be store in whatever -memory location is pointed by the stack at that time causeing a crash. - -Note that this is effectively unused code because in ipa-kdb the only -party that can write a key_data structure to be stored is te kdb_driver -itself and we never encode these s2kparam data. - -But we need to handle this for future proofing. - -Fixes #8071 - -Signed-off-by: Simo Sorce -Reviewed-By: Christian Heimes ---- - util/ipa_krb5.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c -index a27cd4a4e538c738c6ab2157a4daabf8fea7661c..c09c3daa505655f2e5292a79c03683faa75ad244 100644 ---- a/util/ipa_krb5.c -+++ b/util/ipa_krb5.c -@@ -554,7 +554,7 @@ int ber_decode_krb5_key_data(struct berval *encoded, int *m_kvno, - retag = ber_peek_tag(be, &setlen); - if (retag == (LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2)) { - /* not supported yet, skip */ -- retag = ber_scanf(be, "t[x]}"); -+ retag = ber_scanf(be, "t[x]}", &tag); - } else { - retag = ber_scanf(be, "}"); - } --- -2.23.0 - diff --git a/SOURCES/0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch b/SOURCES/0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch deleted file mode 100644 index d376429..0000000 --- a/SOURCES/0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch +++ /dev/null @@ -1,147 +0,0 @@ -From 84317f86f9c96805cf365784794142e65cfbb310 Mon Sep 17 00:00:00 2001 -From: Rob Crittenden -Date: Tue, 2 Jul 2019 13:44:48 -0400 -Subject: [PATCH] CVE-2019-10195: Don't log passwords embedded in commands in - calls using batch - -A raw batch request was fully logged which could expose parameters -we don't want logged, like passwords. - -Override _repr_iter to use the individual commands to log the -values so that values are properly obscured. - -In case of errors log the full value on when the server is in -debug mode. - -Reported by Jamison Bennett from Cloudera - -Signed-off-by: Rob Crittenden -Reviewed-by: Florence Blanc-Renaud ---- - ipaserver/plugins/batch.py | 96 ++++++++++++++++++++++++++++---------- - 1 file changed, 72 insertions(+), 24 deletions(-) - -diff --git a/ipaserver/plugins/batch.py b/ipaserver/plugins/batch.py -index 2794db895a014a6129654889289815d4286cf7f4..9df367d16234d1840a2e5297cdd5c3c59fa4828f 100644 ---- a/ipaserver/plugins/batch.py -+++ b/ipaserver/plugins/batch.py -@@ -92,35 +92,82 @@ class batch(Command): - Output('results', (list, tuple), doc='') - ) - -+ def _validate_request(self, request): -+ """ -+ Check that an individual request in a batch is parseable and the -+ commands exists. -+ """ -+ if 'method' not in request: -+ raise errors.RequirementError(name='method') -+ if 'params' not in request: -+ raise errors.RequirementError(name='params') -+ name = request['method'] -+ if (name not in self.api.Command or -+ isinstance(self.api.Command[name], Local)): -+ raise errors.CommandError(name=name) -+ -+ # If params are not formated as a tuple(list, dict) -+ # the following lines will raise an exception -+ # that triggers an internal server error -+ # Raise a ConversionError instead to report the issue -+ # to the client -+ try: -+ a, kw = request['params'] -+ newkw = dict((str(k), v) for k, v in kw.items()) -+ api.Command[name].args_options_2_params(*a, **newkw) -+ except (AttributeError, ValueError, TypeError): -+ raise errors.ConversionError( -+ name='params', -+ error=_(u'must contain a tuple (list, dict)')) -+ except Exception as e: -+ raise errors.ConversionError( -+ name='params', -+ error=str(e)) -+ -+ def _repr_iter(self, **params): -+ """ -+ Iterate through the request and use the Command _repr_intr so -+ that sensitive information (passwords) is not exposed. -+ -+ In case of a malformatted request redact the entire thing. -+ """ -+ exceptions = False -+ for arg in (params.get('methods', [])): -+ try: -+ self._validate_request(arg) -+ except Exception: -+ # redact the whole request since we don't know what's in it -+ exceptions = True -+ yield u'********' -+ continue -+ -+ name = arg['method'] -+ a, kw = arg['params'] -+ newkw = dict((str(k), v) for k, v in kw.items()) -+ param = api.Command[name].args_options_2_params( -+ *a, **newkw) -+ -+ yield '{}({})'.format( -+ api.Command[name].name, -+ ', '.join(api.Command[name]._repr_iter(**param)) -+ ) -+ -+ if exceptions: -+ logger.debug('batch: %s', -+ ', '.join(super(batch, self)._repr_iter(**params))) -+ - def execute(self, methods=None, **options): - results = [] - for arg in (methods or []): - params = dict() - name = None - try: -- if 'method' not in arg: -- raise errors.RequirementError(name='method') -- if 'params' not in arg: -- raise errors.RequirementError(name='params') -+ self._validate_request(arg) - name = arg['method'] -- if (name not in self.api.Command or -- isinstance(self.api.Command[name], Local)): -- raise errors.CommandError(name=name) -- -- # If params are not formated as a tuple(list, dict) -- # the following lines will raise an exception -- # that triggers an internal server error -- # Raise a ConversionError instead to report the issue -- # to the client -- try: -- a, kw = arg['params'] -- newkw = dict((str(k), v) for k, v in kw.items()) -- params = api.Command[name].args_options_2_params( -- *a, **newkw) -- except (AttributeError, ValueError, TypeError): -- raise errors.ConversionError( -- name='params', -- error=_(u'must contain a tuple (list, dict)')) -+ a, kw = arg['params'] -+ newkw = dict((str(k), v) for k, v in kw.items()) -+ params = api.Command[name].args_options_2_params( -+ *a, **newkw) - newkw.setdefault('version', options['version']) - - result = api.Command[name](*a, **newkw) -@@ -132,8 +179,9 @@ class batch(Command): - ) - result['error']=None - except Exception as e: -- if isinstance(e, errors.RequirementError) or \ -- isinstance(e, errors.CommandError): -+ if (isinstance(e, errors.RequirementError) or -+ isinstance(e, errors.CommandError) or -+ isinstance(e, errors.ConversionError)): - logger.info( - '%s: batch: %s', - context.principal, # pylint: disable=no-member --- -2.23.0 - diff --git a/SOURCES/0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch b/SOURCES/0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch deleted file mode 100644 index 1775c62..0000000 --- a/SOURCES/0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch +++ /dev/null @@ -1,110 +0,0 @@ -From de19fe67c341d99171afda61f6419a80c757b0f7 Mon Sep 17 00:00:00 2001 -From: Florence Blanc-Renaud -Date: Tue, 3 Dec 2019 12:56:22 +0100 -Subject: [PATCH] trust upgrade: ensure that host is member of adtrust agents - -After an upgrade, the group cn=adtrust agents may be missing some members. -Each ad trust controller must appear twice as member: -- krbprincipalname=cifs/hostname@realm,cn=services,cn=accounts,basedn -- fqdn=hostname,cn=computers,cn=accounts,basedn - -Add an upgrade plugin that builds a list of hostnames from the cifs -principals and adds if needed fqdn=hostname... - -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1778777 -Signed-off-by: Florence Blanc-Renaud -Reviewed-By: Alexander Bokovoy -Reviewed-By: Alexander Bokovoy ---- - .../updates/90-post_upgrade_plugins.update | 1 + - ipaserver/install/plugins/adtrust.py | 55 +++++++++++++++++++ - 2 files changed, 56 insertions(+) - -diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update -index 77b910fc26858611e44a5ba3f4f4c18f4895c95e..1d9e8bba8486df197fc9a3e9f83df360f55ca251 100644 ---- a/install/updates/90-post_upgrade_plugins.update -+++ b/install/updates/90-post_upgrade_plugins.update -@@ -13,6 +13,7 @@ plugin: update_default_trust_view - plugin: update_tdo_gidnumber - plugin: update_tdo_to_new_layout - plugin: update_tdo_default_read_keys_permissions -+plugin: update_adtrust_agents_members - 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 950b7b9c82f1b0e115675ff8093d1bd02e913ae2..3da8c9e2021c1ee9cb59a90e9fe269d86e9c337a 100644 ---- a/ipaserver/install/plugins/adtrust.py -+++ b/ipaserver/install/plugins/adtrust.py -@@ -8,9 +8,11 @@ from ipalib import Updater - from ipapython.dn import DN - from ipapython import ipautil - from ipaplatform.paths import paths -+from ipaserver.install import service - from ipaserver.install import sysupgrade - from ipaserver.install.adtrustinstance import ( - ADTRUSTInstance, map_Guests_to_nobody) -+ - from ipaserver.dcerpc_common import TRUST_BIDIRECTIONAL - - try: -@@ -785,3 +787,56 @@ class update_tdo_default_read_keys_permissions(Updater): - tdo.single_value.get('krbCanonicalName')) - - return False, [] -+ -+ -+@register() -+class update_adtrust_agents_members(Updater): -+ """ Ensure that each adtrust agent is a member of the adtrust agents group -+ -+ cn=adtrust agents,cn=sysaccounts,cn=etc,$BASEDN must contain: -+ - member: krbprincipalname=cifs/master@realm,cn=services,cn=accounts,base -+ - member: fqdn=master,cn=computers,cn=accounts,base -+ """ -+ 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']: -+ logger.debug('AD Trusts are not enabled on this server') -+ return False, [] -+ -+ agents_dn = DN( -+ ('cn', 'adtrust agents'), ('cn', 'sysaccounts'), -+ ('cn', 'etc'), self.api.env.basedn) -+ -+ try: -+ agents_entry = ldap.get_entry(agents_dn, ['member']) -+ except errors.NotFound: -+ logger.error("No adtrust agents group found") -+ return False, [] -+ -+ # Build a list of agents from the cifs/.. members -+ agents_list = [] -+ members = agents_entry.get('member', []) -+ suffix = '@{}'.format(self.api.env.realm).lower() -+ -+ for amember in members: -+ if amember[0].attr.lower() == 'krbprincipalname': -+ # Extract krbprincipalname=cifs/hostname@realm from the DN -+ value = amember[0].value -+ if (value.lower().startswith('cifs/') and -+ value.lower().endswith(suffix)): -+ # 5 = length of 'cifs/' -+ hostname = value[5:-len(suffix)] -+ agents_list.append(DN(('fqdn', hostname), -+ self.api.env.container_host, -+ self.api.env.basedn)) -+ -+ # Add the fqdn=hostname... to the group -+ service.add_principals_to_group( -+ ldap, -+ agents_dn, -+ "member", -+ agents_list) -+ -+ return False, [] --- -2.23.0 - diff --git a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch index 24b7c73..9cae834 100644 --- a/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch +++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch @@ -1,4 +1,4 @@ -From 1a992ce1275797ef376e6c137d10f412b92db9db Mon Sep 17 00:00:00 2001 +From 631d69c25e8211721bd4127dd84a5b41beccb995 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 @@ -90,7 +90,7 @@ index d95790a366aac4635e32bbc6bc81773bb9a52e68..431b395a907b6978d9e0dba9870ed0bd 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 +index e6a32fba432d75dfce0cfc0a9bc7264c4beca2ae..5c3fdb118522c12f93e82bb39572ba1e2a1908a2 100644 --- a/client/man/ipa-client-automount.1 +++ b/client/man/ipa-client-automount.1 @@ -16,7 +16,7 @@ @@ -570,7 +570,7 @@ index 6451f3545e8a133efbcfcfeb21ffdda2a1849367..ed441e3bea9aa9b60fd589bd63897a37 ipa\-replica\-conncheck \- Check a replica\-master network connection before installation .SH "SYNOPSIS" diff --git a/install/tools/man/ipa-replica-install.1 b/install/tools/man/ipa-replica-install.1 -index a1284135ac67de2b67b322aec3f6bbfb05f1a8ec..4301128afc65780ab73654d8c213a4f8ce4763a2 100644 +index 12764b8994a04bf56e80492bdcc66578a1f991e0..df403a3ff0c56c8cb7026569c71c94187d2226b7 100644 --- a/install/tools/man/ipa-replica-install.1 +++ b/install/tools/man/ipa-replica-install.1 @@ -1,7 +1,7 @@ @@ -1036,7 +1036,7 @@ index 006bc92bec581e1983f11bfd75498b5484f2567a..6302c4cf0798aab420198975c01874a8 ''' diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py -index c1e593e467cdb856a4ab3251ee103f3da3386a82..78169b501809fcd4db43e433ca4a1693d0c2b92f 100644 +index 5ea4f2e1cc80c995997888aaf44f500524beb796..8bea61fd7ddeff0790b9d875afd24680532dbed9 100644 --- a/ipaserver/install/server/install.py +++ b/ipaserver/install/server/install.py @@ -387,7 +387,7 @@ def install_check(installer): @@ -1049,7 +1049,7 @@ index c1e593e467cdb856a4ab3251ee103f3da3386a82..78169b501809fcd4db43e433ca4a1693 print("This includes:") if setup_ca: diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py -index e13b7f18c4d4df7efde50ac9cb7d2f71bfa765cc..7f23414516e718d95ce510d20885240c6dc976b5 100644 +index 14e8b2c3a76525c6ec2a16ca26fa032aab694a59..bff4a0b501ac519c373ea045a721efaeb2d74e13 100644 --- a/ipaserver/install/server/replicainstall.py +++ b/ipaserver/install/server/replicainstall.py @@ -628,7 +628,7 @@ def check_domain_level_is_supported(current): @@ -1075,7 +1075,7 @@ index 5e8dbca0469bb0234449cce09e20212886fc3f9e..ffc5fcb4c491dbf33606eae80f9092d3 - When importing a profile the "profileId" field, if present, must match the ID given on the command line. diff --git a/ipaserver/plugins/sudorule.py b/ipaserver/plugins/sudorule.py -index 6037938330f13a30d0ccfbedcaac59c567bda0d6..b8a0c82d394edb8744de34394895b86fae2c321f 100644 +index 643215985e932cae6e8d954596194032655b25d4..68baa0174ed88ede3f42092fb68150b55962574e 100644 --- a/ipaserver/plugins/sudorule.py +++ b/ipaserver/plugins/sudorule.py @@ -47,7 +47,7 @@ give certain users (or groups of users) the ability to run some (or all) diff --git a/SOURCES/1002-Package-copy-schema-to-ca.py.patch b/SOURCES/1002-Package-copy-schema-to-ca.py.patch index 22b39aa..c96f4a6 100644 --- a/SOURCES/1002-Package-copy-schema-to-ca.py.patch +++ b/SOURCES/1002-Package-copy-schema-to-ca.py.patch @@ -1,4 +1,4 @@ -From b2dadbd58f3203c5d798286e9a3d8da339a5d9ed Mon Sep 17 00:00:00 2001 +From a483fba7c235e8d4eba90c289594e76e85f4d8e4 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Tue, 14 Mar 2017 16:07:15 +0000 Subject: [PATCH] Package copy-schema-to-ca.py @@ -10,7 +10,7 @@ This reverts commit f4c7f1dd8a9ce530a8291219a904686ee47e59c7. 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in -index 72b328a723dd86c3f84a7c86ec68f224e8880af8..488cf9c02be3e96ffde7ab2f2c3d80b9c82d428a 100644 +index 0f96778f758cb21c01e31ff35e70c79f020aa2d3..c71b257cd9a28c083c8bc95d13a4c1351916a385 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -1489,6 +1489,7 @@ fi diff --git a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch index 91deb73..b3104cc 100644 --- a/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch +++ b/SOURCES/1003-Revert-Increased-mod_wsgi-socket-timeout.patch @@ -1,4 +1,4 @@ -From c0e54fa7d42af945fd42261be4ebac90c9641316 Mon Sep 17 00:00:00 2001 +From 0898c40288721ab83f099c34b8d21cab29f931e2 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Wed, 22 Jun 2016 13:53:46 +0200 Subject: [PATCH] Revert "Increased mod_wsgi socket-timeout" diff --git a/SOURCES/1004-Remove-csrgen.patch b/SOURCES/1004-Remove-csrgen.patch index 23d1a61..b4f58d3 100644 --- a/SOURCES/1004-Remove-csrgen.patch +++ b/SOURCES/1004-Remove-csrgen.patch @@ -1,4 +1,4 @@ -From 376335dad5438a082e411daf34edb39e738861a5 Mon Sep 17 00:00:00 2001 +From 5132d5d27355c6817dfc5c7807b95c457bcaef39 Mon Sep 17 00:00:00 2001 From: Jan Cholasta Date: Thu, 16 Mar 2017 09:44:21 +0000 Subject: [PATCH] Remove csrgen @@ -39,7 +39,7 @@ https://bugzilla.redhat.com/show_bug.cgi?id=1432630 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl diff --git a/freeipa.spec.in b/freeipa.spec.in -index 488cf9c02be3e96ffde7ab2f2c3d80b9c82d428a..6636b9474564ab48d2f804c3854d33a1b071f2c8 100644 +index c71b257cd9a28c083c8bc95d13a4c1351916a385..8182b67e56fa16d636046a45b8fbc873a908cf45 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -248,7 +248,6 @@ BuildRequires: python2-sssdconfig diff --git a/SOURCES/1005-Removing-filesystem-encoding-check.patch b/SOURCES/1005-Removing-filesystem-encoding-check.patch index 0791d59..8a2e552 100644 --- a/SOURCES/1005-Removing-filesystem-encoding-check.patch +++ b/SOURCES/1005-Removing-filesystem-encoding-check.patch @@ -1,4 +1,4 @@ -From 53dea5370de10eef64a11fede6e2033f13fd2b25 Mon Sep 17 00:00:00 2001 +From 9911f805582d68a98728b76b273f691f2beb45da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tibor=20Dudl=C3=A1k?= Date: Fri, 10 Aug 2018 13:16:38 +0200 Subject: [PATCH] Removing filesystem encoding check diff --git a/SOURCES/ipa-centos-branding.patch b/SOURCES/ipa-centos-branding.patch deleted file mode 100644 index 673cd2f..0000000 --- a/SOURCES/ipa-centos-branding.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 99efecaf87dc1fc9517efaff441a6a7ce46444eb Mon Sep 17 00:00:00 2001 -From: Jim Perrin -Date: Wed, 11 Mar 2015 10:37:03 -0500 -Subject: [PATCH] update for new ntp server method - ---- - ipaplatform/base/paths.py | 1 + - ipaserver/install/ntpinstance.py | 2 ++ - 2 files changed, 3 insertions(+) - -diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py -index af50262..5090062 100644 ---- a/ipaplatform/base/paths.py -+++ b/ipaplatform/base/paths.py -@@ -99,6 +99,7 @@ class BasePathNamespace(object): - PKI_TOMCAT_ALIAS_DIR = "/etc/pki/pki-tomcat/alias/" - PKI_TOMCAT_PASSWORD_CONF = "/etc/pki/pki-tomcat/password.conf" - ETC_REDHAT_RELEASE = "/etc/redhat-release" -+ ETC_CENTOS_RELEASE = "/etc/centos-release" - RESOLV_CONF = "/etc/resolv.conf" - SAMBA_KEYTAB = "/etc/samba/samba.keytab" - SMB_CONF = "/etc/samba/smb.conf" -diff --git a/ipaserver/install/ntpinstance.py b/ipaserver/install/ntpinstance.py -index c653525..4b0578b 100644 ---- a/ipaserver/install/ntpinstance.py -+++ b/ipaserver/install/ntpinstance.py -@@ -44,6 +44,8 @@ class NTPInstance(service.Service): - os = "" - if ipautil.file_exists(paths.ETC_FEDORA_RELEASE): - os = "fedora" -+ elif ipautil.file_exists(paths.ETC_CENTOS_RELEASE): -+ os = "centos" - elif ipautil.file_exists(paths.ETC_REDHAT_RELEASE): - os = "rhel" - --- -1.8.3.1 - diff --git a/SPECS/ipa.spec b/SPECS/ipa.spec index f795a72..2ff1336 100644 --- a/SPECS/ipa.spec +++ b/SPECS/ipa.spec @@ -44,8 +44,8 @@ %if 0%{?rhel} # 1.15.1-36: https://bugzilla.redhat.com/show_bug.cgi?id=1755223 %global krb5_version 1.15.1-36 -# Require 4.6.0-4 which brings RC4 for FIPS + trust fixes to priv. separation -%global samba_version 4.7.0 +# Require 4.10 for change in ABI for DEBUGLEVEL_CLASS (rename) +%global samba_version 4.10.0 # 0.7.16: https://github.com/drkjam/netaddr/issues/71 %global python_netaddr_version 0.7.5-9 %global selinux_policy_version 3.13.1-224 @@ -93,7 +93,7 @@ # Work-around fact that RPM SPEC parser does not accept # "Version: @VERSION@" in freeipa.spec.in used for Autoconf string replacement -%define IPA_VERSION 4.6.5 +%define IPA_VERSION 4.6.6 %define AT_SIGN @ # redefine IPA_VERSION only if its value matches the Autoconf placeholder %if "%{IPA_VERSION}" == "%{AT_SIGN}VERSION%{AT_SIGN}" @@ -102,7 +102,7 @@ Name: ipa Version: %{IPA_VERSION} -Release: 11%{?dist}.4 +Release: 11%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base @@ -110,80 +110,42 @@ License: GPLv3+ URL: http://www.freeipa.org/ Source0: https://releases.pagure.org/freeipa/freeipa-%{version}.tar.gz # RHEL spec file only: START: Change branding to IPA and Identity Management -#Source1: header-logo.png -#Source2: login-screen-background.jpg -#Source4: product-name.png +Source1: header-logo.png +Source2: login-screen-background.jpg +Source4: product-name.png # RHEL spec file only: END: Change branding to IPA and Identity Management BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) # RHEL spec file only: START -Patch0001: 0001-Coverity-fix-issue-in-ipa_extdom_extop.c.patch -Patch0002: 0002-Web-UI-topology-graph-Show-FQDN-for-nodes-if-they-ha.patch -Patch0003: 0003-ipa-replica-manage-fix-force-sync.patch -Patch0004: 0004-Unify-and-simplify-LDAP-service-discovery.patch -Patch0005: 0005-Use-api.env.container_masters.patch -Patch0006: 0006-Consolidate-container_masters-queries.patch -Patch0007: 0007-Replace-hard-coded-paths-with-path-constants.patch -Patch0008: 0008-Support-Samba-4.9.patch -Patch0009: 0009-Add-design-page-for-one-way-trust-to-AD-with-shared-.patch -Patch0010: 0010-trust-allow-trust-agents-to-read-POSIX-identities-of.patch -Patch0011: 0011-trusts-add-support-for-one-way-shared-secret-trust.patch -Patch0012: 0012-upgrade-upgrade-existing-trust-agreements-to-new-lay.patch -Patch0013: 0013-upgrade-add-trust-upgrade-to-actual-upgrade-code.patch -Patch0014: 0014-RFE-ipa-client-should-setup-openldap-for-GSSAPI.patch -Patch0015: 0015-Add-uniqueness-constraint-on-CA-ACL-name.patch -Patch0016: 0016-Add-sysadm_r-to-default-SELinux-user-map-order.patch -Patch0017: 0017-Extend-CALessBase-installer_server-to-accept-extra_a.patch -Patch0018: 0018-Skip-zone-overlap-check-with-auto-reverse.patch -Patch0019: 0019-Add-hidden-replica-feature.patch -Patch0020: 0020-ipatests-Exercise-hidden-replica-feature.patch -Patch0021: 0021-Simplify-and-improve-tests.patch -Patch0022: 0022-Implement-server-state-state-enabled-hidden.patch -Patch0023: 0023-Consider-hidden-servers-as-role-provider.patch -Patch0024: 0024-Improve-config-show-to-show-hidden-servers.patch -Patch0025: 0025-More-test-fixes.patch -Patch0026: 0026-Don-t-allow-to-hide-last-server-for-a-role.patch -Patch0027: 0027-Synchronize-hidden-state-from-IPA-master-role.patch -Patch0028: 0028-Test-replica-installation-from-hidden-replica.patch -Patch0029: 0029-Add-design-draft.patch -Patch0030: 0030-Don-t-fail-if-config-show-does-not-return-servers.patch -Patch0031: 0031-Extract-ca_renewal-cert-update-subroutine.patch -Patch0032: 0032-cainstance-add-function-to-determine-ca_renewal-nick.patch -Patch0033: 0033-constants-add-ca_renewal-container.patch -Patch0034: 0034-Add-ipa-cert-fix-tool.patch -Patch0035: 0035-ipa-cert-fix-add-man-page.patch -Patch0036: 0036-ipa-cert-fix-use-customary-exit-statuses.patch -Patch0037: 0037-Show-a-notification-that-sssd-needs-restarting-after.patch -Patch0038: 0038-ipa-server-upgrade-fix-add_systemd_user_hbac.patch -Patch0039: 0039-ipa-setup-kra-fix-python2-parameter.patch -Patch0040: 0040-oddjob-allow-to-pass-options-to-trust-fetch-domains.patch -Patch0041: 0041-adtrust-define-Guests-mapping-after-creating-cifs-pr.patch -Patch0042: 0042-net-groupmap-force-using-empty-config-when-mapping-G.patch -Patch0043: 0043-Bypass-D-BUS-interface-definition-deficiences-for-tr.patch -Patch0044: 0044-ipactl-restart-fix-wrong-logic-when-checking-service.patch -Patch0045: 0045-replica-install-acknowledge-ca_host-override.patch -Patch0046: 0046-ipa-console-catch-proper-exception-when-history-file.patch -Patch0047: 0047-upgrade-adtrust-catch-empty-result-when-retrieving-l.patch -Patch0048: 0048-Consider-configured-servers-as-valid.patch -Patch0049: 0049-ipa-cert-fix-handle-pki-server-cert-fix-failure.patch -Patch0050: 0050-ipa-cert-fix-fix-spurious-renewal-master-change.patch -Patch0051: 0051-adtrust-upgrade-fix-wrong-primary-principal-name.patch -Patch0052: 0052-adtrust-upgrade-fix-wrong-primary-principal-name-par.patch -Patch0053: 0053-trust-fetch-domains-make-sure-we-use-right-KDC-when-.patch -Patch0054: 0054-add-default-access-control-when-migrating-trust-obje.patch -Patch0055: 0055-adtrust-add-default-read_keys-permission-for-TDO-obj.patch -Patch0056: 0056-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch -Patch0057: 0057-Handle-missing-LWCA-certificate-or-chain.patch -Patch0058: 0058-Fix-CustodiaClient-ccache-handling.patch -Patch0059: 0059-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch -Patch0060: 0060-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch -Patch0061: 0061-Bump-krb5-min-version.patch -Patch0062: 0062-DL0-replica-install-fix-nsDS5ReplicaBindDN-config.patch -Patch0063: 0063-extdom-unify-error-code-handling-especially-LDAP_NO_.patch -Patch0064: 0064-ipa-extdom-extop-test-timed-out-getgrgid_r.patch -Patch0065: 0065-Make-sure-to-have-storage-space-for-tag.patch -Patch0066: 0066-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch -Patch0067: 0067-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch +Patch0001: 0001-extdom-unify-error-code-handling.patch +Patch0002: 0002-Use-unicode-strings-for-Python-2-version.patch +Patch0003: 0003-ipa_sam-remove-dependency-to-talloc_strackframe.h.patch +Patch0004: 0004-Remove-ZERO_STRUCT-call.patch +Patch0005: 0005-ipasam-use-SID-formatting-calls-to-libsss_idmap.patch +Patch0006: 0006-user-stage-transfer-all-attributes-from-preserved-to.patch +Patch0007: 0007-xmlrpc-test-add-test-for-preserved-stage-user.patch +Patch0008: 0008-Don-t-return-SSH-keys-with-ipa-host-find-pkey-only.patch +Patch0009: 0009-check-for-single-label-domains-only-during-server-in.patch +Patch0010: 0010-Don-t-configure-KEYRING-ccache-in-containers.patch +Patch0011: 0011-Add-container-environment-check-to-replicainstall.patch +Patch0012: 0012-add-default-access-control-when-migrating-trust-obje.patch +Patch0013: 0013-adtrust-add-default-read_keys-permission-for-TDO-obj.patch +Patch0014: 0014-Disable-deprecated-lambda-check-in-adtrust-upgrade-c.patch +Patch0015: 0015-Fix-segfault-in-ipadb_parse_ldap_entry.patch +Patch0016: 0016-ipa-restore-Restore-ownership-and-perms-on-389-ds-lo.patch +Patch0017: 0017-replica-install-enforce-server-arg.patch +Patch0018: 0018-Log-INFO-message-when-LDAP-connection-fails-on-start.patch +Patch0019: 0019-Fix-NULL-pointer-dereference-in-maybe_require_preaut.patch +Patch0020: 0020-Handle-missing-LWCA-certificate-or-chain.patch +Patch0021: 0021-Fix-CustodiaClient-ccache-handling.patch +Patch0022: 0022-CustodiaClient-use-ldapi-when-ldap_uri-not-specified.patch +Patch0023: 0023-CustodiaClient-fix-IPASecStore-config-on-ipa-4-7.patch +Patch0024: 0024-Bump-krb5-min-version.patch +Patch0025: 0025-ipa-backup-fix-python2-issue-with-os.mkdir.patch +Patch0026: 0026-Do-not-run-trust-upgrade-code-if-master-lacks-Samba-.patch +Patch0027: 0027-Make-sure-to-have-storage-space-for-tag.patch +Patch0028: 0028-CVE-2019-10195-Don-t-log-passwords-embedded-in-comma.patch +Patch0029: 0029-trust-upgrade-ensure-that-host-is-member-of-adtrust-.patch Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch Patch1002: 1002-Package-copy-schema-to-ca.py.patch Patch1003: 1003-Revert-Increased-mod_wsgi-socket-timeout.patch @@ -234,9 +196,9 @@ BuildRequires: java-1.7.0-openjdk-devel BuildRequires: 389-ds-base-devel >= %{ds_version} BuildRequires: svrcore-devel %if 0%{?rhel} -BuildRequires: samba-devel >= 4.7.0 +BuildRequires: samba-devel >= 4.10.0 %else -BuildRequires: samba-devel >= 2:4.7.0 +BuildRequires: samba-devel >= 2:4.10.0 %endif BuildRequires: libtalloc-devel BuildRequires: libtevent-devel @@ -443,10 +405,7 @@ Requires: oddjob Requires: gssproxy >= 0.7.0-2 # 1.15.2: FindByNameAndCertificate (https://pagure.io/SSSD/sssd/issue/3050) Requires: sssd-dbus >= 1.15.2 - -%if 0%{?centos} == 0 Requires: system-logos >= 70.7.0 -%endif Provides: %{alt_name}-server = %{version} Conflicts: %{alt_name}-server @@ -1003,9 +962,9 @@ cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3 # with_python3 # RHEL spec file only: START: Change branding to IPA and Identity Management -#cp %SOURCE1 install/ui/images/header-logo.png -#cp %SOURCE2 install/ui/images/login-screen-background.jpg -#cp %SOURCE4 install/ui/images/product-name.png +cp %SOURCE1 install/ui/images/header-logo.png +cp %SOURCE2 install/ui/images/login-screen-background.jpg +cp %SOURCE4 install/ui/images/product-name.png # RHEL spec file only: END: Change branding to IPA and Identity Management @@ -1029,8 +988,7 @@ find \ %configure --with-vendor-suffix=-%{release} \ %{enable_server_option} \ %{with_ipatests_option} \ - %{linter_options} \ - --with-ipaplatform=rhel + %{linter_options} %make_build @@ -1051,8 +1009,7 @@ find \ %configure --with-vendor-suffix=-%{release} \ %{enable_server_option} \ %{with_ipatests_option} \ - %{linter_options} \ - --with-ipaplatform=rhel + %{linter_options} popd %endif # with_python3 @@ -1139,11 +1096,9 @@ ln -s %{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-tes # remove files which are useful only for make uninstall find %{buildroot} -wholename '*/site-packages/*/install_files.txt' -exec rm {} \; -%if 0%{?centos} == 0 # RHEL spec file only: START: Replace login-screen-logo.png with a symlink ln -sf %{_datadir}/pixmaps/fedora-gdm-logo.png %{buildroot}%{_usr}/share/ipa/ui/images/login-screen-logo.png # RHEL spec file only: END: Replace login-screen-logo.png with a symlink -%endif %find_lang %{gettext_domain} @@ -1555,19 +1510,19 @@ fi %dir %{_sysconfdir}/ipa/html %config(noreplace) %{_sysconfdir}/ipa/html/ssbrowser.html %config(noreplace) %{_sysconfdir}/ipa/html/unauthorized.html -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/kdcproxy/ipa-kdc-proxy.conf +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-kdc-proxy.conf +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipa/kdcproxy/ipa-kdc-proxy.conf %dir %attr(0755,root,root) %{_sysconfdir}/ipa/dnssec %{_usr}/share/ipa/ipa.conf %{_usr}/share/ipa/ipa-rewrite.conf %{_usr}/share/ipa/ipa-pki-proxy.conf -%ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt -%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.con -%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb5.ini -%ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krbrealm.con +%ghost %attr(0644,root,root) %config(noreplace) %{_usr}/share/ipa/html/ca.crt +%ghost %attr(0644,root,root) %{_usr}/share/ipa/html/krb.con +%ghost %attr(0644,root,root) %{_usr}/share/ipa/html/krb5.ini +%ghost %attr(0644,root,root) %{_usr}/share/ipa/html/krbrealm.con %dir %{_usr}/share/ipa/updates/ %{_usr}/share/ipa/updates/* %dir %{_localstatedir}/lib/ipa @@ -1576,8 +1531,8 @@ fi %attr(711,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca -%ghost %{_localstatedir}/lib/ipa/pki-ca/publish -%ghost %{_localstatedir}/named/dyndb-ldap/ipa +%ghost %attr(775,root,pkiuser) %{_localstatedir}/lib/ipa/pki-ca/publish +%ghost %attr(770,named,named) %{_localstatedir}/named/dyndb-ldap/ipa %dir %attr(0700,root,root) %{_sysconfdir}/ipa/custodia %dir %{_usr}/share/ipa/schema.d %attr(0644,root,root) %{_usr}/share/ipa/schema.d/README @@ -1681,19 +1636,20 @@ fi %doc README.md Contributors.txt %license COPYING %dir %attr(0755,root,root) %{_sysconfdir}/ipa/ -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf -%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipa/default.conf +%ghost %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %dir %attr(0755,root,root) %{_sysconfdir}/ipa/nssdb # old dbm format -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db +%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert8.db +%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/key3.db +%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/secmod.db +%ghost %attr(600,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt # new sql format -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert9.db -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/key4.db -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pkcs11.txt -%ghost %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt -%ghost %config(noreplace) %{_sysconfdir}/pki/ca-trust/source/ipa.p11-kit +%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/cert9.db +%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/key4.db +%ghost %attr(644,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/pkcs11.txt +%ghost %attr(600,root,root) %config(noreplace) %{_sysconfdir}/ipa/nssdb/pwdfile.txt +%ghost %attr(644,root,root) %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 @@ -1795,36 +1751,88 @@ fi %changelog -* Tue Feb 04 2020 CentOS Sources - 4.6.5-11.el7.centos.4 -- Roll in CentOS Branding - -* Mon Dec 16 2019 Florence Blanc-Renaud - 4.6.5-11.el7_7.4 -- Resolves: #1781153 - After upgrade AD Trust Agents were removed from LDAP +* Wed Dec 4 2019 Florence Blanc-Renaud - 4.6.6-11.el7 +- Resolves: #1778777 - After upgrade AD Trust Agents were removed from LDAP - trust upgrade: ensure that host is member of adtrust agents -- Resolves: #1777303 - CVE-2019-10195 ipa: batch API logging user passwords to /var/log/httpd/error_log + +* Tue Nov 26 2019 Florence Blanc-Renaud - 4.6.6-10.el7 +- Resolves: #1728123 - EMBARGOED CVE-2019-10195 ipa: FreeIPA: batch API logging user passwords to /var/log/httpd/error_log [rhel-7] - CVE-2019-10195: Don't log passwords embedded in commands in calls using batch -- Resolves: #1773953 - User incorrectly added to negative cache when backend is reconnecting to IPA service / timed out: error code 32 'No such object' - - extdom: unify error code handling especially LDAP_NO_SUCH_OBJECT - - ipa-extdom-extop: test timed out getgrgid_r -- Resolves: #1770728 - Issue with adding multiple RHEL 7 IPA replica to RHEL 6 IPA master - - DL0 replica install: fix nsDS5ReplicaBindDN config -- Resolves: #1767300 - CVE-2019-14867 ipa: Denial of service in IPA server due to wrong use of ber_scanf() - - Make sure to have storage space for tag - -* Mon Sep 30 2019 Florence Blanc-Renaud - 4.6.5-11.el7_7.3 -- Resolves: #1756914 - Sub-CA key replication failure +- Resolves: #1773550 - IPA upgrade fails for latest ipa package when adtrust is installed + - Do not run trust upgrade code if master lacks Samba bindings +- Resolves: #1767302 - EMBARGOED CVE-2019-14867 ipa: Denial of service in IPA server due to wrong use of ber_scanf() [rhel-7.8] + - Make sure to have storage space for tag + +* Wed Oct 30 2019 Florence Blanc-Renaud - 4.6.6-9.el7 +- Resolves: #1762317 - ipa-backup command is failing on rhel-7.8 + - ipa-backup: fix python2 issue with os.mkdir + +* Mon Sep 30 2019 Florence Blanc-Renaud - 4.6.6-8.el7 +- Resolves: #1755223 - Sub-CA key replication failure - Handle missing LWCA certificate or chain - Fix CustodiaClient ccache handling - CustodiaClient: use ldapi when ldap_uri not specified - CustodiaClient: fix IPASecStore config on ipa-4-7 - Bump krb5 min version -* Tue Sep 17 2019 Florence Blanc-Renaud - 4.6.5-11.el7_7.2 -- Resolves: #1752740 - when migrating trusted domain object structure, add default access control definitions, if they were missing in old trust objects +* Tue Sep 24 2019 Florence Blanc-Renaud - 4.6.6-7.el7 +- Resolves: #1754494 - ipa-replica-install does not enforce --server option + - replica install: enforce --server arg +- Resolves: #1729638 - ipa_kdb: assertion failure from NULL lcontext pointer to ldap_get_values_len() + - Fix segfault in ipadb_parse_ldap_entry() + - Log INFO message when LDAP connection fails on startup + - Fix NULL pointer dereference in maybe_require_preauth() +- Resolves: #1636765 - ipa-restore set wrong file permissions and ownership for /var/log/dirsrv/slapd- directory + - ipa-restore: Restore ownership and perms on 389-ds log directory + +* Tue Sep 17 2019 Florence Blanc-Renaud - 4.6.6-6.el7 +- Resolves: #1752005 - Keyrings should not be used in containerized environment + - Don't configure KEYRING ccache in containers +- Resolves: #1751951 - When master's IP address does not resolve to its name, ipa-replica-install fails + - Add container environment check to replicainstall +- Resolves: #1750700 - when migrating trusted domain object structure, add default access control definitions, if they were missing in old trust objects - add default access control when migrating trust objects - adtrust: add default read_keys permission for TDO objects - Disable deprecated-lambda check in adtrust upgrade code +* Mon Sep 09 2019 Florence Blanc-Renaud - 4.6.6-5.el7 +- Resolves: #1749788 - ipa host-find --pkey-only includes SSH keys in output + - Don't return SSH keys with ipa host-find --pkey-only +- Resolves: #1745108 - Bug 1497334 invalidating single-label domains introduces regression of usage for customers + - check for single-label domains only during server install +- Resolves: #1583950 - IPA: IDM drops all custom attributes when moving account from preserved to stage + - user-stage: transfer all attributes from preserved to stage user + - xmlrpc test: add test for preserved > stage user + +* Fri Aug 23 2019 Alexander Bokovoy - 4.6.6-4.el7 +- Resolves: 1744926 - rebuild against Samba 4.10 to solve undefined symbol: DEBUGLEVEL_CLASS +- Backport patches to compile against Samba 4.10 +- Fix Python 2 compatibility in adtrustinstance + +* Mon Aug 19 2019 Alexander Bokovoy - 4.6.6-3.el7 +- Resolves: 1717008 - User incorrectly added to negative cache when backend is reconnecting to IPA service / timed out: error code 32 'No such object' + +* Wed Aug 14 2019 Rob Crittenden - 4.6.6-2.el7 +- Rebuild + +* Mon Jul 29 2019 Florence Blanc-Renaud - 4.6.6-1.el7 +- Resolves: 1733075 - Rebase IPA to latest 4.6.x version +- Resolves: 1512952 - cert renewal is failing when ipa ca cert is renewed from self-signed > external ca > self-sign +- Resolves: 1544470 - cn=cacert could show expired certificate +- Resolves: 1581583 - Error message should be more useful while ipa-backup fails for insufficient space +- Resolves: 1632351 - remove "last init status" from ipa-replica-manage list if it's None. +- Resolves: 1691939 - False error is shown when options are added to an existing sudo rule using 'sudooption' +- Resolves: 1695685 - IPA Web UI is slow to display user details page +- Resolves: 1702426 - ipa-server-common expected file permissions in package don't match runtime permissions +- Resolves: 1711172 - Removing TLSv1.0, TLSv1.1 from nss.conf +- Resolves: 1714076 - Issue with adding multiple RHEL 7 IPA replica to RHEL 6 IPA master +- Resolves: 1714921 - x509.Name -> ipapython.dn.DN does not handle multi-valued RDNs +- Resolves: 1720952 - Cannot modify TTL with ipa dnsrecord-mod --ttl alone on command line +- Resolves: 1721550 - Staged user is not being recognized if the user entry doesn't have an objectClass "posixaccount" +- Resolves: 1727304 - Restrict cipher lists used by openssl connections +- Resolves: 1733209 - ipa-client-automount needs option to specify domain +- Resolves: 1733265 - IPA webgui incorrectly display number of entries in ID views + * Fri Jun 28 2019 Florence Blanc-Renaud - 4.6.5-11.el7 - Resolves: 1723473 - ipa upgrade fails with trust entry already exists - adtrust upgrade: fix wrong primary principal name, part 2