libnet_join: fix "net rpc oldjoin"
[nivanova/samba-autobuild/.git] / source3 / libnet / libnet_join.c
index 6b9be5e153d753e37999b29019c83abfa610f2f1..0595cfe64abca60167e2f30c590ec681c271ca28 100644 (file)
 /****************************************************************
 ****************************************************************/
 
+static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
+                                        struct libnet_JoinCtx *r,
+                                        const char *format, ...)
+                                        PRINTF_ATTRIBUTE(3,4);
+
 static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
                                         struct libnet_JoinCtx *r,
                                         const char *format, ...)
@@ -94,6 +99,11 @@ static void libnet_join_set_error_string(TALLOC_CTX *mem_ctx,
 /****************************************************************
 ****************************************************************/
 
+static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
+                                          struct libnet_UnjoinCtx *r,
+                                          const char *format, ...)
+                                          PRINTF_ATTRIBUTE(3,4);
+
 static void libnet_unjoin_set_error_string(TALLOC_CTX *mem_ctx,
                                           struct libnet_UnjoinCtx *r,
                                           const char *format, ...)
@@ -185,16 +195,11 @@ static ADS_STATUS libnet_join_connect_ads(TALLOC_CTX *mem_ctx,
                    r->in.machine_password == NULL) {
                        return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                }
-               username = talloc_strdup(mem_ctx, r->in.machine_name);
+               username = talloc_asprintf(mem_ctx, "%s$",
+                                          r->in.machine_name);
                if (username == NULL) {
                        return ADS_ERROR(LDAP_NO_MEMORY);
                }
-               if (username[strlen(username)] != '$') {
-                       username = talloc_asprintf(username, "%s$", username);
-                       if (username == NULL) {
-                               return ADS_ERROR(LDAP_NO_MEMORY);
-                       }
-               }
                password = r->in.machine_password;
                ccname = "MEMORY:libnet_join_machine_creds";
        } else {
@@ -253,13 +258,13 @@ static ADS_STATUS libnet_join_connect_ads_user(TALLOC_CTX *mem_ctx,
 
 /****************************************************************
 ****************************************************************/
-#if 0
+
 static ADS_STATUS libnet_join_connect_ads_machine(TALLOC_CTX *mem_ctx,
                                                  struct libnet_JoinCtx *r)
 {
        return libnet_join_connect_ads(mem_ctx, r, true);
 }
-#endif
+
 /****************************************************************
 ****************************************************************/
 
@@ -318,7 +323,8 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx,
 
        status = ads_create_machine_acct(r->in.ads,
                                         r->in.machine_name,
-                                        r->in.account_ou);
+                                        r->in.account_ou,
+                                        r->in.desired_encryption_types);
 
        if (ADS_ERR_OK(status)) {
                DEBUG(1,("machine account creation created\n"));
@@ -416,6 +422,11 @@ static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx,
                goto done;
        }
 
+       if (!ads_pull_uint32(r->in.ads, res, "msDS-SupportedEncryptionTypes",
+                            &r->out.set_encryption_types)) {
+               r->out.set_encryption_types = 0;
+       }
+
  done:
        ads_msgfree(r->in.ads, res);
        TALLOC_FREE(dn);
@@ -457,6 +468,7 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
        size_t num_spns = 0;
        char *spn = NULL;
        bool ok;
+       const char **netbios_aliases = NULL;
 
        /* Find our DN */
 
@@ -518,6 +530,65 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx,
                }
        }
 
+       netbios_aliases = lp_netbios_aliases();
+       if (netbios_aliases != NULL) {
+               for (; *netbios_aliases != NULL; netbios_aliases++) {
+                       /*
+                        * Add HOST/NETBIOSNAME
+                        */
+                       spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases);
+                       if (spn == NULL) {
+                               TALLOC_FREE(spn);
+                               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+                       }
+                       if (!strupper_m(spn)) {
+                               TALLOC_FREE(spn);
+                               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+                       }
+
+                       ok = ads_element_in_array(spn_array, num_spns, spn);
+                       if (ok) {
+                               TALLOC_FREE(spn);
+                               continue;
+                       }
+                       ok = add_string_to_array(spn_array, spn,
+                                                &spn_array, &num_spns);
+                       if (!ok) {
+                               TALLOC_FREE(spn);
+                               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+                       }
+                       TALLOC_FREE(spn);
+
+                       /*
+                        * Add HOST/netbiosname.domainname
+                        */
+                       if (r->out.dns_domain_name == NULL) {
+                               continue;
+                       }
+                       fstr_sprintf(my_fqdn, "%s.%s",
+                                    *netbios_aliases,
+                                    r->out.dns_domain_name);
+
+                       spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn);
+                       if (spn == NULL) {
+                               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+                       }
+
+                       ok = ads_element_in_array(spn_array, num_spns, spn);
+                       if (ok) {
+                               TALLOC_FREE(spn);
+                               continue;
+                       }
+                       ok = add_string_to_array(spn_array, spn,
+                                                &spn_array, &num_spns);
+                       if (!ok) {
+                               TALLOC_FREE(spn);
+                               return ADS_ERROR_LDAP(LDAP_NO_MEMORY);
+                       }
+                       TALLOC_FREE(spn);
+               }
+       }
+
        /* make sure to NULL terminate the array */
        spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1);
        if (spn_array == NULL) {
@@ -678,23 +749,16 @@ static ADS_STATUS libnet_join_set_os_attributes(TALLOC_CTX *mem_ctx,
 
 /****************************************************************
 ****************************************************************/
-#if 0
+
 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);
+       etype_list_str = talloc_asprintf(mem_ctx, "%d",
+                                        r->in.desired_encryption_types);
        if (!etype_list_str) {
                return ADS_ERROR(LDAP_NO_MEMORY);
        }
@@ -706,6 +770,10 @@ static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
                return status;
        }
 
+       if (r->in.desired_encryption_types == r->out.set_encryption_types) {
+               return ADS_SUCCESS;
+       }
+
        /* now do the mods */
 
        mods = ads_init_mods(mem_ctx);
@@ -719,9 +787,16 @@ static ADS_STATUS libnet_join_set_etypes(TALLOC_CTX *mem_ctx,
                return status;
        }
 
-       return ads_gen_mod(r->in.ads, r->out.dn, mods);
+       status = ads_gen_mod(r->in.ads, r->out.dn, mods);
+       if (!ADS_ERR_OK(status)) {
+               return status;
+       }
+
+       r->out.set_encryption_types = r->in.desired_encryption_types;
+
+       return ADS_SUCCESS;
 }
-#endif
+
 /****************************************************************
 ****************************************************************/
 
@@ -789,16 +864,18 @@ static bool libnet_join_derive_salting_principal(TALLOC_CTX *mem_ctx,
                }
        }
 
-       return kerberos_secrets_store_des_salt(salt);
+       r->out.krb5_salt = salt;
+       return true;
 }
 
 /****************************************************************
 ****************************************************************/
 
-static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
-                                                 struct libnet_JoinCtx *r)
+static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx,
+                                                        struct libnet_JoinCtx *r)
 {
        ADS_STATUS status;
+       bool need_etype_update = false;
 
        if (!r->in.ads) {
                status = libnet_join_connect_ads_user(mem_ctx, r);
@@ -833,10 +910,66 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
                return status;
        }
 
+       status = libnet_join_find_machine_acct(mem_ctx, r);
+       if (!ADS_ERR_OK(status)) {
+               return status;
+       }
+
+       if (r->in.desired_encryption_types != r->out.set_encryption_types) {
+               uint32_t func_level = 0;
+
+               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) {
+                       need_etype_update = true;
+               }
+       }
+
+       if (need_etype_update) {
+               /*
+                * We need to reconnect as machine account in order
+                * to update msDS-SupportedEncryptionTypes reliable
+                */
+
+               if (r->in.ads->auth.ccache_name != NULL) {
+                       ads_kdestroy(r->in.ads->auth.ccache_name);
+               }
+
+               ads_destroy(&r->in.ads);
+
+               status = libnet_join_connect_ads_machine(mem_ctx, r);
+               if (!ADS_ERR_OK(status)) {
+                       libnet_join_set_error_string(mem_ctx, r,
+                               "Failed to connect as machine account: %s",
+                               ads_errstr(status));
+                       return status;
+               }
+
+               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);
        }
 
+       return ADS_SUCCESS;
+}
+
+static ADS_STATUS libnet_join_post_processing_ads_sync(TALLOC_CTX *mem_ctx,
+                                                       struct libnet_JoinCtx *r)
+{
        if (!libnet_join_create_keytab(mem_ctx, r)) {
                libnet_join_set_error_string(mem_ctx, r,
                        "failed to create kerberos keytab");
@@ -854,18 +987,12 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
 static bool libnet_join_joindomain_store_secrets(TALLOC_CTX *mem_ctx,
                                                 struct libnet_JoinCtx *r)
 {
-       if (!secrets_store_domain_sid(r->out.netbios_domain_name,
-                                     r->out.domain_sid))
-       {
-               DEBUG(1,("Failed to save domain sid\n"));
-               return false;
-       }
+       NTSTATUS status;
 
-       if (!secrets_store_machine_password(r->in.machine_password,
-                                           r->out.netbios_domain_name,
-                                           r->in.secure_channel_type))
-       {
-               DEBUG(1,("Failed to save machine password\n"));
+       status = secrets_store_JoinCtx(r);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("secrets_store_JoinCtx() failed %s\n",
+                       nt_errstr(status));
                return false;
        }
 
@@ -901,7 +1028,7 @@ static NTSTATUS libnet_join_connect_dc_ipc(const char *dc,
                                   domain,
                                   pass,
                                   flags,
-                                  SMB_SIGNING_DEFAULT);
+                                  SMB_SIGNING_IPC_DEFAULT);
 }
 
 /****************************************************************
@@ -917,12 +1044,23 @@ static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
        NTSTATUS status, result;
        union lsa_PolicyInformation *info = NULL;
        struct dcerpc_binding_handle *b;
+       const char *account = r->in.admin_account;
+       const char *domain = r->in.admin_domain;
+       const char *password = r->in.admin_password;
+       bool use_kerberos = r->in.use_kerberos;
+
+       if (r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) {
+               account = "";
+               domain = "";
+               password = NULL;
+               use_kerberos = false;
+       }
 
        status = libnet_join_connect_dc_ipc(r->in.dc_name,
-                                           r->in.admin_account,
-                                           r->in.admin_domain,
-                                           r->in.admin_password,
-                                           r->in.use_kerberos,
+                                           account,
+                                           domain,
+                                           password,
+                                           use_kerberos,
                                            cli);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
@@ -954,6 +1092,7 @@ static NTSTATUS libnet_join_lookup_dc_rpc(TALLOC_CTX *mem_ctx,
                r->out.netbios_domain_name = info->dns.name.string;
                r->out.dns_domain_name = info->dns.dns_domain.string;
                r->out.forest_name = info->dns.dns_forest.string;
+               r->out.domain_guid = info->dns.domain_guid;
                r->out.domain_sid = dom_sid_dup(mem_ctx, info->dns.sid);
                NT_STATUS_HAVE_NO_MEMORY(r->out.domain_sid);
        }
@@ -993,64 +1132,110 @@ static NTSTATUS libnet_join_joindomain_rpc_unsecure(TALLOC_CTX *mem_ctx,
                                                    struct cli_state *cli)
 {
        TALLOC_CTX *frame = talloc_stackframe();
-       struct rpc_pipe_client *netlogon_pipe = NULL;
+       struct rpc_pipe_client *authenticate_pipe = NULL;
+       struct rpc_pipe_client *passwordset_pipe = NULL;
+       struct cli_credentials *cli_creds;
        struct netlogon_creds_cli_context *netlogon_creds = NULL;
-       struct samr_Password current_nt_hash;
-       const char *account_name = NULL;
+       struct netlogon_creds_CredentialState *creds = NULL;
+       uint32_t netlogon_flags = 0;
+       size_t len = 0;
+       bool ok;
+       DATA_BLOB new_trust_blob = data_blob_null;
        NTSTATUS status;
 
        status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon,
-                                         &netlogon_pipe);
+                                         &authenticate_pipe);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frame);
                return status;
        }
 
        if (!r->in.machine_password) {
-               r->in.machine_password = generate_random_password(mem_ctx,
-                               DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
-                               DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+               int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
+
+               r->in.machine_password = trust_pw_new_value(mem_ctx,
+                                               r->in.secure_channel_type,
+                                               security);
                if (r->in.machine_password == NULL) {
                        TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
        }
 
+       cli_creds = cli_credentials_init(talloc_tos());
+       if (cli_creds == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       cli_credentials_set_username(cli_creds, r->out.account_name,
+                                    CRED_SPECIFIED);
+       cli_credentials_set_domain(cli_creds, r->in.domain_name,
+                                  CRED_SPECIFIED);
+       cli_credentials_set_realm(cli_creds, "", CRED_SPECIFIED);
+       cli_credentials_set_secure_channel_type(cli_creds,
+                                               r->in.secure_channel_type);
+
        /* according to WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED */
-       E_md4hash(r->in.admin_password, current_nt_hash.hash);
+       cli_credentials_set_password(cli_creds, r->in.admin_password,
+                                    CRED_SPECIFIED);
 
-       account_name = talloc_asprintf(frame, "%s$",
-                                      r->in.machine_name);
-       if (account_name == NULL) {
+       status = rpccli_create_netlogon_creds_ctx(
+               cli_creds, authenticate_pipe->desthost, r->in.msg_ctx,
+               frame, &netlogon_creds);
+       if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frame);
-               return NT_STATUS_NO_MEMORY;
+               return status;
        }
 
-       status = rpccli_create_netlogon_creds(netlogon_pipe->desthost,
-                                             r->in.domain_name,
-                                             account_name,
-                                             r->in.secure_channel_type,
-                                             r->in.msg_ctx,
-                                             frame,
-                                             &netlogon_creds);
+       status = rpccli_setup_netlogon_creds(
+               cli, NCACN_NP, netlogon_creds, true /* force_reauth */,
+               cli_creds);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frame);
                return status;
        }
 
-       status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
-                                            netlogon_creds,
-                                            true, /* force_reauth */
-                                            current_nt_hash,
-                                            NULL); /* previous_nt_hash */
+       status = netlogon_creds_cli_get(netlogon_creds, frame, &creds);
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frame);
                return status;
        }
 
+       netlogon_flags = creds->negotiate_flags;
+       TALLOC_FREE(creds);
+
+       if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
+               status = cli_rpc_pipe_open_schannel_with_creds(cli,
+                                                              &ndr_table_netlogon,
+                                                              NCACN_NP,
+                                                              netlogon_creds,
+                                                              &passwordset_pipe);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(frame);
+                       return status;
+               }
+       } else {
+               passwordset_pipe = authenticate_pipe;
+       }
+
+       len = strlen(r->in.machine_password);
+       ok = convert_string_talloc(frame, CH_UNIX, CH_UTF16,
+                                  r->in.machine_password, len,
+                                  (void **)&new_trust_blob.data,
+                                  &new_trust_blob.length);
+       if (!ok) {
+               status = NT_STATUS_UNMAPPABLE_CHARACTER;
+               if (errno == ENOMEM) {
+                       status = NT_STATUS_NO_MEMORY;
+               }
+               TALLOC_FREE(frame);
+               return status;
+       }
+
        status = netlogon_creds_cli_ServerPasswordSet(netlogon_creds,
-                                                     netlogon_pipe->binding_handle,
-                                                     r->in.machine_password,
+                                                     passwordset_pipe->binding_handle,
+                                                     &new_trust_blob,
                                                      NULL); /* new_version */
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(frame);
@@ -1102,9 +1287,11 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
        }
 
        if (!r->in.machine_password) {
-               r->in.machine_password = generate_random_password(mem_ctx,
-                               DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH,
-                               DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
+               int security = r->in.ads ? SEC_ADS : SEC_DOMAIN;
+
+               r->in.machine_password = trust_pw_new_value(mem_ctx,
+                                               r->in.secure_channel_type,
+                                               security);
                NT_STATUS_HAVE_NO_MEMORY(r->in.machine_password);
        }
 
@@ -1282,11 +1469,11 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
        ZERO_STRUCT(user_info.info16);
        user_info.info16.acct_flags = acct_flags;
 
-       status = dcerpc_samr_SetUserInfo(b, mem_ctx,
-                                        &user_pol,
-                                        16,
-                                        &user_info,
-                                        &result);
+       status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
+                                         &user_pol,
+                                         UserControlInformation,
+                                         &user_info,
+                                         &result);
        if (!NT_STATUS_IS_OK(status)) {
                dcerpc_samr_DeleteUser(b, mem_ctx,
                                       &user_pol,
@@ -1328,7 +1515,7 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
 
        status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
                                          &user_pol,
-                                         26,
+                                         UserInternal5InformationNew,
                                          &user_info,
                                          &result);
 
@@ -1345,7 +1532,7 @@ static NTSTATUS libnet_join_joindomain_rpc(TALLOC_CTX *mem_ctx,
 
                status = dcerpc_samr_SetUserInfo2(b, mem_ctx,
                                                  &user_pol,
-                                                 24,
+                                                 UserInternal5Information,
                                                  &user_info,
                                                  &result);
        }
@@ -1415,9 +1602,6 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
        struct netlogon_creds_CredentialState *creds = NULL;
        uint32_t netlogon_flags = 0;
        NTSTATUS status;
-       const char *machine_account = NULL;
-       const char *machine_domain = NULL;
-       const char *machine_password = NULL;
        int flags = 0;
 
        if (!dc_name) {
@@ -1441,22 +1625,17 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
        cli_credentials_set_old_password(cli_creds, NULL, CRED_SPECIFIED);
 
        if (use_kerberos) {
-               flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+               cli_credentials_set_kerberos_state(cli_creds,
+                               CRED_MUST_USE_KERBEROS);
        }
 
-       machine_account = cli_credentials_get_username(cli_creds);
-       machine_domain = cli_credentials_get_domain(cli_creds);
-       machine_password = cli_credentials_get_password(cli_creds);
-
-       status = cli_full_connection(&cli, NULL,
-                                    dc_name,
-                                    NULL, 0,
-                                    "IPC$", "IPC",
-                                    machine_account,
-                                    machine_domain,
-                                    machine_password,
-                                    flags,
-                                    SMB_SIGNING_DEFAULT);
+       status = cli_full_connection_creds(&cli, NULL,
+                                          dc_name,
+                                          NULL, 0,
+                                          "IPC$", "IPC",
+                                          cli_creds,
+                                          flags,
+                                          SMB_SIGNING_IPC_DEFAULT);
 
        if (!NT_STATUS_IS_OK(status)) {
                status = cli_full_connection(&cli, NULL,
@@ -1467,7 +1646,7 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
                                             NULL,
                                             "",
                                             0,
-                                            SMB_SIGNING_DEFAULT);
+                                            SMB_SIGNING_IPC_DEFAULT);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -1475,21 +1654,21 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
                return status;
        }
 
-       status = rpccli_create_netlogon_creds_with_creds(cli_creds,
-                                                        dc_name,
-                                                        msg_ctx,
-                                                        frame,
-                                                        &netlogon_creds);
+       status = rpccli_create_netlogon_creds_ctx(cli_creds,
+                                                 dc_name,
+                                                 msg_ctx,
+                                                 frame,
+                                                 &netlogon_creds);
        if (!NT_STATUS_IS_OK(status)) {
                cli_shutdown(cli);
                TALLOC_FREE(frame);
                return status;
        }
 
-       status = rpccli_setup_netlogon_creds_with_creds(cli, NCACN_NP,
-                                                       netlogon_creds,
-                                                       true, /* force_reauth */
-                                                       cli_creds);
+       status = rpccli_setup_netlogon_creds(cli, NCACN_NP,
+                                            netlogon_creds,
+                                            true, /* force_reauth */
+                                            cli_creds);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("connect_to_domain_password_server: "
                         "unable to open the domain client session to "
@@ -1520,7 +1699,6 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
 
        status = cli_rpc_pipe_open_schannel_with_creds(
                cli, &ndr_table_netlogon, NCACN_NP,
-               cli_creds,
                netlogon_creds, &netlogon_pipe);
 
        TALLOC_FREE(netlogon_pipe);
@@ -1557,7 +1735,7 @@ static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
                libnet_join_set_error_string(mem_ctx, r,
                        "failed to verify domain membership after joining: %s",
                        get_friendly_nt_error_msg(status));
-               return WERR_SETUP_NOT_JOINED;
+               return WERR_NERR_SETUPNOTJOINED;
        }
 
        return WERR_OK;
@@ -1569,15 +1747,10 @@ static WERROR libnet_join_post_verify(TALLOC_CTX *mem_ctx,
 static bool libnet_join_unjoindomain_remove_secrets(TALLOC_CTX *mem_ctx,
                                                    struct libnet_UnjoinCtx *r)
 {
-       if (!secrets_delete_machine_password_ex(lp_workgroup())) {
-               return false;
-       }
-
-       if (!secrets_delete_domain_sid(lp_workgroup())) {
-               return false;
-       }
-
-       return true;
+       /*
+        * TODO: use values from 'struct libnet_UnjoinCtx' ?
+        */
+       return secrets_delete_machine_password_ex(lp_workgroup(), lp_realm());
 }
 
 /****************************************************************
@@ -1777,7 +1950,7 @@ static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
 
        err = smbconf_init_reg(r, &ctx, NULL);
        if (!SBC_ERROR_IS_OK(err)) {
-               werr = WERR_NO_SUCH_SERVICE;
+               werr = WERR_SERVICE_DOES_NOT_EXIST;
                goto done;
        }
 
@@ -1785,14 +1958,14 @@ static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
 
                err = smbconf_set_global_parameter(ctx, "security", "user");
                if (!SBC_ERROR_IS_OK(err)) {
-                       werr = WERR_NO_SUCH_SERVICE;
+                       werr = WERR_SERVICE_DOES_NOT_EXIST;
                        goto done;
                }
 
                err = smbconf_set_global_parameter(ctx, "workgroup",
                                                   r->in.domain_name);
                if (!SBC_ERROR_IS_OK(err)) {
-                       werr = WERR_NO_SUCH_SERVICE;
+                       werr = WERR_SERVICE_DOES_NOT_EXIST;
                        goto done;
                }
 
@@ -1802,28 +1975,28 @@ static WERROR do_join_modify_vals_config(struct libnet_JoinCtx *r)
 
        err = smbconf_set_global_parameter(ctx, "security", "domain");
        if (!SBC_ERROR_IS_OK(err)) {
-               werr = WERR_NO_SUCH_SERVICE;
+               werr = WERR_SERVICE_DOES_NOT_EXIST;
                goto done;
        }
 
        err = smbconf_set_global_parameter(ctx, "workgroup",
                                           r->out.netbios_domain_name);
        if (!SBC_ERROR_IS_OK(err)) {
-               werr = WERR_NO_SUCH_SERVICE;
+               werr = WERR_SERVICE_DOES_NOT_EXIST;
                goto done;
        }
 
        if (r->out.domain_is_ad) {
                err = smbconf_set_global_parameter(ctx, "security", "ads");
                if (!SBC_ERROR_IS_OK(err)) {
-                       werr = WERR_NO_SUCH_SERVICE;
+                       werr = WERR_SERVICE_DOES_NOT_EXIST;
                        goto done;
                }
 
                err = smbconf_set_global_parameter(ctx, "realm",
                                                   r->out.dns_domain_name);
                if (!SBC_ERROR_IS_OK(err)) {
-                       werr = WERR_NO_SUCH_SERVICE;
+                       werr = WERR_SERVICE_DOES_NOT_EXIST;
                        goto done;
                }
        }
@@ -1844,7 +2017,7 @@ static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
 
        err = smbconf_init_reg(r, &ctx, NULL);
        if (!SBC_ERROR_IS_OK(err)) {
-               werr = WERR_NO_SUCH_SERVICE;
+               werr = WERR_SERVICE_DOES_NOT_EXIST;
                goto done;
        }
 
@@ -1852,13 +2025,13 @@ static WERROR do_unjoin_modify_vals_config(struct libnet_UnjoinCtx *r)
 
                err = smbconf_set_global_parameter(ctx, "security", "user");
                if (!SBC_ERROR_IS_OK(err)) {
-                       werr = WERR_NO_SUCH_SERVICE;
+                       werr = WERR_SERVICE_DOES_NOT_EXIST;
                        goto done;
                }
 
                err = smbconf_delete_global_parameter(ctx, "workgroup");
                if (!SBC_ERROR_IS_OK(err)) {
-                       werr = WERR_NO_SUCH_SERVICE;
+                       werr = WERR_SERVICE_DOES_NOT_EXIST;
                        goto done;
                }
 
@@ -1977,7 +2150,7 @@ static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
        if (!r->in.domain_name) {
                libnet_join_set_error_string(mem_ctx, r,
                        "No domain name defined");
-               return WERR_INVALID_PARAM;
+               return WERR_INVALID_PARAMETER;
        }
 
        if (strlen(r->in.machine_name) > 15) {
@@ -1986,25 +2159,43 @@ static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
                          "\"%s\" is %u chars long\n",
                          r->in.machine_name,
                         (unsigned int)strlen(r->in.machine_name));
-               return WERR_INVALID_PARAM;
+               return WERR_INVALID_PARAMETER;
         }
 
+       r->out.account_name = talloc_asprintf(mem_ctx, "%s$",
+                                      r->in.machine_name);
+       if (r->out.account_name == NULL) {
+               libnet_join_set_error_string(mem_ctx, r,
+                       "Unable to construct r->out.account_name");
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
+
        if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
                                    &r->in.domain_name,
                                    &r->in.dc_name)) {
                libnet_join_set_error_string(mem_ctx, r,
                        "Failed to parse domain name");
-               return WERR_INVALID_PARAM;
+               return WERR_INVALID_PARAMETER;
        }
 
        if (!r->in.admin_domain) {
                char *admin_domain = NULL;
                char *admin_account = NULL;
-               split_domain_user(mem_ctx,
-                                 r->in.admin_account,
-                                 &admin_domain,
-                                 &admin_account);
-               r->in.admin_domain = admin_domain;
+               bool ok;
+
+               ok = split_domain_user(mem_ctx,
+                                      r->in.admin_account,
+                                      &admin_domain,
+                                      &admin_account);
+               if (!ok) {
+                       return WERR_NOT_ENOUGH_MEMORY;
+               }
+
+               if (admin_domain != NULL) {
+                       r->in.admin_domain = admin_domain;
+               } else {
+                       r->in.admin_domain = r->in.domain_name;
+               }
                r->in.admin_account = admin_account;
        }
 
@@ -2060,28 +2251,49 @@ static WERROR libnet_join_post_processing(TALLOC_CTX *mem_ctx,
                return r->out.result;
        }
 
-       werr = do_JoinConfig(r);
-       if (!W_ERROR_IS_OK(werr)) {
-               return werr;
-       }
-
        if (!(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_TYPE)) {
+               werr = do_JoinConfig(r);
+               if (!W_ERROR_IS_OK(werr)) {
+                       return werr;
+               }
+
                return WERR_OK;
        }
 
+#ifdef HAVE_ADS
+       if (r->out.domain_is_ad &&
+           !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
+               ADS_STATUS ads_status;
+
+               ads_status  = libnet_join_post_processing_ads_modify(mem_ctx, r);
+               if (!ADS_ERR_OK(ads_status)) {
+                       return WERR_GEN_FAILURE;
+               }
+       }
+#endif /* HAVE_ADS */
+
        saf_join_store(r->out.netbios_domain_name, r->in.dc_name);
        if (r->out.dns_domain_name) {
                saf_join_store(r->out.dns_domain_name, r->in.dc_name);
        }
 
+       if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
+               return WERR_NERR_SETUPNOTJOINED;
+       }
+
+       werr = do_JoinConfig(r);
+       if (!W_ERROR_IS_OK(werr)) {
+               return werr;
+       }
+
 #ifdef HAVE_ADS
        if (r->out.domain_is_ad &&
            !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
                ADS_STATUS ads_status;
 
-               ads_status  = libnet_join_post_processing_ads(mem_ctx, r);
+               ads_status  = libnet_join_post_processing_ads_sync(mem_ctx, r);
                if (!ADS_ERR_OK(ads_status)) {
-                       return WERR_GENERAL_FAILURE;
+                       return WERR_GEN_FAILURE;
                }
        }
 #endif /* HAVE_ADS */
@@ -2125,7 +2337,7 @@ WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
 
        ctx = talloc_zero(mem_ctx, struct libnet_JoinCtx);
        if (!ctx) {
-               return WERR_NOMEM;
+               return WERR_NOT_ENOUGH_MEMORY;
        }
 
        talloc_set_destructor(ctx, libnet_destroy_JoinCtx);
@@ -2135,6 +2347,16 @@ WERROR libnet_init_JoinCtx(TALLOC_CTX *mem_ctx,
 
        ctx->in.secure_channel_type = SEC_CHAN_WKSTA;
 
+       ctx->in.desired_encryption_types = ENC_CRC32 |
+                                          ENC_RSA_MD5 |
+                                          ENC_RC4_HMAC_MD5;
+#ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96
+       ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES128;
+#endif
+#ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96
+       ctx->in.desired_encryption_types |= ENC_HMAC_SHA1_96_AES256;
+#endif
+
        *r = ctx;
 
        return WERR_OK;
@@ -2150,7 +2372,7 @@ WERROR libnet_init_UnjoinCtx(TALLOC_CTX *mem_ctx,
 
        ctx = talloc_zero(mem_ctx, struct libnet_UnjoinCtx);
        if (!ctx) {
-               return WERR_NOMEM;
+               return WERR_NOT_ENOUGH_MEMORY;
        }
 
        talloc_set_destructor(ctx, libnet_destroy_UnjoinCtx);
@@ -2172,6 +2394,7 @@ static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
        bool valid_security = false;
        bool valid_workgroup = false;
        bool valid_realm = false;
+       bool ignored_realm = false;
 
        /* check if configuration is already set correctly */
 
@@ -2191,11 +2414,27 @@ static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
                        valid_realm = strequal(lp_realm(), r->out.dns_domain_name);
                        switch (lp_security()) {
                        case SEC_DOMAIN:
+                               if (!valid_realm && lp_winbind_rpc_only()) {
+                                       valid_realm = true;
+                                       ignored_realm = true;
+                               }
+                               /* FALL THROUGH */
                        case SEC_ADS:
                                valid_security = true;
                        }
 
                        if (valid_workgroup && valid_realm && valid_security) {
+                               if (ignored_realm && !r->in.modify_config)
+                               {
+                                       libnet_join_set_error_string(mem_ctx, r,
+                                               "Warning: ignoring realm when "
+                                               "joining AD domain with "
+                                               "'security=domain' and "
+                                               "'winbind rpc only = yes'. "
+                                               "(realm set to '%s', "
+                                               "should be '%s').", lp_realm(),
+                                               r->out.dns_domain_name);
+                               }
                                /* nothing to be done */
                                return WERR_OK;
                        }
@@ -2300,10 +2539,10 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                                     &info);
                if (!NT_STATUS_IS_OK(status)) {
                        libnet_join_set_error_string(mem_ctx, r,
-                               "failed to find DC for domain %s",
+                               "failed to find DC for domain %s - %s",
                                r->in.domain_name,
                                get_friendly_nt_error_msg(status));
-                       return WERR_DCNOTFOUND;
+                       return WERR_NERR_DCNOTFOUND;
                }
 
                dc = strip_hostname(info->dc_unc);
@@ -2314,7 +2553,7 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                    info->dc_address[1] != '\\') {
                        DBG_ERR("ill-formed DC address '%s'\n",
                                info->dc_address);
-                       return WERR_DCNOTFOUND;
+                       return WERR_NERR_DCNOTFOUND;
                }
 
                numeric_dcip = info->dc_address + 2;
@@ -2332,14 +2571,14 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                                DBG_ERR(
                                    "cannot parse IP address '%s' of DC '%s'\n",
                                    numeric_dcip, r->in.dc_name);
-                               return WERR_DCNOTFOUND;
+                               return WERR_NERR_DCNOTFOUND;
                        }
                } else {
                        if (!interpret_string_addr(&ss, r->in.dc_name, 0)) {
                                DBG_WARNING(
                                    "cannot resolve IP address of DC '%s'\n",
                                    r->in.dc_name);
-                               return WERR_DCNOTFOUND;
+                               return WERR_NERR_DCNOTFOUND;
                        }
                }
 
@@ -2367,9 +2606,11 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 
 #ifdef HAVE_ADS
 
-       create_local_private_krb5_conf_for_domain(
-               r->out.dns_domain_name, r->out.netbios_domain_name,
-               NULL, smbXcli_conn_remote_sockaddr(cli->conn));
+       if (r->out.domain_is_ad) {
+               create_local_private_krb5_conf_for_domain(
+                       r->out.dns_domain_name, r->out.netbios_domain_name,
+                       sitename, smbXcli_conn_remote_sockaddr(cli->conn));
+       }
 
        if (r->out.domain_is_ad &&
            !(r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE)) {
@@ -2385,7 +2626,7 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 
                ads_status = libnet_join_connect_ads_user(mem_ctx, r);
                if (!ADS_ERR_OK(ads_status)) {
-                       return WERR_DEFAULT_JOIN_REQUIRED;
+                       return WERR_NERR_DEFAULTJOINREQUIRED;
                }
 
                ads_status = libnet_join_precreate_machine_acct(mem_ctx, r);
@@ -2405,7 +2646,7 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                                "failed to precreate account in ou %s: %s",
                                r->in.account_ou,
                                ads_errstr(ads_status));
-                       return WERR_DEFAULT_JOIN_REQUIRED;
+                       return WERR_NERR_DEFAULTJOINREQUIRED;
                }
 
                DEBUG(5, ("failed to precreate account in ou %s: %s",
@@ -2425,17 +2666,12 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                        "failed to join domain '%s' over rpc: %s",
                        r->in.domain_name, get_friendly_nt_error_msg(status));
                if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
-                       return WERR_SETUP_ALREADY_JOINED;
+                       return WERR_NERR_SETUPALREADYJOINED;
                }
                werr = ntstatus_to_werror(status);
                goto done;
        }
 
-       if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
-               werr = WERR_SETUP_NOT_JOINED;
-               goto done;
-       }
-
        werr = WERR_OK;
 
  done:
@@ -2536,7 +2772,7 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
                if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
                        libnet_unjoin_set_error_string(mem_ctx, r,
                                "Unable to fetch domain sid: are we joined?");
-                       return WERR_SETUP_NOT_JOINED;
+                       return WERR_NERR_SETUPNOTJOINED;
                }
                r->in.domain_sid = dom_sid_dup(mem_ctx, &sid);
                W_ERROR_HAVE_NO_MEMORY(r->in.domain_sid);
@@ -2562,10 +2798,10 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
                                     &info);
                if (!NT_STATUS_IS_OK(status)) {
                        libnet_unjoin_set_error_string(mem_ctx, r,
-                               "failed to find DC for domain %s",
+                               "failed to find DC for domain %s - %s",
                                r->in.domain_name,
                                get_friendly_nt_error_msg(status));
-                       return WERR_DCNOTFOUND;
+                       return WERR_NERR_DCNOTFOUND;
                }
 
                dc = strip_hostname(info->dc_unc);
@@ -2611,7 +2847,7 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
                                "failed to disable machine account via rpc: %s",
                                get_friendly_nt_error_msg(status));
                        if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
-                               return WERR_SETUP_NOT_JOINED;
+                               return WERR_NERR_SETUPNOTJOINED;
                        }
                        return ntstatus_to_werror(status);
                }
@@ -2636,7 +2872,7 @@ static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
        if (!r->in.domain_name) {
                libnet_unjoin_set_error_string(mem_ctx, r,
                        "No domain name defined");
-               return WERR_INVALID_PARAM;
+               return WERR_INVALID_PARAMETER;
        }
 
        if (!libnet_parse_domain_dc(mem_ctx, r->in.domain_name,
@@ -2644,21 +2880,31 @@ static WERROR libnet_unjoin_pre_processing(TALLOC_CTX *mem_ctx,
                                    &r->in.dc_name)) {
                libnet_unjoin_set_error_string(mem_ctx, r,
                        "Failed to parse domain name");
-               return WERR_INVALID_PARAM;
+               return WERR_INVALID_PARAMETER;
        }
 
        if (IS_DC) {
-               return WERR_SETUP_DOMAIN_CONTROLLER;
+               return WERR_NERR_SETUPDOMAINCONTROLLER;
        }
 
        if (!r->in.admin_domain) {
                char *admin_domain = NULL;
                char *admin_account = NULL;
-               split_domain_user(mem_ctx,
-                                 r->in.admin_account,
-                                 &admin_domain,
-                                 &admin_account);
-               r->in.admin_domain = admin_domain;
+               bool ok;
+
+               ok = split_domain_user(mem_ctx,
+                                      r->in.admin_account,
+                                      &admin_domain,
+                                      &admin_account);
+               if (!ok) {
+                       return WERR_NOT_ENOUGH_MEMORY;
+               }
+
+               if (admin_domain != NULL) {
+                       r->in.admin_domain = admin_domain;
+               } else {
+                       r->in.admin_domain = r->in.domain_name;
+               }
                r->in.admin_account = admin_account;
        }