Compare commits

..

No commits in common. "c8" and "imports/c8/adcli-0.8.2-9.el8" have entirely different histories.

84 changed files with 10166 additions and 44 deletions

View File

@ -1 +1 @@
5aba9ae88ad5a75f8ce143372cb8678b96ca5773 SOURCES/adcli-0.9.2.tar.gz
f3f9537502eba38a22889fbab6e1100c32175ca2 SOURCES/adcli-0.8.2.tar.gz

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/adcli-0.9.2.tar.gz
SOURCES/adcli-0.8.2.tar.gz

View File

@ -0,0 +1,63 @@
From 158468507bb723aa62196846749c23c121d4b298 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 8 Apr 2019 10:55:39 +0200
Subject: [PATCH] Do not use arcfour-hmac-md5 when discovering the salt
Since the arcfour-hmac-md5 encryption types does not use salts it cannot
be used to discover the right salt.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1683745
---
library/adkrb5.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/library/adkrb5.c b/library/adkrb5.c
index da835d7..be3ede5 100644
--- a/library/adkrb5.c
+++ b/library/adkrb5.c
@@ -395,15 +395,33 @@ _adcli_krb5_keytab_discover_salt (krb5_context k5,
krb5_keytab scratch;
krb5_error_code code;
int i;
+ krb5_enctype *salt_enctypes = NULL;
+ size_t c;
+ size_t s;
/* TODO: This should be a unique name */
code = krb5_kt_resolve (k5, "MEMORY:adcli-discover-salt", &scratch);
return_val_if_fail (code == 0, code);
+ for (c = 0; enctypes[c] != 0; c++); /* count enctypes */
+ salt_enctypes = calloc (c + 1, sizeof (krb5_enctype));
+ return_val_if_fail (salt_enctypes != NULL, ENOMEM);
+
+ /* ENCTYPE_ARCFOUR_HMAC does not use salts, so it cannot be used to
+ * discover the right salt. */
+ s = 0;
+ for (c = 0; enctypes[c] != 0; c++) {
+ if (enctypes[c] == ENCTYPE_ARCFOUR_HMAC) {
+ continue;
+ }
+
+ salt_enctypes[s++] = enctypes[c];
+ }
+
for (i = 0; salts[i].data != NULL; i++) {
code = _adcli_krb5_keytab_test_salt (k5, scratch, principal, kvno,
- password, enctypes, &salts[i]);
+ password, salt_enctypes, &salts[i]);
if (code == 0) {
*discovered = i;
break;
@@ -412,6 +430,7 @@ _adcli_krb5_keytab_discover_salt (krb5_context k5,
}
}
+ free (salt_enctypes);
krb5_kt_close (k5, scratch);
return code;
}
--
2.21.0

View File

@ -0,0 +1,29 @@
From 5da6d34e2659f915e830932fd366c635801ecd91 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 12 Aug 2019 17:28:20 +0200
Subject: [PATCH] Fix for issue found by Coverity
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3
---
library/adenroll.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 53cd812..524663a 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -2681,7 +2681,10 @@ adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll)
for (c = 0; cur_enctypes[c] != 0; c++);
new_enctypes = calloc (c + 1, sizeof (krb5_enctype));
- return_val_if_fail (new_enctypes != NULL, NULL);
+ if (new_enctypes == NULL) {
+ krb5_free_enctypes (k5, permitted_enctypes);
+ return NULL;
+ }
n = 0;
for (c = 0; cur_enctypes[c] != 0; c++) {
--
2.21.0

View File

@ -0,0 +1,43 @@
From 3c93c96eb6ea2abd3869921ee4c89e1a4d9e4c44 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 14 Aug 2018 13:08:52 +0200
Subject: [PATCH] Fix for issues found by Coverity
---
library/adenroll.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 02bd9e3..de2242a 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1575,7 +1575,7 @@ load_host_keytab (adcli_enroll *enroll)
}
krb5_free_context (k5);
- return ADCLI_SUCCESS;
+ return res;
}
typedef struct {
@@ -1756,12 +1756,12 @@ add_principal_to_keytab (adcli_enroll *enroll,
enroll->kvno, &password, enctypes, &salts[*which_salt]);
free_principal_salts (k5, salts);
+ }
- if (code != 0) {
- _adcli_err ("Couldn't add keytab entries: %s: %s",
- enroll->keytab_name, krb5_get_error_message (k5, code));
- return ADCLI_ERR_FAIL;
- }
+ if (code != 0) {
+ _adcli_err ("Couldn't add keytab entries: %s: %s",
+ enroll->keytab_name, krb5_get_error_message (k5, code));
+ return ADCLI_ERR_FAIL;
}
--
2.21.0

View File

@ -0,0 +1,181 @@
From 6fd99ff6c5dd6ef0be8d942989b1c6dcee3102d9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 22 Mar 2019 12:37:39 +0100
Subject: [PATCH] Implement 'adcli testjoin'
By calling adcli testjoin it will be checked if the host credentials
stored in the keytab are still valid.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1622583
---
doc/adcli.xml | 34 +++++++++++++++++++++++
tools/computer.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
tools/tools.c | 1 +
tools/tools.h | 4 +++
4 files changed, 111 insertions(+)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index af73433..9605b4a 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -43,6 +43,9 @@
<cmdsynopsis>
<command>adcli update</command>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>adcli testjoin</command>
+ </cmdsynopsis>
<cmdsynopsis>
<command>adcli create-user</command>
<arg choice="opt">--domain=domain.example.com</arg>
@@ -474,6 +477,37 @@ $ adcli update --login-ccache=/tmp/krbcc_123
</refsect1>
+<refsect1 id='testjoin'>
+ <title>Testing if the machine account password is valid</title>
+
+ <para><command>adcli testjoin</command> uses the current credentials in
+ the keytab and tries to authenticate with the machine account to the AD
+ domain. If this works the machine account password and the join are
+ still valid. If it fails the machine account password or the whole
+ machine account have to be refreshed with
+ <command>adcli join</command> or <command>adcli update</command>.
+ </para>
+
+<programlisting>
+$ adcli testjoin
+</programlisting>
+
+ <para>Only the global options not related to authentication are
+ available, additionally you can specify the following options to
+ control how this operation is done.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
+ <listitem><para>Specify the path to the host keytab where
+ current host credentials are stored and the new ones
+ will be written to. If not specified, the default
+ location will be used, usually
+ <filename>/etc/krb5.keytab</filename>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
<refsect1 id='create_user'>
<title>Creating a User</title>
diff --git a/tools/computer.c b/tools/computer.c
index 112340e..610ed2b 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -566,6 +566,78 @@ adcli_tool_computer_update (adcli_conn *conn,
return 0;
}
+int
+adcli_tool_computer_testjoin (adcli_conn *conn,
+ int argc,
+ char *argv[])
+{
+ adcli_enroll *enroll;
+ adcli_result res;
+ const char *ktname;
+ int opt;
+
+ struct option options[] = {
+ { "domain", required_argument, NULL, opt_domain },
+ { "domain-controller", required_argument, NULL, opt_domain_controller },
+ { "host-keytab", required_argument, 0, opt_host_keytab },
+ { "verbose", no_argument, NULL, opt_verbose },
+ { "help", no_argument, NULL, 'h' },
+ { 0 },
+ };
+
+ static adcli_tool_desc usages[] = {
+ { 0, "usage: adcli testjoin" },
+ { 0 },
+ };
+
+ enroll = adcli_enroll_new (conn);
+ if (enroll == NULL)
+ errx (-1, "unexpected memory problems");
+
+ 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:
+ parse_option ((Option)opt, optarg, conn, enroll);
+ break;
+ }
+ }
+
+ /* Force use of a keytab to test the join/machine account password */
+ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT);
+ ktname = adcli_enroll_get_keytab_name (enroll);
+ adcli_conn_set_login_keytab_name (conn, ktname ? ktname : "");
+
+ res = adcli_enroll_load (enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ adcli_conn_unref (conn);
+ errx (-res, "couldn't lookup domain info from keytab: %s",
+ adcli_get_last_error ());
+ }
+
+ res = adcli_conn_connect (conn);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ adcli_conn_unref (conn);
+ errx (-res, "couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ }
+
+ printf ("Sucessfully validated join to domain %s\n",
+ adcli_conn_get_domain_name (conn));
+
+ adcli_enroll_unref (enroll);
+
+ return 0;
+}
int
adcli_tool_computer_preset (adcli_conn *conn,
diff --git a/tools/tools.c b/tools/tools.c
index 915130e..c4e2851 100644
--- a/tools/tools.c
+++ b/tools/tools.c
@@ -55,6 +55,7 @@ struct {
{ "info", adcli_tool_info, "Print information about a domain", CONNECTION_LESS },
{ "join", adcli_tool_computer_join, "Join this machine to a domain", },
{ "update", adcli_tool_computer_update, "Update machine membership in a domain", },
+ { "testjoin", adcli_tool_computer_testjoin, "Test if machine account password is valid", },
{ "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", },
diff --git a/tools/tools.h b/tools/tools.h
index 6c97ccf..8cebbf9 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -70,6 +70,10 @@ int adcli_tool_computer_update (adcli_conn *conn,
int argc,
char *argv[]);
+int adcli_tool_computer_testjoin (adcli_conn *conn,
+ int argc,
+ char *argv[]);
+
int adcli_tool_computer_delete (adcli_conn *conn,
int argc,
char *argv[]);
--
2.20.1

View File

@ -0,0 +1,32 @@
From 5cf1723c308e21cdbe9b98ed2aaa42cb997456fb Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 15 Mar 2019 14:31:12 +0100
Subject: [PATCH] Increment kvno after password change with user creds
Originally only the host credential part was fixed in the context of
https://bugs.freedesktop.org/show_bug.cgi?id=91185. This patch adds the
fix to the case when user credentials are used.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1642546
---
library/adenroll.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/library/adenroll.c b/library/adenroll.c
index e02f403..58362c2 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1057,6 +1057,10 @@ set_password_with_user_creds (adcli_enroll *enroll)
#endif
} else {
_adcli_info ("Set computer password");
+ if (enroll->kvno > 0) {
+ enroll->kvno++;
+ _adcli_info ("kvno incremented to %d", enroll->kvno);
+ }
res = ADCLI_SUCCESS;
}
--
2.20.1

View File

@ -0,0 +1,216 @@
From 0a0d0f66409eb83e06b7dc50543c2f6c15a36bc4 Mon Sep 17 00:00:00 2001
From: Alexey A Nikitin <nikitin@amazon.com>
Date: Mon, 29 Oct 2018 20:40:36 -0700
Subject: [PATCH] Make 'adcli info' DC location mechanism more compliant with
[MS-ADTS] and [MS-NRPC]
AD specifications say that DC locator must attempt to find a suitable DC for the client. That means going through all of the DCs in SRV RRs one by one until one of them answers.
The problem with adcli's original behavior is that it queries only five DCs from SRV, ever. This becomes a problem if for any reason there is a large number of DCs in the domain from which the client cannot get a CLDAP response.
---
library/addisco.c | 146 +++++++++++++++++++++++++++++-----------------
1 file changed, 94 insertions(+), 52 deletions(-)
diff --git a/library/addisco.c b/library/addisco.c
index 8cc5bf0..6e73ead 100644
--- a/library/addisco.c
+++ b/library/addisco.c
@@ -41,8 +41,10 @@
#include <string.h>
#include <time.h>
-/* Number of servers to do discovery against */
-#define DISCO_COUNT 5
+/* Number of servers to do discovery against.
+ * For AD DS maximum number of DCs is 1200.
+ */
+#define DISCO_COUNT 1200
/* The time period in which to do rapid requests */
#define DISCO_FEVER 1
@@ -453,6 +455,51 @@ parse_disco (LDAP *ldap,
return usability;
}
+static int
+ldap_disco_poller (LDAP **ldap,
+ LDAPMessage **message,
+ adcli_disco **results,
+ const char **addrs)
+{
+ int found = ADCLI_DISCO_UNUSABLE;
+ int close_ldap;
+ int parsed;
+ int ret = 0;
+ struct timeval tvpoll = { 0, 0 };
+
+ switch (ldap_result (*ldap, LDAP_RES_ANY, 1, &tvpoll, message)) {
+ case LDAP_RES_SEARCH_ENTRY:
+ case LDAP_RES_SEARCH_RESULT:
+ parsed = parse_disco (*ldap, *addrs, *message, results);
+ if (parsed > found)
+ found = parsed;
+ ldap_msgfree (*message);
+ close_ldap = 1;
+ break;
+ case -1:
+ ldap_get_option (*ldap, LDAP_OPT_RESULT_CODE, &ret);
+ close_ldap = 1;
+ break;
+ default:
+ ldap_msgfree (*message);
+ close_ldap = 0;
+ break;
+ }
+
+ if (ret != LDAP_SUCCESS) {
+ _adcli_ldap_handle_failure (*ldap, ADCLI_ERR_CONFIG,
+ "Couldn't perform discovery search");
+ }
+
+ /* Done with this connection */
+ if (close_ldap) {
+ ldap_unbind_ext_s (*ldap, NULL, NULL);
+ *ldap = NULL;
+ }
+
+ return found;
+}
+
static int
ldap_disco (const char *domain,
srvinfo *srv,
@@ -477,6 +524,7 @@ ldap_disco (const char *domain,
int num, i;
int ret;
int have_any = 0;
+ struct timeval interval;
if (domain) {
value = _adcli_ldap_escape_filter (domain);
@@ -540,7 +588,6 @@ ldap_disco (const char *domain,
version = LDAP_VERSION3;
ldap_set_option (ldap[num], LDAP_OPT_PROTOCOL_VERSION, &version);
ldap_set_option (ldap[num], LDAP_OPT_REFERRALS , 0);
- _adcli_info ("Sending netlogon pings to domain controller: %s", url);
addrs[num] = srv->hostname;
have_any = 1;
num++;
@@ -555,70 +602,65 @@ ldap_disco (const char *domain,
freeaddrinfo (res);
}
- /* Wait for the first response. Poor mans fd watch */
- for (started = now = time (NULL);
- have_any && found != ADCLI_DISCO_USABLE && now < started + DISCO_TIME;
- now = time (NULL)) {
+ /* Initial send and short time wait */
+ interval.tv_sec = 0;
+ for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
+ int parsed;
+
+ if (NULL == ldap[i])
+ continue;
- struct timeval tvpoll = { 0, 0 };
- struct timeval interval;
+ have_any = 1;
+ _adcli_info ("Sending NetLogon ping to domain controller: %s", addrs[i]);
- /* If in the initial period, send feverishly */
- if (now < started + DISCO_FEVER) {
- interval.tv_sec = 0;
- interval.tv_usec = 100 * 1000;
+ ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
+ filter, attrs, 0, NULL, NULL, NULL,
+ -1, &msgidp);
+
+ if (ret != LDAP_SUCCESS) {
+ _adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
+ "Couldn't perform discovery search");
+ ldap_unbind_ext_s (ldap[i], NULL, NULL);
+ ldap[i] = NULL;
+ }
+
+ /* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first
+ * five DCs are given 0.4 seconds timeout, next five are given 0.2
+ * seconds, and the rest are given 0.1 seconds
+ */
+ if (i < 5) {
+ interval.tv_usec = 400000;
+ } else if (i < 10) {
+ interval.tv_usec = 200000;
} else {
- interval.tv_sec = 1;
- interval.tv_usec = 0;
+ interval.tv_usec = 100000;
}
+ select (0, NULL, NULL, NULL, &interval);
+
+ parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
+ if (parsed > found)
+ found = parsed;
+ }
+
+ /* Wait some more until LDAP timeout (DISCO_TIME) */
+ for (started = now = time (NULL);
+ have_any && ADCLI_DISCO_UNUSABLE == found && now < started + DISCO_TIME;
+ now = time (NULL)) {
select (0, NULL, NULL, NULL, &interval);
have_any = 0;
- for (i = 0; found != ADCLI_DISCO_USABLE && i < num; i++) {
- int close_ldap;
+ for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
int parsed;
if (ldap[i] == NULL)
continue;
- ret = 0;
have_any = 1;
- switch (ldap_result (ldap[i], LDAP_RES_ANY, 1, &tvpoll, &message)) {
- case LDAP_RES_SEARCH_ENTRY:
- case LDAP_RES_SEARCH_RESULT:
- parsed = parse_disco (ldap[i], addrs[i], message, results);
- if (parsed > found)
- found = parsed;
- ldap_msgfree (message);
- close_ldap = 1;
- break;
- case 0:
- ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
- filter, attrs, 0, NULL, NULL, NULL,
- -1, &msgidp);
- close_ldap = (ret != 0);
- break;
- case -1:
- ldap_get_option (ldap[i], LDAP_OPT_RESULT_CODE, &ret);
- close_ldap = 1;
- break;
- default:
- ldap_msgfree (message);
- close_ldap = 0;
- break;
- }
-
- if (ret != LDAP_SUCCESS) {
- _adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
- "Couldn't perform discovery search");
- }
- /* Done with this connection */
- if (close_ldap) {
- ldap_unbind_ext_s (ldap[i], NULL, NULL);
- ldap[i] = NULL;
- }
+ parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
+ if (parsed > found)
+ found = parsed;
}
}
--
2.26.2

View File

@ -0,0 +1,31 @@
From d8eb0f5704f34cb7d411cd275d32c63ead297b8d Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 24 Aug 2016 15:37:41 +0200
Subject: [PATCH 01/23] Remove upper-case only check when looking for the
NetBIOS name
It is a convention to use only upper-case letters for NetBIOS names but
it is not enforced on the AD-side. With the new option to specify a
random NetBIOS name it is possible to create host entries in AD with
lower-case letters in the name. To properly determine the name from the
keytab the upper-case check should be dropped,dc=
---
library/adenroll.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index a15e4be..d1020e9 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1309,7 +1309,7 @@ load_keytab_entry (krb5_context k5,
if (!enroll->host_fqdn_explicit && !enroll->computer_name_explicit) {
/* Automatically use the netbios name */
- if (!enroll->computer_name && len > 1 && _adcli_str_is_up (name) &&
+ if (!enroll->computer_name && len > 1 &&
_adcli_str_has_suffix (name, "$") && !strchr (name, '/')) {
enroll->computer_name = name;
name[len - 1] = '\0';
--
2.14.4

View File

@ -0,0 +1,124 @@
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 1/2] Use GSS-SPNEGO if available
Currently adcli uses the GSSAPI SASL mechanism for LDAP authentication
and to establish encryption. While this works in general it does not
handle some of the more advanced features which can be required by AD
DCs.
The GSS-SPNEGO mechanism can handle them and is used with this patch by
adcli if the AD DC indicates that it supports it.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1762420
---
library/adconn.c | 35 ++++++++++++++++++++++++++++++++++-
library/adconn.h | 3 +++
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/library/adconn.c b/library/adconn.c
index bcaced8..ffb54f9 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -77,6 +77,7 @@ struct _adcli_conn_ctx {
char *default_naming_context;
char *configuration_naming_context;
char **supported_capabilities;
+ char **supported_sasl_mechs;
/* Connect state */
LDAP *ldap;
@@ -845,6 +846,7 @@ connect_and_lookup_naming (adcli_conn *conn,
"defaultNamingContext",
"configurationNamingContext",
"supportedCapabilities",
+ "supportedSASLMechanisms",
NULL
};
@@ -897,6 +899,11 @@ connect_and_lookup_naming (adcli_conn *conn,
"supportedCapabilities");
}
+ if (conn->supported_sasl_mechs == NULL) {
+ conn->supported_sasl_mechs = _adcli_ldap_parse_values (ldap, results,
+ "supportedSASLMechanisms");
+ }
+
ldap_msgfree (results);
if (conn->default_naming_context == NULL) {
@@ -1022,6 +1029,7 @@ authenticate_to_directory (adcli_conn *conn)
OM_uint32 minor;
ber_len_t ssf;
int ret;
+ const char *mech = "GSSAPI";
if (conn->ldap_authenticated)
return ADCLI_SUCCESS;
@@ -1038,7 +1046,11 @@ authenticate_to_directory (adcli_conn *conn)
ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf);
return_unexpected_if_fail (ret == 0);
- ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, "GSSAPI", NULL, NULL,
+ if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")) {
+ mech = "GSS-SPNEGO";
+ }
+
+ ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, mech, NULL, NULL,
LDAP_SASL_QUIET, sasl_interact, NULL);
/* Clear the credential cache GSSAPI to use (for this thread) */
@@ -1231,6 +1243,7 @@ conn_free (adcli_conn *conn)
free (conn->default_naming_context);
free (conn->configuration_naming_context);
_adcli_strv_free (conn->supported_capabilities);
+ _adcli_strv_free (conn->supported_sasl_mechs);
free (conn->computer_name);
free (conn->host_fqdn);
@@ -1606,6 +1619,26 @@ adcli_conn_server_has_capability (adcli_conn *conn,
return 0;
}
+bool
+adcli_conn_server_has_sasl_mech (adcli_conn *conn,
+ const char *mech)
+{
+ int i;
+
+ return_val_if_fail (conn != NULL, false);
+ return_val_if_fail (mech != NULL, false);
+
+ if (!conn->supported_sasl_mechs)
+ return false;
+
+ for (i = 0; conn->supported_sasl_mechs[i] != NULL; i++) {
+ if (strcasecmp (mech, conn->supported_sasl_mechs[i]) == 0)
+ return true;
+ }
+
+ return false;
+}
+
bool adcli_conn_is_writeable (adcli_conn *conn)
{
disco_dance_if_necessary (conn);
diff --git a/library/adconn.h b/library/adconn.h
index 1ad5715..37ebdd9 100644
--- a/library/adconn.h
+++ b/library/adconn.h
@@ -149,6 +149,9 @@ void adcli_conn_set_krb5_conf_dir (adcli_conn *conn,
int adcli_conn_server_has_capability (adcli_conn *conn,
const char *capability);
+bool adcli_conn_server_has_sasl_mech (adcli_conn *conn,
+ const char *mech);
+
bool adcli_conn_is_writeable (adcli_conn *conn);
#endif /* ADCONN_H_ */
--
2.21.0

View File

@ -0,0 +1,80 @@
From 341974aae7d0755fc32a0b7e2b34d8e1ef60d195 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 20 Dec 2018 21:05:35 +0100
Subject: [PATCH 1/4] adenroll: make sure only allowed enctypes are used in
FIPS mode
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1717355
---
library/adenroll.c | 36 +++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 52aa8a8..f617f28 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -41,11 +41,19 @@
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#ifndef SAMBA_DATA_TOOL
#define SAMBA_DATA_TOOL "/usr/bin/net"
#endif
+static krb5_enctype v60_later_enctypes_fips[] = {
+ ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+ 0
+};
+
static krb5_enctype v60_later_enctypes[] = {
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
@@ -2594,6 +2602,28 @@ adcli_enroll_set_keytab_name (adcli_enroll *enroll,
enroll->keytab_name_is_krb5 = 0;
}
+#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled"
+
+static bool adcli_fips_enabled (void)
+{
+ int fd;
+ ssize_t len;
+ char buf[8];
+
+ fd = open (PROC_SYS_FIPS, O_RDONLY);
+ if (fd != -1) {
+ len = read (fd, buf, sizeof (buf));
+ close (fd);
+ /* Assume FIPS in enabled if PROC_SYS_FIPS contains a
+ * non-0 value. */
+ if ( ! (len == 2 && buf[0] == '0' && buf[1] == '\n')) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
krb5_enctype *
adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
{
@@ -2602,7 +2632,11 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
return enroll->keytab_enctypes;
if (adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID))
- return v60_later_enctypes;
+ if (adcli_fips_enabled ()) {
+ return v60_later_enctypes_fips;
+ } else {
+ return v60_later_enctypes;
+ }
else
return v51_earlier_enctypes;
}
--
2.21.0

View File

@ -0,0 +1,134 @@
From 85d127fd52a8469f9f3ce0d1130fe17e756fdd75 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 16 Nov 2018 13:32:33 +0100
Subject: [PATCH 1/2] adutil: add _adcli_strv_add_unique
_adcli_strv_add_unique checks is the new value already exists in the
strv before adding it. Check can be done case-sensitive or not.
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/16
---
library/adprivate.h | 5 ++++
library/adutil.c | 65 ++++++++++++++++++++++++++++++++++++++-------
2 files changed, 61 insertions(+), 9 deletions(-)
diff --git a/library/adprivate.h b/library/adprivate.h
index bc9df6d..0806430 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -111,6 +111,11 @@ char ** _adcli_strv_add (char **strv,
char *string,
int *length) GNUC_WARN_UNUSED;
+char ** _adcli_strv_add_unique (char **strv,
+ char *string,
+ int *length,
+ bool case_sensitive) GNUC_WARN_UNUSED;
+
void _adcli_strv_remove_unsorted (char **strv,
const char *string,
int *length);
diff --git a/library/adutil.c b/library/adutil.c
index 17d2caa..76ea158 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -221,6 +221,34 @@ _adcli_strv_add (char **strv,
return seq_push (strv, length, string);
}
+static int
+_adcli_strv_has_ex (char **strv,
+ const char *str,
+ int (* compare) (const char *match, const char*value))
+{
+ int i;
+
+ for (i = 0; strv && strv[i] != NULL; i++) {
+ if (compare (strv[i], str) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+char **
+_adcli_strv_add_unique (char **strv,
+ char *string,
+ int *length,
+ bool case_sensitive)
+{
+ if (_adcli_strv_has_ex (strv, string, case_sensitive ? strcmp : strcasecmp) == 1) {
+ return strv;
+ }
+
+ return _adcli_strv_add (strv, string, length);
+}
+
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
void
@@ -241,19 +269,11 @@ _adcli_strv_remove_unsorted (char **strv,
(seq_compar)strcasecmp, free);
}
-
int
_adcli_strv_has (char **strv,
const char *str)
{
- int i;
-
- for (i = 0; strv && strv[i] != NULL; i++) {
- if (strcmp (strv[i], str) == 0)
- return 1;
- }
-
- return 0;
+ return _adcli_strv_has_ex (strv, str, strcmp);
}
void
@@ -704,6 +724,32 @@ test_strv_add_free (void)
_adcli_strv_free (strv);
}
+static void
+test_strv_add_unique_free (void)
+{
+ char **strv = NULL;
+
+ strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("tWo"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false);
+ strv = _adcli_strv_add_unique (strv, strdup ("TWO"), NULL, true);
+
+ assert_num_eq (_adcli_strv_len (strv), 4);
+
+ assert_str_eq (strv[0], "one");
+ assert_str_eq (strv[1], "two");
+ assert_str_eq (strv[2], "three");
+ assert_str_eq (strv[3], "TWO");
+ assert (strv[4] == NULL);
+
+ _adcli_strv_free (strv);
+}
+
+
static void
test_strv_dup (void)
{
@@ -856,6 +902,7 @@ main (int argc,
char *argv[])
{
test_func (test_strv_add_free, "/util/strv_add_free");
+ test_func (test_strv_add_unique_free, "/util/strv_add_unique_free");
test_func (test_strv_dup, "/util/strv_dup");
test_func (test_strv_count, "/util/strv_count");
test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
--
2.20.1

View File

@ -0,0 +1,71 @@
From 1457b4a7623a8ae58fb8d6a652d1cc44904b8863 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 18 Mar 2019 11:02:57 +0100
Subject: [PATCH 1/2] create-user: add nis-domain option
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/2
---
doc/adcli.xml | 8 ++++++++
tools/entry.c | 6 ++++++
2 files changed, 14 insertions(+)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 4722c3a..18620c0 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -531,6 +531,14 @@ $ adcli create-user Fry --domain=domain.example.com \
the new created user account, which should be the user's
numeric primary user id.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--nis-domain=<parameter>nis_domain</parameter></option></term>
+ <listitem><para>Set the <code>msSFU30NisDomain</code> attribute of
+ the new created user account, which should be the user's
+ NIS domain is the NIS/YP service of Active Directory's Services for Unix (SFU)
+ are used. This is needed to let the 'UNIX attributes' tab of older Active
+ Directoy versions show the set UNIX specific attributes.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/tools/entry.c b/tools/entry.c
index 7b6a200..69ce62c 100644
--- a/tools/entry.c
+++ b/tools/entry.c
@@ -52,6 +52,7 @@ typedef enum {
opt_unix_uid,
opt_unix_gid,
opt_unix_shell,
+ opt_nis_domain,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -62,6 +63,7 @@ static adcli_tool_desc common_usages[] = {
{ opt_unix_uid, "unix uid number" },
{ opt_unix_gid, "unix gid number" },
{ opt_unix_shell, "unix shell" },
+ { opt_nis_domain, "NIS domain" },
{ opt_domain, "active directory domain name" },
{ opt_domain_realm, "kerberos realm for the domain" },
{ opt_domain_controller, "domain directory server to connect to" },
@@ -159,6 +161,7 @@ adcli_tool_user_create (adcli_conn *conn,
{ "unix-uid", required_argument, NULL, opt_unix_uid },
{ "unix-gid", required_argument, NULL, opt_unix_gid },
{ "unix-shell", required_argument, NULL, opt_unix_shell },
+ { "nis-domain", required_argument, NULL, opt_nis_domain },
{ "domain-ou", required_argument, NULL, opt_domain_ou },
{ "domain", required_argument, NULL, opt_domain },
{ "domain-realm", required_argument, NULL, opt_domain_realm },
@@ -200,6 +203,9 @@ adcli_tool_user_create (adcli_conn *conn,
case opt_unix_shell:
adcli_attrs_add (attrs, "loginShell", optarg, NULL);
break;
+ case opt_nis_domain:
+ adcli_attrs_add (attrs, "msSFU30NisDomain", optarg, NULL);
+ break;
case opt_domain_ou:
ou = optarg;
break;
--
2.20.1

View File

@ -0,0 +1,32 @@
From 40d3be22f6e518e4354aa7c3d0278291fcbed32f Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 5 Jun 2020 17:06:58 +0200
Subject: [PATCH] delete: do not exit if keytab cannot be read
Reading the keytab is not required when deleting a host object in AD. It
is only needed in the case where the host was added with a manual set
NetBIOS name (--computer-name option) which does not match the short
hostname and no computer name was given at the delete-computer command
line.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1840752
---
tools/computer.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/tools/computer.c b/tools/computer.c
index 292c4d8..a90c4b2 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -952,8 +952,6 @@ adcli_tool_computer_delete (adcli_conn *conn,
if (res != ADCLI_SUCCESS) {
warnx ("couldn't lookup domain info from keytab: %s",
adcli_get_last_error ());
- adcli_enroll_unref (enroll);
- return -res;
}
res = adcli_conn_connect (conn);
--
2.26.2

View File

@ -0,0 +1,27 @@
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] discovery fix
Do not continue processing on closed connection.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1802258
---
library/addisco.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/library/addisco.c b/library/addisco.c
index 6e73ead..f3b3546 100644
--- a/library/addisco.c
+++ b/library/addisco.c
@@ -622,6 +622,7 @@ ldap_disco (const char *domain,
"Couldn't perform discovery search");
ldap_unbind_ext_s (ldap[i], NULL, NULL);
ldap[i] = NULL;
+ continue;
}
/* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first
--
2.26.2

View File

@ -0,0 +1,25 @@
From 2edc26afda17db1a92703deb16658e9de9f79e14 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 3 Sep 2019 14:39:37 +0200
Subject: [PATCH] doc: add missing samba_data_tool_path.xml(.in) to EXTRA_DIST
---
doc/Makefile.am | 2 ++
1 file changed, 2 insertions(+)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 3a53843..4490688 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -31,6 +31,8 @@ EXTRA_DIST = \
static \
version.xml.in \
version.xml \
+ samba_data_tool_path.xml.in \
+ samba_data_tool_path.xml \
$(NULL)
CLEANFILES = \
--
2.28.0

View File

@ -0,0 +1,30 @@
From 9b187095edb8c914238419ed51fef6041864f4fc Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 26 Aug 2019 13:33:24 +0200
Subject: [PATCH] doc: explain how to force password reset
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1738573
---
doc/adcli.xml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 094f577..4f201e0 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -330,7 +330,11 @@ 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></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.21.0

View File

@ -0,0 +1,242 @@
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] doc: explain required AD permissions
When using a restricted account with adcli some operations might fail
because the account might not have all required permissions. The man
page is extended and now explains which permissions are needed under
given circumstances.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1852080
Resolves: https://gitlab.freedesktop.org/realmd/adcli/-/issues/20
---
doc/Makefile.am | 10 ++++
doc/adcli.xml | 132 +++++++++++++++++++++++++++++++++++++++++++++
library/adenroll.c | 30 ++++++-----
3 files changed, 160 insertions(+), 12 deletions(-)
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 4490688..50fb777 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -33,14 +33,17 @@ EXTRA_DIST = \
version.xml \
samba_data_tool_path.xml.in \
samba_data_tool_path.xml \
+ permissions.xml \
$(NULL)
CLEANFILES = \
$(man8_MANS) \
+ permissions.xml \
$(NULL)
XSLTPROC_FLAGS = \
--nonet \
+ --xinclude \
--stringparam man.output.quietly 1 \
--stringparam funcsynopsis.style ansi \
--stringparam man.th.extra1.suppress 1 \
@@ -50,6 +53,13 @@ XSLTPROC_FLAGS = \
XSLTPROC_MAN = \
$(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
+permissions.xml: ../library/adenroll.c adcli.xml
+ echo "<itemizedlist>" > $@
+ grep '".*".*/\* :ADPermissions: ' $< | sed -e 's#.*"\(.*\)".*/\* :ADPermissions: \(.*\)\*/$$#<listitem><para>\1</para><itemizedlist><listitem><para>\2</para></listitem></itemizedlist></listitem>#' | sed -e 's#\*#</para></listitem><listitem><para>#g' >> $@
+ echo "</itemizedlist>" >> $@
+
+$(man8_MANS): permissions.xml
+
.xml.8:
$(AM_V_GEN) $(XSLTPROC_MAN) $<
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 1437679..cc44fd8 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -885,6 +885,138 @@ Password for Administrator:
</refsect1>
+<refsect1 id='delegation'>
+ <title>Delegated Permissions</title>
+ <para>It is common practice in AD to not use an account from the Domain
+ Administrators group to join a machine to a domain but use a dedicated
+ account which only has permissions to join a machine to one or more OUs
+ in the Active Directory tree. Giving the needed permissions to a single
+ account or a group in Active Directory is called Delegation. A typical
+ example on how to configured Delegation can be found in the Delegation
+ section of the blog post
+ <ulink url="https://docs.microsoft.com/en-us/archive/blogs/dubaisec/who-can-add-workstation-to-the-domain">Who can add workstation to the domain</ulink>.
+ </para>
+
+ <para>When using an account with delegated permissions with adcli
+ basically the same applies as well. However some aspects are explained
+ here in a bit more details to better illustrate different concepts of
+ Active Directory and to make it more easy to debug permissions issues
+ during the join. Please note that the following is not specific to
+ adcli but applies to all applications which would like to modify
+ certain properties or objects in Active Directory with an account with
+ limited permissions.</para>
+
+ <para>First, as said in the blog post it is sufficient to have
+ <literal>"Create computer object"</literal> permissions to join a
+ computer to a domain. But this would only work as expected if the
+ computer object does not exist in Active Directory before the join.
+ Because only when a new object is created Active Directory does not
+ apply additional permission checks on the attributes of the new
+ computer object. This means the delegated user can add any kind of
+ attribute with any value to a new computer object also long as they
+ meet general constraints like e.g. that the attribute must be defined
+ in the schema and is allowed in a objectclass of the object, the value
+ must match the syntax defined in the schema or that the
+ <option>sAMAccountName</option> must be unique in the domain.</para>
+
+ <para>If you want to use the account with delegated permission to
+ remove computer objects in Active Directory (adcli delete-computer) you
+ should of course make sure that the account has
+ <literal>"Delete computer object"</literal> permissions.</para>
+
+ <para>If the computer object already exists the
+ <literal>"Create computer object"</literal> permission does not apply
+ anymore since now an existing object must be modified. Now permissions
+ on the individual attributes are needed. e.g.
+ <literal>"Read and write Account Restrictions"</literal> or
+ <literal>"Reset Password"</literal>. For some attributes Active
+ Directory has two types of permissions the plain
+ <literal>"Read and Write"</literal> permissions and the
+ <literal>"Validated Write"</literal> permissions. For the latter case
+ there are two specific permissions relevant for adcli, namely
+ <itemizedlist>
+ <listitem><para>Validated write to DNS host name</para></listitem>
+ <listitem><para>Validated write to service principal name</para></listitem>
+ </itemizedlist>
+ Details about the validation of the values can be found in the
+ <literal>"Validated Writes"</literal> section of
+ <literal>[MS-ADTS]</literal>, especially
+ <ulink url="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5c578b15-d619-408d-ba17-380714b89fd1">dNSHostName</ulink>
+ and
+ <ulink url="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/28ca4eca-0e0b-4666-9175-a37ccb8edada">servicePrincipalName</ulink>.
+ To cut it short for <literal>"Validated write to DNS host name"</literal>
+ the domain part of the fully-qualified hostname must either match the
+ domain name of the domain you want to join to or must be listed in the
+ <option>msDS-AllowedDNSSuffixes</option> attribute. And for
+ <literal>"Validated write to service principal name"</literal> the
+ hostname part of the service principal name must match the name stored
+ in <option>dNSHostName</option> or some other attributes which are
+ not handled by adcli. This also means that
+ <option>dNSHostName</option> cannot be empty or only contain a short
+ name if the service principal name should contain a fully-qualified
+ name.</para>
+
+ <para>To summarize, if you only have validated write permissions you
+ should make sure the domain part of the hostname matches the domain you
+ want to join or use the <option>--host-fqdn</option> with a matching
+ name.</para>
+
+ <para>The plain read write permissions do not run additional
+ validations but the attribute values must still be in agreement with
+ the general constraints mentioned above. If the computer object already
+ exists adcli might need the following permissions which are also needed
+ by Windows clients to modify existing attributes:
+ <itemizedlist>
+ <listitem><para>Reset Password</para></listitem>
+ <listitem><para>Read and write Account Restrictions</para></listitem>
+ <listitem><para>Read and (validated) write to DNS host name</para></listitem>
+ <listitem><para>Read and (validated) write to service principal name</para></listitem>
+ </itemizedlist>
+ additionally adcli needs
+ <itemizedlist>
+ <listitem><para>Read and write msDS-supportedEncryptionTypes</para></listitem>
+ </itemizedlist>
+ This is added for security reasons to avoid that Active Directory
+ stores Kerberos keys with (potentially weaker) encryption types than
+ the client supports since Active Directory is often configured to still
+ support older (weaker) encryption types for compatibility reasons.
+ </para>
+
+ <para>All other attributes are only set or modified on demand, i.e.
+ adcli must be called with an option the would set or modify the given
+ attribute. In the following the attributes adcli can modify together
+ with the required permissions are listed:
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="permissions.xml" />
+ </para>
+
+ <para>For the management of users and groups (adcli create-user,
+ adcli delete-user, adcli create-group, adcli delete-group) the same
+ applies only for different types of objects, i.e. users and groups.
+ Since currently adcli only supports the creation and the removal of
+ user and group objects it is sufficient to have the
+ <literal>"Create/Delete User objects"</literal> and
+ <literal>"Create/Delete Group objects"</literal> permissions.</para>
+
+ <para>If you want to manage group members as well (adcli add-member,
+ adcli remove-member) <literal>"Read/Write Members"</literal> permissions
+ are needed as well.</para>
+
+ <para>Depending on the version of Active Directory the
+ <literal>"Delegation of Control Wizard"</literal> might offer some
+ shortcuts for common task like e.g.
+ <itemizedlist>
+ <listitem><para>Create, delete and manage user accounts</para></listitem>
+ <listitem><para>Create, delete and manage groups</para></listitem>
+ <listitem><para>Modify the membership of a group</para></listitem>
+ </itemizedlist>
+ The first 2 shortcuts will provided full access to user and group
+ objects which, as explained above, is more than currently is needed.
+ After using those shortcut it is a good idea to verify in the
+ <literal>"Security"</literal> tab in the <literal>"Properties"</literal>
+ of the related Active Directory container that the assigned permissions
+ meet the expectations.</para>
+</refsect1>
+
<refsect1 id='bugs'>
<title>Bugs</title>
<para>
diff --git a/library/adenroll.c b/library/adenroll.c
index e745295..98e9786 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -71,19 +71,25 @@ static krb5_enctype v51_earlier_enctypes[] = {
0
};
+/* The following list containst all attributes handled by adcli, some are
+ * read-only and the others can be written as well. To properly document the
+ * required permissions each attribute which adcli tries to modify should have
+ * a comment starting with ':ADPermissions:' and the related permissions in AD
+ * on the same line. Multiple permissions can be seperated with a '*'. For all
+ * other attribute a suitable comment is very welcome. */
static char *default_ad_ldap_attrs[] = {
- "sAMAccountName",
- "userPrincipalName",
- "msDS-KeyVersionNumber",
- "msDS-supportedEncryptionTypes",
- "dNSHostName",
- "servicePrincipalName",
- "operatingSystem",
- "operatingSystemVersion",
- "operatingSystemServicePack",
- "pwdLastSet",
- "userAccountControl",
- "description",
+ "sAMAccountName", /* Only set during creation */
+ "userPrincipalName", /* :ADPermissions: Read/Write userPrincipal Name */
+ "msDS-KeyVersionNumber", /* Manages by AD */
+ "msDS-supportedEncryptionTypes", /* :ADPermissions: Read/Write msDS-SupportedEncryptionTypes */
+ "dNSHostName", /* :ADPermissions: Read/Write dNSHostName * Read and write DNS host name attributes * Validated write to DNS host name */
+ "servicePrincipalName", /* :ADPermissions: Read/Write servicePrincipalName * Validated write to service principal name */
+ "operatingSystem", /* :ADPermissions: Read/Write Operating System */
+ "operatingSystemVersion", /* :ADPermissions: Read/Write Operating System Version */
+ "operatingSystemServicePack", /* :ADPermissions: Read/Write operatingSystemServicePack */
+ "pwdLastSet", /* Managed by AD */
+ "userAccountControl", /* :ADPermissions: Read/Write userAccountControl */
+ "description", /* :ADPermissions: Read/Write Description */
NULL,
};
--
2.28.0

View File

@ -0,0 +1,66 @@
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 1/7] enroll: add is_service member
Add helpers to indicate a managed service account.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
library/adenroll.c | 17 +++++++++++++++++
library/adenroll.h | 4 ++++
2 files changed, 21 insertions(+)
diff --git a/library/adenroll.c b/library/adenroll.c
index 98e9786..5ae1f7b 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -103,6 +103,8 @@ static char *default_ad_ldap_attrs[] = {
struct _adcli_enroll {
int refs;
adcli_conn *conn;
+ bool is_service;
+ bool is_service_explicit;
char *host_fqdn;
int host_fqdn_explicit;
@@ -2942,6 +2944,21 @@ adcli_enroll_get_desciption (adcli_enroll *enroll)
return enroll->description;
}
+void
+adcli_enroll_set_is_service (adcli_enroll *enroll, bool value)
+{
+ return_if_fail (enroll != NULL);
+
+ enroll->is_service = value;
+ enroll->is_service_explicit = true;
+}
+
+bool
+adcli_enroll_get_is_service (adcli_enroll *enroll)
+{
+ return enroll->is_service;
+}
+
const char **
adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll)
{
diff --git a/library/adenroll.h b/library/adenroll.h
index 0606169..7765ed4 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -130,6 +130,10 @@ const char * adcli_enroll_get_desciption (adcli_enroll *enroll);
void adcli_enroll_set_description (adcli_enroll *enroll,
const char *value);
+bool adcli_enroll_get_is_service (adcli_enroll *enroll);
+void adcli_enroll_set_is_service (adcli_enroll *enroll,
+ bool value);
+
krb5_kvno adcli_enroll_get_kvno (adcli_enroll *enroll);
void adcli_enroll_set_kvno (adcli_enroll *enroll,
--
2.28.0

View File

@ -0,0 +1,72 @@
From 3a84c2469c31967bc22c0490456f07723ef5fc86 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 20 Mar 2019 11:01:50 +0100
Subject: [PATCH 1/4] ensure_keytab_principals: do not leak memory when called
twice
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
---
library/adenroll.c | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index d1f746c..48cb4cf 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -413,6 +413,25 @@ ensure_service_principals (adcli_result res,
return res;
}
+static void enroll_clear_keytab_principals (adcli_enroll *enroll)
+{
+ krb5_context k5;
+ size_t c;
+
+ if (enroll->keytab_principals) {
+ k5 = adcli_conn_get_krb5_context (enroll->conn);
+ return_if_fail (k5 != NULL);
+
+ for (c = 0; enroll->keytab_principals[c] != NULL; c++)
+ krb5_free_principal (k5, enroll->keytab_principals[c]);
+
+ free (enroll->keytab_principals);
+ enroll->keytab_principals = NULL;
+ }
+
+ return;
+}
+
static adcli_result
ensure_keytab_principals (adcli_result res,
adcli_enroll *enroll)
@@ -430,6 +449,7 @@ ensure_keytab_principals (adcli_result res,
k5 = adcli_conn_get_krb5_context (enroll->conn);
return_unexpected_if_fail (k5 != NULL);
+ enroll_clear_keytab_principals (enroll);
enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
return_unexpected_if_fail (enroll->keytab_principals != NULL);
at = 0;
@@ -1860,18 +1880,8 @@ static void
enroll_clear_state (adcli_enroll *enroll)
{
krb5_context k5;
- int i;
-
- if (enroll->keytab_principals) {
- k5 = adcli_conn_get_krb5_context (enroll->conn);
- return_if_fail (k5 != NULL);
-
- for (i = 0; enroll->keytab_principals[i] != NULL; i++)
- krb5_free_principal (k5, enroll->keytab_principals[i]);
- free (enroll->keytab_principals);
- enroll->keytab_principals = NULL;
- }
+ enroll_clear_keytab_principals (enroll);
if (enroll->keytab) {
k5 = adcli_conn_get_krb5_context (enroll->conn);
--
2.20.1

View File

@ -0,0 +1,25 @@
From 870ecd8f982ebb97092a93d730ad4006bd78505c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 8 Aug 2018 12:03:01 +0200
Subject: [PATCH 1/4] fix typo in flag value
---
library/adenroll.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/adenroll.h b/library/adenroll.h
index f87dffa..abbbfd4 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -30,7 +30,7 @@ typedef enum {
ADCLI_ENROLL_NO_KEYTAB = 1 << 1,
ADCLI_ENROLL_ALLOW_OVERWRITE = 1 << 2,
ADCLI_ENROLL_PASSWORD_VALID = 1 << 3,
- ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 3,
+ ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 4,
} adcli_enroll_flags;
typedef struct _adcli_enroll adcli_enroll;
--
2.17.1

View File

@ -0,0 +1,86 @@
From cd296bf24e7cc56fb8d00bad7e9a56c539894309 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 19 Mar 2019 20:44:36 +0100
Subject: [PATCH 1/2] join: always add service principals
If currently --service-name is given during the join only the service
names given by this option are added as service principal names. As a
result the default 'host' service principal name might be missing which
might cause issues e.g. with SSSD and sshd.
The patch makes sure the default service principals 'host' and
'RestrictedKrbHost' are always added during join.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1644311
---
library/adenroll.c | 36 ++++++++++++++++++++++++++++++------
1 file changed, 30 insertions(+), 6 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 58362c2..d1f746c 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -288,16 +288,23 @@ ensure_computer_password (adcli_result res,
}
static adcli_result
-ensure_service_names (adcli_result res,
- adcli_enroll *enroll)
+ensure_default_service_names (adcli_enroll *enroll)
{
int length = 0;
- if (res != ADCLI_SUCCESS)
- return res;
+ if (enroll->service_names != NULL) {
+ length = seq_count (enroll->service_names);
- if (enroll->service_names || enroll->service_principals)
- return ADCLI_SUCCESS;
+ /* Make sure there is no entry with an unexpected case. AD
+ * would not care but since the client side is case-sensitive
+ * we should make sure we use the expected spelling. */
+ seq_remove_unsorted (enroll->service_names,
+ &length, "host",
+ (seq_compar)strcasecmp, free);
+ seq_remove_unsorted (enroll->service_names,
+ &length, "RestrictedKrbHost",
+ (seq_compar)strcasecmp, free);
+ }
/* The default ones specified by MS */
enroll->service_names = _adcli_strv_add (enroll->service_names,
@@ -307,6 +314,19 @@ ensure_service_names (adcli_result res,
return ADCLI_SUCCESS;
}
+static adcli_result
+ensure_service_names (adcli_result res,
+ adcli_enroll *enroll)
+{
+ if (res != ADCLI_SUCCESS)
+ return res;
+
+ if (enroll->service_names || enroll->service_principals)
+ return ADCLI_SUCCESS;
+
+ return ensure_default_service_names (enroll);
+}
+
static adcli_result
add_service_names_to_service_principals (adcli_enroll *enroll)
{
@@ -2039,6 +2059,10 @@ adcli_enroll_join (adcli_enroll *enroll,
if (res != ADCLI_SUCCESS)
return res;
+ res = ensure_default_service_names (enroll);
+ if (res != ADCLI_SUCCESS)
+ return res;
+
res = adcli_enroll_prepare (enroll, flags);
if (res != ADCLI_SUCCESS)
return res;
--
2.20.1

View File

@ -0,0 +1,59 @@
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] join/update: set dNSHostName if not set
If during a join or update an existing AD computer object does not have
the dNSHostName attribute set it will be set with the current hostname.
This is important for cases where the user doing the join or update only
has "Validated write to service principal name" for the computer object.
The validated write with fully-qualified names can only be successful if
dNSHostName is set, see [MS-ADTS] section 3.1.1.5.3.1.1.4 "Validated
Writes - servicePrincipalName" for details.
Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1734764
---
library/adenroll.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 246f658..e745295 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1403,21 +1403,29 @@ update_computer_account (adcli_enroll *enroll)
{
int res = 0;
LDAP *ldap;
+ char *value = NULL;
ldap = adcli_conn_get_ldap_connection (enroll->conn);
return_if_fail (ldap != NULL);
/* Only update attributes which are explicitly given on the command
- * line. Otherwise 'adcli update' must be always called with the same
- * set of options to make sure existing attributes are not deleted or
- * overwritten with different values. */
- if (enroll->host_fqdn_explicit) {
+ * line or not set in the existing AD object. Otherwise 'adcli update'
+ * must be always called with the same set of options to make sure
+ * existing attributes are not deleted or overwritten with different
+ * values. */
+ if (enroll->computer_attributes != NULL) {
+ value = _adcli_ldap_parse_value (ldap,
+ enroll->computer_attributes,
+ "dNSHostName");
+ }
+ if (enroll->host_fqdn_explicit || value == NULL ) {
char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
LDAPMod dNSHostName = { LDAP_MOD_REPLACE, "dNSHostName", { vals_dNSHostName, } };
LDAPMod *mods[] = { &dNSHostName, NULL };
res |= update_computer_attribute (enroll, ldap, mods);
}
+ free (value);
if (res == ADCLI_SUCCESS && enroll->trusted_for_delegation_explicit) {
char *vals_userAccountControl[] = { NULL , NULL };
--
2.28.0

View File

@ -0,0 +1,34 @@
From a64cce9830c2e9c26e120f671b247ee71b45c888 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 12 Apr 2019 17:31:41 +0200
Subject: [PATCH] library: add missing strdup
In add_server_side_service_principals _adcli_strv_add_unique is called
which only adds a string to a list without copying to. Since the
original list will be freed later the value must be copied.
This issue was introduce with 972f1a2f35829ed89f5353bd204683aa9ad6a2d2
and hence
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
---
library/adenroll.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 1cce86a..52aa8a8 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1987,7 +1987,8 @@ add_server_side_service_principals (adcli_enroll *enroll)
_adcli_info ("Checking %s", spn_list[c]);
if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) {
enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
- spn_list[c], &length, false);
+ strdup (spn_list[c]),
+ &length, false);
assert (enroll->service_principals != NULL);
_adcli_info (" Added %s", spn_list[c]);
}
--
2.20.1

View File

@ -0,0 +1,92 @@
From 85b835f8258a57e3b23de47a255dddd822d5bfb3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 15 Mar 2019 17:33:44 +0100
Subject: [PATCH] library: use getaddrinfo with AI_CANONNAME to find a FQDN
Currently adcli creates service principals only with a short name if the
hostname of the client is a short name. This would fail is
Kerberos/GSSAPI clients will use the fully-qualified domain name (FQDN)
to access the host.
With this patch adcli tries to expand the short name by calling
getaddrinfo with the AI_CANONNAME hint.
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/1
---
doc/adcli.xml | 6 +++++-
library/adconn.c | 30 +++++++++++++++++++++++++++++-
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 97dec08..4722c3a 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -228,7 +228,11 @@ Password for Administrator:
<term><option>-H, --host-fqdn=<parameter>host</parameter></option></term>
<listitem><para>Override the local machine's fully qualified
domain name. If not specified, the local machine's hostname
- will be retrieved via <function>gethostname()</function>.</para></listitem>
+ 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 domain
+ name.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
diff --git a/library/adconn.c b/library/adconn.c
index e2250e3..f6c23d3 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -86,11 +86,36 @@ struct _adcli_conn_ctx {
krb5_keytab keytab;
};
+static char *try_to_get_fqdn (const char *host_name)
+{
+ int ret;
+ char *fqdn = NULL;
+ struct addrinfo *res;
+ struct addrinfo hints;
+
+ memset (&hints, 0, sizeof (struct addrinfo));
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ ret = getaddrinfo (host_name, NULL, &hints, &res);
+ if (ret != 0) {
+ _adcli_err ("Failed to find FQDN: %s", gai_strerror (ret));
+ return NULL;
+ }
+
+ fqdn = strdup (res->ai_canonname);
+
+ freeaddrinfo (res);
+
+ return fqdn;
+}
+
static adcli_result
ensure_host_fqdn (adcli_result res,
adcli_conn *conn)
{
char hostname[HOST_NAME_MAX + 1];
+ char *fqdn = NULL;
int ret;
if (res != ADCLI_SUCCESS)
@@ -107,7 +132,10 @@ ensure_host_fqdn (adcli_result res,
return ADCLI_ERR_UNEXPECTED;
}
- conn->host_fqdn = strdup (hostname);
+ if (strchr (hostname, '.') == NULL) {
+ fqdn = try_to_get_fqdn (hostname);
+ }
+ conn->host_fqdn = fqdn != NULL ? fqdn : strdup (hostname);
return_unexpected_if_fail (conn->host_fqdn != NULL);
return ADCLI_SUCCESS;
}
--
2.20.1

View File

@ -0,0 +1,44 @@
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] man: explain optional parameter of login-ccache better
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791545
---
doc/adcli.xml | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index acced25..ecf8726 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -155,13 +155,19 @@ $ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.exa
<varlistentry>
<term><option>-C, --login-ccache=<parameter>ccache_name</parameter></option></term>
<listitem><para>Use the specified kerberos credential
- cache to authenticate with the domain. If no credential
- cache is specified, the default kerberos credential
- cache will be used. Credential caches of type FILE can
- be given with the path to the file. For other
- credential cache types, e.g. DIR, KEYRING or KCM, the
- type must be specified explicitly together with a
- suitable identifier.</para></listitem>
+ cache to authenticate with the domain. If no credential
+ cache is specified, the default kerberos credential
+ cache will be used. Credential caches of type FILE can
+ be given with the path to the file. For other
+ credential cache types, e.g. DIR, KEYRING or KCM, the
+ type must be specified explicitly together with a
+ suitable identifier.</para>
+ <para>Please note that since the
+ <parameter>ccache_name</parameter> is optional the
+ =(equal) sign is mandatory. If = is missing the
+ parameter is treated as optionless extra argument. How
+ this is handled depends on the specific sub-command.
+ </para></listitem>
</varlistentry>
<varlistentry>
<term><option>-U, --login-user=<parameter>User</parameter></option></term>
--
2.26.2

View File

@ -0,0 +1,41 @@
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] man: make handling of optional credential cache more clear
The optional Kerberos credential cache can only be used with the long
option name --login-ccache and not with the short version -C. To make
this more clear each option get its own entry.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791545
---
doc/adcli.xml | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index ecf8726..1437679 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -153,10 +153,16 @@ $ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.exa
</para></listitem>
</varlistentry>
<varlistentry>
- <term><option>-C, --login-ccache=<parameter>ccache_name</parameter></option></term>
- <listitem><para>Use the specified kerberos credential
+ <term><option>-C</option></term>
+ <listitem><para>Use the default Kerberos credential
+ cache to authenticate with the domain.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--login-ccache<parameter>[=ccache_name]</parameter></option></term>
+ <listitem><para>Use the specified Kerberos credential
cache to authenticate with the domain. If no credential
- cache is specified, the default kerberos credential
+ cache is specified, the default Kerberos credential
cache will be used. Credential caches of type FILE can
be given with the path to the file. For other
credential cache types, e.g. DIR, KEYRING or KCM, the
--
2.26.2

View File

@ -0,0 +1,48 @@
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] 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.21.0

View File

@ -0,0 +1,35 @@
From 637cc53953ef61c90530ae5eaf26eb4911336465 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 10 Dec 2020 18:29:18 +0100
Subject: [PATCH] service-account: fix typo in the man page entry
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1906303
---
doc/adcli.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 14921f9..a64687a 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -943,7 +943,7 @@ Password for Administrator:
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>
+ <filename>/etc/krb5.keytab.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
@@ -955,7 +955,7 @@ Password for Administrator:
<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
+$ adcli update --domain=domain.example.com --host-keytab=/etc/krb5.keytab.domain.example.com
</programlisting>
and the managed service account can be deleted with
<programlisting>
--
2.29.2

View File

@ -0,0 +1,36 @@
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] tools: add missing use-ldaps option to update and testjoin
When adding the use-ldaps option the update and testjoin sub-commands
were forgotten.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1883467
---
tools/computer.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/computer.c b/tools/computer.c
index 24ea258..5a97d8b 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -491,6 +491,7 @@ adcli_tool_computer_update (adcli_conn *conn,
struct option options[] = {
{ "domain", required_argument, NULL, opt_domain },
{ "domain-controller", required_argument, NULL, opt_domain_controller },
+ { "use-ldaps", no_argument, 0, opt_use_ldaps },
{ "host-fqdn", required_argument, 0, opt_host_fqdn },
{ "computer-name", required_argument, 0, opt_computer_name },
{ "host-keytab", required_argument, 0, opt_host_keytab },
@@ -612,6 +613,7 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
struct option options[] = {
{ "domain", required_argument, NULL, opt_domain },
{ "domain-controller", required_argument, NULL, opt_domain_controller },
+ { "use-ldaps", no_argument, 0, opt_use_ldaps },
{ "host-keytab", required_argument, 0, opt_host_keytab },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
--
2.28.0

View File

@ -0,0 +1,338 @@
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 1/2] 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.21.0

View File

@ -0,0 +1,41 @@
From 50d580c58dab5928cadfc6ca82aedccee58eaced Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 5 Jun 2020 17:28:28 +0200
Subject: [PATCH] tools: disable SSSD's locator plugin
MIT's libkrb5 checks available locator plugins first before checking the
config file. This might cause issues when the locator plugin returns a
different DC than the one used for the LDAP connection if some data must
be replicated.
This patch sets the SSSD_KRB5_LOCATOR_DISABLE environment variable to
'true' to disable SSSD's locator plugin for adcli.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1762633
---
tools/tools.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/tools.c b/tools/tools.c
index 9d422f2..1b6d879 100644
--- a/tools/tools.c
+++ b/tools/tools.c
@@ -296,6 +296,7 @@ cleanup_krb5_conf_directory (void)
}
unsetenv ("KRB5_CONFIG");
+ unsetenv ("SSSD_KRB5_LOCATOR_DISABLE");
}
static void
@@ -394,6 +395,7 @@ setup_krb5_conf_directory (adcli_conn *conn)
adcli_krb5_conf_filename = filename;
adcli_krb5_d_directory = snippets;
setenv ("KRB5_CONFIG", adcli_krb5_conf_filename, 1);
+ setenv ("SSSD_KRB5_LOCATOR_DISABLE", "true", 1);
} else {
free (filename);
--
2.26.2

View File

@ -0,0 +1,26 @@
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] tools: fix typo in show-password help output
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1791611
---
tools/computer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/computer.c b/tools/computer.c
index a90c4b2..24ea258 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -154,7 +154,7 @@ static adcli_tool_desc common_usages[] = {
"accounts" },
{ opt_show_details, "show information about joining the domain after\n"
"a successful join" },
- { opt_show_password, "show computer account password after after a\n"
+ { opt_show_password, "show computer account password after a\n"
"successful join" },
{ opt_add_samba_data, "add domain SID and computer account password\n"
"to the Samba specific configuration database" },
--
2.26.2

View File

@ -0,0 +1,328 @@
From fa7926c7a9d92bc7c42c610ba6f1706c635aa901 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 15 Apr 2019 17:54:27 +0200
Subject: [PATCH 1/7] tools: remove errx from computer commands
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/computer.c | 166 ++++++++++++++++++++++++++++++-----------------
1 file changed, 107 insertions(+), 59 deletions(-)
diff --git a/tools/computer.c b/tools/computer.c
index bee695c..9cbbb28 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -379,8 +379,10 @@ adcli_tool_computer_join (adcli_conn *conn,
};
enroll = adcli_enroll_new (conn);
- if (enroll == NULL)
- errx (-1, "unexpected memory problems");
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
switch (opt) {
@@ -415,21 +417,28 @@ adcli_tool_computer_join (adcli_conn *conn,
if (argc == 1)
adcli_conn_set_domain_name (conn, argv[0]);
- else if (argc > 1)
- errx (2, "extra arguments specified");
+ else if (argc > 1) {
+ warnx ("extra arguments specified");
+ adcli_enroll_unref (enroll);
+ return 2;
+ }
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ 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, flags);
if (res != ADCLI_SUCCESS) {
- errx (-res, "joining domain %s failed: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("joining domain %s failed: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
if (details)
@@ -486,8 +495,10 @@ adcli_tool_computer_update (adcli_conn *conn,
};
enroll = adcli_enroll_new (conn);
- if (enroll == NULL)
- errx (-1, "unexpected memory problems");
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
switch (opt) {
@@ -525,22 +536,28 @@ adcli_tool_computer_update (adcli_conn *conn,
res = adcli_enroll_load (enroll);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't lookup domain info from keytab: %s",
- adcli_get_last_error ());
+ warnx ("couldn't lookup domain info from keytab: %s",
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ 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_update (enroll, flags);
if (res != ADCLI_SUCCESS) {
- errx (-res, "updating membership with domain %s failed: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("updating membership with domain %s failed: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
if (details)
@@ -578,8 +595,10 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
};
enroll = adcli_enroll_new (conn);
- if (enroll == NULL)
- errx (-1, "unexpected memory problems");
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
switch (opt) {
@@ -604,18 +623,18 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
res = adcli_enroll_load (enroll);
if (res != ADCLI_SUCCESS) {
adcli_enroll_unref (enroll);
- adcli_conn_unref (conn);
- errx (-res, "couldn't lookup domain info from keytab: %s",
- adcli_get_last_error ());
+ warnx ("couldn't lookup domain info from keytab: %s",
+ adcli_get_last_error ());
+ return -res;
}
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
adcli_enroll_unref (enroll);
- adcli_conn_unref (conn);
- errx (-res, "couldn't connect to %s domain: %s",
+ warnx ("couldn't connect to %s domain: %s",
adcli_conn_get_domain_name (conn),
adcli_get_last_error ());
+ return -res;
}
printf ("Sucessfully validated join to domain %s\n",
@@ -665,8 +684,10 @@ adcli_tool_computer_preset (adcli_conn *conn,
};
enroll = adcli_enroll_new (conn);
- if (enroll == NULL)
- errx (-1, "unexpected memory problems");
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
flags = ADCLI_ENROLL_NO_KEYTAB;
while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
@@ -694,17 +715,22 @@ adcli_tool_computer_preset (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc < 1)
- errx (EUSAGE, "specify one or more host names of computer accounts to preset");
+ if (argc < 1) {
+ warnx ("specify one or more host names of computer accounts to preset");
+ adcli_enroll_unref (enroll);
+ return EUSAGE;
+ }
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
reset_password = (adcli_enroll_get_computer_password (enroll) == NULL);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
for (i = 0; i < argc; i++) {
@@ -715,9 +741,11 @@ adcli_tool_computer_preset (adcli_conn *conn,
res = adcli_enroll_join (enroll, flags);
if (res != ADCLI_SUCCESS) {
- errx (-res, "presetting %s in %s domain failed: %s", argv[i],
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("presetting %s in %s domain failed: %s", argv[i],
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
printf ("computer-name: %s\n", adcli_enroll_get_computer_name (enroll));
@@ -758,8 +786,10 @@ adcli_tool_computer_reset (adcli_conn *conn,
};
enroll = adcli_enroll_new (conn);
- if (enroll == NULL)
- errx (-1, "unexpected memory problems");
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
switch (opt) {
@@ -779,14 +809,19 @@ adcli_tool_computer_reset (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc != 1)
- errx (EUSAGE, "specify one host name of computer account to reset");
+ if (argc != 1) {
+ warnx ("specify one host name of computer account to reset");
+ adcli_enroll_unref (enroll);
+ return EUSAGE;
+ }
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
parse_fqdn_or_name (enroll, argv[0]);
@@ -794,9 +829,11 @@ adcli_tool_computer_reset (adcli_conn *conn,
res = adcli_enroll_password (enroll, 0);
if (res != ADCLI_SUCCESS) {
- errx (-res, "resetting %s in %s domain failed: %s", argv[0],
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("resetting %s in %s domain failed: %s", argv[0],
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
adcli_enroll_unref (enroll);
@@ -832,8 +869,10 @@ adcli_tool_computer_delete (adcli_conn *conn,
};
enroll = adcli_enroll_new (conn);
- if (enroll == NULL)
- errx (-1, "unexpected memory problems");
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
switch (opt) {
@@ -853,22 +892,29 @@ adcli_tool_computer_delete (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc > 1)
- errx (EUSAGE, "specify one host name of computer account to delete");
+ if (argc > 1) {
+ warnx ("specify one host name of computer account to delete");
+ adcli_enroll_unref (enroll);
+ return EUSAGE;
+ }
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_enroll_load (enroll);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't lookup domain info from keytab: %s",
- adcli_get_last_error ());
+ warnx ("couldn't lookup domain info from keytab: %s",
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ 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)
@@ -876,9 +922,11 @@ adcli_tool_computer_delete (adcli_conn *conn,
res = adcli_enroll_delete (enroll, 0);
if (res != ADCLI_SUCCESS) {
- errx (-res, "deleting %s in %s domain failed: %s", argv[0],
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("deleting %s in %s domain failed: %s", argv[0],
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
}
adcli_enroll_unref (enroll);
--
2.20.1

View File

@ -0,0 +1,31 @@
From 4ba49015ca1ad98c03a209a11862f8e00d00fbd0 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 24 Aug 2016 16:19:36 +0200
Subject: [PATCH 02/23] Use strdup() if offset are used
Strings with an offset to the original starting point must be copied
because otherwise they cannot be properly freed later.
---
library/adenroll.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index d1020e9..05885d0 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1318,9 +1318,9 @@ load_keytab_entry (krb5_context k5,
} else if (!enroll->host_fqdn && _adcli_str_has_prefix (name, "host/") && strchr (name, '.')) {
/* Skip host/ prefix */
- enroll->host_fqdn = name + 5;
- _adcli_info ("Found host qualified name in keytab: %s", name);
- name = NULL;
+ enroll->host_fqdn = strdup (name + 5);
+ return_val_if_fail (enroll->host_fqdn != NULL, FALSE);
+ _adcli_info ("Found host qualified name in keytab: %s", enroll->host_fqdn);
}
}
--
2.14.4

View File

@ -0,0 +1,25 @@
From 8cc4ef1cae7d4d753f2cf9aeb8021dd96cb75d36 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 8 Aug 2018 12:17:18 +0200
Subject: [PATCH 2/4] _adcli_call_external_program: silence noisy debug message
---
library/adutil.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/adutil.c b/library/adutil.c
index 6334b52..17d2caa 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -672,7 +672,7 @@ done:
if (wret == -1) {
_adcli_err ("No sure what happend to net command.");
} else {
- if (WIFEXITED (status)) {
+ if (WIFEXITED (status) && WEXITSTATUS (status) != 0) {
_adcli_err ("net command failed with %d.",
WEXITSTATUS (status));
}
--
2.17.1

View File

@ -0,0 +1,52 @@
From 2fc259a88be618871cea8ff8b8a13bd3e040aea4 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 13 Jun 2019 17:23:47 +0200
Subject: [PATCH 2/4] adconn: add adcli_conn_set_krb5_context
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3
---
library/adconn.c | 13 +++++++++++++
library/adconn.h | 3 +++
2 files changed, 16 insertions(+)
diff --git a/library/adconn.c b/library/adconn.c
index f6c23d3..bcaced8 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -1406,6 +1406,19 @@ adcli_conn_get_krb5_context (adcli_conn *conn)
return conn->k5;
}
+void
+adcli_conn_set_krb5_context (adcli_conn *conn,
+ krb5_context k5)
+{
+ return_if_fail (conn != NULL);
+
+ if (conn->k5 != NULL) {
+ krb5_free_context (conn->k5);
+ }
+
+ conn->k5 = k5;
+}
+
const char *
adcli_conn_get_login_user (adcli_conn *conn)
{
diff --git a/library/adconn.h b/library/adconn.h
index 13cfd32..1ad5715 100644
--- a/library/adconn.h
+++ b/library/adconn.h
@@ -97,6 +97,9 @@ LDAP * adcli_conn_get_ldap_connection (adcli_conn *conn);
krb5_context adcli_conn_get_krb5_context (adcli_conn *conn);
+void adcli_conn_set_krb5_context (adcli_conn *conn,
+ krb5_context k5);
+
const char * adcli_conn_get_computer_name (adcli_conn *conn);
void adcli_conn_set_computer_name (adcli_conn *conn,
--
2.21.0

View File

@ -0,0 +1,183 @@
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 2/2] 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.21.0

View File

@ -0,0 +1,378 @@
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 2/2] add option use-ldaps
In general using the LDAP port with GSS-SPNEGO should satifiy all
requirements an AD DC should have for authentication on an encrypted
LDAP connection.
But if e.g. the LDAP port is blocked by a firewall using the LDAPS port
with TLS encryption might be an alternative. For this use case the
--use-ldaps option is added.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1762420
---
doc/adcli.xml | 24 +++++++++++++++
library/adconn.c | 79 ++++++++++++++++++++++++++++++++++++++++++------
library/adconn.h | 4 +++
tools/computer.c | 10 ++++++
tools/entry.c | 11 +++++++
5 files changed, 119 insertions(+), 9 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index dd30435..acced25 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -128,6 +128,30 @@
If not specified, then an appropriate domain controller
is automatically discovered.</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.21.0

View File

@ -0,0 +1,83 @@
From 0c027538f398b3823bedbfbf5f388ad97784a0ec Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 16 Nov 2018 13:32:59 +0100
Subject: [PATCH 2/2] adenroll: use _adcli_strv_add_unique for service
principals
Check if service principals is already in the list before adding it.
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/16
---
library/adenroll.c | 31 ++++++++-----------------------
1 file changed, 8 insertions(+), 23 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index de2242a..e02f403 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -313,7 +313,6 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
char *name;
int length = 0;
int i;
- size_t c;
if (enroll->service_principals != NULL) {
length = seq_count (enroll->service_principals);
@@ -322,28 +321,14 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
for (i = 0; enroll->service_names[i] != NULL; i++) {
if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
return_unexpected_if_reached ();
- for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
- if (strcmp (name, enroll->service_principals[c]) == 0) {
- break;
- }
- }
- if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- name, &length);
- }
+ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
+ name, &length, false);
if (enroll->host_fqdn) {
if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
return_unexpected_if_reached ();
- for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
- if (strcmp (name, enroll->service_principals[c]) == 0) {
- break;
- }
- }
- if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- name, &length);
- }
+ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
+ name, &length, false);
}
}
@@ -364,9 +349,9 @@ add_and_remove_service_principals (adcli_enroll *enroll)
list = adcli_enroll_get_service_principals_to_add (enroll);
if (list != NULL) {
for (c = 0; list[c] != NULL; c++) {
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- strdup (list[c]),
- &length);
+ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
+ strdup (list[c]),
+ &length, false);
if (enroll->service_principals == NULL) {
return ADCLI_ERR_UNEXPECTED;
}
@@ -1525,7 +1510,7 @@ load_keytab_entry (krb5_context k5,
value = strdup (name);
return_val_if_fail (value != NULL, FALSE);
_adcli_info ("Found service principal in keytab: %s", value);
- enroll->service_principals = _adcli_strv_add (enroll->service_principals, value, NULL);
+ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, value, NULL, false);
}
}
--
2.20.1

View File

@ -0,0 +1,646 @@
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 2/7] computer: add create-msa sub-command
Add new sub-command to create a managed service account in AD. This can
be used if LDAP access to AD is needed but the host is already joined to
a different domain.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
doc/adcli.xml | 140 ++++++++++++++++++++++++++++++++++++++
library/adenroll.c | 164 ++++++++++++++++++++++++++++++++++++++-------
tools/computer.c | 125 ++++++++++++++++++++++++++++++++++
tools/tools.c | 1 +
tools/tools.h | 4 ++
5 files changed, 409 insertions(+), 25 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index cc44fd8..14921f9 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -98,6 +98,10 @@
<arg choice="opt">--domain=domain.example.com</arg>
<arg choice="plain">computer</arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>adcli create-msa</command>
+ <arg choice="opt">--domain=domain.example.com</arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1 id='general_overview'>
@@ -885,6 +889,142 @@ Password for Administrator:
</refsect1>
+<refsect1 id='managed_service_account'>
+ <title>Create a managed service account</title>
+
+ <para><command>adcli create-msa</command> creates a managed service
+ account (MSA) in the given Active Directory domain. This is useful if a
+ computer should not fully join the Active Directory domain but LDAP
+ access is needed. A typical use case is that the computer is already
+ joined an Active Directory domain and needs access to another Active
+ Directory domain in the same or a trusted forest where the host
+ credentials from the joined Active Directory domain are
+ not valid, e.g. there is only a one-way trust.</para>
+
+<programlisting>
+$ adcli create-msa --domain=domain.example.com
+Password for Administrator:
+</programlisting>
+
+ <para>The managed service account, as maintained by adcli, cannot have
+ additional service principals names (SPNs) associated with it. An SPN
+ is defined within the context of a Kerberos service which is tied to a
+ machine account in Active Directory. Since a machine can be joined to a
+ single Active Directory domain, managed service account in a different
+ Active Directory domain will not have the SPNs that otherwise are part
+ of another Active Directory domain's machine.</para>
+
+ <para>Since it is expected that a client will most probably join to the
+ Active Directory domain matching its DNS domain the managed service
+ account will be needed for a different Active directory domain and as a
+ result the Active Directory domain name is a mandatory option. If
+ called with no other options <command>adcli create-msa</command>
+ will use the short hostname with an additional random suffix as
+ computer name to avoid name collisions.</para>
+
+ <para>LDAP attribute sAMAccountName has a limit of 20 characters.
+ However, machine account's NetBIOS name must be at most 16 characters
+ long, including a trailing '$' sign. Since it is not expected that the
+ managed service accounts created by adcli will be used on the NetBIOS
+ level the remaining 4 characters can be used to add uniqueness. Managed
+ service account names will have a suffix of 3 random characters from
+ number and upper- and lowercase ASCII ranges appended to the chosen
+ short host name, using '!' as a separator. For a host with the
+ shortname 'myhost', a managed service account will have a common name
+ (CN attribute) 'myhost!A2c' and a NetBIOS name
+ (sAMAccountName attribute) will be 'myhost!A2c$'. A corresponding
+ Kerberos principal in the Active Directory domain where the managed
+ service account was created would be
+ 'myhost!A2c$@DOMAIN.EXAMPLE.COM'.</para>
+
+ <para>A keytab for the managed service account is stored into a file
+ specified with -K option. If it is not specified, the file is named
+ after the default keytab file, with lowercase Active Directory domain
+ of the managed service account as a suffix. On most systems it would be
+ <filename>/etc/krb5.keytab</filename> with a suffix of
+ 'domain.example.com', e.g.
+ <filename>/etc/krb5.keytad.domain.example.com</filename>.</para>
+
+ <para><command>adcli create-msa</command> can be called multiple
+ times to reset the password of the managed service account. To identify
+ the right account with the random component in the name the
+ corresponding principal is read from the keytab. If the keytab got
+ deleted <command>adcli</command> will try to identify an existing
+ managed service account with the help of the fully-qualified name, if
+ this fails a new managed service account will be created.</para>
+
+ <para>The managed service account password can be updated with
+<programlisting>
+$ adcli update --domain=domain.example.com --host-keytab=/etc/krb5.keytad.domain.example.com
+</programlisting>
+ and the managed service account can be deleted with
+<programlisting>
+$ adcli delete-computer --domain=domain.example.com 'myhost!A2c'
+</programlisting>
+ </para>
+
+ <para>In addition to the global options, you can specify the following
+ options to control how this operation is done.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>-N, --computer-name=<parameter>computer</parameter></option></term>
+ <listitem><para>The short non-dotted name of the managed
+ service account that will be created in the Active
+ Directory domain. The long option name
+ <option>--computer-name</option> is
+ kept to underline the similarity with the same option
+ of the other sub-commands. If not specified,
+ then the first portion of the <option>--host-fqdn</option>
+ or its default is used with a random suffix.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-O, --domain-ou=<parameter>OU=xxx</parameter></option></term>
+ <listitem><para>The full distinguished name of the OU in
+ which to create the managed service account. If not
+ specified, then the managed service account will be
+ created in a default location.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-H, --host-fqdn=<parameter>host</parameter></option></term>
+ <listitem><para>Override the local machine's fully
+ qualified DNS domain name. If not specified, the local
+ machine's hostname will be retrieved via
+ <function>gethostname()</function>.
+ If <function>gethostname()</function> only returns a short name
+ <function>getaddrinfo()</function> with the AI_CANONNAME hint
+ is called to expand the name to a fully qualified DNS
+ domain name.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
+ <listitem><para>Specify the path to the host keytab where
+ credentials of the managed service account will be
+ written after a successful creation. If not specified,
+ the default location will be used, usually
+ <filename>/etc/krb5.keytab</filename> with
+ the lower-cased Active Directory domain name added as a
+ suffix e.g.
+ <filename>/etc/krb5.keytab.domain.example.com</filename>.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--show-details</option></term>
+ <listitem><para>After a successful creation print out
+ information about the created object. This is output in
+ a format that should be both human and machine
+ readable.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--show-password</option></term>
+ <listitem><para>After a successful creation print out
+ the managed service account password. This is output in
+ a format that should be both human and machine
+ readable.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
<refsect1 id='delegation'>
<title>Delegated Permissions</title>
<para>It is common practice in AD to not use an account from the Domain
diff --git a/library/adenroll.c b/library/adenroll.c
index 5ae1f7b..dbfda36 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -155,6 +155,20 @@ struct _adcli_enroll {
char *description;
};
+static void
+check_if_service (adcli_enroll *enroll,
+ LDAP *ldap,
+ LDAPMessage *results)
+{
+ char **objectclasses = NULL;
+
+ objectclasses = _adcli_ldap_parse_values (ldap, results, "objectClass");
+ enroll->is_service = _adcli_strv_has_ex (objectclasses,
+ "msDS-ManagedServiceAccount",
+ strcasecmp) == 1 ? true : false;
+ _adcli_strv_free (objectclasses);
+}
+
static adcli_result
ensure_host_fqdn (adcli_result res,
adcli_enroll *enroll)
@@ -471,13 +485,15 @@ ensure_keytab_principals (adcli_result res,
{
krb5_context k5;
krb5_error_code code;
- int count;
+ int count = 0;
int at, i;
/* Prepare the principals we're going to add to the keytab */
- return_unexpected_if_fail (enroll->service_principals);
- count = _adcli_strv_len (enroll->service_principals);
+ if (!enroll->is_service) {
+ return_unexpected_if_fail (enroll->service_principals);
+ count = _adcli_strv_len (enroll->service_principals);
+ }
k5 = adcli_conn_get_krb5_context (enroll->conn);
return_unexpected_if_fail (k5 != NULL);
@@ -556,8 +572,12 @@ static adcli_result
lookup_computer_container (adcli_enroll *enroll,
LDAP *ldap)
{
- char *attrs[] = { "wellKnownObjects", NULL };
- char *prefix = "B:32:AA312825768811D1ADED00C04FD8D5CD:";
+ char *attrs[] = { enroll->is_service ? "otherWellKnownObjects"
+ : "wellKnownObjects", NULL };
+ const char *prefix = enroll->is_service ? "B:32:1EB93889E40C45DF9F0C64D23BBB6237:"
+ : "B:32:AA312825768811D1ADED00C04FD8D5CD:";
+ const char *filter = enroll->is_service ? "(&(objectClass=container)(cn=Managed Service Accounts))"
+ : "(&(objectClass=container)(cn=Computers))";
int prefix_len;
LDAPMessage *results;
const char *base;
@@ -586,7 +606,7 @@ lookup_computer_container (adcli_enroll *enroll,
"Couldn't lookup computer container: %s", base);
}
- values = _adcli_ldap_parse_values (ldap, results, "wellKnownObjects");
+ values = _adcli_ldap_parse_values (ldap, results, attrs[0]);
ldap_msgfree (results);
prefix_len = strlen (prefix);
@@ -604,8 +624,7 @@ lookup_computer_container (adcli_enroll *enroll,
/* Try harder */
if (!enroll->computer_container) {
- ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE,
- "(&(objectClass=container)(cn=Computers))",
+ ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_BASE, filter,
attrs, 0, NULL, NULL, NULL, -1, &results);
if (ret == LDAP_SUCCESS) {
enroll->computer_container = _adcli_ldap_parse_dn (ldap, results);
@@ -747,7 +766,7 @@ static adcli_result
create_computer_account (adcli_enroll *enroll,
LDAP *ldap)
{
- char *vals_objectClass[] = { "computer", NULL };
+ char *vals_objectClass[] = { enroll->is_service ? "msDS-ManagedServiceAccount" : "computer", NULL };
LDAPMod objectClass = { LDAP_MOD_ADD, "objectClass", { vals_objectClass, } };
char *vals_sAMAccountName[] = { enroll->computer_sam, NULL };
LDAPMod sAMAccountName = { LDAP_MOD_ADD, "sAMAccountName", { vals_sAMAccountName, } };
@@ -806,7 +825,7 @@ create_computer_account (adcli_enroll *enroll,
m = 0;
for (c = 0; c < mods_count - 1; c++) {
/* Skip empty LDAP sttributes */
- if (all_mods[c]->mod_vals.modv_strvals[0] != NULL) {
+ if (all_mods[c]->mod_vals.modv_strvals != NULL && all_mods[c]->mod_vals.modv_strvals[0] != NULL) {
mods[m++] = all_mods[c];
}
}
@@ -936,7 +955,7 @@ locate_computer_account (adcli_enroll *enroll,
LDAPMessage **rresults,
LDAPMessage **rentry)
{
- char *attrs[] = { "1.1", NULL };
+ char *attrs[] = { "objectClass", NULL };
LDAPMessage *results = NULL;
LDAPMessage *entry = NULL;
const char *base;
@@ -948,7 +967,9 @@ locate_computer_account (adcli_enroll *enroll,
/* If we don't yet know our computer dn, then try and find it */
value = _adcli_ldap_escape_filter (enroll->computer_sam);
return_unexpected_if_fail (value != NULL);
- if (asprintf (&filter, "(&(objectClass=computer)(sAMAccountName=%s))", value) < 0)
+ if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))",
+ enroll->is_service ? "msDS-ManagedServiceAccount" : "computer",
+ value) < 0)
return_unexpected_if_reached ();
free (value);
@@ -962,8 +983,11 @@ locate_computer_account (adcli_enroll *enroll,
if (ret == LDAP_SUCCESS) {
entry = ldap_first_entry (ldap, results);
- /* If we found a computer account, make note of dn */
+ /* If we found a computer/service account, make note of dn */
if (entry) {
+ if (!enroll->is_service_explicit) {
+ check_if_service ( enroll, ldap, results);
+ }
dn = ldap_get_dn (ldap, entry);
free (enroll->computer_dn);
enroll->computer_dn = strdup (dn);
@@ -1003,7 +1027,7 @@ load_computer_account (adcli_enroll *enroll,
LDAPMessage **rresults,
LDAPMessage **rentry)
{
- char *attrs[] = { "1.1", NULL };
+ char *attrs[] = { "objectClass", NULL };
LDAPMessage *results = NULL;
LDAPMessage *entry = NULL;
int ret;
@@ -1081,6 +1105,12 @@ locate_or_create_computer_account (adcli_enroll *enroll,
if (res == ADCLI_SUCCESS && entry == NULL)
res = create_computer_account (enroll, ldap);
+ /* Service account already exists, just continue and update the
+ * password */
+ if (enroll->is_service && entry != NULL) {
+ res = ADCLI_SUCCESS;
+ }
+
if (results)
ldap_msgfree (results);
@@ -1413,6 +1443,11 @@ update_computer_account (adcli_enroll *enroll)
LDAP *ldap;
char *value = NULL;
+ /* No updates for service accounts */
+ if (enroll->is_service) {
+ return;
+ }
+
ldap = adcli_conn_get_ldap_connection (enroll->conn);
return_if_fail (ldap != NULL);
@@ -1501,6 +1536,11 @@ update_service_principals (adcli_enroll *enroll)
LDAP *ldap;
int ret;
+ /* No updates for service accounts */
+ if (enroll->is_service) {
+ return ADCLI_SUCCESS;
+ }
+
ldap = adcli_conn_get_ldap_connection (enroll->conn);
return_unexpected_if_fail (ldap != NULL);
@@ -1614,6 +1654,8 @@ load_keytab_entry (krb5_context k5,
enroll->computer_name = name;
name[len - 1] = '\0';
_adcli_info ("Found computer name in keytab: %s", name);
+ adcli_conn_set_computer_name (enroll->conn,
+ enroll->computer_name);
name = NULL;
} else if (!enroll->host_fqdn && _adcli_str_has_prefix (name, "host/") && strchr (name, '.')) {
@@ -2002,17 +2044,25 @@ adcli_enroll_prepare (adcli_enroll *enroll,
adcli_clear_last_error ();
- /* Basic discovery and figuring out enroll params */
- res = ensure_host_fqdn (res, enroll);
- res = ensure_computer_name (res, enroll);
- res = ensure_computer_sam (res, enroll);
- res = ensure_user_principal (res, enroll);
- res = ensure_computer_password (res, enroll);
- if (!(flags & ADCLI_ENROLL_NO_KEYTAB))
+ if (enroll->is_service) {
+ /* Ensure basic params for service accounts */
+ res = ensure_computer_sam (res, enroll);
+ res = ensure_computer_password (res, enroll);
res = ensure_host_keytab (res, enroll);
- res = ensure_service_names (res, enroll);
- res = ensure_service_principals (res, enroll);
- res = ensure_keytab_principals (res, enroll);
+ res = ensure_keytab_principals (res, enroll);
+ } else {
+ /* Basic discovery and figuring out enroll params */
+ res = ensure_host_fqdn (res, enroll);
+ res = ensure_computer_name (res, enroll);
+ res = ensure_computer_sam (res, enroll);
+ res = ensure_user_principal (res, enroll);
+ res = ensure_computer_password (res, enroll);
+ if (!(flags & ADCLI_ENROLL_NO_KEYTAB))
+ res = ensure_host_keytab (res, enroll);
+ res = ensure_service_names (res, enroll);
+ res = ensure_service_principals (res, enroll);
+ res = ensure_keytab_principals (res, enroll);
+ }
return res;
}
@@ -2157,6 +2207,58 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
return update_keytab_for_principals (enroll, flags);
}
+static adcli_result
+adcli_enroll_add_description_for_service_account (adcli_enroll *enroll)
+{
+ const char *fqdn;
+ char *desc;
+
+ fqdn = adcli_conn_get_host_fqdn (enroll->conn);
+ return_unexpected_if_fail (fqdn != NULL);
+ if (asprintf (&desc, "Please do not edit, Service account for %s, "
+ "managed by adcli.", fqdn) < 0) {
+ return_unexpected_if_reached ();
+ }
+
+ adcli_enroll_set_description (enroll, desc);
+ free (desc);
+
+ return ADCLI_SUCCESS;
+}
+
+static adcli_result
+adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll)
+{
+ krb5_context k5;
+ krb5_error_code code;
+ char def_keytab_name[MAX_KEYTAB_NAME_LEN];
+ char *lc_dom_name;
+ int ret;
+
+ if (adcli_enroll_get_keytab_name (enroll) == NULL) {
+ k5 = adcli_conn_get_krb5_context (enroll->conn);
+ return_unexpected_if_fail (k5 != NULL);
+
+ code = krb5_kt_default_name (k5, def_keytab_name,
+ sizeof (def_keytab_name));
+ return_unexpected_if_fail (code == 0);
+
+ lc_dom_name = strdup (adcli_conn_get_domain_name (enroll->conn));
+ return_unexpected_if_fail (lc_dom_name != NULL);
+ _adcli_str_down (lc_dom_name);
+
+
+ ret = asprintf (&enroll->keytab_name, "%s.%s", def_keytab_name,
+ lc_dom_name);
+ free (lc_dom_name);
+ return_unexpected_if_fail (ret > 0);
+ }
+
+ _adcli_info ("Using service account keytab: %s", enroll->keytab_name);
+
+ return ADCLI_SUCCESS;
+}
+
adcli_result
adcli_enroll_join (adcli_enroll *enroll,
adcli_enroll_flags flags)
@@ -2172,7 +2274,14 @@ adcli_enroll_join (adcli_enroll *enroll,
if (res != ADCLI_SUCCESS)
return res;
- res = ensure_default_service_names (enroll);
+ if (enroll->is_service) {
+ res = adcli_enroll_add_description_for_service_account (enroll);
+ if (res == ADCLI_SUCCESS) {
+ res = adcli_enroll_add_keytab_for_service_account (enroll);
+ }
+ } else {
+ res = ensure_default_service_names (enroll);
+ }
if (res != ADCLI_SUCCESS)
return res;
@@ -2281,6 +2390,11 @@ adcli_enroll_update (adcli_enroll *enroll,
}
free (value);
+ /* We only support password changes for service accounts */
+ if (enroll->is_service && (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
+ return ADCLI_SUCCESS;
+ }
+
return enroll_join_or_update_tasks (enroll, flags);
}
diff --git a/tools/computer.c b/tools/computer.c
index 5a97d8b..63fd374 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -1074,3 +1074,128 @@ adcli_tool_computer_show (adcli_conn *conn,
adcli_enroll_unref (enroll);
return 0;
}
+
+int
+adcli_tool_computer_managed_service_account (adcli_conn *conn,
+ int argc,
+ char *argv[])
+{
+ adcli_enroll *enroll;
+ adcli_result res;
+ int show_password = 0;
+ int details = 0;
+ int opt;
+
+ struct option options[] = {
+ { "domain", required_argument, NULL, opt_domain },
+ { "domain-realm", required_argument, NULL, opt_domain_realm },
+ { "domain-controller", required_argument, NULL, opt_domain_controller },
+ { "use-ldaps", no_argument, 0, opt_use_ldaps },
+ { "login-user", required_argument, NULL, opt_login_user },
+ { "login-ccache", optional_argument, NULL, opt_login_ccache },
+ { "host-fqdn", required_argument, 0, opt_host_fqdn },
+ { "computer-name", required_argument, 0, opt_computer_name },
+ { "host-keytab", required_argument, 0, opt_host_keytab },
+ { "no-password", no_argument, 0, opt_no_password },
+ { "stdin-password", no_argument, 0, opt_stdin_password },
+ { "prompt-password", no_argument, 0, opt_prompt_password },
+ { "domain-ou", required_argument, NULL, opt_domain_ou },
+ { "show-details", no_argument, NULL, opt_show_details },
+ { "show-password", no_argument, NULL, opt_show_password },
+ { "verbose", no_argument, NULL, opt_verbose },
+ { "help", no_argument, NULL, 'h' },
+ { 0 },
+ };
+
+ static adcli_tool_desc usages[] = {
+ { 0, "usage: adcli create-msa --domain=xxxx" },
+ { 0 },
+ };
+
+ enroll = adcli_enroll_new (conn);
+ if (enroll == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
+
+ while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+ switch (opt) {
+ case opt_one_time_password:
+ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT);
+ adcli_conn_set_computer_password (conn, optarg);
+ break;
+ case opt_show_details:
+ details = 1;
+ break;
+ case opt_show_password:
+ show_password = 1;
+ break;
+ case 'h':
+ case '?':
+ case ':':
+ adcli_tool_usage (options, usages);
+ adcli_tool_usage (options, common_usages);
+ adcli_enroll_unref (enroll);
+ return opt == 'h' ? 0 : 2;
+ default:
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1)
+ adcli_conn_set_domain_name (conn, argv[0]);
+ else if (argc > 1) {
+ warnx ("extra arguments specified");
+ adcli_enroll_unref (enroll);
+ return 2;
+ }
+
+ if (adcli_conn_get_domain_name (conn) == NULL) {
+ warnx ("domain name is required");
+ adcli_enroll_unref (enroll);
+ return 2;
+ }
+
+ adcli_enroll_set_is_service (enroll, true);
+ adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+
+ res = adcli_enroll_load (enroll);
+ if (res != ADCLI_SUCCESS) {
+ /* ignored */
+ }
+
+ res = adcli_conn_connect (conn);
+ if (res != ADCLI_SUCCESS) {
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
+ }
+
+ res = adcli_enroll_join (enroll, 0);
+ if (res != ADCLI_SUCCESS) {
+ warnx ("Adding service account for %s failed: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_enroll_unref (enroll);
+ return -res;
+ }
+
+ if (details)
+ dump_details (conn, enroll, show_password);
+ else if (show_password)
+ dump_password (conn, enroll);
+
+ adcli_enroll_unref (enroll);
+
+ return 0;
+}
diff --git a/tools/tools.c b/tools/tools.c
index 1b6d879..d0dcf98 100644
--- a/tools/tools.c
+++ b/tools/tools.c
@@ -60,6 +60,7 @@ struct {
{ "reset-computer", adcli_tool_computer_reset, "Reset a computer account", },
{ "delete-computer", adcli_tool_computer_delete, "Delete a computer account", },
{ "show-computer", adcli_tool_computer_show, "Show computer account attributes stored in AD", },
+ { "create-msa", adcli_tool_computer_managed_service_account, "Create a managed service account in the given AD domain", },
{ "create-user", adcli_tool_user_create, "Create a user account", },
{ "delete-user", adcli_tool_user_delete, "Delete a user account", },
{ "create-group", adcli_tool_group_create, "Create a group", },
diff --git a/tools/tools.h b/tools/tools.h
index 3702875..82d5e4e 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -82,6 +82,10 @@ int adcli_tool_computer_show (adcli_conn *conn,
int argc,
char *argv[]);
+int adcli_tool_computer_managed_service_account (adcli_conn *conn,
+ int argc,
+ char *argv[]);
+
int adcli_tool_user_create (adcli_conn *conn,
int argc,
char *argv[]);
--
2.28.0

View File

@ -0,0 +1,147 @@
From 408880a11879b1a57a450e25c77ef2e310bdffd5 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 18 Mar 2019 16:45:54 +0100
Subject: [PATCH 2/2] create-user: try to find NIS domain if needed
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/2
---
doc/adcli.xml | 4 +++-
library/adentry.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
library/adentry.h | 2 ++
tools/entry.c | 16 ++++++++++++++++
4 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 18620c0..af73433 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -537,7 +537,9 @@ $ adcli create-user Fry --domain=domain.example.com \
the new created user account, which should be the user's
NIS domain is the NIS/YP service of Active Directory's Services for Unix (SFU)
are used. This is needed to let the 'UNIX attributes' tab of older Active
- Directoy versions show the set UNIX specific attributes.</para></listitem>
+ Directoy versions show the set UNIX specific attributes. If not specified
+ adcli will try to determine the NIS domain automatically if needed.
+ </para></listitem>
</varlistentry>
</variablelist>
diff --git a/library/adentry.c b/library/adentry.c
index 9b9e1c6..1cc0518 100644
--- a/library/adentry.c
+++ b/library/adentry.c
@@ -484,3 +484,47 @@ adcli_entry_new_group (adcli_conn *conn,
return_val_if_fail (sam_name != NULL, NULL);
return entry_new (conn, "group", group_entry_builder, sam_name);
}
+
+adcli_result
+adcli_get_nis_domain (adcli_entry *entry,
+ adcli_attrs *attrs)
+{
+ LDAP *ldap;
+ const char *ldap_attrs[] = { "cn", NULL };
+ LDAPMessage *results;
+ LDAPMessage *ldap_entry;
+ char *base;
+ const char *filter = "objectClass=msSFU30DomainInfo";
+ char *cn;
+ int ret;
+
+ ldap = adcli_conn_get_ldap_connection (entry->conn);
+ return_unexpected_if_fail (ldap != NULL);
+
+ if (asprintf (&base, "CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,%s",
+ adcli_conn_get_default_naming_context (entry->conn)) < 0) {
+ return_unexpected_if_reached ();
+ }
+
+ ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_SUB, filter, (char **)ldap_attrs,
+ 0, NULL, NULL, NULL, -1, &results);
+
+ free (base);
+
+ if (ret != LDAP_SUCCESS) {
+ /* No NIS domain available */
+ ldap_msgfree (results);
+ return ADCLI_SUCCESS;
+ }
+
+ ldap_entry = ldap_first_entry (ldap, results);
+ if (ldap_entry != NULL) {
+ cn = _adcli_ldap_parse_value (ldap, ldap_entry, "cn");
+ return_unexpected_if_fail (cn != NULL);
+
+ adcli_attrs_add (attrs, "msSFU30NisDomain", cn, NULL);
+ }
+ ldap_msgfree (results);
+
+ return ADCLI_SUCCESS;
+}
diff --git a/library/adentry.h b/library/adentry.h
index eb8bc00..ae90689 100644
--- a/library/adentry.h
+++ b/library/adentry.h
@@ -58,4 +58,6 @@ const char * adcli_entry_get_sam_name (adcli_entry *entry);
const char * adcli_entry_get_dn (adcli_entry *entry);
+adcli_result adcli_get_nis_domain (adcli_entry *entry,
+ adcli_attrs *attrs);
#endif /* ADENTRY_H_ */
diff --git a/tools/entry.c b/tools/entry.c
index 69ce62c..de56586 100644
--- a/tools/entry.c
+++ b/tools/entry.c
@@ -153,6 +153,8 @@ adcli_tool_user_create (adcli_conn *conn,
adcli_attrs *attrs;
const char *ou = NULL;
int opt;
+ bool has_unix_attr = false;
+ bool has_nis_domain = false;
struct option options[] = {
{ "display-name", required_argument, NULL, opt_display_name },
@@ -193,18 +195,23 @@ adcli_tool_user_create (adcli_conn *conn,
break;
case opt_unix_home:
adcli_attrs_add (attrs, "unixHomeDirectory", optarg, NULL);
+ has_unix_attr = true;
break;
case opt_unix_uid:
adcli_attrs_add (attrs, "uidNumber", optarg, NULL);
+ has_unix_attr = true;
break;
case opt_unix_gid:
adcli_attrs_add (attrs, "gidNumber", optarg, NULL);
+ has_unix_attr = true;
break;
case opt_unix_shell:
adcli_attrs_add (attrs, "loginShell", optarg, NULL);
+ has_unix_attr = true;
break;
case opt_nis_domain:
adcli_attrs_add (attrs, "msSFU30NisDomain", optarg, NULL);
+ has_nis_domain = true;
break;
case opt_domain_ou:
ou = optarg;
@@ -242,6 +249,15 @@ adcli_tool_user_create (adcli_conn *conn,
adcli_get_last_error ());
}
+ if (has_unix_attr && !has_nis_domain) {
+ res = adcli_get_nis_domain (entry, attrs);
+ if (res != ADCLI_SUCCESS) {
+ adcli_entry_unref (entry);
+ adcli_attrs_free (attrs);
+ errx (-res, "couldn't get NIS domain");
+ }
+ }
+
res = adcli_entry_create (entry, attrs);
if (res != ADCLI_SUCCESS) {
errx (-res, "creating user %s in domain %s failed: %s",
--
2.20.1

View File

@ -0,0 +1,42 @@
From e1b45e66bc185f5db4c252e1f3fb1b4400b4538e Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 22 Mar 2019 10:36:38 +0100
Subject: [PATCH 2/4] library: make _adcli_strv_has_ex public
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
---
library/adprivate.h | 4 ++++
library/adutil.c | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/library/adprivate.h b/library/adprivate.h
index 0806430..55e6234 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -125,6 +125,10 @@ void _adcli_strv_free (char **strv);
int _adcli_strv_has (char **strv,
const char *str);
+int _adcli_strv_has_ex (char **strv,
+ const char *str,
+ int (* compare) (const char *match, const char*value));
+
char ** _adcli_strv_dup (char **strv) GNUC_WARN_UNUSED;
char * _adcli_strv_join (char **strv,
diff --git a/library/adutil.c b/library/adutil.c
index 76ea158..9b0c47f 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -221,7 +221,7 @@ _adcli_strv_add (char **strv,
return seq_push (strv, length, string);
}
-static int
+int
_adcli_strv_has_ex (char **strv,
const char *str,
int (* compare) (const char *match, const char*value))
--
2.20.1

View File

@ -0,0 +1,35 @@
From 4987a21f4839ab7ea50e932c72df05075efb89b3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 21 Mar 2019 15:05:33 +0100
Subject: [PATCH 2/2] library: return error if no matching key was found
To avoid a misleading debug message indicating success a proper erro
code should be returned the no matching key was found when trying to
copy an keytab entry for a new principal.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1644311
---
library/adkrb5.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/library/adkrb5.c b/library/adkrb5.c
index 033c181..7f77373 100644
--- a/library/adkrb5.c
+++ b/library/adkrb5.c
@@ -298,11 +298,10 @@ _adcli_krb5_keytab_copy_entries (krb5_context k5,
code = _adcli_krb5_get_keyblock (k5, keytab, &entry.key,
match_enctype_and_kvno, &closure);
- if (code != 0) {
- return code;
+ if (code != 0 || closure.matched == 0) {
+ return code != 0 ? code : ENOKEY;
}
-
entry.principal = principal;
entry.vno = kvno;
--
2.20.1

View File

@ -0,0 +1,398 @@
From cac0fa9df8888245399f2db187e05e31f93d1471 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 15 Apr 2019 17:56:37 +0200
Subject: [PATCH 2/7] tools: remove errx from user and group commands
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/entry.c | 232 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 154 insertions(+), 78 deletions(-)
diff --git a/tools/entry.c b/tools/entry.c
index de56586..97ec6e7 100644
--- a/tools/entry.c
+++ b/tools/entry.c
@@ -232,21 +232,30 @@ adcli_tool_user_create (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc != 1)
- errx (2, "specify one user name to create");
+ if (argc != 1) {
+ warnx ("specify one user name to create");
+ adcli_attrs_free (attrs);
+ return 2;
+ }
entry = adcli_entry_new_user (conn, argv[0]);
- if (entry == NULL)
- errx (-1, "unexpected memory problems");
+ if (entry == NULL) {
+ warnx ("unexpected memory problems");
+ adcli_attrs_free (attrs);
+ return -1;
+ }
adcli_entry_set_domain_ou (entry, ou);
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ adcli_attrs_free (attrs);
+ return -res;
}
if (has_unix_attr && !has_nis_domain) {
@@ -254,16 +263,20 @@ adcli_tool_user_create (adcli_conn *conn,
if (res != ADCLI_SUCCESS) {
adcli_entry_unref (entry);
adcli_attrs_free (attrs);
- errx (-res, "couldn't get NIS domain");
+ warnx ("couldn't get NIS domain");
+ return -res;
}
}
res = adcli_entry_create (entry, attrs);
if (res != ADCLI_SUCCESS) {
- errx (-res, "creating user %s in domain %s failed: %s",
- adcli_entry_get_sam_name (entry),
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("creating user %s in domain %s failed: %s",
+ adcli_entry_get_sam_name (entry),
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ adcli_attrs_free (attrs);
+ return -res;
}
adcli_entry_unref (entry);
@@ -317,28 +330,36 @@ adcli_tool_user_delete (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc != 1)
- errx (2, "specify one user name to delete");
+ if (argc != 1) {
+ warnx ("specify one user name to delete");
+ return 2;
+ }
entry = adcli_entry_new_user (conn, argv[0]);
- if (entry == NULL)
- errx (-1, "unexpected memory problems");
+ if (entry == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
res = adcli_entry_delete (entry);
if (res != ADCLI_SUCCESS) {
- errx (-res, "deleting user %s in domain %s failed: %s",
- adcli_entry_get_sam_name (entry),
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("deleting user %s in domain %s failed: %s",
+ adcli_entry_get_sam_name (entry),
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
adcli_entry_unref (entry);
@@ -404,29 +425,41 @@ adcli_tool_group_create (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc != 1)
- errx (2, "specify one group to create");
+ if (argc != 1) {
+ warnx ("specify one group to create");
+ adcli_attrs_free (attrs);
+ return 2;
+ }
entry = adcli_entry_new_group (conn, argv[0]);
- if (entry == NULL)
- errx (-1, "unexpected memory problems");
+ if (entry == NULL) {
+ warnx ("unexpected memory problems");
+ adcli_attrs_free (attrs);
+ return -1;
+ }
adcli_entry_set_domain_ou (entry, ou);
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to domain %s: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to domain %s: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ adcli_attrs_free (attrs);
+ return -res;
}
res = adcli_entry_create (entry, attrs);
if (res != ADCLI_SUCCESS) {
- errx (-res, "creating group %s in domain %s failed: %s",
- adcli_entry_get_sam_name (entry),
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("creating group %s in domain %s failed: %s",
+ adcli_entry_get_sam_name (entry),
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ adcli_attrs_free (attrs);
+ return -res;
}
adcli_entry_unref (entry);
@@ -480,28 +513,36 @@ adcli_tool_group_delete (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc != 1)
- errx (2, "specify one group name to delete");
+ if (argc != 1) {
+ warnx ("specify one group name to delete");
+ return 2;
+ }
entry = adcli_entry_new_group (conn, argv[0]);
- if (entry == NULL)
- errx (-1, "unexpected memory problems");
+ if (entry == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
res = adcli_entry_delete (entry);
if (res != ADCLI_SUCCESS) {
- errx (-res, "deleting group %s in domain %s failed: %s",
- adcli_entry_get_sam_name (entry),
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("deleting group %s in domain %s failed: %s",
+ adcli_entry_get_sam_name (entry),
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
adcli_entry_unref (entry);
@@ -509,7 +550,7 @@ adcli_tool_group_delete (adcli_conn *conn,
return 0;
}
-static void
+static int
expand_user_dn_as_member (adcli_conn *conn,
adcli_attrs *attrs,
const char *user,
@@ -523,16 +564,19 @@ expand_user_dn_as_member (adcli_conn *conn,
res = adcli_entry_load (entry);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't lookup user %s in domain %s: %s",
- user, adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't lookup user %s in domain %s: %s",
+ user, adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
dn = adcli_entry_get_dn (entry);
if (dn == NULL) {
- errx (-ADCLI_ERR_CONFIG,
- "couldn't found user %s in domain %s",
- user, adcli_conn_get_domain_name (conn));
+ warnx ("couldn't found user %s in domain %s",
+ user, adcli_conn_get_domain_name (conn));
+ adcli_entry_unref (entry);
+ return -ADCLI_ERR_CONFIG;
}
if (adding)
@@ -541,6 +585,8 @@ expand_user_dn_as_member (adcli_conn *conn,
adcli_attrs_delete1 (attrs, "member", dn);
adcli_entry_unref (entry);
+
+ return ADCLI_SUCCESS;
}
int
@@ -590,33 +636,48 @@ adcli_tool_member_add (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc < 2)
- errx (2, "specify a group name and a user to add");
+ if (argc < 2) {
+ warnx ("specify a group name and a user to add");
+ return 2;
+ }
entry = adcli_entry_new_group (conn, argv[0]);
- if (entry == NULL)
- errx (-1, "unexpected memory problems");
+ if (entry == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
attrs = adcli_attrs_new ();
- for (i = 1; i < argc; i++)
- expand_user_dn_as_member (conn, attrs, argv[i], 1);
+ for (i = 1; i < argc; i++) {
+ res = expand_user_dn_as_member (conn, attrs, argv[i], 1);
+ if (res != ADCLI_SUCCESS) {
+ adcli_attrs_free (attrs);
+ adcli_entry_unref (entry);
+ return res;
+ }
+ }
res = adcli_entry_modify (entry, attrs);
if (res != ADCLI_SUCCESS) {
- errx (-res, "adding member(s) to group %s in domain %s failed: %s",
- adcli_entry_get_sam_name (entry),
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("adding member(s) to group %s in domain %s failed: %s",
+ adcli_entry_get_sam_name (entry),
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_attrs_free (attrs);
+ adcli_entry_unref (entry);
+ return -res;
}
adcli_attrs_free (attrs);
@@ -672,33 +733,48 @@ adcli_tool_member_remove (adcli_conn *conn,
argc -= optind;
argv += optind;
- if (argc < 2)
- errx (2, "specify a group name and a user to remove");
+ if (argc < 2) {
+ warnx ("specify a group name and a user to remove");
+ return 2;
+ }
entry = adcli_entry_new_group (conn, argv[0]);
- if (entry == NULL)
- errx (-1, "unexpected memory problems");
+ if (entry == NULL) {
+ warnx ("unexpected memory problems");
+ return -1;
+ }
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
res = adcli_conn_connect (conn);
if (res != ADCLI_SUCCESS) {
- errx (-res, "couldn't connect to %s domain: %s",
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("couldn't connect to %s domain: %s",
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_entry_unref (entry);
+ return -res;
}
attrs = adcli_attrs_new ();
- for (i = 1; i < argc; i++)
- expand_user_dn_as_member (conn, attrs, argv[i], 0);
+ for (i = 1; i < argc; i++) {
+ res = expand_user_dn_as_member (conn, attrs, argv[i], 0);
+ if (res != ADCLI_SUCCESS) {
+ adcli_attrs_free (attrs);
+ adcli_entry_unref (entry);
+ return res;
+ }
+ }
res = adcli_entry_modify (entry, attrs);
if (res != ADCLI_SUCCESS) {
- errx (-res, "adding member(s) to group %s in domain %s failed: %s",
- adcli_entry_get_sam_name (entry),
- adcli_conn_get_domain_name (conn),
- adcli_get_last_error ());
+ warnx ("adding member(s) to group %s in domain %s failed: %s",
+ adcli_entry_get_sam_name (entry),
+ adcli_conn_get_domain_name (conn),
+ adcli_get_last_error ());
+ adcli_attrs_free (attrs);
+ adcli_entry_unref (entry);
+ return -res;
}
adcli_attrs_free (attrs);
--
2.20.1

View File

@ -0,0 +1,57 @@
From f05adc23d5cc9f1dfa5638e31949dcd81d632df9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 13 Aug 2018 17:32:24 +0200
Subject: [PATCH 3/4] Do not add service principals twice
---
library/adenroll.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index c4ba537..bb50365 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -313,6 +313,7 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
char *name;
int length = 0;
int i;
+ size_t c;
if (enroll->service_principals != NULL) {
length = seq_count (enroll->service_principals);
@@ -321,14 +322,28 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
for (i = 0; enroll->service_names[i] != NULL; i++) {
if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
return_unexpected_if_reached ();
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- name, &length);
+ for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
+ if (strcmp (name, enroll->service_principals[c]) == 0) {
+ break;
+ }
+ }
+ if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+ name, &length);
+ }
if (enroll->host_fqdn) {
if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
return_unexpected_if_reached ();
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- name, &length);
+ for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
+ if (strcmp (name, enroll->service_principals[c]) == 0) {
+ break;
+ }
+ }
+ if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+ name, &length);
+ }
}
}
--
2.17.1

View File

@ -0,0 +1,196 @@
From 0c09070e8beec734e3f0c70e14b0a04788077b73 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 13 Jun 2019 17:25:52 +0200
Subject: [PATCH 3/4] adenroll: add adcli_enroll_get_permitted_keytab_enctypes
with tests
The new call does not only return the current encryption types set in AD
or a default list but filters them with the list of permitted encryption
types on the client. This makes sure the client can create and use the
keys.
Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3
---
library/Makefile.am | 5 ++
library/adenroll.c | 124 ++++++++++++++++++++++++++++++++++++++++++++
library/adenroll.h | 2 +
3 files changed, 131 insertions(+)
diff --git a/library/Makefile.am b/library/Makefile.am
index 39e8fd1..4829555 100644
--- a/library/Makefile.am
+++ b/library/Makefile.am
@@ -40,6 +40,7 @@ check_PROGRAMS = \
test-util \
test-ldap \
test-attrs \
+ test-adenroll \
$(NULL)
test_seq_SOURCES = seq.c test.c test.h
@@ -56,6 +57,10 @@ test_attrs_SOURCES = adattrs.c $(test_ldap_SOURCES)
test_attrs_CFLAGS = -DATTRS_TESTS
test_attrs_LDADD = $(test_ldap_LDADD)
+test_adenroll_SOURCES = adenroll.c $(test_ldap_SOURCES)
+test_adenroll_CFLAGS = -DADENROLL_TESTS
+test_adenroll_LDADD = $(KRB5_LIBS)
+
TESTS = $(check_PROGRAMS)
MEMCHECK_ENV = $(TEST_RUNNER) valgrind --error-exitcode=80 --quiet --trace-children=yes
diff --git a/library/adenroll.c b/library/adenroll.c
index f617f28..95c07cd 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -2641,6 +2641,50 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
return v51_earlier_enctypes;
}
+krb5_enctype *
+adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll)
+{
+ krb5_enctype *cur_enctypes;
+ krb5_enctype *permitted_enctypes;
+ krb5_enctype *new_enctypes;
+ krb5_error_code code;
+ krb5_context k5;
+ size_t c;
+ size_t p;
+ size_t n;
+
+ return_val_if_fail (enroll != NULL, NULL);
+ cur_enctypes = adcli_enroll_get_keytab_enctypes (enroll);
+
+ k5 = adcli_conn_get_krb5_context (enroll->conn);
+ return_val_if_fail (k5 != NULL, NULL);
+
+ code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
+ return_val_if_fail (code == 0, NULL);
+
+ for (c = 0; cur_enctypes[c] != 0; c++);
+
+ new_enctypes = calloc (c + 1, sizeof (krb5_enctype));
+ return_val_if_fail (new_enctypes != NULL, NULL);
+
+ n = 0;
+ for (c = 0; cur_enctypes[c] != 0; c++) {
+ for (p = 0; permitted_enctypes[p] != 0; p++) {
+ if (cur_enctypes[c] == permitted_enctypes[p]) {
+ new_enctypes[n++] = cur_enctypes[c];
+ break;
+ }
+ }
+ if (permitted_enctypes[p] == 0) {
+ _adcli_info ("Encryption type [%d] not permitted.", cur_enctypes[c]);
+ }
+ }
+
+ krb5_free_enctypes (k5, permitted_enctypes);
+
+ return new_enctypes;
+}
+
void
adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll,
krb5_enctype *value)
@@ -2833,3 +2877,83 @@ adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
strdup (value), NULL);
return_if_fail (enroll->service_principals_to_remove != NULL);
}
+
+#ifdef ADENROLL_TESTS
+
+#include "test.h"
+
+static void
+test_adcli_enroll_get_permitted_keytab_enctypes (void)
+{
+ krb5_enctype *enctypes;
+ krb5_error_code code;
+ krb5_enctype *permitted_enctypes;
+ krb5_enctype check_enctypes[3] = { 0 };
+ adcli_conn *conn;
+ adcli_enroll *enroll;
+ adcli_result res;
+ krb5_context k5;
+ size_t c;
+
+ conn = adcli_conn_new ("test.dom");
+ assert_ptr_not_null (conn);
+
+ enroll = adcli_enroll_new (conn);
+ assert_ptr_not_null (enroll);
+
+ enctypes = adcli_enroll_get_permitted_keytab_enctypes (NULL);
+ assert_ptr_eq (enctypes, NULL);
+
+ /* krb5 context missing */
+ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
+ assert_ptr_eq (enctypes, NULL);
+
+ /* check that all permitted enctypes can pass */
+ res = _adcli_krb5_init_context (&k5);
+ assert_num_eq (res, ADCLI_SUCCESS);
+
+ adcli_conn_set_krb5_context (conn, k5);
+
+ code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
+ assert_num_eq (code, 0);
+ assert_ptr_not_null (permitted_enctypes);
+ assert_num_cmp (permitted_enctypes[0], !=, 0);
+
+ adcli_enroll_set_keytab_enctypes (enroll, permitted_enctypes);
+
+ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
+ assert_ptr_not_null (enctypes);
+ for (c = 0; permitted_enctypes[c] != 0; c++) {
+ assert_num_eq (enctypes[c], permitted_enctypes[c]);
+ }
+ assert_num_eq (enctypes[c], 0);
+ krb5_free_enctypes (k5, enctypes);
+
+ /* check that ENCTYPE_UNKNOWN is filtered out */
+ check_enctypes[0] = permitted_enctypes[0];
+ check_enctypes[1] = ENCTYPE_UNKNOWN;
+ check_enctypes[2] = 0;
+ adcli_enroll_set_keytab_enctypes (enroll, check_enctypes);
+
+ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
+ assert_ptr_not_null (enctypes);
+ assert_num_eq (enctypes[0], permitted_enctypes[0]);
+ assert_num_eq (enctypes[1], 0);
+ krb5_free_enctypes (k5, enctypes);
+
+ krb5_free_enctypes (k5, permitted_enctypes);
+
+ adcli_enroll_unref (enroll);
+ adcli_conn_unref (conn);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ test_func (test_adcli_enroll_get_permitted_keytab_enctypes,
+ "/attrs/adcli_enroll_get_permitted_keytab_enctypes");
+ return test_run (argc, argv);
+}
+
+#endif /* ADENROLL_TESTS */
diff --git a/library/adenroll.h b/library/adenroll.h
index abbbfd4..1d5d00d 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -138,6 +138,8 @@ krb5_enctype * adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll);
void adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll,
krb5_enctype *enctypes);
+krb5_enctype * adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll);
+
const char * adcli_enroll_get_os_name (adcli_enroll *enroll);
void adcli_enroll_set_os_name (adcli_enroll *enroll,
--
2.21.0

View File

@ -0,0 +1,26 @@
From 85fa595baf689e85c0d897c5eef73fdf1ecc1581 Mon Sep 17 00:00:00 2001
From: Striker Leggette <striker@redhat.com>
Date: Wed, 1 Nov 2017 11:16:39 +0100
Subject: [PATCH 03/23] correct spelling of 'adcli_tool_computer_delete'
description
---
tools/tools.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/tools.c b/tools/tools.c
index 4b243de..915130e 100644
--- a/tools/tools.c
+++ b/tools/tools.c
@@ -57,7 +57,7 @@ struct {
{ "update", adcli_tool_computer_update, "Update machine membership in a domain", },
{ "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 acocunt", },
+ { "delete-computer", adcli_tool_computer_delete, "Delete a computer account", },
{ "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", },
--
2.14.4

View File

@ -0,0 +1,358 @@
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 3/7] enroll: use 'computer' or 'service' in debug messages
Use proper account type in debug messages.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
library/adenroll.c | 115 ++++++++++++++++++++++++++++-----------------
1 file changed, 72 insertions(+), 43 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index dbfda36..9cdc79b 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -155,6 +155,12 @@ struct _adcli_enroll {
char *description;
};
+static const char *
+s_or_c (adcli_enroll *enroll)
+{
+ return enroll->is_service ? "service" : "computer";
+}
+
static void
check_if_service (adcli_enroll *enroll,
LDAP *ldap,
@@ -203,13 +209,15 @@ ensure_computer_name (adcli_result res,
return res;
if (enroll->computer_name) {
- _adcli_info ("Enrolling computer name: %s",
+ _adcli_info ("Enrolling %s name: %s",
+ s_or_c (enroll),
enroll->computer_name);
return ADCLI_SUCCESS;
}
if (!enroll->host_fqdn) {
- _adcli_err ("No host name from which to determine the computer name");
+ _adcli_err ("No host name from which to determine the %s name",
+ s_or_c (enroll));
return ADCLI_ERR_CONFIG;
}
@@ -603,7 +611,8 @@ lookup_computer_container (adcli_enroll *enroll,
} else if (ret != LDAP_SUCCESS) {
return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
- "Couldn't lookup computer container: %s", base);
+ "Couldn't lookup %s container: %s",
+ s_or_c (enroll), base);
}
values = _adcli_ldap_parse_values (ldap, results, attrs[0]);
@@ -614,8 +623,8 @@ lookup_computer_container (adcli_enroll *enroll,
if (strncmp (values[i], prefix, prefix_len) == 0) {
enroll->computer_container = strdup (values[i] + prefix_len);
return_unexpected_if_fail (enroll->computer_container != NULL);
- _adcli_info ("Found well known computer container at: %s",
- enroll->computer_container);
+ _adcli_info ("Found well known %s container at: %s",
+ s_or_c (enroll), enroll->computer_container);
break;
}
}
@@ -629,8 +638,9 @@ lookup_computer_container (adcli_enroll *enroll,
if (ret == LDAP_SUCCESS) {
enroll->computer_container = _adcli_ldap_parse_dn (ldap, results);
if (enroll->computer_container) {
- _adcli_info ("Well known computer container not "
+ _adcli_info ("Well known %s container not "
"found, but found suitable one at: %s",
+ s_or_c (enroll),
enroll->computer_container);
}
}
@@ -646,7 +656,8 @@ lookup_computer_container (adcli_enroll *enroll,
}
if (!enroll->computer_container) {
- _adcli_err ("Couldn't find location to create computer accounts");
+ _adcli_err ("Couldn't find location to create %s accounts",
+ s_or_c (enroll));
return ADCLI_ERR_DIRECTORY;
}
@@ -674,7 +685,8 @@ calculate_computer_account (adcli_enroll *enroll,
if (asprintf (&enroll->computer_dn, "CN=%s,%s", enroll->computer_name, enroll->computer_container) < 0)
return_unexpected_if_reached ();
- _adcli_info ("Calculated computer account: %s", enroll->computer_dn);
+ _adcli_info ("Calculated %s account: %s",
+ s_or_c (enroll), enroll->computer_dn);
return ADCLI_SUCCESS;
}
@@ -861,7 +873,8 @@ create_computer_account (adcli_enroll *enroll,
enroll->computer_dn);
}
- _adcli_info ("Created computer account: %s", enroll->computer_dn);
+ _adcli_info ("Created %s account: %s", s_or_c (enroll),
+ enroll->computer_dn);
return ADCLI_SUCCESS;
}
@@ -908,17 +921,17 @@ validate_computer_account (adcli_enroll *enroll,
assert (enroll->computer_dn != NULL);
if (already_exists && !allow_overwrite) {
- _adcli_err ("The computer account %s already exists",
- enroll->computer_name);
+ _adcli_err ("The %s account %s already exists",
+ s_or_c (enroll), enroll->computer_name);
return ADCLI_ERR_CONFIG;
}
/* Do we have an explicitly requested ou? */
if (enroll->domain_ou && enroll->domain_ou_explicit && already_exists) {
if (!_adcli_ldap_dn_has_ancestor (enroll->computer_dn, enroll->domain_ou)) {
- _adcli_err ("The computer account %s already exists, "
+ _adcli_err ("The %s account %s already exists, "
"but is not in the desired organizational unit.",
- enroll->computer_name);
+ s_or_c (enroll), enroll->computer_name);
return ADCLI_ERR_CONFIG;
}
}
@@ -943,7 +956,8 @@ delete_computer_account (adcli_enroll *enroll,
"Couldn't delete computer account: %s",
enroll->computer_dn);
} else {
- _adcli_info ("Deleted computer account at: %s", enroll->computer_dn);
+ _adcli_info ("Deleted %s account at: %s", s_or_c (enroll),
+ enroll->computer_dn);
}
return ADCLI_SUCCESS;
@@ -992,20 +1006,21 @@ locate_computer_account (adcli_enroll *enroll,
free (enroll->computer_dn);
enroll->computer_dn = strdup (dn);
return_unexpected_if_fail (enroll->computer_dn != NULL);
- _adcli_info ("Found computer account for %s at: %s",
- enroll->computer_sam, dn);
+ _adcli_info ("Found %s account for %s at: %s",
+ s_or_c (enroll), enroll->computer_sam, dn);
ldap_memfree (dn);
} else {
ldap_msgfree (results);
results = NULL;
- _adcli_info ("Computer account for %s does not exist",
- enroll->computer_sam);
+ _adcli_info ("A %s account for %s does not exist",
+ s_or_c (enroll), enroll->computer_sam);
}
} else {
return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
- "Couldn't lookup computer account: %s",
+ "Couldn't lookup %s account: %s",
+ s_or_c (enroll),
enroll->computer_sam);
}
@@ -1039,7 +1054,9 @@ load_computer_account (adcli_enroll *enroll,
if (ret == LDAP_SUCCESS) {
entry = ldap_first_entry (ldap, results);
if (entry) {
- _adcli_info ("Found computer account for %s at: %s",
+ check_if_service (enroll, ldap, results);
+ _adcli_info ("Found %s account for %s at: %s",
+ s_or_c (enroll),
enroll->computer_sam, enroll->computer_dn);
}
@@ -1146,7 +1163,8 @@ set_password_with_user_creds (adcli_enroll *enroll)
&result_code_string, &result_string);
if (code != 0) {
- _adcli_err ("Couldn't set password for computer account: %s: %s",
+ _adcli_err ("Couldn't set password for %s account: %s: %s",
+ s_or_c (enroll),
enroll->computer_sam, krb5_get_error_message (k5, code));
/* TODO: Parse out these values */
res = ADCLI_ERR_DIRECTORY;
@@ -1160,7 +1178,8 @@ set_password_with_user_creds (adcli_enroll *enroll)
if (result_string.length)
message = _adcli_str_dupn (result_string.data, result_string.length);
#endif
- _adcli_err ("Cannot set computer password: %.*s%s%s",
+ _adcli_err ("Cannot set %s password: %.*s%s%s",
+ s_or_c (enroll),
(int)result_code_string.length, result_code_string.data,
message ? ": " : "", message ? message : "");
res = ADCLI_ERR_CREDENTIALS;
@@ -1170,7 +1189,7 @@ set_password_with_user_creds (adcli_enroll *enroll)
free (message);
#endif
} else {
- _adcli_info ("Set computer password");
+ _adcli_info ("Set %s password", s_or_c (enroll));
if (enroll->kvno > 0) {
enroll->kvno++;
_adcli_info ("kvno incremented to %d", enroll->kvno);
@@ -1203,7 +1222,8 @@ set_password_with_computer_creds (adcli_enroll *enroll)
code = _adcli_kinit_computer_creds (enroll->conn, "kadmin/changepw", NULL, &creds);
if (code != 0) {
- _adcli_err ("Couldn't get change password ticket for computer account: %s: %s",
+ _adcli_err ("Couldn't get change password ticket for %s account: %s: %s",
+ s_or_c (enroll),
enroll->computer_sam, krb5_get_error_message (k5, code));
return ADCLI_ERR_DIRECTORY;
}
@@ -1214,7 +1234,8 @@ set_password_with_computer_creds (adcli_enroll *enroll)
krb5_free_cred_contents (k5, &creds);
if (code != 0) {
- _adcli_err ("Couldn't change password for computer account: %s: %s",
+ _adcli_err ("Couldn't change password for %s account: %s: %s",
+ s_or_c (enroll),
enroll->computer_sam, krb5_get_error_message (k5, code));
/* TODO: Parse out these values */
res = ADCLI_ERR_DIRECTORY;
@@ -1284,7 +1305,8 @@ retrieve_computer_account (adcli_enroll *enroll)
if (ret != LDAP_SUCCESS) {
return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
- "Couldn't retrieve computer account info: %s",
+ "Couldn't retrieve %s account info: %s",
+ s_or_c (enroll),
enroll->computer_dn);
}
@@ -1294,15 +1316,15 @@ retrieve_computer_account (adcli_enroll *enroll)
if (value != NULL) {
kvno = strtoul (value, &end, 10);
if (end == NULL || *end != '\0') {
- _adcli_err ("Invalid kvno '%s' for computer account in directory: %s",
- value, enroll->computer_dn);
+ _adcli_err ("Invalid kvno '%s' for %s account in directory: %s",
+ value, s_or_c (enroll), enroll->computer_dn);
res = ADCLI_ERR_DIRECTORY;
} else {
enroll->kvno = kvno;
- _adcli_info ("Retrieved kvno '%s' for computer account in directory: %s",
- value, enroll->computer_dn);
+ _adcli_info ("Retrieved kvno '%s' for %s account in directory: %s",
+ value, s_or_c (enroll), enroll->computer_dn);
}
free (value);
@@ -1311,8 +1333,8 @@ retrieve_computer_account (adcli_enroll *enroll)
/* Apparently old AD didn't have this attribute, use zero */
enroll->kvno = 0;
- _adcli_info ("No kvno found for computer account in directory: %s",
- enroll->computer_dn);
+ _adcli_info ("No kvno found for %s account in directory: %s",
+ s_or_c (enroll), enroll->computer_dn);
}
}
@@ -1353,12 +1375,14 @@ update_and_calculate_enctypes (adcli_enroll *enroll)
if (ret == LDAP_INSUFFICIENT_ACCESS) {
return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_CREDENTIALS,
- "Insufficient permissions to set encryption types on computer account: %s",
+ "Insufficient permissions to set encryption types on %s account: %s",
+ s_or_c (enroll),
enroll->computer_dn);
} else if (ret != LDAP_SUCCESS) {
return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
- "Couldn't set encryption types on computer account: %s",
+ "Couldn't set encryption types on %s account: %s",
+ s_or_c (enroll),
enroll->computer_dn);
}
@@ -1381,13 +1405,14 @@ update_computer_attribute (adcli_enroll *enroll,
string = _adcli_ldap_mods_to_string (mods);
return_unexpected_if_fail (string != NULL);
- _adcli_info ("Modifying computer account: %s", string);
+ _adcli_info ("Modifying %s account: %s", s_or_c (enroll), string);
ret = ldap_modify_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
if (ret != LDAP_SUCCESS) {
- _adcli_warn ("Couldn't set %s on computer account: %s: %s",
- string, enroll->computer_dn, ldap_err2string (ret));
+ _adcli_warn ("Couldn't set %s on %s account: %s: %s",
+ string, s_or_c (enroll), enroll->computer_dn,
+ ldap_err2string (ret));
res = ADCLI_ERR_DIRECTORY;
}
@@ -1411,8 +1436,8 @@ static char *get_user_account_control (adcli_enroll *enroll)
attr_val = strtoul (uac_str, &end, 10);
if (*end != '\0' || attr_val > UINT32_MAX) {
- _adcli_warn ("Invalid userAccountControl '%s' for computer account in directory: %s, assuming 0",
- uac_str, enroll->computer_dn);
+ _adcli_warn ("Invalid userAccountControl '%s' for %s account in directory: %s, assuming 0",
+ uac_str, s_or_c (enroll), enroll->computer_dn);
} else {
uac = attr_val;
}
@@ -1653,7 +1678,8 @@ load_keytab_entry (krb5_context k5,
_adcli_str_has_suffix (name, "$") && !strchr (name, '/')) {
enroll->computer_name = name;
name[len - 1] = '\0';
- _adcli_info ("Found computer name in keytab: %s", name);
+ _adcli_info ("Found %s name in keytab: %s",
+ s_or_c (enroll), name);
adcli_conn_set_computer_name (enroll->conn,
enroll->computer_name);
name = NULL;
@@ -2348,7 +2374,8 @@ adcli_enroll_read_computer_account (adcli_enroll *enroll,
if (res != ADCLI_SUCCESS)
return res;
if (!enroll->computer_dn) {
- _adcli_err ("No computer account for %s exists", enroll->computer_sam);
+ _adcli_err ("No %s account for %s exists",
+ s_or_c (enroll), enroll->computer_sam);
return ADCLI_ERR_CONFIG;
}
}
@@ -2460,7 +2487,8 @@ adcli_enroll_delete (adcli_enroll *enroll,
if (res != ADCLI_SUCCESS)
return res;
if (!enroll->computer_dn) {
- _adcli_err ("No computer account for %s exists",
+ _adcli_err ("No %s account for %s exists",
+ s_or_c (enroll),
enroll->computer_sam);
return ADCLI_ERR_CONFIG;
}
@@ -2503,7 +2531,8 @@ adcli_enroll_password (adcli_enroll *enroll,
if (res != ADCLI_SUCCESS)
return res;
if (!enroll->computer_dn) {
- _adcli_err ("No computer account for %s exists",
+ _adcli_err ("No %s account for %s exists",
+ s_or_c (enroll),
enroll->computer_sam);
return ADCLI_ERR_CONFIG;
}
--
2.28.0

View File

@ -0,0 +1,42 @@
From 10a4dbb5978b6f05cf75f820d97da908e735ace8 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 22 Mar 2019 10:37:11 +0100
Subject: [PATCH 3/4] library: _adcli_krb5_build_principal allow principals as
names
Make _adcli_krb5_build_principal a bit more robust by checking if the
given name already contains a realm suffix.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
---
library/adkrb5.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/library/adkrb5.c b/library/adkrb5.c
index 7f77373..da835d7 100644
--- a/library/adkrb5.c
+++ b/library/adkrb5.c
@@ -41,12 +41,16 @@ _adcli_krb5_build_principal (krb5_context k5,
krb5_principal *principal)
{
krb5_error_code code;
- char *name;
+ char *name = NULL;
- if (asprintf (&name, "%s@%s", user, realm) < 0)
- return_val_if_reached (ENOMEM);
+ /* Use user if user contains a @-character and add @realm otherwise */
+ if (strchr (user, '@') == NULL) {
+ if (asprintf (&name, "%s@%s", user, realm) < 0) {
+ return_val_if_reached (ENOMEM);
+ }
+ }
- code = krb5_parse_name (k5, name, principal);
+ code = krb5_parse_name (k5, name != NULL ? name : user, principal);
return_val_if_fail (code == 0, code);
free (name);
--
2.20.1

View File

@ -0,0 +1,53 @@
From 4794812cc98c8783921f534d20dae8b44f3826d2 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 15 Apr 2019 17:57:37 +0200
Subject: [PATCH 3/7] tools: remove errx from info commands
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/info.c | 21 ++++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/tools/info.c b/tools/info.c
index e7e20ad..c63e0ff 100644
--- a/tools/info.c
+++ b/tools/info.c
@@ -162,21 +162,28 @@ adcli_tool_info (adcli_conn *unused,
if (argc == 1)
domain = argv[0];
- else if (argc != 0)
- errx (2, "specify one user name to create");
+ else if (argc != 0) {
+ warnx ("specify one user name to create");
+ return 2;
+ }
if (server) {
adcli_disco_host (server, &disco);
- if (disco == NULL)
- errx (1, "couldn't discover domain controller: %s", server);
+ if (disco == NULL) {
+ warnx ("couldn't discover domain controller: %s", server);
+ return 1;
+ }
for_host = 1;
} else if (domain) {
adcli_disco_domain (domain, &disco);
- if (disco == NULL)
- errx (1, "couldn't discover domain: %s", domain);
+ if (disco == NULL) {
+ warnx ("couldn't discover domain: %s", domain);
+ return 1;
+ }
for_host = 0;
} else {
- errx (2, "specify a domain to discover");
+ warnx ("specify a domain to discover");
+ return 2;
}
print_info (disco, for_host);
--
2.20.1

View File

@ -0,0 +1,27 @@
From 8f726817b9ff643a382fa12ea9ff489cd5ab9068 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 13 Aug 2018 18:24:58 +0200
Subject: [PATCH 4/4] Do not depend on default_realm in krb5.conf
---
library/adenroll.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index bb50365..02bd9e3 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1661,7 +1661,9 @@ remove_principal_from_keytab (adcli_enroll *enroll,
krb5_principal principal;
match_principal_kvno closure;
- code = krb5_parse_name (k5, principal_name, &principal);
+ code = _adcli_krb5_build_principal (k5, principal_name,
+ adcli_conn_get_domain_realm (enroll->conn),
+ &principal);
if (code != 0) {
_adcli_err ("Couldn't parse principal: %s: %s",
principal_name, krb5_get_error_message (k5, code));
--
2.17.1

View File

@ -0,0 +1,103 @@
From cc3ef52884a48863a81acbfc741735fe09cd85f7 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 13 Jun 2019 18:27:49 +0200
Subject: [PATCH 4/4] adenroll: use only enctypes permitted by Kerberos config
Realted to https://gitlab.freedesktop.org/realmd/adcli/issues/3
---
doc/adcli.xml | 10 ++++++++++
library/adenroll.c | 22 +++++++++++++++++++---
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 9605b4a..094f577 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -342,6 +342,11 @@ Password for Administrator:
</varlistentry>
</variablelist>
+ <para>If supported on the AD side the
+ <option>msDS-supportedEncryptionTypes</option> attribute will be set as
+ well. Either the current value or the default list of AD's supported
+ encryption types filtered by the permitted encryption types of the
+ client's Kerberos configuration are written.</para>
</refsect1>
<refsect1 id='updating'>
@@ -475,6 +480,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123
</varlistentry>
</variablelist>
+ <para>If supported on the AD side the
+ <option>msDS-supportedEncryptionTypes</option> attribute will be set as
+ well. Either the current value or the default list of AD's supported
+ encryption types filtered by the permitted encryption types of the
+ client's Kerberos configuration are written.</para>
</refsect1>
<refsect1 id='testjoin'>
diff --git a/library/adenroll.c b/library/adenroll.c
index 95c07cd..53cd812 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -639,6 +639,7 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
{
char *value = NULL;
krb5_enctype *read_enctypes;
+ krb5_enctype *new_enctypes;
char *new_value = NULL;
int is_2008_or_later;
LDAP *ldap;
@@ -685,7 +686,14 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
}
- new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll));
+ new_enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
+ if (new_enctypes == NULL) {
+ _adcli_warn ("No permitted encryption type found.");
+ return ADCLI_ERR_UNEXPECTED;
+ }
+
+ new_value = _adcli_krb5_format_enctypes (new_enctypes);
+ krb5_free_enctypes (adcli_conn_get_krb5_context (enroll->conn), new_enctypes);
if (new_value == NULL) {
free (value);
_adcli_warn ("The encryption types desired are not available in active directory");
@@ -1758,7 +1766,11 @@ add_principal_to_keytab (adcli_enroll *enroll,
enroll->keytab_name);
}
- enctypes = adcli_enroll_get_keytab_enctypes (enroll);
+ enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
+ if (enctypes == NULL) {
+ _adcli_warn ("No permitted encryption type found.");
+ return ADCLI_ERR_UNEXPECTED;
+ }
if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
@@ -1774,7 +1786,10 @@ add_principal_to_keytab (adcli_enroll *enroll,
*/
salts = build_principal_salts (enroll, k5, principal);
- return_unexpected_if_fail (salts != NULL);
+ if (salts == NULL) {
+ krb5_free_enctypes (k5, enctypes);
+ return ADCLI_ERR_UNEXPECTED;
+ }
if (*which_salt < 0) {
code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
@@ -1794,6 +1809,7 @@ add_principal_to_keytab (adcli_enroll *enroll,
free_principal_salts (k5, salts);
}
+ krb5_free_enctypes (k5, enctypes);
if (code != 0) {
_adcli_err ("Couldn't add keytab entries: %s: %s",
--
2.21.0

View File

@ -0,0 +1,37 @@
From c3ec5121c1e79344ce615612ab3b576bc4745acb Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 1 Nov 2017 12:01:18 +0100
Subject: [PATCH 04/23] doc: explain that all credential cache types are
supported
---
doc/adcli.xml | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index e18ba5d..c54cc1b 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -118,11 +118,15 @@
is automatically discovered.</para></listitem>
</varlistentry>
<varlistentry>
- <term><option>-C, --login-ccache=<parameter>/path/to/file</parameter></option></term>
+ <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 file is specified or
- <option>-C</option> is used, then the default kerberos credential cache will
- be used.</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></listitem>
</varlistentry>
<varlistentry>
<term><option>-U, --login-user=<parameter>User</parameter></option></term>
--
2.14.4

View File

@ -0,0 +1,77 @@
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 4/7] enroll: more filters for random characters
Make handling of random strings more flexible.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
library/adenroll.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 9cdc79b..44383cc 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -259,6 +259,29 @@ ensure_computer_sam (adcli_result res,
return ADCLI_SUCCESS;
}
+typedef int (rand_filter) (char *password, int length);
+
+static int
+filter_sam_chars (char *password,
+ int length)
+{
+ int i, j;
+
+ /*
+ * There are a couple of restrictions for characters in the
+ * sAMAccountName attribute value, for our purpose (random suffix)
+ * letters and numbers are sufficient.
+ */
+ for (i = 0, j = 0; i < length; i++) {
+ if (password[i] >= 48 && password[i] <= 122 &&
+ isalnum (password[i]))
+ password[j++] = password[i];
+ }
+
+ /* return the number of valid characters remaining */
+ return j;
+}
+
static int
filter_password_chars (char *password,
int length)
@@ -283,7 +306,8 @@ filter_password_chars (char *password,
static char *
generate_host_password (adcli_enroll *enroll,
- size_t length)
+ size_t length,
+ rand_filter *filter)
{
char *password;
krb5_context k5;
@@ -305,7 +329,7 @@ generate_host_password (adcli_enroll *enroll,
code = krb5_c_random_make_octets (k5, &buffer);
return_val_if_fail (code == 0, NULL);
- at += filter_password_chars (buffer.data, buffer.length);
+ at += filter (buffer.data, buffer.length);
assert (at <= length);
}
@@ -333,7 +357,7 @@ ensure_computer_password (adcli_result res,
_adcli_info ("Using default reset computer password");
} else {
- enroll->computer_password = generate_host_password (enroll, length);
+ enroll->computer_password = generate_host_password (enroll, length, filter_password_chars);
return_unexpected_if_fail (enroll->computer_password != NULL);
_adcli_info ("Generated %d character computer password", length);
}
--
2.28.0

View File

@ -0,0 +1,82 @@
From 972f1a2f35829ed89f5353bd204683aa9ad6a2d2 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 22 Mar 2019 10:37:57 +0100
Subject: [PATCH 4/4] library: make sure server side SPNs are preserved
adcli should not delete service principal names (SPNs) unexpectedly. If
a SPN was added on the server while presetting a host or updating an
existing entry and upcoming adcli join or update should preserver this
change.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
---
library/adenroll.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/library/adenroll.c b/library/adenroll.c
index 48cb4cf..1cce86a 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1961,6 +1961,47 @@ adcli_enroll_prepare (adcli_enroll *enroll,
return res;
}
+static adcli_result
+add_server_side_service_principals (adcli_enroll *enroll)
+{
+ char **spn_list;
+ LDAP *ldap;
+ size_t c;
+ int length = 0;
+ adcli_result res;
+
+ ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ assert (ldap != NULL);
+
+ spn_list = _adcli_ldap_parse_values (ldap, enroll->computer_attributes,
+ "servicePrincipalName");
+ if (spn_list == NULL) {
+ return ADCLI_SUCCESS;
+ }
+
+ if (enroll->service_principals != NULL) {
+ length = seq_count (enroll->service_principals);
+ }
+
+ for (c = 0; spn_list[c] != NULL; c++) {
+ _adcli_info ("Checking %s", spn_list[c]);
+ if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) {
+ enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
+ spn_list[c], &length, false);
+ assert (enroll->service_principals != NULL);
+ _adcli_info (" Added %s", spn_list[c]);
+ }
+ }
+ _adcli_strv_free (spn_list);
+
+ res = ensure_keytab_principals (ADCLI_SUCCESS, enroll);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
+
+ return ADCLI_SUCCESS;
+}
+
static adcli_result
enroll_join_or_update_tasks (adcli_enroll *enroll,
adcli_enroll_flags flags)
@@ -2019,6 +2060,11 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
update_and_calculate_enctypes (enroll);
update_computer_account (enroll);
+ res = add_server_side_service_principals (enroll);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
+
/* service_names is only set from input on the command line, so no
* additional check for explicit is needed here */
if (enroll->service_names != NULL) {
--
2.20.1

View File

@ -0,0 +1,42 @@
From 251d7d0c71226afb8e51f7bc5794a7a3164f5a20 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 15 Apr 2019 17:59:17 +0200
Subject: [PATCH 4/7] tools: remove errx from adcli_read_password_func
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/tools.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tools/tools.c b/tools/tools.c
index c4e2851..bdf6d38 100644
--- a/tools/tools.c
+++ b/tools/tools.c
@@ -247,7 +247,9 @@ adcli_read_password_func (adcli_login_type login_type,
if (res < 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
- err (EFAIL, "couldn't read password from stdin");
+ warn ("couldn't read password from stdin");
+ free (buffer);
+ return NULL;
} else if (res == 0) {
buffer[offset] = '\0';
@@ -261,8 +263,11 @@ adcli_read_password_func (adcli_login_type login_type,
return buffer;
} else {
- if (memchr (buffer + offset, 0, res))
- errx (EUSAGE, "unsupported null character present in password");
+ if (memchr (buffer + offset, 0, res)) {
+ warnx ("unsupported null character present in password");
+ free (buffer);
+ return NULL;
+ }
offset += res;
}
}
--
2.20.1

View File

@ -0,0 +1,91 @@
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 5/7] enroll: make adcli_enroll_add_keytab_for_service_account
public
Determine keytab name more early to catch errors more early.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
library/adenroll.c | 13 +++++++------
library/adenroll.h | 2 ++
tools/computer.c | 6 ++++++
3 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 44383cc..05bb085 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -2276,9 +2276,10 @@ adcli_enroll_add_description_for_service_account (adcli_enroll *enroll)
return ADCLI_SUCCESS;
}
-static adcli_result
+adcli_result
adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll)
{
+ adcli_result res;
krb5_context k5;
krb5_error_code code;
char def_keytab_name[MAX_KEYTAB_NAME_LEN];
@@ -2286,11 +2287,14 @@ adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll)
int ret;
if (adcli_enroll_get_keytab_name (enroll) == NULL) {
- k5 = adcli_conn_get_krb5_context (enroll->conn);
- return_unexpected_if_fail (k5 != NULL);
+ res = _adcli_krb5_init_context (&k5);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
code = krb5_kt_default_name (k5, def_keytab_name,
sizeof (def_keytab_name));
+ krb5_free_context (k5);
return_unexpected_if_fail (code == 0);
lc_dom_name = strdup (adcli_conn_get_domain_name (enroll->conn));
@@ -2326,9 +2330,6 @@ adcli_enroll_join (adcli_enroll *enroll,
if (enroll->is_service) {
res = adcli_enroll_add_description_for_service_account (enroll);
- if (res == ADCLI_SUCCESS) {
- res = adcli_enroll_add_keytab_for_service_account (enroll);
- }
} else {
res = ensure_default_service_names (enroll);
}
diff --git a/library/adenroll.h b/library/adenroll.h
index 7765ed4..11a30c8 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -146,6 +146,8 @@ const char * adcli_enroll_get_keytab_name (adcli_enroll *enroll);
void adcli_enroll_set_keytab_name (adcli_enroll *enroll,
const char *value);
+adcli_result adcli_enroll_add_keytab_for_service_account (adcli_enroll *enroll);
+
krb5_enctype * adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll);
void adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll,
diff --git a/tools/computer.c b/tools/computer.c
index 63fd374..98a0472 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -1166,6 +1166,12 @@ adcli_tool_computer_managed_service_account (adcli_conn *conn,
adcli_enroll_set_is_service (enroll, true);
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ res = adcli_enroll_add_keytab_for_service_account (enroll);
+ if (res != ADCLI_SUCCESS) {
+ warnx ("Failed to set domain specific keytab name");
+ adcli_enroll_unref (enroll);
+ return 2;
+ }
res = adcli_enroll_load (enroll);
if (res != ADCLI_SUCCESS) {
--
2.28.0

View File

@ -0,0 +1,38 @@
From d2cdc54b0e51436c30ffaf19b0530aa446440367 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 1 Nov 2017 16:29:19 +0100
Subject: [PATCH 05/23] library: add adcli_conn_is_writeable()
---
library/adconn.c | 6 ++++++
library/adconn.h | 2 ++
2 files changed, 8 insertions(+)
diff --git a/library/adconn.c b/library/adconn.c
index a294dfd..67bdfd9 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -1528,3 +1528,9 @@ adcli_conn_server_has_capability (adcli_conn *conn,
return 0;
}
+
+bool adcli_conn_is_writeable (adcli_conn *conn)
+{
+ disco_dance_if_necessary (conn);
+ return ( (conn->domain_disco->flags & ADCLI_DISCO_WRITABLE) != 0);
+}
diff --git a/library/adconn.h b/library/adconn.h
index a0cb1f8..ed1cc58 100644
--- a/library/adconn.h
+++ b/library/adconn.h
@@ -144,4 +144,6 @@ 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_is_writeable (adcli_conn *conn);
+
#endif /* ADCONN_H_ */
--
2.14.4

View File

@ -0,0 +1,63 @@
From b8f5d995d30c17eb8bec3ac5e0777ea94f5b76c3 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 15 Apr 2019 18:00:52 +0200
Subject: [PATCH 5/7] tools: remove errx from setup_krb5_conf_directory
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/tools.c | 38 ++++++++++++++++++++++++--------------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/tools/tools.c b/tools/tools.c
index bdf6d38..fc9fa9a 100644
--- a/tools/tools.c
+++ b/tools/tools.c
@@ -327,21 +327,31 @@ setup_krb5_conf_directory (adcli_conn *conn)
}
if (asprintf (&directory, "%s%sadcli-krb5-XXXXXX", parent,
- (parent[0] && parent[strlen(parent) - 1] == '/') ? "" : "/") < 0)
- errx (1, "unexpected: out of memory");
-
- if (mkdtemp (directory) == NULL) {
- errn = errno;
+ (parent[0] && parent[strlen(parent) - 1] == '/') ? "" : "/") < 0) {
+ warnx ("unexpected: out of memory");
+ directory = NULL; /* content is undefined */
failed = 1;
- warnx ("couldn't create temporary directory in: %s: %s",
- parent, strerror (errn));
- } else {
- if (asprintf (&filename, "%s/krb5.conf", directory) < 0 ||
- asprintf (&snippets, "%s/krb5.d", directory) < 0 ||
- asprintf (&contents, "includedir %s\n%s%s\n", snippets,
- krb5_conf ? "include " : "",
- krb5_conf ? krb5_conf : "") < 0)
- errx (1, "unexpected: out of memory");
+ }
+
+ if (!failed) {
+ if (mkdtemp (directory) == NULL) {
+ errn = errno;
+ failed = 1;
+ warnx ("couldn't create temporary directory in: %s: %s",
+ parent, strerror (errn));
+ } else {
+ if (asprintf (&filename, "%s/krb5.conf", directory) < 0 ||
+ asprintf (&snippets, "%s/krb5.d", directory) < 0 ||
+ asprintf (&contents, "includedir %s\n%s%s\n", snippets,
+ krb5_conf ? "include " : "",
+ krb5_conf ? krb5_conf : "") < 0) {
+ warnx ("unexpected: out of memory");
+ filename = NULL; /* content is undefined */
+ snippets = NULL; /* content is undefined */
+ contents = NULL; /* content is undefined */
+ failed = 1;
+ }
+ }
}
if (!failed) {
--
2.20.1

View File

@ -0,0 +1,67 @@
From 6b60f4c08d811e4bc3a68d1a4770c2ce5619c890 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 1 Nov 2017 17:14:05 +0100
Subject: [PATCH 06/23] Handle kvno increment for RODCs
Since the actual password change does not happen on the read-only domain
controller (RODC) the kvno change has to be replicated back which might
take some time. So we check the kvno before and after the change if we
are connected to a RODC and increment the kvno if needed.
---
library/adenroll.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/library/adenroll.c b/library/adenroll.c
index 05885d0..bb970d1 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1633,8 +1633,30 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
adcli_enroll_flags flags)
{
adcli_result res;
+ krb5_kvno old_kvno = -1;
if (!(flags & ADCLI_ENROLL_PASSWORD_VALID)) {
+
+ /* Handle kvno changes for read-only domain controllers
+ * (RODC). Since the actual password change does not happen on
+ * the RODC the kvno change has to be replicated back which
+ * might take some time. So we check the kvno before and after
+ * the change if we are connected to a RODC and increment the
+ * kvno if needed. */
+ if (!adcli_conn_is_writeable (enroll->conn)) {
+ if (enroll->computer_attributes == NULL) {
+ res = retrieve_computer_account (enroll);
+ if (res != ADCLI_SUCCESS)
+ return res;
+ }
+ old_kvno = adcli_enroll_get_kvno (enroll);
+ _adcli_info ("Found old kvno '%d'", old_kvno);
+
+ ldap_msgfree (enroll->computer_attributes);
+ enroll->computer_attributes = NULL;
+ adcli_enroll_set_kvno (enroll, 0);
+ }
+
res = set_computer_password (enroll);
if (res != ADCLI_SUCCESS)
return res;
@@ -1651,6 +1673,15 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
return res;
}
+ /* Handle kvno changes for read-only domain controllers (RODC) */
+ if (!adcli_conn_is_writeable (enroll->conn) && old_kvno != -1 &&
+ adcli_enroll_get_kvno (enroll) != 0 &&
+ adcli_enroll_get_kvno (enroll) == old_kvno) {
+ enroll->kvno++;
+ _adcli_info ("No kvno change detected on read-only DC, kvno "
+ "will be incremented by 1 to '%d'", enroll->kvno);
+ }
+
/* We ignore failures of setting these fields */
update_and_calculate_enctypes (enroll);
update_computer_account (enroll);
--
2.14.4

View File

@ -0,0 +1,129 @@
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 6/7] enroll: allow fqdn for locate_computer_account
Make it possible to find existing manages service account by the
fully-qualified name.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
library/adenroll.c | 45 +++++++++++++++++++++++++++++++--------------
1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 05bb085..98cd5fa 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -990,10 +990,11 @@ delete_computer_account (adcli_enroll *enroll,
static adcli_result
locate_computer_account (adcli_enroll *enroll,
LDAP *ldap,
+ bool use_fqdn,
LDAPMessage **rresults,
LDAPMessage **rentry)
{
- char *attrs[] = { "objectClass", NULL };
+ char *attrs[] = { "objectClass", "CN", NULL };
LDAPMessage *results = NULL;
LDAPMessage *entry = NULL;
const char *base;
@@ -1003,12 +1004,22 @@ locate_computer_account (adcli_enroll *enroll,
int ret = 0;
/* If we don't yet know our computer dn, then try and find it */
- value = _adcli_ldap_escape_filter (enroll->computer_sam);
- return_unexpected_if_fail (value != NULL);
- if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))",
- enroll->is_service ? "msDS-ManagedServiceAccount" : "computer",
- value) < 0)
- return_unexpected_if_reached ();
+ if (use_fqdn) {
+ return_unexpected_if_fail (enroll->host_fqdn != NULL);
+ value = _adcli_ldap_escape_filter (enroll->host_fqdn);
+ return_unexpected_if_fail (value != NULL);
+ if (asprintf (&filter, "(&(objectClass=%s)(dNSHostName=%s))",
+ enroll->is_service ? "msDS-ManagedServiceAccount" : "computer",
+ value) < 0)
+ return_unexpected_if_reached ();
+ } else {
+ value = _adcli_ldap_escape_filter (enroll->computer_sam);
+ return_unexpected_if_fail (value != NULL);
+ if (asprintf (&filter, "(&(objectClass=%s)(sAMAccountName=%s))",
+ enroll->is_service ? "msDS-ManagedServiceAccount" : "computer",
+ value) < 0)
+ return_unexpected_if_reached ();
+ }
free (value);
base = adcli_conn_get_default_naming_context (enroll->conn);
@@ -1031,21 +1042,26 @@ locate_computer_account (adcli_enroll *enroll,
enroll->computer_dn = strdup (dn);
return_unexpected_if_fail (enroll->computer_dn != NULL);
_adcli_info ("Found %s account for %s at: %s",
- s_or_c (enroll), enroll->computer_sam, dn);
+ s_or_c (enroll),
+ use_fqdn ? enroll->host_fqdn
+ : enroll->computer_sam, dn);
ldap_memfree (dn);
} else {
ldap_msgfree (results);
results = NULL;
_adcli_info ("A %s account for %s does not exist",
- s_or_c (enroll), enroll->computer_sam);
+ s_or_c (enroll),
+ use_fqdn ? enroll->host_fqdn
+ : enroll->computer_sam);
}
} else {
return _adcli_ldap_handle_failure (ldap, ADCLI_ERR_DIRECTORY,
"Couldn't lookup %s account: %s",
s_or_c (enroll),
- enroll->computer_sam);
+ use_fqdn ? enroll->host_fqdn
+ :enroll->computer_sam);
}
if (rresults)
@@ -1120,7 +1136,8 @@ locate_or_create_computer_account (adcli_enroll *enroll,
/* Try to find the computer account */
if (!enroll->computer_dn) {
- res = locate_computer_account (enroll, ldap, &results, &entry);
+ res = locate_computer_account (enroll, ldap, false,
+ &results, &entry);
if (res != ADCLI_SUCCESS)
return res;
searched = 1;
@@ -2395,7 +2412,7 @@ adcli_enroll_read_computer_account (adcli_enroll *enroll,
/* Find the computer dn */
if (!enroll->computer_dn) {
- res = locate_computer_account (enroll, ldap, NULL, NULL);
+ res = locate_computer_account (enroll, ldap, false, NULL, NULL);
if (res != ADCLI_SUCCESS)
return res;
if (!enroll->computer_dn) {
@@ -2508,7 +2525,7 @@ adcli_enroll_delete (adcli_enroll *enroll,
/* Find the computer dn */
if (!enroll->computer_dn) {
- res = locate_computer_account (enroll, ldap, NULL, NULL);
+ res = locate_computer_account (enroll, ldap, false, NULL, NULL);
if (res != ADCLI_SUCCESS)
return res;
if (!enroll->computer_dn) {
@@ -2552,7 +2569,7 @@ adcli_enroll_password (adcli_enroll *enroll,
/* Find the computer dn */
if (!enroll->computer_dn) {
- res = locate_computer_account (enroll, ldap, NULL, NULL);
+ res = locate_computer_account (enroll, ldap, false, NULL, NULL);
if (res != ADCLI_SUCCESS)
return res;
if (!enroll->computer_dn) {
--
2.28.0

View File

@ -0,0 +1,175 @@
From d9912e19e48ec482351b9c384140ad71922ec5c0 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 8 Apr 2019 17:22:00 +0200
Subject: [PATCH 6/7] tools: entry - remove errx from parse_option
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/entry.c | 70 ++++++++++++++++++++++++++++++++++-----------------
1 file changed, 47 insertions(+), 23 deletions(-)
diff --git a/tools/entry.c b/tools/entry.c
index 97ec6e7..f361845 100644
--- a/tools/entry.c
+++ b/tools/entry.c
@@ -81,7 +81,7 @@ static adcli_tool_desc common_usages[] = {
{ 0 },
};
-static void
+static int
parse_option (Option opt,
const char *optarg,
adcli_conn *conn)
@@ -93,54 +93,58 @@ parse_option (Option opt,
switch (opt) {
case opt_login_ccache:
adcli_conn_set_login_ccache_name (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_login_user:
adcli_conn_set_login_user (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain:
adcli_conn_set_domain_name (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain_realm:
adcli_conn_set_domain_realm (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain_controller:
adcli_conn_set_domain_controller (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_no_password:
if (stdin_password || prompt_password) {
- errx (EUSAGE, "cannot use --no-password argument with %s",
- stdin_password ? "--stdin-password" : "--prompt-password");
+ warnx ("cannot use --no-password argument with %s",
+ stdin_password ? "--stdin-password" : "--prompt-password");
+ return EUSAGE;
} else {
adcli_conn_set_password_func (conn, NULL, NULL, NULL);
no_password = 1;
}
- return;
+ return ADCLI_SUCCESS;
case opt_prompt_password:
if (stdin_password || no_password) {
- errx (EUSAGE, "cannot use --prompt-password argument with %s",
- stdin_password ? "--stdin-password" : "--no-password");
+ warnx ("cannot use --prompt-password argument with %s",
+ stdin_password ? "--stdin-password" : "--no-password");
+ return EUSAGE;
} else {
adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL);
prompt_password = 1;
}
- return;
+ return ADCLI_SUCCESS;
case opt_stdin_password:
if (prompt_password || no_password) {
- errx (EUSAGE, "cannot use --stdin-password argument with %s",
- prompt_password ? "--prompt-password" : "--no-password");
+ warnx ("cannot use --stdin-password argument with %s",
+ prompt_password ? "--prompt-password" : "--no-password");
+ return EUSAGE;
} else {
adcli_conn_set_password_func (conn, adcli_read_password_func, NULL, NULL);
stdin_password = 1;
}
- return;
+ return ADCLI_SUCCESS;
case opt_verbose:
- return;
+ return ADCLI_SUCCESS;
default:
assert (0 && "not reached");
break;
}
- errx (EUSAGE, "failure to parse option '%c'", opt);
+ warnx ("failure to parse option '%c'", opt);
+ return EUSAGE;
}
int
@@ -224,7 +228,11 @@ adcli_tool_user_create (adcli_conn *conn,
adcli_attrs_free (attrs);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn);
+ res = parse_option ((Option)opt, optarg, conn);
+ if (res != ADCLI_SUCCESS) {
+ adcli_attrs_free (attrs);
+ return res;
+ }
break;
}
}
@@ -322,7 +330,10 @@ adcli_tool_user_delete (adcli_conn *conn,
adcli_tool_usage (options, common_usages);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn);
+ res = parse_option ((Option)opt, optarg, conn);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
break;
}
}
@@ -417,7 +428,11 @@ adcli_tool_group_create (adcli_conn *conn,
adcli_attrs_free (attrs);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn);
+ res = parse_option ((Option)opt, optarg, conn);
+ if (res != ADCLI_SUCCESS) {
+ adcli_attrs_free (attrs);
+ return res;
+ }
break;
}
}
@@ -505,7 +520,10 @@ adcli_tool_group_delete (adcli_conn *conn,
adcli_tool_usage (options, common_usages);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn);
+ res = parse_option ((Option)opt, optarg, conn);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
break;
}
}
@@ -628,7 +646,10 @@ adcli_tool_member_add (adcli_conn *conn,
adcli_tool_usage (options, common_usages);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn);
+ res = parse_option ((Option)opt, optarg, conn);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
break;
}
}
@@ -725,7 +746,10 @@ adcli_tool_member_remove (adcli_conn *conn,
adcli_tool_usage (options, common_usages);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn);
+ res = parse_option ((Option)opt, optarg, conn);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
break;
}
}
--
2.20.1

View File

@ -0,0 +1,28 @@
From 3d312a6c89a88be444fb5ed768fbaa6155bf1cc9 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 14:39:46 +0100
Subject: [PATCH 07/23] Fix memory leak in test_check_nt_time_string_lifetime
The test added with 650e5d33ef31437a049fb454ad3dc5457c56abe7 introduced
a small memory leak.
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
library/adutil.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/library/adutil.c b/library/adutil.c
index 21ccd27..cd40f45 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -501,6 +501,7 @@ test_check_nt_time_string_lifetime (void)
(time (NULL) + 10 + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 *10)
!= -1);
assert (!_adcli_check_nt_time_string_lifetime (time_str, 0));
+ free (time_str);
/* This test will fail some time after 2200AD as a reminder to reflect
* why adcli is still needed. */
--
2.14.4

View File

@ -0,0 +1,122 @@
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 7/7] service-account: add random suffix to account name
Add a random component to the default managed service account name to
avoid name collisions.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1854112
---
library/adenroll.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/library/adenroll.c b/library/adenroll.c
index 98cd5fa..f693e58 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1121,6 +1121,59 @@ load_computer_account (adcli_enroll *enroll,
return ADCLI_SUCCESS;
}
+static adcli_result
+refresh_service_account_name_sam_and_princ (adcli_enroll *enroll,
+ const char *name)
+{
+ adcli_result res;
+
+ adcli_enroll_set_computer_name (enroll, name);
+ res = ensure_computer_sam (ADCLI_SUCCESS, enroll);
+ res = ensure_keytab_principals (res, enroll);
+
+ return res;
+}
+
+static adcli_result
+calculate_random_service_account_name (adcli_enroll *enroll)
+{
+ char *suffix;
+ char *new_name;
+ int ret;
+ adcli_result res;
+
+ suffix = generate_host_password (enroll, 3, filter_sam_chars);
+ return_unexpected_if_fail (suffix != NULL);
+
+ ret = asprintf (&new_name, "%s!%s", enroll->computer_name, suffix);
+ free (suffix);
+ return_unexpected_if_fail (ret > 0);
+
+ res = refresh_service_account_name_sam_and_princ (enroll, new_name);
+ free (new_name);
+
+ return res;
+}
+
+static adcli_result
+get_service_account_name_from_ldap (adcli_enroll *enroll, LDAPMessage *results)
+{
+ LDAP *ldap;
+ char *cn;
+ adcli_result res;
+
+ ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ assert (ldap != NULL);
+
+ cn = _adcli_ldap_parse_value (ldap, results, "CN");
+ return_unexpected_if_fail (cn != NULL);
+
+ res = refresh_service_account_name_sam_and_princ (enroll, cn);
+ free (cn);
+
+ return res;
+}
+
static adcli_result
locate_or_create_computer_account (adcli_enroll *enroll,
int allow_overwrite)
@@ -1143,8 +1196,32 @@ locate_or_create_computer_account (adcli_enroll *enroll,
searched = 1;
}
+ /* Try with fqdn for service accounts */
+ if (!enroll->computer_dn && enroll->is_service
+ && enroll->host_fqdn != NULL) {
+ res = locate_computer_account (enroll, ldap, true,
+ &results, &entry);
+ if (res != ADCLI_SUCCESS)
+ return res;
+ searched = 1;
+
+ if (results != NULL) {
+ res = get_service_account_name_from_ldap (enroll,
+ results);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
+ }
+ }
+
/* Next try and come up with where we think it should be */
if (enroll->computer_dn == NULL) {
+ if (enroll->is_service && !enroll->computer_name_explicit) {
+ res = calculate_random_service_account_name (enroll);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
+ }
res = calculate_computer_account (enroll, ldap);
if (res != ADCLI_SUCCESS)
return res;
@@ -2113,6 +2190,8 @@ adcli_enroll_prepare (adcli_enroll *enroll,
if (enroll->is_service) {
/* Ensure basic params for service accounts */
+ res = ensure_host_fqdn (res, enroll);
+ res = ensure_computer_name (res, enroll);
res = ensure_computer_sam (res, enroll);
res = ensure_computer_password (res, enroll);
res = ensure_host_keytab (res, enroll);
--
2.28.0

View File

@ -0,0 +1,294 @@
From f127ddef23a532cd9763190527bf79b4e47fa2ab Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 8 Apr 2019 17:33:17 +0200
Subject: [PATCH 7/7] tools: computer - remove errx from parse_option
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
---
tools/computer.c | 128 +++++++++++++++++++++++++++++------------------
1 file changed, 80 insertions(+), 48 deletions(-)
diff --git a/tools/computer.c b/tools/computer.c
index 9cbbb28..ac8a203 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -159,7 +159,7 @@ static adcli_tool_desc common_usages[] = {
{ 0 },
};
-static void
+static int
parse_option (Option opt,
const char *optarg,
adcli_conn *conn,
@@ -175,132 +175,139 @@ parse_option (Option opt,
switch (opt) {
case opt_login_ccache:
adcli_conn_set_login_ccache_name (conn, optarg ? optarg : "");
- return;
+ return ADCLI_SUCCESS;
case opt_login_user:
if (adcli_conn_get_allowed_login_types (conn) & ADCLI_LOGIN_USER_ACCOUNT) {
adcli_conn_set_login_user (conn, optarg);
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
} else {
- errx (EUSAGE, "cannot set --user if --login-type not set to 'user'");
+ warnx ("cannot set --user if --login-type not set to 'user'");
+ return EUSAGE;
}
- return;
+ return ADCLI_SUCCESS;
case opt_login_type:
if (optarg && strcmp (optarg, "computer") == 0) {
- if (adcli_conn_get_login_user (conn) != NULL)
- errx (EUSAGE, "cannot set --login-type to 'computer' if --user is set");
- else
+ if (adcli_conn_get_login_user (conn) != NULL) {
+ warnx ("cannot set --login-type to 'computer' if --user is set");
+ return EUSAGE;
+ } else
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT);
} else if (optarg && strcmp (optarg, "user") == 0) {
adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
} else {
- errx (EUSAGE, "unknown login type '%s'", optarg);
+ warnx ("unknown login type '%s'", optarg);
+ return EUSAGE;
}
- return;
+ return ADCLI_SUCCESS;
case opt_host_fqdn:
adcli_conn_set_host_fqdn (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_host_keytab:
adcli_enroll_set_keytab_name (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_computer_name:
adcli_conn_set_computer_name (conn, optarg);
adcli_enroll_set_computer_name (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain:
adcli_conn_set_domain_name (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain_realm:
adcli_conn_set_domain_realm (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain_controller:
adcli_conn_set_domain_controller (conn, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_domain_ou:
adcli_enroll_set_domain_ou (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_service_name:
adcli_enroll_add_service_name (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_no_password:
if (stdin_password || prompt_password) {
- errx (EUSAGE, "cannot use --no-password argument with %s",
- stdin_password ? "--stdin-password" : "--prompt-password");
+ warnx ("cannot use --no-password argument with %s",
+ stdin_password ? "--stdin-password" : "--prompt-password");
+ return EUSAGE;
} else {
adcli_conn_set_password_func (conn, NULL, NULL, NULL);
no_password = 1;
}
- return;
+ return ADCLI_SUCCESS;
case opt_prompt_password:
if (stdin_password || no_password) {
- errx (EUSAGE, "cannot use --prompt-password argument with %s",
- stdin_password ? "--stdin-password" : "--no-password");
+ warnx ("cannot use --prompt-password argument with %s",
+ stdin_password ? "--stdin-password" : "--no-password");
+ return EUSAGE;
} else {
adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL);
prompt_password = 1;
}
- return;
+ return ADCLI_SUCCESS;
case opt_stdin_password:
if (prompt_password || no_password) {
- errx (EUSAGE, "cannot use --stdin-password argument with %s",
- prompt_password ? "--prompt-password" : "--no-password");
+ warnx ("cannot use --stdin-password argument with %s",
+ prompt_password ? "--prompt-password" : "--no-password");
+ return EUSAGE;
} else {
adcli_conn_set_password_func (conn, adcli_read_password_func, NULL, NULL);
stdin_password = 1;
}
- return;
+ return ADCLI_SUCCESS;
case opt_os_name:
adcli_enroll_set_os_name (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_os_version:
adcli_enroll_set_os_version (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_os_service_pack:
adcli_enroll_set_os_service_pack (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_user_principal:
if (optarg && optarg[0])
adcli_enroll_set_user_principal (enroll, optarg);
else
adcli_enroll_auto_user_principal (enroll);
- return;
+ return ADCLI_SUCCESS;
case opt_computer_password_lifetime:
errno = 0;
lifetime = strtoul (optarg, &endptr, 10);
if (errno != 0 || *endptr != '\0' || endptr == optarg) {
- errx (EUSAGE,
- "failure to parse value '%s' of option 'computer-password-lifetime'; "
- "expecting non-negative integer indicating the lifetime in days",
- optarg);
+ warnx ("failure to parse value '%s' of option 'computer-password-lifetime'; "
+ "expecting non-negative integer indicating the lifetime in days",
+ optarg);
+ return EUSAGE;
}
adcli_enroll_set_computer_password_lifetime (enroll, lifetime);
- return;
+ return ADCLI_SUCCESS;
case opt_samba_data_tool:
errno = 0;
ret = access (optarg, X_OK);
if (ret != 0) {
ret = errno;
- errx (EUSAGE, "Failed to access tool to add Samba data: %s", strerror (ret));
+ warnx ("Failed to access tool to add Samba data: %s", strerror (ret));
+ return EUSAGE;
} else {
adcli_enroll_set_samba_data_tool (enroll, optarg);
}
- return;
+ return ADCLI_SUCCESS;
case opt_trusted_for_delegation:
if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) {
adcli_enroll_set_trusted_for_delegation (enroll, true);
} else {
adcli_enroll_set_trusted_for_delegation (enroll, false);
}
- return;
+ return ADCLI_SUCCESS;
case opt_add_service_principal:
adcli_enroll_add_service_principal_to_add (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_remove_service_principal:
adcli_enroll_add_service_principal_to_remove (enroll, optarg);
- return;
+ return ADCLI_SUCCESS;
case opt_verbose:
- return;
+ return ADCLI_SUCCESS;
/* Should be handled by caller */
case opt_show_details:
@@ -311,7 +318,8 @@ parse_option (Option opt,
break;
}
- errx (EUSAGE, "failure to parse option '%c'", opt);
+ warnx ("failure to parse option '%c'", opt);
+ return EUSAGE;
}
static void
@@ -407,7 +415,11 @@ adcli_tool_computer_join (adcli_conn *conn,
adcli_enroll_unref (enroll);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn, enroll);
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
break;
}
}
@@ -519,7 +531,11 @@ adcli_tool_computer_update (adcli_conn *conn,
adcli_enroll_unref (enroll);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn, enroll);
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
break;
}
}
@@ -610,7 +626,11 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
adcli_enroll_unref (enroll);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn, enroll);
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
break;
}
}
@@ -707,7 +727,11 @@ adcli_tool_computer_preset (adcli_conn *conn,
adcli_enroll_unref (enroll);
return 2;
default:
- parse_option ((Option)opt, optarg, conn, enroll);
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
break;
}
}
@@ -801,7 +825,11 @@ adcli_tool_computer_reset (adcli_conn *conn,
adcli_enroll_unref (enroll);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn, enroll);
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
break;
}
}
@@ -884,7 +912,11 @@ adcli_tool_computer_delete (adcli_conn *conn,
adcli_enroll_unref (enroll);
return opt == 'h' ? 0 : 2;
default:
- parse_option ((Option)opt, optarg, conn, enroll);
+ res = parse_option ((Option)opt, optarg, conn, enroll);
+ if (res != ADCLI_SUCCESS) {
+ adcli_enroll_unref (enroll);
+ return res;
+ }
break;
}
}
--
2.20.1

View File

@ -0,0 +1,178 @@
From f28edf4e887cf8616fa21dacc2b0f0d31f5f92fb Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 14:37:05 +0100
Subject: [PATCH 08/23] library: add _adcli_bin_sid_to_str()
Convert a binary SID to the string representation.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
library/adprivate.h | 4 ++
library/adutil.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 117 insertions(+)
diff --git a/library/adprivate.h b/library/adprivate.h
index fc146af..e99f9fc 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -31,6 +31,7 @@
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
+#include <stdint.h>
#include <ldap.h>
@@ -132,6 +133,9 @@ int _adcli_str_has_prefix (const char *str,
int _adcli_str_has_suffix (const char *str,
const char *suffix);
+char * _adcli_bin_sid_to_str (const uint8_t *data,
+ size_t len);
+
char * _adcli_str_dupn (void *data,
size_t len);
diff --git a/library/adutil.c b/library/adutil.c
index cd40f45..829cdd9 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -293,6 +293,83 @@ _adcli_strv_set (char ***field,
*field = newval;
}
+char *
+_adcli_bin_sid_to_str (const uint8_t *data,
+ size_t len)
+{
+ uint8_t sid_rev_num;
+ int8_t num_auths;
+ uint8_t id_auth[6];
+ uint32_t id_auth_val;
+ uint32_t sub_auths[15];
+ uint32_t val;
+ size_t p = 0;
+ size_t c;
+ int nc;
+ char *sid_buf;
+ size_t sid_buf_len;
+
+ if (data == NULL || len < 8) {
+ return NULL;
+ }
+
+ sid_rev_num = (uint8_t) data [p];
+ p++;
+
+ num_auths = (int8_t) data[p];
+ p++;
+
+ if (num_auths > 15 || len < 8 + (num_auths * sizeof (uint32_t))) {
+ return NULL;
+ }
+
+ for (c = 0; c < 6; c++) {
+ id_auth[c] = (uint8_t) data[p];
+ p++;
+ }
+
+ /* Only 32bits are used for the string representation */
+ id_auth_val = (id_auth[2] << 24) +
+ (id_auth[3] << 16) +
+ (id_auth[4] << 8) +
+ (id_auth[5]);
+
+ for (c = 0; c < num_auths; c++) {
+ memcpy (&val, data + p, sizeof (uint32_t));
+ sub_auths[c] = le32toh (val);
+
+ p += sizeof (uint32_t);
+ }
+
+ sid_buf_len = 17 + (num_auths * 11);
+ sid_buf = calloc (1, sid_buf_len);
+ if (sid_buf == NULL) {
+ return NULL;
+ }
+
+ nc = snprintf (sid_buf, sid_buf_len, "S-%u-%lu", sid_rev_num,
+ (unsigned long) id_auth_val);
+ if (nc < 0 || nc >= sid_buf_len) {
+ free (sid_buf);
+ return NULL;
+ }
+
+ p = 0;
+ for (c = 0; c < num_auths; c++) {
+ p += nc;
+ sid_buf_len -= nc;
+
+ nc = snprintf (sid_buf + p, sid_buf_len, "-%lu",
+ (unsigned long) sub_auths[c]);
+ if (nc < 0 || nc >= sid_buf_len) {
+ free (sid_buf);
+ return NULL;
+ }
+ }
+
+ return sid_buf;
+}
+
char *
_adcli_str_dupn (void *data,
size_t len)
@@ -508,6 +585,41 @@ test_check_nt_time_string_lifetime (void)
assert (_adcli_check_nt_time_string_lifetime ("130645404000000000", 100000));
}
+static void
+test_bin_sid_to_str (void)
+{
+ uint8_t sid1[] = { 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0xF8, 0x12, 0x13, 0xDC,
+ 0x47, 0xF3, 0x1C, 0x76, 0x47, 0x2F, 0x2E, 0xD7,
+ 0x51, 0x04, 0x00, 0x00 };
+
+ uint8_t sid2[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0xF8, 0x12, 0x13, 0xDC,
+ 0x47, 0xF3, 0x1C, 0x76, 0x47, 0x2F, 0x2E, 0xD7};
+
+ uint8_t sid3[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+ 0x15, 0x00, 0x00, 0x00, 0x29, 0xC9, 0x4F, 0xD9,
+ 0xC2, 0x3C, 0xC3, 0x78, 0x36, 0x55, 0x87, 0xF8};
+
+
+ char *str;
+
+ str = _adcli_bin_sid_to_str (sid1, sizeof (sid1));
+ assert (str != NULL);
+ assert (strcmp (str, "S-1-5-21-3692237560-1981608775-3610128199-1105") == 0);
+ free (str);
+
+ str = _adcli_bin_sid_to_str (sid2, sizeof (sid2));
+ assert (str != NULL);
+ assert (strcmp (str, "S-1-5-21-3692237560-1981608775-3610128199") == 0);
+ free (str);
+
+ str = _adcli_bin_sid_to_str (sid3, sizeof (sid2));
+ assert (str != NULL);
+ assert (strcmp (str, "S-1-5-21-3645884713-2026060994-4169618742") == 0);
+ free (str);
+}
+
int
main (int argc,
char *argv[])
@@ -516,6 +628,7 @@ main (int argc,
test_func (test_strv_dup, "/util/strv_dup");
test_func (test_strv_count, "/util/strv_count");
test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
+ test_func (test_bin_sid_to_str, "/util/bin_sid_to_str");
return test_run (argc, argv);
}
--
2.14.4

View File

@ -0,0 +1,317 @@
From 63576f12524f521c0cf08d42b279654885135a90 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 14:39:17 +0100
Subject: [PATCH 09/23] library: add _adcli_call_external_program()
Allow adcli to call an external program given by an absolute path name
and an array of options. stdin and stdout can be used if needed.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
configure.ac | 28 +++++++
library/adprivate.h | 6 ++
library/adutil.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 245 insertions(+)
diff --git a/configure.ac b/configure.ac
index 221d8ae..fe86638 100644
--- a/configure.ac
+++ b/configure.ac
@@ -263,6 +263,34 @@ AC_SUBST(LCOV)
AC_SUBST(GCOV)
AC_SUBST(GENHTML)
+AC_PATH_PROG(BIN_CAT, cat, no)
+if test "$BIN_CAT" = "no" ; then
+ AC_MSG_ERROR([cat is not available])
+else
+ AC_DEFINE_UNQUOTED(BIN_CAT, "$BIN_CAT", [path to cat, used in unit test])
+fi
+
+AC_PATH_PROG(BIN_TAC, tac, no)
+if test "$BIN_TAC" = "no" ; then
+ AC_MSG_ERROR([tac is not available])
+else
+ AC_DEFINE_UNQUOTED(BIN_TAC, "$BIN_TAC", [path to tac, used in unit test])
+fi
+
+AC_PATH_PROG(BIN_REV, rev, no)
+if test "$BIN_REV" = "no" ; then
+ AC_MSG_ERROR([rev is not available])
+else
+ AC_DEFINE_UNQUOTED(BIN_REV, "$BIN_REV", [path to rev, used in unit test])
+fi
+
+AC_PATH_PROG(BIN_ECHO, echo, no)
+if test "$BIN_ECHO" = "no" ; then
+ AC_MSG_ERROR([echo is not available])
+else
+ AC_DEFINE_UNQUOTED(BIN_ECHO, "$BIN_ECHO", [path to echo, used in unit test])
+fi
+
# ---------------------------------------------------------------------
ADCLI_LT_RELEASE=$ADCLI_CURRENT:$ADCLI_REVISION:$ADCLI_AGE
diff --git a/library/adprivate.h b/library/adprivate.h
index e99f9fc..7257c93 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -285,4 +285,10 @@ struct _adcli_attrs {
bool _adcli_check_nt_time_string_lifetime (const char *nt_time_string, unsigned int lifetime);
+adcli_result _adcli_call_external_program (const char *binary,
+ char * const *argv,
+ const char *stdin_data,
+ uint8_t **stdout_data,
+ size_t *stdout_data_len);
+
#endif /* ADPRIVATE_H_ */
diff --git a/library/adutil.c b/library/adutil.c
index 829cdd9..a27bd68 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -36,6 +36,7 @@
#include <unistd.h>
#include <stdint.h>
#include <time.h>
+#include <sys/wait.h>
static adcli_message_func message_func = NULL;
static char last_error[2048] = { 0, };
@@ -506,6 +507,161 @@ _adcli_check_nt_time_string_lifetime (const char *nt_time_string,
return false;
}
+adcli_result
+_adcli_call_external_program (const char *binary, char * const *argv,
+ const char *stdin_data,
+ uint8_t **stdout_data, size_t *stdout_data_len)
+{
+ int ret;
+ int pipefd_to_child[2] = { -1, -1};
+ int pipefd_from_child[2] = { -1, -1};
+ pid_t child_pid = 0;
+ int err;
+ size_t len;
+ ssize_t rlen;
+ pid_t wret;
+ int status;
+ uint8_t read_buf[4096];
+ uint8_t *out;
+
+ errno = 0;
+ ret = access (binary, X_OK);
+ if (ret != 0) {
+ err = errno;
+ _adcli_err ("Cannot run [%s]: [%d][%s].", binary, err,
+ strerror (err));
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ }
+
+ ret = pipe (pipefd_from_child);
+ if (ret == -1) {
+ err = errno;
+ _adcli_err ("pipe failed [%d][%s].", err, strerror (err));
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ }
+
+ ret = pipe (pipefd_to_child);
+ if (ret == -1) {
+ err = errno;
+ _adcli_err ("pipe failed [%d][%s].", err, strerror (err));
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ }
+
+ child_pid = fork ();
+
+ if (child_pid == 0) { /* child */
+ close (pipefd_to_child[1]);
+ ret = dup2 (pipefd_to_child[0], STDIN_FILENO);
+ if (ret == -1) {
+ err = errno;
+ _adcli_err ("dup2 failed [%d][%s].", err,
+ strerror (err));
+ exit (EXIT_FAILURE);
+ }
+
+ close (pipefd_from_child[0]);
+ ret = dup2 (pipefd_from_child[1], STDOUT_FILENO);
+ if (ret == -1) {
+ err = errno;
+ _adcli_err ("dup2 failed [%d][%s].", err,
+ strerror (err));
+ exit (EXIT_FAILURE);
+ }
+
+ execv (binary, argv);
+ _adcli_err ("Failed to run %s.", binary);
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ } else if (child_pid > 0) { /* parent */
+
+ if (stdin_data != NULL) {
+ len = strlen (stdin_data);
+ ret = write (pipefd_to_child[1], stdin_data, len);
+ if (ret != len) {
+ _adcli_err ("Failed to send computer account password "
+ "to net command.");
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ }
+ }
+
+ close (pipefd_to_child[0]);
+ pipefd_to_child[0] = -1;
+ close (pipefd_to_child[1]);
+ pipefd_to_child[0] = -1;
+
+ if (stdout_data != NULL || stdout_data_len != NULL) {
+ rlen = read (pipefd_from_child[0], read_buf, sizeof (read_buf));
+ if (rlen < 0) {
+ ret = errno;
+ _adcli_err ("Failed to read from child [%d][%s].\n",
+ ret, strerror (ret));
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ }
+
+ out = malloc (sizeof(uint8_t) * rlen);
+ if (out == NULL) {
+ _adcli_err ("Failed to allocate memory "
+ "for child output.");
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ } else {
+ memcpy (out, read_buf, rlen);
+ }
+
+ if (stdout_data != NULL) {
+ *stdout_data = out;
+ } else {
+ free (out);
+ }
+
+ if (stdout_data_len != NULL) {
+ *stdout_data_len = rlen;
+ }
+ }
+
+ } else {
+ _adcli_err ("Cannot run net command.");
+ ret = ADCLI_ERR_FAIL;
+ goto done;
+ }
+
+ ret = ADCLI_SUCCESS;
+
+done:
+ if (pipefd_from_child[0] != -1) {
+ close (pipefd_from_child[0]);
+ }
+ if (pipefd_from_child[1] != -1) {
+ close (pipefd_from_child[1]);
+ }
+ if (pipefd_to_child[0] != -1) {
+ close (pipefd_to_child[0]);
+ }
+ if (pipefd_to_child[1] != -1) {
+ close (pipefd_to_child[1]);
+ }
+
+ if (child_pid > 0) {
+ wret = waitpid (child_pid, &status, 0);
+ if (wret == -1) {
+ _adcli_err ("No sure what happend to net command.");
+ } else {
+ if (WIFEXITED (status)) {
+ _adcli_err ("net command failed with %d.",
+ WEXITSTATUS (status));
+ }
+ }
+ }
+
+ return ret;
+}
+
+
#ifdef UTIL_TESTS
#include "test.h"
@@ -620,6 +776,60 @@ test_bin_sid_to_str (void)
free (str);
}
+static void
+test_call_external_program (void)
+{
+ adcli_result res;
+ char *argv[] = { NULL, NULL, NULL };
+ uint8_t *stdout_data;
+ size_t stdout_data_len;
+
+ argv[0] = "/does/not/exists";
+ res = _adcli_call_external_program (argv[0], argv, NULL, NULL, NULL);
+ assert (res == ADCLI_ERR_FAIL);
+
+#ifdef BIN_CAT
+ argv[0] = BIN_CAT;
+ res = _adcli_call_external_program (argv[0], argv, "Hello",
+ &stdout_data, &stdout_data_len);
+ assert (res == ADCLI_SUCCESS);
+ assert (strncmp ("Hello", (char *) stdout_data, stdout_data_len) == 0);
+ free (stdout_data);
+
+ res = _adcli_call_external_program (argv[0], argv, "Hello",
+ NULL, NULL);
+ assert (res == ADCLI_SUCCESS);
+#endif
+
+#ifdef BIN_REV
+ argv[0] = BIN_REV;
+ res = _adcli_call_external_program (argv[0], argv, "Hello\n",
+ &stdout_data, &stdout_data_len);
+ assert (res == ADCLI_SUCCESS);
+ assert (strncmp ("olleH\n", (char *) stdout_data, stdout_data_len) == 0);
+ free (stdout_data);
+#endif
+
+#ifdef BIN_TAC
+ argv[0] = BIN_TAC;
+ res = _adcli_call_external_program (argv[0], argv, "Hello\nWorld\n",
+ &stdout_data, &stdout_data_len);
+ assert (res == ADCLI_SUCCESS);
+ assert (strncmp ("World\nHello\n", (char *) stdout_data, stdout_data_len) == 0);
+ free (stdout_data);
+#endif
+
+#ifdef BIN_ECHO
+ argv[0] = BIN_ECHO;
+ argv[1] = "Hello";
+ res = _adcli_call_external_program (argv[0], argv, NULL,
+ &stdout_data, &stdout_data_len);
+ assert (res == ADCLI_SUCCESS);
+ assert (strncmp ("Hello\n", (char *) stdout_data, stdout_data_len) == 0);
+ free (stdout_data);
+#endif
+}
+
int
main (int argc,
char *argv[])
@@ -629,6 +839,7 @@ main (int argc,
test_func (test_strv_count, "/util/strv_count");
test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
test_func (test_bin_sid_to_str, "/util/bin_sid_to_str");
+ test_func (test_call_external_program, "/util/call_external_program");
return test_run (argc, argv);
}
--
2.14.4

View File

@ -0,0 +1,69 @@
From bab08d90162c9146c1b4e8373f4b08209b84768c Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 14:44:45 +0100
Subject: [PATCH 10/23] library: add _adcli_ldap_parse_sid()
Get a binary SID from a LDAP message and return it in the string
representation.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
library/adldap.c | 24 ++++++++++++++++++++++++
library/adprivate.h | 4 ++++
2 files changed, 28 insertions(+)
diff --git a/library/adldap.c b/library/adldap.c
index 7c7a01b..07dc373 100644
--- a/library/adldap.c
+++ b/library/adldap.c
@@ -67,6 +67,30 @@ _adcli_ldap_handle_failure (LDAP *ldap,
return defres;
}
+char *
+_adcli_ldap_parse_sid (LDAP *ldap,
+ LDAPMessage *results,
+ const char *attr_name)
+{
+ LDAPMessage *entry;
+ struct berval **bvs;
+ char *val = NULL;
+
+ entry = ldap_first_entry (ldap, results);
+ if (entry != NULL) {
+ bvs = ldap_get_values_len (ldap, entry, attr_name);
+ if (bvs != NULL) {
+ if (bvs[0]) {
+ val = _adcli_bin_sid_to_str ( (uint8_t *) bvs[0]->bv_val,
+ bvs[0]->bv_len);
+ return_val_if_fail (val != NULL, NULL);
+ }
+ ldap_value_free_len (bvs);
+ }
+ }
+
+ return val;
+}
char *
_adcli_ldap_parse_value (LDAP *ldap,
diff --git a/library/adprivate.h b/library/adprivate.h
index 7257c93..83a88f6 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -174,6 +174,10 @@ adcli_result _adcli_ldap_handle_failure (LDAP *ldap,
const char *desc,
...) GNUC_PRINTF(3, 4);
+char * _adcli_ldap_parse_sid (LDAP *ldap,
+ LDAPMessage *results,
+ const char *attr_name);
+
char * _adcli_ldap_parse_value (LDAP *ldap,
LDAPMessage *results,
const char *attr_name);
--
2.14.4

View File

@ -0,0 +1,71 @@
From 3fa854b1439c039a2250cb24efadae6a66b0e9da Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 14:40:46 +0100
Subject: [PATCH 11/23] library: add lookup_domain_sid()
Read the domain SID from the default naming context AD object and store
it in adcli_conn.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
library/adconn.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/library/adconn.c b/library/adconn.c
index 67bdfd9..6b84b88 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -72,6 +72,7 @@ struct _adcli_conn_ctx {
char *domain_controller;
char *canonical_host;
char *domain_short;
+ char *domain_sid;
adcli_disco *domain_disco;
char *default_naming_context;
char *configuration_naming_context;
@@ -1068,6 +1069,32 @@ lookup_short_name (adcli_conn *conn)
}
}
+static void
+lookup_domain_sid (adcli_conn *conn)
+{
+ char *attrs[] = { "objectSid", NULL, };
+ LDAPMessage *results;
+ int ret;
+
+ free (conn->domain_sid);
+ conn->domain_sid = NULL;
+
+ ret = ldap_search_ext_s (conn->ldap, conn->default_naming_context, LDAP_SCOPE_BASE,
+ NULL, attrs, 0, NULL, NULL, NULL, -1, &results);
+ if (ret == LDAP_SUCCESS) {
+ conn->domain_sid = _adcli_ldap_parse_sid (conn->ldap, results, "objectSid");
+ ldap_msgfree (results);
+
+ if (conn->domain_sid)
+ _adcli_info ("Looked up domain SID: %s", conn->domain_sid);
+ else
+ _adcli_err ("No domain SID found");
+ } else {
+ _adcli_ldap_handle_failure (conn->ldap, ADCLI_ERR_DIRECTORY,
+ "Couldn't lookup domain SID");
+ }
+}
+
static void
conn_clear_state (adcli_conn *conn)
{
@@ -1148,6 +1175,7 @@ adcli_conn_connect (adcli_conn *conn)
return res;
lookup_short_name (conn);
+ lookup_domain_sid (conn);
return ADCLI_SUCCESS;
}
--
2.14.4

View File

@ -0,0 +1,61 @@
From f98c4f92091f6a68f390078f73be3bb6ca6e6550 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 18:23:03 +0100
Subject: [PATCH 12/23] library: add adcli_conn_get_domain_sid()
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
library/adconn.c | 8 ++++++++
library/adconn.h | 2 ++
tools/computer.c | 1 +
3 files changed, 11 insertions(+)
diff --git a/library/adconn.c b/library/adconn.c
index 6b84b88..d2fb1d5 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -1355,6 +1355,14 @@ adcli_conn_get_domain_short (adcli_conn *conn)
return conn->domain_short;
}
+const char *
+adcli_conn_get_domain_sid (adcli_conn *conn)
+{
+ return_val_if_fail (conn != NULL, NULL);
+ return conn->domain_sid;
+}
+
+
LDAP *
adcli_conn_get_ldap_connection (adcli_conn *conn)
{
diff --git a/library/adconn.h b/library/adconn.h
index ed1cc58..13cfd32 100644
--- a/library/adconn.h
+++ b/library/adconn.h
@@ -91,6 +91,8 @@ void adcli_conn_set_domain_controller (adcli_conn *conn,
const char * adcli_conn_get_domain_short (adcli_conn *conn);
+const char * adcli_conn_get_domain_sid (adcli_conn *conn);
+
LDAP * adcli_conn_get_ldap_connection (adcli_conn *conn);
krb5_context adcli_conn_get_krb5_context (adcli_conn *conn);
diff --git a/tools/computer.c b/tools/computer.c
index d8a58c9..a3d0f03 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -43,6 +43,7 @@ dump_details (adcli_conn *conn,
printf ("domain-realm = %s\n", adcli_conn_get_domain_realm (conn));
printf ("domain-controller = %s\n", adcli_conn_get_domain_controller (conn));
printf ("domain-short = %s\n", adcli_conn_get_domain_short (conn));
+ printf ("domain-SID = %s\n", adcli_conn_get_domain_sid (conn));
printf ("naming-context = %s\n", adcli_conn_get_default_naming_context (conn));
printf ("domain-ou = %s\n", adcli_enroll_get_domain_ou (enroll));
--
2.14.4

View File

@ -0,0 +1,142 @@
From d362a0799618b576918f5c5d0625565484670ba2 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 14:46:00 +0100
Subject: [PATCH 13/23] tools: add option --add-samba-data
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
doc/adcli.xml | 30 ++++++++++++++++++++++++++++++
library/adenroll.h | 1 +
tools/computer.c | 12 ++++++++++++
3 files changed, 43 insertions(+)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index c54cc1b..fbc6c63 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -292,6 +292,21 @@ Password for Administrator:
machine account password. This is output in a format that should
be both human and machine readable.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--add-samba-data</option></term>
+ <listitem><para>After a successful join add the domain
+ SID and the machine account password to the Samba
+ specific databases by calling Samba's
+ <command>net</command> utility.</para>
+
+ <para>Please note that Samba's <command>net</command>
+ requires some settings in <filename>smb.conf</filename>
+ to create the database entries correctly. Most
+ important here is currently the
+ <option>workgroup</option> option, see
+ <citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -382,6 +397,21 @@ $ adcli update --login-ccache=/tmp/krbcc_123
about join operation. This is output in a format that should
be both human and machine readable.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--add-samba-data</option></term>
+ <listitem><para>After a successful join add the domain
+ SID and the machine account password to the Samba
+ specific databases by calling Samba's
+ <command>net</command> utility.</para>
+
+ <para>Please note that Samba's <command>net</command>
+ requires some settings in <filename>smb.conf</filename>
+ to create the database entries correctly. Most
+ important here is currently the
+ <option>workgroup</option> option, see
+ <citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/library/adenroll.h b/library/adenroll.h
index 9a107ab..32c9764 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -30,6 +30,7 @@ typedef enum {
ADCLI_ENROLL_NO_KEYTAB = 1 << 1,
ADCLI_ENROLL_ALLOW_OVERWRITE = 1 << 2,
ADCLI_ENROLL_PASSWORD_VALID = 1 << 3,
+ ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 3,
} adcli_enroll_flags;
typedef struct _adcli_enroll adcli_enroll;
diff --git a/tools/computer.c b/tools/computer.c
index a3d0f03..fc646f2 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -106,6 +106,7 @@ typedef enum {
opt_os_service_pack,
opt_user_principal,
opt_computer_password_lifetime,
+ opt_add_samba_data,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -142,6 +143,8 @@ static adcli_tool_desc common_usages[] = {
"a successful join" },
{ opt_show_password, "show computer account password after after a\n"
"successful join" },
+ { opt_add_samba_data, "add domain SID and computer account password\n"
+ "to the Samba specific configuration database" },
{ opt_verbose, "show verbose progress and failure messages", },
{ 0 },
};
@@ -269,6 +272,7 @@ parse_option (Option opt,
case opt_show_details:
case opt_show_password:
case opt_one_time_password:
+ case opt_add_samba_data:
assert (0 && "not reached");
break;
}
@@ -326,6 +330,7 @@ adcli_tool_computer_join (adcli_conn *conn,
{ "user-principal", optional_argument, NULL, opt_user_principal },
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
+ { "add-samba-data", no_argument, NULL, opt_add_samba_data },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
@@ -352,6 +357,9 @@ adcli_tool_computer_join (adcli_conn *conn,
case opt_show_password:
show_password = 1;
break;
+ case opt_add_samba_data:
+ flags |= ADCLI_ENROLL_ADD_SAMBA_DATA;
+ break;
case 'h':
case '?':
case ':':
@@ -425,6 +433,7 @@ adcli_tool_computer_update (adcli_conn *conn,
{ "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime },
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
+ { "add-samba-data", no_argument, NULL, opt_add_samba_data },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
@@ -447,6 +456,9 @@ adcli_tool_computer_update (adcli_conn *conn,
case opt_show_password:
show_password = 1;
break;
+ case opt_add_samba_data:
+ flags |= ADCLI_ENROLL_ADD_SAMBA_DATA;
+ break;
case 'h':
case '?':
case ':':
--
2.14.4

View File

@ -0,0 +1,75 @@
From c090131e4f912f6f6c4f79eb40fbe500eb31c171 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 30 Jan 2018 18:24:15 +0100
Subject: [PATCH 14/23] tools: store Samba data if requested
Use Samba's net utility to add the machine account password and the
domain SID to the Samba configuration.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
library/adenroll.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/library/adenroll.c b/library/adenroll.c
index bb970d1..20731cd 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -1533,6 +1533,36 @@ update_keytab_for_principals (adcli_enroll *enroll)
return ADCLI_SUCCESS;
}
+static adcli_result
+update_samba_data (adcli_enroll *enroll)
+{
+ int ret;
+ char *argv_pw[] = { "/usr/bin/net", "changesecretpw", "-i", "-f", NULL };
+ char *argv_sid[] = { "/usr/bin/net", "setdomainsid", NULL, NULL };
+
+ _adcli_info ("Trying to set Samba secret.\n");
+ ret = _adcli_call_external_program (argv_pw[0], argv_pw,
+ enroll->computer_password, NULL, NULL);
+ if (ret != ADCLI_SUCCESS) {
+ _adcli_err ("Failed to set Samba computer account password.\n");
+ }
+
+ argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
+ if (argv_sid[2] == NULL) {
+ _adcli_err ("Domain SID not available.\n");
+ } else {
+ _adcli_info ("Trying to set domain SID %s for Samba.\n",
+ argv_sid[2]);
+ ret = _adcli_call_external_program (argv_sid[0], argv_sid,
+ NULL, NULL, NULL);
+ if (ret != ADCLI_SUCCESS) {
+ _adcli_err ("Failed to set Samba domain SID.\n");
+ }
+ }
+
+ return ret;
+}
+
static void
enroll_clear_state (adcli_enroll *enroll)
{
@@ -1687,6 +1717,15 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
update_computer_account (enroll);
update_service_principals (enroll);
+ if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
+ res = update_samba_data (enroll);
+ if (res != ADCLI_SUCCESS) {
+ _adcli_info ("Failed to add Samba specific data, smbd "
+ "or winbindd might not work as "
+ "expected.\n");
+ }
+ }
+
if (flags & ADCLI_ENROLL_NO_KEYTAB)
return ADCLI_SUCCESS;
--
2.14.4

View File

@ -0,0 +1,292 @@
From 9b73f79a2436760b8278377014bf78a144a427ae Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 1 Feb 2018 14:26:22 +0100
Subject: [PATCH 15/23] make Samba data tool configurable
Allow to specify an alternative path to Samba's net utility at configure
time and at run time.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
configure.ac | 13 ++++++++++++
doc/adcli.xml | 21 ++++++++++++++++++-
doc/samba_data_tool_path.xml.in | 1 +
library/adenroll.c | 46 ++++++++++++++++++++++++++++++++++-------
library/adenroll.h | 5 +++++
tools/computer.c | 16 ++++++++++++++
7 files changed, 95 insertions(+), 8 deletions(-)
create mode 100644 doc/samba_data_tool_path.xml.in
diff --git a/configure.ac b/configure.ac
index fe86638..68877c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -291,6 +291,18 @@ else
AC_DEFINE_UNQUOTED(BIN_ECHO, "$BIN_ECHO", [path to echo, used in unit test])
fi
+AC_MSG_CHECKING([where is Samba's net utility])
+AC_ARG_WITH([samba_data_tool],
+ AC_HELP_STRING([--with-samba-data-tool=/path],
+ [Path to Samba's net utility]),
+ [],
+ [with_samba_data_tool=/usr/bin/net])
+AC_MSG_RESULT([$with_samba_data_tool])
+
+AC_DEFINE_UNQUOTED(SAMBA_DATA_TOOL, "$with_samba_data_tool",
+ [Path to Samba's net utility])
+
+AC_SUBST(SAMBA_DATA_TOOL, [$with_samba_data_tool])
# ---------------------------------------------------------------------
ADCLI_LT_RELEASE=$ADCLI_CURRENT:$ADCLI_REVISION:$ADCLI_AGE
@@ -300,6 +312,7 @@ AC_CONFIG_FILES([Makefile
build/Makefile
doc/Makefile
doc/version.xml
+ doc/samba_data_tool_path.xml
library/Makefile
tools/Makefile
])
diff --git a/doc/adcli.xml b/doc/adcli.xml
index fbc6c63..c2b7760 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+ <!ENTITY samba_data_tool SYSTEM "samba_data_tool_path.xml">
+]>
<refentry id="adcli">
@@ -307,6 +310,14 @@ Password for Administrator:
<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+ <listitem><para>If Samba's <command>net</command>
+ cannot be found at
+ <filename>&samba_data_tool;</filename> this option can
+ be used to specific an alternative location with the
+ help of an absolute path.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -412,6 +423,14 @@ $ adcli update --login-ccache=/tmp/krbcc_123
<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+ <listitem><para>If Samba's <command>net</command>
+ cannot be found at
+ <filename>&samba_data_tool;</filename> this option can
+ be used to specific an alternative location with the
+ help of an absolute path.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/doc/samba_data_tool_path.xml.in b/doc/samba_data_tool_path.xml.in
new file mode 100644
index 0000000..a667c57
--- /dev/null
+++ b/doc/samba_data_tool_path.xml.in
@@ -0,0 +1 @@
+@SAMBA_DATA_TOOL@
diff --git a/library/adenroll.c b/library/adenroll.c
index 20731cd..a693049 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -42,6 +42,10 @@
#include <stdio.h>
#include <unistd.h>
+#ifndef SAMBA_DATA_TOOL
+#define SAMBA_DATA_TOOL "/usr/bin/net"
+#endif
+
static krb5_enctype v60_later_enctypes[] = {
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
@@ -100,6 +104,7 @@ struct _adcli_enroll {
int keytab_enctypes_explicit;
unsigned int computer_password_lifetime;
int computer_password_lifetime_explicit;
+ char *samba_data_tool;
};
static adcli_result
@@ -1537,26 +1542,33 @@ static adcli_result
update_samba_data (adcli_enroll *enroll)
{
int ret;
- char *argv_pw[] = { "/usr/bin/net", "changesecretpw", "-i", "-f", NULL };
- char *argv_sid[] = { "/usr/bin/net", "setdomainsid", NULL, NULL };
+ char *argv_pw[] = { NULL, "changesecretpw", "-i", "-f", NULL };
+ char *argv_sid[] = { NULL, "setdomainsid", NULL, NULL };
+
+ argv_pw[0] = (char *) adcli_enroll_get_samba_data_tool (enroll);
+ if (argv_pw[0] ==NULL) {
+ _adcli_err ("Samba data tool not available.");
+ return ADCLI_ERR_FAIL;
+ }
+ argv_sid[0] = argv_pw[0];
- _adcli_info ("Trying to set Samba secret.\n");
+ _adcli_info ("Trying to set Samba secret.");
ret = _adcli_call_external_program (argv_pw[0], argv_pw,
enroll->computer_password, NULL, NULL);
if (ret != ADCLI_SUCCESS) {
- _adcli_err ("Failed to set Samba computer account password.\n");
+ _adcli_err ("Failed to set Samba computer account password.");
}
argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
if (argv_sid[2] == NULL) {
- _adcli_err ("Domain SID not available.\n");
+ _adcli_err ("Domain SID not available.");
} else {
- _adcli_info ("Trying to set domain SID %s for Samba.\n",
+ _adcli_info ("Trying to set domain SID %s for Samba.",
argv_sid[2]);
ret = _adcli_call_external_program (argv_sid[0], argv_sid,
NULL, NULL, NULL);
if (ret != ADCLI_SUCCESS) {
- _adcli_err ("Failed to set Samba domain SID.\n");
+ _adcli_err ("Failed to set Samba domain SID.");
}
}
@@ -1951,6 +1963,9 @@ adcli_enroll_new (adcli_conn *conn)
enroll->os_name = strdup (value);
return_val_if_fail (enroll->os_name != NULL, NULL);
+ enroll->samba_data_tool = strdup (SAMBA_DATA_TOOL);
+ return_val_if_fail (enroll->samba_data_tool != NULL, NULL);
+
return enroll;
}
@@ -1978,6 +1993,7 @@ enroll_free (adcli_enroll *enroll)
free (enroll->os_name);
free (enroll->os_version);
free (enroll->os_service_pack);
+ free (enroll->samba_data_tool);
free (enroll->user_principal);
_adcli_strv_free (enroll->service_names);
@@ -2343,3 +2359,19 @@ adcli_enroll_set_computer_password_lifetime (adcli_enroll *enroll,
enroll->computer_password_lifetime_explicit = 1;
}
+
+void
+adcli_enroll_set_samba_data_tool (adcli_enroll *enroll, const char *value)
+{
+ return_if_fail (enroll != NULL);
+ if (value != NULL && value[0] != '\0') {
+ _adcli_str_set (&enroll->samba_data_tool, value);
+ }
+}
+
+const char *
+adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
+{
+ return_val_if_fail (enroll != NULL, NULL);
+ return enroll->samba_data_tool;
+}
diff --git a/library/adenroll.h b/library/adenroll.h
index 32c9764..31ca0bc 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -141,4 +141,9 @@ const char * adcli_enroll_get_os_service_pack (adcli_enroll *enroll);
void adcli_enroll_set_os_service_pack (adcli_enroll *enroll,
const char *value);
+void adcli_enroll_set_samba_data_tool (adcli_enroll *enroll,
+ const char *value);
+
+const char * adcli_enroll_get_samba_data_tool (adcli_enroll *enroll);
+
#endif /* ADENROLL_H_ */
diff --git a/tools/computer.c b/tools/computer.c
index fc646f2..f86548b 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -30,6 +30,7 @@
#include <err.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
static void
dump_details (adcli_conn *conn,
@@ -107,6 +108,7 @@ typedef enum {
opt_user_principal,
opt_computer_password_lifetime,
opt_add_samba_data,
+ opt_samba_data_tool,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -145,6 +147,7 @@ static adcli_tool_desc common_usages[] = {
"successful join" },
{ opt_add_samba_data, "add domain SID and computer account password\n"
"to the Samba specific configuration database" },
+ { opt_samba_data_tool, "Absolute path to the tool used for add-samba-data" },
{ opt_verbose, "show verbose progress and failure messages", },
{ 0 },
};
@@ -160,6 +163,7 @@ parse_option (Option opt,
static int stdin_password = 0;
char *endptr;
unsigned int lifetime;
+ int ret;
switch (opt) {
case opt_login_ccache:
@@ -265,6 +269,16 @@ parse_option (Option opt,
adcli_enroll_set_computer_password_lifetime (enroll, lifetime);
return;
+ case opt_samba_data_tool:
+ errno = 0;
+ ret = access (optarg, X_OK);
+ if (ret != 0) {
+ ret = errno;
+ errx (EUSAGE, "Failed to access tool to add Samba data: %s", strerror (ret));
+ } else {
+ adcli_enroll_set_samba_data_tool (enroll, optarg);
+ }
+ return;
case opt_verbose:
return;
@@ -331,6 +345,7 @@ adcli_tool_computer_join (adcli_conn *conn,
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+ { "samba-data-tool", no_argument, NULL, opt_samba_data_tool },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
@@ -434,6 +449,7 @@ adcli_tool_computer_update (adcli_conn *conn,
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+ { "samba-data-tool", no_argument, NULL, opt_samba_data_tool },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
--
2.14.4

View File

@ -0,0 +1,247 @@
From f306f2f20c1d35fac63d27147824f039f7ef2d67 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 31 May 2018 18:27:37 +0200
Subject: [PATCH 16/23] Add trusted-for-delegation option
Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1538730
---
doc/adcli.xml | 14 ++++++++++
library/adenroll.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
library/adenroll.h | 4 +++
tools/computer.c | 12 ++++++++
4 files changed, 108 insertions(+), 2 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index c2b7760..b246190 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -283,6 +283,13 @@ Password for Administrator:
<option>--login-type=computer</option> and providing a
password as input.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--trusted-for-delegation=<parameter>yes|no|true|false</parameter></option></term>
+ <listitem><para>Set or unset the TRUSTED_FOR_DELEGATION
+ flag in the userAccountControl attribute to allow or
+ not allow that Kerberos tickets can be forwarded to the
+ host.</para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>--show-details</option></term>
<listitem><para>After a successful join print out information
@@ -402,6 +409,13 @@ $ adcli update --login-ccache=/tmp/krbcc_123
in days. By default the password is updated if it is
older than 30 days.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--trusted-for-delegation=<parameter>yes|no|true|false</parameter></option></term>
+ <listitem><para>Set or unset the TRUSTED_FOR_DELEGATION
+ flag in the userAccountControl attribute to allow or
+ not allow that Kerberos tickets can be forwarded to the
+ host.</para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>--show-details</option></term>
<listitem><para>After a successful join print out information
diff --git a/library/adenroll.c b/library/adenroll.c
index a693049..eca3c37 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -63,6 +63,13 @@ static krb5_enctype v51_earlier_enctypes[] = {
0
};
+/* Some constants for the userAccountControl AD LDAP attribute, see e.g.
+ * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
+ * for details. */
+#define UAC_WORKSTATION_TRUST_ACCOUNT 0x1000
+#define UAC_DONT_EXPIRE_PASSWORD 0x10000
+#define UAC_TRUSTED_FOR_DELEGATION 0x80000
+
struct _adcli_enroll {
int refs;
adcli_conn *conn;
@@ -105,6 +112,7 @@ struct _adcli_enroll {
unsigned int computer_password_lifetime;
int computer_password_lifetime_explicit;
char *samba_data_tool;
+ bool trusted_for_delegation;
};
static adcli_result
@@ -538,6 +546,10 @@ create_computer_account (adcli_enroll *enroll,
NULL,
};
+ if (adcli_enroll_get_trusted_for_delegation (enroll)) {
+ vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */
+ }
+
ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
/*
@@ -971,6 +983,7 @@ retrieve_computer_account (adcli_enroll *enroll)
"operatingSystemVersion",
"operatingSystemServicePack",
"pwdLastSet",
+ "userAccountControl",
NULL,
};
@@ -1149,6 +1162,47 @@ update_computer_attribute (adcli_enroll *enroll,
return res;
}
+static char *get_user_account_control (adcli_enroll *enroll)
+{
+ uint32_t uac = 0;
+ unsigned long attr_val;
+ char *uac_str;
+ LDAP *ldap;
+ char *end;
+
+ ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ return_val_if_fail (ldap != NULL, NULL);
+
+ uac_str = _adcli_ldap_parse_value (ldap, enroll->computer_attributes, "userAccountControl");
+ if (uac_str != NULL) {
+
+ attr_val = strtoul (uac_str, &end, 10);
+ if (*end != '\0' || attr_val > UINT32_MAX) {
+ _adcli_warn ("Invalid userAccountControl '%s' for computer account in directory: %s, assuming 0",
+ uac_str, enroll->computer_dn);
+ } else {
+ uac = attr_val;
+ }
+ free (uac_str);
+ }
+
+ if (uac == 0) {
+ uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD;
+ }
+
+ if (adcli_enroll_get_trusted_for_delegation (enroll)) {
+ uac |= UAC_TRUSTED_FOR_DELEGATION;
+ } else {
+ uac &= ~(UAC_TRUSTED_FOR_DELEGATION);
+ }
+
+ if (asprintf (&uac_str, "%d", uac) < 0) {
+ return_val_if_reached (NULL);
+ }
+
+ return uac_str;
+}
+
static void
update_computer_account (adcli_enroll *enroll)
{
@@ -1167,11 +1221,16 @@ update_computer_account (adcli_enroll *enroll)
}
if (res == ADCLI_SUCCESS) {
- char *vals_userAccountControl[] = { "69632", NULL }; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD */
+ char *vals_userAccountControl[] = { NULL , NULL };
LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
LDAPMod *mods[] = { &userAccountControl, NULL };
- res |= update_computer_attribute (enroll, ldap, mods);
+ vals_userAccountControl[0] = get_user_account_control (enroll);
+ if (vals_userAccountControl[0] != NULL) {
+ res |= update_computer_attribute (enroll, ldap, mods);
+ } else {
+ _adcli_warn ("Cannot update userAccountControl");
+ }
}
if (res == ADCLI_SUCCESS) {
@@ -2375,3 +2434,20 @@ adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
return_val_if_fail (enroll != NULL, NULL);
return enroll->samba_data_tool;
}
+
+bool
+adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll)
+{
+ return_val_if_fail (enroll != NULL, false);
+
+ return enroll->trusted_for_delegation;
+}
+
+void
+adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
+ bool value)
+{
+ return_if_fail (enroll != NULL);
+
+ enroll->trusted_for_delegation = value;
+}
diff --git a/library/adenroll.h b/library/adenroll.h
index 31ca0bc..be2ca18 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -109,6 +109,10 @@ unsigned int adcli_enroll_get_computer_password_lifetime (adcli_enroll *en
void adcli_enroll_set_computer_password_lifetime (adcli_enroll *enroll,
unsigned int lifetime);
+bool adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll);
+void adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
+ bool 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 f86548b..b905fd1 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -109,6 +109,7 @@ typedef enum {
opt_computer_password_lifetime,
opt_add_samba_data,
opt_samba_data_tool,
+ opt_trusted_for_delegation,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -135,6 +136,8 @@ static adcli_tool_desc common_usages[] = {
{ opt_os_service_pack, "the computer operating system service pack", },
{ opt_user_principal, "add an authentication principal to the account", },
{ opt_computer_password_lifetime, "lifetime of the host accounts password in days", },
+ { opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n"
+ "in the userAccountControl attribute", },
{ opt_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"
@@ -279,6 +282,13 @@ parse_option (Option opt,
adcli_enroll_set_samba_data_tool (enroll, optarg);
}
return;
+ case opt_trusted_for_delegation:
+ if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) {
+ adcli_enroll_set_trusted_for_delegation (enroll, true);
+ } else {
+ adcli_enroll_set_trusted_for_delegation (enroll, false);
+ }
+ return;
case opt_verbose:
return;
@@ -342,6 +352,7 @@ adcli_tool_computer_join (adcli_conn *conn,
{ "os-version", required_argument, NULL, opt_os_version },
{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
{ "user-principal", optional_argument, NULL, opt_user_principal },
+ { "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
@@ -446,6 +457,7 @@ adcli_tool_computer_update (adcli_conn *conn,
{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
{ "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 },
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
--
2.14.4

View File

@ -0,0 +1,126 @@
From 27c7dde2c0e84c3bb610d1aadb0fd8faff70d3fa Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Fri, 1 Jun 2018 21:26:47 +0200
Subject: [PATCH 17/23] Only update attributes given on the command line
When updating attributes of the LDAP computer object we only want to
update attributes which are related to options given on the command
line. Otherwise a simple call of 'adcli update' to check if the machine
account password needs an update might unexpectedly reset other
attributes as well.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547013
https://bugzilla.redhat.com/show_bug.cgi?id=1545568
https://bugzilla.redhat.com/show_bug.cgi?id=1538730
---
library/adenroll.c | 35 ++++++++++++++++++++++++++++++-----
1 file changed, 30 insertions(+), 5 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index eca3c37..ee845ef 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -99,8 +99,11 @@ struct _adcli_enroll {
int user_princpal_generate;
char *os_name;
+ int os_name_explicit;
char *os_version;
+ int os_version_explicit;
char *os_service_pack;
+ int os_service_pack_explicit;
krb5_kvno kvno;
char *keytab_name;
@@ -113,6 +116,7 @@ struct _adcli_enroll {
int computer_password_lifetime_explicit;
char *samba_data_tool;
bool trusted_for_delegation;
+ int trusted_for_delegation_explicit;
};
static adcli_result
@@ -1212,7 +1216,11 @@ update_computer_account (adcli_enroll *enroll)
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) {
char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
LDAPMod dNSHostName = { LDAP_MOD_REPLACE, "dNSHostName", { vals_dNSHostName, } };
LDAPMod *mods[] = { &dNSHostName, NULL };
@@ -1220,7 +1228,7 @@ update_computer_account (adcli_enroll *enroll)
res |= update_computer_attribute (enroll, ldap, mods);
}
- if (res == ADCLI_SUCCESS) {
+ if (res == ADCLI_SUCCESS && enroll->trusted_for_delegation_explicit) {
char *vals_userAccountControl[] = { NULL , NULL };
LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
LDAPMod *mods[] = { &userAccountControl, NULL };
@@ -1240,12 +1248,25 @@ update_computer_account (adcli_enroll *enroll)
LDAPMod operatingSystemVersion = { LDAP_MOD_REPLACE, "operatingSystemVersion", { vals_operatingSystemVersion, } };
char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
LDAPMod operatingSystemServicePack = { LDAP_MOD_REPLACE, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
- LDAPMod *mods[] = { &operatingSystem, &operatingSystemVersion, &operatingSystemServicePack, NULL };
+ LDAPMod *mods[] = { NULL, NULL, NULL, NULL };
+ size_t c = 0;
- res |= update_computer_attribute (enroll, ldap, mods);
+ if (enroll->os_name_explicit) {
+ mods[c++] = &operatingSystem;
+ }
+ if (enroll->os_version_explicit) {
+ mods[c++] = &operatingSystemVersion;
+ }
+ if (enroll->os_service_pack_explicit) {
+ mods[c++] = &operatingSystemServicePack;
+ }
+
+ if (c != 0) {
+ res |= update_computer_attribute (enroll, ldap, mods);
+ }
}
- if (res == ADCLI_SUCCESS) {
+ if (res == ADCLI_SUCCESS && !enroll->user_princpal_generate) {
char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
LDAPMod userPrincipalName = { LDAP_MOD_REPLACE, "userPrincipalName", { vals_userPrincipalName, }, };
LDAPMod *mods[] = { &userPrincipalName, NULL, };
@@ -2337,6 +2358,7 @@ adcli_enroll_set_os_name (adcli_enroll *enroll,
if (value && value[0] == '\0')
value = NULL;
_adcli_str_set (&enroll->os_name, value);
+ enroll->os_name_explicit = 1;
}
const char *
@@ -2354,6 +2376,7 @@ adcli_enroll_set_os_version (adcli_enroll *enroll,
if (value && value[0] == '\0')
value = NULL;
_adcli_str_set (&enroll->os_version, value);
+ enroll->os_version_explicit = 1;
}
const char *
@@ -2371,6 +2394,7 @@ adcli_enroll_set_os_service_pack (adcli_enroll *enroll,
if (value && value[0] == '\0')
value = NULL;
_adcli_str_set (&enroll->os_service_pack, value);
+ enroll->os_service_pack_explicit = 1;
}
const char *
@@ -2450,4 +2474,5 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
return_if_fail (enroll != NULL);
enroll->trusted_for_delegation = value;
+ enroll->trusted_for_delegation_explicit = 1;
}
--
2.14.4

View File

@ -0,0 +1,387 @@
From 54c3d176326f719ffefded17bb797bc9e6c7f3c0 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 4 Jun 2018 10:49:33 +0200
Subject: [PATCH 18/23] update: allow to add service names
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547013
https://bugzilla.redhat.com/show_bug.cgi?id=1545568
---
library/adenroll.c | 136 +++++++++++++++++++++++++++++++++-------------------
library/adkrb5.c | 113 +++++++++++++++++++++++++++++++++++++++++++
library/adprivate.h | 6 +++
3 files changed, 206 insertions(+), 49 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index ee845ef..6fdc773 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -305,13 +305,37 @@ ensure_service_names (adcli_result res,
}
static adcli_result
-ensure_service_principals (adcli_result res,
- adcli_enroll *enroll)
+add_service_names_to_service_principals (adcli_enroll *enroll)
{
char *name;
int length = 0;
int i;
+ if (enroll->service_principals != NULL) {
+ length = seq_count (enroll->service_principals);
+ }
+
+ for (i = 0; enroll->service_names[i] != NULL; i++) {
+ if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
+ return_unexpected_if_reached ();
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+ name, &length);
+
+ if (enroll->host_fqdn) {
+ if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
+ return_unexpected_if_reached ();
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+ name, &length);
+ }
+ }
+
+ return ADCLI_SUCCESS;
+}
+
+static adcli_result
+ensure_service_principals (adcli_result res,
+ adcli_enroll *enroll)
+{
if (res != ADCLI_SUCCESS)
return res;
@@ -319,20 +343,7 @@ ensure_service_principals (adcli_result res,
if (!enroll->service_principals) {
assert (enroll->service_names != NULL);
-
- for (i = 0; enroll->service_names[i] != NULL; i++) {
- if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
- return_unexpected_if_reached ();
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- name, &length);
-
- if (enroll->host_fqdn) {
- if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
- return_unexpected_if_reached ();
- enroll->service_principals = _adcli_strv_add (enroll->service_principals,
- name, &length);
- }
- }
+ return add_service_names_to_service_principals (enroll);
}
return ADCLI_SUCCESS;
@@ -356,6 +367,7 @@ ensure_keytab_principals (adcli_result res,
return_unexpected_if_fail (k5 != NULL);
enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
+ return_unexpected_if_fail (enroll->keytab_principals != NULL);
at = 0;
/* First add the principal for the computer account name */
@@ -1266,7 +1278,7 @@ update_computer_account (adcli_enroll *enroll)
}
}
- if (res == ADCLI_SUCCESS && !enroll->user_princpal_generate) {
+ if (res == ADCLI_SUCCESS && enroll->user_principal != NULL && !enroll->user_princpal_generate) {
char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
LDAPMod userPrincipalName = { LDAP_MOD_REPLACE, "userPrincipalName", { vals_userPrincipalName, }, };
LDAPMod *mods[] = { &userPrincipalName, NULL, };
@@ -1519,7 +1531,8 @@ add_principal_to_keytab (adcli_enroll *enroll,
krb5_context k5,
krb5_principal principal,
const char *principal_name,
- int *which_salt)
+ int *which_salt,
+ adcli_enroll_flags flags)
{
match_principal_kvno closure;
krb5_data password;
@@ -1547,41 +1560,47 @@ add_principal_to_keytab (adcli_enroll *enroll,
enroll->keytab_name);
}
- password.data = enroll->computer_password;
- password.length = strlen (enroll->computer_password);
-
enctypes = adcli_enroll_get_keytab_enctypes (enroll);
- /*
- * So we need to discover which salt to use. As a side effect we are
- * also testing that our account works.
- */
+ if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
+ code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
+ enroll->kvno, enctypes);
+ } else {
- salts = build_principal_salts (enroll, k5, principal);
- return_unexpected_if_fail (salts != NULL);
+ password.data = enroll->computer_password;
+ password.length = strlen (enroll->computer_password);
- if (*which_salt < 0) {
- code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
- enctypes, salts, which_salt);
- if (code != 0) {
- _adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
- principal_name, krb5_get_error_message (k5, code));
- *which_salt = DEFAULT_SALT;
- } else {
- assert (*which_salt >= 0);
- _adcli_info ("Discovered which keytab salt to use");
+ /*
+ * So we need to discover which salt to use. As a side effect we are
+ * also testing that our account works.
+ */
+
+ salts = build_principal_salts (enroll, k5, principal);
+ return_unexpected_if_fail (salts != NULL);
+
+ if (*which_salt < 0) {
+ code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
+ enctypes, salts, which_salt);
+ if (code != 0) {
+ _adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
+ principal_name, krb5_get_error_message (k5, code));
+ *which_salt = DEFAULT_SALT;
+ } else {
+ assert (*which_salt >= 0);
+ _adcli_info ("Discovered which keytab salt to use");
+ }
}
- }
- code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
- enroll->kvno, &password, enctypes, &salts[*which_salt]);
+ code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
+ enroll->kvno, &password, enctypes, &salts[*which_salt]);
- free_principal_salts (k5, salts);
+ free_principal_salts (k5, salts);
- if (code != 0) {
- _adcli_err ("Couldn't add keytab entries: %s: %s",
- enroll->keytab_name, krb5_get_error_message (k5, code));
- return ADCLI_ERR_FAIL;
+ if (code != 0) {
+ _adcli_err ("Couldn't add keytab entries: %s: %s",
+ enroll->keytab_name, krb5_get_error_message (k5, code));
+ return ADCLI_ERR_FAIL;
+ }
}
@@ -1591,7 +1610,8 @@ add_principal_to_keytab (adcli_enroll *enroll,
}
static adcli_result
-update_keytab_for_principals (adcli_enroll *enroll)
+update_keytab_for_principals (adcli_enroll *enroll,
+ adcli_enroll_flags flags)
{
krb5_context k5;
adcli_result res;
@@ -1608,7 +1628,7 @@ update_keytab_for_principals (adcli_enroll *enroll)
if (krb5_unparse_name (k5, enroll->keytab_principals[i], &name) != 0)
name = "";
res = add_principal_to_keytab (enroll, k5, enroll->keytab_principals[i],
- name, &which_salt);
+ name, &which_salt, flags);
krb5_free_unparsed_name (k5, name);
if (res != ADCLI_SUCCESS)
@@ -1807,6 +1827,20 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
/* We ignore failures of setting these fields */
update_and_calculate_enctypes (enroll);
update_computer_account (enroll);
+
+ /* service_names is only set from input on the command line, so no
+ * additional check for explicit is needed here */
+ if (enroll->service_names != NULL) {
+ res = add_service_names_to_service_principals (enroll);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
+ res = ensure_keytab_principals (res, enroll);
+ if (res != ADCLI_SUCCESS) {
+ return res;
+ }
+ }
+
update_service_principals (enroll);
if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
@@ -1826,7 +1860,7 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
* that we use for salting.
*/
- return update_keytab_for_principals (enroll);
+ return update_keytab_for_principals (enroll, flags);
}
adcli_result
@@ -1927,7 +1961,11 @@ adcli_enroll_update (adcli_enroll *enroll,
if (_adcli_check_nt_time_string_lifetime (value,
adcli_enroll_get_computer_password_lifetime (enroll))) {
- flags |= ADCLI_ENROLL_NO_KEYTAB;
+ /* Do not update keytab if neither new service principals have
+ * to be added nor the user principal has to be changed. */
+ if (enroll->service_names == NULL && (enroll->user_principal == NULL || enroll->user_princpal_generate)) {
+ flags |= ADCLI_ENROLL_NO_KEYTAB;
+ }
flags |= ADCLI_ENROLL_PASSWORD_VALID;
}
free (value);
diff --git a/library/adkrb5.c b/library/adkrb5.c
index b0e903e..033c181 100644
--- a/library/adkrb5.c
+++ b/library/adkrb5.c
@@ -204,6 +204,119 @@ _adcli_krb5_open_keytab (krb5_context k5,
return ADCLI_SUCCESS;
}
+typedef struct {
+ krb5_kvno kvno;
+ krb5_enctype enctype;
+ int matched;
+} match_enctype_kvno;
+
+static krb5_boolean
+match_enctype_and_kvno (krb5_context k5,
+ krb5_keytab_entry *entry,
+ void *data)
+{
+ krb5_boolean similar = FALSE;
+ match_enctype_kvno *closure = data;
+ krb5_error_code code;
+
+ assert (closure->enctype);
+
+ code = krb5_c_enctype_compare (k5, closure->enctype, entry->key.enctype,
+ &similar);
+
+ if (code == 0 && entry->vno == closure->kvno && similar) {
+ closure->matched = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+_adcli_krb5_get_keyblock (krb5_context k5,
+ krb5_keytab keytab,
+ krb5_keyblock *keyblock,
+ krb5_boolean (* match_func) (krb5_context,
+ krb5_keytab_entry *,
+ void *),
+ void *match_data)
+{
+ krb5_kt_cursor cursor;
+ krb5_keytab_entry entry;
+ krb5_error_code code;
+
+ code = krb5_kt_start_seq_get (k5, keytab, &cursor);
+ if (code == KRB5_KT_END || code == ENOENT)
+ return 0;
+ else if (code != 0)
+ return code;
+
+ for (;;) {
+ code = krb5_kt_next_entry (k5, keytab, &entry, &cursor);
+ if (code != 0)
+ break;
+
+ /* See if we should remove this entry */
+ if (!match_func (k5, &entry, match_data)) {
+ krb5_free_keytab_entry_contents (k5, &entry);
+ continue;
+ }
+
+ code = krb5_copy_keyblock_contents (k5, &entry.key, keyblock);
+ krb5_free_keytab_entry_contents (k5, &entry);
+ break;
+
+
+ }
+
+ if (code == KRB5_KT_END)
+ code = 0;
+
+ krb5_kt_end_seq_get (k5, keytab, &cursor);
+ return code;
+}
+
+krb5_error_code
+_adcli_krb5_keytab_copy_entries (krb5_context k5,
+ krb5_keytab keytab,
+ krb5_principal principal,
+ krb5_kvno kvno,
+ krb5_enctype *enctypes)
+{
+ krb5_keytab_entry entry;
+ krb5_error_code code;
+ int i;
+ match_enctype_kvno closure;
+
+ for (i = 0; enctypes[i] != 0; i++) {
+
+ closure.kvno = kvno;
+ closure.enctype = enctypes[i];
+ closure.matched = 0;
+
+ memset (&entry, 0, sizeof (entry));
+
+ code = _adcli_krb5_get_keyblock (k5, keytab, &entry.key,
+ match_enctype_and_kvno, &closure);
+ if (code != 0) {
+ return code;
+ }
+
+
+ entry.principal = principal;
+ entry.vno = kvno;
+
+ code = krb5_kt_add_entry (k5, keytab, &entry);
+
+ entry.principal = NULL;
+ krb5_free_keytab_entry_contents (k5, &entry);
+
+ if (code != 0)
+ return code;
+ }
+
+ return 0;
+}
krb5_error_code
_adcli_krb5_keytab_add_entries (krb5_context k5,
diff --git a/library/adprivate.h b/library/adprivate.h
index 83a88f6..7485249 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -282,6 +282,12 @@ krb5_enctype * _adcli_krb5_parse_enctypes (const char *value);
char * _adcli_krb5_format_enctypes (krb5_enctype *enctypes);
+krb5_error_code _adcli_krb5_keytab_copy_entries (krb5_context k5,
+ krb5_keytab keytab,
+ krb5_principal principal,
+ krb5_kvno kvno,
+ krb5_enctype *enctypes);
+
struct _adcli_attrs {
LDAPMod **mods;
int len;
--
2.14.4

View File

@ -0,0 +1,181 @@
From 9ad1164405e7b4decb7c4ad96fe5ab27d6e53366 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Wed, 6 Jun 2018 16:31:32 +0200
Subject: [PATCH 19/23] Calculate enctypes in a separate function
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1542354
---
library/adenroll.c | 137 +++++++++++++++++++++++++++++++----------------------
1 file changed, 81 insertions(+), 56 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 6fdc773..75ac1e4 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -542,6 +542,83 @@ calculate_computer_account (adcli_enroll *enroll,
return ADCLI_SUCCESS;
}
+static adcli_result
+calculate_enctypes (adcli_enroll *enroll, char **enctype)
+{
+ char *value = NULL;
+ krb5_enctype *read_enctypes;
+ char *new_value = NULL;
+ int is_2008_or_later;
+ LDAP *ldap;
+
+ *enctype = NULL;
+ /*
+ * Because we're using a keytab we want the server to be aware of the
+ * encryption types supported on the client, because we can't dynamically
+ * use a new one that's thrown at us.
+ *
+ * If the encryption types are not explicitly set by the caller of this
+ * library, then see if the account already has some encryption types
+ * marked on it.
+ *
+ * If not, write our default set to the account.
+ *
+ * Note that Windows 2003 and earlier have a standard set of encryption
+ * types, and no msDS-supportedEncryptionTypes attribute.
+ */
+
+ ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ return_unexpected_if_fail (ldap != NULL);
+
+ is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
+
+ /* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
+ if (is_2008_or_later) {
+ value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
+ "msDS-supportedEncryptionTypes");
+
+ if (!enroll->keytab_enctypes_explicit && value != NULL) {
+ read_enctypes = _adcli_krb5_parse_enctypes (value);
+ if (read_enctypes == NULL) {
+ _adcli_warn ("Invalid or unsupported encryption types are set on "
+ "the computer account (%s).", value);
+ } else {
+ free (enroll->keytab_enctypes);
+ enroll->keytab_enctypes = read_enctypes;
+ }
+ }
+
+ /* In 2003 or earlier, standard set of enc types */
+ } else {
+ value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
+ }
+
+ new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll));
+ if (new_value == NULL) {
+ free (value);
+ _adcli_warn ("The encryption types desired are not available in active directory");
+ return ADCLI_ERR_CONFIG;
+ }
+
+ /* If we already have this value, then don't need to update */
+ if (value && strcmp (new_value, value) == 0) {
+ free (value);
+ free (new_value);
+ return ADCLI_SUCCESS;
+ }
+ free (value);
+
+ if (!is_2008_or_later) {
+ free (new_value);
+ _adcli_warn ("Server does not support setting encryption types");
+ return ADCLI_SUCCESS;
+ }
+
+ *enctype = new_value;
+ return ADCLI_SUCCESS;
+}
+
+
static adcli_result
create_computer_account (adcli_enroll *enroll,
LDAP *ldap)
@@ -1053,75 +1130,23 @@ retrieve_computer_account (adcli_enroll *enroll)
static adcli_result
update_and_calculate_enctypes (adcli_enroll *enroll)
{
- char *value = NULL;
- krb5_enctype *read_enctypes;
char *vals_supportedEncryptionTypes[] = { NULL, NULL };
LDAPMod mod = { LDAP_MOD_REPLACE, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
LDAPMod *mods[2] = { &mod, NULL };
- int is_2008_or_later;
char *new_value;
LDAP *ldap;
int ret;
- /*
- * Because we're using a keytab we want the server to be aware of the
- * encryption types supported on the client, because we can't dynamically
- * use a new one that's thrown at us.
- *
- * If the encryption types are not explicitly set by the caller of this
- * library, then see if the account already has some encryption types
- * marked on it.
- *
- * If not, write our default set to the account.
- *
- * Note that Windows 2003 and earlier have a standard set of encryption
- * types, and no msDS-supportedEncryptionTypes attribute.
- */
-
ldap = adcli_conn_get_ldap_connection (enroll->conn);
return_unexpected_if_fail (ldap != NULL);
- is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
-
- /* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
- if (is_2008_or_later) {
- value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
- "msDS-supportedEncryptionTypes");
-
- if (!enroll->keytab_enctypes_explicit && value != NULL) {
- read_enctypes = _adcli_krb5_parse_enctypes (value);
- if (read_enctypes == NULL) {
- _adcli_warn ("Invalid or unsupported encryption types are set on "
- "the computer account (%s).", value);
- } else {
- free (enroll->keytab_enctypes);
- enroll->keytab_enctypes = read_enctypes;
- }
- }
-
- /* In 2003 or earlier, standard set of enc types */
- } else {
- value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
- }
-
- new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll));
- if (new_value == NULL) {
- free (value);
- _adcli_warn ("The encryption types desired are not available in active directory");
- return ADCLI_ERR_CONFIG;
- }
-
- /* If we already have this value, then don't need to update */
- if (value && strcmp (new_value, value) == 0) {
- free (value);
+ ret = calculate_enctypes (enroll, &new_value);
+ if (ret != ADCLI_SUCCESS) {
free (new_value);
- return ADCLI_SUCCESS;
+ return ret;
}
- free (value);
- if (!is_2008_or_later) {
- free (new_value);
- _adcli_warn ("Server does not support setting encryption types");
+ if (new_value == NULL) {
return ADCLI_SUCCESS;
}
--
2.14.4

View File

@ -0,0 +1,110 @@
From cbe33b3e6d0d3415e4642d71942380d1793311f1 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Mon, 11 Jun 2018 09:44:49 +0200
Subject: [PATCH 20/23] join: add all attributes while creating computer object
It is possible to create special accounts which can only join a computer
to a domain but is not allowed to do any further operations which the
computer object. As a result if such an account is used during the join
only the ldapadd operation is permitted but not any later ldapmodify
operation. To create the computer object correctly in this case all
attributes must be added while the object is created and not later.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1542354
---
library/adenroll.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 47 insertions(+), 5 deletions(-)
diff --git a/library/adenroll.c b/library/adenroll.c
index 75ac1e4..b508caf 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -573,7 +573,7 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
/* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
- if (is_2008_or_later) {
+ if (is_2008_or_later && enroll->computer_attributes != NULL) {
value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
"msDS-supportedEncryptionTypes");
@@ -618,7 +618,6 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
return ADCLI_SUCCESS;
}
-
static adcli_result
create_computer_account (adcli_enroll *enroll,
LDAP *ldap)
@@ -628,22 +627,65 @@ create_computer_account (adcli_enroll *enroll,
char *vals_sAMAccountName[] = { enroll->computer_sam, NULL };
LDAPMod sAMAccountName = { LDAP_MOD_ADD, "sAMAccountName", { vals_sAMAccountName, } };
char *vals_userAccountControl[] = { "69632", NULL }; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD */
- LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
+ LDAPMod userAccountControl = { LDAP_MOD_ADD, "userAccountControl", { vals_userAccountControl, } };
+ char *vals_supportedEncryptionTypes[] = { NULL, NULL };
+ LDAPMod encTypes = { LDAP_MOD_ADD, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
+ char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
+ LDAPMod dNSHostName = { LDAP_MOD_ADD, "dNSHostName", { vals_dNSHostName, } };
+ char *vals_operatingSystem[] = { enroll->os_name, NULL };
+ LDAPMod operatingSystem = { LDAP_MOD_ADD, "operatingSystem", { vals_operatingSystem, } };
+ char *vals_operatingSystemVersion[] = { enroll->os_version, NULL };
+ LDAPMod operatingSystemVersion = { LDAP_MOD_ADD, "operatingSystemVersion", { vals_operatingSystemVersion, } };
+ char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
+ LDAPMod operatingSystemServicePack = { LDAP_MOD_ADD, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
+ 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 *val = NULL;
int ret;
+ size_t c;
+ size_t m;
- LDAPMod *mods[] = {
+ LDAPMod *all_mods[] = {
&objectClass,
&sAMAccountName,
&userAccountControl,
- NULL,
+ &encTypes,
+ &dNSHostName,
+ &operatingSystem,
+ &operatingSystemVersion,
+ &operatingSystemServicePack,
+ &userPrincipalName,
+ &servicePrincipalName,
+ NULL
};
+ size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *);
+ LDAPMod *mods[mods_count];
+
if (adcli_enroll_get_trusted_for_delegation (enroll)) {
vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */
}
+ ret = calculate_enctypes (enroll, &val);
+ if (ret != ADCLI_SUCCESS) {
+ return ret;
+ }
+ vals_supportedEncryptionTypes[0] = val;
+
+ m = 0;
+ for (c = 0; c < mods_count - 1; c++) {
+ /* Skip empty LDAP sttributes */
+ if (all_mods[c]->mod_vals.modv_strvals[0] != NULL) {
+ mods[m++] = all_mods[c];
+ }
+ }
+ mods[m] = NULL;
+
ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
+ free (val);
/*
* Hand to head. This is really dumb... AD returns
--
2.14.4

View File

@ -0,0 +1,288 @@
From 4208646609da9b25b70c21f5f39c92fabbd59dfc Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 14 Jun 2018 16:48:22 +0200
Subject: [PATCH 21/23] util: add _adcli_strv_remove_unsorted
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547014
---
library/adprivate.h | 4 ++
library/adutil.c | 21 ++++++++
library/seq.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++---
library/seq.h | 12 +++++
4 files changed, 179 insertions(+), 7 deletions(-)
diff --git a/library/adprivate.h b/library/adprivate.h
index 7485249..bc9df6d 100644
--- a/library/adprivate.h
+++ b/library/adprivate.h
@@ -111,6 +111,10 @@ char ** _adcli_strv_add (char **strv,
char *string,
int *length) GNUC_WARN_UNUSED;
+void _adcli_strv_remove_unsorted (char **strv,
+ const char *string,
+ int *length);
+
void _adcli_strv_free (char **strv);
int _adcli_strv_has (char **strv,
diff --git a/library/adutil.c b/library/adutil.c
index a27bd68..6334b52 100644
--- a/library/adutil.c
+++ b/library/adutil.c
@@ -221,6 +221,27 @@ _adcli_strv_add (char **strv,
return seq_push (strv, length, string);
}
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+
+void
+_adcli_strv_remove_unsorted (char **strv,
+ const char *string,
+ int *length)
+{
+ int len;
+
+ return_if_fail (string != NULL);
+
+ if (!length) {
+ len = seq_count (strv);
+ length = &len;
+ }
+
+ return seq_remove_unsorted (strv, length, discard_const (string),
+ (seq_compar)strcasecmp, free);
+}
+
+
int
_adcli_strv_has (char **strv,
const char *str)
diff --git a/library/seq.c b/library/seq.c
index 627dcaf..8e7475d 100644
--- a/library/seq.c
+++ b/library/seq.c
@@ -111,6 +111,24 @@ seq_push (seq_voidp sequence,
return seq;
}
+static int
+linear_search (void **seq,
+ int low,
+ int high,
+ void *match,
+ seq_compar compar)
+{
+ int at;
+
+ for (at = low; at < high; at++) {
+ if (compar (match, seq[at]) == 0) {
+ break;
+ }
+ }
+
+ return at;
+}
+
static int
binary_search (void **seq,
int low,
@@ -171,12 +189,13 @@ seq_insert (seq_voidp sequence,
return seq;
}
-void
-seq_remove (seq_voidp sequence,
- int *length,
- void *match,
- seq_compar compar,
- seq_destroy destroy)
+static void
+seq_remove_int (seq_voidp sequence,
+ int *length,
+ void *match,
+ seq_search search,
+ seq_compar compar,
+ seq_destroy destroy)
{
void **seq = sequence;
int at;
@@ -187,7 +206,7 @@ seq_remove (seq_voidp sequence,
assert (match != NULL);
len = *length;
- at = binary_search (seq, 0, len, match, compar);
+ at = search (seq, 0, len, match, compar);
/* We have a matching value */
if (at < len && compar (match, seq[at]) == 0) {
@@ -201,6 +220,26 @@ seq_remove (seq_voidp sequence,
*length = len;
}
+void
+seq_remove (seq_voidp sequence,
+ int *length,
+ void *match,
+ seq_compar compar,
+ seq_destroy destroy)
+{
+ return seq_remove_int (sequence, length, match, binary_search, compar, destroy);
+}
+
+void
+seq_remove_unsorted (seq_voidp sequence,
+ int *length,
+ void *match,
+ seq_compar compar,
+ seq_destroy destroy)
+{
+ return seq_remove_int (sequence, length, match, linear_search, compar, destroy);
+}
+
void
seq_filter (seq_voidp sequence,
int *length,
@@ -430,6 +469,99 @@ test_remove (void)
seq_free (seq, NULL);
}
+static void
+test_remove_unsorted (void)
+{
+ void **seq = NULL;
+ int len = 0;
+
+ seq = seq_push (seq, &len, "3");
+ seq = seq_push (seq, &len, "5");
+ seq = seq_push (seq, &len, "1");
+ seq = seq_push (seq, &len, "4");
+ seq = seq_push (seq, &len, "2");
+
+ assert_str_eq (seq[0], "3");
+ assert_str_eq (seq[1], "5");
+ assert_str_eq (seq[2], "1");
+ assert_str_eq (seq[3], "4");
+ assert_str_eq (seq[4], "2");
+ assert (seq[5] == NULL);
+ assert_num_eq (len, 5);
+
+ seq_remove_unsorted (seq, &len, "3", (seq_compar)strcmp, NULL);
+ seq_remove_unsorted (seq, &len, "2", (seq_compar)strcmp, NULL);
+
+ assert_str_eq (seq[0], "5");
+ assert_str_eq (seq[1], "1");
+ assert_str_eq (seq[2], "4");
+ assert (seq[3] == NULL);
+ assert_num_eq (len, 3);
+
+ seq_free (seq, NULL);
+}
+
+static void
+test_remove_first (void)
+{
+ void **seq = NULL;
+ int len = 0;
+
+ seq = seq_insert (seq, &len, "3", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "5", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "1", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "4", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "2", (seq_compar)strcmp, NULL);
+
+ assert_str_eq (seq[0], "1");
+ assert_str_eq (seq[1], "2");
+ assert_str_eq (seq[2], "3");
+ assert_str_eq (seq[3], "4");
+ assert_str_eq (seq[4], "5");
+ assert (seq[5] == NULL);
+ assert_num_eq (len, 5);
+
+ seq_remove (seq, &len, "1", (seq_compar)strcmp, NULL);
+
+ assert_str_eq (seq[0], "2");
+ assert_str_eq (seq[1], "3");
+ assert_str_eq (seq[2], "4");
+ assert_str_eq (seq[3], "5");
+ assert (seq[4] == NULL);
+ assert_num_eq (len, 4);
+
+ seq_free (seq, NULL);
+}
+
+static void
+test_remove_last (void)
+{
+ void **seq = NULL;
+ int len = 0;
+
+ seq = seq_insert (seq, &len, "3", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "1", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "4", (seq_compar)strcmp, NULL);
+ seq = seq_insert (seq, &len, "2", (seq_compar)strcmp, NULL);
+
+ assert_str_eq (seq[0], "1");
+ assert_str_eq (seq[1], "2");
+ assert_str_eq (seq[2], "3");
+ assert_str_eq (seq[3], "4");
+ assert (seq[4] == NULL);
+ assert_num_eq (len, 4);
+
+ seq_remove (seq, &len, "4", (seq_compar)strcmp, NULL);
+
+ assert_str_eq (seq[0], "1");
+ assert_str_eq (seq[1], "2");
+ assert_str_eq (seq[2], "3");
+ assert (seq[3] == NULL);
+ assert_num_eq (len, 3);
+
+ seq_free (seq, NULL);
+}
+
static int
compar_even (void *match,
void *value)
@@ -631,6 +763,9 @@ main (int argc,
test_func (test_insert, "/seq/insert");
test_func (test_insert_destroys, "/seq/insert_destroys");
test_func (test_remove, "/seq/remove");
+ test_func (test_remove_unsorted, "/seq/remove_unsorted");
+ test_func (test_remove_first, "/seq/remove_first");
+ test_func (test_remove_last, "/seq/remove_last");
test_func (test_remove_destroys, "/seq/remove_destroys");
test_func (test_filter, "/seq/filter");
test_func (test_filter_null, "/seq/filter_null");
diff --git a/library/seq.h b/library/seq.h
index 694965b..5d48848 100644
--- a/library/seq.h
+++ b/library/seq.h
@@ -44,6 +44,12 @@ typedef void * (* seq_copy) (void *value);
typedef void (* seq_destroy) (void *value);
+typedef int (* seq_search) (void **seq,
+ int low,
+ int high,
+ void *match,
+ seq_compar compar);
+
seq_voidp seq_push (seq_voidp seq,
int *length,
void *value) WARN_UNUSED;
@@ -62,6 +68,12 @@ void seq_remove (seq_voidp seq,
seq_compar compar,
seq_destroy destroy);
+void seq_remove_unsorted (seq_voidp seq,
+ int *length,
+ void *match,
+ seq_compar compar,
+ seq_destroy destroy);
+
seq_voidp seq_lookup (seq_voidp seq,
int *length,
void *match,
--
2.14.4

View File

@ -0,0 +1,360 @@
From ee71c4c0614a504b4472bf64a24fc3c18c6b9987 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 14 Jun 2018 16:49:26 +0200
Subject: [PATCH 22/23] Add add-service-principal and remove-service-principal
options
Currently it is only possible to specific a service name for service
principals but not to set the full service principal. This is e.g.
needed if there is a service running on a host which should be reachable
by a different DNS name as well.
With this patch service principal can be added and removed by specifying
the full name.
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547014
---
doc/adcli.xml | 21 ++++++++
library/adenroll.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++--
library/adenroll.h | 8 +++
library/adldap.c | 16 ++++--
tools/computer.c | 13 +++++
5 files changed, 189 insertions(+), 8 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index b246190..83b6981 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -290,6 +290,14 @@ Password for Administrator:
not allow that Kerberos tickets can be forwarded to the
host.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--add-service-principal=<parameter>service/hostname</parameter></option></term>
+ <listitem><para>Add a service principal name. In
+ contrast to the <option>--service-name</option> the
+ hostname part can be specified as well in case the
+ service should be accessible with a different host
+ name as well.</para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>--show-details</option></term>
<listitem><para>After a successful join print out information
@@ -416,6 +424,19 @@ $ adcli update --login-ccache=/tmp/krbcc_123
not allow that Kerberos tickets can be forwarded to the
host.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--add-service-principal=<parameter>service/hostname</parameter></option></term>
+ <listitem><para>Add a service principal name. In
+ contrast to the <option>--service-name</option> the
+ hostname part can be specified as well in case the
+ service should be accessible with a different host
+ name as well.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--remove-service-principal=<parameter>service/hostname</parameter></option></term>
+ <listitem><para>Remove a service principal name from
+ the keytab and the AD host object.</para></listitem>
+ </varlistentry>
<varlistentry>
<term><option>--show-details</option></term>
<listitem><para>After a successful join print out information
diff --git a/library/adenroll.c b/library/adenroll.c
index b508caf..c4ba537 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -95,6 +95,9 @@ struct _adcli_enroll {
char **service_principals;
int service_principals_explicit;
+ char **service_principals_to_add;
+ char **service_principals_to_remove;
+
char *user_principal;
int user_princpal_generate;
@@ -332,6 +335,43 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
return ADCLI_SUCCESS;
}
+static adcli_result
+add_and_remove_service_principals (adcli_enroll *enroll)
+{
+ int length = 0;
+ size_t c;
+ const char **list;
+
+ if (enroll->service_principals != NULL) {
+ length = seq_count (enroll->service_principals);
+ }
+
+ list = adcli_enroll_get_service_principals_to_add (enroll);
+ if (list != NULL) {
+ for (c = 0; list[c] != NULL; c++) {
+ enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+ strdup (list[c]),
+ &length);
+ if (enroll->service_principals == NULL) {
+ return ADCLI_ERR_UNEXPECTED;
+ }
+ }
+ }
+
+ list = adcli_enroll_get_service_principals_to_remove (enroll);
+ if (list != NULL) {
+ for (c = 0; list[c] != NULL; c++) {
+ /* enroll->service_principals typically refects the
+ * order of the principal in the keytabm so it is not
+ * ordered. */
+ _adcli_strv_remove_unsorted (enroll->service_principals,
+ list[c], &length);
+ }
+ }
+
+ return ADCLI_SUCCESS;
+}
+
static adcli_result
ensure_service_principals (adcli_result res,
adcli_enroll *enroll)
@@ -343,10 +383,14 @@ ensure_service_principals (adcli_result res,
if (!enroll->service_principals) {
assert (enroll->service_names != NULL);
- return add_service_names_to_service_principals (enroll);
+ res = add_service_names_to_service_principals (enroll);
}
- return ADCLI_SUCCESS;
+ if (res == ADCLI_SUCCESS) {
+ res = add_and_remove_service_principals (enroll);
+ }
+
+ return res;
}
static adcli_result
@@ -1593,6 +1637,39 @@ free_principal_salts (krb5_context k5,
free (salts);
}
+static adcli_result
+remove_principal_from_keytab (adcli_enroll *enroll,
+ krb5_context k5,
+ const char *principal_name)
+{
+ krb5_error_code code;
+ krb5_principal principal;
+ match_principal_kvno closure;
+
+ code = krb5_parse_name (k5, principal_name, &principal);
+ if (code != 0) {
+ _adcli_err ("Couldn't parse principal: %s: %s",
+ principal_name, krb5_get_error_message (k5, code));
+ return ADCLI_ERR_FAIL;
+ }
+
+ closure.kvno = enroll->kvno;
+ closure.principal = principal;
+ closure.matched = 0;
+
+ code = _adcli_krb5_keytab_clear (k5, enroll->keytab,
+ match_principal_and_kvno, &closure);
+ krb5_free_principal (k5, principal);
+
+ if (code != 0) {
+ _adcli_err ("Couldn't update keytab: %s: %s",
+ enroll->keytab_name, krb5_get_error_message (k5, code));
+ return ADCLI_ERR_FAIL;
+ }
+
+ return ADCLI_SUCCESS;
+}
+
static adcli_result
add_principal_to_keytab (adcli_enroll *enroll,
krb5_context k5,
@@ -1702,6 +1779,17 @@ update_keytab_for_principals (adcli_enroll *enroll,
return res;
}
+ if (enroll->service_principals_to_remove != NULL) {
+ for (i = 0; enroll->service_principals_to_remove[i] != NULL; i++) {
+ res = remove_principal_from_keytab (enroll, k5,
+ enroll->service_principals_to_remove[i]);
+ if (res != ADCLI_SUCCESS) {
+ _adcli_warn ("Failed to remove %s from keytab.",
+ enroll->service_principals_to_remove[i]);
+ }
+ }
+ }
+
return ADCLI_SUCCESS;
}
@@ -2029,8 +2117,11 @@ adcli_enroll_update (adcli_enroll *enroll,
if (_adcli_check_nt_time_string_lifetime (value,
adcli_enroll_get_computer_password_lifetime (enroll))) {
/* Do not update keytab if neither new service principals have
- * to be added nor the user principal has to be changed. */
- if (enroll->service_names == NULL && (enroll->user_principal == NULL || enroll->user_princpal_generate)) {
+ * to be added or deleted nor the user principal has to be changed. */
+ if (enroll->service_names == NULL
+ && (enroll->user_principal == NULL || enroll->user_princpal_generate)
+ && enroll->service_principals_to_add == NULL
+ && enroll->service_principals_to_remove == NULL) {
flags |= ADCLI_ENROLL_NO_KEYTAB;
}
flags |= ADCLI_ENROLL_PASSWORD_VALID;
@@ -2581,3 +2672,43 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
enroll->trusted_for_delegation = value;
enroll->trusted_for_delegation_explicit = 1;
}
+
+const char **
+adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll)
+{
+ return_val_if_fail (enroll != NULL, NULL);
+
+ return (const char **)enroll->service_principals_to_add;
+}
+
+void
+adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
+ const char *value)
+{
+ return_if_fail (enroll != NULL);
+ return_if_fail (value != NULL);
+
+ enroll->service_principals_to_add = _adcli_strv_add (enroll->service_principals_to_add,
+ strdup (value), NULL);
+ return_if_fail (enroll->service_principals_to_add != NULL);
+}
+
+const char **
+adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll)
+{
+ return_val_if_fail (enroll != NULL, NULL);
+
+ return (const char **)enroll->service_principals_to_remove;
+}
+
+void
+adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
+ const char *value)
+{
+ return_if_fail (enroll != NULL);
+ return_if_fail (value != NULL);
+
+ enroll->service_principals_to_remove = _adcli_strv_add (enroll->service_principals_to_remove,
+ strdup (value), NULL);
+ return_if_fail (enroll->service_principals_to_remove != NULL);
+}
diff --git a/library/adenroll.h b/library/adenroll.h
index be2ca18..f87dffa 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -98,6 +98,14 @@ const char ** adcli_enroll_get_service_principals (adcli_enroll *enroll);
void adcli_enroll_set_service_principals (adcli_enroll *enroll,
const char **value);
+const char ** adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll);
+void adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
+ const char *value);
+
+const char ** adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll);
+void adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
+ const char *value);
+
const char * adcli_enroll_get_user_principal (adcli_enroll *enroll);
void adcli_enroll_set_user_principal (adcli_enroll *enroll,
diff --git a/library/adldap.c b/library/adldap.c
index 07dc373..d93efb7 100644
--- a/library/adldap.c
+++ b/library/adldap.c
@@ -210,16 +210,24 @@ _adcli_ldap_have_in_mod (LDAPMod *mod,
struct berval *vals;
struct berval **pvals;
int count = 0;
+ int count_have = 0;
int i;
int ret;
- /* Already in berval format, just compare */
- if (mod->mod_op & LDAP_MOD_BVALUES)
- return _adcli_ldap_have_vals (mod->mod_vals.modv_bvals, have);
-
/* Count number of values */
for (i = 0; mod->mod_vals.modv_strvals[i] != 0; i++)
count++;
+ for (i = 0; have[i] != 0; i++)
+ count_have++;
+
+ /* If numbers different something has to be added or removed */
+ if (count != count_have) {
+ return 0;
+ }
+
+ /* Already in berval format, just compare */
+ if (mod->mod_op & LDAP_MOD_BVALUES)
+ return _adcli_ldap_have_vals (mod->mod_vals.modv_bvals, have);
vals = malloc (sizeof (struct berval) * (count + 1));
pvals = malloc (sizeof (struct berval *) * (count + 1));
diff --git a/tools/computer.c b/tools/computer.c
index b905fd1..377d449 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -110,6 +110,8 @@ typedef enum {
opt_add_samba_data,
opt_samba_data_tool,
opt_trusted_for_delegation,
+ opt_add_service_principal,
+ opt_remove_service_principal,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -138,6 +140,8 @@ static adcli_tool_desc common_usages[] = {
{ opt_computer_password_lifetime, "lifetime of the host accounts password in days", },
{ opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n"
"in the userAccountControl attribute", },
+ { opt_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_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"
@@ -289,6 +293,12 @@ parse_option (Option opt,
adcli_enroll_set_trusted_for_delegation (enroll, false);
}
return;
+ case opt_add_service_principal:
+ adcli_enroll_add_service_principal_to_add (enroll, optarg);
+ return;
+ case opt_remove_service_principal:
+ adcli_enroll_add_service_principal_to_remove (enroll, optarg);
+ return;
case opt_verbose:
return;
@@ -353,6 +363,7 @@ adcli_tool_computer_join (adcli_conn *conn,
{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
{ "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 },
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
@@ -458,6 +469,8 @@ adcli_tool_computer_update (adcli_conn *conn,
{ "user-principal", optional_argument, NULL, opt_user_principal },
{ "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime },
{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
+ { "add-service-principal", required_argument, NULL, opt_add_service_principal },
+ { "remove-service-principal", required_argument, NULL, opt_remove_service_principal },
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
--
2.14.4

View File

@ -0,0 +1,32 @@
From 026cfacabfad58ae2cebcdf6cd82d905023ea289 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 31 May 2018 17:01:36 +0200
Subject: [PATCH 23/23] adcli_conn_is_writeable: do not crash id domain_disco
is missing
Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1575554
---
library/adconn.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/library/adconn.c b/library/adconn.c
index d2fb1d5..e2250e3 100644
--- a/library/adconn.c
+++ b/library/adconn.c
@@ -1567,6 +1567,11 @@ adcli_conn_server_has_capability (adcli_conn *conn,
bool adcli_conn_is_writeable (adcli_conn *conn)
{
- disco_dance_if_necessary (conn);
- return ( (conn->domain_disco->flags & ADCLI_DISCO_WRITABLE) != 0);
+ disco_dance_if_necessary (conn);
+
+ if (conn->domain_disco == NULL) {
+ return false;
+ }
+
+ return ( (conn->domain_disco->flags & ADCLI_DISCO_WRITABLE) != 0);
}
--
2.14.4

View File

@ -0,0 +1,203 @@
From 1e57862cf5d8f4f774868b3599e4a34c525ae348 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 5 Jul 2018 13:06:26 +0200
Subject: [PATCH 24/24] doc: fix typos in the adcli man page
Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1440533
---
doc/adcli.xml | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/doc/adcli.xml b/doc/adcli.xml
index 83b6981..97dec08 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -105,19 +105,19 @@
<varlistentry>
<term><option>-D, --domain=<parameter>domain</parameter></option></term>
<listitem><para>The domain to connect to. If a domain is
- not specified then the domain part of the local computer's
+ not specified, then the domain part of the local computer's
host name is used.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-R, --domain-realm=<parameter>REALM</parameter></option></term>
<listitem><para>Kerberos realm for the domain. If not
- specified then the upper cased domain name is
+ specified, then the upper cased domain name is
used.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-S, --domain-controller=<parameter>server</parameter></option></term>
<listitem><para>Connect to a specific domain controller.
- If not specified then an appropriate domain controller
+ If not specified, then an appropriate domain controller
is automatically discovered.</para></listitem>
</varlistentry>
<varlistentry>
@@ -134,7 +134,7 @@
<varlistentry>
<term><option>-U, --login-user=<parameter>User</parameter></option></term>
<listitem><para>Use the specified user account to
- authenticate with the domain. If not specified then
+ authenticate with the domain. If not specified, then
the name 'Administrator' will be used.</para></listitem>
</varlistentry>
<varlistentry>
@@ -181,7 +181,7 @@ $ adcli info --domain-controller=dc.domain.example.com
<para><command>adcli info</command> will output as much information as
it can about the domain. The information is designed to be both machine
and human readable. The command will exit with a non-zero exit code
- if the domain does note exist or cannot be reached.</para>
+ if the domain does not exist or cannot be reached.</para>
<para>To show domain info for a specific domain controller use the
<option>--domain-controller</option> option to specify which domain
@@ -213,35 +213,35 @@ Password for Administrator:
<varlistentry>
<term><option>-N, --computer-name=<parameter>computer</parameter></option></term>
<listitem><para>The short non-dotted name of the computer
- account that will be created in the domain. If not specified
+ account that will be created in the domain. If not specified,
then the first portion of the <option>--host-fqdn</option>
is used.</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 computer account. If not specified
+ which to create the computer account. If not specified,
then the computer 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
- domain name. If not specified the local machine's hostname
+ domain name. If not specified, the local machine's hostname
will be retrieved via <function>gethostname()</function>.</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
host credentials will be written after a successful join
- operation. If not specified the default location will be
+ operation. If not specified, the default location will be
used, usually <filename>/etc/krb5.keytab</filename>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--login-type=<parameter>{computer|user}</parameter></option></term>
<listitem><para>Specify the type of authentication that
will be performed before creating the machine account in
- the domain. If set to 'computer' then the computer must
+ the domain. If set to 'computer', then the computer must
already have a preset account in the domain. If not
specified and none of the other <option>--login-xxx</option>
arguments have been specified, then will try both
@@ -329,7 +329,7 @@ Password for Administrator:
<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
<listitem><para>If Samba's <command>net</command>
cannot be found at
- <filename>&samba_data_tool;</filename> this option can
+ <filename>&samba_data_tool;</filename>, this option can
be used to specific an alternative location with the
help of an absolute path.</para></listitem>
</varlistentry>
@@ -351,7 +351,7 @@ Password for Administrator:
$ adcli update
</programlisting>
- <para>If used with a credential cache other attributes of the computer
+ <para>If used with a credential cache, other attributes of the computer
account can be changed as well if the principal has sufficient
privileges.</para>
@@ -367,20 +367,20 @@ $ adcli update --login-ccache=/tmp/krbcc_123
<varlistentry>
<term><option>-N, --computer-name=<parameter>computer</parameter></option></term>
<listitem><para>The short non-dotted name of the computer
- account that will be created in the domain. If not specified
+ account that will be created in the domain. If not specified,
it will be retrieved from the keytab entries.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-H, --host-fqdn=<parameter>host</parameter></option></term>
<listitem><para>The local machine's fully qualified
- domain name. If not specified the local machine's hostname
+ domain name. If not specified, the local machine's hostname
will be retrieved from the keytab entries.</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
current host credentials are stored and the new ones
- will be written to. If not specified the default
+ will be written to. If not specified, the default
location will be used, usually
<filename>/etc/krb5.keytab</filename>.</para></listitem>
</varlistentry>
@@ -462,7 +462,7 @@ $ adcli update --login-ccache=/tmp/krbcc_123
<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
<listitem><para>If Samba's <command>net</command>
cannot be found at
- <filename>&samba_data_tool;</filename> this option can
+ <filename>&samba_data_tool;</filename>, this option can
be used to specific an alternative location with the
help of an absolute path.</para></listitem>
</varlistentry>
@@ -493,7 +493,7 @@ $ adcli create-user Fry --domain=domain.example.com \
<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 user account. If not specified
+ which to create the user account. If not specified,
then the computer account will be created in a default
location.</para></listitem>
</varlistentry>
@@ -569,7 +569,7 @@ $ adcli create-group Pilots --domain=domain.example.com \
<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 group. If not specified
+ which to create the group. If not specified,
then the group will be created in a default
location.</para></listitem>
</varlistentry>
@@ -649,14 +649,14 @@ Password for Administrator:
<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 computer accounts. If not specified
+ which to create the computer accounts. If not specified,
then the computer account will be created in a default
location.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--one-time-password</option></term>
<listitem><para>Specify a one time password to use when
- presetting the computer accounts. If not specified then
+ presetting the computer accounts. If not specified, then
a default password will be used, which allows for later
automatic joins.</para></listitem>
</varlistentry>
@@ -696,7 +696,7 @@ Password for Administrator:
<title>Reset Computer Account</title>
<para><command>adcli reset-computer</command> resets a computer account
- in the domain. If a the appropriate machine is currently joined to the
+ in the domain. If the appropriate machine is currently joined to the
domain, then its membership will be broken. The account must already
exist.</para>
@@ -716,7 +716,7 @@ $ adcli reset-computer --domain=domain.example.com host2
<term><option>--login-type=<parameter>{computer|user}</parameter></option></term>
<listitem><para>Specify the type of authentication that
will be performed before creating the machine account in
- the domain. If set to 'computer' then the computer must
+ the domain. If set to 'computer', then the computer must
already have a preset account in the domain. If not
specified and none of the other <option>--login-xxx</option>
arguments have been specified, then will try both
--
2.14.4

View File

@ -1,27 +1,169 @@
Name: adcli
Version: 0.9.2
Release: 1%{?dist}
Summary: Active Directory enrollment
License: LGPLv2+
URL: https://gitlab.freedesktop.org/realmd/adcli
Source0: https://gitlab.freedesktop.org/realmd/adcli/uploads/ea560656ac921b3fe0d455976aaae9be/adcli-%{version}.tar.gz
Name: adcli
Version: 0.8.2
Release: 9%{?dist}
Summary: Active Directory enrollment
License: LGPLv2+
URL: http://cgit.freedesktop.org/realmd/adcli
Source0: http://www.freedesktop.org/software/realmd/releases/adcli-%{version}.tar.gz
BuildRequires: gcc
BuildRequires: intltool pkgconfig
BuildRequires: libtool
BuildRequires: gettext-devel
BuildRequires: krb5-devel
BuildRequires: openldap-devel
BuildRequires: libxslt
BuildRequires: xmlto
BuildRequires: make
Patch1: 0001-Remove-upper-case-only-check-when-looking-for-the-Ne.patch
Patch2: 0002-Use-strdup-if-offset-are-used.patch
Patch3: 0003-correct-spelling-of-adcli_tool_computer_delete-descr.patch
Patch4: 0004-doc-explain-that-all-credential-cache-types-are-supp.patch
Patch5: 0005-library-add-adcli_conn_is_writeable.patch
Patch6: 0006-Handle-kvno-increment-for-RODCs.patch
Patch7: 0007-Fix-memory-leak-in-test_check_nt_time_string_lifetim.patch
Patch8: 0008-library-add-_adcli_bin_sid_to_str.patch
Patch9: 0009-library-add-_adcli_call_external_program.patch
Patch10: 0010-library-add-_adcli_ldap_parse_sid.patch
Patch11: 0011-library-add-lookup_domain_sid.patch
Patch12: 0012-library-add-adcli_conn_get_domain_sid.patch
Patch13: 0013-tools-add-option-add-samba-data.patch
Patch14: 0014-tools-store-Samba-data-if-requested.patch
Patch15: 0015-make-Samba-data-tool-configurable.patch
Patch16: 0016-Add-trusted-for-delegation-option.patch
Patch17: 0017-Only-update-attributes-given-on-the-command-line.patch
Patch18: 0018-update-allow-to-add-service-names.patch
Patch19: 0019-Calculate-enctypes-in-a-separate-function.patch
Patch20: 0020-join-add-all-attributes-while-creating-computer-obje.patch
Patch21: 0021-util-add-_adcli_strv_remove_unsorted.patch
Patch22: 0022-Add-add-service-principal-and-remove-service-princip.patch
Patch23: 0023-adcli_conn_is_writeable-do-not-crash-id-domain_disco.patch
Patch24: 0024-doc-fix-typos-in-the-adcli-man-page.patch
Requires: cyrus-sasl-gssapi
Conflicts: adcli-doc < %{version}-%{release}
Patch25: 0001-fix-typo-in-flag-value.patch
Patch26: 0002-_adcli_call_external_program-silence-noisy-debug-mes.patch
Patch27: 0003-Do-not-add-service-principals-twice.patch
Patch28: 0004-Do-not-depend-on-default_realm-in-krb5.conf.patch
# rhbz#1677194 - Realm cannot join domain when hostname is not FQDN
Patch29: 0001-adutil-add-_adcli_strv_add_unique.patch
Patch30: 0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch
# Forward port of RHEL-7.7 ticket rhbz#1642546 - adcli exports kerberos ticket
# with old kvno
Patch31: 0001-Increment-kvno-after-password-change-with-user-creds.patch
# Forward port of RHEL-7.7 ticket rhbz#1595911 - [RFE] Have `adcli join` work
# without FQDN in `hostname` output
Patch32: 0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch
# Forward port of RHEL-7.7 ticket rhbz#1644311 - Improve handling of service
# principals
Patch33: 0001-join-always-add-service-principals.patch
Patch34: 0002-library-return-error-if-no-matching-key-was-found.patch
# Forward port of RHEL-7.7 ticket rhbz#1337489 - [RFE] adcli command with
# --unix-* options doesn't update values in UnixAttributes Tab for user
Patch35: 0001-create-user-add-nis-domain-option.patch
Patch36: 0002-create-user-try-to-find-NIS-domain-if-needed.patch
# Forward port of RHEL-7.7 ticket rhbz#1630187 - [RFE] adcli join should
# preserve SPN added by adcli preset-computer
Patch37: 0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch
Patch38: 0002-library-make-_adcli_strv_has_ex-public.patch
Patch39: 0003-library-_adcli_krb5_build_principal-allow-principals.patch
Patch40: 0004-library-make-sure-server-side-SPNs-are-preserved.patch
# Forward port of RHEL-7.7 ticket rhbz#1622583 - [RFE] Need an option for adcli
# command which will show domain join status.
Patch41: 0001-Implement-adcli-testjoin.patch
# Forward port of RHEL-7.7 ticket rhbz#1630187 - [RFE] adcli join should
# preserve SPN added by adcli preset-computer - additional patch
Patch42: 0001-library-add-missing-strdup.patch
# Forward port of RHEL-7.7 ticket rhbz#1588596 - many adcli-krb5-?????
# directories are created /tmp
Patch43: 0001-tools-remove-errx-from-computer-commands.patch
Patch44: 0002-tools-remove-errx-from-user-and-group-commands.patch
Patch45: 0003-tools-remove-errx-from-info-commands.patch
Patch46: 0004-tools-remove-errx-from-adcli_read_password_func.patch
Patch47: 0005-tools-remove-errx-from-setup_krb5_conf_directory.patch
Patch48: 0006-tools-entry-remove-errx-from-parse_option.patch
Patch49: 0007-tools-computer-remove-errx-from-parse_option.patch
# rhbz#1717355 - `adcli join` fails in FIPS enabled environment
Patch50: 0001-Fix-for-issues-found-by-Coverity.patch
Patch51: 0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch
Patch52: 0002-adconn-add-adcli_conn_set_krb5_context.patch
Patch53: 0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch
Patch54: 0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch
# rhbz#1745931 - adcli update --add-samba-data does not work as expected
Patch55: 0001-doc-explain-how-to-force-password-reset.patch
Patch56: 0001-man-move-note-to-the-right-section.patch
# rhbz#1745932 - Issue is that with arcfour-hmac as first encryption type
Patch57: 0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch
Patch58: 0001-Fix-for-issue-found-by-Coverity.patch
# rhbz#1737342 - [RFE] enhancement adcli to set description attribute and to
# show all AD attributes
Patch59: 0001-tools-add-show-computer-command.patch
Patch60: 0002-add-description-option-to-join-and-update.patch
Patch61: 0001-Use-GSS-SPNEGO-if-available.patch
Patch62: 0002-add-option-use-ldaps.patch
# rhbz#1806260 - [abrt] [faf] adcli: raise(): /usr/sbin/adcli killed by 6
Patch63: 0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch
Patch64: 0001-discovery-fix.patch
# rhbz#1846882 - No longer able to delete computer from AD using adcli
Patch65: 0001-delete-do-not-exit-if-keytab-cannot-be-read.patch
# rhbz#1846878 - adcli: presetting $computer in $domain domain failed: Cannot
# set computer password: Authentication error
Patch66: 0001-tools-disable-SSSD-s-locator-plugin.patch
# rhbz#1791611 - Typo in adcli update --help option
Patch67: 0001-tools-fix-typo-in-show-password-help-output.patch
# rhbz#1791545 - Manpage and help does not explain the use of "-C" option
Patch68: 0001-man-explain-optional-parameter-of-login-ccache-bette.patch
Patch69: 0001-man-make-handling-of-optional-credential-cache-more-.patch
# rhbz#1883467 - Add --use-ldaps option to adcli update as well
Patch70: 0001-tools-add-missing-use-ldaps-option-to-update-and-tes.patch
# rhbz#1734764 - Cannot join a pre-staged Computer Account on AD in Custom OU
# using Delegated user
Patch71: 0001-join-update-set-dNSHostName-if-not-set.patch
# rhbz#1852080 - missing documentation for required AD rights for adcli join
# and net join
Patch72: 0001-doc-add-missing-samba_data_tool_path.xml-.in-to-EXTR.patch
Patch73: 0001-doc-explain-required-AD-permissions.patch
# rhbz#1854112 - [RFE] Add new mode to just create an AD account to be able to
# connect to LDAP
Patch74: 0001-enroll-add-is_service-member.patch
Patch75: 0002-computer-add-create-msa-sub-command.patch
Patch76: 0003-enroll-use-computer-or-service-in-debug-messages.patch
Patch77: 0004-enroll-more-filters-for-random-characters.patch
Patch78: 0005-enroll-make-adcli_enroll_add_keytab_for_service_acco.patch
Patch79: 0006-enroll-allow-fqdn-for-locate_computer_account.patch
Patch80: 0007-service-account-add-random-suffix-to-account-name.patch
# rhbz#1906303 - Typo in CREATE A SERVICE ACCOUNT section of man page of adcli
Patch81: 0001-service-account-fix-typo-in-the-man-page-entry.patch
BuildRequires: gcc
BuildRequires: intltool pkgconfig
BuildRequires: libtool
BuildRequires: gettext-devel
BuildRequires: krb5-devel
BuildRequires: openldap-devel
BuildRequires: libxslt
BuildRequires: xmlto
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
@ -34,11 +176,7 @@ standard LDAP and Kerberos calls.
%build
autoreconf --force --install --verbose
%configure --disable-static --disable-silent-rules \
%if 0%{?rhel}
--with-vendor-error-message='Please check\n https://red.ht/support_rhel_ad \nto get help for common issues.' \
%endif
%{nil}
%configure --disable-static --disable-silent-rules
make %{?_smp_mflags}
%check
@ -48,7 +186,11 @@ make check
make install DESTDIR=%{buildroot}
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%ldconfig_scriptlets
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%clean
%files
%{_sbindir}/adcli
@ -58,7 +200,6 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%package doc
Summary: adcli documentation
BuildArch: noarch
Conflicts: adcli < %{version}-%{release}
%description doc
adcli is a tool for joining an Active Directory domain using
@ -69,22 +210,6 @@ documentation.
%doc %{_datadir}/doc/adcli/*
%changelog
* Fri Oct 21 2022 Sumit Bose <sbose@redhat.com> - 0.9.2-1
- Update to upstream release 0.9.2
Resolves: rhbz#1991619, rhbz#2111348, rhbz#2133838
* Mon Jun 14 2021 Sumit Bose <sbose@redhat.com> - 0.8.2-12
- [RFE] Allow adcli to create AD user with password as well as set or reset
existing user password [#1952828]
- [RFE] add option to populate "managed by" computer attribute [#1690920]
* Thu Jun 03 2021 Sumit Bose <sbose@redhat.com> - 0.8.2-11
- Add missing patch for [#1769644]
* Thu Jun 03 2021 Sumit Bose <sbose@redhat.com> - 0.8.2-10
- [RFE] Adcli and Realm Error Code Optimization Request [#1889386]
- [RFE] adcli should allow to modify DONT_EXPIRE_PASSWORD attribute [#1769644]
* Fri Dec 11 2020 Sumit Bose <sbose@redhat,com> - 0.8.2-9
- Typo in CREATE A SERVICE ACCOUNT section of man page of adcli [#1906303]