import adcli-0.8.2-2.el8

This commit is contained in:
CentOS Sources 2019-05-07 01:17:23 -04:00 committed by Andrew Lukoshko
commit 95ad1e7b0d
31 changed files with 3768 additions and 0 deletions

1
.adcli.metadata Normal file
View File

@ -0,0 +1 @@
f3f9537502eba38a22889fbab6e1100c32175ca2 SOURCES/adcli-0.8.2.tar.gz

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
SOURCES/adcli-0.8.2.tar.gz

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

235
SPECS/adcli.spec Normal file
View File

@ -0,0 +1,235 @@
Name: adcli
Version: 0.8.2
Release: 2%{?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
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
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
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
%description
adcli is a tool for joining an Active Directory domain using
standard LDAP and Kerberos calls.
%define _hardened_build 1
%prep
%setup -q
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch26 -p1
%patch27 -p1
%patch28 -p1
%build
autoreconf --force --install --verbose
%configure --disable-static --disable-silent-rules
make %{?_smp_mflags}
%check
make check
%install
make install DESTDIR=%{buildroot}
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%clean
%files
%{_sbindir}/adcli
%doc AUTHORS COPYING ChangeLog NEWS README
%doc %{_mandir}/*/*
%package doc
Summary: adcli documentation
BuildArch: noarch
%description doc
adcli is a tool for joining an Active Directory domain using
standard LDAP and Kerberos calls. This package contains its
documentation.
%files doc
%doc %{_datadir}/doc/adcli/*
%changelog
* Tue Oct 09 2018 Sumit Bose <sbose@redhat.com> - 0.8.2-2
- Do not add service principals twice and related fixes
- Resolves: rhbz#1631734
* Thu Jul 05 2018 Sumit Bose <sbose@redhat.com> - 0.8.2-1
- Update to upstream release 0.8.2
- various other fixes and improvements from the latest Fedora update
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.8.0-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.8.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.8.0-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.8.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 0.8.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Thu Dec 17 2015 Sumit Bose <sbose@redhat.com> - 0.8.0-1
- Update to upstream release 0.8.0
* Mon Oct 19 2015 Stef Walter <stefw@redhat.com> - 0.7.6-1
- Fix issue with keytab use with sshd
- Resolves: rhbz#1267319
- Put documentation in a subpackage
* Tue Jun 16 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7.5-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Fri Aug 15 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7.5-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7.5-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
* Thu Jan 30 2014 Stef Walter <stefw@redhat.com> - 0.7.5-2
- Fix incorrect ownership of manual page directory
* Fri Sep 13 2013 Stef Walter <stefw@redhat.com> - 0.7.5-1
- Update to upstream point release 0.7.5
- Workaround for discovery via IPv6 address
- Correctly put IPv6 addresses in temporary krb5.conf
* Mon Sep 09 2013 Stef Walter <stefw@redhat.com> - 0.7.4-1
- Update to upstream point release 0.7.4
- Correctly handle truncating long host names
- Try to contact all available addresses for discovery
- Build fixes
* Wed Aug 07 2013 Stef Walter <stefw@redhat.com> - 0.7.3-1
- Update to upstream point release 0.7.3
- Don't try to set encryption types on Windows 2003
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.7.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
* Mon Jul 22 2013 Stef Walter <stefw@redhat.com> - 0.7.2-1
- Update to upstream point release 0.7.2
- Part of fix for bug [#961244]
* Mon Jul 15 2013 Stef Walter <stefw@redhat.com> - 0.7.1-4
- Build with verbose output logging
* Tue Jun 11 2013 Stef Walter <stefw@redhat.com> - 0.7.1-3
- Run 'make check' when building the package
* Mon May 13 2013 Stef Walter <stefw@redhat.com> - 0.7.1-2
- Bump version to get around botched update
* Mon May 13 2013 Stef Walter <stefw@redhat.com> - 0.7.1-1
- Update to upstream 0.7.1 release
- Fix problems with salt discovery [#961399]
* Mon May 06 2013 Stef Walter <stefw@redhat.com> - 0.7-1
- Work around broken krb5 with empty passwords [#960001]
- Fix memory corruption issue [#959999]
- Update to 0.7, fixing various bugs
* Mon Apr 29 2013 Stef Walter <stefw@redhat.com> - 0.6-1
- Update to 0.6, fixing various bugs
* Wed Apr 10 2013 Stef walter <stefw@redhat.com> - 0.5-2
- Add appropriate Obsoletes line for libadcli removal
* Wed Apr 10 2013 Stef Walter <stefw@redhat.com> - 0.5-1
- Update to upstream 0.5 version
- No more libadcli, and thus no adcli-devel
- Many new adcli commands
- Documentation
* Wed Feb 13 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
* Mon Nov 12 2012 Stef Walter <stefw@redhat.com> - 0.4-1
- Update for 0.4 version, fixing various bugs
* Sat Oct 20 2012 Stef Walter <stefw@redhat.com> - 0.3-1
- Update for 0.3 version
* Tue Sep 4 2012 Stef Walter <stefw@redhat.com> - 0.2-1
- Update for 0.2 version
* Wed Aug 15 2012 Stef Walter <stefw@redhat.com> - 0.1-1
- Initial 0.1 package