s3:libads: Fix creating machine account using LDAP
authorAndreas Schneider <asn@samba.org>
Tue, 13 Aug 2019 14:34:34 +0000 (16:34 +0200)
committerAndreas Schneider <asn@cryptomilk.org>
Wed, 9 Oct 2019 07:06:35 +0000 (07:06 +0000)
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>
source3/libads/ads_proto.h
source3/libads/ldap.c
source3/libnet/libnet_join.c

index 92bb3a22cdb9cafd037ff5d6b0eab913e73338be..495ef5d33253dee8d94da4ed0372d872de03c004 100644 (file)
@@ -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);
index 7c35c6b806a61f1ddc59eb31c30dd06ce216427f..d7f5515a095d653daf62f7b6bbba8115bcaf54f2 100644 (file)
@@ -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);
 
index 3e24ba77dfde7e17ecd83a4b7e1f510338382585..0e7775079bba5e9d14681f9ec75b3e2dc88ec5b3 100644 (file)
@@ -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"));
@@ -2675,12 +2687,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) {
@@ -2694,8 +2705,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) &&