Merged update from upstream sources

This is an automated DistroBaker update from upstream sources.
If you do not know what this is about or would like to opt out,
contact the OSCI team.

Source: https://src.fedoraproject.org/rpms/adcli.git#8f286a0ecf1f2a98cdf0ff3c02bac10768cd0892
This commit is contained in:
DistroBaker 2021-02-20 15:00:22 +00:00
parent 1a791be520
commit 7f8613b855
24 changed files with 22 additions and 3151 deletions

1
.gitignore vendored
View File

@ -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

View File

@ -1,32 +0,0 @@
From 40d3be22f6e518e4354aa7c3d0278291fcbed32f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,48 +0,0 @@
From d2d3879bdfcea70757a8b0527882e79e8b5c6e70 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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>workgroup</option> option, see
<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details.</para>
- <para>Note that if the machine account password is not
- older than 30 days, you have to pass
- <option>--computer-password-lifetime=0</option> to
- force the update.</para></listitem>
+ for details.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
@@ -472,7 +468,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123
important here is currently the
<option>workgroup</option> option, see
<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details.</para></listitem>
+ for details.</para>
+ <para>Note that if the machine account password is not
+ older than 30 days, you have to pass
+ <option>--computer-password-lifetime=0</option> to
+ force the update.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
--
2.25.1

View File

@ -1,37 +0,0 @@
From 76ca1e6737742208d83e016d43a3379e378f8d90 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,41 +0,0 @@
From 50d580c58dab5928cadfc6ca82aedccee58eaced Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,26 +0,0 @@
From d70075c597e7ebc1683d407409c45b04110676a0 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,59 +0,0 @@
From beb7abfacc0010987d2cd8ab70f7c373d309eed9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,44 +0,0 @@
From 93a39bd12db11dd407676f428cfbc30406a88c36 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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
<varlistentry>
<term><option>-C, --login-ccache=<parameter>ccache_name</parameter></option></term>
<listitem><para>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.</para></listitem>
+ 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.</para>
+ <para>Please note that since the
+ <parameter>ccache_name</parameter> 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.
+ </para></listitem>
</varlistentry>
<varlistentry>
<term><option>-U, --login-user=<parameter>User</parameter></option></term>
--
2.26.2

View File

@ -1,338 +0,0 @@
From 0a169bd9b2687293f74bb57694eb82f9769610c9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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 @@
<arg choice="opt">--domain=domain.example.com</arg>
<arg choice="plain">computer</arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>adcli show-computer</command>
+ <arg choice="opt">--domain=domain.example.com</arg>
+ <arg choice="plain">computer</arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id='general_overview'>
@@ -811,6 +816,29 @@ Password for Administrator:
</refsect1>
+<refsect1 id='show_computer_account'>
+ <title>Show Computer Account Attributes</title>
+
+ <para><command>adcli show-computer</command> show the computer account
+ attributes stored in AD. The account must already exist.</para>
+
+<programlisting>
+$ adcli show-computer --domain=domain.example.com host2
+Password for Administrator:
+</programlisting>
+
+ <para>If the computer name contains a dot, then it is
+ treated as fully qualified host name, otherwise it is treated
+ as short computer name.</para>
+
+ <para>If no computer name is specified, then the host name of the
+ computer adcli is running on is used, as returned by
+ <literal>gethostname()</literal>.</para>
+
+ <para>The various global options can be used.</para>
+
+</refsect1>
+
<refsect1 id='bugs'>
<title>Bugs</title>
<para>
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

View File

@ -1,183 +0,0 @@
From 3937a2a7db90611aa7a93248233b0c5d31e85a3e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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:
<listitem><para>Set the operating system version on the computer
account. Not set by default.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--description=<parameter>description</parameter></option></term>
+ <listitem><para>Set the description attribute on the computer
+ account. Not set by default.</para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>--service-name=<parameter>service</parameter></option></term>
<listitem><para>Additional service name for a kerberos
@@ -416,6 +421,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123
<listitem><para>Set the operating system version on the computer
account. Not set by default.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--description=<parameter>description</parameter></option></term>
+ <listitem><para>Set the description attribute on the computer
+ account. Not set by default.</para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>--service-name=<parameter>service</parameter></option></term>
<listitem><para>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

View File

@ -1,242 +0,0 @@
From fa5c5fb4f8e7bcadf3e5a3798bd060720fd35eaa Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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 "<itemizedlist>" > $@
+ grep '".*".*/\* :ADPermissions: ' $< | sed -e 's#.*"\(.*\)".*/\* :ADPermissions: \(.*\)\*/$$#<listitem><para>\1</para><itemizedlist><listitem><para>\2</para></listitem></itemizedlist></listitem>#' | sed -e 's#\*#</para></listitem><listitem><para>#g' >> $@
+ echo "</itemizedlist>" >> $@
+
+$(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:
</refsect1>
+<refsect1 id='delegation'>
+ <title>Delegated Permissions</title>
+ <para>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
+ <ulink url="https://docs.microsoft.com/en-us/archive/blogs/dubaisec/who-can-add-workstation-to-the-domain">Who can add workstation to the domain</ulink>.
+ </para>
+
+ <para>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.</para>
+
+ <para>First, as said in the blog post it is sufficient to have
+ <literal>"Create computer object"</literal> 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
+ <option>sAMAccountName</option> must be unique in the domain.</para>
+
+ <para>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
+ <literal>"Delete computer object"</literal> permissions.</para>
+
+ <para>If the computer object already exists the
+ <literal>"Create computer object"</literal> permission does not apply
+ anymore since now an existing object must be modified. Now permissions
+ on the individual attributes are needed. e.g.
+ <literal>"Read and write Account Restrictions"</literal> or
+ <literal>"Reset Password"</literal>. For some attributes Active
+ Directory has two types of permissions the plain
+ <literal>"Read and Write"</literal> permissions and the
+ <literal>"Validated Write"</literal> permissions. For the latter case
+ there are two specific permissions relevant for adcli, namely
+ <itemizedlist>
+ <listitem><para>Validated write to DNS host name</para></listitem>
+ <listitem><para>Validated write to service principal name</para></listitem>
+ </itemizedlist>
+ Details about the validation of the values can be found in the
+ <literal>"Validated Writes"</literal> section of
+ <literal>[MS-ADTS]</literal>, especially
+ <ulink url="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5c578b15-d619-408d-ba17-380714b89fd1">dNSHostName</ulink>
+ and
+ <ulink url="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/28ca4eca-0e0b-4666-9175-a37ccb8edada">servicePrincipalName</ulink>.
+ To cut it short for <literal>"Validated write to DNS host name"</literal>
+ 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
+ <option>msDS-AllowedDNSSuffixes</option> attribute. And for
+ <literal>"Validated write to service principal name"</literal> the
+ hostname part of the service principal name must match the name stored
+ in <option>dNSHostName</option> or some other attributes which are
+ not handled by adcli. This also means that
+ <option>dNSHostName</option> cannot be empty or only contain a short
+ name if the service principal name should contain a fully-qualified
+ name.</para>
+
+ <para>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 <option>--host-fqdn</option> with a matching
+ name.</para>
+
+ <para>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:
+ <itemizedlist>
+ <listitem><para>Reset Password</para></listitem>
+ <listitem><para>Read and write Account Restrictions</para></listitem>
+ <listitem><para>Read and (validated) write to DNS host name</para></listitem>
+ <listitem><para>Read and (validated) write to service principal name</para></listitem>
+ </itemizedlist>
+ additionally adcli needs
+ <itemizedlist>
+ <listitem><para>Read and write msDS-supportedEncryptionTypes</para></listitem>
+ </itemizedlist>
+ 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.
+ </para>
+
+ <para>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:
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="permissions.xml" />
+ </para>
+
+ <para>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
+ <literal>"Create/Delete User objects"</literal> and
+ <literal>"Create/Delete Group objects"</literal> permissions.</para>
+
+ <para>If you want to manage group members as well (adcli add-member,
+ adcli remove-member) <literal>"Read/Write Members"</literal> permissions
+ are needed as well.</para>
+
+ <para>Depending on the version of Active Directory the
+ <literal>"Delegation of Control Wizard"</literal> might offer some
+ shortcuts for common task like e.g.
+ <itemizedlist>
+ <listitem><para>Create, delete and manage user accounts</para></listitem>
+ <listitem><para>Create, delete and manage groups</para></listitem>
+ <listitem><para>Modify the membership of a group</para></listitem>
+ </itemizedlist>
+ 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
+ <literal>"Security"</literal> tab in the <literal>"Properties"</literal>
+ of the related Active Directory container that the assigned permissions
+ meet the expectations.</para>
+</refsect1>
+
<refsect1 id='bugs'>
<title>Bugs</title>
<para>
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

View File

@ -1,42 +0,0 @@
From 88fbb7e2395dec20b37697a213a097909870c21f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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
</para></listitem>
</varlistentry>
<varlistentry>
- <term><option>-C, --login-ccache=<parameter>ccache_name</parameter></option></term>
- <listitem><para>Use the specified kerberos credential
+ <term><option>-C</option></term>
+ <listitem><para>Use the default Kerberos credential
+ cache to authenticate with the domain.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--login-ccache<parameter>[=ccache_name]</parameter></option></term>
+ <listitem><para>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

View File

@ -1,124 +0,0 @@
From a6f795ba3d6048b32d7863468688bf7f42b2cafd Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,66 +0,0 @@
From 4e4dbf8d2b437808863f8be85e7f30865d88c7fc Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,378 +0,0 @@
From 85097245b57f190337225dbdbf6e33b58616c092 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--use-ldaps</option></term>
+ <listitem><para>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.</para>
+ <para> 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. <filename>/etc/openldap/ldap.conf</filename>.
+ As an alternative it can be specified with the help of
+ an environment variable, e.g.
+<programlisting>
+$ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.example.com
+...
+</programlisting>
+ Please see
+ <citerefentry><refentrytitle>ldap.conf</refentrytitle>
+ <manvolnum>5</manvolnum></citerefentry> for details.
+ </para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>-C, --login-ccache=<parameter>ccache_name</parameter></option></term>
<listitem><para>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

View File

@ -1,646 +0,0 @@
From 41379f7ad6a9442dd55cc43d832427911e86db31 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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 @@
<arg choice="opt">--domain=domain.example.com</arg>
<arg choice="plain">computer</arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>adcli create-msa</command>
+ <arg choice="opt">--domain=domain.example.com</arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id='general_overview'>
@@ -885,6 +889,142 @@ Password for Administrator:
</refsect1>
+<refsect1 id='managed_service_account'>
+ <title>Create a managed service account</title>
+
+ <para><command>adcli create-msa</command> 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.</para>
+
+<programlisting>
+$ adcli create-msa --domain=domain.example.com
+Password for Administrator:
+</programlisting>
+
+ <para>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.</para>
+
+ <para>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 <command>adcli create-msa</command>
+ will use the short hostname with an additional random suffix as
+ computer name to avoid name collisions.</para>
+
+ <para>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'.</para>
+
+ <para>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
+ <filename>/etc/krb5.keytab</filename> with a suffix of
+ 'domain.example.com', e.g.
+ <filename>/etc/krb5.keytad.domain.example.com</filename>.</para>
+
+ <para><command>adcli create-msa</command> 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 <command>adcli</command> 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.</para>
+
+ <para>The managed service account password can be updated with
+<programlisting>
+$ adcli update --domain=domain.example.com --host-keytab=/etc/krb5.keytad.domain.example.com
+</programlisting>
+ and the managed service account can be deleted with
+<programlisting>
+$ adcli delete-computer --domain=domain.example.com 'myhost!A2c'
+</programlisting>
+ </para>
+
+ <para>In addition to the global options, you can specify the following
+ options to control how this operation is done.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-N, --computer-name=<parameter>computer</parameter></option></term>
+ <listitem><para>The short non-dotted name of the managed
+ service account that will be created in the Active
+ Directory domain. The long option name
+ <option>--computer-name</option> is
+ kept to underline the similarity with the same option
+ of the other sub-commands. If not specified,
+ then the first portion of the <option>--host-fqdn</option>
+ or its default is used with a random suffix.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-O, --domain-ou=<parameter>OU=xxx</parameter></option></term>
+ <listitem><para>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.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-H, --host-fqdn=<parameter>host</parameter></option></term>
+ <listitem><para>Override the local machine's fully
+ qualified DNS domain name. If not specified, the local
+ machine's hostname will be retrieved via
+ <function>gethostname()</function>.
+ If <function>gethostname()</function> only returns a short name
+ <function>getaddrinfo()</function> with the AI_CANONNAME hint
+ is called to expand the name to a fully qualified DNS
+ domain name.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
+ <listitem><para>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
+ <filename>/etc/krb5.keytab</filename> with
+ the lower-cased Active Directory domain name added as a
+ suffix e.g.
+ <filename>/etc/krb5.keytab.domain.example.com</filename>.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--show-details</option></term>
+ <listitem><para>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.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--show-password</option></term>
+ <listitem><para>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.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
<refsect1 id='delegation'>
<title>Delegated Permissions</title>
<para>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

View File

@ -1,27 +0,0 @@
From 08bac0946de29f3e5de90743ce6dfc7118d4ad20 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,358 +0,0 @@
From eea6a8071b5e5df74808903bb15b30acf820ce3f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,77 +0,0 @@
From 2750f536ac6746756335eec8332060d2365a4126 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,91 +0,0 @@
From 81c98e367ba4bc8d77668acd31e462ad31cf12be Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,129 +0,0 @@
From 2a695dfe09cafeee3a648d3b969c364f8d3f494f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,122 +0,0 @@
From 6b94f9712378b8f1fa1bc530c64cb987abb0c43b Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
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

View File

@ -1,33 +1,10 @@
Name: adcli
Version: 0.9.0
Release: 7%{?dist}
Version: 0.9.1
Release: 1%{?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
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
URL: https://gitlab.freedesktop.org/realmd/adcli
Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee789194435e70fbf30/adcli-%{version}.tar.gz
BuildRequires: gcc
BuildRequires: intltool pkgconfig
@ -86,6 +63,9 @@ documentation.
%doc %{_datadir}/doc/adcli/*
%changelog
* Sat Feb 20 2021 Sumit Bose <sbose@redhat.com> - 0.9.1-1
- Update to upstream release 0.9.1
* Mon Jan 25 2021 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.0-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild

View File

@ -1 +1 @@
SHA512 (adcli-0.9.0.tar.gz) = e9b210bf7a932750fc838d6f027ca1fbeca1bd6a0028b551c9a72c0fe3ee680d47031c614b74447613d06bd41462c489e8572d49e60b344d575ebb572c022344
SHA512 (adcli-0.9.1.tar.gz) = 60562720bf28f2dec06f272bdb875e3486f223e77f8a9e96b3468d17dbebdf9ddabd147d7e65c5de9ba7d4e8c033ad6d28a4012d03297c7de25b78ef4890746d