diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e4e65c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +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 new file mode 100644 index 0000000..0dfcd18 --- /dev/null +++ b/.ipa.metadata @@ -0,0 +1,4 @@ +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-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/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/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-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-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/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/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/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/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/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/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-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-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/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/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/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/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/1001-Change-branding-to-IPA-and-Identity-Management.patch b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch new file mode 100644 index 0000000..e0e69ef --- /dev/null +++ b/SOURCES/1001-Change-branding-to-IPA-and-Identity-Management.patch @@ -0,0 +1,1101 @@ +From 4565a6730faa3eb5ea5da1e226d7a624930f86c5 Mon Sep 17 00:00:00 2001 +From: Jan Cholasta +Date: Tue, 14 Mar 2017 15:48:07 +0000 +Subject: [PATCH] Change branding to IPA and Identity Management + +--- + client/man/default.conf.5 | 2 +- + client/man/ipa-certupdate.1 | 2 +- + client/man/ipa-client-automount.1 | 2 +- + client/man/ipa-client-install.1 | 2 +- + client/man/ipa-getkeytab.1 | 4 +- + client/man/ipa-join.1 | 2 +- + client/man/ipa-rmkeytab.1 | 2 +- + client/man/ipa.1 | 2 +- + install/html/ssbrowser.html | 4 +- + install/html/unauthorized.html | 4 +- + install/migration/error.html | 4 +- + install/migration/index.html | 2 +- + install/migration/invalid.html | 2 +- + install/share/schema.d/README | 4 +- + install/tools/ipa-adtrust-install | 4 +- + install/tools/ipa-replica-conncheck | 2 +- + install/tools/man/ipa-adtrust-install.1 | 2 +- + install/tools/man/ipa-advise.1 | 4 +- + install/tools/man/ipa-backup.1 | 2 +- + install/tools/man/ipa-ca-install.1 | 2 +- + install/tools/man/ipa-cacert-manage.1 | 2 +- + install/tools/man/ipa-cert-fix.1 | 6 +- + install/tools/man/ipa-compat-manage.1 | 2 +- + install/tools/man/ipa-crlgen-manage.1 | 2 +- + install/tools/man/ipa-csreplica-manage.1 | 2 +- + install/tools/man/ipa-dns-install.1 | 4 +- + install/tools/man/ipa-kra-install.1 | 2 +- + install/tools/man/ipa-ldap-updater.1 | 2 +- + install/tools/man/ipa-managed-entries.1 | 2 +- + install/tools/man/ipa-nis-manage.1 | 2 +- + install/tools/man/ipa-otptoken-import.1 | 2 +- + install/tools/man/ipa-pkinit-manage.1 | 2 +- + install/tools/man/ipa-replica-conncheck.1 | 2 +- + install/tools/man/ipa-replica-install.1 | 6 +- + install/tools/man/ipa-replica-manage.1 | 2 +- + install/tools/man/ipa-replica-prepare.1 | 2 +- + install/tools/man/ipa-restore.1 | 2 +- + install/tools/man/ipa-server-certinstall.1 | 2 +- + install/tools/man/ipa-server-install.1 | 4 +- + install/tools/man/ipa-server-upgrade.1 | 2 +- + install/tools/man/ipa-winsync-migrate.1 | 2 +- + install/tools/man/ipactl.8 | 2 +- + install/ui/css/patternfly.css | 2 +- + install/ui/index.html | 2 +- + install/ui/less/brand.less | 103 ++++++++++----------- + install/ui/less/patternfly.less | 48 ++++++++++ + install/ui/reset_password.html | 2 +- + install/ui/src/freeipa/widgets/App.js | 2 +- + install/ui/sync_otp.html | 2 +- + ipaserver/advise/plugins/legacy_clients.py | 8 +- + ipaserver/install/dns.py | 2 +- + ipaserver/install/ipa_cert_fix.py | 2 +- + ipaserver/install/ipa_kra_install.py | 4 +- + ipaserver/install/server/install.py | 2 +- + ipaserver/install/server/replicainstall.py | 2 +- + ipaserver/plugins/certprofile.py | 2 +- + ipaserver/plugins/sudorule.py | 4 +- + 57 files changed, 171 insertions(+), 126 deletions(-) + +diff --git a/client/man/default.conf.5 b/client/man/default.conf.5 +index f21d9d5b7a02e9c9858bb44cf3f2f4c16655901a..d6c1e42d1af3a2085451f43240d7e719143bb10b 100644 +--- a/client/man/default.conf.5 ++++ b/client/man/default.conf.5 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "default.conf" "5" "Feb 21 2011" "FreeIPA" "FreeIPA Manual Pages" ++.TH "default.conf" "5" "Feb 21 2011" "IPA" "IPA Manual Pages" + .SH "NAME" + default.conf \- IPA configuration file + .SH "SYNOPSIS" +diff --git a/client/man/ipa-certupdate.1 b/client/man/ipa-certupdate.1 +index d95790a366aac4635e32bbc6bc81773bb9a52e68..431b395a907b6978d9e0dba9870ed0bd0c54f07b 100644 +--- a/client/man/ipa-certupdate.1 ++++ b/client/man/ipa-certupdate.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Jan Cholasta + .\" +-.TH "ipa-certupdate" "1" "Jul 2 2014" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-certupdate" "1" "Jul 2 2014" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-certupdate \- Update local IPA certificate databases with certificates from the server + .SH "SYNOPSIS" +diff --git a/client/man/ipa-client-automount.1 b/client/man/ipa-client-automount.1 +index e6a32fba432d75dfce0cfc0a9bc7264c4beca2ae..5c3fdb118522c12f93e82bb39572ba1e2a1908a2 100644 +--- a/client/man/ipa-client-automount.1 ++++ b/client/man/ipa-client-automount.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "ipa-client-automount" "1" "May 25 2012" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-client-automount" "1" "May 25 2012" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-client\-automount \- Configure automount and NFS for IPA + .SH "SYNOPSIS" +diff --git a/client/man/ipa-client-install.1 b/client/man/ipa-client-install.1 +index b669b175af7df909f7b62dbce56cc219e154b153..9547288615698232458877afcd10a0de76f75259 100644 +--- a/client/man/ipa-client-install.1 ++++ b/client/man/ipa-client-install.1 +@@ -1,7 +1,7 @@ + .\" A man page for ipa-client-install + .\" Copyright (C) 2008-2016 FreeIPA Contributors see COPYING for license + .\" +-.TH "ipa-client-install" "1" "Dec 19 2016" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-client-install" "1" "Dec 19 2016" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-client\-install \- Configure an IPA client + .SH "SYNOPSIS" +diff --git a/client/man/ipa-getkeytab.1 b/client/man/ipa-getkeytab.1 +index 39ff0d5da85b5a641328a512feeb06bc9c1ab9d7..bf1e72a3672a72554f9563a41d4eeed88bfd272b 100644 +--- a/client/man/ipa-getkeytab.1 ++++ b/client/man/ipa-getkeytab.1 +@@ -17,7 +17,7 @@ + .\" Author: Karl MacMillan + .\" Author: Simo Sorce + .\" +-.TH "ipa-getkeytab" "1" "Oct 10 2007" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-getkeytab" "1" "Oct 10 2007" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-getkeytab \- Get a keytab for a Kerberos principal + .SH "SYNOPSIS" +@@ -117,7 +117,7 @@ GSSAPI or EXTERNAL. + \fB\-r\fR + Retrieve mode. Retrieve an existing key from the server instead of generating a + new one. This is incompatibile with the \-\-password option, and will work only +-against a FreeIPA server more recent than version 3.3. The user requesting the ++against a IPA server more recent than version 3.3. The user requesting the + keytab must have access to the keys for this operation to succeed. + .SH "EXAMPLES" + Add and retrieve a keytab for the NFS service principal on +diff --git a/client/man/ipa-join.1 b/client/man/ipa-join.1 +index d881607842bb0227c2da863bd1674db01530e910..30b667558ba3105cf320896ef40b0661a18066f5 100644 +--- a/client/man/ipa-join.1 ++++ b/client/man/ipa-join.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Rob Crittenden + .\" +-.TH "ipa-join" "1" "Oct 8 2009" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-join" "1" "Oct 8 2009" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-join \- Join a machine to an IPA realm and get a keytab for the host service principal + .SH "SYNOPSIS" +diff --git a/client/man/ipa-rmkeytab.1 b/client/man/ipa-rmkeytab.1 +index 53f775439dbdb5a4b9dfee7fe6c7277fce10893c..2c8218c94996b1411637a7c53f2f5bc5612f3ea3 100644 +--- a/client/man/ipa-rmkeytab.1 ++++ b/client/man/ipa-rmkeytab.1 +@@ -17,7 +17,7 @@ + .\" Author: Rob Crittenden + .\" + .\" +-.TH "ipa-rmkeytab" "1" "Oct 30 2009" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa-rmkeytab" "1" "Oct 30 2009" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa\-rmkeytab \- Remove a kerberos principal from a keytab + .SH "SYNOPSIS" +diff --git a/client/man/ipa.1 b/client/man/ipa.1 +index d190677cf79af7a2b2225eb4a61f485120186e26..0988aaa93dd45f8a57af1aa23560b4844443c776 100644 +--- a/client/man/ipa.1 ++++ b/client/man/ipa.1 +@@ -16,7 +16,7 @@ + .\" + .\" Author: Pavel Zuna + .\" +-.TH "ipa" "1" "Apr 29 2016" "FreeIPA" "FreeIPA Manual Pages" ++.TH "ipa" "1" "Apr 29 2016" "IPA" "IPA Manual Pages" + .SH "NAME" + ipa \- IPA command\-line interface + .SH "SYNOPSIS" +diff --git a/install/html/ssbrowser.html b/install/html/ssbrowser.html +index 5ab871d8e3738ba94eafc6437647adc1c9ca2e99..44c46df47565428a0c8a854881a179cabf3d3496 100644 +--- a/install/html/ssbrowser.html ++++ b/install/html/ssbrowser.html +@@ -2,7 +2,7 @@ + + + +- IPA: Identity Policy Audit ++ Identity Management + + +