more enctypes...
[metze/samba/wip.git] / source3 / libnet / libnet_join.c
index 86130cae16e7b2b818c9ab206cd7b753d7592670..5a0834520820b2de77d86d2a4c72a7a80c4ffdb3 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "includes.h"
 #include "ads.h"
+#include "libsmb/namequery.h"
 #include "librpc/gen_ndr/ndr_libnet_join.h"
 #include "libnet/libnet_join.h"
 #include "libcli/auth/libcli_auth.h"
@@ -43,6 +44,7 @@
 #include "libcli/auth/netlogon_creds_cli.h"
 #include "auth/credentials/credentials.h"
 #include "krb5_env.h"
+#include "libsmb/dsgetdcname.h"
 
 /****************************************************************
 ****************************************************************/
@@ -195,16 +197,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 {
@@ -869,14 +866,15 @@ 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;
@@ -968,6 +966,12 @@ static ADS_STATUS libnet_join_post_processing_ads(TALLOC_CTX *mem_ctx,
                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");
@@ -985,18 +989,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;
        }
 
@@ -1048,12 +1046,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;
@@ -1085,6 +1094,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);
        }
@@ -1124,64 +1134,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);
@@ -1233,9 +1289,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);
        }
 
@@ -1413,11 +1471,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,
@@ -1459,7 +1517,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);
 
@@ -1476,7 +1534,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);
        }
@@ -1546,9 +1604,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) {
@@ -1572,22 +1627,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_IPC_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,
@@ -1606,21 +1656,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 "
@@ -1651,7 +1701,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);
@@ -1700,15 +1749,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());
 }
 
 /****************************************************************
@@ -2120,6 +2164,14 @@ static WERROR libnet_join_pre_processing(TALLOC_CTX *mem_ctx,
                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)) {
@@ -2187,6 +2239,18 @@ static void libnet_join_add_dom_rids_to_builtins(struct dom_sid *domain_sid)
                          "BUILTIN\\Administrators during join: %s\n",
                          nt_errstr(status)));
        }
+
+       /* Try adding dom guests to builtin\guests. Only log failures. */
+       status = create_builtin_guests(domain_sid);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_PROTOCOL_UNREACHABLE)) {
+               DEBUG(10,("Unable to auto-add domain guests to "
+                         "BUILTIN\\Guests during join because "
+                         "winbindd must be running.\n"));
+       } else if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(5, ("Failed to auto-add domain guests to "
+                         "BUILTIN\\Guests during join: %s\n",
+                         nt_errstr(status)));
+       }
 }
 
 /****************************************************************
@@ -2201,26 +2265,47 @@ 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_GEN_FAILURE;
                }
@@ -2276,15 +2361,7 @@ 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
+       ctx->in.desired_encryption_types = kerberos_supported_encryption_types();
 
        *r = ctx;
 
@@ -2347,7 +2424,8 @@ static WERROR libnet_join_check_config(TALLOC_CTX *mem_ctx,
                                        valid_realm = true;
                                        ignored_realm = true;
                                }
-                               /* FALL THROUGH */
+
+                               FALL_THROUGH;
                        case SEC_ADS:
                                valid_security = true;
                        }
@@ -2581,9 +2659,10 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                DEBUG(5, ("failed to precreate account in ou %s: %s",
                        r->in.account_ou, ads_errstr(ads_status)));
        }
+ rpc_join:
+
 #endif /* HAVE_ADS */
 
- rpc_join:
        if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) &&
            (r->in.join_flags & WKSSVC_JOIN_FLAGS_MACHINE_PWD_PASSED)) {
                status = libnet_join_joindomain_rpc_unsecure(mem_ctx, r, cli);
@@ -2601,11 +2680,6 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
                goto done;
        }
 
-       if (!libnet_join_joindomain_store_secrets(mem_ctx, r)) {
-               werr = WERR_NERR_SETUPNOTJOINED;
-               goto done;
-       }
-
        werr = WERR_OK;
 
  done:
@@ -2786,6 +2860,8 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
                        return ntstatus_to_werror(status);
                }
 
+               r->out.dns_domain_name = talloc_strdup(mem_ctx,
+                                                     r->in.domain_name);
                r->out.disabled_machine_account = true;
        }