diff options
author | Andreas Schneider <asn@samba.org> | 2019-08-13 16:34:34 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2019-10-16 12:15:54 +0000 |
commit | 1e38443496098a94f405d2a8c346428d0c378bbd (patch) | |
tree | 9276de144c712f8e4dddfa9c046d97a4605d1904 | |
parent | ac8c51fbb5611d5bd2c34cb5693a32238ef64cac (diff) | |
download | samba-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.h | 4 | ||||
-rw-r--r-- | source3/libads/ldap.c | 118 | ||||
-rw-r--r-- | source3/libnet/libnet_join.c | 23 |
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) && |