summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Schneider <asn@samba.org>2019-08-13 16:34:34 +0200
committerStefan Metzmacher <metze@samba.org>2019-10-16 12:15:54 +0000
commit1e38443496098a94f405d2a8c346428d0c378bbd (patch)
tree9276de144c712f8e4dddfa9c046d97a4605d1904
parentac8c51fbb5611d5bd2c34cb5693a32238ef64cac (diff)
downloadsamba-1e38443496098a94f405d2a8c346428d0c378bbd.tar.gz
s3:libads: Fix creating machine account using LDAP
This implements the same behaviour as Windows. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884 Pair-Programmed-With: Guenther Deschner <gd@samba.org> Signed-off-by: Guenther Deschner <gd@samba.org> Signed-off-by: Andreas Schneider <asn@samba.org> Reviewed-by: Alexander Bokovoy <ab@samba.org> (cherry picked from commit ce7762935051c862ecdd3e82d93096aac61dd292)
-rw-r--r--source3/libads/ads_proto.h4
-rw-r--r--source3/libads/ldap.c118
-rw-r--r--source3/libnet/libnet_join.c23
3 files changed, 124 insertions, 21 deletions
diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h
index 92bb3a22cdb..495ef5d3325 100644
--- a/source3/libads/ads_proto.h
+++ b/source3/libads/ads_proto.h
@@ -114,8 +114,10 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, const char *machine_
const char **spns);
ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
const char *machine_name,
+ const char *machine_password,
const char *org_unit,
- uint32_t etype_list);
+ uint32_t etype_list,
+ const char *dns_domain_name);
ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name,
const char *org_unit, bool *moved);
int ads_count_replies(ADS_STRUCT *ads, void *res);
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 8fbd97e25e2..81efda0cf30 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -1516,7 +1516,6 @@ ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods,
name, (const void **) vals);
}
-#if 0
/**
* Add a single ber-encoded value to a mod list
* @param ctx An initialized TALLOC_CTX
@@ -1537,7 +1536,6 @@ static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods,
return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES,
name, (const void **) values);
}
-#endif
static void ads_print_error(int ret, LDAP *ld)
{
@@ -2111,8 +2109,10 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads,
ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
const char *machine_name,
+ const char *machine_password,
const char *org_unit,
- uint32_t etype_list)
+ uint32_t etype_list,
+ const char *dns_domain_name)
{
ADS_STATUS ret;
char *samAccountName = NULL;
@@ -2120,13 +2120,23 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
TALLOC_CTX *ctx = NULL;
ADS_MODLIST mods;
char *machine_escaped = NULL;
+ char *dns_hostname = NULL;
char *new_dn = NULL;
- const char *objectClass[] = {"top", "person", "organizationalPerson",
- "user", "computer", NULL};
+ char *utf8_pw = NULL;
+ size_t utf8_pw_len = 0;
+ char *utf16_pw = NULL;
+ size_t utf16_pw_len = 0;
+ struct berval machine_pw_val;
+ bool ok;
+ const char **spn_array = NULL;
+ size_t num_spns = 0;
+ const char *spn_prefix[] = {
+ "HOST",
+ "RestrictedKrbHost",
+ };
+ size_t i;
LDAPMessage *res = NULL;
- uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\
- UF_DONT_EXPIRE_PASSWD |\
- UF_ACCOUNTDISABLE );
+ uint32_t acct_control = UF_WORKSTATION_TRUST_ACCOUNT;
ctx = talloc_init("ads_add_machine_acct");
if (ctx == NULL) {
@@ -2139,10 +2149,9 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
goto done;
}
+ /* Check if the machine account already exists. */
ret = ads_find_machine_acct(ads, &res, machine_escaped);
if (ADS_ERR_OK(ret)) {
- DBG_DEBUG("Host account for %s already exists.\n",
- machine_escaped);
ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS);
ads_msgfree(ads, res);
goto done;
@@ -2155,28 +2164,111 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads,
goto done;
}
+ /* Create machine account */
+
samAccountName = talloc_asprintf(ctx, "%s$", machine_name);
if (samAccountName == NULL) {
ret = ADS_ERROR(LDAP_NO_MEMORY);
goto done;
}
+ dns_hostname = talloc_asprintf(ctx,
+ "%s.%s",
+ machine_name,
+ dns_domain_name);
+ if (dns_hostname == NULL) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ /* Add dns_hostname SPNs */
+ for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) {
+ char *spn = talloc_asprintf(ctx,
+ "%s/%s",
+ spn_prefix[i],
+ dns_hostname);
+ if (spn == NULL) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ ok = add_string_to_array(spn_array,
+ spn,
+ &spn_array,
+ &num_spns);
+ if (!ok) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+ }
+
+ /* Add machine_name SPNs */
+ for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) {
+ char *spn = talloc_asprintf(ctx,
+ "%s/%s",
+ spn_prefix[i],
+ machine_name);
+ if (spn == NULL) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ ok = add_string_to_array(spn_array,
+ spn,
+ &spn_array,
+ &num_spns);
+ if (!ok) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+ }
+
+ /* Make sure to NULL terminate the array */
+ spn_array = talloc_realloc(ctx, spn_array, const char *, num_spns + 1);
+ if (spn_array == NULL) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+ spn_array[num_spns] = NULL;
+
controlstr = talloc_asprintf(ctx, "%u", acct_control);
if (controlstr == NULL) {
ret = ADS_ERROR(LDAP_NO_MEMORY);
goto done;
}
+ utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password);
+ if (utf8_pw == NULL) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+ utf8_pw_len = strlen(utf8_pw);
+
+ ok = convert_string_talloc(ctx,
+ CH_UTF8, CH_UTF16MUNGED,
+ utf8_pw, utf8_pw_len,
+ (void *)&utf16_pw, &utf16_pw_len);
+ if (!ok) {
+ ret = ADS_ERROR(LDAP_NO_MEMORY);
+ goto done;
+ }
+
+ machine_pw_val = (struct berval) {
+ .bv_val = utf16_pw,
+ .bv_len = utf16_pw_len,
+ };
+
mods = ads_init_mods(ctx);
if (mods == NULL) {
ret = ADS_ERROR(LDAP_NO_MEMORY);
goto done;
}
- ads_mod_str(ctx, &mods, "cn", machine_name);
- ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName);
- ads_mod_strlist(ctx, &mods, "objectClass", objectClass);
+ ads_mod_str(ctx, &mods, "objectClass", "Computer");
+ ads_mod_str(ctx, &mods, "SamAccountName", samAccountName);
ads_mod_str(ctx, &mods, "userAccountControl", controlstr);
+ ads_mod_str(ctx, &mods, "DnsHostName", dns_hostname);
+ ads_mod_strlist(ctx, &mods, "ServicePrincipalName", spn_array);
+ ads_mod_ber(ctx, &mods, "unicodePwd", &machine_pw_val);
ret = ads_gen_add(ads, new_dn, mods);
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index a512afc238a..d5c8599beee 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -338,10 +338,22 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
/* Attempt to create the machine account and bail if this fails.
Assume that the admin wants exactly what they requested */
+ if (r->in.machine_password == NULL) {
+ r->in.machine_password =
+ trust_pw_new_value(mem_ctx,
+ r->in.secure_channel_type,
+ SEC_ADS);
+ if (r->in.machine_password == NULL) {
+ return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+ }
+ }
+
status = ads_create_machine_acct(r->in.ads,
r->in.machine_name,
+ r->in.machine_password,
r->in.account_ou,
- r->in.desired_encryption_types);
+ r->in.desired_encryption_types,
+ r->out.dns_domain_name);
if (ADS_ERR_OK(status)) {
DEBUG(1,("machine account creation created\n"));
@@ -2668,12 +2680,11 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
if (ADS_ERR_OK(ads_status)) {
/*
- * LDAP object create succeeded, now go to the rpc
- * password set routines
+ * LDAP object creation succeeded.
*/
-
r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE;
- goto rpc_join;
+
+ return WERR_OK;
}
if (initial_account_ou != NULL) {
@@ -2687,8 +2698,6 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
DBG_INFO("Failed to pre-create account in OU %s: %s\n",
r->in.account_ou, ads_errstr(ads_status));
}
- rpc_join:
-
#endif /* HAVE_ADS */
if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&