Update to upstream release 0.9.1
This commit is contained in:
parent
6aa58fb290
commit
078693fb25
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
60
adcli.spec
60
adcli.spec
@ -1,49 +1,26 @@
|
||||
Name: adcli
|
||||
Version: 0.9.0
|
||||
Release: 7%{?dist}
|
||||
Summary: Active Directory enrollment
|
||||
License: LGPLv2+
|
||||
URL: http://cgit.freedesktop.org/realmd/adcli
|
||||
Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/02d8757266c24fdc10822306582287bf/adcli-%{version}.tar.gz
|
||||
Name: adcli
|
||||
Version: 0.9.1
|
||||
Release: 1%{?dist}
|
||||
Summary: Active Directory enrollment
|
||||
License: LGPLv2+
|
||||
URL: https://gitlab.freedesktop.org/realmd/adcli
|
||||
Source0: https://gitlab.freedesktop.org/sbose/adcli/uploads/30880d967e79cee789194435e70fbf30/adcli-%{version}.tar.gz
|
||||
|
||||
Patch1: 0001-man-move-note-to-the-right-section.patch
|
||||
Patch2: 0002-tools-add-show-computer-command.patch
|
||||
Patch3: 0003-add-description-option-to-join-and-update.patch
|
||||
Patch4: 0004-Use-GSS-SPNEGO-if-available.patch
|
||||
Patch5: 0005-add-option-use-ldaps.patch
|
||||
Patch6: 0006-discovery-fix.patch
|
||||
Patch7: 0001-delete-do-not-exit-if-keytab-cannot-be-read.patch
|
||||
Patch8: 0001-tools-disable-SSSD-s-locator-plugin.patch
|
||||
Patch9: 0001-tools-fix-typo-in-show-password-help-output.patch
|
||||
Patch10: 0002-man-explain-optional-parameter-of-login-ccache-bette.patch
|
||||
Patch11: 0003-man-make-handling-of-optional-credential-cache-more-.patch
|
||||
|
||||
Patch12: 0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch
|
||||
Patch13: 0002-join-update-set-dNSHostName-if-not-set.patch
|
||||
Patch14: 0003-doc-explain-required-AD-permissions.patch
|
||||
Patch15: 0004-enroll-add-is_service-member.patch
|
||||
Patch16: 0005-computer-add-create-msa-sub-command.patch
|
||||
Patch17: 0006-enroll-use-computer-or-service-in-debug-messages.patch
|
||||
Patch18: 0007-enroll-more-filters-for-random-characters.patch
|
||||
Patch19: 0008-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch
|
||||
Patch20: 0009-enroll-allow-fqdn-for-locate_computer_account.patch
|
||||
Patch21: 0010-service-account-add-random-suffix-to-account-name.patch
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: intltool pkgconfig
|
||||
BuildRequires: libtool
|
||||
BuildRequires: gettext-devel
|
||||
BuildRequires: krb5-devel
|
||||
BuildRequires: openldap-devel
|
||||
BuildRequires: libxslt
|
||||
BuildRequires: xmlto
|
||||
BuildRequires: gcc
|
||||
BuildRequires: intltool pkgconfig
|
||||
BuildRequires: libtool
|
||||
BuildRequires: gettext-devel
|
||||
BuildRequires: krb5-devel
|
||||
BuildRequires: openldap-devel
|
||||
BuildRequires: libxslt
|
||||
BuildRequires: xmlto
|
||||
BuildRequires: make
|
||||
|
||||
Requires: cyrus-sasl-gssapi
|
||||
Requires: cyrus-sasl-gssapi
|
||||
|
||||
# adcli no longer has a library of development files
|
||||
# the adcli tool itself is to be used by callers
|
||||
Obsoletes: adcli-devel < 0.5
|
||||
Obsoletes: adcli-devel < 0.5
|
||||
|
||||
%description
|
||||
adcli is a tool for joining an Active Directory domain using
|
||||
@ -86,6 +63,9 @@ documentation.
|
||||
%doc %{_datadir}/doc/adcli/*
|
||||
|
||||
%changelog
|
||||
* Sat Feb 20 2021 Sumit Bose <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
|
||||
|
||||
|
2
sources
2
sources
@ -1 +1 @@
|
||||
SHA512 (adcli-0.9.0.tar.gz) = e9b210bf7a932750fc838d6f027ca1fbeca1bd6a0028b551c9a72c0fe3ee680d47031c614b74447613d06bd41462c489e8572d49e60b344d575ebb572c022344
|
||||
SHA512 (adcli-0.9.1.tar.gz) = 60562720bf28f2dec06f272bdb875e3486f223e77f8a9e96b3468d17dbebdf9ddabd147d7e65c5de9ba7d4e8c033ad6d28a4012d03297c7de25b78ef4890746d
|
||||
|
Loading…
Reference in New Issue
Block a user