diff --git a/SOURCES/0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch b/SOURCES/0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch new file mode 100644 index 0000000..81d6e2c --- /dev/null +++ b/SOURCES/0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch @@ -0,0 +1,60 @@ +From 158468507bb723aa62196846749c23c121d4b298 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 8 Apr 2019 10:55:39 +0200 +Subject: [PATCH] Do not use arcfour-hmac-md5 when discovering the salt + +Since the arcfour-hmac-md5 encryption types does not use salts it cannot +be used to discover the right salt. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1683745 + +diff --git a/library/adkrb5.c b/library/adkrb5.c +index da835d7..be3ede5 100644 +--- a/library/adkrb5.c ++++ b/library/adkrb5.c +@@ -395,15 +395,33 @@ _adcli_krb5_keytab_discover_salt (krb5_context k5, + krb5_keytab scratch; + krb5_error_code code; + int i; ++ krb5_enctype *salt_enctypes = NULL; ++ size_t c; ++ size_t s; + + /* TODO: This should be a unique name */ + + code = krb5_kt_resolve (k5, "MEMORY:adcli-discover-salt", &scratch); + return_val_if_fail (code == 0, code); + ++ for (c = 0; enctypes[c] != 0; c++); /* count enctypes */ ++ salt_enctypes = calloc (c + 1, sizeof (krb5_enctype)); ++ return_val_if_fail (salt_enctypes != NULL, ENOMEM); ++ ++ /* ENCTYPE_ARCFOUR_HMAC does not use salts, so it cannot be used to ++ * discover the right salt. */ ++ s = 0; ++ for (c = 0; enctypes[c] != 0; c++) { ++ if (enctypes[c] == ENCTYPE_ARCFOUR_HMAC) { ++ continue; ++ } ++ ++ salt_enctypes[s++] = enctypes[c]; ++ } ++ + for (i = 0; salts[i].data != NULL; i++) { + code = _adcli_krb5_keytab_test_salt (k5, scratch, principal, kvno, +- password, enctypes, &salts[i]); ++ password, salt_enctypes, &salts[i]); + if (code == 0) { + *discovered = i; + break; +@@ -412,6 +430,7 @@ _adcli_krb5_keytab_discover_salt (krb5_context k5, + } + } + ++ free (salt_enctypes); + krb5_kt_close (k5, scratch); + return code; + } +-- +2.21.0 + diff --git a/SOURCES/0001-Fix-for-issue-found-by-Coverity.patch b/SOURCES/0001-Fix-for-issue-found-by-Coverity.patch new file mode 100644 index 0000000..6706ba5 --- /dev/null +++ b/SOURCES/0001-Fix-for-issue-found-by-Coverity.patch @@ -0,0 +1,26 @@ +From 5da6d34e2659f915e830932fd366c635801ecd91 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 12 Aug 2019 17:28:20 +0200 +Subject: [PATCH] Fix for issue found by Coverity + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3 + +diff --git a/library/adenroll.c b/library/adenroll.c +index 53cd812..524663a 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2681,7 +2681,10 @@ adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll) + for (c = 0; cur_enctypes[c] != 0; c++); + + new_enctypes = calloc (c + 1, sizeof (krb5_enctype)); +- return_val_if_fail (new_enctypes != NULL, NULL); ++ if (new_enctypes == NULL) { ++ krb5_free_enctypes (k5, permitted_enctypes); ++ return NULL; ++ } + + n = 0; + for (c = 0; cur_enctypes[c] != 0; c++) { +-- +2.21.0 + diff --git a/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch b/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch new file mode 100644 index 0000000..c7e698e --- /dev/null +++ b/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch @@ -0,0 +1,43 @@ +From 3c93c96eb6ea2abd3869921ee4c89e1a4d9e4c44 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 14 Aug 2018 13:08:52 +0200 +Subject: [PATCH] Fix for issues found by Coverity + +--- + library/adenroll.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 02bd9e3..de2242a 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -1575,7 +1575,7 @@ load_host_keytab (adcli_enroll *enroll) + } + + krb5_free_context (k5); +- return ADCLI_SUCCESS; ++ return res; + } + + typedef struct { +@@ -1756,12 +1756,12 @@ add_principal_to_keytab (adcli_enroll *enroll, + enroll->kvno, &password, enctypes, &salts[*which_salt]); + + free_principal_salts (k5, salts); ++ } + +- if (code != 0) { +- _adcli_err ("Couldn't add keytab entries: %s: %s", +- enroll->keytab_name, krb5_get_error_message (k5, code)); +- return ADCLI_ERR_FAIL; +- } ++ if (code != 0) { ++ _adcli_err ("Couldn't add keytab entries: %s: %s", ++ enroll->keytab_name, krb5_get_error_message (k5, code)); ++ return ADCLI_ERR_FAIL; + } + + +-- +2.21.0 + diff --git a/SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch b/SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch new file mode 100644 index 0000000..770f49c --- /dev/null +++ b/SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch @@ -0,0 +1,216 @@ +From 0a0d0f66409eb83e06b7dc50543c2f6c15a36bc4 Mon Sep 17 00:00:00 2001 +From: Alexey A Nikitin +Date: Mon, 29 Oct 2018 20:40:36 -0700 +Subject: [PATCH] Make 'adcli info' DC location mechanism more compliant with + [MS-ADTS] and [MS-NRPC] + +AD specifications say that DC locator must attempt to find a suitable DC for the client. That means going through all of the DCs in SRV RRs one by one until one of them answers. + +The problem with adcli's original behavior is that it queries only five DCs from SRV, ever. This becomes a problem if for any reason there is a large number of DCs in the domain from which the client cannot get a CLDAP response. +--- + library/addisco.c | 146 +++++++++++++++++++++++++++++----------------- + 1 file changed, 94 insertions(+), 52 deletions(-) + +diff --git a/library/addisco.c b/library/addisco.c +index 8cc5bf0..6e73ead 100644 +--- a/library/addisco.c ++++ b/library/addisco.c +@@ -41,8 +41,10 @@ + #include + #include + +-/* Number of servers to do discovery against */ +-#define DISCO_COUNT 5 ++/* Number of servers to do discovery against. ++ * For AD DS maximum number of DCs is 1200. ++ */ ++#define DISCO_COUNT 1200 + + /* The time period in which to do rapid requests */ + #define DISCO_FEVER 1 +@@ -453,6 +455,51 @@ parse_disco (LDAP *ldap, + return usability; + } + ++static int ++ldap_disco_poller (LDAP **ldap, ++ LDAPMessage **message, ++ adcli_disco **results, ++ const char **addrs) ++{ ++ int found = ADCLI_DISCO_UNUSABLE; ++ int close_ldap; ++ int parsed; ++ int ret = 0; ++ struct timeval tvpoll = { 0, 0 }; ++ ++ switch (ldap_result (*ldap, LDAP_RES_ANY, 1, &tvpoll, message)) { ++ case LDAP_RES_SEARCH_ENTRY: ++ case LDAP_RES_SEARCH_RESULT: ++ parsed = parse_disco (*ldap, *addrs, *message, results); ++ if (parsed > found) ++ found = parsed; ++ ldap_msgfree (*message); ++ close_ldap = 1; ++ break; ++ case -1: ++ ldap_get_option (*ldap, LDAP_OPT_RESULT_CODE, &ret); ++ close_ldap = 1; ++ break; ++ default: ++ ldap_msgfree (*message); ++ close_ldap = 0; ++ break; ++ } ++ ++ if (ret != LDAP_SUCCESS) { ++ _adcli_ldap_handle_failure (*ldap, ADCLI_ERR_CONFIG, ++ "Couldn't perform discovery search"); ++ } ++ ++ /* Done with this connection */ ++ if (close_ldap) { ++ ldap_unbind_ext_s (*ldap, NULL, NULL); ++ *ldap = NULL; ++ } ++ ++ return found; ++} ++ + static int + ldap_disco (const char *domain, + srvinfo *srv, +@@ -477,6 +524,7 @@ ldap_disco (const char *domain, + int num, i; + int ret; + int have_any = 0; ++ struct timeval interval; + + if (domain) { + value = _adcli_ldap_escape_filter (domain); +@@ -540,7 +588,6 @@ ldap_disco (const char *domain, + version = LDAP_VERSION3; + ldap_set_option (ldap[num], LDAP_OPT_PROTOCOL_VERSION, &version); + ldap_set_option (ldap[num], LDAP_OPT_REFERRALS , 0); +- _adcli_info ("Sending netlogon pings to domain controller: %s", url); + addrs[num] = srv->hostname; + have_any = 1; + num++; +@@ -555,70 +602,65 @@ ldap_disco (const char *domain, + freeaddrinfo (res); + } + +- /* Wait for the first response. Poor mans fd watch */ +- for (started = now = time (NULL); +- have_any && found != ADCLI_DISCO_USABLE && now < started + DISCO_TIME; +- now = time (NULL)) { ++ /* Initial send and short time wait */ ++ interval.tv_sec = 0; ++ for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) { ++ int parsed; ++ ++ if (NULL == ldap[i]) ++ continue; + +- struct timeval tvpoll = { 0, 0 }; +- struct timeval interval; ++ have_any = 1; ++ _adcli_info ("Sending NetLogon ping to domain controller: %s", addrs[i]); + +- /* If in the initial period, send feverishly */ +- if (now < started + DISCO_FEVER) { +- interval.tv_sec = 0; +- interval.tv_usec = 100 * 1000; ++ ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE, ++ filter, attrs, 0, NULL, NULL, NULL, ++ -1, &msgidp); ++ ++ if (ret != LDAP_SUCCESS) { ++ _adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG, ++ "Couldn't perform discovery search"); ++ ldap_unbind_ext_s (ldap[i], NULL, NULL); ++ ldap[i] = NULL; ++ } ++ ++ /* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first ++ * five DCs are given 0.4 seconds timeout, next five are given 0.2 ++ * seconds, and the rest are given 0.1 seconds ++ */ ++ if (i < 5) { ++ interval.tv_usec = 400000; ++ } else if (i < 10) { ++ interval.tv_usec = 200000; + } else { +- interval.tv_sec = 1; +- interval.tv_usec = 0; ++ interval.tv_usec = 100000; + } ++ select (0, NULL, NULL, NULL, &interval); ++ ++ parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i])); ++ if (parsed > found) ++ found = parsed; ++ } ++ ++ /* Wait some more until LDAP timeout (DISCO_TIME) */ ++ for (started = now = time (NULL); ++ have_any && ADCLI_DISCO_UNUSABLE == found && now < started + DISCO_TIME; ++ now = time (NULL)) { + + select (0, NULL, NULL, NULL, &interval); + + have_any = 0; +- for (i = 0; found != ADCLI_DISCO_USABLE && i < num; i++) { +- int close_ldap; ++ for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) { + int parsed; + + if (ldap[i] == NULL) + continue; + +- ret = 0; + have_any = 1; +- switch (ldap_result (ldap[i], LDAP_RES_ANY, 1, &tvpoll, &message)) { +- case LDAP_RES_SEARCH_ENTRY: +- case LDAP_RES_SEARCH_RESULT: +- parsed = parse_disco (ldap[i], addrs[i], message, results); +- if (parsed > found) +- found = parsed; +- ldap_msgfree (message); +- close_ldap = 1; +- break; +- case 0: +- ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE, +- filter, attrs, 0, NULL, NULL, NULL, +- -1, &msgidp); +- close_ldap = (ret != 0); +- break; +- case -1: +- ldap_get_option (ldap[i], LDAP_OPT_RESULT_CODE, &ret); +- close_ldap = 1; +- break; +- default: +- ldap_msgfree (message); +- close_ldap = 0; +- break; +- } +- +- if (ret != LDAP_SUCCESS) { +- _adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG, +- "Couldn't perform discovery search"); +- } + +- /* Done with this connection */ +- if (close_ldap) { +- ldap_unbind_ext_s (ldap[i], NULL, NULL); +- ldap[i] = NULL; +- } ++ parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i])); ++ if (parsed > found) ++ found = parsed; + } + } + +-- +2.21.0 + diff --git a/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch b/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch new file mode 100644 index 0000000..a1f63cc --- /dev/null +++ b/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch @@ -0,0 +1,124 @@ +From a4c35124b5c83603333ee7518d0783ff708e86df Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 11 Oct 2019 16:39:25 +0200 +Subject: [PATCH 1/2] Use GSS-SPNEGO if available + +Currently adcli uses the GSSAPI SASL mechanism for LDAP authentication +and to establish encryption. While this works in general it does not +handle some of the more advanced features which can be required by AD +DCs. + +The GSS-SPNEGO mechanism can handle them and is used with this patch by +adcli if the AD DC indicates that it supports it. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1762420 +--- + library/adconn.c | 35 ++++++++++++++++++++++++++++++++++- + library/adconn.h | 3 +++ + 2 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/library/adconn.c b/library/adconn.c +index f6c23d3..a3f4548 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -77,6 +77,7 @@ struct _adcli_conn_ctx { + char *default_naming_context; + char *configuration_naming_context; + char **supported_capabilities; ++ char **supported_sasl_mechs; + + /* Connect state */ + LDAP *ldap; +@@ -845,6 +846,7 @@ connect_and_lookup_naming (adcli_conn *conn, + "defaultNamingContext", + "configurationNamingContext", + "supportedCapabilities", ++ "supportedSASLMechanisms", + NULL + }; + +@@ -897,6 +899,11 @@ connect_and_lookup_naming (adcli_conn *conn, + "supportedCapabilities"); + } + ++ if (conn->supported_sasl_mechs == NULL) { ++ conn->supported_sasl_mechs = _adcli_ldap_parse_values (ldap, results, ++ "supportedSASLMechanisms"); ++ } ++ + ldap_msgfree (results); + + if (conn->default_naming_context == NULL) { +@@ -1022,6 +1029,7 @@ authenticate_to_directory (adcli_conn *conn) + OM_uint32 minor; + ber_len_t ssf; + int ret; ++ const char *mech = "GSSAPI"; + + if (conn->ldap_authenticated) + return ADCLI_SUCCESS; +@@ -1038,7 +1046,11 @@ authenticate_to_directory (adcli_conn *conn) + ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf); + return_unexpected_if_fail (ret == 0); + +- ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, "GSSAPI", NULL, NULL, ++ if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")) { ++ mech = "GSS-SPNEGO"; ++ } ++ ++ ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, mech, NULL, NULL, + LDAP_SASL_QUIET, sasl_interact, NULL); + + /* Clear the credential cache GSSAPI to use (for this thread) */ +@@ -1231,6 +1243,7 @@ conn_free (adcli_conn *conn) + free (conn->default_naming_context); + free (conn->configuration_naming_context); + _adcli_strv_free (conn->supported_capabilities); ++ _adcli_strv_free (conn->supported_sasl_mechs); + + free (conn->computer_name); + free (conn->host_fqdn); +@@ -1593,6 +1606,26 @@ adcli_conn_server_has_capability (adcli_conn *conn, + return 0; + } + ++bool ++adcli_conn_server_has_sasl_mech (adcli_conn *conn, ++ const char *mech) ++{ ++ int i; ++ ++ return_val_if_fail (conn != NULL, false); ++ return_val_if_fail (mech != NULL, false); ++ ++ if (!conn->supported_sasl_mechs) ++ return false; ++ ++ for (i = 0; conn->supported_sasl_mechs[i] != NULL; i++) { ++ if (strcasecmp (mech, conn->supported_sasl_mechs[i]) == 0) ++ return true; ++ } ++ ++ return false; ++} ++ + bool adcli_conn_is_writeable (adcli_conn *conn) + { + disco_dance_if_necessary (conn); +diff --git a/library/adconn.h b/library/adconn.h +index 13cfd32..8e88045 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -146,6 +146,9 @@ void adcli_conn_set_krb5_conf_dir (adcli_conn *conn, + int adcli_conn_server_has_capability (adcli_conn *conn, + const char *capability); + ++bool adcli_conn_server_has_sasl_mech (adcli_conn *conn, ++ const char *mech); ++ + bool adcli_conn_is_writeable (adcli_conn *conn); + + #endif /* ADCONN_H_ */ +-- +2.21.1 + diff --git a/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch b/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch new file mode 100644 index 0000000..ad69b70 --- /dev/null +++ b/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch @@ -0,0 +1,80 @@ +From 341974aae7d0755fc32a0b7e2b34d8e1ef60d195 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 20 Dec 2018 21:05:35 +0100 +Subject: [PATCH 1/4] adenroll: make sure only allowed enctypes are used in + FIPS mode + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1717355 +--- + library/adenroll.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 52aa8a8..f617f28 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -41,11 +41,19 @@ + #include + #include + #include ++#include ++#include + + #ifndef SAMBA_DATA_TOOL + #define SAMBA_DATA_TOOL "/usr/bin/net" + #endif + ++static krb5_enctype v60_later_enctypes_fips[] = { ++ ENCTYPE_AES256_CTS_HMAC_SHA1_96, ++ ENCTYPE_AES128_CTS_HMAC_SHA1_96, ++ 0 ++}; ++ + static krb5_enctype v60_later_enctypes[] = { + ENCTYPE_AES256_CTS_HMAC_SHA1_96, + ENCTYPE_AES128_CTS_HMAC_SHA1_96, +@@ -2594,6 +2602,28 @@ adcli_enroll_set_keytab_name (adcli_enroll *enroll, + enroll->keytab_name_is_krb5 = 0; + } + ++#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled" ++ ++static bool adcli_fips_enabled (void) ++{ ++ int fd; ++ ssize_t len; ++ char buf[8]; ++ ++ fd = open (PROC_SYS_FIPS, O_RDONLY); ++ if (fd != -1) { ++ len = read (fd, buf, sizeof (buf)); ++ close (fd); ++ /* Assume FIPS in enabled if PROC_SYS_FIPS contains a ++ * non-0 value. */ ++ if ( ! (len == 2 && buf[0] == '0' && buf[1] == '\n')) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + krb5_enctype * + adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll) + { +@@ -2602,7 +2632,11 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll) + return enroll->keytab_enctypes; + + if (adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID)) +- return v60_later_enctypes; ++ if (adcli_fips_enabled ()) { ++ return v60_later_enctypes_fips; ++ } else { ++ return v60_later_enctypes; ++ } + else + return v51_earlier_enctypes; + } +-- +2.21.0 + diff --git a/SOURCES/0001-doc-explain-how-to-force-password-reset.patch b/SOURCES/0001-doc-explain-how-to-force-password-reset.patch new file mode 100644 index 0000000..01e694d --- /dev/null +++ b/SOURCES/0001-doc-explain-how-to-force-password-reset.patch @@ -0,0 +1,27 @@ +From 9b187095edb8c914238419ed51fef6041864f4fc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 26 Aug 2019 13:33:24 +0200 +Subject: [PATCH] doc: explain how to force password reset + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1738573 + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 094f577..4f201e0 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -330,7 +330,11 @@ Password for Administrator: + important here is currently the + option, see + smb.conf5 +- for details. ++ for details. ++ Note that if the machine account password is not ++ older than 30 days, you have to pass ++ to ++ force the update. + + + +-- +2.21.0 + diff --git a/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch b/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch new file mode 100644 index 0000000..769a022 --- /dev/null +++ b/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch @@ -0,0 +1,52 @@ +From 2fc259a88be618871cea8ff8b8a13bd3e040aea4 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 13 Jun 2019 17:23:47 +0200 +Subject: [PATCH 2/4] adconn: add adcli_conn_set_krb5_context + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3 +--- + library/adconn.c | 13 +++++++++++++ + library/adconn.h | 3 +++ + 2 files changed, 16 insertions(+) + +diff --git a/library/adconn.c b/library/adconn.c +index f6c23d3..bcaced8 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -1406,6 +1406,19 @@ adcli_conn_get_krb5_context (adcli_conn *conn) + return conn->k5; + } + ++void ++adcli_conn_set_krb5_context (adcli_conn *conn, ++ krb5_context k5) ++{ ++ return_if_fail (conn != NULL); ++ ++ if (conn->k5 != NULL) { ++ krb5_free_context (conn->k5); ++ } ++ ++ conn->k5 = k5; ++} ++ + const char * + adcli_conn_get_login_user (adcli_conn *conn) + { +diff --git a/library/adconn.h b/library/adconn.h +index 13cfd32..1ad5715 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -97,6 +97,9 @@ LDAP * adcli_conn_get_ldap_connection (adcli_conn *conn); + + krb5_context adcli_conn_get_krb5_context (adcli_conn *conn); + ++void adcli_conn_set_krb5_context (adcli_conn *conn, ++ krb5_context k5); ++ + const char * adcli_conn_get_computer_name (adcli_conn *conn); + + void adcli_conn_set_computer_name (adcli_conn *conn, +-- +2.21.0 + diff --git a/SOURCES/0002-add-option-use-ldaps.patch b/SOURCES/0002-add-option-use-ldaps.patch new file mode 100644 index 0000000..8e97803 --- /dev/null +++ b/SOURCES/0002-add-option-use-ldaps.patch @@ -0,0 +1,370 @@ +From 196163b419f3a22c78bd14095b91822fe08aa595 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 19 Dec 2019 07:22:33 +0100 +Subject: [PATCH 2/2] add option use-ldaps + +In general using the LDAP port with GSS-SPNEGO should satifiy all +requirements an AD DC should have for authentication on an encrypted +LDAP connection. + +But if e.g. the LDAP port is blocked by a firewall using the LDAPS port +with TLS encryption might be an alternative. For this use case the +--use-ldaps option is added. + +Related to https://bugzilla.redhat.com/show_bug.cgi?id=1762420 +--- + doc/adcli.xml | 24 +++++++++++++++ + library/adconn.c | 79 ++++++++++++++++++++++++++++++++++++++++++------ + library/adconn.h | 4 +++ + tools/computer.c | 9 ++++++ + tools/entry.c | 11 +++++++ + 5 files changed, 118 insertions(+), 9 deletions(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 9605b4a..3cefe48 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -123,6 +123,30 @@ + If not specified, then an appropriate domain controller + is automatically discovered. + ++ ++ ++ Connect to the domain controller ++ with LDAPS. By default the LDAP port is used and SASL ++ GSS-SPNEGO or GSSAPI is used for authentication and to ++ establish encryption. This should satisfy all ++ requirements set on the server side and LDAPS should ++ only be used if the LDAP port is not accessible due to ++ firewalls or other reasons. ++ Please note that the place where CA certificates ++ can be found to validate the AD DC certificates ++ must be configured in the OpenLDAP configuration ++ file, e.g. /etc/openldap/ldap.conf. ++ As an alternative it can be specified with the help of ++ an environment variable, e.g. ++ ++$ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.example.com ++... ++ ++ Please see ++ ldap.conf ++ 5 for details. ++ ++ + + + Use the specified kerberos credential +diff --git a/library/adconn.c b/library/adconn.c +index a3f4548..8a55776 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -70,6 +70,7 @@ struct _adcli_conn_ctx { + char *domain_name; + char *domain_realm; + char *domain_controller; ++ bool use_ldaps; + char *canonical_host; + char *domain_short; + char *domain_sid; +@@ -773,7 +774,8 @@ int ldap_init_fd (ber_socket_t fd, int proto, LDAP_CONST char *url, struct ldap + + static LDAP * + connect_to_address (const char *host, +- const char *canonical_host) ++ const char *canonical_host, ++ bool use_ldaps) + { + struct addrinfo *res = NULL; + struct addrinfo *ai; +@@ -783,6 +785,16 @@ connect_to_address (const char *host, + char *url; + int sock; + int rc; ++ int opt_rc; ++ const char *port = "389"; ++ const char *proto = "ldap"; ++ const char *errmsg = NULL; ++ ++ if (use_ldaps) { ++ port = "636"; ++ proto = "ldaps"; ++ _adcli_info ("Using LDAPS to connect to %s", host); ++ } + + memset (&hints, '\0', sizeof(hints)); + #ifdef AI_ADDRCONFIG +@@ -794,7 +806,7 @@ connect_to_address (const char *host, + if (!canonical_host) + canonical_host = host; + +- rc = getaddrinfo (host, "389", &hints, &res); ++ rc = getaddrinfo (host, port, &hints, &res); + if (rc != 0) { + _adcli_err ("Couldn't resolve host name: %s: %s", host, gai_strerror (rc)); + return NULL; +@@ -810,7 +822,7 @@ connect_to_address (const char *host, + close (sock); + } else { + error = 0; +- if (asprintf (&url, "ldap://%s", canonical_host) < 0) ++ if (asprintf (&url, "%s://%s", proto, canonical_host) < 0) + return_val_if_reached (NULL); + rc = ldap_init_fd (sock, 1, url, &ldap); + free (url); +@@ -820,6 +832,25 @@ connect_to_address (const char *host, + ldap_err2string (rc)); + break; + } ++ ++ if (use_ldaps) { ++ rc = ldap_install_tls (ldap); ++ if (rc != LDAP_SUCCESS) { ++ opt_rc = ldap_get_option (ldap, ++ LDAP_OPT_DIAGNOSTIC_MESSAGE, ++ (void *) &errmsg); ++ if (opt_rc != LDAP_SUCCESS) { ++ errmsg = NULL; ++ } ++ _adcli_err ("Couldn't initialize TLS [%s]: %s", ++ ldap_err2string (rc), ++ errmsg == NULL ? "- no details -" ++ : errmsg); ++ ldap_unbind_ext_s (ldap, NULL, NULL); ++ ldap = NULL; ++ break; ++ } ++ } + } + } + +@@ -856,7 +887,8 @@ connect_and_lookup_naming (adcli_conn *conn, + if (!canonical_host) + canonical_host = disco->host_addr; + +- ldap = connect_to_address (disco->host_addr, canonical_host); ++ ldap = connect_to_address (disco->host_addr, canonical_host, ++ adcli_conn_get_use_ldaps (conn)); + if (ldap == NULL) + return ADCLI_ERR_DIRECTORY; + +@@ -1041,14 +1073,28 @@ authenticate_to_directory (adcli_conn *conn) + status = gss_krb5_ccache_name (&minor, conn->login_ccache_name, NULL); + return_unexpected_if_fail (status == 0); + +- /* Clumsily tell ldap + cyrus-sasl that we want encryption */ +- ssf = 1; +- ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf); +- return_unexpected_if_fail (ret == 0); ++ if (adcli_conn_get_use_ldaps (conn)) { ++ /* do not use SASL encryption on LDAPS connection */ ++ ssf = 0; ++ ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf); ++ return_unexpected_if_fail (ret == 0); ++ ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MAX, &ssf); ++ return_unexpected_if_fail (ret == 0); ++ } else { ++ /* Clumsily tell ldap + cyrus-sasl that we want encryption */ ++ ssf = 1; ++ ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf); ++ return_unexpected_if_fail (ret == 0); ++ } + +- if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")) { ++ /* There are issues with cryrus-sasl and GSS-SPNEGO with TLS even if ++ * ssf_max is set to 0. To be on the safe side GSS-SPNEGO is only used ++ * without LDAPS. */ ++ if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO") ++ && !adcli_conn_get_use_ldaps (conn)) { + mech = "GSS-SPNEGO"; + } ++ _adcli_info ("Using %s for SASL bind", mech); + + ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, mech, NULL, NULL, + LDAP_SASL_QUIET, sasl_interact, NULL); +@@ -1230,6 +1276,7 @@ adcli_conn_new (const char *domain_name) + conn->refs = 1; + conn->logins_allowed = ADCLI_LOGIN_COMPUTER_ACCOUNT | ADCLI_LOGIN_USER_ACCOUNT; + adcli_conn_set_domain_name (conn, domain_name); ++ adcli_conn_set_use_ldaps (conn, false); + return conn; + } + +@@ -1389,6 +1436,20 @@ adcli_conn_set_domain_controller (adcli_conn *conn, + no_more_disco (conn); + } + ++bool ++adcli_conn_get_use_ldaps (adcli_conn *conn) ++{ ++ return_val_if_fail (conn != NULL, NULL); ++ return conn->use_ldaps; ++} ++ ++void ++adcli_conn_set_use_ldaps (adcli_conn *conn, bool value) ++{ ++ return_if_fail (conn != NULL); ++ conn->use_ldaps = value; ++} ++ + const char * + adcli_conn_get_domain_short (adcli_conn *conn) + { +diff --git a/library/adconn.h b/library/adconn.h +index 8e88045..3e287b1 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -89,6 +89,10 @@ const char * adcli_conn_get_domain_controller (adcli_conn *conn); + void adcli_conn_set_domain_controller (adcli_conn *conn, + const char *value); + ++bool adcli_conn_get_use_ldaps (adcli_conn *conn); ++void adcli_conn_set_use_ldaps (adcli_conn *conn, ++ bool value); ++ + const char * adcli_conn_get_domain_short (adcli_conn *conn); + + const char * adcli_conn_get_domain_sid (adcli_conn *conn); +diff --git a/tools/computer.c b/tools/computer.c +index ac8a203..7bf8f9b 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -112,12 +112,14 @@ typedef enum { + opt_trusted_for_delegation, + opt_add_service_principal, + opt_remove_service_principal, ++ opt_use_ldaps, + } Option; + + static adcli_tool_desc common_usages[] = { + { opt_domain, "active directory domain name" }, + { opt_domain_realm, "kerberos realm for the domain" }, + { opt_domain_controller, "domain controller to connect to" }, ++ { opt_use_ldaps, "use LDAPS port for communication" }, + { opt_host_fqdn, "override the fully qualified domain name of the\n" + "local machine" }, + { opt_host_keytab, "filename for the host kerberos keytab" }, +@@ -306,6 +308,9 @@ parse_option (Option opt, + case opt_remove_service_principal: + adcli_enroll_add_service_principal_to_remove (enroll, optarg); + return ADCLI_SUCCESS; ++ case opt_use_ldaps: ++ adcli_conn_set_use_ldaps (conn, true); ++ return ADCLI_SUCCESS; + case opt_verbose: + return ADCLI_SUCCESS; + +@@ -352,6 +357,7 @@ adcli_tool_computer_join (adcli_conn *conn, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, + { "domain-server", required_argument, NULL, opt_domain_controller }, /* compat */ ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "user", required_argument, NULL, opt_login_user }, /* compat */ + { "login-ccache", optional_argument, NULL, opt_login_ccache }, +@@ -681,6 +687,7 @@ adcli_tool_computer_preset (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "domain-ou", required_argument, NULL, opt_domain_ou }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, +@@ -793,6 +800,7 @@ adcli_tool_computer_reset (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "login-type", required_argument, NULL, opt_login_type }, +@@ -881,6 +889,7 @@ adcli_tool_computer_delete (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "no-password", no_argument, 0, opt_no_password }, +diff --git a/tools/entry.c b/tools/entry.c +index f361845..05e4313 100644 +--- a/tools/entry.c ++++ b/tools/entry.c +@@ -53,6 +53,7 @@ typedef enum { + opt_unix_gid, + opt_unix_shell, + opt_nis_domain, ++ opt_use_ldaps, + } Option; + + static adcli_tool_desc common_usages[] = { +@@ -67,6 +68,7 @@ static adcli_tool_desc common_usages[] = { + { opt_domain, "active directory domain name" }, + { opt_domain_realm, "kerberos realm for the domain" }, + { opt_domain_controller, "domain directory server to connect to" }, ++ { opt_use_ldaps, "use LDAPS port for communication" }, + { opt_login_ccache, "kerberos credential cache file which contains\n" + "ticket to used to connect to the domain" }, + { opt_login_user, "user (usually administrative) login name of\n" +@@ -136,6 +138,9 @@ parse_option (Option opt, + stdin_password = 1; + } + return ADCLI_SUCCESS; ++ case opt_use_ldaps: ++ adcli_conn_set_use_ldaps (conn, true); ++ return ADCLI_SUCCESS; + case opt_verbose: + return ADCLI_SUCCESS; + default: +@@ -172,6 +177,7 @@ adcli_tool_user_create (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "no-password", no_argument, 0, opt_no_password }, +@@ -306,6 +312,7 @@ adcli_tool_user_delete (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "no-password", no_argument, 0, opt_no_password }, +@@ -394,6 +401,7 @@ adcli_tool_group_create (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "domain-ou", required_argument, NULL, opt_domain_ou }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, +@@ -496,6 +504,7 @@ adcli_tool_group_delete (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "no-password", no_argument, 0, opt_no_password }, +@@ -622,6 +631,7 @@ adcli_tool_member_add (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "no-password", no_argument, 0, opt_no_password }, +@@ -722,6 +732,7 @@ adcli_tool_member_remove (adcli_conn *conn, + { "domain", required_argument, NULL, opt_domain }, + { "domain-realm", required_argument, NULL, opt_domain_realm }, + { "domain-controller", required_argument, NULL, opt_domain_controller }, ++ { "use-ldaps", no_argument, 0, opt_use_ldaps }, + { "login-user", required_argument, NULL, opt_login_user }, + { "login-ccache", optional_argument, NULL, opt_login_ccache }, + { "no-password", no_argument, 0, opt_no_password }, +-- +2.21.1 + diff --git a/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch b/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch new file mode 100644 index 0000000..f810c13 --- /dev/null +++ b/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch @@ -0,0 +1,196 @@ +From 0c09070e8beec734e3f0c70e14b0a04788077b73 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 13 Jun 2019 17:25:52 +0200 +Subject: [PATCH 3/4] adenroll: add adcli_enroll_get_permitted_keytab_enctypes + with tests + +The new call does not only return the current encryption types set in AD +or a default list but filters them with the list of permitted encryption +types on the client. This makes sure the client can create and use the +keys. + +Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3 +--- + library/Makefile.am | 5 ++ + library/adenroll.c | 124 ++++++++++++++++++++++++++++++++++++++++++++ + library/adenroll.h | 2 + + 3 files changed, 131 insertions(+) + +diff --git a/library/Makefile.am b/library/Makefile.am +index 39e8fd1..4829555 100644 +--- a/library/Makefile.am ++++ b/library/Makefile.am +@@ -40,6 +40,7 @@ check_PROGRAMS = \ + test-util \ + test-ldap \ + test-attrs \ ++ test-adenroll \ + $(NULL) + + test_seq_SOURCES = seq.c test.c test.h +@@ -56,6 +57,10 @@ test_attrs_SOURCES = adattrs.c $(test_ldap_SOURCES) + test_attrs_CFLAGS = -DATTRS_TESTS + test_attrs_LDADD = $(test_ldap_LDADD) + ++test_adenroll_SOURCES = adenroll.c $(test_ldap_SOURCES) ++test_adenroll_CFLAGS = -DADENROLL_TESTS ++test_adenroll_LDADD = $(KRB5_LIBS) ++ + TESTS = $(check_PROGRAMS) + + MEMCHECK_ENV = $(TEST_RUNNER) valgrind --error-exitcode=80 --quiet --trace-children=yes +diff --git a/library/adenroll.c b/library/adenroll.c +index f617f28..95c07cd 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2641,6 +2641,50 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll) + return v51_earlier_enctypes; + } + ++krb5_enctype * ++adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll) ++{ ++ krb5_enctype *cur_enctypes; ++ krb5_enctype *permitted_enctypes; ++ krb5_enctype *new_enctypes; ++ krb5_error_code code; ++ krb5_context k5; ++ size_t c; ++ size_t p; ++ size_t n; ++ ++ return_val_if_fail (enroll != NULL, NULL); ++ cur_enctypes = adcli_enroll_get_keytab_enctypes (enroll); ++ ++ k5 = adcli_conn_get_krb5_context (enroll->conn); ++ return_val_if_fail (k5 != NULL, NULL); ++ ++ code = krb5_get_permitted_enctypes (k5, &permitted_enctypes); ++ return_val_if_fail (code == 0, NULL); ++ ++ for (c = 0; cur_enctypes[c] != 0; c++); ++ ++ new_enctypes = calloc (c + 1, sizeof (krb5_enctype)); ++ return_val_if_fail (new_enctypes != NULL, NULL); ++ ++ n = 0; ++ for (c = 0; cur_enctypes[c] != 0; c++) { ++ for (p = 0; permitted_enctypes[p] != 0; p++) { ++ if (cur_enctypes[c] == permitted_enctypes[p]) { ++ new_enctypes[n++] = cur_enctypes[c]; ++ break; ++ } ++ } ++ if (permitted_enctypes[p] == 0) { ++ _adcli_info ("Encryption type [%d] not permitted.", cur_enctypes[c]); ++ } ++ } ++ ++ krb5_free_enctypes (k5, permitted_enctypes); ++ ++ return new_enctypes; ++} ++ + void + adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, + krb5_enctype *value) +@@ -2833,3 +2877,83 @@ adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll, + strdup (value), NULL); + return_if_fail (enroll->service_principals_to_remove != NULL); + } ++ ++#ifdef ADENROLL_TESTS ++ ++#include "test.h" ++ ++static void ++test_adcli_enroll_get_permitted_keytab_enctypes (void) ++{ ++ krb5_enctype *enctypes; ++ krb5_error_code code; ++ krb5_enctype *permitted_enctypes; ++ krb5_enctype check_enctypes[3] = { 0 }; ++ adcli_conn *conn; ++ adcli_enroll *enroll; ++ adcli_result res; ++ krb5_context k5; ++ size_t c; ++ ++ conn = adcli_conn_new ("test.dom"); ++ assert_ptr_not_null (conn); ++ ++ enroll = adcli_enroll_new (conn); ++ assert_ptr_not_null (enroll); ++ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (NULL); ++ assert_ptr_eq (enctypes, NULL); ++ ++ /* krb5 context missing */ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ assert_ptr_eq (enctypes, NULL); ++ ++ /* check that all permitted enctypes can pass */ ++ res = _adcli_krb5_init_context (&k5); ++ assert_num_eq (res, ADCLI_SUCCESS); ++ ++ adcli_conn_set_krb5_context (conn, k5); ++ ++ code = krb5_get_permitted_enctypes (k5, &permitted_enctypes); ++ assert_num_eq (code, 0); ++ assert_ptr_not_null (permitted_enctypes); ++ assert_num_cmp (permitted_enctypes[0], !=, 0); ++ ++ adcli_enroll_set_keytab_enctypes (enroll, permitted_enctypes); ++ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ assert_ptr_not_null (enctypes); ++ for (c = 0; permitted_enctypes[c] != 0; c++) { ++ assert_num_eq (enctypes[c], permitted_enctypes[c]); ++ } ++ assert_num_eq (enctypes[c], 0); ++ krb5_free_enctypes (k5, enctypes); ++ ++ /* check that ENCTYPE_UNKNOWN is filtered out */ ++ check_enctypes[0] = permitted_enctypes[0]; ++ check_enctypes[1] = ENCTYPE_UNKNOWN; ++ check_enctypes[2] = 0; ++ adcli_enroll_set_keytab_enctypes (enroll, check_enctypes); ++ ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ assert_ptr_not_null (enctypes); ++ assert_num_eq (enctypes[0], permitted_enctypes[0]); ++ assert_num_eq (enctypes[1], 0); ++ krb5_free_enctypes (k5, enctypes); ++ ++ krb5_free_enctypes (k5, permitted_enctypes); ++ ++ adcli_enroll_unref (enroll); ++ adcli_conn_unref (conn); ++} ++ ++int ++main (int argc, ++ char *argv[]) ++{ ++ test_func (test_adcli_enroll_get_permitted_keytab_enctypes, ++ "/attrs/adcli_enroll_get_permitted_keytab_enctypes"); ++ return test_run (argc, argv); ++} ++ ++#endif /* ADENROLL_TESTS */ +diff --git a/library/adenroll.h b/library/adenroll.h +index abbbfd4..1d5d00d 100644 +--- a/library/adenroll.h ++++ b/library/adenroll.h +@@ -138,6 +138,8 @@ krb5_enctype * adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll); + void adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, + krb5_enctype *enctypes); + ++krb5_enctype * adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll); ++ + const char * adcli_enroll_get_os_name (adcli_enroll *enroll); + + void adcli_enroll_set_os_name (adcli_enroll *enroll, +-- +2.21.0 + diff --git a/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch b/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch new file mode 100644 index 0000000..a496e32 --- /dev/null +++ b/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch @@ -0,0 +1,103 @@ +From cc3ef52884a48863a81acbfc741735fe09cd85f7 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 13 Jun 2019 18:27:49 +0200 +Subject: [PATCH 4/4] adenroll: use only enctypes permitted by Kerberos config + +Realted to https://gitlab.freedesktop.org/realmd/adcli/issues/3 +--- + doc/adcli.xml | 10 ++++++++++ + library/adenroll.c | 22 +++++++++++++++++++--- + 2 files changed, 29 insertions(+), 3 deletions(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 9605b4a..094f577 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -342,6 +342,11 @@ Password for Administrator: + + + ++ If supported on the AD side the ++ attribute will be set as ++ well. Either the current value or the default list of AD's supported ++ encryption types filtered by the permitted encryption types of the ++ client's Kerberos configuration are written. + + + +@@ -475,6 +480,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + + + ++ If supported on the AD side the ++ attribute will be set as ++ well. Either the current value or the default list of AD's supported ++ encryption types filtered by the permitted encryption types of the ++ client's Kerberos configuration are written. + + + +diff --git a/library/adenroll.c b/library/adenroll.c +index 95c07cd..53cd812 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -639,6 +639,7 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype) + { + char *value = NULL; + krb5_enctype *read_enctypes; ++ krb5_enctype *new_enctypes; + char *new_value = NULL; + int is_2008_or_later; + LDAP *ldap; +@@ -685,7 +686,14 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype) + value = _adcli_krb5_format_enctypes (v51_earlier_enctypes); + } + +- new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll)); ++ new_enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ if (new_enctypes == NULL) { ++ _adcli_warn ("No permitted encryption type found."); ++ return ADCLI_ERR_UNEXPECTED; ++ } ++ ++ new_value = _adcli_krb5_format_enctypes (new_enctypes); ++ krb5_free_enctypes (adcli_conn_get_krb5_context (enroll->conn), new_enctypes); + if (new_value == NULL) { + free (value); + _adcli_warn ("The encryption types desired are not available in active directory"); +@@ -1758,7 +1766,11 @@ add_principal_to_keytab (adcli_enroll *enroll, + enroll->keytab_name); + } + +- enctypes = adcli_enroll_get_keytab_enctypes (enroll); ++ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll); ++ if (enctypes == NULL) { ++ _adcli_warn ("No permitted encryption type found."); ++ return ADCLI_ERR_UNEXPECTED; ++ } + + if (flags & ADCLI_ENROLL_PASSWORD_VALID) { + code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal, +@@ -1774,7 +1786,10 @@ add_principal_to_keytab (adcli_enroll *enroll, + */ + + salts = build_principal_salts (enroll, k5, principal); +- return_unexpected_if_fail (salts != NULL); ++ if (salts == NULL) { ++ krb5_free_enctypes (k5, enctypes); ++ return ADCLI_ERR_UNEXPECTED; ++ } + + if (*which_salt < 0) { + code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password, +@@ -1794,6 +1809,7 @@ add_principal_to_keytab (adcli_enroll *enroll, + + free_principal_salts (k5, salts); + } ++ krb5_free_enctypes (k5, enctypes); + + if (code != 0) { + _adcli_err ("Couldn't add keytab entries: %s: %s", +-- +2.21.0 + diff --git a/SPECS/adcli.spec b/SPECS/adcli.spec index 4fc9299..0ebe6b9 100644 --- a/SPECS/adcli.spec +++ b/SPECS/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.8.1 -Release: 9%{?dist} +Release: 13%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: http://cgit.freedesktop.org/realmd/adcli @@ -90,6 +90,29 @@ Patch53: 0005-tools-remove-errx-from-setup_krb5_conf_directory.patch Patch54: 0006-tools-entry-remove-errx-from-parse_option.patch Patch55: 0007-tools-computer-remove-errx-from-parse_option.patch +# rhbz#1665162 - adcli is failing with "Couldn't add keytab entries: FILE:/etc/krb5.keytab: Cannot allocate memory" (edit) +Patch56: 0001-Fix-for-issues-found-by-Coverity.patch +Patch57: 0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch +Patch58: 0002-adconn-add-adcli_conn_set_krb5_context.patch +Patch59: 0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch +Patch60: 0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch + +# Coverity fix related to fixes for rhbz#1665162 +Patch61: 0001-Fix-for-issue-found-by-Coverity.patch + +# rhbz#1683745 - Issue is that with arcfour-hmac as first encryption type +Patch62: 0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch + +# rhbz#1738573 - adcli update --add-samba-data does not work as expected +Patch63: 0001-doc-explain-how-to-force-password-reset.patch + +# rhbz#1685138 - adcli info should send netlogin pings to all domain controllers, not only a subset +Patch64: 0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch + +# rhbz#1786776 - adcli should be able to Force LDAPS over 636 with AD Access Provider w.r.t sssd (RHEL7) +Patch65: 0001-Use-GSS-SPNEGO-if-available.patch +Patch66: 0002-add-option-use-ldaps.patch + BuildRequires: intltool pkgconfig BuildRequires: libtool BuildRequires: gettext-devel @@ -138,6 +161,21 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %doc %{_mandir}/*/* %changelog +* Tue Jan 14 2020 Sumit Bose - 0.8.1-13 +- adcli should be able to Force LDAPS over 636 with AD Access Provider w.r.t sssd [#1786776] + +* Wed Sep 04 2019 Sumit Bose - 0.8.1-12 +- adcli info should send netlogin pings to all domain controllers, not only a subset [#1685138] + +* Tue Aug 27 2019 Sumit Bose - 0.8.1-11 +- Fixes and improvements for RHEL-7.8 +- Issue is that with arcfour-hmac as first encryption type in the config ... [#1683745] +- adcli update --add-samba-data does not work as expected [#1738573] + +* Mon Aug 12 2019 Sumit Bose - 0.8.1-10 +- adcli is failing with "Couldn't add keytab entries: FILE:/etc/krb5.keytab: + Cannot allocate memory" [1665162] + * Thu May 02 2019 Sumit Bose - 0.8.1-9 - Fixes for RHEL-7.7 updates - additional patch for [RFE] adcli join should preserve SPN added by adcli