diff --git a/.gitignore b/.gitignore index e6fcc1d..440751f 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,3 @@ /adcli-0.9.0.tar.gz /adcli-0.9.1.tar.gz /adcli-0.9.2.tar.gz -/adcli-0.9.3.1.tar.gz diff --git a/0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch b/0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch new file mode 100644 index 0000000..fab7322 --- /dev/null +++ b/0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch @@ -0,0 +1,97 @@ +From a4aa0d00f588ba24484db70aeb3bdafdf618c4f6 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 13:39:12 +0200 +Subject: [PATCH 01/17] disco: Add functions to extract domain GUID from LDAP + ping + +Signed-off-by: Samuel Cabrero +--- + library/addisco.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 72 insertions(+) + +diff --git a/library/addisco.c b/library/addisco.c +index b2c5553..ac073e5 100644 +--- a/library/addisco.c ++++ b/library/addisco.c +@@ -335,6 +335,78 @@ get_32_le (unsigned char **at, + return 1; + } + ++static int ++get_16_le (unsigned char **at, ++ unsigned char *end, ++ uint16_t *val) ++{ ++ unsigned char *p = *at; ++ if (end - p < 2) ++ return 0; ++ *val = p[0] | p[1] << 8; ++ (*at) += 2; ++ return 1; ++} ++ ++struct GUID { ++ uint32_t time_low; ++ uint16_t time_mid; ++ uint16_t time_hi_and_version; ++ uint8_t clock_seq[2]; ++ uint8_t node[6]; ++}; ++ ++/* Format is "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" */ ++/* 32 chars + 4 ' ' + \0 + 2 for adding {} */ ++struct GUID_txt_buf { ++ char buf[39]; ++}; ++ ++static char *GUID_buf_string(const struct GUID *guid, ++ struct GUID_txt_buf *dst) ++{ ++ if (guid == NULL) { ++ return NULL; ++ } ++ snprintf(dst->buf, sizeof(dst->buf), ++ "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", ++ guid->time_low, guid->time_mid, ++ guid->time_hi_and_version, ++ guid->clock_seq[0], ++ guid->clock_seq[1], ++ guid->node[0], guid->node[1], ++ guid->node[2], guid->node[3], ++ guid->node[4], guid->node[5]); ++ return dst->buf; ++} ++ ++static int ++parse_guid (unsigned char **at, ++ unsigned char *end, ++ char **result) ++{ ++ struct GUID g = { 0 }; ++ struct GUID_txt_buf buf; ++ ++ if (end - (*at) < sizeof(struct GUID)) { ++ return 0; ++ } ++ ++ get_32_le(at, end, &g.time_low); ++ get_16_le(at, end, &g.time_mid); ++ get_16_le(at, end, &g.time_hi_and_version); ++ ++ memcpy(&g.clock_seq, *at, sizeof(g.clock_seq)); ++ (*at) += sizeof(g.clock_seq); ++ ++ memcpy(&g.node, *at, sizeof(g.node)); ++ (*at) += sizeof(g.node); ++ ++ *result = strdup(GUID_buf_string(&g, &buf)); ++ ++ return 1; ++} ++ + static int + skip_n (unsigned char **at, + unsigned char *end, +-- +2.47.0 + diff --git a/0001-enroll-fix-issues-if-default-keytab-is-used.patch b/0001-enroll-fix-issues-if-default-keytab-is-used.patch deleted file mode 100644 index 953b97a..0000000 --- a/0001-enroll-fix-issues-if-default-keytab-is-used.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 9c31bb06590f2d96a2d6d8ce87dc3273c283a671 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 19 Dec 2025 14:48:13 +0100 -Subject: [PATCH] enroll: fix issues if default keytab is used - -librkb5 returns the default keytab with a 'FILE:' prefix which must be -removed before calling libselinux functions to operate on the keytab -file. - -Resolves: https://issues.redhat.com/browse/RHEL-78631 ---- - library/adenroll.c | 32 ++++++++++++++++++++------------ - library/adenroll.h | 3 +-- - tools/computer.c | 6 +++--- - 3 files changed, 24 insertions(+), 17 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 20ad198..9484cbf 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -2116,30 +2116,38 @@ ensure_host_keytab (adcli_result res, - return ADCLI_SUCCESS; - } - --adcli_result --ensure_host_keytab_selinux_context (adcli_result res, -- adcli_enroll *enroll) -+void -+restore_host_keytab_selinux_context (adcli_enroll *enroll) - { - #ifdef BUILD_SELINUX_POLICY - int ret; -- -- if (res != ADCLI_SUCCESS) -- return res; -+ krb5_context k5; -+ const char *name_start; - - if (enroll->keytab_name == NULL) { - _adcli_info ("No keytab name available, skipping SELinux restorecon."); -- return ADCLI_SUCCESS; -+ return; -+ } -+ -+ name_start = enroll->keytab_name; -+ if (strncmp (name_start, "FILE:", 5) == 0) { -+ name_start = enroll->keytab_name + 5; - } - -- ret = selinux_restorecon (adcli_enroll_get_keytab_name (enroll), 0); -+ if (enroll->keytab != NULL) { -+ k5 = adcli_conn_get_krb5_context (enroll->conn); -+ krb5_kt_close (k5, enroll->keytab); -+ enroll->keytab = NULL; -+ } -+ -+ ret = selinux_restorecon (name_start, 0); - if (ret != 0) { -- _adcli_err ("Failed to set SELinux context for %s with error %d: %s", -- enroll->keytab_name, ret, strerror (ret)); -- return ADCLI_ERR_FAIL; -+ _adcli_err ("Failed to set SELinux context for %s with error %d: %s, ignored", -+ name_start, ret, strerror (errno)); - } - #endif - -- return ADCLI_SUCCESS; -+ return; - } - - -diff --git a/library/adenroll.h b/library/adenroll.h -index 79eb7a8..5aba81b 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -192,6 +192,5 @@ void adcli_enroll_set_samba_data_tool (adcli_enroll *enroll, - - const char * adcli_enroll_get_samba_data_tool (adcli_enroll *enroll); - --adcli_result ensure_host_keytab_selinux_context (adcli_result res, -- adcli_enroll *enroll); -+void restore_host_keytab_selinux_context (adcli_enroll *enroll); - #endif /* ADENROLL_H_ */ -diff --git a/tools/computer.c b/tools/computer.c -index ee027dc..f056366 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -520,7 +520,7 @@ adcli_tool_computer_join (adcli_conn *conn, - else if (show_password) - dump_password (conn, enroll); - -- ensure_host_keytab_selinux_context (ADCLI_SUCCESS, enroll); -+ restore_host_keytab_selinux_context (enroll); - - adcli_enroll_unref (enroll); - -@@ -655,7 +655,7 @@ adcli_tool_computer_update (adcli_conn *conn, - else if (show_password) - dump_password (conn, enroll); - -- ensure_host_keytab_selinux_context (ADCLI_SUCCESS, enroll); -+ restore_host_keytab_selinux_context (enroll); - - adcli_enroll_unref (enroll); - -@@ -1275,7 +1275,7 @@ adcli_tool_computer_managed_service_account (adcli_conn *conn, - else if (show_password) - dump_password (conn, enroll); - -- ensure_host_keytab_selinux_context (ADCLI_SUCCESS, enroll); -+ restore_host_keytab_selinux_context (enroll); - - adcli_enroll_unref (enroll); - --- -2.52.0 - diff --git a/0002-disco-Extract-domain-GUID-from-LDAP-ping.patch b/0002-disco-Extract-domain-GUID-from-LDAP-ping.patch new file mode 100644 index 0000000..d91ce20 --- /dev/null +++ b/0002-disco-Extract-domain-GUID-from-LDAP-ping.patch @@ -0,0 +1,65 @@ +From f443691a420b37f84e5af04ffd8fd2e7e1e7be25 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 13:40:08 +0200 +Subject: [PATCH 02/17] disco: Extract domain GUID from LDAP ping + +Signed-off-by: Samuel Cabrero +--- + library/addisco.c | 14 ++------------ + library/addisco.h | 1 + + 2 files changed, 3 insertions(+), 12 deletions(-) + +diff --git a/library/addisco.c b/library/addisco.c +index ac073e5..7136f0e 100644 +--- a/library/addisco.c ++++ b/library/addisco.c +@@ -407,17 +407,6 @@ parse_guid (unsigned char **at, + return 1; + } + +-static int +-skip_n (unsigned char **at, +- unsigned char *end, +- int n) +-{ +- if (end - (*at) < n) +- return 0; +- (*at) += n; +- return 1; +-} +- + static adcli_disco * + parse_disco_data (struct berval *bv) + { +@@ -436,7 +425,7 @@ parse_disco_data (struct berval *bv) + /* domain forest */ + if (!get_32_le (&at, end, &type) || type != 23 || + !get_32_le (&at, end, &disco->flags) || +- !skip_n (&at, end, 16) || /* guid */ ++ !parse_guid (&at, end, &disco->domain_guid) || + !parse_disco_string (beg, end, &at, &disco->forest) || + !parse_disco_string (beg, end, &at, &disco->domain) || + !parse_disco_string (beg, end, &at, &disco->host_name) || +@@ -1077,6 +1066,7 @@ adcli_disco_free (adcli_disco *disco) + free (disco->host_addr); + free (disco->host_name); + free (disco->host_short); ++ free (disco->domain_guid); + free (disco->forest); + free (disco->domain); + free (disco->domain_short); +diff --git a/library/addisco.h b/library/addisco.h +index 718db7d..11a1464 100644 +--- a/library/addisco.h ++++ b/library/addisco.h +@@ -48,6 +48,7 @@ typedef struct _adcli_disco { + char *forest; + char *domain; + char *domain_short; ++ char *domain_guid; + char *host_name; + char *host_addr; + char *host_short; +-- +2.47.0 + diff --git a/0003-conn-Copy-domain-GUID-from-disco.patch b/0003-conn-Copy-domain-GUID-from-disco.patch new file mode 100644 index 0000000..674eff7 --- /dev/null +++ b/0003-conn-Copy-domain-GUID-from-disco.patch @@ -0,0 +1,73 @@ +From 396ba2b16136611334a87ac7d72ae29e53dc6808 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 13:43:47 +0200 +Subject: [PATCH 03/17] conn: Copy domain GUID from disco + +Signed-off-by: Samuel Cabrero +--- + library/adconn.c | 14 ++++++++++++++ + library/adconn.h | 2 ++ + 2 files changed, 16 insertions(+) + +diff --git a/library/adconn.c b/library/adconn.c +index 37405cc..f28ccba 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -74,6 +74,7 @@ struct _adcli_conn_ctx { + char *canonical_host; + char *domain_short; + char *domain_sid; ++ char *domain_guid; + adcli_disco *domain_disco; + enum conn_is_writeable is_writeable; + char *default_naming_context; +@@ -164,6 +165,11 @@ disco_dance_if_necessary (adcli_conn *conn) + conn->domain_short = strdup (conn->domain_disco->domain_short); + return_if_fail (conn->domain_short != NULL); + } ++ ++ if (!conn->domain_guid && conn->domain_disco->domain_guid) { ++ conn->domain_guid = strdup(conn->domain_disco->domain_guid); ++ return_if_fail (conn->domain_guid != NULL); ++ } + } + } + +@@ -1313,6 +1319,7 @@ conn_free (adcli_conn *conn) + free (conn->domain_realm); + free (conn->domain_controller); + free (conn->domain_short); ++ free (conn->domain_guid); + free (conn->default_naming_context); + free (conn->configuration_naming_context); + _adcli_strv_free (conn->supported_capabilities); +@@ -1421,6 +1428,13 @@ adcli_conn_get_domain_name (adcli_conn *conn) + return conn->domain_name; + } + ++const char * ++adcli_conn_get_domain_guid(adcli_conn *conn) ++{ ++ return_val_if_fail (conn != NULL, NULL); ++ return conn->domain_guid; ++} ++ + void + adcli_conn_set_domain_name (adcli_conn *conn, + const char *value) +diff --git a/library/adconn.h b/library/adconn.h +index 3a3c32b..34b4c23 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -104,6 +104,8 @@ const char * adcli_conn_get_domain_short (adcli_conn *conn); + + const char * adcli_conn_get_domain_sid (adcli_conn *conn); + ++const char * adcli_conn_get_domain_guid (adcli_conn *conn); ++ + LDAP * adcli_conn_get_ldap_connection (adcli_conn *conn); + + krb5_context adcli_conn_get_krb5_context (adcli_conn *conn); +-- +2.47.0 + diff --git a/0004-conn-Copy-forest-name-from-disco.patch b/0004-conn-Copy-forest-name-from-disco.patch new file mode 100644 index 0000000..2611219 --- /dev/null +++ b/0004-conn-Copy-forest-name-from-disco.patch @@ -0,0 +1,73 @@ +From 8c0d20d2f7d3eefa67f8d1c7d05fdc5680d7919c Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 13:45:06 +0200 +Subject: [PATCH 04/17] conn: Copy forest name from disco + +Signed-off-by: Samuel Cabrero +--- + library/adconn.c | 14 ++++++++++++++ + library/adconn.h | 2 ++ + 2 files changed, 16 insertions(+) + +diff --git a/library/adconn.c b/library/adconn.c +index f28ccba..c714169 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -75,6 +75,7 @@ struct _adcli_conn_ctx { + char *domain_short; + char *domain_sid; + char *domain_guid; ++ char *forest; + adcli_disco *domain_disco; + enum conn_is_writeable is_writeable; + char *default_naming_context; +@@ -166,6 +167,11 @@ disco_dance_if_necessary (adcli_conn *conn) + return_if_fail (conn->domain_short != NULL); + } + ++ if (!conn->forest && conn->domain_disco->forest) { ++ conn->forest = strdup(conn->domain_disco->forest); ++ return_if_fail (conn->forest != NULL); ++ } ++ + if (!conn->domain_guid && conn->domain_disco->domain_guid) { + conn->domain_guid = strdup(conn->domain_disco->domain_guid); + return_if_fail (conn->domain_guid != NULL); +@@ -1320,6 +1326,7 @@ conn_free (adcli_conn *conn) + free (conn->domain_controller); + free (conn->domain_short); + free (conn->domain_guid); ++ free (conn->forest); + free (conn->default_naming_context); + free (conn->configuration_naming_context); + _adcli_strv_free (conn->supported_capabilities); +@@ -1428,6 +1435,13 @@ adcli_conn_get_domain_name (adcli_conn *conn) + return conn->domain_name; + } + ++const char * ++adcli_conn_get_forest_name (adcli_conn *conn) ++{ ++ return_val_if_fail (conn != NULL, NULL); ++ return conn->forest; ++} ++ + const char * + adcli_conn_get_domain_guid(adcli_conn *conn) + { +diff --git a/library/adconn.h b/library/adconn.h +index 34b4c23..f377ea7 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -83,6 +83,8 @@ void adcli_conn_set_host_fqdn (adcli_conn *conn, + + const char * adcli_conn_get_domain_name (adcli_conn *conn); + ++const char * adcli_conn_get_forest_name (adcli_conn *conn); ++ + void adcli_conn_set_domain_name (adcli_conn *conn, + const char *value); + +-- +2.47.0 + diff --git a/0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch b/0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch new file mode 100644 index 0000000..1038314 --- /dev/null +++ b/0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch @@ -0,0 +1,27 @@ +From 04564d8295c42ad012f16570a16770f511b7fd16 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 17:56:24 +0200 +Subject: [PATCH 05/17] conn: Stop as soon as we have a valid LDAP connection + +No need to test all possible addresses. + +Signed-off-by: Samuel Cabrero +--- + library/adconn.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/library/adconn.c b/library/adconn.c +index c714169..77c09c4 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -868,6 +868,7 @@ connect_to_address (const char *host, + break; + } + } ++ break; + } + } + +-- +2.47.0 + diff --git a/0006-conn-Store-the-address-of-the-connected-server.patch b/0006-conn-Store-the-address-of-the-connected-server.patch new file mode 100644 index 0000000..1f46153 --- /dev/null +++ b/0006-conn-Store-the-address-of-the-connected-server.patch @@ -0,0 +1,91 @@ +From 347c843807678135fb4a2c287bc35606d35ff626 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 14:56:54 +0200 +Subject: [PATCH 06/17] conn: Store the address of the connected server + +Signed-off-by: Samuel Cabrero +--- + library/adconn.c | 19 +++++++++++++++++-- + 1 file changed, 17 insertions(+), 2 deletions(-) + +diff --git a/library/adconn.c b/library/adconn.c +index 77c09c4..34b6fe1 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -85,6 +85,7 @@ struct _adcli_conn_ctx { + + /* Connect state */ + LDAP *ldap; ++ struct sockaddr *addr; + int ldap_authenticated; + krb5_context k5; + krb5_ccache ccache; +@@ -792,7 +793,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, +- bool use_ldaps) ++ bool use_ldaps, ++ struct sockaddr **addr) + { + struct addrinfo *res = NULL; + struct addrinfo *ai; +@@ -875,6 +877,11 @@ connect_to_address (const char *host, + if (!ldap && error) + _adcli_err ("Couldn't connect to host: %s: %s", host, strerror (error)); + ++ *addr = malloc(sizeof(struct sockaddr)); ++ if (*addr != NULL) { ++ memcpy(*addr, ai->ai_addr, sizeof(struct sockaddr)); ++ } ++ + freeaddrinfo (res); + /* coverity[leaked_handle] - the socket is carried inside the ldap struct */ + return ldap; +@@ -888,6 +895,7 @@ connect_and_lookup_naming (adcli_conn *conn, + LDAPMessage *results; + adcli_result res; + LDAP *ldap; ++ struct sockaddr *addr; + int ret; + int ver; + +@@ -900,13 +908,15 @@ connect_and_lookup_naming (adcli_conn *conn, + }; + + assert (conn->ldap == NULL); ++ assert (conn->addr == NULL); + + canonical_host = disco->host_name; + if (!canonical_host) + canonical_host = disco->host_addr; + + ldap = connect_to_address (disco->host_addr, canonical_host, +- adcli_conn_get_use_ldaps (conn)); ++ adcli_conn_get_use_ldaps (conn), ++ &addr); + if (ldap == NULL) + return ADCLI_ERR_DIRECTORY; + +@@ -969,6 +979,7 @@ connect_and_lookup_naming (adcli_conn *conn, + } + + conn->ldap = ldap; ++ conn->addr = addr; + + free (conn->canonical_host); + conn->canonical_host = strdup (canonical_host); +@@ -1228,6 +1239,10 @@ conn_clear_state (adcli_conn *conn) + ldap_unbind_ext_s (conn->ldap, NULL, NULL); + conn->ldap = NULL; + ++ if (conn->addr) ++ free(conn->addr); ++ conn->addr = NULL; ++ + free (conn->canonical_host); + conn->canonical_host = NULL; + +-- +2.47.0 + diff --git a/0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch b/0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch new file mode 100644 index 0000000..8c910ad --- /dev/null +++ b/0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch @@ -0,0 +1,45 @@ +From 77794bc757af097682f0aa9cf85c2208c478b6f1 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 31 Aug 2023 17:11:55 +0200 +Subject: [PATCH 07/17] conn: Allow to retrieve the connected LDAP address + +Signed-off-by: Samuel Cabrero +--- + library/adconn.c | 7 +++++++ + library/adconn.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/library/adconn.c b/library/adconn.c +index 34b6fe1..087225d 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -1542,6 +1542,13 @@ adcli_conn_get_ldap_connection (adcli_conn *conn) + return conn->ldap; + } + ++struct sockaddr * ++adcli_conn_get_ldap_address (adcli_conn *conn) ++{ ++ return_val_if_fail (conn != NULL, NULL); ++ return conn->addr; ++} ++ + krb5_context + adcli_conn_get_krb5_context (adcli_conn *conn) + { +diff --git a/library/adconn.h b/library/adconn.h +index f377ea7..7c615df 100644 +--- a/library/adconn.h ++++ b/library/adconn.h +@@ -110,6 +110,8 @@ const char * adcli_conn_get_domain_guid (adcli_conn *conn); + + LDAP * adcli_conn_get_ldap_connection (adcli_conn *conn); + ++struct sockaddr * adcli_conn_get_ldap_address (adcli_conn *conn); ++ + krb5_context adcli_conn_get_krb5_context (adcli_conn *conn); + + void adcli_conn_set_krb5_context (adcli_conn *conn, +-- +2.47.0 + diff --git a/0008-util-Allow-to-append-variables-to-external-program-e.patch b/0008-util-Allow-to-append-variables-to-external-program-e.patch new file mode 100644 index 0000000..b623345 --- /dev/null +++ b/0008-util-Allow-to-append-variables-to-external-program-e.patch @@ -0,0 +1,186 @@ +From f4b3ede69824dd84456f252f0da2fe595874cb88 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Wed, 6 Sep 2023 11:49:19 +0200 +Subject: [PATCH 08/17] util: Allow to append variables to external program + environment + +Signed-off-by: Samuel Cabrero +--- + library/adenroll.c | 4 +-- + library/adprivate.h | 1 + + library/adutil.c | 69 +++++++++++++++++++++++++++++++++++++++------ + 3 files changed, 64 insertions(+), 10 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 5ae1215..72f1b6f 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2384,14 +2384,14 @@ update_samba_data (adcli_enroll *enroll) + _adcli_info ("Trying to set domain SID %s for Samba.", + argv_sid[2]); + ret = _adcli_call_external_program (argv_sid[0], argv_sid, +- NULL, NULL, NULL); ++ NULL, NULL, NULL, NULL); + if (ret != ADCLI_SUCCESS) { + _adcli_err ("Failed to set Samba domain SID."); + } + } + + _adcli_info ("Trying to set Samba secret."); +- ret = _adcli_call_external_program (argv_pw[0], argv_pw, ++ ret = _adcli_call_external_program (argv_pw[0], argv_pw, NULL, + enroll->computer_password, NULL, NULL); + if (ret != ADCLI_SUCCESS) { + _adcli_err ("Failed to set Samba computer account password."); +diff --git a/library/adprivate.h b/library/adprivate.h +index 822f919..bf0381c 100644 +--- a/library/adprivate.h ++++ b/library/adprivate.h +@@ -318,6 +318,7 @@ bool _adcli_check_nt_time_string_lifetime (const char *nt_time_strin + + adcli_result _adcli_call_external_program (const char *binary, + char * const *argv, ++ char * const *envp, + const char *stdin_data, + uint8_t **stdout_data, + size_t *stdout_data_len); +diff --git a/library/adutil.c b/library/adutil.c +index 4bb06a3..6a8e612 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -551,7 +551,7 @@ _adcli_check_nt_time_string_lifetime (const char *nt_time_string, + + adcli_result + _adcli_call_external_program (const char *binary, char * const *argv, +- const char *stdin_data, ++ char * const *envp, const char *stdin_data, + uint8_t **stdout_data, size_t *stdout_data_len) + { + int ret; +@@ -565,6 +565,48 @@ _adcli_call_external_program (const char *binary, char * const *argv, + int status; + uint8_t read_buf[4096]; + uint8_t *out; ++ char **child_env = NULL; ++ size_t child_env_size = 0; ++ ++ /* prepare child environment, append envp to environ */ ++ if (envp != NULL) { ++ size_t environ_size = 0; ++ size_t envp_size = 0; ++ int i, j; ++ ++ for (i = 0; environ[i] != NULL; i++) { ++ environ_size++; ++ } ++ ++ for (i = 0; envp[i] != NULL; i++) { ++ envp_size++; ++ } ++ ++ child_env_size = environ_size + envp_size + 1; ++ child_env = calloc(child_env_size, sizeof(char *)); ++ if (child_env == NULL) { ++ _adcli_err("Failed to allocate memory."); ++ return ADCLI_ERR_FAIL; ++ } ++ ++ memset(child_env, 0, child_env_size); ++ ++ for (i = 0, j = 0; environ[i] != NULL; i++, j++) { ++ child_env[j] = strdup(environ[i]); ++ if (child_env[j] == NULL) { ++ _adcli_err("Failed to allocate memory."); ++ return ADCLI_ERR_FAIL; ++ } ++ } ++ ++ for (i = 0; envp[i] != NULL; i++, j++) { ++ child_env[j] = strdup(envp[i]); ++ if (child_env[j] == NULL) { ++ _adcli_err("Failed to allocate memory."); ++ return ADCLI_ERR_FAIL; ++ } ++ } ++ } + + errno = 0; + ret = access (binary, X_OK); +@@ -613,7 +655,11 @@ _adcli_call_external_program (const char *binary, char * const *argv, + exit (EXIT_FAILURE); + } + +- execv (binary, argv); ++ if (child_env != NULL) { ++ execve(binary, argv, child_env); ++ } else { ++ execv(binary, argv); ++ } + _adcli_err ("Failed to run %s.", binary); + ret = ADCLI_ERR_FAIL; + goto done; +@@ -672,6 +718,13 @@ _adcli_call_external_program (const char *binary, char * const *argv, + goto done; + } + ++ if (child_env != NULL) { ++ for (int i = 0; i < child_env_size; i++) { ++ free(child_env[i]); ++ } ++ free(child_env); ++ } ++ + ret = ADCLI_SUCCESS; + + done: +@@ -853,25 +906,25 @@ test_call_external_program (void) + size_t stdout_data_len; + + argv[0] = "/does/not/exists"; +- res = _adcli_call_external_program (argv[0], argv, NULL, NULL, NULL); ++ res = _adcli_call_external_program (argv[0], argv, NULL, NULL, NULL, NULL); + assert (res == ADCLI_ERR_FAIL); + + #ifdef BIN_CAT + argv[0] = BIN_CAT; +- res = _adcli_call_external_program (argv[0], argv, "Hello", ++ res = _adcli_call_external_program (argv[0], argv, NULL, "Hello", + &stdout_data, &stdout_data_len); + assert (res == ADCLI_SUCCESS); + assert (strncmp ("Hello", (char *) stdout_data, stdout_data_len) == 0); + free (stdout_data); + +- res = _adcli_call_external_program (argv[0], argv, "Hello", ++ res = _adcli_call_external_program (argv[0], argv, NULL, "Hello", + NULL, NULL); + assert (res == ADCLI_SUCCESS); + #endif + + #ifdef BIN_REV + argv[0] = BIN_REV; +- res = _adcli_call_external_program (argv[0], argv, "Hello\n", ++ res = _adcli_call_external_program (argv[0], argv, NULL, "Hello\n", + &stdout_data, &stdout_data_len); + assert (res == ADCLI_SUCCESS); + assert (strncmp ("olleH\n", (char *) stdout_data, stdout_data_len) == 0); +@@ -880,7 +933,7 @@ test_call_external_program (void) + + #ifdef BIN_TAC + argv[0] = BIN_TAC; +- res = _adcli_call_external_program (argv[0], argv, "Hello\nWorld\n", ++ res = _adcli_call_external_program (argv[0], argv, NULL, "Hello\nWorld\n", + &stdout_data, &stdout_data_len); + assert (res == ADCLI_SUCCESS); + assert (strncmp ("World\nHello\n", (char *) stdout_data, stdout_data_len) == 0); +@@ -890,7 +943,7 @@ test_call_external_program (void) + #ifdef BIN_ECHO + argv[0] = BIN_ECHO; + argv[1] = "Hello"; +- res = _adcli_call_external_program (argv[0], argv, NULL, ++ res = _adcli_call_external_program (argv[0], argv, NULL, NULL, + &stdout_data, &stdout_data_len); + assert (res == ADCLI_SUCCESS); + assert (strncmp ("Hello\n", (char *) stdout_data, stdout_data_len) == 0); +-- +2.47.0 + diff --git a/0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch b/0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch new file mode 100644 index 0000000..1eef731 --- /dev/null +++ b/0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch @@ -0,0 +1,27 @@ +From 302d5ff3dd9d7d619da7cbf1a108d2168de1a630 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Wed, 6 Sep 2023 12:05:03 +0200 +Subject: [PATCH 09/17] util: Flag write end of pipe as invalid after closing + it + +Signed-off-by: Samuel Cabrero +--- + library/adutil.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/library/adutil.c b/library/adutil.c +index 6a8e612..2947391 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -679,7 +679,7 @@ _adcli_call_external_program (const char *binary, char * const *argv, + close (pipefd_to_child[0]); + pipefd_to_child[0] = -1; + close (pipefd_to_child[1]); +- pipefd_to_child[0] = -1; ++ pipefd_to_child[1] = -1; + + if (stdout_data != NULL || stdout_data_len != NULL) { + rlen = read (pipefd_from_child[0], read_buf, sizeof (read_buf)); +-- +2.47.0 + diff --git a/0010-util-Return-failure-if-child-exit-status-reports-so.patch b/0010-util-Return-failure-if-child-exit-status-reports-so.patch new file mode 100644 index 0000000..797f0f9 --- /dev/null +++ b/0010-util-Return-failure-if-child-exit-status-reports-so.patch @@ -0,0 +1,27 @@ +From 1d98352999e797f8f091064d0d3bd0627bccecb8 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Wed, 6 Sep 2023 16:30:45 +0200 +Subject: [PATCH 10/17] util: Return failure if child exit status reports so + +Otherwise error string from stdout won't be printed. + +Signed-off-by: Samuel Cabrero +--- + library/adutil.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/library/adutil.c b/library/adutil.c +index 2947391..ea49607 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -749,6 +749,7 @@ done: + if (WIFEXITED (status) && WEXITSTATUS (status) != 0) { + _adcli_err ("net command failed with %d.", + WEXITSTATUS (status)); ++ ret = ADCLI_ERR_FAIL; + } + } + } +-- +2.47.0 + diff --git a/0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch b/0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch new file mode 100644 index 0000000..4fdc233 --- /dev/null +++ b/0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch @@ -0,0 +1,30 @@ +From 5a8b64a1647808d6649f82b2ea20331fcc7367f9 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Wed, 6 Sep 2023 16:29:32 +0200 +Subject: [PATCH 11/17] enroll: Issue a warning if Samba provision was + requested but failed + +Signed-off-by: Samuel Cabrero +--- + library/adenroll.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 72f1b6f..c5a85a5 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2618,9 +2618,9 @@ enroll_join_or_update_tasks (adcli_enroll *enroll, + if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) { + res = update_samba_data (enroll); + if (res != ADCLI_SUCCESS) { +- _adcli_info ("Failed to add Samba specific data, smbd " ++ _adcli_warn ("Failed to add Samba specific data, smbd " + "or winbindd might not work as " +- "expected.\n"); ++ "expected."); + } + } + +-- +2.47.0 + diff --git a/0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch b/0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch new file mode 100644 index 0000000..5d172ca --- /dev/null +++ b/0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch @@ -0,0 +1,87 @@ +From 14a55c1f1f0195e9ada03457e252fafda37ba3f9 Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Wed, 6 Sep 2023 12:55:50 +0200 +Subject: [PATCH 12/17] enroll: Add a function to convert an IP address to text + +Signed-off-by: Samuel Cabrero +--- + library/adutil.c | 34 ++++++++++++++++++++++++++++++++++ + library/adutil.h | 5 +++++ + 2 files changed, 39 insertions(+) + +diff --git a/library/adutil.c b/library/adutil.c +index ea49607..36822e2 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + static adcli_message_func message_func = NULL; + static char last_error[2048] = { 0, }; +@@ -757,6 +758,39 @@ done: + return ret; + } + ++adcli_result ++adcli_sockaddr_to_string(struct sockaddr *sa, char *addr, size_t addr_len) ++{ ++ const char *p; ++ ++ if (sa == NULL) { ++ return ADCLI_ERR_FAIL; ++ } ++ ++ errno = 0; ++ switch (sa->sa_family) { ++ case AF_INET: ++ p = inet_ntop(AF_INET, ++ &(((struct sockaddr_in *)sa)->sin_addr), ++ addr, addr_len); ++ break; ++ case AF_INET6: ++ p = inet_ntop(AF_INET6, ++ &(((struct sockaddr_in6 *)sa)->sin6_addr), ++ addr, addr_len); ++ break; ++ default: ++ _adcli_err("Failed to get LDAP server address, unknown socket family"); ++ return ADCLI_ERR_FAIL; ++ } ++ ++ if (p == NULL) { ++ _adcli_err("Failed to convert LDAP server address: %s", strerror(errno)); ++ return ADCLI_ERR_FAIL; ++ } ++ ++ return ADCLI_SUCCESS; ++} + + #ifdef UTIL_TESTS + +diff --git a/library/adutil.h b/library/adutil.h +index a07c5da..27c0587 100644 +--- a/library/adutil.h ++++ b/library/adutil.h +@@ -26,6 +26,7 @@ + + #include + #include ++#include + + typedef enum { + /* Successful completion */ +@@ -91,4 +92,8 @@ void adcli_clear_last_error (void); + + const char * adcli_get_last_error (void); + ++adcli_result adcli_sockaddr_to_string (struct sockaddr *sa, ++ char *addr, ++ size_t addr_len); ++ + #endif /* ADUTIL_H_ */ +-- +2.47.0 + diff --git a/0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch b/0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch new file mode 100644 index 0000000..38f2c7d --- /dev/null +++ b/0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch @@ -0,0 +1,31 @@ +From 1231fbdd894570afc0081ca6c36675b6e2581c7f Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 7 Sep 2023 10:13:38 +0200 +Subject: [PATCH 13/17] build: Check for NetComposeOfflineDomainJoin in samba's + netapi library + +Signed-off-by: Samuel Cabrero +--- + configure.ac | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/configure.ac b/configure.ac +index af62507..1912019 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -95,6 +95,12 @@ AC_CHECK_LIB(ldap, ldap_init_fd, [true], [ + AC_SUBST(LDAP_LIBS) + AC_SUBST(LDAP_CFLAGS) + ++# ------------------------------------------------------------------- ++# samba ++ ++AC_CHECK_LIB([netapi], [NetComposeOfflineDomainJoin], ++ [AC_DEFINE(SAMBA_NETAPI_HAS_COMPOSEODJ, 1, [Samba NetApi supports composeodj])]) ++ + # ------------------------------------------------------------------- + # resolv + +-- +2.47.0 + diff --git a/0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch b/0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch new file mode 100644 index 0000000..6a85aaa --- /dev/null +++ b/0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch @@ -0,0 +1,178 @@ +From 573216f40efd8aa1bcbaf606cd89d3906e648acb Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 7 Sep 2023 10:19:29 +0200 +Subject: [PATCH 14/17] enroll: Populate Samba's secrets database using offline + domain join + +Signed-off-by: Samuel Cabrero +--- + library/adenroll.c | 146 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 146 insertions(+) + +diff --git a/library/adenroll.c b/library/adenroll.c +index c5a85a5..b6558ed 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2363,6 +2363,150 @@ update_keytab_for_principals (adcli_enroll *enroll, + return ADCLI_SUCCESS; + } + ++#if defined(SAMBA_NETAPI_HAS_COMPOSEODJ) ++ ++#define CHECK_SNPRINTF(x, v) \ ++ do { if ((x) < 0 || (x) >= sizeof((v))) { \ ++ _adcli_err ("%s: Insufficient buffer for %s", __func__, #v); \ ++ return ADCLI_ERR_FAIL; \ ++ } } while (0) ++ ++static adcli_result ++update_samba_data (adcli_enroll *enroll) ++{ ++ int ret; ++ char dns_domain_name[128]; ++ char netbios_domain_name[128]; ++ char domain_sid[128]; ++ char domain_guid[128]; ++ char forest_name[128]; ++ char machine_account_name[128]; ++ char dc_name[128]; ++ char dc_address[128]; ++ char ldap_address[INET6_ADDRSTRLEN]; ++ char *envp_composeodj[] = {"PASSWD_FD=0", NULL}; ++ char *argv_composeodj[] = { ++ NULL, ++ "offlinejoin", ++ "composeodj", ++ dns_domain_name, ++ netbios_domain_name, ++ domain_sid, ++ domain_guid, ++ forest_name, ++ machine_account_name, ++ dc_name, ++ dc_address, ++ "printblob", ++ NULL}; ++ char *argv_requestodj[] = { ++ NULL, ++ "offlinejoin", ++ "requestodj", ++ "-i", ++ NULL}; ++ uint8_t *compose_out_data = NULL; ++ size_t compose_out_data_len = 0; ++ uint8_t *request_out_data = NULL; ++ size_t request_out_data_len = 0; ++ ++ argv_composeodj[0] = (char *)adcli_enroll_get_samba_data_tool(enroll); ++ if (argv_composeodj[0] == NULL) { ++ _adcli_err("Samba data tool not available."); ++ return ADCLI_ERR_FAIL; ++ } ++ argv_requestodj[0] = argv_composeodj[0]; ++ ++ ret = adcli_sockaddr_to_string(adcli_conn_get_ldap_address(enroll->conn), ++ ldap_address, sizeof(ldap_address)); ++ if (ret != ADCLI_SUCCESS) { ++ return ret; ++ } ++ ++ ret = snprintf(dns_domain_name, sizeof(dns_domain_name), "--realm=%s", ++ adcli_conn_get_domain_name(enroll->conn)); ++ CHECK_SNPRINTF(ret, dns_domain_name); ++ ++ ret = snprintf(netbios_domain_name, sizeof(netbios_domain_name), ++ "--workgroup=%s", adcli_conn_get_domain_short(enroll->conn)); ++ CHECK_SNPRINTF(ret, netbios_domain_name); ++ ++ ret = snprintf(domain_sid, sizeof(domain_sid), "domain_sid=%s", ++ adcli_conn_get_domain_sid(enroll->conn)); ++ CHECK_SNPRINTF(ret, domain_sid); ++ ++ ret = snprintf(domain_guid, sizeof(domain_guid), "domain_guid=%s", ++ adcli_conn_get_domain_guid(enroll->conn)); ++ CHECK_SNPRINTF(ret, domain_guid); ++ ++ ret = snprintf(forest_name, sizeof(forest_name), "forest_name=%s", ++ adcli_conn_get_forest_name(enroll->conn)); ++ CHECK_SNPRINTF(ret, forest_name); ++ ++ ret = snprintf(machine_account_name, sizeof(machine_account_name), ++ "--user=%s", enroll->computer_sam); ++ CHECK_SNPRINTF(ret, machine_account_name); ++ ++ ret = snprintf(dc_name, sizeof(dc_name), "--server=%s", ++ adcli_conn_get_domain_controller(enroll->conn)); ++ CHECK_SNPRINTF(ret, dc_name); ++ ++ ret = snprintf(dc_address, sizeof(dc_address), "--ipaddress=%s", ++ ldap_address); ++ CHECK_SNPRINTF(ret, dc_address); ++ ++ _adcli_info("Trying to compose Samba ODJ blob."); ++ ret = _adcli_call_external_program(argv_composeodj[0], ++ argv_composeodj, envp_composeodj, ++ enroll->computer_password, ++ &compose_out_data, &compose_out_data_len); ++ if (ret != ADCLI_SUCCESS) { ++ while (compose_out_data && compose_out_data_len > 0 && ++ compose_out_data[compose_out_data_len - 1] == '\n') { ++ compose_out_data_len--; ++ } ++ _adcli_err("Failed to compose Samba ODJ blob: %.*s", ++ (int)compose_out_data_len, (char *)compose_out_data); ++ goto out; ++ } ++ ++ if (compose_out_data == NULL || compose_out_data_len == 0) { ++ _adcli_err("Failed to compose ODJ blob, no data returned."); ++ ret = ADCLI_ERR_FAIL; ++ goto out; ++ } ++ ++ _adcli_info("Trying to request Samba ODJ."); ++ ret = _adcli_call_external_program(argv_requestodj[0], ++ argv_requestodj, NULL, ++ (const char *)compose_out_data, ++ &request_out_data, &request_out_data_len); ++ if (ret != ADCLI_SUCCESS) { ++ while (request_out_data && request_out_data_len > 0 && ++ request_out_data[request_out_data_len - 1] == '\n') { ++ request_out_data_len--; ++ } ++ _adcli_err("Failed to request Samba ODJ: %.*s", ++ (int)request_out_data_len, request_out_data); ++ goto out; ++ } ++ ++ ret = ADCLI_SUCCESS; ++out: ++ if (compose_out_data != NULL) { ++ /* Burn memory, the blob contains the machine password */ ++ memset(compose_out_data, 0, compose_out_data_len); ++ free(compose_out_data); ++ } ++ if (request_out_data != NULL) { ++ free(request_out_data); ++ } ++ ++ return ret; ++} ++ ++#else /* defined(SAMBA_NETAPI_HAS_COMPOSEODJ) */ ++ + static adcli_result + update_samba_data (adcli_enroll *enroll) + { +@@ -2400,6 +2544,8 @@ update_samba_data (adcli_enroll *enroll) + return ret; + } + ++#endif ++ + static void + enroll_clear_state (adcli_enroll *enroll) + { +-- +2.47.0 + diff --git a/0015-doc-improve-some-Samba-related-doc-items.patch b/0015-doc-improve-some-Samba-related-doc-items.patch new file mode 100644 index 0000000..3bdb610 --- /dev/null +++ b/0015-doc-improve-some-Samba-related-doc-items.patch @@ -0,0 +1,73 @@ +From 954a0bd085ae9e62fc33405d190484f88cc18a93 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 5 Nov 2024 11:42:20 +0100 +Subject: [PATCH 15/17] doc: improve some Samba related doc items + +--- + doc/adcli-devel.xml | 9 +++++++-- + doc/adcli.xml | 10 ++++++---- + 2 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/doc/adcli-devel.xml b/doc/adcli-devel.xml +index 0f1f4ad..ef51ba0 100644 +--- a/doc/adcli-devel.xml ++++ b/doc/adcli-devel.xml +@@ -43,12 +43,17 @@ + MIT Kerberos libraries + + ++ If Samba's offline join feature should be used the ++ libnetapi development package should be install as well ++ so that configure can detect if the used Samba version ++ already supports offline joins. ++ + On Debian or Ubuntu you can use the following command to + install the dependencies: + + + $ sudo apt-get install build-essential autoconf automake xmlto xsltproc \ +- libkrb5-dev libldap2-dev libsasl2-dev ++ libkrb5-dev libldap2-dev libsasl2-dev samba-dev + + + On Fedora you can use the following command to install the +@@ -57,7 +62,7 @@ $ sudo apt-get install build-essential autoconf automake xmlto xsltproc \ + + $ sudo yum groupinstall "Development Tools" + $ sudo yum install automake autoconf xmlto xsltproc krb5-devel openldap-devel \ +- cyrus-sasl-devel ++ cyrus-sasl-devel libnetapi-devel + + + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 93e1520..7f65f06 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -413,8 +413,9 @@ Password for Administrator: + Please note that Samba's net + requires some settings in smb.conf + to create the database entries correctly. Most +- important here is currently the +- option, see ++ important here are currently the ++ , and ++ options, see + smb.conf5 + for details. + +@@ -615,8 +616,9 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + Please note that Samba's net + requires some settings in smb.conf + to create the database entries correctly. Most +- important here is currently the +- option, see ++ important here are currently the ++ , and ++ options, see + smb.conf5 + for details. + Note that if the machine account password is not +-- +2.47.0 + diff --git a/0016-Various-fixes-for-issues-found-by-static-code-scanne.patch b/0016-Various-fixes-for-issues-found-by-static-code-scanne.patch new file mode 100644 index 0000000..dd60edc --- /dev/null +++ b/0016-Various-fixes-for-issues-found-by-static-code-scanne.patch @@ -0,0 +1,198 @@ +From fab13daeaf23cc4a26b10cfe0c3d7ac469a9da76 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 5 Nov 2024 14:22:47 +0100 +Subject: [PATCH 16/17] Various fixes for issues found by static code scanners + +--- + library/adconn.c | 17 ++++++++++++----- + library/adenroll.c | 4 ++-- + library/adutil.c | 2 +- + library/seq.c | 13 +++++++++---- + library/seq.h | 3 ++- + tools/tools.c | 24 +++++++++++++++++------- + 6 files changed, 43 insertions(+), 20 deletions(-) + +diff --git a/library/adconn.c b/library/adconn.c +index 087225d..e668b8d 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -402,9 +402,9 @@ clear_krb5_conf_snippet (adcli_conn *conn) + static adcli_result + setup_krb5_conf_snippet (adcli_conn *conn) + { +- char *filename; +- char *snippet; +- char *controller; ++ char *filename = NULL; ++ char *snippet = NULL; ++ char *controller = NULL; + int errn; + int ret; + int fd; +@@ -429,7 +429,10 @@ setup_krb5_conf_snippet (adcli_conn *conn) + controller = strdup (conn->domain_controller); + } + +- return_unexpected_if_fail (controller != NULL); ++ if (controller == NULL) { ++ free (filename); ++ return_unexpected_if_reached (); ++ } + + if (asprintf (&snippet, "[realms]\n" + " %s = {\n" +@@ -442,8 +445,11 @@ setup_krb5_conf_snippet (adcli_conn *conn) + " %s = %s\n", + conn->domain_realm, controller, controller, controller, + conn->canonical_host, conn->domain_realm, +- conn->domain_controller, conn->domain_realm) < 0) ++ conn->domain_controller, conn->domain_realm) < 0) { ++ free (controller); ++ free (filename); + return_unexpected_if_reached (); ++ } + + old_mask = umask (0177); + fd = mkstemp (filename); +@@ -451,6 +457,7 @@ setup_krb5_conf_snippet (adcli_conn *conn) + if (fd < 0) { + _adcli_warn ("Couldn't create krb5.conf snippet file in: %s: %s", + conn->krb5_conf_dir, strerror (errno)); ++ free (filename); + + } else { + conn->krb5_conf_snippet = filename; +diff --git a/library/adenroll.c b/library/adenroll.c +index b6558ed..e978f46 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -2340,9 +2340,9 @@ update_keytab_for_principals (adcli_enroll *enroll, + + for (i = 0; enroll->keytab_principals[i] != 0; i++) { + if (krb5_unparse_name (k5, enroll->keytab_principals[i], &name) != 0) +- name = ""; ++ name = NULL; + res = add_principal_to_keytab (enroll, k5, enroll->keytab_principals[i], +- name, &which_salt, flags); ++ name != NULL ? name : "", &which_salt, flags); + krb5_free_unparsed_name (k5, name); + + if (res != ADCLI_SUCCESS) +diff --git a/library/adutil.c b/library/adutil.c +index 36822e2..a112ad8 100644 +--- a/library/adutil.c ++++ b/library/adutil.c +@@ -169,7 +169,7 @@ _adcli_strv_dup (char **strv) + return NULL; + + count = seq_count (strv); +- return seq_dup (strv, &count, (seq_copy)strdup); ++ return seq_dup (strv, &count, (seq_copy)strdup, (seq_destroy)free); + } + + char * +diff --git a/library/seq.c b/library/seq.c +index 8e7475d..5410918 100644 +--- a/library/seq.c ++++ b/library/seq.c +@@ -299,7 +299,8 @@ seq_lookup (seq_voidp sequence, + void * + seq_dup (seq_voidp sequence, + int *length, +- seq_copy copy) ++ seq_copy copy, ++ seq_destroy destroy) + { + void **seq = sequence; + void **copied; +@@ -308,6 +309,7 @@ seq_dup (seq_voidp sequence, + int at; + + assert (length != NULL); ++ assert ( (copy != NULL && destroy != NULL) || (copy == NULL && destroy == NULL) ); + + len = *length; + alloc = alloc_size (len + 1); +@@ -321,7 +323,10 @@ seq_dup (seq_voidp sequence, + copied[at] = seq[at]; + } else { + copied[at] = copy (seq[at]); +- bail_on_null (copied[at]); ++ if (copied[at] == NULL) { ++ destroy (copied); ++ return NULL; ++ } + } + } + +@@ -707,7 +712,7 @@ test_dup (void) + seq = seq_insert (seq, &len, "3", (seq_compar)strcmp, NULL); + seq = seq_insert (seq, &len, "1", (seq_compar)strcmp, NULL); + +- dup = seq_dup (seq, &len, NULL); ++ dup = seq_dup (seq, &len, NULL, NULL); + assert (dup != NULL); + + assert_str_eq (dup[0], "1"); +@@ -734,7 +739,7 @@ test_dup_deep (void) + seq = seq_insert (seq, &len, "3", (seq_compar)strcmp, NULL); + seq = seq_insert (seq, &len, "1", (seq_compar)strcmp, NULL); + +- dup = seq_dup (seq, &len, (seq_copy)strdup); ++ dup = seq_dup (seq, &len, (seq_copy)strdup, (seq_destroy)free); + assert (dup != NULL); + + assert_str_eq (dup[0], "1"); +diff --git a/library/seq.h b/library/seq.h +index 5d48848..3fec747 100644 +--- a/library/seq.h ++++ b/library/seq.h +@@ -89,7 +89,8 @@ int seq_count (seq_voidp seq); + + seq_voidp seq_dup (seq_voidp seq, + int *length, +- seq_copy copy); ++ seq_copy copy, ++ seq_destroy destroy); + + void seq_free (seq_voidp seq, + seq_destroy destroy); +diff --git a/tools/tools.c b/tools/tools.c +index 7e382ae..444485c 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -399,14 +399,24 @@ setup_krb5_conf_directory (adcli_conn *conn) + warnx ("couldn't create temporary directory in: %s: %s", + parent, strerror (errn)); + } else { +- if (asprintf (&filename, "%s/krb5.conf", directory) < 0 || +- asprintf (&snippets, "%s/krb5.d", directory) < 0 || +- asprintf (&contents, "includedir %s\n%s%s\n", snippets, +- krb5_conf ? "include " : "", +- krb5_conf ? krb5_conf : "") < 0) { ++ if (asprintf (&filename, "%s/krb5.conf", directory) < 0) { ++ warnx ("unexpected: out of memory"); ++ failed = 1; ++ } ++ if (!failed && asprintf (&snippets, "%s/krb5.d", directory) < 0) { ++ free (filename); ++ filename = NULL; ++ warnx ("unexpected: out of memory"); ++ failed = 1; ++ } ++ if (!failed && asprintf (&contents, "includedir %s\n%s%s\n", snippets, ++ krb5_conf ? "include " : "", ++ krb5_conf ? krb5_conf : "") < 0) { ++ free (snippets); ++ snippets = NULL; ++ free (filename); ++ filename = NULL; + warnx ("unexpected: out of memory"); +- filename = NULL; /* content is undefined */ +- snippets = NULL; /* content is undefined */ + contents = NULL; /* content is undefined */ + failed = 1; + } +-- +2.47.0 + diff --git a/0017-krb5-add-adcli_krb5_get_error_message.patch b/0017-krb5-add-adcli_krb5_get_error_message.patch new file mode 100644 index 0000000..0c5ba40 --- /dev/null +++ b/0017-krb5-add-adcli_krb5_get_error_message.patch @@ -0,0 +1,226 @@ +From d3db46e8b03f0f2db0df01466b597fde588a06bf Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 5 Nov 2024 19:00:54 +0100 +Subject: [PATCH 17/17] krb5: add adcli_krb5_get_error_message() + +The krb5_get_error_message() call returns an error message in an +allocated string which must be freed. This makes it hard to simply use +krb5_get_error_message() in a printf() argument list. +adcli_krb5_get_error_message() used a static memory area to make the +usage more easy. +--- + library/adconn.c | 10 +++++----- + library/adenroll.c | 18 +++++++++--------- + library/adentry.c | 2 +- + library/adkrb5.c | 22 +++++++++++++++++++--- + library/adprivate.h | 2 ++ + 5 files changed, 36 insertions(+), 18 deletions(-) + +diff --git a/library/adconn.c b/library/adconn.c +index e668b8d..2c94af9 100644 +--- a/library/adconn.c ++++ b/library/adconn.c +@@ -367,20 +367,20 @@ handle_kinit_krb5_code (adcli_conn *conn, + code == KRB5_PREAUTH_FAILED) { + if (type == ADCLI_LOGIN_COMPUTER_ACCOUNT) { + _adcli_err ("Couldn't authenticate as machine account: %s: %s", +- name, krb5_get_error_message (conn->k5, code)); ++ name, adcli_krb5_get_error_message (conn->k5, code)); + } else { + _adcli_err ("Couldn't authenticate as: %s: %s", +- name, krb5_get_error_message (conn->k5, code)); ++ name, adcli_krb5_get_error_message (conn->k5, code)); + } + return ADCLI_ERR_CREDENTIALS; + + } else { + if (type == ADCLI_LOGIN_COMPUTER_ACCOUNT) { + _adcli_err ("Couldn't get kerberos ticket for machine account: %s: %s", +- name, krb5_get_error_message (conn->k5, code)); ++ name, adcli_krb5_get_error_message (conn->k5, code)); + } else { + _adcli_err ("Couldn't get kerberos ticket for: %s: %s", +- name, krb5_get_error_message (conn->k5, code)); ++ name, adcli_krb5_get_error_message (conn->k5, code)); + } + return ADCLI_ERR_DIRECTORY; + } +@@ -726,7 +726,7 @@ prep_kerberos_and_kinit (adcli_conn *conn) + + if (code != 0) { + _adcli_err ("Couldn't open kerberos credential cache: %s: %s", +- conn->login_ccache_name, krb5_get_error_message (NULL, code)); ++ conn->login_ccache_name, adcli_krb5_get_error_message (NULL, code)); + return ADCLI_ERR_CONFIG; + } + } +diff --git a/library/adenroll.c b/library/adenroll.c +index e978f46..c854c9e 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -549,7 +549,7 @@ ensure_keytab_principals (adcli_result res, + if (code != 0) { + _adcli_err ("Couldn't parse kerberos user principal: %s: %s", + enroll->user_principal, +- krb5_get_error_message (k5, code)); ++ adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_CONFIG; + } + } +@@ -1523,7 +1523,7 @@ set_password_with_user_creds (adcli_enroll *enroll) + if (code != 0) { + _adcli_err ("Couldn't set password for %s account: %s: %s", + s_or_c (enroll), +- enroll->computer_sam, krb5_get_error_message (k5, code)); ++ enroll->computer_sam, adcli_krb5_get_error_message (k5, code)); + /* TODO: Parse out these values */ + res = ADCLI_ERR_DIRECTORY; + +@@ -1584,7 +1584,7 @@ set_password_with_computer_creds (adcli_enroll *enroll) + if (code != 0) { + _adcli_err ("Couldn't get change password ticket for %s account: %s: %s", + s_or_c (enroll), +- enroll->computer_sam, krb5_get_error_message (k5, code)); ++ enroll->computer_sam, adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_DIRECTORY; + } + +@@ -1596,7 +1596,7 @@ set_password_with_computer_creds (adcli_enroll *enroll) + if (code != 0) { + _adcli_err ("Couldn't change password for %s account: %s: %s", + s_or_c (enroll), +- enroll->computer_sam, krb5_get_error_message (k5, code)); ++ enroll->computer_sam, adcli_krb5_get_error_message (k5, code)); + /* TODO: Parse out these values */ + res = ADCLI_ERR_DIRECTORY; + +@@ -2113,7 +2113,7 @@ load_host_keytab (adcli_enroll *enroll) + code = _adcli_krb5_keytab_enumerate (k5, keytab, load_keytab_entry, enroll); + if (code != 0) { + _adcli_err ("Couldn't enumerate keytab: %s: %s", +- enroll->keytab_name, krb5_get_error_message (k5, code)); ++ enroll->keytab_name, adcli_krb5_get_error_message (k5, code)); + res = ADCLI_ERR_FAIL; + } + krb5_kt_close (k5, keytab); +@@ -2225,7 +2225,7 @@ remove_principal_from_keytab (adcli_enroll *enroll, + + if (code != 0) { + _adcli_err ("Couldn't update keytab: %s: %s", +- enroll->keytab_name, krb5_get_error_message (k5, code)); ++ enroll->keytab_name, adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_FAIL; + } + +@@ -2257,7 +2257,7 @@ add_principal_to_keytab (adcli_enroll *enroll, + + if (code != 0) { + _adcli_err ("Couldn't update keytab: %s: %s", +- enroll->keytab_name, krb5_get_error_message (k5, code)); ++ enroll->keytab_name, adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_FAIL; + } + +@@ -2296,7 +2296,7 @@ add_principal_to_keytab (adcli_enroll *enroll, + enctypes, salts, which_salt); + if (code != 0) { + _adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s", +- principal_name, krb5_get_error_message (k5, code)); ++ principal_name, adcli_krb5_get_error_message (k5, code)); + *which_salt = DEFAULT_SALT; + } else { + assert (*which_salt >= 0); +@@ -2313,7 +2313,7 @@ add_principal_to_keytab (adcli_enroll *enroll, + + if (code != 0) { + _adcli_err ("Couldn't add keytab entries: %s: %s", +- enroll->keytab_name, krb5_get_error_message (k5, code)); ++ enroll->keytab_name, adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_FAIL; + } + +diff --git a/library/adentry.c b/library/adentry.c +index 0d9b9af..38ec7ca 100644 +--- a/library/adentry.c ++++ b/library/adentry.c +@@ -515,7 +515,7 @@ adcli_entry_set_passwd (adcli_entry *entry, const char *user_pwd) + if (code != 0) { + _adcli_err ("Couldn't set password for %s account: %s: %s", + entry->object_class, +- entry->sam_name, krb5_get_error_message (k5, code)); ++ entry->sam_name, adcli_krb5_get_error_message (k5, code)); + /* TODO: Parse out these values */ + res = ADCLI_ERR_DIRECTORY; + +diff --git a/library/adkrb5.c b/library/adkrb5.c +index be3ede5..7a9ee8f 100644 +--- a/library/adkrb5.c ++++ b/library/adkrb5.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + krb5_error_code + _adcli_krb5_build_principal (krb5_context k5, +@@ -174,7 +175,7 @@ _adcli_krb5_init_context (krb5_context *k5) + + } else if (code != 0) { + _adcli_err ("Failed to create kerberos context: %s", +- krb5_get_error_message (NULL, code)); ++ adcli_krb5_get_error_message (NULL, code)); + return ADCLI_ERR_UNEXPECTED; + } + +@@ -192,7 +193,7 @@ _adcli_krb5_open_keytab (krb5_context k5, + code = krb5_kt_resolve (k5, keytab_name, keytab); + if (code != 0) { + _adcli_err ("Failed to open keytab: %s: %s", +- keytab_name, krb5_get_error_message (k5, code)); ++ keytab_name, adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_FAIL; + } + +@@ -200,7 +201,7 @@ _adcli_krb5_open_keytab (krb5_context k5, + code = krb5_kt_default (k5, keytab); + if (code != 0) { + _adcli_err ("Failed to open default keytab: %s", +- krb5_get_error_message (k5, code)); ++ adcli_krb5_get_error_message (k5, code)); + return ADCLI_ERR_FAIL; + } + } +@@ -570,3 +571,18 @@ _adcli_krb5_format_enctypes (krb5_enctype *enctypes) + + return value; + } ++ ++const char *adcli_krb5_get_error_message (krb5_context ctx, krb5_error_code code) ++{ ++ static char out[4096]; ++ const char *tmp; ++ size_t len; ++ ++ tmp = krb5_get_error_message (ctx, code); ++ len = strlen (tmp); ++ memcpy (out, tmp, MIN (sizeof (out), len)); ++ out[sizeof(out) - 1] = '\0'; ++ krb5_free_error_message (ctx, tmp); ++ ++ return out; ++} +diff --git a/library/adprivate.h b/library/adprivate.h +index bf0381c..cca58f9 100644 +--- a/library/adprivate.h ++++ b/library/adprivate.h +@@ -323,4 +323,6 @@ adcli_result _adcli_call_external_program (const char *binary, + uint8_t **stdout_data, + size_t *stdout_data_len); + ++const char *adcli_krb5_get_error_message (krb5_context ctx, ++ krb5_error_code code); + #endif /* ADPRIVATE_H_ */ +-- +2.47.0 + diff --git a/adcli.spec b/adcli.spec index 2d022ff..1ce90e3 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,16 +1,31 @@ -%global with_selinux 1 -%global selinuxtype targeted -%global modulename adcli - Name: adcli -Version: 0.9.3.1 -Release: 4%{?dist} +Version: 0.9.2 +Release: 10%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli -Source0: https://gitlab.freedesktop.org/-/project/1196/uploads/5a1c55410c0965835b81fbd28d820d46/adcli-%{version}.tar.gz +Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/ea560656ac921b3fe0d455976aaae9be/adcli-%{version}.tar.gz -Patch1: 0001-enroll-fix-issues-if-default-keytab-is-used.patch +# Add support for Samba's offline join feature +Patch1: 0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch +Patch2: 0002-disco-Extract-domain-GUID-from-LDAP-ping.patch +Patch3: 0003-conn-Copy-domain-GUID-from-disco.patch +Patch4: 0004-conn-Copy-forest-name-from-disco.patch +Patch5: 0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch +Patch6: 0006-conn-Store-the-address-of-the-connected-server.patch +Patch7: 0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch +Patch8: 0008-util-Allow-to-append-variables-to-external-program-e.patch +Patch9: 0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch +Patch10: 0010-util-Return-failure-if-child-exit-status-reports-so.patch +Patch11: 0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch +Patch12: 0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch +Patch13: 0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch +Patch14: 0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch +Patch15: 0015-doc-improve-some-Samba-related-doc-items.patch + +# fixes for issues found by static analyser +Patch16: 0016-Various-fixes-for-issues-found-by-static-code-scanne.patch +Patch17: 0017-krb5-add-adcli_krb5_get_error_message.patch BuildRequires: gcc BuildRequires: intltool pkgconfig @@ -23,12 +38,6 @@ BuildRequires: xmlto BuildRequires: make BuildRequires: libnetapi-devel -# Build dependencies for SELinux policy -%if %{with selinux} -BuildRequires: libselinux-devel -BuildRequires: selinux-policy-devel -%endif - Requires: cyrus-sasl-gssapi Conflicts: adcli-doc < %{version}-%{release} @@ -36,31 +45,10 @@ Conflicts: adcli-doc < %{version}-%{release} # the adcli tool itself is to be used by callers Obsoletes: adcli-devel < 0.5 -%if %{with selinux} -# This ensures that the *-selinux package and all it’s dependencies are not -# pulled into containers and other systems that do not use SELinux. The -# policy defines types and file contexts for client and server. -Requires: (%{name}-selinux if selinux-policy-%{selinuxtype}) -%endif - %description adcli is a tool for joining an Active Directory domain using standard LDAP and Kerberos calls. -%if %{with selinux} -# SELinux subpackage -%package selinux -Summary: The adcli SELinux policy -BuildArch: noarch -Requires: selinux-policy-%{selinuxtype} -Requires(post): selinux-policy-%{selinuxtype} -%{?selinux_requires_min} - -%description selinux -Custom SELinux policy module for adcli to make sure generated Kerberos keytab -files have the right SELinux context. -%endif - %define _hardened_build 1 %prep @@ -84,32 +72,13 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %ldconfig_scriptlets -%if %{with selinux} -# SELinux contexts are saved so that only affected files can be -# relabeled after the policy module installation -%pre selinux -%selinux_relabel_pre -s %{selinuxtype} - -%post selinux -%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp - -%postun selinux -if [ $1 -eq 0 ]; then - %selinux_modules_uninstall -s %{selinuxtype} %{modulename} -fi - -%posttrans selinux -%selinux_relabel_post -s %{selinuxtype} - -%endif - %files %{_sbindir}/adcli %doc AUTHORS COPYING ChangeLog NEWS README %doc %{_mandir}/*/* %package doc -Summary: The adcli documentation package +Summary: adcli documentation BuildArch: noarch Conflicts: adcli < %{version}-%{release} @@ -121,26 +90,7 @@ documentation. %files doc %doc %{_datadir}/doc/adcli/* -%if %{with selinux} -%files selinux -%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp -%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename} -%endif - %changelog -* Fri Jan 16 2026 Fedora Release Engineering - 0.9.3.1-4 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild - -* Fri Dec 19 2025 Sumit Bose - 0.9.3.1-3 -- Fix issue with restoring SELinux file label - -* Tue Dec 16 2025 Sumit Bose - 0.9.3.1-2 -- Use selinux_requires_min to avoid policycoreutils-python-utils dependency - Resolves: rhbz#2422451 - -* Tue Dec 09 2025 Sumit Bose - 0.9.3.1-1 -- Rebase to latest upstream version - * Wed Jul 23 2025 Fedora Release Engineering - 0.9.2-10 - Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild diff --git a/sources b/sources index aa241fa..1dd0180 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (adcli-0.9.3.1.tar.gz) = 3f501173b5344b38f33a3f65faec9e894da81b44b37bb161da103d8a29459d8807dfe566a5dd0a8c7eec466567b6cca4331c81dd70158b5478a61b03be37355d +SHA512 (adcli-0.9.2.tar.gz) = 0953ffb940b9abdf6277731b3fa14656b9af5686902f1b8c44389c2537e6c33db5b5272061964cf60fd6a7831e581c5362bff89d0adddc9b17059ed3a30e3971