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..f37f2f1 --- /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.26.2 + 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..bae8b22 --- /dev/null +++ b/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch @@ -0,0 +1,124 @@ +From a6f795ba3d6048b32d7863468688bf7f42b2cafd 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 bcaced8..ffb54f9 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); +@@ -1606,6 +1619,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 1ad5715..37ebdd9 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -149,6 +149,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.0 + diff --git a/SOURCES/0001-delete-do-not-exit-if-keytab-cannot-be-read.patch b/SOURCES/0001-delete-do-not-exit-if-keytab-cannot-be-read.patch new file mode 100644 index 0000000..15aaf07 --- /dev/null +++ b/SOURCES/0001-delete-do-not-exit-if-keytab-cannot-be-read.patch @@ -0,0 +1,32 @@ +From 40d3be22f6e518e4354aa7c3d0278291fcbed32f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 5 Jun 2020 17:06:58 +0200 +Subject: [PATCH] delete: do not exit if keytab cannot be read + +Reading the keytab is not required when deleting a host object in AD. It +is only needed in the case where the host was added with a manual set +NetBIOS name (--computer-name option) which does not match the short +hostname and no computer name was given at the delete-computer command +line. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1840752 +--- + tools/computer.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/tools/computer.c b/tools/computer.c +index 292c4d8..a90c4b2 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -952,8 +952,6 @@ adcli_tool_computer_delete (adcli_conn *conn, + if (res != ADCLI_SUCCESS) { + warnx ("couldn't lookup domain info from keytab: %s", + adcli_get_last_error ()); +- adcli_enroll_unref (enroll); +- return -res; + } + + res = adcli_conn_connect (conn); +-- +2.26.2 + diff --git a/SOURCES/0001-discovery-fix.patch b/SOURCES/0001-discovery-fix.patch new file mode 100644 index 0000000..7c1018d --- /dev/null +++ b/SOURCES/0001-discovery-fix.patch @@ -0,0 +1,27 @@ +From 08bac0946de29f3e5de90743ce6dfc7118d4ad20 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 11 Feb 2020 17:42:03 +0100 +Subject: [PATCH] discovery fix + +Do not continue processing on closed connection. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1802258 +--- + library/addisco.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/library/addisco.c b/library/addisco.c +index 6e73ead..f3b3546 100644 +--- a/library/addisco.c ++++ b/library/addisco.c +@@ -622,6 +622,7 @@ ldap_disco (const char *domain, + "Couldn't perform discovery search"); + ldap_unbind_ext_s (ldap[i], NULL, NULL); + ldap[i] = NULL; ++ continue; + } + + /* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first +-- +2.26.2 + diff --git a/SOURCES/0001-man-explain-optional-parameter-of-login-ccache-bette.patch b/SOURCES/0001-man-explain-optional-parameter-of-login-ccache-bette.patch new file mode 100644 index 0000000..191fa3e --- /dev/null +++ b/SOURCES/0001-man-explain-optional-parameter-of-login-ccache-bette.patch @@ -0,0 +1,44 @@ +From 93a39bd12db11dd407676f428cfbc30406a88c36 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Jun 2020 15:57:47 +0200 +Subject: [PATCH] man: explain optional parameter of login-ccache better + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791545 +--- + doc/adcli.xml | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index acced25..ecf8726 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -155,13 +155,19 @@ $ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.exa + + + Use the specified kerberos credential +- cache to authenticate with the domain. If no credential +- cache is specified, the default kerberos credential +- cache will be used. Credential caches of type FILE can +- be given with the path to the file. For other +- credential cache types, e.g. DIR, KEYRING or KCM, the +- type must be specified explicitly together with a +- suitable identifier. ++ cache to authenticate with the domain. If no credential ++ cache is specified, the default kerberos credential ++ cache will be used. Credential caches of type FILE can ++ be given with the path to the file. For other ++ credential cache types, e.g. DIR, KEYRING or KCM, the ++ type must be specified explicitly together with a ++ suitable identifier. ++ Please note that since the ++ ccache_name is optional the ++ =(equal) sign is mandatory. If = is missing the ++ parameter is treated as optionless extra argument. How ++ this is handled depends on the specific sub-command. ++ + + + +-- +2.26.2 + diff --git a/SOURCES/0001-tools-disable-SSSD-s-locator-plugin.patch b/SOURCES/0001-tools-disable-SSSD-s-locator-plugin.patch new file mode 100644 index 0000000..07d791e --- /dev/null +++ b/SOURCES/0001-tools-disable-SSSD-s-locator-plugin.patch @@ -0,0 +1,41 @@ +From 50d580c58dab5928cadfc6ca82aedccee58eaced Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 5 Jun 2020 17:28:28 +0200 +Subject: [PATCH] tools: disable SSSD's locator plugin + +MIT's libkrb5 checks available locator plugins first before checking the +config file. This might cause issues when the locator plugin returns a +different DC than the one used for the LDAP connection if some data must +be replicated. + +This patch sets the SSSD_KRB5_LOCATOR_DISABLE environment variable to +'true' to disable SSSD's locator plugin for adcli. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1762633 +--- + tools/tools.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/tools.c b/tools/tools.c +index 9d422f2..1b6d879 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -296,6 +296,7 @@ cleanup_krb5_conf_directory (void) + } + + unsetenv ("KRB5_CONFIG"); ++ unsetenv ("SSSD_KRB5_LOCATOR_DISABLE"); + } + + static void +@@ -394,6 +395,7 @@ setup_krb5_conf_directory (adcli_conn *conn) + adcli_krb5_conf_filename = filename; + adcli_krb5_d_directory = snippets; + setenv ("KRB5_CONFIG", adcli_krb5_conf_filename, 1); ++ setenv ("SSSD_KRB5_LOCATOR_DISABLE", "true", 1); + + } else { + free (filename); +-- +2.26.2 + diff --git a/SOURCES/0001-tools-fix-typo-in-show-password-help-output.patch b/SOURCES/0001-tools-fix-typo-in-show-password-help-output.patch new file mode 100644 index 0000000..d82d49c --- /dev/null +++ b/SOURCES/0001-tools-fix-typo-in-show-password-help-output.patch @@ -0,0 +1,26 @@ +From d70075c597e7ebc1683d407409c45b04110676a0 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 15 Jun 2020 15:41:53 +0200 +Subject: [PATCH] tools: fix typo in show-password help output + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791611 +--- + tools/computer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/computer.c b/tools/computer.c +index a90c4b2..24ea258 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -154,7 +154,7 @@ static adcli_tool_desc common_usages[] = { + "accounts" }, + { opt_show_details, "show information about joining the domain after\n" + "a successful join" }, +- { opt_show_password, "show computer account password after after a\n" ++ { opt_show_password, "show computer account password after a\n" + "successful join" }, + { opt_add_samba_data, "add domain SID and computer account password\n" + "to the Samba specific configuration database" }, +-- +2.26.2 + diff --git a/SOURCES/0002-add-option-use-ldaps.patch b/SOURCES/0002-add-option-use-ldaps.patch new file mode 100644 index 0000000..ab34272 --- /dev/null +++ b/SOURCES/0002-add-option-use-ldaps.patch @@ -0,0 +1,378 @@ +From 85097245b57f190337225dbdbf6e33b58616c092 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 | 10 ++++++ + tools/entry.c | 11 +++++++ + 5 files changed, 119 insertions(+), 9 deletions(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index dd30435..acced25 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -128,6 +128,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 ffb54f9..7bab852 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 37ebdd9..1d5faa8 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 840e334..292c4d8 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -113,12 +113,14 @@ typedef enum { + opt_add_service_principal, + opt_remove_service_principal, + opt_description, ++ 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" }, +@@ -311,6 +313,9 @@ parse_option (Option opt, + case opt_description: + adcli_enroll_set_description (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; + +@@ -357,6 +362,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 }, +@@ -688,6 +694,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 }, +@@ -800,6 +807,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 }, +@@ -888,6 +896,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 }, +@@ -985,6 +994,7 @@ adcli_tool_computer_show (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 }, +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.0 + diff --git a/SPECS/adcli.spec b/SPECS/adcli.spec index 5a5336b..d0ecaa3 100644 --- a/SPECS/adcli.spec +++ b/SPECS/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.8.2 -Release: 4%{?dist} +Release: 6%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: http://cgit.freedesktop.org/realmd/adcli @@ -104,6 +104,26 @@ Patch58: 0001-Fix-for-issue-found-by-Coverity.patch Patch59: 0001-tools-add-show-computer-command.patch Patch60: 0002-add-description-option-to-join-and-update.patch +Patch61: 0001-Use-GSS-SPNEGO-if-available.patch +Patch62: 0002-add-option-use-ldaps.patch + +# rhbz#1806260 - [abrt] [faf] adcli: raise(): /usr/sbin/adcli killed by 6 +Patch63: 0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch +Patch64: 0001-discovery-fix.patch + +# rhbz#1846882 - No longer able to delete computer from AD using adcli +Patch65: 0001-delete-do-not-exit-if-keytab-cannot-be-read.patch + +# rhbz#1846878 - adcli: presetting $computer in $domain domain failed: Cannot +# set computer password: Authentication error +Patch66: 0001-tools-disable-SSSD-s-locator-plugin.patch + +# rhbz#1791611 - Typo in adcli update --help option +Patch67: 0001-tools-fix-typo-in-show-password-help-output.patch + +# rhbz#1791545 - Manpage and help does not explain the use of "-C" option +Patch68: 0001-man-explain-optional-parameter-of-login-ccache-bette.patch + BuildRequires: gcc BuildRequires: intltool pkgconfig BuildRequires: libtool @@ -164,6 +184,18 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Mon Jun 15 2020 Sumit Bose - 0.8.2-6 +- [abrt] [faf] adcli: raise(): /usr/sbin/adcli killed by 6 [#1806260] +- No longer able to delete computer from AD using adcli [#1846882] +- adcli: presetting $computer in $domain domain failed: Cannot set computer + password: Authentication error [#1846878] +- Typo in adcli update --help option [#1791611] +- Manpage and help does not explain the use of "-C" option [#1791545] + +* Wed Jan 29 2020 Sumit Bose - 0.8.2-5 +- adcli should be able to Force LDAPS over 636 with AD Access Provider w.r.t + sssd [#1762420] + * Thu Nov 28 2019 Sumit Bose - 0.8.2-4 - adcli update --add-samba-data does not work as expected [#1745931] - Issue is that with arcfour-hmac as first encryption type [#1745932]