allow net ads join accept new osServicePack parameter
[samba.git] / source3 / libnet / libnet_join.c
index 1612d64d54ba9e804a9a8f397577388bb909c93a..c5a61fe73cc049a9ccd6faa2bdfc8744c6fb58d9 100644 (file)
@@ -390,8 +390,10 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
        ADS_STATUS status;
        ADS_MODLIST mods;
        fstring my_fqdn;
-       const char *spn_array[3] = {NULL, NULL, NULL};
+       const char **spn_array = NULL;
+       size_t num_spns = 0;
        char *spn = NULL;
+       bool ok;
 
        /* Find our DN */
 
@@ -400,6 +402,14 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
                return status;
        }
 
+       status = libnet_join_get_machine_spns(mem_ctx,
+                                             r,
+                                             discard_const_p(char **, &spn_array),
+                                             &num_spns);
+       if (!ADS_ERR_OK(status)) {
+               DEBUG(5, ("Retrieving the servicePrincipalNames failed.\n"));
+       }
+
        /* Windows only creates HOST/shortname & HOST/fqdn. */
 
        spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name);
@@ -409,7 +419,15 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
        if (!strupper_m(spn)) {
                return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
        }
-       spn_array[0] = spn;
+
+       ok = ads_element_in_array(spn_array, num_spns, spn);
+       if (!ok) {
+               ok = add_string_to_array(spn_array, spn,
+                                        &spn_array, &num_spns);
+               if (!ok) {
+                       return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+               }
+       }
 
        if (!name_to_fqdn(my_fqdn, r->in.machine_name)
            || (strchr(my_fqdn, '.') == NULL)) {
@@ -426,9 +444,24 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
                if (!spn) {
                        return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
                }
-               spn_array[1] = spn;
+
+               ok = ads_element_in_array(spn_array, num_spns, spn);
+               if (!ok) {
+                       ok = add_string_to_array(spn_array, spn,
+                                                &spn_array, &num_spns);
+                       if (!ok) {
+                               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+                       }
+               }
        }
 
+       /* make sure to NULL terminate the array */
+       spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1);
+       if (spn_array == NULL) {
+               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+       }
+       spn_array[num_spns] = NULL;
+
        mods = ads_init_mods(mem_ctx);
        if (!mods) {
                return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
@@ -541,8 +574,19 @@ static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
                return ADS_ERROR(LDAP_NO_MEMORY);
        }
 
-       os_sp = talloc_asprintf(mem_ctx, "Samba %s", samba_version_string());
-       if (!os_sp) {
+       if (r->in.os_servicepack) {
+               /*
+                * if blank string then leave os_sp equal to NULL to force
+                * attribute delete (LDAP_MOD_DELETE)
+                */
+               if (!strequal(r->in.os_servicepack,"")) {
+                       os_sp = talloc_strdup(mem_ctx, r->in.os_servicepack);
+               }
+       } else {
+               os_sp = talloc_asprintf(mem_ctx, "Samba %s",
+                                       samba_version_string());
+       }
+       if (!os_sp && !strequal(r->in.os_servicepack,"")) {
                return ADS_ERROR(LDAP_NO_MEMORY);
        }
 
@@ -572,6 +616,52 @@ static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
 /****************************************************************
 ****************************************************************/
 
+static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
+                                        struct libnet_JoinCtx *r)
+{
+       ADS_STATUS status;
+       ADS_MODLIST mods;
+       uint32_t etype_list = ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
+       const char *etype_list_str;
+
+#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+       etype_list |= ENC_HMAC_SHA1_96_AES128;
+#endif
+#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+       etype_list |= ENC_HMAC_SHA1_96_AES256;
+#endif
+
+       etype_list_str = talloc_asprintf(mem_ctx, "%d", etype_list);
+       if (!etype_list_str) {
+               return ADS_ERROR(LDAP_NO_MEMORY);
+       }
+
+       /* Find our DN */
+
+       status = libnet_join_find_machine_acct(mem_ctx, r);
+       if (!ADS_ERR_OK(status)) {
+               return status;
+       }
+
+       /* now do the mods */
+
+       mods = ads_init_mods(mem_ctx);
+       if (!mods) {
+               return ADS_ERROR(LDAP_NO_MEMORY);
+       }
+
+       status = ads_mod_str(mem_ctx, &mods, "msDS-SupportedEncryptionTypes",
+                            etype_list_str);
+       if (!ADS_ERR_OK(status)) {
+               return status;
+       }
+
+       return ads_gen_mod(r->in.ads, r->out.dn, mods);
+}
+
+/****************************************************************
+****************************************************************/
+
 static bool libnet_join_create_keytab(TALLOC_CTX *mem_ctx,
                                      struct libnet_JoinCtx *r)
 {
@@ -646,6 +736,7 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
                                                  struct libnet_JoinCtx *r)
 {
        ADS_STATUS status;
+       uint32_t func_level = 0;
 
        if (!r->in.ads) {
                status = libnet_join_connect_ads(mem_ctx, r);
@@ -680,6 +771,24 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
                return status;
        }
 
+       status = ads_domain_func_level(r->in.ads, &func_level);
+       if (!ADS_ERR_OK(status)) {
+               libnet_join_set_error_string(mem_ctx, r,
+                       "failed to query domain controller functional level: %s",
+                       ads_errstr(status));
+               return status;
+       }
+
+       if (func_level >= DS_DOMAIN_FUNCTION_2008) {
+               status = libnet_join_set_etypes(mem_ctx, r);
+               if (!ADS_ERR_OK(status)) {
+                       libnet_join_set_error_string(mem_ctx, r,
+                               "failed to set machine kerberos encryption types: %s",
+                               ads_errstr(status));
+                       return status;
+               }
+       }
+
        if (!libnet_join_derive_salting_principal(mem_ctx, r)) {
                return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
        }
@@ -885,7 +994,7 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
                return status;
        }
 
-       status = rpccli_setup_netlogon_creds(cli,
+       status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
                                             netlogon_creds,
                                             true, /* force_reauth */
                                             current_nt_hash,
@@ -1346,7 +1455,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
                return status;
        }
 
-       status = rpccli_setup_netlogon_creds(cli,
+       status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
                                             netlogon_creds,
                                             true, /* force_reauth */
                                             current_nt_hash,
@@ -1859,10 +1968,6 @@ static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
                return WERR_INVALID_PARAM;
        }
 
-       if (IS_DC) {
-               return WERR_SETUP_DOMAIN_CONTROLLER;
-       }
-
        if (!r->in.admin_domain) {
                char *admin_domain = NULL;
                char *admin_account = NULL;
@@ -2045,7 +2150,9 @@ static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
 
        switch (r->out.domain_is_ad) {
                case false:
-                       valid_security = (lp_security() == SEC_DOMAIN);
+                       valid_security = (lp_security() == SEC_DOMAIN)
+                               || (lp_server_role() == ROLE_DOMAIN_PDC)
+                               || (lp_server_role() == ROLE_DOMAIN_BDC);
                        if (valid_workgroup && valid_security) {
                                /* nothing to be done */
                                return WERR_OK;