From 078693fb251c434e2f943b547cf97d79012f83e7 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Sat, 20 Feb 2021 15:28:15 +0100 Subject: [PATCH 01/27] Update to upstream release 0.9.1 --- .gitignore | 1 + ...do-not-exit-if-keytab-cannot-be-read.patch | 32 - 0001-man-move-note-to-the-right-section.patch | 48 -- ...g-use-ldaps-option-to-update-and-tes.patch | 37 - ...-tools-disable-SSSD-s-locator-plugin.patch | 41 -- ...ix-typo-in-show-password-help-output.patch | 26 - ...in-update-set-dNSHostName-if-not-set.patch | 59 -- ...onal-parameter-of-login-ccache-bette.patch | 44 -- 0002-tools-add-show-computer-command.patch | 338 --------- ...escription-option-to-join-and-update.patch | 183 ----- ...-doc-explain-required-AD-permissions.patch | 242 ------- ...g-of-optional-credential-cache-more-.patch | 42 -- 0004-Use-GSS-SPNEGO-if-available.patch | 124 ---- 0004-enroll-add-is_service-member.patch | 66 -- 0005-add-option-use-ldaps.patch | 378 ---------- ...-computer-add-create-msa-sub-command.patch | 646 ------------------ 0006-discovery-fix.patch | 27 - ...omputer-or-service-in-debug-messages.patch | 358 ---------- ...l-more-filters-for-random-characters.patch | 77 --- ...i_enroll_add_keytab_for_service_acco.patch | 91 --- ...low-fqdn-for-locate_computer_account.patch | 129 ---- ...nt-add-random-suffix-to-account-name.patch | 122 ---- adcli.spec | 60 +- sources | 2 +- 24 files changed, 22 insertions(+), 3151 deletions(-) delete mode 100644 0001-delete-do-not-exit-if-keytab-cannot-be-read.patch delete mode 100644 0001-man-move-note-to-the-right-section.patch delete mode 100644 0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch delete mode 100644 0001-tools-disable-SSSD-s-locator-plugin.patch delete mode 100644 0001-tools-fix-typo-in-show-password-help-output.patch delete mode 100644 0002-join-update-set-dNSHostName-if-not-set.patch delete mode 100644 0002-man-explain-optional-parameter-of-login-ccache-bette.patch delete mode 100644 0002-tools-add-show-computer-command.patch delete mode 100644 0003-add-description-option-to-join-and-update.patch delete mode 100644 0003-doc-explain-required-AD-permissions.patch delete mode 100644 0003-man-make-handling-of-optional-credential-cache-more-.patch delete mode 100644 0004-Use-GSS-SPNEGO-if-available.patch delete mode 100644 0004-enroll-add-is_service-member.patch delete mode 100644 0005-add-option-use-ldaps.patch delete mode 100644 0005-computer-add-create-msa-sub-command.patch delete mode 100644 0006-discovery-fix.patch delete mode 100644 0006-enroll-use-computer-or-service-in-debug-messages.patch delete mode 100644 0007-enroll-more-filters-for-random-characters.patch delete mode 100644 0008-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch delete mode 100644 0009-enroll-allow-fqdn-for-locate_computer_account.patch delete mode 100644 0010-service-account-add-random-suffix-to-account-name.patch diff --git a/.gitignore b/.gitignore index a1343b9..ac6fbea 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /adcli-0.8.0.tar.gz /adcli-0.8.2.tar.gz /adcli-0.9.0.tar.gz +/adcli-0.9.1.tar.gz diff --git a/0001-delete-do-not-exit-if-keytab-cannot-be-read.patch b/0001-delete-do-not-exit-if-keytab-cannot-be-read.patch deleted file mode 100644 index 15aaf07..0000000 --- a/0001-delete-do-not-exit-if-keytab-cannot-be-read.patch +++ /dev/null @@ -1,32 +0,0 @@ -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/0001-man-move-note-to-the-right-section.patch b/0001-man-move-note-to-the-right-section.patch deleted file mode 100644 index c128204..0000000 --- a/0001-man-move-note-to-the-right-section.patch +++ /dev/null @@ -1,48 +0,0 @@ -From d2d3879bdfcea70757a8b0527882e79e8b5c6e70 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 27 Nov 2019 18:26:44 +0100 -Subject: [PATCH 1/6] man: move note to the right section - -Unfortunately the note about the password lifetime was added to the join -section. This patch move it to the update section where it belongs to. - -Related to https://bugzilla.redhat.com/show_bug.cgi?id=1738573 - https://bugzilla.redhat.com/show_bug.cgi?id=1745931 - https://bugzilla.redhat.com/show_bug.cgi?id=1774622 ---- - doc/adcli.xml | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 4f201e0..9faf96a 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -330,11 +330,7 @@ Password for Administrator: - important here is currently the - option, see - smb.conf5 -- for details. -- Note that if the machine account password is not -- older than 30 days, you have to pass -- to -- force the update. -+ for details. - - - -@@ -472,7 +468,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123 - important here is currently the - option, see - smb.conf5 -- for details. -+ for details. -+ Note that if the machine account password is not -+ older than 30 days, you have to pass -+ to -+ force the update. - - - --- -2.25.1 - diff --git a/0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch b/0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch deleted file mode 100644 index 13a72a1..0000000 --- a/0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 76ca1e6737742208d83e016d43a3379e378f8d90 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 14 Oct 2020 17:44:10 +0200 -Subject: [PATCH 01/10] tools: add missing use-ldaps option to update and - testjoin - -When adding the use-ldaps option the update and testjoin sub-commands -were forgotten. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1883467 ---- - tools/computer.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tools/computer.c b/tools/computer.c -index 24ea258..5a97d8b 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -491,6 +491,7 @@ adcli_tool_computer_update (adcli_conn *conn, - struct option options[] = { - { "domain", required_argument, NULL, opt_domain }, - { "domain-controller", required_argument, NULL, opt_domain_controller }, -+ { "use-ldaps", no_argument, 0, opt_use_ldaps }, - { "host-fqdn", required_argument, 0, opt_host_fqdn }, - { "computer-name", required_argument, 0, opt_computer_name }, - { "host-keytab", required_argument, 0, opt_host_keytab }, -@@ -612,6 +613,7 @@ adcli_tool_computer_testjoin (adcli_conn *conn, - struct option options[] = { - { "domain", required_argument, NULL, opt_domain }, - { "domain-controller", required_argument, NULL, opt_domain_controller }, -+ { "use-ldaps", no_argument, 0, opt_use_ldaps }, - { "host-keytab", required_argument, 0, opt_host_keytab }, - { "verbose", no_argument, NULL, opt_verbose }, - { "help", no_argument, NULL, 'h' }, --- -2.28.0 - diff --git a/0001-tools-disable-SSSD-s-locator-plugin.patch b/0001-tools-disable-SSSD-s-locator-plugin.patch deleted file mode 100644 index 07d791e..0000000 --- a/0001-tools-disable-SSSD-s-locator-plugin.patch +++ /dev/null @@ -1,41 +0,0 @@ -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/0001-tools-fix-typo-in-show-password-help-output.patch b/0001-tools-fix-typo-in-show-password-help-output.patch deleted file mode 100644 index 3e16726..0000000 --- a/0001-tools-fix-typo-in-show-password-help-output.patch +++ /dev/null @@ -1,26 +0,0 @@ -From d70075c597e7ebc1683d407409c45b04110676a0 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 15 Jun 2020 15:41:53 +0200 -Subject: [PATCH 1/3] 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/0002-join-update-set-dNSHostName-if-not-set.patch b/0002-join-update-set-dNSHostName-if-not-set.patch deleted file mode 100644 index 83fc958..0000000 --- a/0002-join-update-set-dNSHostName-if-not-set.patch +++ /dev/null @@ -1,59 +0,0 @@ -From beb7abfacc0010987d2cd8ab70f7c373d309eed9 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 15 Oct 2020 18:01:12 +0200 -Subject: [PATCH 02/10] join/update: set dNSHostName if not set - -If during a join or update an existing AD computer object does not have -the dNSHostName attribute set it will be set with the current hostname. -This is important for cases where the user doing the join or update only -has "Validated write to service principal name" for the computer object. -The validated write with fully-qualified names can only be successful if -dNSHostName is set, see [MS-ADTS] section 3.1.1.5.3.1.1.4 "Validated -Writes - servicePrincipalName" for details. - -Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1734764 ---- - library/adenroll.c | 16 ++++++++++++---- - 1 file changed, 12 insertions(+), 4 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 246f658..e745295 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -1403,21 +1403,29 @@ update_computer_account (adcli_enroll *enroll) - { - int res = 0; - LDAP *ldap; -+ char *value = NULL; - - ldap = adcli_conn_get_ldap_connection (enroll->conn); - return_if_fail (ldap != NULL); - - /* Only update attributes which are explicitly given on the command -- * line. Otherwise 'adcli update' must be always called with the same -- * set of options to make sure existing attributes are not deleted or -- * overwritten with different values. */ -- if (enroll->host_fqdn_explicit) { -+ * line or not set in the existing AD object. Otherwise 'adcli update' -+ * must be always called with the same set of options to make sure -+ * existing attributes are not deleted or overwritten with different -+ * values. */ -+ if (enroll->computer_attributes != NULL) { -+ value = _adcli_ldap_parse_value (ldap, -+ enroll->computer_attributes, -+ "dNSHostName"); -+ } -+ if (enroll->host_fqdn_explicit || value == NULL ) { - char *vals_dNSHostName[] = { enroll->host_fqdn, NULL }; - LDAPMod dNSHostName = { LDAP_MOD_REPLACE, "dNSHostName", { vals_dNSHostName, } }; - LDAPMod *mods[] = { &dNSHostName, NULL }; - - res |= update_computer_attribute (enroll, ldap, mods); - } -+ free (value); - - if (res == ADCLI_SUCCESS && enroll->trusted_for_delegation_explicit) { - char *vals_userAccountControl[] = { NULL , NULL }; --- -2.28.0 - diff --git a/0002-man-explain-optional-parameter-of-login-ccache-bette.patch b/0002-man-explain-optional-parameter-of-login-ccache-bette.patch deleted file mode 100644 index a76cbb6..0000000 --- a/0002-man-explain-optional-parameter-of-login-ccache-bette.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 93a39bd12db11dd407676f428cfbc30406a88c36 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 15 Jun 2020 15:57:47 +0200 -Subject: [PATCH 2/3] 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/0002-tools-add-show-computer-command.patch b/0002-tools-add-show-computer-command.patch deleted file mode 100644 index 67684d1..0000000 --- a/0002-tools-add-show-computer-command.patch +++ /dev/null @@ -1,338 +0,0 @@ -From 0a169bd9b2687293f74bb57694eb82f9769610c9 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 27 Nov 2019 12:34:45 +0100 -Subject: [PATCH 2/6] tools: add show-computer command - -The show-computer command prints the LDAP attributes of the related -computer object from AD. - -Related to https://bugzilla.redhat.com/show_bug.cgi?id=1737342 ---- - doc/adcli.xml | 28 ++++++++++++++ - library/adenroll.c | 78 +++++++++++++++++++++++++++++--------- - library/adenroll.h | 5 +++ - tools/computer.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++ - tools/tools.c | 1 + - tools/tools.h | 4 ++ - 6 files changed, 191 insertions(+), 18 deletions(-) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 9faf96a..1f93186 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -93,6 +93,11 @@ - --domain=domain.example.com - computer - -+ -+ adcli show-computer -+ --domain=domain.example.com -+ computer -+ - - - -@@ -811,6 +816,29 @@ Password for Administrator: - - - -+ -+ Show Computer Account Attributes -+ -+ adcli show-computer show the computer account -+ attributes stored in AD. The account must already exist. -+ -+ -+$ adcli show-computer --domain=domain.example.com host2 -+Password for Administrator: -+ -+ -+ If the computer name contains a dot, then it is -+ treated as fully qualified host name, otherwise it is treated -+ as short computer name. -+ -+ If no computer name is specified, then the host name of the -+ computer adcli is running on is used, as returned by -+ gethostname(). -+ -+ The various global options can be used. -+ -+ -+ - - Bugs - -diff --git a/library/adenroll.c b/library/adenroll.c -index 524663a..8d2adeb 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -71,6 +71,21 @@ static krb5_enctype v51_earlier_enctypes[] = { - 0 - }; - -+static char *default_ad_ldap_attrs[] = { -+ "sAMAccountName", -+ "userPrincipalName", -+ "msDS-KeyVersionNumber", -+ "msDS-supportedEncryptionTypes", -+ "dNSHostName", -+ "servicePrincipalName", -+ "operatingSystem", -+ "operatingSystemVersion", -+ "operatingSystemServicePack", -+ "pwdLastSet", -+ "userAccountControl", -+ NULL, -+}; -+ - /* Some constants for the userAccountControl AD LDAP attribute, see e.g. - * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro - * for details. */ -@@ -1213,19 +1228,6 @@ retrieve_computer_account (adcli_enroll *enroll) - char *end; - int ret; - -- char *attrs[] = { -- "msDS-KeyVersionNumber", -- "msDS-supportedEncryptionTypes", -- "dNSHostName", -- "servicePrincipalName", -- "operatingSystem", -- "operatingSystemVersion", -- "operatingSystemServicePack", -- "pwdLastSet", -- "userAccountControl", -- NULL, -- }; -- - assert (enroll->computer_dn != NULL); - assert (enroll->computer_attributes == NULL); - -@@ -1233,7 +1235,8 @@ retrieve_computer_account (adcli_enroll *enroll) - assert (ldap != NULL); - - ret = ldap_search_ext_s (ldap, enroll->computer_dn, LDAP_SCOPE_BASE, -- "(objectClass=*)", attrs, 0, NULL, NULL, NULL, -1, -+ "(objectClass=*)", default_ad_ldap_attrs, -+ 0, NULL, NULL, NULL, -1, - &enroll->computer_attributes); - - if (ret != LDAP_SUCCESS) { -@@ -2179,12 +2182,11 @@ adcli_enroll_load (adcli_enroll *enroll) - } - - adcli_result --adcli_enroll_update (adcli_enroll *enroll, -- adcli_enroll_flags flags) -+adcli_enroll_read_computer_account (adcli_enroll *enroll, -+ adcli_enroll_flags flags) - { - adcli_result res = ADCLI_SUCCESS; - LDAP *ldap; -- char *value; - - return_unexpected_if_fail (enroll != NULL); - -@@ -2214,7 +2216,18 @@ adcli_enroll_update (adcli_enroll *enroll, - } - - /* Get information about the computer account */ -- res = retrieve_computer_account (enroll); -+ return retrieve_computer_account (enroll); -+} -+ -+adcli_result -+adcli_enroll_update (adcli_enroll *enroll, -+ adcli_enroll_flags flags) -+{ -+ adcli_result res = ADCLI_SUCCESS; -+ LDAP *ldap; -+ char *value; -+ -+ res = adcli_enroll_read_computer_account (enroll, flags); - if (res != ADCLI_SUCCESS) - return res; - -@@ -2242,6 +2255,35 @@ adcli_enroll_update (adcli_enroll *enroll, - return enroll_join_or_update_tasks (enroll, flags); - } - -+adcli_result -+adcli_enroll_show_computer_attribute (adcli_enroll *enroll) -+{ -+ LDAP *ldap; -+ size_t c; -+ char **vals; -+ size_t v; -+ -+ ldap = adcli_conn_get_ldap_connection (enroll->conn); -+ assert (ldap != NULL); -+ -+ for (c = 0; default_ad_ldap_attrs[c] != NULL; c++) { -+ vals = _adcli_ldap_parse_values (ldap, -+ enroll->computer_attributes, -+ default_ad_ldap_attrs[c]); -+ printf ("%s:\n", default_ad_ldap_attrs[c]); -+ if (vals == NULL) { -+ printf (" - not set -\n"); -+ } else { -+ for (v = 0; vals[v] != NULL; v++) { -+ printf (" %s\n", vals[v]); -+ } -+ } -+ _adcli_strv_free (vals); -+ } -+ -+ return ADCLI_SUCCESS; -+} -+ - adcli_result - adcli_enroll_delete (adcli_enroll *enroll, - adcli_enroll_flags delete_flags) -diff --git a/library/adenroll.h b/library/adenroll.h -index 1d5d00d..11eb517 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -46,6 +46,11 @@ adcli_result adcli_enroll_join (adcli_enroll *enroll, - adcli_result adcli_enroll_update (adcli_enroll *enroll, - adcli_enroll_flags flags); - -+adcli_result adcli_enroll_read_computer_account (adcli_enroll *enroll, -+ adcli_enroll_flags flags); -+ -+adcli_result adcli_enroll_show_computer_attribute (adcli_enroll *enroll); -+ - adcli_result adcli_enroll_delete (adcli_enroll *enroll, - adcli_enroll_flags delete_flags); - -diff --git a/tools/computer.c b/tools/computer.c -index ac8a203..c8b96a4 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -964,3 +964,96 @@ adcli_tool_computer_delete (adcli_conn *conn, - adcli_enroll_unref (enroll); - return 0; - } -+ -+int -+adcli_tool_computer_show (adcli_conn *conn, -+ int argc, -+ char *argv[]) -+{ -+ adcli_enroll *enroll; -+ adcli_result res; -+ int opt; -+ -+ struct option options[] = { -+ { "domain", required_argument, NULL, opt_domain }, -+ { "domain-realm", required_argument, NULL, opt_domain_realm }, -+ { "domain-controller", required_argument, NULL, opt_domain_controller }, -+ { "login-user", required_argument, NULL, opt_login_user }, -+ { "login-ccache", optional_argument, NULL, opt_login_ccache }, -+ { "login-type", required_argument, NULL, opt_login_type }, -+ { "no-password", no_argument, 0, opt_no_password }, -+ { "stdin-password", no_argument, 0, opt_stdin_password }, -+ { "prompt-password", no_argument, 0, opt_prompt_password }, -+ { "verbose", no_argument, NULL, opt_verbose }, -+ { "help", no_argument, NULL, 'h' }, -+ { 0 }, -+ }; -+ -+ static adcli_tool_desc usages[] = { -+ { 0, "usage: adcli show-computer --domain=xxxx host1.example.com" }, -+ { 0 }, -+ }; -+ -+ enroll = adcli_enroll_new (conn); -+ if (enroll == NULL) { -+ warnx ("unexpected memory problems"); -+ return -1; -+ } -+ -+ while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { -+ switch (opt) { -+ case 'h': -+ case '?': -+ case ':': -+ adcli_tool_usage (options, usages); -+ adcli_tool_usage (options, common_usages); -+ adcli_enroll_unref (enroll); -+ return opt == 'h' ? 0 : 2; -+ default: -+ res = parse_option ((Option)opt, optarg, conn, enroll); -+ if (res != ADCLI_SUCCESS) { -+ adcli_enroll_unref (enroll); -+ return res; -+ } -+ break; -+ } -+ } -+ -+ argc -= optind; -+ argv += optind; -+ -+ res = adcli_conn_connect (conn); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("couldn't connect to %s domain: %s", -+ adcli_conn_get_domain_name (conn), -+ adcli_get_last_error ()); -+ adcli_enroll_unref (enroll); -+ return -res; -+ } -+ -+ if (argc == 1) { -+ parse_fqdn_or_name (enroll, argv[0]); -+ } -+ -+ res = adcli_enroll_read_computer_account (enroll, 0); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("couldn't read data for %s: %s", -+ adcli_enroll_get_host_fqdn (enroll) != NULL -+ ? adcli_enroll_get_host_fqdn (enroll) -+ : adcli_enroll_get_computer_name (enroll), -+ adcli_get_last_error ()); -+ adcli_enroll_unref (enroll); -+ return -res; -+ } -+ -+ res = adcli_enroll_show_computer_attribute (enroll); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("couldn't print data for %s: %s", -+ argv[0], adcli_get_last_error ()); -+ adcli_enroll_unref (enroll); -+ return -res; -+ } -+ -+ adcli_enroll_unref (enroll); -+ return 0; -+} -diff --git a/tools/tools.c b/tools/tools.c -index fc9fa9a..9d422f2 100644 ---- a/tools/tools.c -+++ b/tools/tools.c -@@ -59,6 +59,7 @@ struct { - { "preset-computer", adcli_tool_computer_preset, "Pre setup computers accounts", }, - { "reset-computer", adcli_tool_computer_reset, "Reset a computer account", }, - { "delete-computer", adcli_tool_computer_delete, "Delete a computer account", }, -+ { "show-computer", adcli_tool_computer_show, "Show computer account attributes stored in AD", }, - { "create-user", adcli_tool_user_create, "Create a user account", }, - { "delete-user", adcli_tool_user_delete, "Delete a user account", }, - { "create-group", adcli_tool_group_create, "Create a group", }, -diff --git a/tools/tools.h b/tools/tools.h -index 8cebbf9..3702875 100644 ---- a/tools/tools.h -+++ b/tools/tools.h -@@ -78,6 +78,10 @@ int adcli_tool_computer_delete (adcli_conn *conn, - int argc, - char *argv[]); - -+int adcli_tool_computer_show (adcli_conn *conn, -+ int argc, -+ char *argv[]); -+ - int adcli_tool_user_create (adcli_conn *conn, - int argc, - char *argv[]); --- -2.25.1 - diff --git a/0003-add-description-option-to-join-and-update.patch b/0003-add-description-option-to-join-and-update.patch deleted file mode 100644 index 43e1633..0000000 --- a/0003-add-description-option-to-join-and-update.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 3937a2a7db90611aa7a93248233b0c5d31e85a3e Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 27 Nov 2019 14:48:32 +0100 -Subject: [PATCH 3/6] add description option to join and update - -This new option allows to set the description LDAP attribute for the AD -computer object. - -Related to https://bugzilla.redhat.com/show_bug.cgi?id=1737342 ---- - doc/adcli.xml | 10 ++++++++++ - library/adenroll.c | 29 +++++++++++++++++++++++++++++ - library/adenroll.h | 4 ++++ - tools/computer.c | 7 +++++++ - 4 files changed, 50 insertions(+) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 1f93186..dd30435 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -275,6 +275,11 @@ Password for Administrator: - Set the operating system version on the computer - account. Not set by default. - -+ -+ -+ Set the description attribute on the computer -+ account. Not set by default. -+ - - - Additional service name for a kerberos -@@ -416,6 +421,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123 - Set the operating system version on the computer - account. Not set by default. - -+ -+ -+ Set the description attribute on the computer -+ account. Not set by default. -+ - - - Additional service name for a Kerberos -diff --git a/library/adenroll.c b/library/adenroll.c -index 8d2adeb..246f658 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -83,6 +83,7 @@ static char *default_ad_ldap_attrs[] = { - "operatingSystemServicePack", - "pwdLastSet", - "userAccountControl", -+ "description", - NULL, - }; - -@@ -143,6 +144,7 @@ struct _adcli_enroll { - char *samba_data_tool; - bool trusted_for_delegation; - int trusted_for_delegation_explicit; -+ char *description; - }; - - static adcli_result -@@ -756,6 +758,8 @@ create_computer_account (adcli_enroll *enroll, - char *vals_userPrincipalName[] = { enroll->user_principal, NULL }; - LDAPMod userPrincipalName = { LDAP_MOD_ADD, "userPrincipalName", { vals_userPrincipalName, }, }; - LDAPMod servicePrincipalName = { LDAP_MOD_ADD, "servicePrincipalName", { enroll->service_principals, } }; -+ char *vals_description[] = { enroll->description, NULL }; -+ LDAPMod description = { LDAP_MOD_ADD, "description", { vals_description, }, }; - - char *val = NULL; - -@@ -774,6 +778,7 @@ create_computer_account (adcli_enroll *enroll, - &operatingSystemServicePack, - &userPrincipalName, - &servicePrincipalName, -+ &description, - NULL - }; - -@@ -1460,6 +1465,14 @@ update_computer_account (adcli_enroll *enroll) - res |= update_computer_attribute (enroll, ldap, mods); - } - -+ if (res == ADCLI_SUCCESS && enroll->description != NULL) { -+ char *vals_description[] = { enroll->description, NULL }; -+ LDAPMod description = { LDAP_MOD_REPLACE, "description", { vals_description, }, }; -+ LDAPMod *mods[] = { &description, NULL, }; -+ -+ res |= update_computer_attribute (enroll, ldap, mods); -+ } -+ - if (res != 0) - _adcli_info ("Updated existing computer account: %s", enroll->computer_dn); - } -@@ -2899,6 +2912,22 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll, - enroll->trusted_for_delegation_explicit = 1; - } - -+void -+adcli_enroll_set_description (adcli_enroll *enroll, const char *value) -+{ -+ return_if_fail (enroll != NULL); -+ if (value != NULL && value[0] != '\0') { -+ _adcli_str_set (&enroll->description, value); -+ } -+} -+ -+const char * -+adcli_enroll_get_desciption (adcli_enroll *enroll) -+{ -+ return_val_if_fail (enroll != NULL, NULL); -+ return enroll->description; -+} -+ - const char ** - adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll) - { -diff --git a/library/adenroll.h b/library/adenroll.h -index 11eb517..0606169 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -126,6 +126,10 @@ bool adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll - void adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll, - bool value); - -+const char * adcli_enroll_get_desciption (adcli_enroll *enroll); -+void adcli_enroll_set_description (adcli_enroll *enroll, -+ const char *value); -+ - krb5_kvno adcli_enroll_get_kvno (adcli_enroll *enroll); - - void adcli_enroll_set_kvno (adcli_enroll *enroll, -diff --git a/tools/computer.c b/tools/computer.c -index c8b96a4..840e334 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -112,6 +112,7 @@ typedef enum { - opt_trusted_for_delegation, - opt_add_service_principal, - opt_remove_service_principal, -+ opt_description, - } Option; - - static adcli_tool_desc common_usages[] = { -@@ -142,6 +143,7 @@ static adcli_tool_desc common_usages[] = { - "in the userAccountControl attribute", }, - { opt_add_service_principal, "add the given service principal to the account\n" }, - { opt_remove_service_principal, "remove the given service principal from the account\n" }, -+ { opt_description, "add a description to the account\n" }, - { opt_no_password, "don't prompt for or read a password" }, - { opt_prompt_password, "prompt for a password if necessary" }, - { opt_stdin_password, "read a password from stdin (until EOF) if\n" -@@ -306,6 +308,9 @@ parse_option (Option opt, - case opt_remove_service_principal: - adcli_enroll_add_service_principal_to_remove (enroll, optarg); - return ADCLI_SUCCESS; -+ case opt_description: -+ adcli_enroll_set_description (enroll, optarg); -+ return ADCLI_SUCCESS; - case opt_verbose: - return ADCLI_SUCCESS; - -@@ -369,6 +374,7 @@ adcli_tool_computer_join (adcli_conn *conn, - { "os-name", required_argument, NULL, opt_os_name }, - { "os-version", required_argument, NULL, opt_os_version }, - { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, -+ { "description", optional_argument, NULL, opt_description }, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, - { "add-service-principal", required_argument, NULL, opt_add_service_principal }, -@@ -487,6 +493,7 @@ adcli_tool_computer_update (adcli_conn *conn, - { "os-name", required_argument, NULL, opt_os_name }, - { "os-version", required_argument, NULL, opt_os_version }, - { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, -+ { "description", optional_argument, NULL, opt_description }, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, --- -2.25.1 - diff --git a/0003-doc-explain-required-AD-permissions.patch b/0003-doc-explain-required-AD-permissions.patch deleted file mode 100644 index d6d9024..0000000 --- a/0003-doc-explain-required-AD-permissions.patch +++ /dev/null @@ -1,242 +0,0 @@ -From fa5c5fb4f8e7bcadf3e5a3798bd060720fd35eaa Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 20 Oct 2020 13:34:41 +0200 -Subject: [PATCH 03/10] doc: explain required AD permissions - -When using a restricted account with adcli some operations might fail -because the account might not have all required permissions. The man -page is extended and now explains which permissions are needed under -given circumstances. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1852080 -Resolves: https://gitlab.freedesktop.org/realmd/adcli/-/issues/20 ---- - doc/Makefile.am | 10 ++++ - doc/adcli.xml | 132 +++++++++++++++++++++++++++++++++++++++++++++ - library/adenroll.c | 30 ++++++----- - 3 files changed, 160 insertions(+), 12 deletions(-) - -diff --git a/doc/Makefile.am b/doc/Makefile.am -index 4490688..50fb777 100644 ---- a/doc/Makefile.am -+++ b/doc/Makefile.am -@@ -33,14 +33,17 @@ EXTRA_DIST = \ - version.xml \ - samba_data_tool_path.xml.in \ - samba_data_tool_path.xml \ -+ permissions.xml \ - $(NULL) - - CLEANFILES = \ - $(man8_MANS) \ -+ permissions.xml \ - $(NULL) - - XSLTPROC_FLAGS = \ - --nonet \ -+ --xinclude \ - --stringparam man.output.quietly 1 \ - --stringparam funcsynopsis.style ansi \ - --stringparam man.th.extra1.suppress 1 \ -@@ -50,6 +53,13 @@ XSLTPROC_FLAGS = \ - XSLTPROC_MAN = \ - $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl - -+permissions.xml: ../library/adenroll.c adcli.xml -+ echo "" > $@ -+ grep '".*".*/\* :ADPermissions: ' $< | sed -e 's#.*"\(.*\)".*/\* :ADPermissions: \(.*\)\*/$$#\1\2#' | sed -e 's#\*##g' >> $@ -+ echo "" >> $@ -+ -+$(man8_MANS): permissions.xml -+ - .xml.8: - $(AM_V_GEN) $(XSLTPROC_MAN) $< - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 1437679..cc44fd8 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -885,6 +885,138 @@ Password for Administrator: - - - -+ -+ Delegated Permissions -+ It is common practice in AD to not use an account from the Domain -+ Administrators group to join a machine to a domain but use a dedicated -+ account which only has permissions to join a machine to one or more OUs -+ in the Active Directory tree. Giving the needed permissions to a single -+ account or a group in Active Directory is called Delegation. A typical -+ example on how to configured Delegation can be found in the Delegation -+ section of the blog post -+ Who can add workstation to the domain. -+ -+ -+ When using an account with delegated permissions with adcli -+ basically the same applies as well. However some aspects are explained -+ here in a bit more details to better illustrate different concepts of -+ Active Directory and to make it more easy to debug permissions issues -+ during the join. Please note that the following is not specific to -+ adcli but applies to all applications which would like to modify -+ certain properties or objects in Active Directory with an account with -+ limited permissions. -+ -+ First, as said in the blog post it is sufficient to have -+ "Create computer object" permissions to join a -+ computer to a domain. But this would only work as expected if the -+ computer object does not exist in Active Directory before the join. -+ Because only when a new object is created Active Directory does not -+ apply additional permission checks on the attributes of the new -+ computer object. This means the delegated user can add any kind of -+ attribute with any value to a new computer object also long as they -+ meet general constraints like e.g. that the attribute must be defined -+ in the schema and is allowed in a objectclass of the object, the value -+ must match the syntax defined in the schema or that the -+ must be unique in the domain. -+ -+ If you want to use the account with delegated permission to -+ remove computer objects in Active Directory (adcli delete-computer) you -+ should of course make sure that the account has -+ "Delete computer object" permissions. -+ -+ If the computer object already exists the -+ "Create computer object" permission does not apply -+ anymore since now an existing object must be modified. Now permissions -+ on the individual attributes are needed. e.g. -+ "Read and write Account Restrictions" or -+ "Reset Password". For some attributes Active -+ Directory has two types of permissions the plain -+ "Read and Write" permissions and the -+ "Validated Write" permissions. For the latter case -+ there are two specific permissions relevant for adcli, namely -+ -+ Validated write to DNS host name -+ Validated write to service principal name -+ -+ Details about the validation of the values can be found in the -+ "Validated Writes" section of -+ [MS-ADTS], especially -+ dNSHostName -+ and -+ servicePrincipalName. -+ To cut it short for "Validated write to DNS host name" -+ the domain part of the fully-qualified hostname must either match the -+ domain name of the domain you want to join to or must be listed in the -+ attribute. And for -+ "Validated write to service principal name" the -+ hostname part of the service principal name must match the name stored -+ in or some other attributes which are -+ not handled by adcli. This also means that -+ cannot be empty or only contain a short -+ name if the service principal name should contain a fully-qualified -+ name. -+ -+ To summarize, if you only have validated write permissions you -+ should make sure the domain part of the hostname matches the domain you -+ want to join or use the with a matching -+ name. -+ -+ The plain read write permissions do not run additional -+ validations but the attribute values must still be in agreement with -+ the general constraints mentioned above. If the computer object already -+ exists adcli might need the following permissions which are also needed -+ by Windows clients to modify existing attributes: -+ -+ Reset Password -+ Read and write Account Restrictions -+ Read and (validated) write to DNS host name -+ Read and (validated) write to service principal name -+ -+ additionally adcli needs -+ -+ Read and write msDS-supportedEncryptionTypes -+ -+ This is added for security reasons to avoid that Active Directory -+ stores Kerberos keys with (potentially weaker) encryption types than -+ the client supports since Active Directory is often configured to still -+ support older (weaker) encryption types for compatibility reasons. -+ -+ -+ All other attributes are only set or modified on demand, i.e. -+ adcli must be called with an option the would set or modify the given -+ attribute. In the following the attributes adcli can modify together -+ with the required permissions are listed: -+ -+ -+ -+ For the management of users and groups (adcli create-user, -+ adcli delete-user, adcli create-group, adcli delete-group) the same -+ applies only for different types of objects, i.e. users and groups. -+ Since currently adcli only supports the creation and the removal of -+ user and group objects it is sufficient to have the -+ "Create/Delete User objects" and -+ "Create/Delete Group objects" permissions. -+ -+ If you want to manage group members as well (adcli add-member, -+ adcli remove-member) "Read/Write Members" permissions -+ are needed as well. -+ -+ Depending on the version of Active Directory the -+ "Delegation of Control Wizard" might offer some -+ shortcuts for common task like e.g. -+ -+ Create, delete and manage user accounts -+ Create, delete and manage groups -+ Modify the membership of a group -+ -+ The first 2 shortcuts will provided full access to user and group -+ objects which, as explained above, is more than currently is needed. -+ After using those shortcut it is a good idea to verify in the -+ "Security" tab in the "Properties" -+ of the related Active Directory container that the assigned permissions -+ meet the expectations. -+ -+ - - Bugs - -diff --git a/library/adenroll.c b/library/adenroll.c -index e745295..98e9786 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -71,19 +71,25 @@ static krb5_enctype v51_earlier_enctypes[] = { - 0 - }; - -+/* The following list containst all attributes handled by adcli, some are -+ * read-only and the others can be written as well. To properly document the -+ * required permissions each attribute which adcli tries to modify should have -+ * a comment starting with ':ADPermissions:' and the related permissions in AD -+ * on the same line. Multiple permissions can be seperated with a '*'. For all -+ * other attribute a suitable comment is very welcome. */ - static char *default_ad_ldap_attrs[] = { -- "sAMAccountName", -- "userPrincipalName", -- "msDS-KeyVersionNumber", -- "msDS-supportedEncryptionTypes", -- "dNSHostName", -- "servicePrincipalName", -- "operatingSystem", -- "operatingSystemVersion", -- "operatingSystemServicePack", -- "pwdLastSet", -- "userAccountControl", -- "description", -+ "sAMAccountName", /* Only set during creation */ -+ "userPrincipalName", /* :ADPermissions: Read/Write userPrincipal Name */ -+ "msDS-KeyVersionNumber", /* Manages by AD */ -+ "msDS-supportedEncryptionTypes", /* :ADPermissions: Read/Write msDS-SupportedEncryptionTypes */ -+ "dNSHostName", /* :ADPermissions: Read/Write dNSHostName * Read and write DNS host name attributes * Validated write to DNS host name */ -+ "servicePrincipalName", /* :ADPermissions: Read/Write servicePrincipalName * Validated write to service principal name */ -+ "operatingSystem", /* :ADPermissions: Read/Write Operating System */ -+ "operatingSystemVersion", /* :ADPermissions: Read/Write Operating System Version */ -+ "operatingSystemServicePack", /* :ADPermissions: Read/Write operatingSystemServicePack */ -+ "pwdLastSet", /* Managed by AD */ -+ "userAccountControl", /* :ADPermissions: Read/Write userAccountControl */ -+ "description", /* :ADPermissions: Read/Write Description */ - NULL, - }; - --- -2.28.0 - diff --git a/0003-man-make-handling-of-optional-credential-cache-more-.patch b/0003-man-make-handling-of-optional-credential-cache-more-.patch deleted file mode 100644 index 328cc5a..0000000 --- a/0003-man-make-handling-of-optional-credential-cache-more-.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 88fbb7e2395dec20b37697a213a097909870c21f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 13 Aug 2020 17:10:01 +0200 -Subject: [PATCH 3/3] man: make handling of optional credential cache more - clear - -The optional Kerberos credential cache can only be used with the long -option name --login-ccache and not with the short version -C. To make -this more clear each option get its own entry. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791545 ---- - doc/adcli.xml | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index ecf8726..1437679 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -153,10 +153,16 @@ $ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.exa - - - -- -- Use the specified kerberos credential -+ -+ Use the default Kerberos credential -+ cache to authenticate with the domain. -+ -+ -+ -+ -+ Use the specified Kerberos credential - cache to authenticate with the domain. If no credential -- cache is specified, the default kerberos 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 --- -2.26.2 - diff --git a/0004-Use-GSS-SPNEGO-if-available.patch b/0004-Use-GSS-SPNEGO-if-available.patch deleted file mode 100644 index dba4893..0000000 --- a/0004-Use-GSS-SPNEGO-if-available.patch +++ /dev/null @@ -1,124 +0,0 @@ -From a6f795ba3d6048b32d7863468688bf7f42b2cafd Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 11 Oct 2019 16:39:25 +0200 -Subject: [PATCH 4/6] 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.25.1 - diff --git a/0004-enroll-add-is_service-member.patch b/0004-enroll-add-is_service-member.patch deleted file mode 100644 index d4057d9..0000000 --- a/0004-enroll-add-is_service-member.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 4e4dbf8d2b437808863f8be85e7f30865d88c7fc Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 23 Oct 2020 16:46:43 +0200 -Subject: [PATCH 04/10] enroll: add is_service member - -Add helpers to indicate a managed service account. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - library/adenroll.c | 17 +++++++++++++++++ - library/adenroll.h | 4 ++++ - 2 files changed, 21 insertions(+) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 98e9786..5ae1f7b 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -103,6 +103,8 @@ static char *default_ad_ldap_attrs[] = { - struct _adcli_enroll { - int refs; - adcli_conn *conn; -+ bool is_service; -+ bool is_service_explicit; - - char *host_fqdn; - int host_fqdn_explicit; -@@ -2942,6 +2944,21 @@ adcli_enroll_get_desciption (adcli_enroll *enroll) - return enroll->description; - } - -+void -+adcli_enroll_set_is_service (adcli_enroll *enroll, bool value) -+{ -+ return_if_fail (enroll != NULL); -+ -+ enroll->is_service = value; -+ enroll->is_service_explicit = true; -+} -+ -+bool -+adcli_enroll_get_is_service (adcli_enroll *enroll) -+{ -+ return enroll->is_service; -+} -+ - const char ** - adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll) - { -diff --git a/library/adenroll.h b/library/adenroll.h -index 0606169..7765ed4 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -130,6 +130,10 @@ const char * adcli_enroll_get_desciption (adcli_enroll *enroll); - void adcli_enroll_set_description (adcli_enroll *enroll, - const char *value); - -+bool adcli_enroll_get_is_service (adcli_enroll *enroll); -+void adcli_enroll_set_is_service (adcli_enroll *enroll, -+ bool value); -+ - krb5_kvno adcli_enroll_get_kvno (adcli_enroll *enroll); - - void adcli_enroll_set_kvno (adcli_enroll *enroll, --- -2.28.0 - diff --git a/0005-add-option-use-ldaps.patch b/0005-add-option-use-ldaps.patch deleted file mode 100644 index 675f204..0000000 --- a/0005-add-option-use-ldaps.patch +++ /dev/null @@ -1,378 +0,0 @@ -From 85097245b57f190337225dbdbf6e33b58616c092 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 19 Dec 2019 07:22:33 +0100 -Subject: [PATCH 5/6] 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.25.1 - diff --git a/0005-computer-add-create-msa-sub-command.patch b/0005-computer-add-create-msa-sub-command.patch deleted file mode 100644 index 552a3ca..0000000 --- a/0005-computer-add-create-msa-sub-command.patch +++ /dev/null @@ -1,646 +0,0 @@ -From 41379f7ad6a9442dd55cc43d832427911e86db31 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 23 Oct 2020 16:53:43 +0200 -Subject: [PATCH 05/10] computer: add create-msa sub-command - -Add new sub-command to create a managed service account in AD. This can -be used if LDAP access to AD is needed but the host is already joined to -a different domain. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - doc/adcli.xml | 140 ++++++++++++++++++++++++++++++++++++++ - library/adenroll.c | 164 ++++++++++++++++++++++++++++++++++++++------- - tools/computer.c | 125 ++++++++++++++++++++++++++++++++++ - tools/tools.c | 1 + - tools/tools.h | 4 ++ - 5 files changed, 409 insertions(+), 25 deletions(-) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index cc44fd8..14921f9 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -98,6 +98,10 @@ - --domain=domain.example.com - computer - -+ -+ adcli create-msa -+ --domain=domain.example.com -+ - - - -@@ -885,6 +889,142 @@ Password for Administrator: - - - -+ -+ Create a managed service account -+ -+ adcli create-msa creates a managed service -+ account (MSA) in the given Active Directory domain. This is useful if a -+ computer should not fully join the Active Directory domain but LDAP -+ access is needed. A typical use case is that the computer is already -+ joined an Active Directory domain and needs access to another Active -+ Directory domain in the same or a trusted forest where the host -+ credentials from the joined Active Directory domain are -+ not valid, e.g. there is only a one-way trust. -+ -+ -+$ adcli create-msa --domain=domain.example.com -+Password for Administrator: -+ -+ -+ The managed service account, as maintained by adcli, cannot have -+ additional service principals names (SPNs) associated with it. An SPN -+ is defined within the context of a Kerberos service which is tied to a -+ machine account in Active Directory. Since a machine can be joined to a -+ single Active Directory domain, managed service account in a different -+ Active Directory domain will not have the SPNs that otherwise are part -+ of another Active Directory domain's machine. -+ -+ Since it is expected that a client will most probably join to the -+ Active Directory domain matching its DNS domain the managed service -+ account will be needed for a different Active directory domain and as a -+ result the Active Directory domain name is a mandatory option. If -+ called with no other options adcli create-msa -+ will use the short hostname with an additional random suffix as -+ computer name to avoid name collisions. -+ -+ LDAP attribute sAMAccountName has a limit of 20 characters. -+ However, machine account's NetBIOS name must be at most 16 characters -+ long, including a trailing '$' sign. Since it is not expected that the -+ managed service accounts created by adcli will be used on the NetBIOS -+ level the remaining 4 characters can be used to add uniqueness. Managed -+ service account names will have a suffix of 3 random characters from -+ number and upper- and lowercase ASCII ranges appended to the chosen -+ short host name, using '!' as a separator. For a host with the -+ shortname 'myhost', a managed service account will have a common name -+ (CN attribute) 'myhost!A2c' and a NetBIOS name -+ (sAMAccountName attribute) will be 'myhost!A2c$'. A corresponding -+ Kerberos principal in the Active Directory domain where the managed -+ service account was created would be -+ 'myhost!A2c$@DOMAIN.EXAMPLE.COM'. -+ -+ A keytab for the managed service account is stored into a file -+ specified with -K option. If it is not specified, the file is named -+ after the default keytab file, with lowercase Active Directory domain -+ of the managed service account as a suffix. On most systems it would be -+ /etc/krb5.keytab with a suffix of -+ 'domain.example.com', e.g. -+ /etc/krb5.keytad.domain.example.com. -+ -+ adcli create-msa can be called multiple -+ times to reset the password of the managed service account. To identify -+ the right account with the random component in the name the -+ corresponding principal is read from the keytab. If the keytab got -+ deleted adcli will try to identify an existing -+ managed service account with the help of the fully-qualified name, if -+ this fails a new managed service account will be created. -+ -+ The managed service account password can be updated with -+ -+$ adcli update --domain=domain.example.com --host-keytab=/etc/krb5.keytad.domain.example.com -+ -+ and the managed service account can be deleted with -+ -+$ adcli delete-computer --domain=domain.example.com 'myhost!A2c' -+ -+ -+ -+ In addition to the global options, you can specify the following -+ options to control how this operation is done. -+ -+ -+ -+ -+ The short non-dotted name of the managed -+ service account that will be created in the Active -+ Directory domain. The long option name -+ is -+ kept to underline the similarity with the same option -+ of the other sub-commands. If not specified, -+ then the first portion of the -+ or its default is used with a random suffix. -+ -+ -+ -+ The full distinguished name of the OU in -+ which to create the managed service account. If not -+ specified, then the managed service account will be -+ created in a default location. -+ -+ -+ -+ Override the local machine's fully -+ qualified DNS domain name. If not specified, the local -+ machine's hostname will be retrieved via -+ gethostname(). -+ If gethostname() only returns a short name -+ getaddrinfo() with the AI_CANONNAME hint -+ is called to expand the name to a fully qualified DNS -+ domain name. -+ -+ -+ -+ Specify the path to the host keytab where -+ credentials of the managed service account will be -+ written after a successful creation. If not specified, -+ the default location will be used, usually -+ /etc/krb5.keytab with -+ the lower-cased Active Directory domain name added as a -+ suffix e.g. -+ /etc/krb5.keytab.domain.example.com. -+ -+ -+ -+ -+ After a successful creation print out -+ information about the created object. This is output in -+ a format that should be both human and machine -+ readable. -+ -+ -+ -+ After a successful creation print out -+ the managed service account password. This is output in -+ a format that should be both human and machine -+ readable. -+ -+ -+ -+ - - Delegated Permissions - It is common practice in AD to not use an account from the Domain -diff --git a/library/adenroll.c b/library/adenroll.c -index 5ae1f7b..dbfda36 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -155,6 +155,20 @@ struct _adcli_enroll { - char *description; - }; - -+static void -+check_if_service (adcli_enroll *enroll, -+ LDAP *ldap, -+ LDAPMessage *results) -+{ -+ char **objectclasses = NULL; -+ -+ objectclasses = _adcli_ldap_parse_values (ldap, results, "objectClass"); -+ enroll->is_service = _adcli_strv_has_ex (objectclasses, -+ "msDS-ManagedServiceAccount", -+ strcasecmp) == 1 ? true : false; -+ _adcli_strv_free (objectclasses); -+} -+ - static adcli_result - ensure_host_fqdn (adcli_result res, - adcli_enroll *enroll) -@@ -471,13 +485,15 @@ ensure_keytab_principals (adcli_result res, - { - krb5_context k5; - krb5_error_code code; -- int count; -+ int count = 0; - int at, i; - - /* Prepare the principals we're going to add to the keytab */ - -- return_unexpected_if_fail (enroll->service_principals); -- count = _adcli_strv_len (enroll->service_principals); -+ if (!enroll->is_service) { -+ return_unexpected_if_fail (enroll->service_principals); -+ count = _adcli_strv_len (enroll->service_principals); -+ } - - k5 = adcli_conn_get_krb5_context (enroll->conn); - return_unexpected_if_fail (k5 != NULL); -@@ -556,8 +572,12 @@ static adcli_result - lookup_computer_container (adcli_enroll *enroll, - LDAP *ldap) - { -- char *attrs[] = { "wellKnownObjects", NULL }; -- char *prefix = "B:32:AA312825768811D1ADED00C04FD8D5CD:"; -+ char *attrs[] = { enroll->is_service ? "otherWellKnownObjects" -+ : "wellKnownObjects", NULL }; -+ const char *prefix = enroll->is_service ? "B:32:1EB93889E40C45DF9F0C64D23BBB6237:" -+ : "B:32:AA312825768811D1ADED00C04FD8D5CD:"; -+ const char *filter = enroll->is_service ? "(&(objectClass=container)(cn=Managed Service Accounts))" -+ : "(&(objectClass=container)(cn=Computers))"; - int prefix_len; - LDAPMessage *results; - const char *base; -@@ -586,7 +606,7 @@ lookup_computer_container (adcli_enroll *enroll, - "Couldn't lookup computer container: %s", base); - } - -- values = _adcli_ldap_parse_values (ldap, results, "wellKnownObjects"); -+ values = _adcli_ldap_parse_values (ldap, results, attrs[0]); - ldap_msgfree (results); - - prefix_len = strlen (prefix); -@@ -604,8 +624,7 @@ lookup_computer_container (adcli_enroll *enroll, - - /* Try harder */ - if (!enroll->computer_container) { -- ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE, -- "(&(objectClass=container)(cn=Computers))", -+ ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE, filter, - attrs, 0, NULL, NULL, NULL, -1, &results); - if (ret == LDAP_SUCCESS) { - enroll->computer_container = _adcli_ldap_parse_dn (ldap, results); -@@ -747,7 +766,7 @@ static adcli_result - create_computer_account (adcli_enroll *enroll, - LDAP *ldap) - { -- char *vals_objectClass[] = { "computer", NULL }; -+ char *vals_objectClass[] = { enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", NULL }; - LDAPMod objectClass = { LDAP_MOD_ADD, "objectClass", { vals_objectClass, } }; - char *vals_sAMAccountName[] = { enroll->computer_sam, NULL }; - LDAPMod sAMAccountName = { LDAP_MOD_ADD, "sAMAccountName", { vals_sAMAccountName, } }; -@@ -806,7 +825,7 @@ create_computer_account (adcli_enroll *enroll, - m = 0; - for (c = 0; c < mods_count - 1; c++) { - /* Skip empty LDAP sttributes */ -- if (all_mods[c]->mod_vals.modv_strvals[0] != NULL) { -+ if (all_mods[c]->mod_vals.modv_strvals != NULL && all_mods[c]->mod_vals.modv_strvals[0] != NULL) { - mods[m++] = all_mods[c]; - } - } -@@ -936,7 +955,7 @@ locate_computer_account (adcli_enroll *enroll, - LDAPMessage **rresults, - LDAPMessage **rentry) - { -- char *attrs[] = { "1.1", NULL }; -+ char *attrs[] = { "objectClass", NULL }; - LDAPMessage *results = NULL; - LDAPMessage *entry = NULL; - const char *base; -@@ -948,7 +967,9 @@ locate_computer_account (adcli_enroll *enroll, - /* If we don't yet know our computer dn, then try and find it */ - value = _adcli_ldap_escape_filter (enroll->computer_sam); - return_unexpected_if_fail (value != NULL); -- if (asprintf (&filter, "(&(objectClass=computer)(sAMAccountName=%s))", value) < 0) -+ if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))", -+ enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", -+ value) < 0) - return_unexpected_if_reached (); - free (value); - -@@ -962,8 +983,11 @@ locate_computer_account (adcli_enroll *enroll, - if (ret == LDAP_SUCCESS) { - entry = ldap_first_entry (ldap, results); - -- /* If we found a computer account, make note of dn */ -+ /* If we found a computer/service account, make note of dn */ - if (entry) { -+ if (!enroll->is_service_explicit) { -+ check_if_service ( enroll, ldap, results); -+ } - dn = ldap_get_dn (ldap, entry); - free (enroll->computer_dn); - enroll->computer_dn = strdup (dn); -@@ -1003,7 +1027,7 @@ load_computer_account (adcli_enroll *enroll, - LDAPMessage **rresults, - LDAPMessage **rentry) - { -- char *attrs[] = { "1.1", NULL }; -+ char *attrs[] = { "objectClass", NULL }; - LDAPMessage *results = NULL; - LDAPMessage *entry = NULL; - int ret; -@@ -1081,6 +1105,12 @@ locate_or_create_computer_account (adcli_enroll *enroll, - if (res == ADCLI_SUCCESS && entry == NULL) - res = create_computer_account (enroll, ldap); - -+ /* Service account already exists, just continue and update the -+ * password */ -+ if (enroll->is_service && entry != NULL) { -+ res = ADCLI_SUCCESS; -+ } -+ - if (results) - ldap_msgfree (results); - -@@ -1413,6 +1443,11 @@ update_computer_account (adcli_enroll *enroll) - LDAP *ldap; - char *value = NULL; - -+ /* No updates for service accounts */ -+ if (enroll->is_service) { -+ return; -+ } -+ - ldap = adcli_conn_get_ldap_connection (enroll->conn); - return_if_fail (ldap != NULL); - -@@ -1501,6 +1536,11 @@ update_service_principals (adcli_enroll *enroll) - LDAP *ldap; - int ret; - -+ /* No updates for service accounts */ -+ if (enroll->is_service) { -+ return ADCLI_SUCCESS; -+ } -+ - ldap = adcli_conn_get_ldap_connection (enroll->conn); - return_unexpected_if_fail (ldap != NULL); - -@@ -1614,6 +1654,8 @@ load_keytab_entry (krb5_context k5, - enroll->computer_name = name; - name[len - 1] = '\0'; - _adcli_info ("Found computer name in keytab: %s", name); -+ adcli_conn_set_computer_name (enroll->conn, -+ enroll->computer_name); - name = NULL; - - } else if (!enroll->host_fqdn && _adcli_str_has_prefix (name, "host/") && strchr (name, '.')) { -@@ -2002,17 +2044,25 @@ adcli_enroll_prepare (adcli_enroll *enroll, - - adcli_clear_last_error (); - -- /* Basic discovery and figuring out enroll params */ -- res = ensure_host_fqdn (res, enroll); -- res = ensure_computer_name (res, enroll); -- res = ensure_computer_sam (res, enroll); -- res = ensure_user_principal (res, enroll); -- res = ensure_computer_password (res, enroll); -- if (!(flags & ADCLI_ENROLL_NO_KEYTAB)) -+ if (enroll->is_service) { -+ /* Ensure basic params for service accounts */ -+ res = ensure_computer_sam (res, enroll); -+ res = ensure_computer_password (res, enroll); - res = ensure_host_keytab (res, enroll); -- res = ensure_service_names (res, enroll); -- res = ensure_service_principals (res, enroll); -- res = ensure_keytab_principals (res, enroll); -+ res = ensure_keytab_principals (res, enroll); -+ } else { -+ /* Basic discovery and figuring out enroll params */ -+ res = ensure_host_fqdn (res, enroll); -+ res = ensure_computer_name (res, enroll); -+ res = ensure_computer_sam (res, enroll); -+ res = ensure_user_principal (res, enroll); -+ res = ensure_computer_password (res, enroll); -+ if (!(flags & ADCLI_ENROLL_NO_KEYTAB)) -+ res = ensure_host_keytab (res, enroll); -+ res = ensure_service_names (res, enroll); -+ res = ensure_service_principals (res, enroll); -+ res = ensure_keytab_principals (res, enroll); -+ } - - return res; - } -@@ -2157,6 +2207,58 @@ enroll_join_or_update_tasks (adcli_enroll *enroll, - return update_keytab_for_principals (enroll, flags); - } - -+static adcli_result -+adcli_enroll_add_description_for_service_account (adcli_enroll *enroll) -+{ -+ const char *fqdn; -+ char *desc; -+ -+ fqdn = adcli_conn_get_host_fqdn (enroll->conn); -+ return_unexpected_if_fail (fqdn != NULL); -+ if (asprintf (&desc, "Please do not edit, Service account for %s, " -+ "managed by adcli.", fqdn) < 0) { -+ return_unexpected_if_reached (); -+ } -+ -+ adcli_enroll_set_description (enroll, desc); -+ free (desc); -+ -+ return ADCLI_SUCCESS; -+} -+ -+static adcli_result -+adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll) -+{ -+ krb5_context k5; -+ krb5_error_code code; -+ char def_keytab_name[MAX_KEYTAB_NAME_LEN]; -+ char *lc_dom_name; -+ int ret; -+ -+ if (adcli_enroll_get_keytab_name (enroll) == NULL) { -+ k5 = adcli_conn_get_krb5_context (enroll->conn); -+ return_unexpected_if_fail (k5 != NULL); -+ -+ code = krb5_kt_default_name (k5, def_keytab_name, -+ sizeof (def_keytab_name)); -+ return_unexpected_if_fail (code == 0); -+ -+ lc_dom_name = strdup (adcli_conn_get_domain_name (enroll->conn)); -+ return_unexpected_if_fail (lc_dom_name != NULL); -+ _adcli_str_down (lc_dom_name); -+ -+ -+ ret = asprintf (&enroll->keytab_name, "%s.%s", def_keytab_name, -+ lc_dom_name); -+ free (lc_dom_name); -+ return_unexpected_if_fail (ret > 0); -+ } -+ -+ _adcli_info ("Using service account keytab: %s", enroll->keytab_name); -+ -+ return ADCLI_SUCCESS; -+} -+ - adcli_result - adcli_enroll_join (adcli_enroll *enroll, - adcli_enroll_flags flags) -@@ -2172,7 +2274,14 @@ adcli_enroll_join (adcli_enroll *enroll, - if (res != ADCLI_SUCCESS) - return res; - -- res = ensure_default_service_names (enroll); -+ if (enroll->is_service) { -+ res = adcli_enroll_add_description_for_service_account (enroll); -+ if (res == ADCLI_SUCCESS) { -+ res = adcli_enroll_add_keytab_for_service_account (enroll); -+ } -+ } else { -+ res = ensure_default_service_names (enroll); -+ } - if (res != ADCLI_SUCCESS) - return res; - -@@ -2281,6 +2390,11 @@ adcli_enroll_update (adcli_enroll *enroll, - } - free (value); - -+ /* We only support password changes for service accounts */ -+ if (enroll->is_service && (flags & ADCLI_ENROLL_PASSWORD_VALID)) { -+ return ADCLI_SUCCESS; -+ } -+ - return enroll_join_or_update_tasks (enroll, flags); - } - -diff --git a/tools/computer.c b/tools/computer.c -index 5a97d8b..63fd374 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -1074,3 +1074,128 @@ adcli_tool_computer_show (adcli_conn *conn, - adcli_enroll_unref (enroll); - return 0; - } -+ -+int -+adcli_tool_computer_managed_service_account (adcli_conn *conn, -+ int argc, -+ char *argv[]) -+{ -+ adcli_enroll *enroll; -+ adcli_result res; -+ int show_password = 0; -+ int details = 0; -+ int opt; -+ -+ struct option options[] = { -+ { "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 }, -+ { "host-fqdn", required_argument, 0, opt_host_fqdn }, -+ { "computer-name", required_argument, 0, opt_computer_name }, -+ { "host-keytab", required_argument, 0, opt_host_keytab }, -+ { "no-password", no_argument, 0, opt_no_password }, -+ { "stdin-password", no_argument, 0, opt_stdin_password }, -+ { "prompt-password", no_argument, 0, opt_prompt_password }, -+ { "domain-ou", required_argument, NULL, opt_domain_ou }, -+ { "show-details", no_argument, NULL, opt_show_details }, -+ { "show-password", no_argument, NULL, opt_show_password }, -+ { "verbose", no_argument, NULL, opt_verbose }, -+ { "help", no_argument, NULL, 'h' }, -+ { 0 }, -+ }; -+ -+ static adcli_tool_desc usages[] = { -+ { 0, "usage: adcli create-msa --domain=xxxx" }, -+ { 0 }, -+ }; -+ -+ enroll = adcli_enroll_new (conn); -+ if (enroll == NULL) { -+ warnx ("unexpected memory problems"); -+ return -1; -+ } -+ -+ while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { -+ switch (opt) { -+ case opt_one_time_password: -+ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT); -+ adcli_conn_set_computer_password (conn, optarg); -+ break; -+ case opt_show_details: -+ details = 1; -+ break; -+ case opt_show_password: -+ show_password = 1; -+ break; -+ case 'h': -+ case '?': -+ case ':': -+ adcli_tool_usage (options, usages); -+ adcli_tool_usage (options, common_usages); -+ adcli_enroll_unref (enroll); -+ return opt == 'h' ? 0 : 2; -+ default: -+ res = parse_option ((Option)opt, optarg, conn, enroll); -+ if (res != ADCLI_SUCCESS) { -+ adcli_enroll_unref (enroll); -+ return res; -+ } -+ break; -+ } -+ } -+ -+ argc -= optind; -+ argv += optind; -+ -+ if (argc == 1) -+ adcli_conn_set_domain_name (conn, argv[0]); -+ else if (argc > 1) { -+ warnx ("extra arguments specified"); -+ adcli_enroll_unref (enroll); -+ return 2; -+ } -+ -+ if (adcli_conn_get_domain_name (conn) == NULL) { -+ warnx ("domain name is required"); -+ adcli_enroll_unref (enroll); -+ return 2; -+ } -+ -+ adcli_enroll_set_is_service (enroll, true); -+ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); -+ -+ res = adcli_enroll_load (enroll); -+ if (res != ADCLI_SUCCESS) { -+ /* ignored */ -+ } -+ -+ res = adcli_conn_connect (conn); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("couldn't connect to %s domain: %s", -+ adcli_conn_get_domain_name (conn), -+ adcli_get_last_error ()); -+ adcli_enroll_unref (enroll); -+ return -res; -+ } -+ -+ res = adcli_enroll_join (enroll, 0); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("Adding service account for %s failed: %s", -+ adcli_conn_get_domain_name (conn), -+ adcli_get_last_error ()); -+ adcli_enroll_unref (enroll); -+ return -res; -+ } -+ -+ if (details) -+ dump_details (conn, enroll, show_password); -+ else if (show_password) -+ dump_password (conn, enroll); -+ -+ adcli_enroll_unref (enroll); -+ -+ return 0; -+} -diff --git a/tools/tools.c b/tools/tools.c -index 1b6d879..d0dcf98 100644 ---- a/tools/tools.c -+++ b/tools/tools.c -@@ -60,6 +60,7 @@ struct { - { "reset-computer", adcli_tool_computer_reset, "Reset a computer account", }, - { "delete-computer", adcli_tool_computer_delete, "Delete a computer account", }, - { "show-computer", adcli_tool_computer_show, "Show computer account attributes stored in AD", }, -+ { "create-msa", adcli_tool_computer_managed_service_account, "Create a managed service account in the given AD domain", }, - { "create-user", adcli_tool_user_create, "Create a user account", }, - { "delete-user", adcli_tool_user_delete, "Delete a user account", }, - { "create-group", adcli_tool_group_create, "Create a group", }, -diff --git a/tools/tools.h b/tools/tools.h -index 3702875..82d5e4e 100644 ---- a/tools/tools.h -+++ b/tools/tools.h -@@ -82,6 +82,10 @@ int adcli_tool_computer_show (adcli_conn *conn, - int argc, - char *argv[]); - -+int adcli_tool_computer_managed_service_account (adcli_conn *conn, -+ int argc, -+ char *argv[]); -+ - int adcli_tool_user_create (adcli_conn *conn, - int argc, - char *argv[]); --- -2.28.0 - diff --git a/0006-discovery-fix.patch b/0006-discovery-fix.patch deleted file mode 100644 index 04568ce..0000000 --- a/0006-discovery-fix.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 08bac0946de29f3e5de90743ce6dfc7118d4ad20 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 11 Feb 2020 17:42:03 +0100 -Subject: [PATCH 6/6] 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.25.1 - diff --git a/0006-enroll-use-computer-or-service-in-debug-messages.patch b/0006-enroll-use-computer-or-service-in-debug-messages.patch deleted file mode 100644 index 3b41636..0000000 --- a/0006-enroll-use-computer-or-service-in-debug-messages.patch +++ /dev/null @@ -1,358 +0,0 @@ -From eea6a8071b5e5df74808903bb15b30acf820ce3f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 23 Oct 2020 16:55:11 +0200 -Subject: [PATCH 06/10] enroll: use 'computer' or 'service' in debug messages - -Use proper account type in debug messages. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - library/adenroll.c | 115 ++++++++++++++++++++++++++++----------------- - 1 file changed, 72 insertions(+), 43 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index dbfda36..9cdc79b 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -155,6 +155,12 @@ struct _adcli_enroll { - char *description; - }; - -+static const char * -+s_or_c (adcli_enroll *enroll) -+{ -+ return enroll->is_service ? "service" : "computer"; -+} -+ - static void - check_if_service (adcli_enroll *enroll, - LDAP *ldap, -@@ -203,13 +209,15 @@ ensure_computer_name (adcli_result res, - return res; - - if (enroll->computer_name) { -- _adcli_info ("Enrolling computer name: %s", -+ _adcli_info ("Enrolling %s name: %s", -+ s_or_c (enroll), - enroll->computer_name); - return ADCLI_SUCCESS; - } - - if (!enroll->host_fqdn) { -- _adcli_err ("No host name from which to determine the computer name"); -+ _adcli_err ("No host name from which to determine the %s name", -+ s_or_c (enroll)); - return ADCLI_ERR_CONFIG; - } - -@@ -603,7 +611,8 @@ lookup_computer_container (adcli_enroll *enroll, - - } else if (ret != LDAP_SUCCESS) { - return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY, -- "Couldn't lookup computer container: %s", base); -+ "Couldn't lookup %s container: %s", -+ s_or_c (enroll), base); - } - - values = _adcli_ldap_parse_values (ldap, results, attrs[0]); -@@ -614,8 +623,8 @@ lookup_computer_container (adcli_enroll *enroll, - if (strncmp (values[i], prefix, prefix_len) == 0) { - enroll->computer_container = strdup (values[i] + prefix_len); - return_unexpected_if_fail (enroll->computer_container != NULL); -- _adcli_info ("Found well known computer container at: %s", -- enroll->computer_container); -+ _adcli_info ("Found well known %s container at: %s", -+ s_or_c (enroll), enroll->computer_container); - break; - } - } -@@ -629,8 +638,9 @@ lookup_computer_container (adcli_enroll *enroll, - if (ret == LDAP_SUCCESS) { - enroll->computer_container = _adcli_ldap_parse_dn (ldap, results); - if (enroll->computer_container) { -- _adcli_info ("Well known computer container not " -+ _adcli_info ("Well known %s container not " - "found, but found suitable one at: %s", -+ s_or_c (enroll), - enroll->computer_container); - } - } -@@ -646,7 +656,8 @@ lookup_computer_container (adcli_enroll *enroll, - } - - if (!enroll->computer_container) { -- _adcli_err ("Couldn't find location to create computer accounts"); -+ _adcli_err ("Couldn't find location to create %s accounts", -+ s_or_c (enroll)); - return ADCLI_ERR_DIRECTORY; - } - -@@ -674,7 +685,8 @@ calculate_computer_account (adcli_enroll *enroll, - if (asprintf (&enroll->computer_dn, "CN=%s,%s", enroll->computer_name, enroll->computer_container) < 0) - return_unexpected_if_reached (); - -- _adcli_info ("Calculated computer account: %s", enroll->computer_dn); -+ _adcli_info ("Calculated %s account: %s", -+ s_or_c (enroll), enroll->computer_dn); - return ADCLI_SUCCESS; - } - -@@ -861,7 +873,8 @@ create_computer_account (adcli_enroll *enroll, - enroll->computer_dn); - } - -- _adcli_info ("Created computer account: %s", enroll->computer_dn); -+ _adcli_info ("Created %s account: %s", s_or_c (enroll), -+ enroll->computer_dn); - return ADCLI_SUCCESS; - } - -@@ -908,17 +921,17 @@ validate_computer_account (adcli_enroll *enroll, - assert (enroll->computer_dn != NULL); - - if (already_exists && !allow_overwrite) { -- _adcli_err ("The computer account %s already exists", -- enroll->computer_name); -+ _adcli_err ("The %s account %s already exists", -+ s_or_c (enroll), enroll->computer_name); - return ADCLI_ERR_CONFIG; - } - - /* Do we have an explicitly requested ou? */ - if (enroll->domain_ou && enroll->domain_ou_explicit && already_exists) { - if (!_adcli_ldap_dn_has_ancestor (enroll->computer_dn, enroll->domain_ou)) { -- _adcli_err ("The computer account %s already exists, " -+ _adcli_err ("The %s account %s already exists, " - "but is not in the desired organizational unit.", -- enroll->computer_name); -+ s_or_c (enroll), enroll->computer_name); - return ADCLI_ERR_CONFIG; - } - } -@@ -943,7 +956,8 @@ delete_computer_account (adcli_enroll *enroll, - "Couldn't delete computer account: %s", - enroll->computer_dn); - } else { -- _adcli_info ("Deleted computer account at: %s", enroll->computer_dn); -+ _adcli_info ("Deleted %s account at: %s", s_or_c (enroll), -+ enroll->computer_dn); - } - - return ADCLI_SUCCESS; -@@ -992,20 +1006,21 @@ locate_computer_account (adcli_enroll *enroll, - free (enroll->computer_dn); - enroll->computer_dn = strdup (dn); - return_unexpected_if_fail (enroll->computer_dn != NULL); -- _adcli_info ("Found computer account for %s at: %s", -- enroll->computer_sam, dn); -+ _adcli_info ("Found %s account for %s at: %s", -+ s_or_c (enroll), enroll->computer_sam, dn); - ldap_memfree (dn); - - } else { - ldap_msgfree (results); - results = NULL; -- _adcli_info ("Computer account for %s does not exist", -- enroll->computer_sam); -+ _adcli_info ("A %s account for %s does not exist", -+ s_or_c (enroll), enroll->computer_sam); - } - - } else { - return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY, -- "Couldn't lookup computer account: %s", -+ "Couldn't lookup %s account: %s", -+ s_or_c (enroll), - enroll->computer_sam); - } - -@@ -1039,7 +1054,9 @@ load_computer_account (adcli_enroll *enroll, - if (ret == LDAP_SUCCESS) { - entry = ldap_first_entry (ldap, results); - if (entry) { -- _adcli_info ("Found computer account for %s at: %s", -+ check_if_service (enroll, ldap, results); -+ _adcli_info ("Found %s account for %s at: %s", -+ s_or_c (enroll), - enroll->computer_sam, enroll->computer_dn); - } - -@@ -1146,7 +1163,8 @@ set_password_with_user_creds (adcli_enroll *enroll) - &result_code_string, &result_string); - - if (code != 0) { -- _adcli_err ("Couldn't set password for computer account: %s: %s", -+ _adcli_err ("Couldn't set password for %s account: %s: %s", -+ s_or_c (enroll), - enroll->computer_sam, krb5_get_error_message (k5, code)); - /* TODO: Parse out these values */ - res = ADCLI_ERR_DIRECTORY; -@@ -1160,7 +1178,8 @@ set_password_with_user_creds (adcli_enroll *enroll) - if (result_string.length) - message = _adcli_str_dupn (result_string.data, result_string.length); - #endif -- _adcli_err ("Cannot set computer password: %.*s%s%s", -+ _adcli_err ("Cannot set %s password: %.*s%s%s", -+ s_or_c (enroll), - (int)result_code_string.length, result_code_string.data, - message ? ": " : "", message ? message : ""); - res = ADCLI_ERR_CREDENTIALS; -@@ -1170,7 +1189,7 @@ set_password_with_user_creds (adcli_enroll *enroll) - free (message); - #endif - } else { -- _adcli_info ("Set computer password"); -+ _adcli_info ("Set %s password", s_or_c (enroll)); - if (enroll->kvno > 0) { - enroll->kvno++; - _adcli_info ("kvno incremented to %d", enroll->kvno); -@@ -1203,7 +1222,8 @@ set_password_with_computer_creds (adcli_enroll *enroll) - - code = _adcli_kinit_computer_creds (enroll->conn, "kadmin/changepw", NULL, &creds); - if (code != 0) { -- _adcli_err ("Couldn't get change password ticket for computer account: %s: %s", -+ _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)); - return ADCLI_ERR_DIRECTORY; - } -@@ -1214,7 +1234,8 @@ set_password_with_computer_creds (adcli_enroll *enroll) - krb5_free_cred_contents (k5, &creds); - - if (code != 0) { -- _adcli_err ("Couldn't change password for computer account: %s: %s", -+ _adcli_err ("Couldn't change password for %s account: %s: %s", -+ s_or_c (enroll), - enroll->computer_sam, krb5_get_error_message (k5, code)); - /* TODO: Parse out these values */ - res = ADCLI_ERR_DIRECTORY; -@@ -1284,7 +1305,8 @@ retrieve_computer_account (adcli_enroll *enroll) - - if (ret != LDAP_SUCCESS) { - return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY, -- "Couldn't retrieve computer account info: %s", -+ "Couldn't retrieve %s account info: %s", -+ s_or_c (enroll), - enroll->computer_dn); - } - -@@ -1294,15 +1316,15 @@ retrieve_computer_account (adcli_enroll *enroll) - if (value != NULL) { - kvno = strtoul (value, &end, 10); - if (end == NULL || *end != '\0') { -- _adcli_err ("Invalid kvno '%s' for computer account in directory: %s", -- value, enroll->computer_dn); -+ _adcli_err ("Invalid kvno '%s' for %s account in directory: %s", -+ value, s_or_c (enroll), enroll->computer_dn); - res = ADCLI_ERR_DIRECTORY; - - } else { - enroll->kvno = kvno; - -- _adcli_info ("Retrieved kvno '%s' for computer account in directory: %s", -- value, enroll->computer_dn); -+ _adcli_info ("Retrieved kvno '%s' for %s account in directory: %s", -+ value, s_or_c (enroll), enroll->computer_dn); - } - - free (value); -@@ -1311,8 +1333,8 @@ retrieve_computer_account (adcli_enroll *enroll) - /* Apparently old AD didn't have this attribute, use zero */ - enroll->kvno = 0; - -- _adcli_info ("No kvno found for computer account in directory: %s", -- enroll->computer_dn); -+ _adcli_info ("No kvno found for %s account in directory: %s", -+ s_or_c (enroll), enroll->computer_dn); - } - } - -@@ -1353,12 +1375,14 @@ update_and_calculate_enctypes (adcli_enroll *enroll) - - if (ret == LDAP_INSUFFICIENT_ACCESS) { - return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS, -- "Insufficient permissions to set encryption types on computer account: %s", -+ "Insufficient permissions to set encryption types on %s account: %s", -+ s_or_c (enroll), - enroll->computer_dn); - - } else if (ret != LDAP_SUCCESS) { - return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY, -- "Couldn't set encryption types on computer account: %s", -+ "Couldn't set encryption types on %s account: %s", -+ s_or_c (enroll), - enroll->computer_dn); - } - -@@ -1381,13 +1405,14 @@ update_computer_attribute (adcli_enroll *enroll, - string = _adcli_ldap_mods_to_string (mods); - return_unexpected_if_fail (string != NULL); - -- _adcli_info ("Modifying computer account: %s", string); -+ _adcli_info ("Modifying %s account: %s", s_or_c (enroll), string); - - ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL); - - if (ret != LDAP_SUCCESS) { -- _adcli_warn ("Couldn't set %s on computer account: %s: %s", -- string, enroll->computer_dn, ldap_err2string (ret)); -+ _adcli_warn ("Couldn't set %s on %s account: %s: %s", -+ string, s_or_c (enroll), enroll->computer_dn, -+ ldap_err2string (ret)); - res = ADCLI_ERR_DIRECTORY; - } - -@@ -1411,8 +1436,8 @@ static char *get_user_account_control (adcli_enroll *enroll) - - attr_val = strtoul (uac_str, &end, 10); - if (*end != '\0' || attr_val > UINT32_MAX) { -- _adcli_warn ("Invalid userAccountControl '%s' for computer account in directory: %s, assuming 0", -- uac_str, enroll->computer_dn); -+ _adcli_warn ("Invalid userAccountControl '%s' for %s account in directory: %s, assuming 0", -+ uac_str, s_or_c (enroll), enroll->computer_dn); - } else { - uac = attr_val; - } -@@ -1653,7 +1678,8 @@ load_keytab_entry (krb5_context k5, - _adcli_str_has_suffix (name, "$") && !strchr (name, '/')) { - enroll->computer_name = name; - name[len - 1] = '\0'; -- _adcli_info ("Found computer name in keytab: %s", name); -+ _adcli_info ("Found %s name in keytab: %s", -+ s_or_c (enroll), name); - adcli_conn_set_computer_name (enroll->conn, - enroll->computer_name); - name = NULL; -@@ -2348,7 +2374,8 @@ adcli_enroll_read_computer_account (adcli_enroll *enroll, - if (res != ADCLI_SUCCESS) - return res; - if (!enroll->computer_dn) { -- _adcli_err ("No computer account for %s exists", enroll->computer_sam); -+ _adcli_err ("No %s account for %s exists", -+ s_or_c (enroll), enroll->computer_sam); - return ADCLI_ERR_CONFIG; - } - } -@@ -2460,7 +2487,8 @@ adcli_enroll_delete (adcli_enroll *enroll, - if (res != ADCLI_SUCCESS) - return res; - if (!enroll->computer_dn) { -- _adcli_err ("No computer account for %s exists", -+ _adcli_err ("No %s account for %s exists", -+ s_or_c (enroll), - enroll->computer_sam); - return ADCLI_ERR_CONFIG; - } -@@ -2503,7 +2531,8 @@ adcli_enroll_password (adcli_enroll *enroll, - if (res != ADCLI_SUCCESS) - return res; - if (!enroll->computer_dn) { -- _adcli_err ("No computer account for %s exists", -+ _adcli_err ("No %s account for %s exists", -+ s_or_c (enroll), - enroll->computer_sam); - return ADCLI_ERR_CONFIG; - } --- -2.28.0 - diff --git a/0007-enroll-more-filters-for-random-characters.patch b/0007-enroll-more-filters-for-random-characters.patch deleted file mode 100644 index b2ff629..0000000 --- a/0007-enroll-more-filters-for-random-characters.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 2750f536ac6746756335eec8332060d2365a4126 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 27 Oct 2020 14:44:07 +0100 -Subject: [PATCH 07/10] enroll: more filters for random characters - -Make handling of random strings more flexible. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - library/adenroll.c | 30 +++++++++++++++++++++++++++--- - 1 file changed, 27 insertions(+), 3 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 9cdc79b..44383cc 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -259,6 +259,29 @@ ensure_computer_sam (adcli_result res, - return ADCLI_SUCCESS; - } - -+typedef int (rand_filter) (char *password, int length); -+ -+static int -+filter_sam_chars (char *password, -+ int length) -+{ -+ int i, j; -+ -+ /* -+ * There are a couple of restrictions for characters in the -+ * sAMAccountName attribute value, for our purpose (random suffix) -+ * letters and numbers are sufficient. -+ */ -+ for (i = 0, j = 0; i < length; i++) { -+ if (password[i] >= 48 && password[i] <= 122 && -+ isalnum (password[i])) -+ password[j++] = password[i]; -+ } -+ -+ /* return the number of valid characters remaining */ -+ return j; -+} -+ - static int - filter_password_chars (char *password, - int length) -@@ -283,7 +306,8 @@ filter_password_chars (char *password, - - static char * - generate_host_password (adcli_enroll *enroll, -- size_t length) -+ size_t length, -+ rand_filter *filter) - { - char *password; - krb5_context k5; -@@ -305,7 +329,7 @@ generate_host_password (adcli_enroll *enroll, - code = krb5_c_random_make_octets (k5, &buffer); - return_val_if_fail (code == 0, NULL); - -- at += filter_password_chars (buffer.data, buffer.length); -+ at += filter (buffer.data, buffer.length); - assert (at <= length); - } - -@@ -333,7 +357,7 @@ ensure_computer_password (adcli_result res, - _adcli_info ("Using default reset computer password"); - - } else { -- enroll->computer_password = generate_host_password (enroll, length); -+ enroll->computer_password = generate_host_password (enroll, length, filter_password_chars); - return_unexpected_if_fail (enroll->computer_password != NULL); - _adcli_info ("Generated %d character computer password", length); - } --- -2.28.0 - diff --git a/0008-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch b/0008-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch deleted file mode 100644 index 9279f07..0000000 --- a/0008-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 81c98e367ba4bc8d77668acd31e462ad31cf12be Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 27 Oct 2020 14:47:31 +0100 -Subject: [PATCH 08/10] enroll: make - adcli_enroll_add_keytab_for_service_account public - -Determine keytab name more early to catch errors more early. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - library/adenroll.c | 13 +++++++------ - library/adenroll.h | 2 ++ - tools/computer.c | 6 ++++++ - 3 files changed, 15 insertions(+), 6 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 44383cc..05bb085 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -2276,9 +2276,10 @@ adcli_enroll_add_description_for_service_account (adcli_enroll *enroll) - return ADCLI_SUCCESS; - } - --static adcli_result -+adcli_result - adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll) - { -+ adcli_result res; - krb5_context k5; - krb5_error_code code; - char def_keytab_name[MAX_KEYTAB_NAME_LEN]; -@@ -2286,11 +2287,14 @@ adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll) - int ret; - - if (adcli_enroll_get_keytab_name (enroll) == NULL) { -- k5 = adcli_conn_get_krb5_context (enroll->conn); -- return_unexpected_if_fail (k5 != NULL); -+ res = _adcli_krb5_init_context (&k5); -+ if (res != ADCLI_SUCCESS) { -+ return res; -+ } - - code = krb5_kt_default_name (k5, def_keytab_name, - sizeof (def_keytab_name)); -+ krb5_free_context (k5); - return_unexpected_if_fail (code == 0); - - lc_dom_name = strdup (adcli_conn_get_domain_name (enroll->conn)); -@@ -2326,9 +2330,6 @@ adcli_enroll_join (adcli_enroll *enroll, - - if (enroll->is_service) { - res = adcli_enroll_add_description_for_service_account (enroll); -- if (res == ADCLI_SUCCESS) { -- res = adcli_enroll_add_keytab_for_service_account (enroll); -- } - } else { - res = ensure_default_service_names (enroll); - } -diff --git a/library/adenroll.h b/library/adenroll.h -index 7765ed4..11a30c8 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -146,6 +146,8 @@ const char * adcli_enroll_get_keytab_name (adcli_enroll *enroll); - void adcli_enroll_set_keytab_name (adcli_enroll *enroll, - const char *value); - -+adcli_result adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll); -+ - krb5_enctype * adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll); - - void adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, -diff --git a/tools/computer.c b/tools/computer.c -index 63fd374..98a0472 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -1166,6 +1166,12 @@ adcli_tool_computer_managed_service_account (adcli_conn *conn, - - adcli_enroll_set_is_service (enroll, true); - adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); -+ res = adcli_enroll_add_keytab_for_service_account (enroll); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("Failed to set domain specific keytab name"); -+ adcli_enroll_unref (enroll); -+ return 2; -+ } - - res = adcli_enroll_load (enroll); - if (res != ADCLI_SUCCESS) { --- -2.28.0 - diff --git a/0009-enroll-allow-fqdn-for-locate_computer_account.patch b/0009-enroll-allow-fqdn-for-locate_computer_account.patch deleted file mode 100644 index a35e050..0000000 --- a/0009-enroll-allow-fqdn-for-locate_computer_account.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 2a695dfe09cafeee3a648d3b969c364f8d3f494f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 27 Oct 2020 14:49:55 +0100 -Subject: [PATCH 09/10] enroll: allow fqdn for locate_computer_account - -Make it possible to find existing manages service account by the -fully-qualified name. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - library/adenroll.c | 45 +++++++++++++++++++++++++++++++-------------- - 1 file changed, 31 insertions(+), 14 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 05bb085..98cd5fa 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -990,10 +990,11 @@ delete_computer_account (adcli_enroll *enroll, - static adcli_result - locate_computer_account (adcli_enroll *enroll, - LDAP *ldap, -+ bool use_fqdn, - LDAPMessage **rresults, - LDAPMessage **rentry) - { -- char *attrs[] = { "objectClass", NULL }; -+ char *attrs[] = { "objectClass", "CN", NULL }; - LDAPMessage *results = NULL; - LDAPMessage *entry = NULL; - const char *base; -@@ -1003,12 +1004,22 @@ locate_computer_account (adcli_enroll *enroll, - int ret = 0; - - /* If we don't yet know our computer dn, then try and find it */ -- value = _adcli_ldap_escape_filter (enroll->computer_sam); -- return_unexpected_if_fail (value != NULL); -- if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))", -- enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", -- value) < 0) -- return_unexpected_if_reached (); -+ if (use_fqdn) { -+ return_unexpected_if_fail (enroll->host_fqdn != NULL); -+ value = _adcli_ldap_escape_filter (enroll->host_fqdn); -+ return_unexpected_if_fail (value != NULL); -+ if (asprintf (&filter, "(&(objectClass=%s)(dNSHostName=%s))", -+ enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", -+ value) < 0) -+ return_unexpected_if_reached (); -+ } else { -+ value = _adcli_ldap_escape_filter (enroll->computer_sam); -+ return_unexpected_if_fail (value != NULL); -+ if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))", -+ enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", -+ value) < 0) -+ return_unexpected_if_reached (); -+ } - free (value); - - base = adcli_conn_get_default_naming_context (enroll->conn); -@@ -1031,21 +1042,26 @@ locate_computer_account (adcli_enroll *enroll, - enroll->computer_dn = strdup (dn); - return_unexpected_if_fail (enroll->computer_dn != NULL); - _adcli_info ("Found %s account for %s at: %s", -- s_or_c (enroll), enroll->computer_sam, dn); -+ s_or_c (enroll), -+ use_fqdn ? enroll->host_fqdn -+ : enroll->computer_sam, dn); - ldap_memfree (dn); - - } else { - ldap_msgfree (results); - results = NULL; - _adcli_info ("A %s account for %s does not exist", -- s_or_c (enroll), enroll->computer_sam); -+ s_or_c (enroll), -+ use_fqdn ? enroll->host_fqdn -+ : enroll->computer_sam); - } - - } else { - return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY, - "Couldn't lookup %s account: %s", - s_or_c (enroll), -- enroll->computer_sam); -+ use_fqdn ? enroll->host_fqdn -+ :enroll->computer_sam); - } - - if (rresults) -@@ -1120,7 +1136,8 @@ locate_or_create_computer_account (adcli_enroll *enroll, - - /* Try to find the computer account */ - if (!enroll->computer_dn) { -- res = locate_computer_account (enroll, ldap, &results, &entry); -+ res = locate_computer_account (enroll, ldap, false, -+ &results, &entry); - if (res != ADCLI_SUCCESS) - return res; - searched = 1; -@@ -2395,7 +2412,7 @@ adcli_enroll_read_computer_account (adcli_enroll *enroll, - - /* Find the computer dn */ - if (!enroll->computer_dn) { -- res = locate_computer_account (enroll, ldap, NULL, NULL); -+ res = locate_computer_account (enroll, ldap, false, NULL, NULL); - if (res != ADCLI_SUCCESS) - return res; - if (!enroll->computer_dn) { -@@ -2508,7 +2525,7 @@ adcli_enroll_delete (adcli_enroll *enroll, - - /* Find the computer dn */ - if (!enroll->computer_dn) { -- res = locate_computer_account (enroll, ldap, NULL, NULL); -+ res = locate_computer_account (enroll, ldap, false, NULL, NULL); - if (res != ADCLI_SUCCESS) - return res; - if (!enroll->computer_dn) { -@@ -2552,7 +2569,7 @@ adcli_enroll_password (adcli_enroll *enroll, - - /* Find the computer dn */ - if (!enroll->computer_dn) { -- res = locate_computer_account (enroll, ldap, NULL, NULL); -+ res = locate_computer_account (enroll, ldap, false, NULL, NULL); - if (res != ADCLI_SUCCESS) - return res; - if (!enroll->computer_dn) { --- -2.28.0 - diff --git a/0010-service-account-add-random-suffix-to-account-name.patch b/0010-service-account-add-random-suffix-to-account-name.patch deleted file mode 100644 index 74a93fb..0000000 --- a/0010-service-account-add-random-suffix-to-account-name.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 6b94f9712378b8f1fa1bc530c64cb987abb0c43b Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 27 Oct 2020 15:23:04 +0100 -Subject: [PATCH 10/10] service-account: add random suffix to account name - -Add a random component to the default managed service account name to -avoid name collisions. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112 ---- - library/adenroll.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 79 insertions(+) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 98cd5fa..f693e58 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -1121,6 +1121,59 @@ load_computer_account (adcli_enroll *enroll, - return ADCLI_SUCCESS; - } - -+static adcli_result -+refresh_service_account_name_sam_and_princ (adcli_enroll *enroll, -+ const char *name) -+{ -+ adcli_result res; -+ -+ adcli_enroll_set_computer_name (enroll, name); -+ res = ensure_computer_sam (ADCLI_SUCCESS, enroll); -+ res = ensure_keytab_principals (res, enroll); -+ -+ return res; -+} -+ -+static adcli_result -+calculate_random_service_account_name (adcli_enroll *enroll) -+{ -+ char *suffix; -+ char *new_name; -+ int ret; -+ adcli_result res; -+ -+ suffix = generate_host_password (enroll, 3, filter_sam_chars); -+ return_unexpected_if_fail (suffix != NULL); -+ -+ ret = asprintf (&new_name, "%s!%s", enroll->computer_name, suffix); -+ free (suffix); -+ return_unexpected_if_fail (ret > 0); -+ -+ res = refresh_service_account_name_sam_and_princ (enroll, new_name); -+ free (new_name); -+ -+ return res; -+} -+ -+static adcli_result -+get_service_account_name_from_ldap (adcli_enroll *enroll, LDAPMessage *results) -+{ -+ LDAP *ldap; -+ char *cn; -+ adcli_result res; -+ -+ ldap = adcli_conn_get_ldap_connection (enroll->conn); -+ assert (ldap != NULL); -+ -+ cn = _adcli_ldap_parse_value (ldap, results, "CN"); -+ return_unexpected_if_fail (cn != NULL); -+ -+ res = refresh_service_account_name_sam_and_princ (enroll, cn); -+ free (cn); -+ -+ return res; -+} -+ - static adcli_result - locate_or_create_computer_account (adcli_enroll *enroll, - int allow_overwrite) -@@ -1143,8 +1196,32 @@ locate_or_create_computer_account (adcli_enroll *enroll, - searched = 1; - } - -+ /* Try with fqdn for service accounts */ -+ if (!enroll->computer_dn && enroll->is_service -+ && enroll->host_fqdn != NULL) { -+ res = locate_computer_account (enroll, ldap, true, -+ &results, &entry); -+ if (res != ADCLI_SUCCESS) -+ return res; -+ searched = 1; -+ -+ if (results != NULL) { -+ res = get_service_account_name_from_ldap (enroll, -+ results); -+ if (res != ADCLI_SUCCESS) { -+ return res; -+ } -+ } -+ } -+ - /* Next try and come up with where we think it should be */ - if (enroll->computer_dn == NULL) { -+ if (enroll->is_service && !enroll->computer_name_explicit) { -+ res = calculate_random_service_account_name (enroll); -+ if (res != ADCLI_SUCCESS) { -+ return res; -+ } -+ } - res = calculate_computer_account (enroll, ldap); - if (res != ADCLI_SUCCESS) - return res; -@@ -2113,6 +2190,8 @@ adcli_enroll_prepare (adcli_enroll *enroll, - - if (enroll->is_service) { - /* Ensure basic params for service accounts */ -+ res = ensure_host_fqdn (res, enroll); -+ res = ensure_computer_name (res, enroll); - res = ensure_computer_sam (res, enroll); - res = ensure_computer_password (res, enroll); - res = ensure_host_keytab (res, enroll); --- -2.28.0 - diff --git a/adcli.spec b/adcli.spec index 507efba..b4ce2f9 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,49 +1,26 @@ -Name: adcli -Version: 0.9.0 -Release: 7%{?dist} -Summary: Active Directory enrollment -License: LGPLv2+ -URL: http://cgit.freedesktop.org/realmd/adcli -Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/02d8757266c24fdc10822306582287bf/adcli-%{version}.tar.gz +Name: adcli +Version: 0.9.1 +Release: 1%{?dist} +Summary: Active Directory enrollment +License: LGPLv2+ +URL: https://gitlab.freedesktop.org/realmd/adcli +Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee789194435e70fbf30/adcli-%{version}.tar.gz -Patch1: 0001-man-move-note-to-the-right-section.patch -Patch2: 0002-tools-add-show-computer-command.patch -Patch3: 0003-add-description-option-to-join-and-update.patch -Patch4: 0004-Use-GSS-SPNEGO-if-available.patch -Patch5: 0005-add-option-use-ldaps.patch -Patch6: 0006-discovery-fix.patch -Patch7: 0001-delete-do-not-exit-if-keytab-cannot-be-read.patch -Patch8: 0001-tools-disable-SSSD-s-locator-plugin.patch -Patch9: 0001-tools-fix-typo-in-show-password-help-output.patch -Patch10: 0002-man-explain-optional-parameter-of-login-ccache-bette.patch -Patch11: 0003-man-make-handling-of-optional-credential-cache-more-.patch - -Patch12: 0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch -Patch13: 0002-join-update-set-dNSHostName-if-not-set.patch -Patch14: 0003-doc-explain-required-AD-permissions.patch -Patch15: 0004-enroll-add-is_service-member.patch -Patch16: 0005-computer-add-create-msa-sub-command.patch -Patch17: 0006-enroll-use-computer-or-service-in-debug-messages.patch -Patch18: 0007-enroll-more-filters-for-random-characters.patch -Patch19: 0008-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch -Patch20: 0009-enroll-allow-fqdn-for-locate_computer_account.patch -Patch21: 0010-service-account-add-random-suffix-to-account-name.patch - -BuildRequires: gcc -BuildRequires: intltool pkgconfig -BuildRequires: libtool -BuildRequires: gettext-devel -BuildRequires: krb5-devel -BuildRequires: openldap-devel -BuildRequires: libxslt -BuildRequires: xmlto +BuildRequires: gcc +BuildRequires: intltool pkgconfig +BuildRequires: libtool +BuildRequires: gettext-devel +BuildRequires: krb5-devel +BuildRequires: openldap-devel +BuildRequires: libxslt +BuildRequires: xmlto BuildRequires: make -Requires: cyrus-sasl-gssapi +Requires: cyrus-sasl-gssapi # adcli no longer has a library of development files # the adcli tool itself is to be used by callers -Obsoletes: adcli-devel < 0.5 +Obsoletes: adcli-devel < 0.5 %description adcli is a tool for joining an Active Directory domain using @@ -86,6 +63,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Sat Feb 20 2021 Sumit Bose - 0.9.1-1 +- Update to upstream release 0.9.1 + * Mon Jan 25 2021 Fedora Release Engineering - 0.9.0-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild diff --git a/sources b/sources index 4e3b7c0..d958e5d 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (adcli-0.9.0.tar.gz) = e9b210bf7a932750fc838d6f027ca1fbeca1bd6a0028b551c9a72c0fe3ee680d47031c614b74447613d06bd41462c489e8572d49e60b344d575ebb572c022344 +SHA512 (adcli-0.9.1.tar.gz) = 60562720bf28f2dec06f272bdb875e3486f223e77f8a9e96b3468d17dbebdf9ddabd147d7e65c5de9ba7d4e8c033ad6d28a4012d03297c7de25b78ef4890746d From 47faff9b58787947cf406bc828bb62bdd46807ec Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Sat, 20 Feb 2021 17:51:03 +0100 Subject: [PATCH 02/27] Add Conflicts to avoid update/downgrade issues --- adcli.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index b4ce2f9..24ecce3 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -17,6 +17,7 @@ BuildRequires: xmlto BuildRequires: make Requires: cyrus-sasl-gssapi +Conflicts: adcli-doc < %{version}-%{release} # adcli no longer has a library of development files # the adcli tool itself is to be used by callers @@ -53,6 +54,7 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %package doc Summary: adcli documentation BuildArch: noarch +Conflicts: adcli < %{version}-%{release} %description doc adcli is a tool for joining an Active Directory domain using @@ -63,6 +65,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Sat Feb 20 2021 Sumit Bose - 0.9.1-2 +- Add Conflicts to avoid update/downgrade issues + * Sat Feb 20 2021 Sumit Bose - 0.9.1-1 - Update to upstream release 0.9.1 From 54a1f3a35f8fc57492d5a9e9f9787ae7180fc09b Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 29 Mar 2021 14:22:21 +0200 Subject: [PATCH 03/27] Add vendor error message Resolves: rhbz#1889386 --- ...endor-error-message-configure-option.patch | 60 +++++++++++++++++++ adcli.spec | 14 ++++- 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 0001-build-add-with-vendor-error-message-configure-option.patch diff --git a/0001-build-add-with-vendor-error-message-configure-option.patch b/0001-build-add-with-vendor-error-message-configure-option.patch new file mode 100644 index 0000000..75235ee --- /dev/null +++ b/0001-build-add-with-vendor-error-message-configure-option.patch @@ -0,0 +1,60 @@ +From 0353d704879f20983184f8bded4f16538d72f7cc Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 10 Mar 2021 18:12:09 +0100 +Subject: [PATCH] build: add --with-vendor-error-message configure option + +With the new configure option --with-vendor-error-message a packager or +a distribution can add a message if adcli returns with an error. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1889386 +--- + configure.ac | 15 +++++++++++++++ + tools/tools.c | 6 ++++++ + 2 files changed, 21 insertions(+) + +diff --git a/configure.ac b/configure.ac +index baa0d3b..7dfba97 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -123,6 +123,21 @@ if test "$sasl_invalid" = "yes"; then + AC_MSG_ERROR([Couldn't find Cyrus SASL headers]) + fi + ++# -------------------------------------------------------------------- ++# Vendor error message ++ ++AC_ARG_WITH([vendor-error-message], ++ [AS_HELP_STRING([--with-vendor-error-message=ARG], ++ [Add a vendor specific error message shown if a adcli command fails] ++ )], ++ [AS_IF([test "x$withval" != "x"], ++ [AC_DEFINE_UNQUOTED([VENDOR_MSG], ++ ["$withval"], ++ [Vendor specific error message])], ++ [AC_MSG_ERROR([--with-vendor-error-message requires an argument])] ++ )], ++ []) ++ + # -------------------------------------------------------------------- + # Documentation options + +diff --git a/tools/tools.c b/tools/tools.c +index d0dcf98..84bbba9 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -538,6 +538,12 @@ main (int argc, + + if (conn) + adcli_conn_unref (conn); ++#ifdef VENDOR_MSG ++ if (ret != 0) { ++ fprintf (stderr, VENDOR_MSG"\n"); ++ } ++#endif ++ + return ret; + } + +-- +2.30.2 + diff --git a/adcli.spec b/adcli.spec index 24ecce3..febbfb8 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,11 +1,13 @@ Name: adcli Version: 0.9.1 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee789194435e70fbf30/adcli-%{version}.tar.gz +Patch1: 0001-build-add-with-vendor-error-message-configure-option.patch + BuildRequires: gcc BuildRequires: intltool pkgconfig BuildRequires: libtool @@ -34,7 +36,11 @@ standard LDAP and Kerberos calls. %build autoreconf --force --install --verbose -%configure --disable-static --disable-silent-rules +%configure --disable-static --disable-silent-rules \ +%if 0%{?rhel} + --with-vendor-error-message='Please check\n https://red.ht/support_rhel_ad \nto get help for common issues.' \ +%endif + %{nil} make %{?_smp_mflags} %check @@ -65,6 +71,10 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Mon Mar 29 2021 Sumit Bose - 0.9.1-3 +- Add vendor error message + Resolves: rhbz#1889386 + * Sat Feb 20 2021 Sumit Bose - 0.9.1-2 - Add Conflicts to avoid update/downgrade issues From c2d6ef0b1abefdbbcc6e7b9fd0afe76d6bce92de Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 7 Apr 2021 11:29:06 +0200 Subject: [PATCH 04/27] Add macro updates for autoconf-2.71 and downstream gating --- ...update-some-macros-for-autoconf-2.71.patch | 84 +++++++++++++++++++ adcli.spec | 6 +- gating.yaml | 6 ++ 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 0001-configure-update-some-macros-for-autoconf-2.71.patch create mode 100644 gating.yaml diff --git a/0001-configure-update-some-macros-for-autoconf-2.71.patch b/0001-configure-update-some-macros-for-autoconf-2.71.patch new file mode 100644 index 0000000..e9f0bc6 --- /dev/null +++ b/0001-configure-update-some-macros-for-autoconf-2.71.patch @@ -0,0 +1,84 @@ +From a8492d71a6db8565544444eef11de8c733c95ef8 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 6 Apr 2021 19:32:07 +0200 +Subject: [PATCH] configure: update some macros for autoconf-2.71 + +--- + configure.ac | 10 +++++----- + library/Makefile.am | 2 +- + tools/Makefile.am | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 7dfba97..c6ff31d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1,4 +1,4 @@ +-AC_PREREQ(2.61) ++AC_PREREQ([2.61]) + + AC_INIT([adcli], + [0.9.1], +@@ -33,7 +33,7 @@ LT_INIT([dlopen disable-static]) + AC_PROG_CC + AC_PROG_CPP + AM_PROG_CC_C_O +-AM_PROG_LIBTOOL ++LT_INIT + + # ------------------------------------------------------------------- + # Kerberos +@@ -143,7 +143,7 @@ AC_ARG_WITH([vendor-error-message], + + AC_MSG_CHECKING([whether to build documentation]) + AC_ARG_ENABLE(doc, +- AC_HELP_STRING([--enable-doc], ++ AS_HELP_STRING([--enable-doc], + [Disable building documentation]) + ) + +@@ -180,7 +180,7 @@ doc_status=$enable_doc + + AC_MSG_CHECKING([for debug mode]) + AC_ARG_ENABLE(debug, +- AC_HELP_STRING([--enable-debug=no/default/yes], ++ AS_HELP_STRING([--enable-debug=no/default/yes], + [Turn on or off debugging])) + + if test "$enable_debug" != "no"; then +@@ -308,7 +308,7 @@ fi + + AC_MSG_CHECKING([where is Samba's net utility]) + AC_ARG_WITH([samba_data_tool], +- AC_HELP_STRING([--with-samba-data-tool=/path], ++ AS_HELP_STRING([--with-samba-data-tool=/path], + [Path to Samba's net utility]), + [], + [with_samba_data_tool=/usr/bin/net]) +diff --git a/library/Makefile.am b/library/Makefile.am +index 4829555..e046606 100644 +--- a/library/Makefile.am ++++ b/library/Makefile.am +@@ -1,6 +1,6 @@ + include $(top_srcdir)/Makefile.decl + +-INCLUDES = \ ++AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -DADCLI_UNSTABLE_API \ + -DHOST_TRIPLET=\"$(host_triplet)\" \ +diff --git a/tools/Makefile.am b/tools/Makefile.am +index 1cdf451..71ec14d 100644 +--- a/tools/Makefile.am ++++ b/tools/Makefile.am +@@ -1,6 +1,6 @@ + include $(top_srcdir)/Makefile.decl + +-INCLUDES = \ ++AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/library \ + -DKRB5_CONFIG=\""$(sysconfdir)/krb5.conf"\" \ +-- +2.30.2 + diff --git a/adcli.spec b/adcli.spec index febbfb8..34419c2 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,12 +1,13 @@ Name: adcli Version: 0.9.1 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee789194435e70fbf30/adcli-%{version}.tar.gz Patch1: 0001-build-add-with-vendor-error-message-configure-option.patch +Patch2: 0001-configure-update-some-macros-for-autoconf-2.71.patch BuildRequires: gcc BuildRequires: intltool pkgconfig @@ -71,6 +72,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Apr 07 2021 Sumit Bose - 0.9.1-4 +- Add macro updates for autoconf-2.71 and downstream gating + * Mon Mar 29 2021 Sumit Bose - 0.9.1-3 - Add vendor error message Resolves: rhbz#1889386 diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..c190bde --- /dev/null +++ b/gating.yaml @@ -0,0 +1,6 @@ +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional} From a6fdb37cc332458db9bdfa31513e12ce6be814cd Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 2 Jun 2021 19:34:56 +0200 Subject: [PATCH 05/27] Add dont-expire-password option and coverity fixes --- 0001-coverity-add-missing-NULL-checks.patch | 44 ++++ 0002-Add-dont-expire-password-option.patch | 229 ++++++++++++++++++++ adcli.spec | 8 +- 3 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 0001-coverity-add-missing-NULL-checks.patch create mode 100644 0002-Add-dont-expire-password-option.patch diff --git a/0001-coverity-add-missing-NULL-checks.patch b/0001-coverity-add-missing-NULL-checks.patch new file mode 100644 index 0000000..cb6c77b --- /dev/null +++ b/0001-coverity-add-missing-NULL-checks.patch @@ -0,0 +1,44 @@ +From 3c652910d05616ee12c710e2071fc884dde4eaea Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 2 Jun 2021 13:39:31 +0200 +Subject: [PATCH 1/2] coverity: add missing NULL checks + +--- + library/adenroll.c | 2 ++ + library/adldap.c | 7 +++++++ + 2 files changed, 9 insertions(+) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 2b830a4..0f3e8b9 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -3060,6 +3060,8 @@ adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, + krb5_enctype *newval = NULL; + int len; + ++ return_if_fail (enroll != NULL); ++ + if (value) { + for (len = 0; value[len] != 0; len++); + newval = malloc (sizeof (krb5_enctype) * (len + 1)); +diff --git a/library/adldap.c b/library/adldap.c +index d93efb7..b86014c 100644 +--- a/library/adldap.c ++++ b/library/adldap.c +@@ -231,6 +231,13 @@ _adcli_ldap_have_in_mod (LDAPMod *mod, + + vals = malloc (sizeof (struct berval) * (count + 1)); + pvals = malloc (sizeof (struct berval *) * (count + 1)); ++ if (vals == NULL || pvals == NULL) { ++ _adcli_err ("Memory allocation failed, assuming attribute must be updated."); ++ free (vals); ++ free (pvals); ++ return 0; ++ } ++ + for (i = 0; i < count; i++) { + vals[i].bv_val = mod->mod_vals.modv_strvals[i]; + vals[i].bv_len = strlen (vals[i].bv_val); +-- +2.31.1 + diff --git a/0002-Add-dont-expire-password-option.patch b/0002-Add-dont-expire-password-option.patch new file mode 100644 index 0000000..5189f40 --- /dev/null +++ b/0002-Add-dont-expire-password-option.patch @@ -0,0 +1,229 @@ +From a78116ba0e608050f391223bad3834d48c9adf1b Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 2 Jun 2021 17:24:07 +0200 +Subject: [PATCH 2/2] Add dont-expire-password option + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1769644 +--- + doc/adcli.xml | 28 ++++++++++++++++++++++++++++ + library/adenroll.c | 44 +++++++++++++++++++++++++++++++++++++++++++- + library/adenroll.h | 4 ++++ + tools/computer.c | 12 ++++++++++++ + 4 files changed, 87 insertions(+), 1 deletion(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 8ec48d4..1ed5d3f 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -347,6 +347,20 @@ Password for Administrator: + not allow that Kerberos tickets can be forwarded to the + host. + ++ ++ ++ Set or unset the DONT_EXPIRE_PASSWORD ++ flag in the userAccountControl attribute to indicate if ++ the machine account password should expire or not. By ++ default adcli will set this flag while joining the ++ domain which corresponds to the default behavior of ++ Windows clients. ++ Please note that if the password will expire ++ (--dont-expire-password=false) a renewal mechanism has ++ to be enabled on the client to not loose the ++ connectivity to AD if the password expires. ++ ++ + + + Add a service principal name. In +@@ -491,6 +505,20 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + not allow that Kerberos tickets can be forwarded to the + host. + ++ ++ ++ Set or unset the DONT_EXPIRE_PASSWORD ++ flag in the userAccountControl attribute to indicate if ++ the machine account password should expire or not. By ++ default adcli will set this flag while joining the ++ domain which corresponds to the default behavior of ++ Windows clients. ++ Please note that if the password will expire ++ (--dont-expire-password=false) a renewal mechanism has ++ to be enabled on the client to not loose the ++ connectivity to AD if the password expires. ++ ++ + + + Set or unset the ACCOUNTDISABLE +diff --git a/library/adenroll.c b/library/adenroll.c +index 0f3e8b9..7653f89 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -153,6 +153,8 @@ struct _adcli_enroll { + char *samba_data_tool; + bool trusted_for_delegation; + int trusted_for_delegation_explicit; ++ bool dont_expire_password; ++ int dont_expire_password_explicit; + bool account_disable; + int account_disable_explicit; + char *description; +@@ -832,6 +834,8 @@ create_computer_account (adcli_enroll *enroll, + int ret; + size_t c; + size_t m; ++ uint32_t uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD ; ++ char *uac_str = NULL; + + LDAPMod *all_mods[] = { + &objectClass, +@@ -852,11 +856,21 @@ create_computer_account (adcli_enroll *enroll, + LDAPMod *mods[mods_count]; + + if (adcli_enroll_get_trusted_for_delegation (enroll)) { +- vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */ ++ uac |= UAC_TRUSTED_FOR_DELEGATION; + } + ++ if (!adcli_enroll_get_dont_expire_password (enroll)) { ++ uac &= ~(UAC_DONT_EXPIRE_PASSWORD); ++ } ++ ++ if (asprintf (&uac_str, "%d", uac) < 0) { ++ return_val_if_reached (ADCLI_ERR_UNEXPECTED); ++ } ++ vals_userAccountControl[0] = uac_str; ++ + ret = calculate_enctypes (enroll, &val); + if (ret != ADCLI_SUCCESS) { ++ free (uac_str); + return ret; + } + vals_supportedEncryptionTypes[0] = val; +@@ -871,6 +885,7 @@ create_computer_account (adcli_enroll *enroll, + mods[m] = NULL; + + ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL); ++ free (uac_str); + free (val); + + /* +@@ -1577,6 +1592,14 @@ static char *get_user_account_control (adcli_enroll *enroll) + } + } + ++ if (enroll->dont_expire_password_explicit) { ++ if (adcli_enroll_get_dont_expire_password (enroll)) { ++ uac |= UAC_DONT_EXPIRE_PASSWORD; ++ } else { ++ uac &= ~(UAC_DONT_EXPIRE_PASSWORD); ++ } ++ } ++ + if (enroll->account_disable_explicit) { + if (adcli_enroll_get_account_disable (enroll)) { + uac |= UAC_ACCOUNTDISABLE; +@@ -1627,6 +1650,7 @@ update_computer_account (adcli_enroll *enroll) + free (value); + + if (res == ADCLI_SUCCESS && (enroll->trusted_for_delegation_explicit || ++ enroll->dont_expire_password_explicit || + enroll->account_disable_explicit)) { + char *vals_userAccountControl[] = { NULL , NULL }; + LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } }; +@@ -3208,6 +3232,24 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll, + enroll->trusted_for_delegation_explicit = 1; + } + ++bool ++adcli_enroll_get_dont_expire_password (adcli_enroll *enroll) ++{ ++ return_val_if_fail (enroll != NULL, false); ++ ++ return enroll->dont_expire_password; ++} ++ ++void ++adcli_enroll_set_dont_expire_password (adcli_enroll *enroll, ++ bool value) ++{ ++ return_if_fail (enroll != NULL); ++ ++ enroll->dont_expire_password = value; ++ enroll->dont_expire_password_explicit = 1; ++} ++ + bool + adcli_enroll_get_account_disable (adcli_enroll *enroll) + { +diff --git a/library/adenroll.h b/library/adenroll.h +index 8b1c1c7..34dc683 100644 +--- a/library/adenroll.h ++++ b/library/adenroll.h +@@ -126,6 +126,10 @@ bool adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll + void adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll, + bool value); + ++bool adcli_enroll_get_dont_expire_password (adcli_enroll *enroll); ++void adcli_enroll_set_dont_expire_password (adcli_enroll *enroll, ++ bool value); ++ + bool adcli_enroll_get_account_disable (adcli_enroll *enroll); + void adcli_enroll_set_account_disable (adcli_enroll *enroll, + bool value); +diff --git a/tools/computer.c b/tools/computer.c +index 6e309d9..16a1983 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -110,6 +110,7 @@ typedef enum { + opt_add_samba_data, + opt_samba_data_tool, + opt_trusted_for_delegation, ++ opt_dont_expire_password, + opt_add_service_principal, + opt_remove_service_principal, + opt_description, +@@ -144,6 +145,8 @@ static adcli_tool_desc common_usages[] = { + { opt_computer_password_lifetime, "lifetime of the host accounts password in days", }, + { opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n" + "in the userAccountControl attribute", }, ++ { opt_dont_expire_password, "set/unset the DONT_EXPIRE_PASSWORD flag\n" ++ "in the userAccountControl attribute", }, + { opt_account_disable, "set/unset the ACCOUNTDISABLE flag\n" + "in the userAccountControl attribute", }, + { opt_add_service_principal, "add the given service principal to the account\n" }, +@@ -307,6 +310,13 @@ parse_option (Option opt, + adcli_enroll_set_trusted_for_delegation (enroll, false); + } + return ADCLI_SUCCESS; ++ case opt_dont_expire_password: ++ if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) { ++ adcli_enroll_set_dont_expire_password (enroll, true); ++ } else { ++ adcli_enroll_set_dont_expire_password (enroll, false); ++ } ++ return ADCLI_SUCCESS; + case opt_account_disable: + if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) { + adcli_enroll_set_account_disable (enroll, true); +@@ -393,6 +403,7 @@ adcli_tool_computer_join (adcli_conn *conn, + { "description", optional_argument, NULL, opt_description }, + { "user-principal", optional_argument, NULL, opt_user_principal }, + { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, ++ { "dont-expire-password", required_argument, NULL, opt_dont_expire_password }, + { "add-service-principal", required_argument, NULL, opt_add_service_principal }, + { "show-details", no_argument, NULL, opt_show_details }, + { "show-password", no_argument, NULL, opt_show_password }, +@@ -516,6 +527,7 @@ adcli_tool_computer_update (adcli_conn *conn, + { "user-principal", optional_argument, NULL, opt_user_principal }, + { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, + { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, ++ { "dont-expire-password", required_argument, NULL, opt_dont_expire_password }, + { "account-disable", required_argument, NULL, opt_account_disable }, + { "add-service-principal", required_argument, NULL, opt_add_service_principal }, + { "remove-service-principal", required_argument, NULL, opt_remove_service_principal }, +-- +2.31.1 + diff --git a/adcli.spec b/adcli.spec index 34419c2..66fa6c2 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 4%{?dist} +Release: 5%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -8,6 +8,9 @@ Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee78919 Patch1: 0001-build-add-with-vendor-error-message-configure-option.patch Patch2: 0001-configure-update-some-macros-for-autoconf-2.71.patch +Patch3: 0001-coverity-add-missing-NULL-checks.patch +Patch4: 0002-Add-dont-expire-password-option.patch + BuildRequires: gcc BuildRequires: intltool pkgconfig @@ -72,6 +75,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jun 02 2021 Sumit Bose - 0.9.1-5 +- Add dont-expire-password option and coverity fixes + * Wed Apr 07 2021 Sumit Bose - 0.9.1-4 - Add macro updates for autoconf-2.71 and downstream gating From a368b2fb84c2461ac6bf5042da55da1081dfbd8a Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 3 Jun 2021 15:37:25 +0200 Subject: [PATCH 06/27] Add fix for dont-expire-password option Resolves: rhbz#1769644 --- ...dont-expire-password-option-and-join.patch | 27 +++++++++++++++++++ adcli.spec | 6 ++++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 0001-Fix-for-dont-expire-password-option-and-join.patch diff --git a/0001-Fix-for-dont-expire-password-option-and-join.patch b/0001-Fix-for-dont-expire-password-option-and-join.patch new file mode 100644 index 0000000..92c22f4 --- /dev/null +++ b/0001-Fix-for-dont-expire-password-option-and-join.patch @@ -0,0 +1,27 @@ +From 0d8482d4ed83677424f6c9428672d225bfdfe4d9 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 3 Jun 2021 15:03:20 +0200 +Subject: [PATCH] Fix for dont-expire-password option and join + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1769644 +--- + library/adenroll.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index 7653f89..f00d179 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -859,7 +859,8 @@ create_computer_account (adcli_enroll *enroll, + uac |= UAC_TRUSTED_FOR_DELEGATION; + } + +- if (!adcli_enroll_get_dont_expire_password (enroll)) { ++ if (enroll->dont_expire_password_explicit ++ && !adcli_enroll_get_dont_expire_password (enroll)) { + uac &= ~(UAC_DONT_EXPIRE_PASSWORD); + } + +-- +2.31.1 + diff --git a/adcli.spec b/adcli.spec index 66fa6c2..a95ca2b 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -10,6 +10,7 @@ Patch1: 0001-build-add-with-vendor-error-message-configure-option.patch Patch2: 0001-configure-update-some-macros-for-autoconf-2.71.patch Patch3: 0001-coverity-add-missing-NULL-checks.patch Patch4: 0002-Add-dont-expire-password-option.patch +Patch5: 0001-Fix-for-dont-expire-password-option-and-join.patch BuildRequires: gcc @@ -75,6 +76,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Thu Jun 03 2021 Sumit Bose - 0.9.1-6 +- Add fix for dont-expire-password option + * Wed Jun 02 2021 Sumit Bose - 0.9.1-5 - Add dont-expire-password option and coverity fixes From a299f31d7fe3363f07053557a1c4af5c43f1db19 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 28 Jun 2021 20:24:21 +0200 Subject: [PATCH 07/27] Add user-passwd sub-command and setattr/delattr option Resolves: rhbz#1690920, rhbz#1952828 --- ...C-flags-to-a-more-common-header-file.patch | 51 +++ ...entry_attrs-with-userAccountControl-.patch | 60 +++ 0003-entry-add-passwd-user-sub-command.patch | 366 +++++++++++++++++ 0004-Add-setattr-option.patch | 386 ++++++++++++++++++ 0005-Add-delattr-option.patch | 192 +++++++++ adcli.spec | 11 +- 6 files changed, 1065 insertions(+), 1 deletion(-) create mode 100644 0001-library-move-UAC-flags-to-a-more-common-header-file.patch create mode 100644 0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch create mode 100644 0003-entry-add-passwd-user-sub-command.patch create mode 100644 0004-Add-setattr-option.patch create mode 100644 0005-Add-delattr-option.patch diff --git a/0001-library-move-UAC-flags-to-a-more-common-header-file.patch b/0001-library-move-UAC-flags-to-a-more-common-header-file.patch new file mode 100644 index 0000000..aea2a99 --- /dev/null +++ b/0001-library-move-UAC-flags-to-a-more-common-header-file.patch @@ -0,0 +1,51 @@ +From a7a40ce4f47fe40305624b6d86c135b7d27c387d Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 11 Jun 2021 12:44:36 +0200 +Subject: [PATCH 1/5] library: move UAC flags to a more common header file + +--- + library/adenroll.c | 8 -------- + library/adprivate.h | 8 ++++++++ + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/library/adenroll.c b/library/adenroll.c +index f00d179..0b1c066 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -93,14 +93,6 @@ static char *default_ad_ldap_attrs[] = { + NULL, + }; + +-/* Some constants for the userAccountControl AD LDAP attribute, see e.g. +- * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro +- * for details. */ +-#define UAC_ACCOUNTDISABLE 0x0002 +-#define UAC_WORKSTATION_TRUST_ACCOUNT 0x1000 +-#define UAC_DONT_EXPIRE_PASSWORD 0x10000 +-#define UAC_TRUSTED_FOR_DELEGATION 0x80000 +- + struct _adcli_enroll { + int refs; + adcli_conn *conn; +diff --git a/library/adprivate.h b/library/adprivate.h +index 55e6234..822f919 100644 +--- a/library/adprivate.h ++++ b/library/adprivate.h +@@ -39,6 +39,14 @@ + #define HOST_NAME_MAX 255 + #endif + ++/* Some constants for the userAccountControl AD LDAP attribute, see e.g. ++ * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro ++ * for details. */ ++#define UAC_ACCOUNTDISABLE 0x0002 ++#define UAC_WORKSTATION_TRUST_ACCOUNT 0x1000 ++#define UAC_DONT_EXPIRE_PASSWORD 0x10000 ++#define UAC_TRUSTED_FOR_DELEGATION 0x80000 ++ + /* Utilities */ + + #if !defined(__cplusplus) && (__GNUC__ > 2) +-- +2.31.1 + diff --git a/0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch b/0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch new file mode 100644 index 0000000..cb92099 --- /dev/null +++ b/0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch @@ -0,0 +1,60 @@ +From 7148ab196d0a96ede9b5ef463b0481d0fe372b21 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 11 Jun 2021 12:46:03 +0200 +Subject: [PATCH 2/5] adcli_entry: add entry_attrs with userAccountControl + attribute + +--- + library/adentry.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/library/adentry.c b/library/adentry.c +index 1cc0518..13dcaf8 100644 +--- a/library/adentry.c ++++ b/library/adentry.c +@@ -42,6 +42,7 @@ struct _adcli_entry { + char *entry_dn; + char *domain_ou; + char *entry_container; ++ LDAPMessage *entry_attrs; + }; + + static adcli_entry * +@@ -63,6 +64,7 @@ entry_new (adcli_conn *conn, + + entry->builder = builder; + entry->object_class = object_class; ++ entry->entry_attrs = NULL; + return entry; + } + +@@ -82,6 +84,7 @@ entry_free (adcli_entry *entry) + free (entry->entry_container); + free (entry->entry_dn); + free (entry->domain_ou); ++ ldap_msgfree (entry->entry_attrs); + adcli_conn_unref (entry->conn); + free (entry); + } +@@ -102,7 +105,7 @@ static adcli_result + update_entry_from_domain (adcli_entry *entry, + LDAP *ldap) + { +- const char *attrs[] = { "1.1", NULL }; ++ const char *attrs[] = { "userAccountControl", NULL }; + LDAPMessage *results; + LDAPMessage *first; + const char *base; +@@ -139,7 +142,8 @@ update_entry_from_domain (adcli_entry *entry, + return_unexpected_if_fail (entry->entry_dn != NULL); + } + +- ldap_msgfree (results); ++ ldap_msgfree (entry->entry_attrs); ++ entry->entry_attrs = results; + return ADCLI_SUCCESS; + } + +-- +2.31.1 + diff --git a/0003-entry-add-passwd-user-sub-command.patch b/0003-entry-add-passwd-user-sub-command.patch new file mode 100644 index 0000000..7ad5111 --- /dev/null +++ b/0003-entry-add-passwd-user-sub-command.patch @@ -0,0 +1,366 @@ +From 6a673b236dfdfdf9c73cc3d2ccf3949eb1a5ddd0 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 11 Jun 2021 12:47:37 +0200 +Subject: [PATCH 3/5] entry: add passwd-user sub-command + +The new command allows to set or reset a user password with the help of +an account privileged to set the password. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1952828 +--- + doc/adcli.xml | 20 +++++++ + library/adentry.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++ + library/adentry.h | 3 + + tools/entry.c | 99 +++++++++++++++++++++++++++++++++ + tools/tools.c | 1 + + tools/tools.h | 4 ++ + 6 files changed, 265 insertions(+) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 1ed5d3f..6c36297 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -56,6 +56,11 @@ + --domain=domain.example.com + user + ++ ++ adcli passwd-user ++ --domain=domain.example.com ++ user ++ + + adcli create-group + --domain=domain.example.com +@@ -696,6 +701,21 @@ $ adcli delete-user Fry --domain=domain.example.com + + + ++ ++ (Re)setting the password of a User with an Administrative Account ++ ++ adcli passwd-user sets or resets the password ++ of user account. The administrative account used for this operation ++ must have privileges to set a password. ++ ++ ++$ adcli passwd-user Fry --domain=domain.example.com ++ ++ ++ The various global options can be used. ++ ++ ++ + + + Creating a Group +diff --git a/library/adentry.c b/library/adentry.c +index 13dcaf8..0d9b9af 100644 +--- a/library/adentry.c ++++ b/library/adentry.c +@@ -409,6 +409,144 @@ adcli_entry_delete (adcli_entry *entry) + return ADCLI_SUCCESS; + } + ++static adcli_result ++adcli_entry_ensure_enabled (adcli_entry *entry) ++{ ++ adcli_result res; ++ LDAP *ldap; ++ adcli_attrs *attrs; ++ uint32_t uac = 0; ++ char *uac_str; ++ unsigned long attr_val; ++ char *end; ++ ++ return_unexpected_if_fail (entry->entry_attrs != NULL); ++ ++ ldap = adcli_conn_get_ldap_connection (entry->conn); ++ return_unexpected_if_fail (ldap != NULL); ++ ++ uac_str = _adcli_ldap_parse_value (ldap, entry->entry_attrs, ++ "userAccountControl"); ++ if (uac_str != NULL) { ++ attr_val = strtoul (uac_str, &end, 10); ++ if (*end != '\0' || attr_val > UINT32_MAX) { ++ _adcli_warn ("Invalid userAccountControl '%s' for %s account in directory: %s, assuming 0", ++ uac_str, entry->object_class, entry->entry_dn); ++ } else { ++ uac = attr_val; ++ } ++ free (uac_str); ++ } ++ if (uac & UAC_ACCOUNTDISABLE) { ++ uac &= ~(UAC_ACCOUNTDISABLE); ++ ++ if (asprintf (&uac_str, "%d", uac) < 0) { ++ _adcli_warn ("Cannot enable %s entry %s after password (re)set", ++ entry->object_class, entry->entry_dn); ++ return ADCLI_ERR_UNEXPECTED; ++ } ++ ++ attrs = adcli_attrs_new (); ++ adcli_attrs_replace (attrs, "userAccountControl", uac_str, ++ NULL); ++ res = adcli_entry_modify (entry, attrs); ++ if (res == ADCLI_SUCCESS) { ++ _adcli_info ("Enabled %s entry %s after password (re)set", ++ entry->object_class, entry->entry_dn); ++ } else { ++ _adcli_warn ("Failed to enable %s entry %s after password (re)set", ++ entry->object_class, entry->entry_dn); ++ } ++ free (uac_str); ++ adcli_attrs_free (attrs); ++ } else { ++ res = ADCLI_SUCCESS; ++ } ++ ++ return res; ++} ++ ++adcli_result ++adcli_entry_set_passwd (adcli_entry *entry, const char *user_pwd) ++{ ++ adcli_result res; ++ LDAP *ldap; ++ krb5_error_code code; ++ krb5_context k5; ++ krb5_ccache ccache; ++ krb5_data result_string = { 0, }; ++ krb5_data result_code_string = { 0, }; ++ int result_code; ++ char *message; ++ krb5_principal user_principal; ++ ++ ldap = adcli_conn_get_ldap_connection (entry->conn); ++ return_unexpected_if_fail (ldap != NULL); ++ ++ /* Find the user */ ++ res = update_entry_from_domain (entry, ldap); ++ if (res != ADCLI_SUCCESS) ++ return res; ++ ++ if (!entry->entry_dn) { ++ _adcli_err ("Cannot find the %s entry %s in the domain", ++ entry->object_class, entry->sam_name); ++ return ADCLI_ERR_CONFIG; ++ } ++ ++ k5 = adcli_conn_get_krb5_context (entry->conn); ++ return_unexpected_if_fail (k5 != NULL); ++ ++ code = _adcli_krb5_build_principal (k5, entry->sam_name, ++ adcli_conn_get_domain_realm (entry->conn), ++ &user_principal); ++ return_unexpected_if_fail (code == 0); ++ ++ ccache = adcli_conn_get_login_ccache (entry->conn); ++ return_unexpected_if_fail (ccache != NULL); ++ ++ memset (&result_string, 0, sizeof (result_string)); ++ memset (&result_code_string, 0, sizeof (result_code_string)); ++ ++ code = krb5_set_password_using_ccache (k5, ccache, user_pwd, ++ user_principal, &result_code, ++ &result_code_string, &result_string); ++ ++ 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)); ++ /* TODO: Parse out these values */ ++ res = ADCLI_ERR_DIRECTORY; ++ ++ } else if (result_code != 0) { ++#ifdef HAVE_KRB5_CHPW_MESSAGE ++ if (krb5_chpw_message (k5, &result_string, &message) != 0) ++ message = NULL; ++#else ++ message = NULL; ++ if (result_string.length) ++ message = _adcli_str_dupn (result_string.data, result_string.length); ++#endif ++ _adcli_err ("Cannot set %s password: %.*s%s%s", ++ entry->object_class, ++ (int)result_code_string.length, result_code_string.data, ++ message ? ": " : "", message ? message : ""); ++ res = ADCLI_ERR_CREDENTIALS; ++#ifdef HAVE_KRB5_CHPW_MESSAGE ++ krb5_free_string (k5, message); ++#else ++ free (message); ++#endif ++ } else { ++ _adcli_info ("Password (re)setted for %s: %s", entry->object_class, entry->entry_dn); ++ ++ res = adcli_entry_ensure_enabled (entry); ++ } ++ ++ return res; ++} ++ + const char * + adcli_entry_get_sam_name (adcli_entry *entry) + { +diff --git a/library/adentry.h b/library/adentry.h +index ae90689..f2382b1 100644 +--- a/library/adentry.h ++++ b/library/adentry.h +@@ -49,6 +49,9 @@ adcli_result adcli_entry_modify (adcli_entry *entry, + + adcli_result adcli_entry_delete (adcli_entry *entry); + ++adcli_result adcli_entry_set_passwd (adcli_entry *entry, ++ const char *user_pwd); ++ + const char * adcli_entry_get_domain_ou (adcli_entry *entry); + + void adcli_entry_set_domain_ou (adcli_entry *entry, +diff --git a/tools/entry.c b/tools/entry.c +index 05e4313..52d2546 100644 +--- a/tools/entry.c ++++ b/tools/entry.c +@@ -24,6 +24,7 @@ + #include "config.h" + + #include "adcli.h" ++#include "adprivate.h" + #include "adattrs.h" + #include "tools.h" + +@@ -385,6 +386,104 @@ adcli_tool_user_delete (adcli_conn *conn, + return 0; + } + ++int ++adcli_tool_user_passwd (adcli_conn *conn, ++ int argc, ++ char *argv[]) ++{ ++ adcli_result res; ++ adcli_entry *entry; ++ int opt; ++ char *user_pwd = NULL; ++ ++ struct option options[] = { ++ { "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 }, ++ { "stdin-password", no_argument, 0, opt_stdin_password }, ++ { "prompt-password", no_argument, 0, opt_prompt_password }, ++ { "verbose", no_argument, NULL, opt_verbose }, ++ { "help", no_argument, NULL, 'h' }, ++ { 0 }, ++ }; ++ ++ static adcli_tool_desc usages[] = { ++ { 0, "usage: adcli passwd-user --domain=xxxx user" }, ++ { 0 }, ++ }; ++ ++ while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { ++ switch (opt) { ++ case 'h': ++ case '?': ++ case ':': ++ adcli_tool_usage (options, usages); ++ adcli_tool_usage (options, common_usages); ++ return opt == 'h' ? 0 : 2; ++ default: ++ res = parse_option ((Option)opt, optarg, conn); ++ if (res != ADCLI_SUCCESS) { ++ return res; ++ } ++ break; ++ } ++ } ++ ++ argc -= optind; ++ argv += optind; ++ ++ if (argc != 1) { ++ warnx ("specify one user name to (re)set password"); ++ return 2; ++ } ++ ++ entry = adcli_entry_new_user (conn, argv[0]); ++ if (entry == NULL) { ++ warnx ("unexpected memory problems"); ++ return -1; ++ } ++ ++ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); ++ ++ res = adcli_conn_connect (conn); ++ if (res != ADCLI_SUCCESS) { ++ warnx ("couldn't connect to %s domain: %s", ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; ++ } ++ ++ user_pwd = adcli_prompt_password_func (ADCLI_LOGIN_USER_ACCOUNT, ++ adcli_entry_get_sam_name(entry), ++ 0, NULL); ++ if (user_pwd == NULL || *user_pwd == '\0') { ++ warnx ("missing password"); ++ _adcli_password_free (user_pwd); ++ adcli_entry_unref (entry); ++ return 2; ++ } ++ ++ res = adcli_entry_set_passwd (entry, user_pwd); ++ _adcli_password_free (user_pwd); ++ if (res != ADCLI_SUCCESS) { ++ warnx ("(re)setting password for user %s in domain %s failed: %s", ++ adcli_entry_get_sam_name (entry), ++ adcli_conn_get_domain_name (conn), ++ adcli_get_last_error ()); ++ adcli_entry_unref (entry); ++ return -res; ++ } ++ ++ adcli_entry_unref (entry); ++ ++ return 0; ++} ++ + int + adcli_tool_group_create (adcli_conn *conn, + int argc, +diff --git a/tools/tools.c b/tools/tools.c +index 84bbba9..a14b9ca 100644 +--- a/tools/tools.c ++++ b/tools/tools.c +@@ -63,6 +63,7 @@ struct { + { "create-msa", adcli_tool_computer_managed_service_account, "Create a managed service account in the given AD domain", }, + { "create-user", adcli_tool_user_create, "Create a user account", }, + { "delete-user", adcli_tool_user_delete, "Delete a user account", }, ++ { "passwd-user", adcli_tool_user_passwd, "(Re)set a user password", }, + { "create-group", adcli_tool_group_create, "Create a group", }, + { "delete-group", adcli_tool_group_delete, "Delete a group", }, + { "add-member", adcli_tool_member_add, "Add users to a group", }, +diff --git a/tools/tools.h b/tools/tools.h +index 82d5e4e..d38aa32 100644 +--- a/tools/tools.h ++++ b/tools/tools.h +@@ -94,6 +94,10 @@ int adcli_tool_user_delete (adcli_conn *conn, + int argc, + char *argv[]); + ++int adcli_tool_user_passwd (adcli_conn *conn, ++ int argc, ++ char *argv[]); ++ + int adcli_tool_group_create (adcli_conn *conn, + int argc, + char *argv[]); +-- +2.31.1 + diff --git a/0004-Add-setattr-option.patch b/0004-Add-setattr-option.patch new file mode 100644 index 0000000..7976e7c --- /dev/null +++ b/0004-Add-setattr-option.patch @@ -0,0 +1,386 @@ +From c5b0cee2976682b4fc1aeb02636cc9f2c6dbc2a5 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 14 Jun 2021 07:54:01 +0200 +Subject: [PATCH 4/5] Add setattr option + +With the new option common LDAP attributes can be set. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1690920 +--- + doc/adcli.xml | 34 +++++++++ + library/adenroll.c | 169 ++++++++++++++++++++++++++++++++++++++++++++- + library/adenroll.h | 4 ++ + tools/computer.c | 10 +++ + 4 files changed, 216 insertions(+), 1 deletion(-) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 6c36297..8383aa7 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -374,6 +374,23 @@ Password for Administrator: + service should be accessible with a different host + name as well. + ++ ++ ++ Add the LDAP attribute ++ with the ++ given to ++ the new LDAP host object. ++ This option can be used multiple times to add multiple ++ different attributes. Multi-value attributes are ++ currently not supported. ++ Please note that the account used to join the ++ domain must have the required privileges to add the ++ given attributes. Some attributes might have ++ constraints with respect to syntax and allowed values ++ which must be met as well. Attributes managed by other ++ adcli options cannot be set with this option. ++ ++ + + + After a successful join print out information +@@ -543,6 +560,23 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + Remove a service principal name from + the keytab and the AD host object. + ++ ++ ++ Add the LDAP attribute ++ with the ++ given to ++ the LDAP host object. ++ This option can be used multiple times to add multiple ++ different attributes. Multi-value attributes are ++ currently not supported. ++ Please note that the account used to update the ++ host object must have the required privileges to modify ++ the given attributes. Some attributes might have ++ constraints with respect to syntax and allowed values ++ which must be met as well. Attributes managed by other ++ adcli options cannot be set with this option. ++ ++ + + + After a successful join print out information +diff --git a/library/adenroll.c b/library/adenroll.c +index 0b1c066..dd51567 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -150,6 +150,7 @@ struct _adcli_enroll { + bool account_disable; + int account_disable_explicit; + char *description; ++ char **setattr; + }; + + static const char * +@@ -795,6 +796,56 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype) + return ADCLI_SUCCESS; + } + ++static LDAPMod ** ++get_mods_for_attrs (adcli_enroll *enroll, int mod_op) ++{ ++ size_t len; ++ size_t c; ++ char *end; ++ LDAPMod **mods = NULL; ++ ++ len = _adcli_strv_len (enroll->setattr); ++ if (len == 0) { ++ return NULL; ++ } ++ ++ mods = calloc (len + 1, sizeof (LDAPMod *)); ++ return_val_if_fail (mods != NULL, NULL); ++ ++ for (c = 0; c < len; c++) { ++ end = strchr (enroll->setattr[c], '='); ++ if (end == NULL) { ++ ldap_mods_free (mods, 1); ++ return NULL; ++ } ++ ++ mods[c] = calloc (1, sizeof (LDAPMod)); ++ if (mods[c] == NULL) { ++ ldap_mods_free (mods, 1); ++ return NULL; ++ } ++ ++ mods[c]->mod_op = mod_op; ++ *end = '\0'; ++ mods[c]->mod_type = strdup (enroll->setattr[c]); ++ *end = '='; ++ mods[c]->mod_values = calloc (2, sizeof (char *)); ++ if (mods[c]->mod_type == NULL || mods[c]->mod_values == NULL) { ++ ldap_mods_free (mods, 1); ++ return NULL; ++ } ++ ++ mods[c]->mod_values[0] = strdup (end + 1); ++ if (mods[c]->mod_values[0] == NULL) { ++ ldap_mods_free (mods, 1); ++ return NULL; ++ } ++ } ++ ++ return mods; ++} ++ ++ + static adcli_result + create_computer_account (adcli_enroll *enroll, + LDAP *ldap) +@@ -828,6 +879,7 @@ create_computer_account (adcli_enroll *enroll, + size_t m; + uint32_t uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD ; + char *uac_str = NULL; ++ LDAPMod **extra_mods = NULL; + + LDAPMod *all_mods[] = { + &objectClass, +@@ -845,7 +897,7 @@ create_computer_account (adcli_enroll *enroll, + }; + + size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *); +- LDAPMod *mods[mods_count]; ++ LDAPMod **mods; + + if (adcli_enroll_get_trusted_for_delegation (enroll)) { + uac |= UAC_TRUSTED_FOR_DELEGATION; +@@ -868,6 +920,17 @@ create_computer_account (adcli_enroll *enroll, + } + vals_supportedEncryptionTypes[0] = val; + ++ if (enroll->setattr != NULL) { ++ extra_mods = get_mods_for_attrs (enroll, LDAP_MOD_ADD); ++ if (extra_mods == NULL) { ++ _adcli_err ("Failed to add setattr attributes, " ++ "just using defaults"); ++ } ++ } ++ ++ mods = calloc (mods_count + seq_count (extra_mods) + 1, sizeof (LDAPMod *)); ++ return_val_if_fail (mods != NULL, ADCLI_ERR_UNEXPECTED); ++ + m = 0; + for (c = 0; c < mods_count - 1; c++) { + /* Skip empty LDAP sttributes */ +@@ -875,9 +938,15 @@ create_computer_account (adcli_enroll *enroll, + mods[m++] = all_mods[c]; + } + } ++ ++ for (c = 0; c < seq_count (extra_mods); c++) { ++ mods[m++] = extra_mods[c]; ++ } + mods[m] = NULL; + + ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL); ++ ldap_mods_free (extra_mods, 1); ++ free (mods); + free (uac_str); + free (val); + +@@ -1698,6 +1767,14 @@ update_computer_account (adcli_enroll *enroll) + res |= update_computer_attribute (enroll, ldap, mods); + } + ++ if (res == ADCLI_SUCCESS && enroll->setattr != NULL) { ++ LDAPMod **mods = get_mods_for_attrs (enroll, LDAP_MOD_REPLACE); ++ if (mods != NULL) { ++ res |= update_computer_attribute (enroll, ldap, mods); ++ ldap_mods_free (mods, 1); ++ } ++ } ++ + if (res != 0) + _adcli_info ("Updated existing computer account: %s", enroll->computer_dn); + } +@@ -2751,6 +2828,7 @@ enroll_free (adcli_enroll *enroll) + free (enroll->user_principal); + _adcli_strv_free (enroll->service_names); + _adcli_strv_free (enroll->service_principals); ++ _adcli_strv_free (enroll->setattr); + _adcli_password_free (enroll->computer_password); + + adcli_enroll_set_keytab_name (enroll, NULL); +@@ -3332,6 +3410,72 @@ adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll, + return_if_fail (enroll->service_principals_to_remove != NULL); + } + ++static int comp_attr_name (const char *s1, const char *s2) ++{ ++ size_t c = 0; ++ ++ /* empty strings cannot contain an attribute name */ ++ if (s1 == NULL || s2 == NULL || *s1 == '\0' || *s2 == '\0') { ++ return 1; ++ } ++ ++ for (c = 0 ; s1[c] != '\0' && s2[c] != '\0'; c++) { ++ if (s1[c] == '=' && s2[c] == '=') { ++ return 0; ++ } else if (tolower (s1[c]) != tolower (s2[c])) { ++ return 1; ++ } ++ } ++ ++ return 1; ++} ++ ++adcli_result ++adcli_enroll_add_setattr (adcli_enroll *enroll, const char *value) ++{ ++ char *delim; ++ ++ return_val_if_fail (enroll != NULL, ADCLI_ERR_CONFIG); ++ return_val_if_fail (value != NULL, ADCLI_ERR_CONFIG); ++ ++ delim = strchr (value, '='); ++ if (delim == NULL) { ++ _adcli_err ("Missing '=' in setattr option [%s]", value); ++ return ADCLI_ERR_CONFIG; ++ } ++ ++ if (*(delim + 1) == '\0') { ++ _adcli_err ("Missing value in setattr option [%s]", value); ++ return ADCLI_ERR_CONFIG; ++ } ++ ++ *delim = '\0'; ++ if (_adcli_strv_has_ex (default_ad_ldap_attrs, value, strcasecmp) == 1) { ++ _adcli_err ("Attribute [%s] cannot be set with setattr", value); ++ return ADCLI_ERR_CONFIG; ++ } ++ *delim = '='; ++ ++ if (_adcli_strv_has_ex (enroll->setattr, value, comp_attr_name) == 1) { ++ _adcli_err ("Attribute [%s] already set", value); ++ return ADCLI_ERR_CONFIG; ++ } ++ ++ enroll->setattr = _adcli_strv_add (enroll->setattr, strdup (value), ++ NULL); ++ return_val_if_fail (enroll->setattr != NULL, ADCLI_ERR_CONFIG); ++ ++ return ADCLI_SUCCESS; ++} ++ ++const char ** ++adcli_enroll_get_setattr (adcli_enroll *enroll) ++{ ++ return_val_if_fail (enroll != NULL, NULL); ++ return (const char **) enroll->setattr; ++} ++ ++ + #ifdef ADENROLL_TESTS + + #include "test.h" +@@ -3401,12 +3545,35 @@ test_adcli_enroll_get_permitted_keytab_enctypes (void) + adcli_conn_unref (conn); + } + ++static void ++test_comp_attr_name (void) ++{ ++ assert_num_eq (1, comp_attr_name (NULL ,NULL)); ++ assert_num_eq (1, comp_attr_name ("" ,NULL)); ++ assert_num_eq (1, comp_attr_name ("" ,"")); ++ assert_num_eq (1, comp_attr_name (NULL ,"")); ++ assert_num_eq (1, comp_attr_name (NULL ,"abc=xyz")); ++ assert_num_eq (1, comp_attr_name ("" ,"abc=xyz")); ++ assert_num_eq (1, comp_attr_name ("abc=xyz", NULL)); ++ assert_num_eq (1, comp_attr_name ("abc=xyz", "")); ++ assert_num_eq (1, comp_attr_name ("abc=xyz", "ab=xyz")); ++ assert_num_eq (1, comp_attr_name ("ab=xyz", "abc=xyz")); ++ assert_num_eq (1, comp_attr_name ("abcxyz", "abc=xyz")); ++ assert_num_eq (1, comp_attr_name ("abc=xyz", "abcxyz")); ++ assert_num_eq (1, comp_attr_name ("abc=xyz", "a")); ++ assert_num_eq (1, comp_attr_name ("a", "abc=xyz")); ++ ++ assert_num_eq (0, comp_attr_name ("abc=xyz", "abc=xyz")); ++ assert_num_eq (0, comp_attr_name ("abc=xyz", "abc=123")); ++} ++ + int + main (int argc, + char *argv[]) + { + test_func (test_adcli_enroll_get_permitted_keytab_enctypes, + "/attrs/adcli_enroll_get_permitted_keytab_enctypes"); ++ test_func (test_comp_attr_name, "/attrs/comp_attr_name"); + return test_run (argc, argv); + } + +diff --git a/library/adenroll.h b/library/adenroll.h +index 34dc683..862bb60 100644 +--- a/library/adenroll.h ++++ b/library/adenroll.h +@@ -138,6 +138,10 @@ const char * adcli_enroll_get_desciption (adcli_enroll *enroll); + void adcli_enroll_set_description (adcli_enroll *enroll, + const char *value); + ++const char ** adcli_enroll_get_setattr (adcli_enroll *enroll); ++adcli_result adcli_enroll_add_setattr (adcli_enroll *enroll, ++ const char *value); ++ + bool adcli_enroll_get_is_service (adcli_enroll *enroll); + void adcli_enroll_set_is_service (adcli_enroll *enroll, + bool value); +diff --git a/tools/computer.c b/tools/computer.c +index 16a1983..af38894 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -114,6 +114,7 @@ typedef enum { + opt_add_service_principal, + opt_remove_service_principal, + opt_description, ++ opt_setattr, + opt_use_ldaps, + opt_account_disable, + } Option; +@@ -152,6 +153,7 @@ static adcli_tool_desc common_usages[] = { + { opt_add_service_principal, "add the given service principal to the account\n" }, + { opt_remove_service_principal, "remove the given service principal from the account\n" }, + { opt_description, "add a description to the account\n" }, ++ { opt_setattr, "add an attribute with a value\n" }, + { opt_no_password, "don't prompt for or read a password" }, + { opt_prompt_password, "prompt for a password if necessary" }, + { opt_stdin_password, "read a password from stdin (until EOF) if\n" +@@ -333,6 +335,12 @@ parse_option (Option opt, + case opt_description: + adcli_enroll_set_description (enroll, optarg); + return ADCLI_SUCCESS; ++ case opt_setattr: ++ ret = adcli_enroll_add_setattr (enroll, optarg); ++ if (ret != ADCLI_SUCCESS) { ++ warnx ("parsing setattr option failed"); ++ } ++ return ret; + case opt_use_ldaps: + adcli_conn_set_use_ldaps (conn, true); + return ADCLI_SUCCESS; +@@ -401,6 +409,7 @@ adcli_tool_computer_join (adcli_conn *conn, + { "os-version", required_argument, NULL, opt_os_version }, + { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, + { "description", optional_argument, NULL, opt_description }, ++ { "setattr", required_argument, NULL, opt_setattr }, + { "user-principal", optional_argument, NULL, opt_user_principal }, + { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, + { "dont-expire-password", required_argument, NULL, opt_dont_expire_password }, +@@ -524,6 +533,7 @@ adcli_tool_computer_update (adcli_conn *conn, + { "os-version", required_argument, NULL, opt_os_version }, + { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, + { "description", optional_argument, NULL, opt_description }, ++ { "setattr", required_argument, NULL, opt_setattr }, + { "user-principal", optional_argument, NULL, opt_user_principal }, + { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, + { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, +-- +2.31.1 + diff --git a/0005-Add-delattr-option.patch b/0005-Add-delattr-option.patch new file mode 100644 index 0000000..ee72cfe --- /dev/null +++ b/0005-Add-delattr-option.patch @@ -0,0 +1,192 @@ +From cd5b6cdcf3e6bfc5776f2865f460f608421dfa3f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 14 Jun 2021 08:42:21 +0200 +Subject: [PATCH 5/5] Add delattr option + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1690920 +--- + doc/adcli.xml | 11 ++++++++ + library/adenroll.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ + library/adenroll.h | 4 +++ + tools/computer.c | 9 +++++++ + 4 files changed, 90 insertions(+) + +diff --git a/doc/adcli.xml b/doc/adcli.xml +index 8383aa7..bcf4857 100644 +--- a/doc/adcli.xml ++++ b/doc/adcli.xml +@@ -577,6 +577,17 @@ $ adcli update --login-ccache=/tmp/krbcc_123 + adcli options cannot be set with this option. + + ++ ++ ++ Remove the LDAP attribute ++ from the ++ LDAP host object. This option can be used multiple ++ times to remove multiple different attributes. ++ Please note that the account used to update the ++ host object must have the required privileges to delete ++ the given attributes. Attributes managed by other adcli ++ options cannot be removed. ++ + + + After a successful join print out information +diff --git a/library/adenroll.c b/library/adenroll.c +index dd51567..9a06d52 100644 +--- a/library/adenroll.c ++++ b/library/adenroll.c +@@ -151,6 +151,7 @@ struct _adcli_enroll { + int account_disable_explicit; + char *description; + char **setattr; ++ char **delattr; + }; + + static const char * +@@ -845,6 +846,39 @@ get_mods_for_attrs (adcli_enroll *enroll, int mod_op) + return mods; + } + ++static LDAPMod ** ++get_del_mods_for_attrs (adcli_enroll *enroll, int mod_op) ++{ ++ size_t len; ++ size_t c; ++ LDAPMod **mods = NULL; ++ ++ len = _adcli_strv_len (enroll->delattr); ++ if (len == 0) { ++ return NULL; ++ } ++ ++ mods = calloc (len + 1, sizeof (LDAPMod *)); ++ return_val_if_fail (mods != NULL, NULL); ++ ++ for (c = 0; c < len; c++) { ++ mods[c] = calloc (1, sizeof (LDAPMod)); ++ if (mods[c] == NULL) { ++ ldap_mods_free (mods, 1); ++ return NULL; ++ } ++ ++ mods[c]->mod_op = mod_op; ++ mods[c]->mod_type = strdup (enroll->delattr[c]); ++ mods[c]->mod_values = NULL; ++ if (mods[c]->mod_type == NULL) { ++ ldap_mods_free (mods, 1); ++ return NULL; ++ } ++ } ++ ++ return mods; ++} + + static adcli_result + create_computer_account (adcli_enroll *enroll, +@@ -1775,6 +1809,14 @@ update_computer_account (adcli_enroll *enroll) + } + } + ++ if (res == ADCLI_SUCCESS && enroll->delattr != NULL) { ++ LDAPMod **mods = get_del_mods_for_attrs (enroll, LDAP_MOD_DELETE); ++ if (mods != NULL) { ++ res |= update_computer_attribute (enroll, ldap, mods); ++ ldap_mods_free (mods, 1); ++ } ++ } ++ + if (res != 0) + _adcli_info ("Updated existing computer account: %s", enroll->computer_dn); + } +@@ -3475,6 +3517,30 @@ adcli_enroll_get_setattr (adcli_enroll *enroll) + return (const char **) enroll->setattr; + } + ++adcli_result ++adcli_enroll_add_delattr (adcli_enroll *enroll, const char *value) ++{ ++ return_val_if_fail (enroll != NULL, ADCLI_ERR_CONFIG); ++ return_val_if_fail (value != NULL, ADCLI_ERR_CONFIG); ++ ++ if (_adcli_strv_has_ex (default_ad_ldap_attrs, value, strcasecmp) == 1) { ++ _adcli_err ("Attribute [%s] cannot be removed with delattr", value); ++ return ADCLI_ERR_CONFIG; ++ } ++ ++ enroll->delattr = _adcli_strv_add (enroll->delattr, strdup (value), ++ NULL); ++ return_val_if_fail (enroll->delattr != NULL, ADCLI_ERR_CONFIG); ++ ++ return ADCLI_SUCCESS; ++} ++ ++const char ** ++adcli_enroll_get_delattr (adcli_enroll *enroll) ++{ ++ return_val_if_fail (enroll != NULL, NULL); ++ return (const char **) enroll->delattr; ++} + + #ifdef ADENROLL_TESTS + +diff --git a/library/adenroll.h b/library/adenroll.h +index 862bb60..e3ada33 100644 +--- a/library/adenroll.h ++++ b/library/adenroll.h +@@ -142,6 +142,10 @@ const char ** adcli_enroll_get_setattr (adcli_enroll *enroll); + adcli_result adcli_enroll_add_setattr (adcli_enroll *enroll, + const char *value); + ++const char ** adcli_enroll_get_delattr (adcli_enroll *enroll); ++adcli_result adcli_enroll_add_delattr (adcli_enroll *enroll, ++ const char *value); ++ + bool adcli_enroll_get_is_service (adcli_enroll *enroll); + void adcli_enroll_set_is_service (adcli_enroll *enroll, + bool value); +diff --git a/tools/computer.c b/tools/computer.c +index af38894..dffeecb 100644 +--- a/tools/computer.c ++++ b/tools/computer.c +@@ -115,6 +115,7 @@ typedef enum { + opt_remove_service_principal, + opt_description, + opt_setattr, ++ opt_delattr, + opt_use_ldaps, + opt_account_disable, + } Option; +@@ -154,6 +155,7 @@ static adcli_tool_desc common_usages[] = { + { opt_remove_service_principal, "remove the given service principal from the account\n" }, + { opt_description, "add a description to the account\n" }, + { opt_setattr, "add an attribute with a value\n" }, ++ { opt_delattr, "remove an attribute\n" }, + { opt_no_password, "don't prompt for or read a password" }, + { opt_prompt_password, "prompt for a password if necessary" }, + { opt_stdin_password, "read a password from stdin (until EOF) if\n" +@@ -341,6 +343,12 @@ parse_option (Option opt, + warnx ("parsing setattr option failed"); + } + return ret; ++ case opt_delattr: ++ ret = adcli_enroll_add_delattr (enroll, optarg); ++ if (ret != ADCLI_SUCCESS) { ++ warnx ("parsing delattr option failed"); ++ } ++ return ret; + case opt_use_ldaps: + adcli_conn_set_use_ldaps (conn, true); + return ADCLI_SUCCESS; +@@ -534,6 +542,7 @@ adcli_tool_computer_update (adcli_conn *conn, + { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, + { "description", optional_argument, NULL, opt_description }, + { "setattr", required_argument, NULL, opt_setattr }, ++ { "delattr", required_argument, NULL, opt_delattr }, + { "user-principal", optional_argument, NULL, opt_user_principal }, + { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, + { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, +-- +2.31.1 + diff --git a/adcli.spec b/adcli.spec index a95ca2b..1ce13da 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 6%{?dist} +Release: 7%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -11,6 +11,11 @@ Patch2: 0001-configure-update-some-macros-for-autoconf-2.71.patch Patch3: 0001-coverity-add-missing-NULL-checks.patch Patch4: 0002-Add-dont-expire-password-option.patch Patch5: 0001-Fix-for-dont-expire-password-option-and-join.patch +Patch6: 0001-library-move-UAC-flags-to-a-more-common-header-file.patch +Patch7: 0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch +Patch8: 0003-entry-add-passwd-user-sub-command.patch +Patch9: 0004-Add-setattr-option.patch +Patch10: 0005-Add-delattr-option.patch BuildRequires: gcc @@ -76,6 +81,10 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Mon Jun 28 2021 Sumit Bose - 0.9.1-7 +- Add user-passwd sub-command +- Add setattr/delattr option + * Thu Jun 03 2021 Sumit Bose - 0.9.1-6 - Add fix for dont-expire-password option From d575416bf58f7a472f85221afb7b5dd2ad949fd6 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 21 Jul 2021 12:19:40 +0000 Subject: [PATCH 08/27] - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild Signed-off-by: Fedora Release Engineering From d4ee038ec2458cc68fcc5ee02baaf399baba7ce2 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 21 Jul 2021 17:14:50 +0000 Subject: [PATCH 09/27] - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 1ce13da..cce5849 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 7%{?dist} +Release: 8%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -81,6 +81,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jul 21 2021 Fedora Release Engineering - 0.9.1-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + * Mon Jun 28 2021 Sumit Bose - 0.9.1-7 - Add user-passwd sub-command - Add setattr/delattr option From c47954a13f2125f0b8d0dfbcf4aea8e69a0625a2 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 28 Jul 2021 14:36:59 +0200 Subject: [PATCH 10/27] Add ns_get16() and ns_get32() to configure check Resolves: rhbz#1984891 --- ...ck-for-ns_get16-and-ns_get32-as-well.patch | 38 +++++++++++++++++++ adcli.spec | 7 +++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch diff --git a/0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch b/0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch new file mode 100644 index 0000000..22f8a6a --- /dev/null +++ b/0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch @@ -0,0 +1,38 @@ +From e841ba7513f3f8b6393183d2dea9adcbf7ba2e44 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 28 Jul 2021 12:55:16 +0200 +Subject: [PATCH] configure: check for ns_get16 and ns_get32 as well + +With newer versions of glibc res_query() might ba already available in +glibc with ns_get16() and ns_get32() still requires libresolv. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1984891 +--- + configure.ac | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index c6ff31d..fc6e790 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -98,13 +98,15 @@ AC_SUBST(LDAP_CFLAGS) + # ------------------------------------------------------------------- + # resolv + +-AC_MSG_CHECKING(for which library has res_query) ++AC_MSG_CHECKING([for which library has res_query, ns_get16 and ns_get32]) + for lib in "" "-lresolv"; do + saved_LIBS="$LIBS" + LIBS="$LIBS $lib" + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([#include ], +- [res_query (0, 0, 0, 0, 0)]) ++ [res_query (0, 0, 0, 0, 0); ++ ns_get32 (NULL); ++ ns_get16 (NULL);]) + ], + [ AC_MSG_RESULT(${lib:-libc}); have_res_query="yes"; break; ], + [ LIBS="$saved_LIBS" ]) +-- +2.31.1 + diff --git a/adcli.spec b/adcli.spec index cce5849..575de28 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 8%{?dist} +Release: 9%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -16,6 +16,7 @@ Patch7: 0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch Patch8: 0003-entry-add-passwd-user-sub-command.patch Patch9: 0004-Add-setattr-option.patch Patch10: 0005-Add-delattr-option.patch +Patch11: 0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch BuildRequires: gcc @@ -81,6 +82,10 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jul 28 2021 Sumit Bose - 0.9.1-9 +- Add ns_get16() and ns_get32() to configure check + Resolves: rhbz#1984891 + * Wed Jul 21 2021 Fedora Release Engineering - 0.9.1-8 - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild From badb3d8a5f1fafee9975bc674bfb7bddca54cf7e Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 19 Jan 2022 20:54:58 +0000 Subject: [PATCH 11/27] - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 575de28..0c94e65 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 9%{?dist} +Release: 10%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -82,6 +82,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jan 19 2022 Fedora Release Engineering - 0.9.1-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + * Wed Jul 28 2021 Sumit Bose - 0.9.1-9 - Add ns_get16() and ns_get32() to configure check Resolves: rhbz#1984891 From 023fa48ee01ae508e3ada81b5f84b4ac09396c7e Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 20 Jul 2022 20:25:42 +0000 Subject: [PATCH 12/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 0c94e65..89365c9 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.1 -Release: 10%{?dist} +Release: 11%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -82,6 +82,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jul 20 2022 Fedora Release Engineering - 0.9.1-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + * Wed Jan 19 2022 Fedora Release Engineering - 0.9.1-10 - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild From 3e5d9ce656a194f56ea854d919ef665bf09c5fa8 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 29 Sep 2022 08:20:32 +0200 Subject: [PATCH 13/27] Update to upstream release 0.9.2 --- .gitignore | 1 + ...dont-expire-password-option-and-join.patch | 27 -- ...endor-error-message-configure-option.patch | 60 --- ...ck-for-ns_get16-and-ns_get32-as-well.patch | 38 -- ...update-some-macros-for-autoconf-2.71.patch | 84 ---- 0001-coverity-add-missing-NULL-checks.patch | 44 -- ...C-flags-to-a-more-common-header-file.patch | 51 --- 0002-Add-dont-expire-password-option.patch | 229 ----------- ...entry_attrs-with-userAccountControl-.patch | 60 --- 0003-entry-add-passwd-user-sub-command.patch | 366 ----------------- 0004-Add-setattr-option.patch | 386 ------------------ 0005-Add-delattr-option.patch | 192 --------- adcli.spec | 21 +- sources | 2 +- 14 files changed, 8 insertions(+), 1553 deletions(-) delete mode 100644 0001-Fix-for-dont-expire-password-option-and-join.patch delete mode 100644 0001-build-add-with-vendor-error-message-configure-option.patch delete mode 100644 0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch delete mode 100644 0001-configure-update-some-macros-for-autoconf-2.71.patch delete mode 100644 0001-coverity-add-missing-NULL-checks.patch delete mode 100644 0001-library-move-UAC-flags-to-a-more-common-header-file.patch delete mode 100644 0002-Add-dont-expire-password-option.patch delete mode 100644 0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch delete mode 100644 0003-entry-add-passwd-user-sub-command.patch delete mode 100644 0004-Add-setattr-option.patch delete mode 100644 0005-Add-delattr-option.patch diff --git a/.gitignore b/.gitignore index ac6fbea..440751f 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /adcli-0.8.2.tar.gz /adcli-0.9.0.tar.gz /adcli-0.9.1.tar.gz +/adcli-0.9.2.tar.gz diff --git a/0001-Fix-for-dont-expire-password-option-and-join.patch b/0001-Fix-for-dont-expire-password-option-and-join.patch deleted file mode 100644 index 92c22f4..0000000 --- a/0001-Fix-for-dont-expire-password-option-and-join.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0d8482d4ed83677424f6c9428672d225bfdfe4d9 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Thu, 3 Jun 2021 15:03:20 +0200 -Subject: [PATCH] Fix for dont-expire-password option and join - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1769644 ---- - library/adenroll.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 7653f89..f00d179 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -859,7 +859,8 @@ create_computer_account (adcli_enroll *enroll, - uac |= UAC_TRUSTED_FOR_DELEGATION; - } - -- if (!adcli_enroll_get_dont_expire_password (enroll)) { -+ if (enroll->dont_expire_password_explicit -+ && !adcli_enroll_get_dont_expire_password (enroll)) { - uac &= ~(UAC_DONT_EXPIRE_PASSWORD); - } - --- -2.31.1 - diff --git a/0001-build-add-with-vendor-error-message-configure-option.patch b/0001-build-add-with-vendor-error-message-configure-option.patch deleted file mode 100644 index 75235ee..0000000 --- a/0001-build-add-with-vendor-error-message-configure-option.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 0353d704879f20983184f8bded4f16538d72f7cc Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 10 Mar 2021 18:12:09 +0100 -Subject: [PATCH] build: add --with-vendor-error-message configure option - -With the new configure option --with-vendor-error-message a packager or -a distribution can add a message if adcli returns with an error. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1889386 ---- - configure.ac | 15 +++++++++++++++ - tools/tools.c | 6 ++++++ - 2 files changed, 21 insertions(+) - -diff --git a/configure.ac b/configure.ac -index baa0d3b..7dfba97 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -123,6 +123,21 @@ if test "$sasl_invalid" = "yes"; then - AC_MSG_ERROR([Couldn't find Cyrus SASL headers]) - fi - -+# -------------------------------------------------------------------- -+# Vendor error message -+ -+AC_ARG_WITH([vendor-error-message], -+ [AS_HELP_STRING([--with-vendor-error-message=ARG], -+ [Add a vendor specific error message shown if a adcli command fails] -+ )], -+ [AS_IF([test "x$withval" != "x"], -+ [AC_DEFINE_UNQUOTED([VENDOR_MSG], -+ ["$withval"], -+ [Vendor specific error message])], -+ [AC_MSG_ERROR([--with-vendor-error-message requires an argument])] -+ )], -+ []) -+ - # -------------------------------------------------------------------- - # Documentation options - -diff --git a/tools/tools.c b/tools/tools.c -index d0dcf98..84bbba9 100644 ---- a/tools/tools.c -+++ b/tools/tools.c -@@ -538,6 +538,12 @@ main (int argc, - - if (conn) - adcli_conn_unref (conn); -+#ifdef VENDOR_MSG -+ if (ret != 0) { -+ fprintf (stderr, VENDOR_MSG"\n"); -+ } -+#endif -+ - return ret; - } - --- -2.30.2 - diff --git a/0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch b/0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch deleted file mode 100644 index 22f8a6a..0000000 --- a/0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch +++ /dev/null @@ -1,38 +0,0 @@ -From e841ba7513f3f8b6393183d2dea9adcbf7ba2e44 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 28 Jul 2021 12:55:16 +0200 -Subject: [PATCH] configure: check for ns_get16 and ns_get32 as well - -With newer versions of glibc res_query() might ba already available in -glibc with ns_get16() and ns_get32() still requires libresolv. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1984891 ---- - configure.ac | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index c6ff31d..fc6e790 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -98,13 +98,15 @@ AC_SUBST(LDAP_CFLAGS) - # ------------------------------------------------------------------- - # resolv - --AC_MSG_CHECKING(for which library has res_query) -+AC_MSG_CHECKING([for which library has res_query, ns_get16 and ns_get32]) - for lib in "" "-lresolv"; do - saved_LIBS="$LIBS" - LIBS="$LIBS $lib" - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([#include ], -- [res_query (0, 0, 0, 0, 0)]) -+ [res_query (0, 0, 0, 0, 0); -+ ns_get32 (NULL); -+ ns_get16 (NULL);]) - ], - [ AC_MSG_RESULT(${lib:-libc}); have_res_query="yes"; break; ], - [ LIBS="$saved_LIBS" ]) --- -2.31.1 - diff --git a/0001-configure-update-some-macros-for-autoconf-2.71.patch b/0001-configure-update-some-macros-for-autoconf-2.71.patch deleted file mode 100644 index e9f0bc6..0000000 --- a/0001-configure-update-some-macros-for-autoconf-2.71.patch +++ /dev/null @@ -1,84 +0,0 @@ -From a8492d71a6db8565544444eef11de8c733c95ef8 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Tue, 6 Apr 2021 19:32:07 +0200 -Subject: [PATCH] configure: update some macros for autoconf-2.71 - ---- - configure.ac | 10 +++++----- - library/Makefile.am | 2 +- - tools/Makefile.am | 2 +- - 3 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 7dfba97..c6ff31d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1,4 +1,4 @@ --AC_PREREQ(2.61) -+AC_PREREQ([2.61]) - - AC_INIT([adcli], - [0.9.1], -@@ -33,7 +33,7 @@ LT_INIT([dlopen disable-static]) - AC_PROG_CC - AC_PROG_CPP - AM_PROG_CC_C_O --AM_PROG_LIBTOOL -+LT_INIT - - # ------------------------------------------------------------------- - # Kerberos -@@ -143,7 +143,7 @@ AC_ARG_WITH([vendor-error-message], - - AC_MSG_CHECKING([whether to build documentation]) - AC_ARG_ENABLE(doc, -- AC_HELP_STRING([--enable-doc], -+ AS_HELP_STRING([--enable-doc], - [Disable building documentation]) - ) - -@@ -180,7 +180,7 @@ doc_status=$enable_doc - - AC_MSG_CHECKING([for debug mode]) - AC_ARG_ENABLE(debug, -- AC_HELP_STRING([--enable-debug=no/default/yes], -+ AS_HELP_STRING([--enable-debug=no/default/yes], - [Turn on or off debugging])) - - if test "$enable_debug" != "no"; then -@@ -308,7 +308,7 @@ fi - - AC_MSG_CHECKING([where is Samba's net utility]) - AC_ARG_WITH([samba_data_tool], -- AC_HELP_STRING([--with-samba-data-tool=/path], -+ AS_HELP_STRING([--with-samba-data-tool=/path], - [Path to Samba's net utility]), - [], - [with_samba_data_tool=/usr/bin/net]) -diff --git a/library/Makefile.am b/library/Makefile.am -index 4829555..e046606 100644 ---- a/library/Makefile.am -+++ b/library/Makefile.am -@@ -1,6 +1,6 @@ - include $(top_srcdir)/Makefile.decl - --INCLUDES = \ -+AM_CPPFLAGS = \ - -I$(top_srcdir) \ - -DADCLI_UNSTABLE_API \ - -DHOST_TRIPLET=\"$(host_triplet)\" \ -diff --git a/tools/Makefile.am b/tools/Makefile.am -index 1cdf451..71ec14d 100644 ---- a/tools/Makefile.am -+++ b/tools/Makefile.am -@@ -1,6 +1,6 @@ - include $(top_srcdir)/Makefile.decl - --INCLUDES = \ -+AM_CPPFLAGS = \ - -I$(top_srcdir) \ - -I$(top_srcdir)/library \ - -DKRB5_CONFIG=\""$(sysconfdir)/krb5.conf"\" \ --- -2.30.2 - diff --git a/0001-coverity-add-missing-NULL-checks.patch b/0001-coverity-add-missing-NULL-checks.patch deleted file mode 100644 index cb6c77b..0000000 --- a/0001-coverity-add-missing-NULL-checks.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 3c652910d05616ee12c710e2071fc884dde4eaea Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 2 Jun 2021 13:39:31 +0200 -Subject: [PATCH 1/2] coverity: add missing NULL checks - ---- - library/adenroll.c | 2 ++ - library/adldap.c | 7 +++++++ - 2 files changed, 9 insertions(+) - -diff --git a/library/adenroll.c b/library/adenroll.c -index 2b830a4..0f3e8b9 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -3060,6 +3060,8 @@ adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll, - krb5_enctype *newval = NULL; - int len; - -+ return_if_fail (enroll != NULL); -+ - if (value) { - for (len = 0; value[len] != 0; len++); - newval = malloc (sizeof (krb5_enctype) * (len + 1)); -diff --git a/library/adldap.c b/library/adldap.c -index d93efb7..b86014c 100644 ---- a/library/adldap.c -+++ b/library/adldap.c -@@ -231,6 +231,13 @@ _adcli_ldap_have_in_mod (LDAPMod *mod, - - vals = malloc (sizeof (struct berval) * (count + 1)); - pvals = malloc (sizeof (struct berval *) * (count + 1)); -+ if (vals == NULL || pvals == NULL) { -+ _adcli_err ("Memory allocation failed, assuming attribute must be updated."); -+ free (vals); -+ free (pvals); -+ return 0; -+ } -+ - for (i = 0; i < count; i++) { - vals[i].bv_val = mod->mod_vals.modv_strvals[i]; - vals[i].bv_len = strlen (vals[i].bv_val); --- -2.31.1 - diff --git a/0001-library-move-UAC-flags-to-a-more-common-header-file.patch b/0001-library-move-UAC-flags-to-a-more-common-header-file.patch deleted file mode 100644 index aea2a99..0000000 --- a/0001-library-move-UAC-flags-to-a-more-common-header-file.patch +++ /dev/null @@ -1,51 +0,0 @@ -From a7a40ce4f47fe40305624b6d86c135b7d27c387d Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 11 Jun 2021 12:44:36 +0200 -Subject: [PATCH 1/5] library: move UAC flags to a more common header file - ---- - library/adenroll.c | 8 -------- - library/adprivate.h | 8 ++++++++ - 2 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/library/adenroll.c b/library/adenroll.c -index f00d179..0b1c066 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -93,14 +93,6 @@ static char *default_ad_ldap_attrs[] = { - NULL, - }; - --/* Some constants for the userAccountControl AD LDAP attribute, see e.g. -- * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro -- * for details. */ --#define UAC_ACCOUNTDISABLE 0x0002 --#define UAC_WORKSTATION_TRUST_ACCOUNT 0x1000 --#define UAC_DONT_EXPIRE_PASSWORD 0x10000 --#define UAC_TRUSTED_FOR_DELEGATION 0x80000 -- - struct _adcli_enroll { - int refs; - adcli_conn *conn; -diff --git a/library/adprivate.h b/library/adprivate.h -index 55e6234..822f919 100644 ---- a/library/adprivate.h -+++ b/library/adprivate.h -@@ -39,6 +39,14 @@ - #define HOST_NAME_MAX 255 - #endif - -+/* Some constants for the userAccountControl AD LDAP attribute, see e.g. -+ * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro -+ * for details. */ -+#define UAC_ACCOUNTDISABLE 0x0002 -+#define UAC_WORKSTATION_TRUST_ACCOUNT 0x1000 -+#define UAC_DONT_EXPIRE_PASSWORD 0x10000 -+#define UAC_TRUSTED_FOR_DELEGATION 0x80000 -+ - /* Utilities */ - - #if !defined(__cplusplus) && (__GNUC__ > 2) --- -2.31.1 - diff --git a/0002-Add-dont-expire-password-option.patch b/0002-Add-dont-expire-password-option.patch deleted file mode 100644 index 5189f40..0000000 --- a/0002-Add-dont-expire-password-option.patch +++ /dev/null @@ -1,229 +0,0 @@ -From a78116ba0e608050f391223bad3834d48c9adf1b Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Wed, 2 Jun 2021 17:24:07 +0200 -Subject: [PATCH 2/2] Add dont-expire-password option - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1769644 ---- - doc/adcli.xml | 28 ++++++++++++++++++++++++++++ - library/adenroll.c | 44 +++++++++++++++++++++++++++++++++++++++++++- - library/adenroll.h | 4 ++++ - tools/computer.c | 12 ++++++++++++ - 4 files changed, 87 insertions(+), 1 deletion(-) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 8ec48d4..1ed5d3f 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -347,6 +347,20 @@ Password for Administrator: - not allow that Kerberos tickets can be forwarded to the - host. - -+ -+ -+ Set or unset the DONT_EXPIRE_PASSWORD -+ flag in the userAccountControl attribute to indicate if -+ the machine account password should expire or not. By -+ default adcli will set this flag while joining the -+ domain which corresponds to the default behavior of -+ Windows clients. -+ Please note that if the password will expire -+ (--dont-expire-password=false) a renewal mechanism has -+ to be enabled on the client to not loose the -+ connectivity to AD if the password expires. -+ -+ - - - Add a service principal name. In -@@ -491,6 +505,20 @@ $ adcli update --login-ccache=/tmp/krbcc_123 - not allow that Kerberos tickets can be forwarded to the - host. - -+ -+ -+ Set or unset the DONT_EXPIRE_PASSWORD -+ flag in the userAccountControl attribute to indicate if -+ the machine account password should expire or not. By -+ default adcli will set this flag while joining the -+ domain which corresponds to the default behavior of -+ Windows clients. -+ Please note that if the password will expire -+ (--dont-expire-password=false) a renewal mechanism has -+ to be enabled on the client to not loose the -+ connectivity to AD if the password expires. -+ -+ - - - Set or unset the ACCOUNTDISABLE -diff --git a/library/adenroll.c b/library/adenroll.c -index 0f3e8b9..7653f89 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -153,6 +153,8 @@ struct _adcli_enroll { - char *samba_data_tool; - bool trusted_for_delegation; - int trusted_for_delegation_explicit; -+ bool dont_expire_password; -+ int dont_expire_password_explicit; - bool account_disable; - int account_disable_explicit; - char *description; -@@ -832,6 +834,8 @@ create_computer_account (adcli_enroll *enroll, - int ret; - size_t c; - size_t m; -+ uint32_t uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD ; -+ char *uac_str = NULL; - - LDAPMod *all_mods[] = { - &objectClass, -@@ -852,11 +856,21 @@ create_computer_account (adcli_enroll *enroll, - LDAPMod *mods[mods_count]; - - if (adcli_enroll_get_trusted_for_delegation (enroll)) { -- vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */ -+ uac |= UAC_TRUSTED_FOR_DELEGATION; - } - -+ if (!adcli_enroll_get_dont_expire_password (enroll)) { -+ uac &= ~(UAC_DONT_EXPIRE_PASSWORD); -+ } -+ -+ if (asprintf (&uac_str, "%d", uac) < 0) { -+ return_val_if_reached (ADCLI_ERR_UNEXPECTED); -+ } -+ vals_userAccountControl[0] = uac_str; -+ - ret = calculate_enctypes (enroll, &val); - if (ret != ADCLI_SUCCESS) { -+ free (uac_str); - return ret; - } - vals_supportedEncryptionTypes[0] = val; -@@ -871,6 +885,7 @@ create_computer_account (adcli_enroll *enroll, - mods[m] = NULL; - - ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL); -+ free (uac_str); - free (val); - - /* -@@ -1577,6 +1592,14 @@ static char *get_user_account_control (adcli_enroll *enroll) - } - } - -+ if (enroll->dont_expire_password_explicit) { -+ if (adcli_enroll_get_dont_expire_password (enroll)) { -+ uac |= UAC_DONT_EXPIRE_PASSWORD; -+ } else { -+ uac &= ~(UAC_DONT_EXPIRE_PASSWORD); -+ } -+ } -+ - if (enroll->account_disable_explicit) { - if (adcli_enroll_get_account_disable (enroll)) { - uac |= UAC_ACCOUNTDISABLE; -@@ -1627,6 +1650,7 @@ update_computer_account (adcli_enroll *enroll) - free (value); - - if (res == ADCLI_SUCCESS && (enroll->trusted_for_delegation_explicit || -+ enroll->dont_expire_password_explicit || - enroll->account_disable_explicit)) { - char *vals_userAccountControl[] = { NULL , NULL }; - LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } }; -@@ -3208,6 +3232,24 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll, - enroll->trusted_for_delegation_explicit = 1; - } - -+bool -+adcli_enroll_get_dont_expire_password (adcli_enroll *enroll) -+{ -+ return_val_if_fail (enroll != NULL, false); -+ -+ return enroll->dont_expire_password; -+} -+ -+void -+adcli_enroll_set_dont_expire_password (adcli_enroll *enroll, -+ bool value) -+{ -+ return_if_fail (enroll != NULL); -+ -+ enroll->dont_expire_password = value; -+ enroll->dont_expire_password_explicit = 1; -+} -+ - bool - adcli_enroll_get_account_disable (adcli_enroll *enroll) - { -diff --git a/library/adenroll.h b/library/adenroll.h -index 8b1c1c7..34dc683 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -126,6 +126,10 @@ bool adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll - void adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll, - bool value); - -+bool adcli_enroll_get_dont_expire_password (adcli_enroll *enroll); -+void adcli_enroll_set_dont_expire_password (adcli_enroll *enroll, -+ bool value); -+ - bool adcli_enroll_get_account_disable (adcli_enroll *enroll); - void adcli_enroll_set_account_disable (adcli_enroll *enroll, - bool value); -diff --git a/tools/computer.c b/tools/computer.c -index 6e309d9..16a1983 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -110,6 +110,7 @@ typedef enum { - opt_add_samba_data, - opt_samba_data_tool, - opt_trusted_for_delegation, -+ opt_dont_expire_password, - opt_add_service_principal, - opt_remove_service_principal, - opt_description, -@@ -144,6 +145,8 @@ static adcli_tool_desc common_usages[] = { - { opt_computer_password_lifetime, "lifetime of the host accounts password in days", }, - { opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n" - "in the userAccountControl attribute", }, -+ { opt_dont_expire_password, "set/unset the DONT_EXPIRE_PASSWORD flag\n" -+ "in the userAccountControl attribute", }, - { opt_account_disable, "set/unset the ACCOUNTDISABLE flag\n" - "in the userAccountControl attribute", }, - { opt_add_service_principal, "add the given service principal to the account\n" }, -@@ -307,6 +310,13 @@ parse_option (Option opt, - adcli_enroll_set_trusted_for_delegation (enroll, false); - } - return ADCLI_SUCCESS; -+ case opt_dont_expire_password: -+ if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) { -+ adcli_enroll_set_dont_expire_password (enroll, true); -+ } else { -+ adcli_enroll_set_dont_expire_password (enroll, false); -+ } -+ return ADCLI_SUCCESS; - case opt_account_disable: - if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) { - adcli_enroll_set_account_disable (enroll, true); -@@ -393,6 +403,7 @@ adcli_tool_computer_join (adcli_conn *conn, - { "description", optional_argument, NULL, opt_description }, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, -+ { "dont-expire-password", required_argument, NULL, opt_dont_expire_password }, - { "add-service-principal", required_argument, NULL, opt_add_service_principal }, - { "show-details", no_argument, NULL, opt_show_details }, - { "show-password", no_argument, NULL, opt_show_password }, -@@ -516,6 +527,7 @@ adcli_tool_computer_update (adcli_conn *conn, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, -+ { "dont-expire-password", required_argument, NULL, opt_dont_expire_password }, - { "account-disable", required_argument, NULL, opt_account_disable }, - { "add-service-principal", required_argument, NULL, opt_add_service_principal }, - { "remove-service-principal", required_argument, NULL, opt_remove_service_principal }, --- -2.31.1 - diff --git a/0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch b/0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch deleted file mode 100644 index cb92099..0000000 --- a/0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 7148ab196d0a96ede9b5ef463b0481d0fe372b21 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 11 Jun 2021 12:46:03 +0200 -Subject: [PATCH 2/5] adcli_entry: add entry_attrs with userAccountControl - attribute - ---- - library/adentry.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/library/adentry.c b/library/adentry.c -index 1cc0518..13dcaf8 100644 ---- a/library/adentry.c -+++ b/library/adentry.c -@@ -42,6 +42,7 @@ struct _adcli_entry { - char *entry_dn; - char *domain_ou; - char *entry_container; -+ LDAPMessage *entry_attrs; - }; - - static adcli_entry * -@@ -63,6 +64,7 @@ entry_new (adcli_conn *conn, - - entry->builder = builder; - entry->object_class = object_class; -+ entry->entry_attrs = NULL; - return entry; - } - -@@ -82,6 +84,7 @@ entry_free (adcli_entry *entry) - free (entry->entry_container); - free (entry->entry_dn); - free (entry->domain_ou); -+ ldap_msgfree (entry->entry_attrs); - adcli_conn_unref (entry->conn); - free (entry); - } -@@ -102,7 +105,7 @@ static adcli_result - update_entry_from_domain (adcli_entry *entry, - LDAP *ldap) - { -- const char *attrs[] = { "1.1", NULL }; -+ const char *attrs[] = { "userAccountControl", NULL }; - LDAPMessage *results; - LDAPMessage *first; - const char *base; -@@ -139,7 +142,8 @@ update_entry_from_domain (adcli_entry *entry, - return_unexpected_if_fail (entry->entry_dn != NULL); - } - -- ldap_msgfree (results); -+ ldap_msgfree (entry->entry_attrs); -+ entry->entry_attrs = results; - return ADCLI_SUCCESS; - } - --- -2.31.1 - diff --git a/0003-entry-add-passwd-user-sub-command.patch b/0003-entry-add-passwd-user-sub-command.patch deleted file mode 100644 index 7ad5111..0000000 --- a/0003-entry-add-passwd-user-sub-command.patch +++ /dev/null @@ -1,366 +0,0 @@ -From 6a673b236dfdfdf9c73cc3d2ccf3949eb1a5ddd0 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 11 Jun 2021 12:47:37 +0200 -Subject: [PATCH 3/5] entry: add passwd-user sub-command - -The new command allows to set or reset a user password with the help of -an account privileged to set the password. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1952828 ---- - doc/adcli.xml | 20 +++++++ - library/adentry.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++ - library/adentry.h | 3 + - tools/entry.c | 99 +++++++++++++++++++++++++++++++++ - tools/tools.c | 1 + - tools/tools.h | 4 ++ - 6 files changed, 265 insertions(+) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 1ed5d3f..6c36297 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -56,6 +56,11 @@ - --domain=domain.example.com - user - -+ -+ adcli passwd-user -+ --domain=domain.example.com -+ user -+ - - adcli create-group - --domain=domain.example.com -@@ -696,6 +701,21 @@ $ adcli delete-user Fry --domain=domain.example.com - - - -+ -+ (Re)setting the password of a User with an Administrative Account -+ -+ adcli passwd-user sets or resets the password -+ of user account. The administrative account used for this operation -+ must have privileges to set a password. -+ -+ -+$ adcli passwd-user Fry --domain=domain.example.com -+ -+ -+ The various global options can be used. -+ -+ -+ - - - Creating a Group -diff --git a/library/adentry.c b/library/adentry.c -index 13dcaf8..0d9b9af 100644 ---- a/library/adentry.c -+++ b/library/adentry.c -@@ -409,6 +409,144 @@ adcli_entry_delete (adcli_entry *entry) - return ADCLI_SUCCESS; - } - -+static adcli_result -+adcli_entry_ensure_enabled (adcli_entry *entry) -+{ -+ adcli_result res; -+ LDAP *ldap; -+ adcli_attrs *attrs; -+ uint32_t uac = 0; -+ char *uac_str; -+ unsigned long attr_val; -+ char *end; -+ -+ return_unexpected_if_fail (entry->entry_attrs != NULL); -+ -+ ldap = adcli_conn_get_ldap_connection (entry->conn); -+ return_unexpected_if_fail (ldap != NULL); -+ -+ uac_str = _adcli_ldap_parse_value (ldap, entry->entry_attrs, -+ "userAccountControl"); -+ if (uac_str != NULL) { -+ attr_val = strtoul (uac_str, &end, 10); -+ if (*end != '\0' || attr_val > UINT32_MAX) { -+ _adcli_warn ("Invalid userAccountControl '%s' for %s account in directory: %s, assuming 0", -+ uac_str, entry->object_class, entry->entry_dn); -+ } else { -+ uac = attr_val; -+ } -+ free (uac_str); -+ } -+ if (uac & UAC_ACCOUNTDISABLE) { -+ uac &= ~(UAC_ACCOUNTDISABLE); -+ -+ if (asprintf (&uac_str, "%d", uac) < 0) { -+ _adcli_warn ("Cannot enable %s entry %s after password (re)set", -+ entry->object_class, entry->entry_dn); -+ return ADCLI_ERR_UNEXPECTED; -+ } -+ -+ attrs = adcli_attrs_new (); -+ adcli_attrs_replace (attrs, "userAccountControl", uac_str, -+ NULL); -+ res = adcli_entry_modify (entry, attrs); -+ if (res == ADCLI_SUCCESS) { -+ _adcli_info ("Enabled %s entry %s after password (re)set", -+ entry->object_class, entry->entry_dn); -+ } else { -+ _adcli_warn ("Failed to enable %s entry %s after password (re)set", -+ entry->object_class, entry->entry_dn); -+ } -+ free (uac_str); -+ adcli_attrs_free (attrs); -+ } else { -+ res = ADCLI_SUCCESS; -+ } -+ -+ return res; -+} -+ -+adcli_result -+adcli_entry_set_passwd (adcli_entry *entry, const char *user_pwd) -+{ -+ adcli_result res; -+ LDAP *ldap; -+ krb5_error_code code; -+ krb5_context k5; -+ krb5_ccache ccache; -+ krb5_data result_string = { 0, }; -+ krb5_data result_code_string = { 0, }; -+ int result_code; -+ char *message; -+ krb5_principal user_principal; -+ -+ ldap = adcli_conn_get_ldap_connection (entry->conn); -+ return_unexpected_if_fail (ldap != NULL); -+ -+ /* Find the user */ -+ res = update_entry_from_domain (entry, ldap); -+ if (res != ADCLI_SUCCESS) -+ return res; -+ -+ if (!entry->entry_dn) { -+ _adcli_err ("Cannot find the %s entry %s in the domain", -+ entry->object_class, entry->sam_name); -+ return ADCLI_ERR_CONFIG; -+ } -+ -+ k5 = adcli_conn_get_krb5_context (entry->conn); -+ return_unexpected_if_fail (k5 != NULL); -+ -+ code = _adcli_krb5_build_principal (k5, entry->sam_name, -+ adcli_conn_get_domain_realm (entry->conn), -+ &user_principal); -+ return_unexpected_if_fail (code == 0); -+ -+ ccache = adcli_conn_get_login_ccache (entry->conn); -+ return_unexpected_if_fail (ccache != NULL); -+ -+ memset (&result_string, 0, sizeof (result_string)); -+ memset (&result_code_string, 0, sizeof (result_code_string)); -+ -+ code = krb5_set_password_using_ccache (k5, ccache, user_pwd, -+ user_principal, &result_code, -+ &result_code_string, &result_string); -+ -+ 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)); -+ /* TODO: Parse out these values */ -+ res = ADCLI_ERR_DIRECTORY; -+ -+ } else if (result_code != 0) { -+#ifdef HAVE_KRB5_CHPW_MESSAGE -+ if (krb5_chpw_message (k5, &result_string, &message) != 0) -+ message = NULL; -+#else -+ message = NULL; -+ if (result_string.length) -+ message = _adcli_str_dupn (result_string.data, result_string.length); -+#endif -+ _adcli_err ("Cannot set %s password: %.*s%s%s", -+ entry->object_class, -+ (int)result_code_string.length, result_code_string.data, -+ message ? ": " : "", message ? message : ""); -+ res = ADCLI_ERR_CREDENTIALS; -+#ifdef HAVE_KRB5_CHPW_MESSAGE -+ krb5_free_string (k5, message); -+#else -+ free (message); -+#endif -+ } else { -+ _adcli_info ("Password (re)setted for %s: %s", entry->object_class, entry->entry_dn); -+ -+ res = adcli_entry_ensure_enabled (entry); -+ } -+ -+ return res; -+} -+ - const char * - adcli_entry_get_sam_name (adcli_entry *entry) - { -diff --git a/library/adentry.h b/library/adentry.h -index ae90689..f2382b1 100644 ---- a/library/adentry.h -+++ b/library/adentry.h -@@ -49,6 +49,9 @@ adcli_result adcli_entry_modify (adcli_entry *entry, - - adcli_result adcli_entry_delete (adcli_entry *entry); - -+adcli_result adcli_entry_set_passwd (adcli_entry *entry, -+ const char *user_pwd); -+ - const char * adcli_entry_get_domain_ou (adcli_entry *entry); - - void adcli_entry_set_domain_ou (adcli_entry *entry, -diff --git a/tools/entry.c b/tools/entry.c -index 05e4313..52d2546 100644 ---- a/tools/entry.c -+++ b/tools/entry.c -@@ -24,6 +24,7 @@ - #include "config.h" - - #include "adcli.h" -+#include "adprivate.h" - #include "adattrs.h" - #include "tools.h" - -@@ -385,6 +386,104 @@ adcli_tool_user_delete (adcli_conn *conn, - return 0; - } - -+int -+adcli_tool_user_passwd (adcli_conn *conn, -+ int argc, -+ char *argv[]) -+{ -+ adcli_result res; -+ adcli_entry *entry; -+ int opt; -+ char *user_pwd = NULL; -+ -+ struct option options[] = { -+ { "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 }, -+ { "stdin-password", no_argument, 0, opt_stdin_password }, -+ { "prompt-password", no_argument, 0, opt_prompt_password }, -+ { "verbose", no_argument, NULL, opt_verbose }, -+ { "help", no_argument, NULL, 'h' }, -+ { 0 }, -+ }; -+ -+ static adcli_tool_desc usages[] = { -+ { 0, "usage: adcli passwd-user --domain=xxxx user" }, -+ { 0 }, -+ }; -+ -+ while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) { -+ switch (opt) { -+ case 'h': -+ case '?': -+ case ':': -+ adcli_tool_usage (options, usages); -+ adcli_tool_usage (options, common_usages); -+ return opt == 'h' ? 0 : 2; -+ default: -+ res = parse_option ((Option)opt, optarg, conn); -+ if (res != ADCLI_SUCCESS) { -+ return res; -+ } -+ break; -+ } -+ } -+ -+ argc -= optind; -+ argv += optind; -+ -+ if (argc != 1) { -+ warnx ("specify one user name to (re)set password"); -+ return 2; -+ } -+ -+ entry = adcli_entry_new_user (conn, argv[0]); -+ if (entry == NULL) { -+ warnx ("unexpected memory problems"); -+ return -1; -+ } -+ -+ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT); -+ -+ res = adcli_conn_connect (conn); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("couldn't connect to %s domain: %s", -+ adcli_conn_get_domain_name (conn), -+ adcli_get_last_error ()); -+ adcli_entry_unref (entry); -+ return -res; -+ } -+ -+ user_pwd = adcli_prompt_password_func (ADCLI_LOGIN_USER_ACCOUNT, -+ adcli_entry_get_sam_name(entry), -+ 0, NULL); -+ if (user_pwd == NULL || *user_pwd == '\0') { -+ warnx ("missing password"); -+ _adcli_password_free (user_pwd); -+ adcli_entry_unref (entry); -+ return 2; -+ } -+ -+ res = adcli_entry_set_passwd (entry, user_pwd); -+ _adcli_password_free (user_pwd); -+ if (res != ADCLI_SUCCESS) { -+ warnx ("(re)setting password for user %s in domain %s failed: %s", -+ adcli_entry_get_sam_name (entry), -+ adcli_conn_get_domain_name (conn), -+ adcli_get_last_error ()); -+ adcli_entry_unref (entry); -+ return -res; -+ } -+ -+ adcli_entry_unref (entry); -+ -+ return 0; -+} -+ - int - adcli_tool_group_create (adcli_conn *conn, - int argc, -diff --git a/tools/tools.c b/tools/tools.c -index 84bbba9..a14b9ca 100644 ---- a/tools/tools.c -+++ b/tools/tools.c -@@ -63,6 +63,7 @@ struct { - { "create-msa", adcli_tool_computer_managed_service_account, "Create a managed service account in the given AD domain", }, - { "create-user", adcli_tool_user_create, "Create a user account", }, - { "delete-user", adcli_tool_user_delete, "Delete a user account", }, -+ { "passwd-user", adcli_tool_user_passwd, "(Re)set a user password", }, - { "create-group", adcli_tool_group_create, "Create a group", }, - { "delete-group", adcli_tool_group_delete, "Delete a group", }, - { "add-member", adcli_tool_member_add, "Add users to a group", }, -diff --git a/tools/tools.h b/tools/tools.h -index 82d5e4e..d38aa32 100644 ---- a/tools/tools.h -+++ b/tools/tools.h -@@ -94,6 +94,10 @@ int adcli_tool_user_delete (adcli_conn *conn, - int argc, - char *argv[]); - -+int adcli_tool_user_passwd (adcli_conn *conn, -+ int argc, -+ char *argv[]); -+ - int adcli_tool_group_create (adcli_conn *conn, - int argc, - char *argv[]); --- -2.31.1 - diff --git a/0004-Add-setattr-option.patch b/0004-Add-setattr-option.patch deleted file mode 100644 index 7976e7c..0000000 --- a/0004-Add-setattr-option.patch +++ /dev/null @@ -1,386 +0,0 @@ -From c5b0cee2976682b4fc1aeb02636cc9f2c6dbc2a5 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 14 Jun 2021 07:54:01 +0200 -Subject: [PATCH 4/5] Add setattr option - -With the new option common LDAP attributes can be set. - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1690920 ---- - doc/adcli.xml | 34 +++++++++ - library/adenroll.c | 169 ++++++++++++++++++++++++++++++++++++++++++++- - library/adenroll.h | 4 ++ - tools/computer.c | 10 +++ - 4 files changed, 216 insertions(+), 1 deletion(-) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 6c36297..8383aa7 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -374,6 +374,23 @@ Password for Administrator: - service should be accessible with a different host - name as well. - -+ -+ -+ Add the LDAP attribute -+ with the -+ given to -+ the new LDAP host object. -+ This option can be used multiple times to add multiple -+ different attributes. Multi-value attributes are -+ currently not supported. -+ Please note that the account used to join the -+ domain must have the required privileges to add the -+ given attributes. Some attributes might have -+ constraints with respect to syntax and allowed values -+ which must be met as well. Attributes managed by other -+ adcli options cannot be set with this option. -+ -+ - - - After a successful join print out information -@@ -543,6 +560,23 @@ $ adcli update --login-ccache=/tmp/krbcc_123 - Remove a service principal name from - the keytab and the AD host object. - -+ -+ -+ Add the LDAP attribute -+ with the -+ given to -+ the LDAP host object. -+ This option can be used multiple times to add multiple -+ different attributes. Multi-value attributes are -+ currently not supported. -+ Please note that the account used to update the -+ host object must have the required privileges to modify -+ the given attributes. Some attributes might have -+ constraints with respect to syntax and allowed values -+ which must be met as well. Attributes managed by other -+ adcli options cannot be set with this option. -+ -+ - - - After a successful join print out information -diff --git a/library/adenroll.c b/library/adenroll.c -index 0b1c066..dd51567 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -150,6 +150,7 @@ struct _adcli_enroll { - bool account_disable; - int account_disable_explicit; - char *description; -+ char **setattr; - }; - - static const char * -@@ -795,6 +796,56 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype) - return ADCLI_SUCCESS; - } - -+static LDAPMod ** -+get_mods_for_attrs (adcli_enroll *enroll, int mod_op) -+{ -+ size_t len; -+ size_t c; -+ char *end; -+ LDAPMod **mods = NULL; -+ -+ len = _adcli_strv_len (enroll->setattr); -+ if (len == 0) { -+ return NULL; -+ } -+ -+ mods = calloc (len + 1, sizeof (LDAPMod *)); -+ return_val_if_fail (mods != NULL, NULL); -+ -+ for (c = 0; c < len; c++) { -+ end = strchr (enroll->setattr[c], '='); -+ if (end == NULL) { -+ ldap_mods_free (mods, 1); -+ return NULL; -+ } -+ -+ mods[c] = calloc (1, sizeof (LDAPMod)); -+ if (mods[c] == NULL) { -+ ldap_mods_free (mods, 1); -+ return NULL; -+ } -+ -+ mods[c]->mod_op = mod_op; -+ *end = '\0'; -+ mods[c]->mod_type = strdup (enroll->setattr[c]); -+ *end = '='; -+ mods[c]->mod_values = calloc (2, sizeof (char *)); -+ if (mods[c]->mod_type == NULL || mods[c]->mod_values == NULL) { -+ ldap_mods_free (mods, 1); -+ return NULL; -+ } -+ -+ mods[c]->mod_values[0] = strdup (end + 1); -+ if (mods[c]->mod_values[0] == NULL) { -+ ldap_mods_free (mods, 1); -+ return NULL; -+ } -+ } -+ -+ return mods; -+} -+ -+ - static adcli_result - create_computer_account (adcli_enroll *enroll, - LDAP *ldap) -@@ -828,6 +879,7 @@ create_computer_account (adcli_enroll *enroll, - size_t m; - uint32_t uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD ; - char *uac_str = NULL; -+ LDAPMod **extra_mods = NULL; - - LDAPMod *all_mods[] = { - &objectClass, -@@ -845,7 +897,7 @@ create_computer_account (adcli_enroll *enroll, - }; - - size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *); -- LDAPMod *mods[mods_count]; -+ LDAPMod **mods; - - if (adcli_enroll_get_trusted_for_delegation (enroll)) { - uac |= UAC_TRUSTED_FOR_DELEGATION; -@@ -868,6 +920,17 @@ create_computer_account (adcli_enroll *enroll, - } - vals_supportedEncryptionTypes[0] = val; - -+ if (enroll->setattr != NULL) { -+ extra_mods = get_mods_for_attrs (enroll, LDAP_MOD_ADD); -+ if (extra_mods == NULL) { -+ _adcli_err ("Failed to add setattr attributes, " -+ "just using defaults"); -+ } -+ } -+ -+ mods = calloc (mods_count + seq_count (extra_mods) + 1, sizeof (LDAPMod *)); -+ return_val_if_fail (mods != NULL, ADCLI_ERR_UNEXPECTED); -+ - m = 0; - for (c = 0; c < mods_count - 1; c++) { - /* Skip empty LDAP sttributes */ -@@ -875,9 +938,15 @@ create_computer_account (adcli_enroll *enroll, - mods[m++] = all_mods[c]; - } - } -+ -+ for (c = 0; c < seq_count (extra_mods); c++) { -+ mods[m++] = extra_mods[c]; -+ } - mods[m] = NULL; - - ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL); -+ ldap_mods_free (extra_mods, 1); -+ free (mods); - free (uac_str); - free (val); - -@@ -1698,6 +1767,14 @@ update_computer_account (adcli_enroll *enroll) - res |= update_computer_attribute (enroll, ldap, mods); - } - -+ if (res == ADCLI_SUCCESS && enroll->setattr != NULL) { -+ LDAPMod **mods = get_mods_for_attrs (enroll, LDAP_MOD_REPLACE); -+ if (mods != NULL) { -+ res |= update_computer_attribute (enroll, ldap, mods); -+ ldap_mods_free (mods, 1); -+ } -+ } -+ - if (res != 0) - _adcli_info ("Updated existing computer account: %s", enroll->computer_dn); - } -@@ -2751,6 +2828,7 @@ enroll_free (adcli_enroll *enroll) - free (enroll->user_principal); - _adcli_strv_free (enroll->service_names); - _adcli_strv_free (enroll->service_principals); -+ _adcli_strv_free (enroll->setattr); - _adcli_password_free (enroll->computer_password); - - adcli_enroll_set_keytab_name (enroll, NULL); -@@ -3332,6 +3410,72 @@ adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll, - return_if_fail (enroll->service_principals_to_remove != NULL); - } - -+static int comp_attr_name (const char *s1, const char *s2) -+{ -+ size_t c = 0; -+ -+ /* empty strings cannot contain an attribute name */ -+ if (s1 == NULL || s2 == NULL || *s1 == '\0' || *s2 == '\0') { -+ return 1; -+ } -+ -+ for (c = 0 ; s1[c] != '\0' && s2[c] != '\0'; c++) { -+ if (s1[c] == '=' && s2[c] == '=') { -+ return 0; -+ } else if (tolower (s1[c]) != tolower (s2[c])) { -+ return 1; -+ } -+ } -+ -+ return 1; -+} -+ -+adcli_result -+adcli_enroll_add_setattr (adcli_enroll *enroll, const char *value) -+{ -+ char *delim; -+ -+ return_val_if_fail (enroll != NULL, ADCLI_ERR_CONFIG); -+ return_val_if_fail (value != NULL, ADCLI_ERR_CONFIG); -+ -+ delim = strchr (value, '='); -+ if (delim == NULL) { -+ _adcli_err ("Missing '=' in setattr option [%s]", value); -+ return ADCLI_ERR_CONFIG; -+ } -+ -+ if (*(delim + 1) == '\0') { -+ _adcli_err ("Missing value in setattr option [%s]", value); -+ return ADCLI_ERR_CONFIG; -+ } -+ -+ *delim = '\0'; -+ if (_adcli_strv_has_ex (default_ad_ldap_attrs, value, strcasecmp) == 1) { -+ _adcli_err ("Attribute [%s] cannot be set with setattr", value); -+ return ADCLI_ERR_CONFIG; -+ } -+ *delim = '='; -+ -+ if (_adcli_strv_has_ex (enroll->setattr, value, comp_attr_name) == 1) { -+ _adcli_err ("Attribute [%s] already set", value); -+ return ADCLI_ERR_CONFIG; -+ } -+ -+ enroll->setattr = _adcli_strv_add (enroll->setattr, strdup (value), -+ NULL); -+ return_val_if_fail (enroll->setattr != NULL, ADCLI_ERR_CONFIG); -+ -+ return ADCLI_SUCCESS; -+} -+ -+const char ** -+adcli_enroll_get_setattr (adcli_enroll *enroll) -+{ -+ return_val_if_fail (enroll != NULL, NULL); -+ return (const char **) enroll->setattr; -+} -+ -+ - #ifdef ADENROLL_TESTS - - #include "test.h" -@@ -3401,12 +3545,35 @@ test_adcli_enroll_get_permitted_keytab_enctypes (void) - adcli_conn_unref (conn); - } - -+static void -+test_comp_attr_name (void) -+{ -+ assert_num_eq (1, comp_attr_name (NULL ,NULL)); -+ assert_num_eq (1, comp_attr_name ("" ,NULL)); -+ assert_num_eq (1, comp_attr_name ("" ,"")); -+ assert_num_eq (1, comp_attr_name (NULL ,"")); -+ assert_num_eq (1, comp_attr_name (NULL ,"abc=xyz")); -+ assert_num_eq (1, comp_attr_name ("" ,"abc=xyz")); -+ assert_num_eq (1, comp_attr_name ("abc=xyz", NULL)); -+ assert_num_eq (1, comp_attr_name ("abc=xyz", "")); -+ assert_num_eq (1, comp_attr_name ("abc=xyz", "ab=xyz")); -+ assert_num_eq (1, comp_attr_name ("ab=xyz", "abc=xyz")); -+ assert_num_eq (1, comp_attr_name ("abcxyz", "abc=xyz")); -+ assert_num_eq (1, comp_attr_name ("abc=xyz", "abcxyz")); -+ assert_num_eq (1, comp_attr_name ("abc=xyz", "a")); -+ assert_num_eq (1, comp_attr_name ("a", "abc=xyz")); -+ -+ assert_num_eq (0, comp_attr_name ("abc=xyz", "abc=xyz")); -+ assert_num_eq (0, comp_attr_name ("abc=xyz", "abc=123")); -+} -+ - int - main (int argc, - char *argv[]) - { - test_func (test_adcli_enroll_get_permitted_keytab_enctypes, - "/attrs/adcli_enroll_get_permitted_keytab_enctypes"); -+ test_func (test_comp_attr_name, "/attrs/comp_attr_name"); - return test_run (argc, argv); - } - -diff --git a/library/adenroll.h b/library/adenroll.h -index 34dc683..862bb60 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -138,6 +138,10 @@ const char * adcli_enroll_get_desciption (adcli_enroll *enroll); - void adcli_enroll_set_description (adcli_enroll *enroll, - const char *value); - -+const char ** adcli_enroll_get_setattr (adcli_enroll *enroll); -+adcli_result adcli_enroll_add_setattr (adcli_enroll *enroll, -+ const char *value); -+ - bool adcli_enroll_get_is_service (adcli_enroll *enroll); - void adcli_enroll_set_is_service (adcli_enroll *enroll, - bool value); -diff --git a/tools/computer.c b/tools/computer.c -index 16a1983..af38894 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -114,6 +114,7 @@ typedef enum { - opt_add_service_principal, - opt_remove_service_principal, - opt_description, -+ opt_setattr, - opt_use_ldaps, - opt_account_disable, - } Option; -@@ -152,6 +153,7 @@ static adcli_tool_desc common_usages[] = { - { opt_add_service_principal, "add the given service principal to the account\n" }, - { opt_remove_service_principal, "remove the given service principal from the account\n" }, - { opt_description, "add a description to the account\n" }, -+ { opt_setattr, "add an attribute with a value\n" }, - { opt_no_password, "don't prompt for or read a password" }, - { opt_prompt_password, "prompt for a password if necessary" }, - { opt_stdin_password, "read a password from stdin (until EOF) if\n" -@@ -333,6 +335,12 @@ parse_option (Option opt, - case opt_description: - adcli_enroll_set_description (enroll, optarg); - return ADCLI_SUCCESS; -+ case opt_setattr: -+ ret = adcli_enroll_add_setattr (enroll, optarg); -+ if (ret != ADCLI_SUCCESS) { -+ warnx ("parsing setattr option failed"); -+ } -+ return ret; - case opt_use_ldaps: - adcli_conn_set_use_ldaps (conn, true); - return ADCLI_SUCCESS; -@@ -401,6 +409,7 @@ adcli_tool_computer_join (adcli_conn *conn, - { "os-version", required_argument, NULL, opt_os_version }, - { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, - { "description", optional_argument, NULL, opt_description }, -+ { "setattr", required_argument, NULL, opt_setattr }, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, - { "dont-expire-password", required_argument, NULL, opt_dont_expire_password }, -@@ -524,6 +533,7 @@ adcli_tool_computer_update (adcli_conn *conn, - { "os-version", required_argument, NULL, opt_os_version }, - { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, - { "description", optional_argument, NULL, opt_description }, -+ { "setattr", required_argument, NULL, opt_setattr }, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, --- -2.31.1 - diff --git a/0005-Add-delattr-option.patch b/0005-Add-delattr-option.patch deleted file mode 100644 index ee72cfe..0000000 --- a/0005-Add-delattr-option.patch +++ /dev/null @@ -1,192 +0,0 @@ -From cd5b6cdcf3e6bfc5776f2865f460f608421dfa3f Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Mon, 14 Jun 2021 08:42:21 +0200 -Subject: [PATCH 5/5] Add delattr option - -Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1690920 ---- - doc/adcli.xml | 11 ++++++++ - library/adenroll.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ - library/adenroll.h | 4 +++ - tools/computer.c | 9 +++++++ - 4 files changed, 90 insertions(+) - -diff --git a/doc/adcli.xml b/doc/adcli.xml -index 8383aa7..bcf4857 100644 ---- a/doc/adcli.xml -+++ b/doc/adcli.xml -@@ -577,6 +577,17 @@ $ adcli update --login-ccache=/tmp/krbcc_123 - adcli options cannot be set with this option. - - -+ -+ -+ Remove the LDAP attribute -+ from the -+ LDAP host object. This option can be used multiple -+ times to remove multiple different attributes. -+ Please note that the account used to update the -+ host object must have the required privileges to delete -+ the given attributes. Attributes managed by other adcli -+ options cannot be removed. -+ - - - After a successful join print out information -diff --git a/library/adenroll.c b/library/adenroll.c -index dd51567..9a06d52 100644 ---- a/library/adenroll.c -+++ b/library/adenroll.c -@@ -151,6 +151,7 @@ struct _adcli_enroll { - int account_disable_explicit; - char *description; - char **setattr; -+ char **delattr; - }; - - static const char * -@@ -845,6 +846,39 @@ get_mods_for_attrs (adcli_enroll *enroll, int mod_op) - return mods; - } - -+static LDAPMod ** -+get_del_mods_for_attrs (adcli_enroll *enroll, int mod_op) -+{ -+ size_t len; -+ size_t c; -+ LDAPMod **mods = NULL; -+ -+ len = _adcli_strv_len (enroll->delattr); -+ if (len == 0) { -+ return NULL; -+ } -+ -+ mods = calloc (len + 1, sizeof (LDAPMod *)); -+ return_val_if_fail (mods != NULL, NULL); -+ -+ for (c = 0; c < len; c++) { -+ mods[c] = calloc (1, sizeof (LDAPMod)); -+ if (mods[c] == NULL) { -+ ldap_mods_free (mods, 1); -+ return NULL; -+ } -+ -+ mods[c]->mod_op = mod_op; -+ mods[c]->mod_type = strdup (enroll->delattr[c]); -+ mods[c]->mod_values = NULL; -+ if (mods[c]->mod_type == NULL) { -+ ldap_mods_free (mods, 1); -+ return NULL; -+ } -+ } -+ -+ return mods; -+} - - static adcli_result - create_computer_account (adcli_enroll *enroll, -@@ -1775,6 +1809,14 @@ update_computer_account (adcli_enroll *enroll) - } - } - -+ if (res == ADCLI_SUCCESS && enroll->delattr != NULL) { -+ LDAPMod **mods = get_del_mods_for_attrs (enroll, LDAP_MOD_DELETE); -+ if (mods != NULL) { -+ res |= update_computer_attribute (enroll, ldap, mods); -+ ldap_mods_free (mods, 1); -+ } -+ } -+ - if (res != 0) - _adcli_info ("Updated existing computer account: %s", enroll->computer_dn); - } -@@ -3475,6 +3517,30 @@ adcli_enroll_get_setattr (adcli_enroll *enroll) - return (const char **) enroll->setattr; - } - -+adcli_result -+adcli_enroll_add_delattr (adcli_enroll *enroll, const char *value) -+{ -+ return_val_if_fail (enroll != NULL, ADCLI_ERR_CONFIG); -+ return_val_if_fail (value != NULL, ADCLI_ERR_CONFIG); -+ -+ if (_adcli_strv_has_ex (default_ad_ldap_attrs, value, strcasecmp) == 1) { -+ _adcli_err ("Attribute [%s] cannot be removed with delattr", value); -+ return ADCLI_ERR_CONFIG; -+ } -+ -+ enroll->delattr = _adcli_strv_add (enroll->delattr, strdup (value), -+ NULL); -+ return_val_if_fail (enroll->delattr != NULL, ADCLI_ERR_CONFIG); -+ -+ return ADCLI_SUCCESS; -+} -+ -+const char ** -+adcli_enroll_get_delattr (adcli_enroll *enroll) -+{ -+ return_val_if_fail (enroll != NULL, NULL); -+ return (const char **) enroll->delattr; -+} - - #ifdef ADENROLL_TESTS - -diff --git a/library/adenroll.h b/library/adenroll.h -index 862bb60..e3ada33 100644 ---- a/library/adenroll.h -+++ b/library/adenroll.h -@@ -142,6 +142,10 @@ const char ** adcli_enroll_get_setattr (adcli_enroll *enroll); - adcli_result adcli_enroll_add_setattr (adcli_enroll *enroll, - const char *value); - -+const char ** adcli_enroll_get_delattr (adcli_enroll *enroll); -+adcli_result adcli_enroll_add_delattr (adcli_enroll *enroll, -+ const char *value); -+ - bool adcli_enroll_get_is_service (adcli_enroll *enroll); - void adcli_enroll_set_is_service (adcli_enroll *enroll, - bool value); -diff --git a/tools/computer.c b/tools/computer.c -index af38894..dffeecb 100644 ---- a/tools/computer.c -+++ b/tools/computer.c -@@ -115,6 +115,7 @@ typedef enum { - opt_remove_service_principal, - opt_description, - opt_setattr, -+ opt_delattr, - opt_use_ldaps, - opt_account_disable, - } Option; -@@ -154,6 +155,7 @@ static adcli_tool_desc common_usages[] = { - { opt_remove_service_principal, "remove the given service principal from the account\n" }, - { opt_description, "add a description to the account\n" }, - { opt_setattr, "add an attribute with a value\n" }, -+ { opt_delattr, "remove an attribute\n" }, - { opt_no_password, "don't prompt for or read a password" }, - { opt_prompt_password, "prompt for a password if necessary" }, - { opt_stdin_password, "read a password from stdin (until EOF) if\n" -@@ -341,6 +343,12 @@ parse_option (Option opt, - warnx ("parsing setattr option failed"); - } - return ret; -+ case opt_delattr: -+ ret = adcli_enroll_add_delattr (enroll, optarg); -+ if (ret != ADCLI_SUCCESS) { -+ warnx ("parsing delattr option failed"); -+ } -+ return ret; - case opt_use_ldaps: - adcli_conn_set_use_ldaps (conn, true); - return ADCLI_SUCCESS; -@@ -534,6 +542,7 @@ adcli_tool_computer_update (adcli_conn *conn, - { "os-service-pack", optional_argument, NULL, opt_os_service_pack }, - { "description", optional_argument, NULL, opt_description }, - { "setattr", required_argument, NULL, opt_setattr }, -+ { "delattr", required_argument, NULL, opt_delattr }, - { "user-principal", optional_argument, NULL, opt_user_principal }, - { "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime }, - { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation }, --- -2.31.1 - diff --git a/adcli.spec b/adcli.spec index 89365c9..f36ed6b 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,22 +1,10 @@ Name: adcli -Version: 0.9.1 -Release: 11%{?dist} +Version: 0.9.2 +Release: 1%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli -Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee789194435e70fbf30/adcli-%{version}.tar.gz - -Patch1: 0001-build-add-with-vendor-error-message-configure-option.patch -Patch2: 0001-configure-update-some-macros-for-autoconf-2.71.patch -Patch3: 0001-coverity-add-missing-NULL-checks.patch -Patch4: 0002-Add-dont-expire-password-option.patch -Patch5: 0001-Fix-for-dont-expire-password-option-and-join.patch -Patch6: 0001-library-move-UAC-flags-to-a-more-common-header-file.patch -Patch7: 0002-adcli_entry-add-entry_attrs-with-userAccountControl-.patch -Patch8: 0003-entry-add-passwd-user-sub-command.patch -Patch9: 0004-Add-setattr-option.patch -Patch10: 0005-Add-delattr-option.patch -Patch11: 0001-configure-check-for-ns_get16-and-ns_get32-as-well.patch +Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/ea560656ac921b3fe0d455976aaae9be/adcli-%{version}.tar.gz BuildRequires: gcc @@ -82,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Thu Sep 29 2022 Sumit Bose - 0.9.2-1 +- Update to upstream release 0.9.2 + * Wed Jul 20 2022 Fedora Release Engineering - 0.9.1-11 - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild diff --git a/sources b/sources index d958e5d..1dd0180 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (adcli-0.9.1.tar.gz) = 60562720bf28f2dec06f272bdb875e3486f223e77f8a9e96b3468d17dbebdf9ddabd147d7e65c5de9ba7d4e8c033ad6d28a4012d03297c7de25b78ef4890746d +SHA512 (adcli-0.9.2.tar.gz) = 0953ffb940b9abdf6277731b3fa14656b9af5686902f1b8c44389c2537e6c33db5b5272061964cf60fd6a7831e581c5362bff89d0adddc9b17059ed3a30e3971 From b128d37655ad0077b41fd11d80f31cace4cbc956 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 18 Jan 2023 21:22:59 +0000 Subject: [PATCH 14/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index f36ed6b..fe23293 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -70,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jan 18 2023 Fedora Release Engineering - 0.9.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + * Thu Sep 29 2022 Sumit Bose - 0.9.2-1 - Update to upstream release 0.9.2 From e22d26d93ddb165b5c1b8fd2b4cfeffa44c8e371 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 19 Jul 2023 12:53:22 +0000 Subject: [PATCH 15/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild Signed-off-by: Fedora Release Engineering --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index fe23293..8819ccc 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 2%{?dist} +Release: 3%{?dist} Summary: Active Directory enrollment License: LGPLv2+ URL: https://gitlab.freedesktop.org/realmd/adcli @@ -70,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jul 19 2023 Fedora Release Engineering - 0.9.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + * Wed Jan 18 2023 Fedora Release Engineering - 0.9.2-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild From 7e8c213dc60f5bcfbafb1db0c803cae4a39016cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Wed, 5 May 2021 18:21:48 +0200 Subject: [PATCH 16/27] Use make macros --- adcli.spec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adcli.spec b/adcli.spec index 8819ccc..f1ff4d1 100644 --- a/adcli.spec +++ b/adcli.spec @@ -40,13 +40,13 @@ autoreconf --force --install --verbose --with-vendor-error-message='Please check\n https://red.ht/support_rhel_ad \nto get help for common issues.' \ %endif %{nil} -make %{?_smp_mflags} +%make_build %check make check %install -make install DESTDIR=%{buildroot} +%make_install find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';' %ldconfig_scriptlets From 2498cfad651c337feb4a5f80e4d59dbf724fb498 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 8 May 2023 17:51:35 +0200 Subject: [PATCH 17/27] Migrated to SPDX license --- adcli.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/adcli.spec b/adcli.spec index f1ff4d1..2e81331 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,8 +1,8 @@ Name: adcli Version: 0.9.2 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Active Directory enrollment -License: LGPLv2+ +License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/ea560656ac921b3fe0d455976aaae9be/adcli-%{version}.tar.gz @@ -70,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Oct 18 2023 Sumit Bose - 0.9.2-4 +- migrated to SPDX license + * Wed Jul 19 2023 Fedora Release Engineering - 0.9.2-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild From d5e5cbb731a092412b00beb18d235b74edf097c9 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 19 Jan 2024 12:08:48 +0000 Subject: [PATCH 18/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 2e81331..7acb7b0 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 4%{?dist} +Release: 5%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -70,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Fri Jan 19 2024 Fedora Release Engineering - 0.9.2-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Wed Oct 18 2023 Sumit Bose - 0.9.2-4 - migrated to SPDX license From 8a50fe9d1c8ef48cf6a6228302fd5f52dc97f2ae Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Mon, 22 Jan 2024 22:38:36 +0000 Subject: [PATCH 19/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 7acb7b0..48a0418 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 5%{?dist} +Release: 6%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -70,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Mon Jan 22 2024 Fedora Release Engineering - 0.9.2-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + * Fri Jan 19 2024 Fedora Release Engineering - 0.9.2-5 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild From aafe1deee2d6861714681ed1ddd26713aef885b0 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 17 Jul 2024 16:35:06 +0000 Subject: [PATCH 20/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 48a0418..f108f2d 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 6%{?dist} +Release: 7%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -70,6 +70,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jul 17 2024 Fedora Release Engineering - 0.9.2-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + * Mon Jan 22 2024 Fedora Release Engineering - 0.9.2-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild From de0e3ba85a762a6da237f29180f0cd100430b80a Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 27 Nov 2024 19:28:39 +0100 Subject: [PATCH 21/27] support for Samba's offline join and static analyser fixes --- ...ons-to-extract-domain-GUID-from-LDAP.patch | 97 ++++++++ ...o-Extract-domain-GUID-from-LDAP-ping.patch | 65 +++++ 0003-conn-Copy-domain-GUID-from-disco.patch | 73 ++++++ 0004-conn-Copy-forest-name-from-disco.patch | 73 ++++++ ...n-as-we-have-a-valid-LDAP-connection.patch | 27 +++ ...-the-address-of-the-connected-server.patch | 91 +++++++ ...-retrieve-the-connected-LDAP-address.patch | 45 ++++ ...pend-variables-to-external-program-e.patch | 186 ++++++++++++++ ...end-of-pipe-as-invalid-after-closing.patch | 27 +++ ...lure-if-child-exit-status-reports-so.patch | 27 +++ ...arning-if-Samba-provision-was-reques.patch | 30 +++ ...ction-to-convert-an-IP-address-to-te.patch | 87 +++++++ ...NetComposeOfflineDomainJoin-in-samba.patch | 31 +++ ...Samba-s-secrets-database-using-offli.patch | 178 ++++++++++++++ ...improve-some-Samba-related-doc-items.patch | 73 ++++++ ...r-issues-found-by-static-code-scanne.patch | 198 +++++++++++++++ ...rb5-add-adcli_krb5_get_error_message.patch | 226 ++++++++++++++++++ adcli.spec | 26 +- 18 files changed, 1559 insertions(+), 1 deletion(-) create mode 100644 0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch create mode 100644 0002-disco-Extract-domain-GUID-from-LDAP-ping.patch create mode 100644 0003-conn-Copy-domain-GUID-from-disco.patch create mode 100644 0004-conn-Copy-forest-name-from-disco.patch create mode 100644 0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch create mode 100644 0006-conn-Store-the-address-of-the-connected-server.patch create mode 100644 0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch create mode 100644 0008-util-Allow-to-append-variables-to-external-program-e.patch create mode 100644 0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch create mode 100644 0010-util-Return-failure-if-child-exit-status-reports-so.patch create mode 100644 0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch create mode 100644 0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch create mode 100644 0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch create mode 100644 0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch create mode 100644 0015-doc-improve-some-Samba-related-doc-items.patch create mode 100644 0016-Various-fixes-for-issues-found-by-static-code-scanne.patch create mode 100644 0017-krb5-add-adcli_krb5_get_error_message.patch 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/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 f108f2d..f24ef5c 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,11 +1,31 @@ Name: adcli Version: 0.9.2 -Release: 7%{?dist} +Release: 8%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/ea560656ac921b3fe0d455976aaae9be/adcli-%{version}.tar.gz +# 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 @@ -16,6 +36,7 @@ BuildRequires: openldap-devel BuildRequires: libxslt BuildRequires: xmlto BuildRequires: make +BuildRequires: libnetapi-devel Requires: cyrus-sasl-gssapi Conflicts: adcli-doc < %{version}-%{release} @@ -70,6 +91,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Nov 20 2024 Sumit Bose - 0.9.2-8 +- support for Samba's offline join and static analyser fixes + * Wed Jul 17 2024 Fedora Release Engineering - 0.9.2-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild From c7e544d4417b87f8cf0db47cddd08a0416f1ab0a Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Thu, 16 Jan 2025 10:34:02 +0000 Subject: [PATCH 22/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index f24ef5c..050e662 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 8%{?dist} +Release: 9%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -91,6 +91,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Thu Jan 16 2025 Fedora Release Engineering - 0.9.2-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + * Wed Nov 20 2024 Sumit Bose - 0.9.2-8 - support for Samba's offline join and static analyser fixes From e2d83dd03ec9f813d26eff93a8c9b63ac22c98e3 Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Wed, 23 Jul 2025 16:44:52 +0000 Subject: [PATCH 23/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 050e662..1ce90e3 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,6 +1,6 @@ Name: adcli Version: 0.9.2 -Release: 9%{?dist} +Release: 10%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -91,6 +91,9 @@ documentation. %doc %{_datadir}/doc/adcli/* %changelog +* Wed Jul 23 2025 Fedora Release Engineering - 0.9.2-10 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + * Thu Jan 16 2025 Fedora Release Engineering - 0.9.2-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild From f793f7c317c253d07a73a135b1992597d093c09b Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 9 Dec 2025 11:00:05 +0100 Subject: [PATCH 24/27] Rebase to latest upstream version --- .gitignore | 1 + ...ons-to-extract-domain-GUID-from-LDAP.patch | 97 -------- ...o-Extract-domain-GUID-from-LDAP-ping.patch | 65 ----- 0003-conn-Copy-domain-GUID-from-disco.patch | 73 ------ 0004-conn-Copy-forest-name-from-disco.patch | 73 ------ ...n-as-we-have-a-valid-LDAP-connection.patch | 27 --- ...-the-address-of-the-connected-server.patch | 91 ------- ...-retrieve-the-connected-LDAP-address.patch | 45 ---- ...pend-variables-to-external-program-e.patch | 186 -------------- ...end-of-pipe-as-invalid-after-closing.patch | 27 --- ...lure-if-child-exit-status-reports-so.patch | 27 --- ...arning-if-Samba-provision-was-reques.patch | 30 --- ...ction-to-convert-an-IP-address-to-te.patch | 87 ------- ...NetComposeOfflineDomainJoin-in-samba.patch | 31 --- ...Samba-s-secrets-database-using-offli.patch | 178 -------------- ...improve-some-Samba-related-doc-items.patch | 73 ------ ...r-issues-found-by-static-code-scanne.patch | 198 --------------- ...rb5-add-adcli_krb5_get_error_message.patch | 226 ------------------ adcli.spec | 88 +++++-- sources | 2 +- 20 files changed, 65 insertions(+), 1560 deletions(-) delete mode 100644 0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch delete mode 100644 0002-disco-Extract-domain-GUID-from-LDAP-ping.patch delete mode 100644 0003-conn-Copy-domain-GUID-from-disco.patch delete mode 100644 0004-conn-Copy-forest-name-from-disco.patch delete mode 100644 0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch delete mode 100644 0006-conn-Store-the-address-of-the-connected-server.patch delete mode 100644 0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch delete mode 100644 0008-util-Allow-to-append-variables-to-external-program-e.patch delete mode 100644 0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch delete mode 100644 0010-util-Return-failure-if-child-exit-status-reports-so.patch delete mode 100644 0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch delete mode 100644 0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch delete mode 100644 0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch delete mode 100644 0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch delete mode 100644 0015-doc-improve-some-Samba-related-doc-items.patch delete mode 100644 0016-Various-fixes-for-issues-found-by-static-code-scanne.patch delete mode 100644 0017-krb5-add-adcli_krb5_get_error_message.patch diff --git a/.gitignore b/.gitignore index 440751f..e6fcc1d 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ /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 deleted file mode 100644 index fab7322..0000000 --- a/0001-disco-Add-functions-to-extract-domain-GUID-from-LDAP.patch +++ /dev/null @@ -1,97 +0,0 @@ -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/0002-disco-Extract-domain-GUID-from-LDAP-ping.patch b/0002-disco-Extract-domain-GUID-from-LDAP-ping.patch deleted file mode 100644 index d91ce20..0000000 --- a/0002-disco-Extract-domain-GUID-from-LDAP-ping.patch +++ /dev/null @@ -1,65 +0,0 @@ -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 deleted file mode 100644 index 674eff7..0000000 --- a/0003-conn-Copy-domain-GUID-from-disco.patch +++ /dev/null @@ -1,73 +0,0 @@ -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 deleted file mode 100644 index 2611219..0000000 --- a/0004-conn-Copy-forest-name-from-disco.patch +++ /dev/null @@ -1,73 +0,0 @@ -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 deleted file mode 100644 index 1038314..0000000 --- a/0005-conn-Stop-as-soon-as-we-have-a-valid-LDAP-connection.patch +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 1f46153..0000000 --- a/0006-conn-Store-the-address-of-the-connected-server.patch +++ /dev/null @@ -1,91 +0,0 @@ -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 deleted file mode 100644 index 8c910ad..0000000 --- a/0007-conn-Allow-to-retrieve-the-connected-LDAP-address.patch +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index b623345..0000000 --- a/0008-util-Allow-to-append-variables-to-external-program-e.patch +++ /dev/null @@ -1,186 +0,0 @@ -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 deleted file mode 100644 index 1eef731..0000000 --- a/0009-util-Flag-write-end-of-pipe-as-invalid-after-closing.patch +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 797f0f9..0000000 --- a/0010-util-Return-failure-if-child-exit-status-reports-so.patch +++ /dev/null @@ -1,27 +0,0 @@ -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 deleted file mode 100644 index 4fdc233..0000000 --- a/0011-enroll-Issue-a-warning-if-Samba-provision-was-reques.patch +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index 5d172ca..0000000 --- a/0012-enroll-Add-a-function-to-convert-an-IP-address-to-te.patch +++ /dev/null @@ -1,87 +0,0 @@ -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 deleted file mode 100644 index 38f2c7d..0000000 --- a/0013-build-Check-for-NetComposeOfflineDomainJoin-in-samba.patch +++ /dev/null @@ -1,31 +0,0 @@ -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 deleted file mode 100644 index 6a85aaa..0000000 --- a/0014-enroll-Populate-Samba-s-secrets-database-using-offli.patch +++ /dev/null @@ -1,178 +0,0 @@ -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 deleted file mode 100644 index 3bdb610..0000000 --- a/0015-doc-improve-some-Samba-related-doc-items.patch +++ /dev/null @@ -1,73 +0,0 @@ -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 deleted file mode 100644 index dd60edc..0000000 --- a/0016-Various-fixes-for-issues-found-by-static-code-scanne.patch +++ /dev/null @@ -1,198 +0,0 @@ -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 deleted file mode 100644 index 0c5ba40..0000000 --- a/0017-krb5-add-adcli_krb5_get_error_message.patch +++ /dev/null @@ -1,226 +0,0 @@ -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 1ce90e3..475a660 100644 --- a/adcli.spec +++ b/adcli.spec @@ -1,31 +1,14 @@ +%global with_selinux 1 +%global selinuxtype targeted +%global modulename adcli + Name: adcli -Version: 0.9.2 -Release: 10%{?dist} +Version: 0.9.3.1 +Release: 1%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli -Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/ea560656ac921b3fe0d455976aaae9be/adcli-%{version}.tar.gz - -# 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 +Source0: https://gitlab.freedesktop.org/-/project/1196/uploads/5a1c55410c0965835b81fbd28d820d46/adcli-%{version}.tar.gz BuildRequires: gcc BuildRequires: intltool pkgconfig @@ -38,6 +21,12 @@ 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} @@ -45,10 +34,31 @@ 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} + +%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 @@ -72,13 +82,32 @@ 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: adcli documentation +Summary: The adcli documentation package BuildArch: noarch Conflicts: adcli < %{version}-%{release} @@ -90,7 +119,16 @@ 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 +* 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 1dd0180..aa241fa 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (adcli-0.9.2.tar.gz) = 0953ffb940b9abdf6277731b3fa14656b9af5686902f1b8c44389c2537e6c33db5b5272061964cf60fd6a7831e581c5362bff89d0adddc9b17059ed3a30e3971 +SHA512 (adcli-0.9.3.1.tar.gz) = 3f501173b5344b38f33a3f65faec9e894da81b44b37bb161da103d8a29459d8807dfe566a5dd0a8c7eec466567b6cca4331c81dd70158b5478a61b03be37355d From 2c56e5a7a221518d9bb790e50ee05c85d058f92d Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 16 Dec 2025 12:01:55 +0100 Subject: [PATCH 25/27] Use selinux_requires_min to avoid policycoreutils-python-utils dependency Resolves: rhbz#2422451 --- adcli.spec | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/adcli.spec b/adcli.spec index 475a660..782c6df 100644 --- a/adcli.spec +++ b/adcli.spec @@ -4,7 +4,7 @@ Name: adcli Version: 0.9.3.1 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -52,7 +52,7 @@ Summary: The adcli SELinux policy BuildArch: noarch Requires: selinux-policy-%{selinuxtype} Requires(post): selinux-policy-%{selinuxtype} -%{?selinux_requires} +%{?selinux_requires_min} %description selinux Custom SELinux policy module for adcli to make sure generated Kerberos keytab @@ -126,6 +126,10 @@ documentation. %endif %changelog +* 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 From 30a6ef6bc2ed1e9b3a39593beb7d96ad88938d5c Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 19 Dec 2025 15:33:51 +0100 Subject: [PATCH 26/27] Fix issue with restoring SELinux file label --- ...fix-issues-if-default-keytab-is-used.patch | 117 ++++++++++++++++++ adcli.spec | 7 +- 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 0001-enroll-fix-issues-if-default-keytab-is-used.patch diff --git a/0001-enroll-fix-issues-if-default-keytab-is-used.patch b/0001-enroll-fix-issues-if-default-keytab-is-used.patch new file mode 100644 index 0000000..953b97a --- /dev/null +++ b/0001-enroll-fix-issues-if-default-keytab-is-used.patch @@ -0,0 +1,117 @@ +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/adcli.spec b/adcli.spec index 782c6df..97f9528 100644 --- a/adcli.spec +++ b/adcli.spec @@ -4,12 +4,14 @@ Name: adcli Version: 0.9.3.1 -Release: 2%{?dist} +Release: 3%{?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 +Patch1: 0001-enroll-fix-issues-if-default-keytab-is-used.patch + BuildRequires: gcc BuildRequires: intltool pkgconfig BuildRequires: libtool @@ -126,6 +128,9 @@ documentation. %endif %changelog +* 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 From 27cb9476381a61da4d2919e644858c09c89384cb Mon Sep 17 00:00:00 2001 From: Fedora Release Engineering Date: Fri, 16 Jan 2026 03:26:18 +0000 Subject: [PATCH 27/27] Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild --- adcli.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adcli.spec b/adcli.spec index 97f9528..2d022ff 100644 --- a/adcli.spec +++ b/adcli.spec @@ -4,7 +4,7 @@ Name: adcli Version: 0.9.3.1 -Release: 3%{?dist} +Release: 4%{?dist} Summary: Active Directory enrollment License: LGPL-2.1-or-later URL: https://gitlab.freedesktop.org/realmd/adcli @@ -128,6 +128,9 @@ documentation. %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