r17472: Remove unused variable.
[samba.git] / source4 / libnet / libnet_join.c
index 28d12247c9fd14ce04c6c22ed6ea4f7fcc3f0bb1..1d64257ca36ca20f222c52ea8c1b708539fffda5 100644 (file)
 
 #include "includes.h"
 #include "libnet/libnet.h"
-#include "librpc/gen_ndr/ndr_samr.h"
-#include "librpc/gen_ndr/ndr_lsa.h"
-#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsuapi_c.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
-#include "libcli/cldap/cldap.h"
-#include "include/secrets.h"
-#include "librpc/gen_ndr/drsuapi.h"
-
-/*
- * find out Site specific stuff:
- * 1.) setup an CLDAP socket
- * 2.) lookup the Site name
- * 3.) Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>.
- * TODO: 4.) use DsAddEntry() to create CN=NTDS Settings,CN=<netbios name>,CN=Servers,CN=<site name>...
- */
-static NTSTATUS libnet_JoinSite(struct libnet_context *ctx,
-                               struct dcerpc_pipe *drsuapi_pipe,
-                               struct policy_handle drsuapi_bind_handle,
-                               struct ldb_context *remote_ldb,
-                               struct libnet_JoinDomain *libnet_r)
-{
-       NTSTATUS status;
-       TALLOC_CTX *tmp_ctx;
-
-       struct cldap_socket *cldap = NULL;
-       struct cldap_netlogon search;
-
-       struct ldb_dn *server_dn;
-       struct ldb_message *msg;
-       int rtn;
-
-       const char *site_name;
-       const char *server_dn_str;
-       const char *config_dn_str;
-
-       tmp_ctx = talloc_named(libnet_r, 0, "libnet_JoinSite temp context");
-       if (!tmp_ctx) {
-               libnet_r->out.error_string = NULL;
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* Resolve the site name. */
-
-       ZERO_STRUCT(search);
-       search.in.dest_address = libnet_r->out.samr_binding->host;
-       search.in.acct_control = -1;
-       search.in.version = 6;
-
-       cldap = cldap_socket_init(tmp_ctx, NULL);
-       status = cldap_netlogon(cldap, tmp_ctx, &search);
-       if (!NT_STATUS_IS_OK(status)) {
-               /* Default to using Default-First-Site-Name rather than returning status at this point. */
-               site_name = talloc_asprintf(tmp_ctx, "%s", "Default-First-Site-Name");
-               if (!site_name) {
-                       libnet_r->out.error_string = NULL;
-                       talloc_free(tmp_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       } else {
-               site_name = search.out.netlogon.logon5.site_name;
-       }
-
-       config_dn_str = talloc_asprintf(tmp_ctx, "CN=Configuration,%s", libnet_r->out.domain_dn_str);
-       if (!config_dn_str) {
-               libnet_r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       server_dn_str = talloc_asprintf(tmp_ctx, "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
-                                                libnet_r->in.netbios_name, site_name, config_dn_str);
-       if (!server_dn_str) {
-               libnet_r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /*
-        Add entry CN=<netbios name>,CN=Servers,CN=<site name>,CN=Sites,CN=Configuration,<domain dn>.
-       */
-       msg = ldb_msg_new(tmp_ctx);
-       if (!msg) {
-               libnet_r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       rtn = ldb_msg_add_string(msg, "objectClass", "server");
-       if (rtn != 0) {
-               libnet_r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-       rtn = ldb_msg_add_string(msg, "systemFlags", "50000000");
-       if (rtn != 0) {
-               libnet_r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-       rtn = ldb_msg_add_string(msg, "serverReference",libnet_r->out.account_dn_str);
-       if (rtn != 0) {
-               libnet_r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       server_dn = ldb_dn_explode(tmp_ctx, server_dn_str);
-       if (server_dn == NULL) {
-               libnet_r->out.error_string = talloc_asprintf(libnet_r, 
-                                       "Invalid server dn: %s",
-                                       server_dn_str);
-               talloc_free(tmp_ctx);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       msg->dn = server_dn; 
-
-       rtn = ldb_add(remote_ldb, msg);
-       if (rtn == LDB_ERR_ENTRY_ALREADY_EXISTS) {
-               int i;
-               
-               /* make a 'modify' msg, and only for serverReference */
-               msg = ldb_msg_new(tmp_ctx);
-               if (!msg) {
-                       libnet_r->out.error_string = NULL;
-                       talloc_free(tmp_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               msg->dn = server_dn; 
-
-               rtn = ldb_msg_add_string(msg, "serverReference",libnet_r->out.account_dn_str);
-               if (rtn != 0) {
-                       libnet_r->out.error_string = NULL;
-                       talloc_free(tmp_ctx);
-                       return NT_STATUS_NO_MEMORY;
-               }
-               
-               /* mark all the message elements (should be just one)
-                  as LDB_FLAG_MOD_REPLACE */
-               for (i=0;i<msg->num_elements;i++) {
-                       msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
-               }
-
-               rtn = ldb_modify(remote_ldb, msg);
-               if (rtn != 0) {
-                       libnet_r->out.error_string
-                               = talloc_asprintf(libnet_r,
-                                                 "Failed to modify server entry %s: %s: %d",
-                                                 server_dn_str,
-                                                 ldb_errstring(remote_ldb), rtn);
-                       talloc_free(tmp_ctx);
-                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
-               }
-       } else if (rtn != 0) {
-               libnet_r->out.error_string
-                       = talloc_asprintf(libnet_r,
-                               "Failed to add server entry %s: %s: %d",
-                               server_dn_str,
-                                         ldb_errstring(remote_ldb), rtn);
-               talloc_free(tmp_ctx);
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-       DEBUG(0, ("We still need to perform a DsAddEntry() so that we can create the CN=NTDS Settings container.\n"));
-
-       /* Store the server DN in libnet_r */
-       libnet_r->out.server_dn_str = server_dn_str;
-       talloc_steal(libnet_r, server_dn_str);
-       
-       talloc_free(tmp_ctx);
-       return NT_STATUS_OK;
-}
+#include "passdb/secrets.h"
+#include "dsdb/samdb/samdb.h"
+#include "db_wrap.h"
+#include "libcli/security/security.h"
+#include "auth/credentials/credentials.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
 
 /*
  * complete a domain join, when joining to a AD domain:
@@ -274,8 +111,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        status = dcerpc_pipe_connect_b(tmp_ctx, 
                                       &drsuapi_pipe,
                                       drsuapi_binding,
-                                      DCERPC_DRSUAPI_UUID,
-                                      DCERPC_DRSUAPI_VERSION, 
+                                      &dcerpc_table_drsuapi,
                                       ctx->cred, 
                                       ctx->event_ctx);
        if (!NT_STATUS_IS_OK(status)) {
@@ -299,16 +135,14 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
                        r->out.error_string
                                = talloc_asprintf(r,
-                                                 "dcerpc_drsuapi_DsBind for [%s\\%s] failed - %s\n", 
-                                                 r->in.domain_name, r->in.account_name, 
+                                                 "dcerpc_drsuapi_DsBind failed - %s\n", 
                                                  dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code));
                        talloc_free(tmp_ctx);
                        return status;
                } else {
                        r->out.error_string
                                = talloc_asprintf(r,
-                                                 "dcerpc_drsuapi_DsBind for [%s\\%s] failed - %s\n", 
-                                                 r->in.domain_name, r->in.account_name, 
+                                                 "dcerpc_drsuapi_DsBind failed - %s\n", 
                                                  nt_errstr(status));
                        talloc_free(tmp_ctx);
                        return status;
@@ -535,10 +369,8 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
 
        r->out.kvno = kvno;
 
-       if (r->in.acct_type ==  ACB_SVRTRUST) {
-               status = libnet_JoinSite(ctx,
-                                        drsuapi_pipe, drsuapi_bind_handle,
-                                        remote_ldb, r);
+       if (r->in.acct_type == ACB_SVRTRUST) {
+               status = libnet_JoinSite(remote_ldb, r);
        }
        talloc_free(tmp_ctx);
 
@@ -547,21 +379,23 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
 
 /*
  * do a domain join using DCERPC/SAMR calls
- * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
- *    is it correct to contact the the pdc of the domain of the user who's password should be set?
- * 2. do a samr_Connect to get a policy handle
- * 3. do a samr_LookupDomain to get the domain sid
- * 4. do a samr_OpenDomain to get a domain handle
- * 5. do a samr_CreateAccount to try and get a new account 
+ * - connect to the LSA pipe, to try and find out information about the domain
+ * - create a secondary connection to SAMR pipe
+ * - do a samr_Connect to get a policy handle
+ * - do a samr_LookupDomain to get the domain sid
+ * - do a samr_OpenDomain to get a domain handle
+ * - do a samr_CreateAccount to try and get a new account 
  * 
  * If that fails, do:
- * 5.1. do a samr_LookupNames to get the users rid
- * 5.2. do a samr_OpenUser to get a user handle
+ * - do a samr_LookupNames to get the users rid
+ * - do a samr_OpenUser to get a user handle
+ * - potentially delete and recreate the user
+ * - assert the account is of the right type with samrQueryUserInfo
  * 
- * 6. call libnet_SetPassword_samr_handle to set the password
+ * - call libnet_SetPassword_samr_handle to set the password
  *
- * 7. do a samrSetUserInfo to set the account flags
- * 8. do some ADS specific things when we join as Domain Controller,
+ * - do a samrSetUserInfo to set the account flags
+ * - do some ADS specific things when we join as Domain Controller,
  *    look at libnet_joinADSDomain() for the details
  */
 NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *r)
@@ -569,17 +403,10 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        TALLOC_CTX *tmp_ctx;
 
        NTSTATUS status, cu_status;
-       struct libnet_RpcConnect *c;
-       struct lsa_ObjectAttribute attr;
-       struct lsa_QosInfo qos;
-       struct lsa_OpenPolicy2 lsa_open_policy;
-       struct policy_handle lsa_p_handle;
-       struct lsa_QueryInfoPolicy2 lsa_query_info2;
-       struct lsa_QueryInfoPolicy lsa_query_info;
-
-       struct dcerpc_binding *samr_binding;
+
+       struct libnet_RpcConnect *connect_with_info;
        struct dcerpc_pipe *samr_pipe;
-       struct dcerpc_pipe *lsa_pipe;
+
        struct samr_Connect sc;
        struct policy_handle p_handle;
        struct samr_OpenDomain od;
@@ -599,12 +426,8 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        uint32_t rid, access_granted;
        int policy_min_pw_len = 0;
 
-       struct dom_sid *domain_sid = NULL;
        struct dom_sid *account_sid = NULL;
-       const char *domain_name = NULL;
        const char *password_str = NULL;
-       const char *realm = NULL; /* Also flag for remote being AD */
-       
        
        r->out.error_string = NULL;
        r2.samr_handle.out.error_string = NULL;
@@ -622,168 +445,46 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return NT_STATUS_NO_MEMORY;
        }
        
-       samr_pipe = talloc(tmp_ctx, struct dcerpc_pipe);
-       if (!samr_pipe) {
+       connect_with_info = talloc(tmp_ctx, struct libnet_RpcConnect);
+       if (!connect_with_info) {
                r->out.error_string = NULL;
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
        }
-       
-       c = talloc(tmp_ctx, struct libnet_RpcConnect);
-       if (!c) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-       
+
        /* prepare connect to the LSA pipe of PDC */
        if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
-               c->level             = LIBNET_RPC_CONNECT_PDC;
-               c->in.domain_name    = r->in.domain_name;
+               connect_with_info->in.name    = r->in.domain_name;
        } else {
-               c->level             = LIBNET_RPC_CONNECT_BINDING;
-               c->in.binding        = r->in.binding;
-       }
-       c->in.dcerpc_iface_name      = DCERPC_LSARPC_NAME;
-       c->in.dcerpc_iface_uuid      = DCERPC_LSARPC_UUID;
-       c->in.dcerpc_iface_version   = DCERPC_LSARPC_VERSION;
-       
-       /* connect to the LSA pipe of the PDC */
-
-       status = libnet_RpcConnect(ctx, c, c);
-       if (!NT_STATUS_IS_OK(status)) {
-               if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
-                       r->out.error_string = talloc_asprintf(mem_ctx,
-                                                             "Connection to LSA pipe of PDC of domain '%s' failed: %s",
-                                                             r->in.domain_name, nt_errstr(status));
-               } else {
-                       r->out.error_string = talloc_asprintf(mem_ctx,
-                                                             "Connection to LSA pipe with binding '%s' failed: %s",
-                                                             r->in.binding, nt_errstr(status));
-               }
-               talloc_free(tmp_ctx);
-               return status;
-       }                       
-       lsa_pipe = c->out.dcerpc_pipe;
-       
-       /* Get an LSA policy handle */
-
-       ZERO_STRUCT(lsa_p_handle);
-       qos.len = 0;
-       qos.impersonation_level = 2;
-       qos.context_mode = 1;
-       qos.effective_only = 0;
-
-       attr.len = 0;
-       attr.root_dir = NULL;
-       attr.object_name = NULL;
-       attr.attributes = 0;
-       attr.sec_desc = NULL;
-       attr.sec_qos = &qos;
-
-       lsa_open_policy.in.attr = &attr;
-       
-       lsa_open_policy.in.system_name = talloc_asprintf(tmp_ctx, "\\"); 
-       if (!lsa_open_policy.in.system_name) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_ctx);
-               return NT_STATUS_NO_MEMORY;
+               connect_with_info->in.binding = r->in.binding;
        }
 
-       lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       lsa_open_policy.out.handle = &lsa_p_handle;
-
-       status = dcerpc_lsa_OpenPolicy2(lsa_pipe, tmp_ctx, &lsa_open_policy); 
-
-       /* This now fails on ncacn_ip_tcp against Win2k3 SP1 */
-       if (NT_STATUS_IS_OK(status)) {
-               /* Look to see if this is ADS (a fault indicates NT4 or Samba 3.0) */
-               
-               lsa_query_info2.in.handle = &lsa_p_handle;
-               lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
-               
-               status = dcerpc_lsa_QueryInfoPolicy2(lsa_pipe, tmp_ctx,                 
-                                                    &lsa_query_info2);
-               
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
-                       if (!NT_STATUS_IS_OK(status)) {
-                               r->out.error_string = talloc_asprintf(mem_ctx,
-                                                                     "lsa_QueryInfoPolicy2 failed: %s",
-                                                                     nt_errstr(status));
-                               talloc_free(tmp_ctx);
-                               return status;
-                       }
-                       realm = lsa_query_info2.out.info->dns.dns_domain.string;
-               }
-               
-               /* Grab the domain SID (regardless of the result of the previous call */
-               
-               lsa_query_info.in.handle = &lsa_p_handle;
-               lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
-               
-               status = dcerpc_lsa_QueryInfoPolicy(lsa_pipe, tmp_ctx, 
-                                                   &lsa_query_info);
-               
-               if (!NT_STATUS_IS_OK(status)) {
-                       r->out.error_string = talloc_asprintf(mem_ctx,
-                                                             "lsa_QueryInfoPolicy2 failed: %s",
-                                                             nt_errstr(status));
-                       talloc_free(tmp_ctx);
-                       return status;
-               }
-               
-               domain_sid = lsa_query_info.out.info->domain.sid;
-               domain_name = lsa_query_info.out.info->domain.name.string;
-       } else {
-               /* Cause the code further down to try this with just SAMR */
-               domain_sid = NULL;
-               if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
-                       domain_name = talloc_strdup(tmp_ctx, r->in.domain_name);
-               } else {
-                       /* Bugger, we just lost our way to automaticly find the domain name */
-                       domain_name = talloc_strdup(tmp_ctx, lp_workgroup());
-               }
-       }
+       connect_with_info->level              = LIBNET_RPC_CONNECT_DC_INFO;
+       connect_with_info->in.dcerpc_iface    = &dcerpc_table_samr;
 
        /*
          establish a SAMR connection, on the same CIFS transport
        */
-
-       /* Find the original binding string */
-       status = dcerpc_parse_binding(tmp_ctx, lsa_pipe->conn->binding_string, &samr_binding);  
-       if (!NT_STATUS_IS_OK(status)) {
-               r->out.error_string = talloc_asprintf(mem_ctx,
-                                               "Failed to parse lsa binding '%s'",
-                                               lsa_pipe->conn->binding_string);
-               talloc_free(tmp_ctx);
-               return status;
-       }
-
-       /* Make binding string for samr, not the other pipe */
-       status = dcerpc_epm_map_binding(tmp_ctx, samr_binding,                                  
-                                       DCERPC_SAMR_UUID, DCERPC_SAMR_VERSION,
-                                       lsa_pipe->conn->event_ctx);
+       status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info);
        if (!NT_STATUS_IS_OK(status)) {
-               r->out.error_string = talloc_asprintf(mem_ctx,
-                                               "Failed to map DCERPC/TCP NCACN_NP pipe for '%s' - %s",
-                                               DCERPC_NETLOGON_UUID,
-                                               nt_errstr(status));
+               if (r->in.binding) {
+                       r->out.error_string = talloc_asprintf(mem_ctx,
+                                                             "Connection to SAMR pipe of DC %s failed: %s",
+                                                             r->in.binding, connect_with_info->out.error_string);
+               } else {
+                       r->out.error_string = talloc_asprintf(mem_ctx,
+                                                             "Connection to SAMR pipe of PDC for %s failed: %s",
+                                                             r->in.domain_name, connect_with_info->out.error_string);
+               }
                talloc_free(tmp_ctx);
                return status;
        }
 
-       /* Setup a SAMR connection */
-       status = dcerpc_secondary_connection(lsa_pipe, &samr_pipe, samr_binding);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->out.error_string = talloc_asprintf(mem_ctx,
-                                               "SAMR secondary connection failed: %s",
-                                               nt_errstr(status));
-               talloc_free(tmp_ctx);
-               return status;
-       }
+       samr_pipe = connect_with_info->out.dcerpc_pipe;
 
-       status = dcerpc_pipe_auth(samr_pipe, samr_binding, DCERPC_SAMR_UUID, 
-                                 DCERPC_SAMR_VERSION, ctx->cred);
+       status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe,
+                                 connect_with_info->out.dcerpc_pipe->binding, 
+                                 &dcerpc_table_samr, ctx->cred);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                "SAMR bind failed: %s",
@@ -808,11 +509,21 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return status;
        }
 
+       /* If this is a connection on ncacn_ip_tcp to Win2k3 SP1, we don't get back this useful info */
+       if (!connect_with_info->out.domain_name) {
+               if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
+                       connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, r->in.domain_name);
+               } else {
+                       /* Bugger, we just lost our way to automaticly find the domain name */
+                       connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lp_workgroup());
+               }
+       }
+
        /* Perhaps we didn't get a SID above, because we are against ncacn_ip_tcp */
-       if (!domain_sid) {
+       if (!connect_with_info->out.domain_sid) {
                struct lsa_String name;
                struct samr_LookupDomain l;
-               name.string = domain_name;
+               name.string = connect_with_info->out.domain_name;
                l.in.connect_handle = &p_handle;
                l.in.domain_name = &name;
                
@@ -824,23 +535,23 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                        talloc_free(tmp_ctx);
                        return status;
                }
-               domain_sid = l.out.sid;
+               connect_with_info->out.domain_sid = l.out.sid;
        }
 
        /* prepare samr_OpenDomain */
        ZERO_STRUCT(d_handle);
        od.in.connect_handle = &p_handle;
        od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
-       od.in.sid = domain_sid;
+       od.in.sid = connect_with_info->out.domain_sid;
        od.out.domain_handle = &d_handle;
 
        /* do a samr_OpenDomain to get a domain handle */
        status = dcerpc_samr_OpenDomain(samr_pipe, tmp_ctx, &od);                       
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
-                                       "samr_OpenDomain for [%s] failed: %s",
-                                       r->in.domain_name,
-                                       nt_errstr(status));
+                                                     "samr_OpenDomain for [%s] failed: %s",
+                                                     dom_sid_string(tmp_ctx, connect_with_info->out.domain_sid),
+                                                     nt_errstr(status));
                talloc_free(tmp_ctx);
                return status;
        }
@@ -931,7 +642,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                        if (!NT_STATUS_IS_OK(status)) {
                                r->out.error_string = talloc_asprintf(mem_ctx,
                                                                      "samr_CreateUser2 (recreate) for [%s] failed: %s\n",
-                                                                     r->in.domain_name, nt_errstr(status));
+                                                                     r->in.account_name, nt_errstr(status));
                                talloc_free(tmp_ctx);
                                return status;
                        }
@@ -939,7 +650,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        } else if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                      "samr_CreateUser2 for [%s] failed: %s\n",
-                                                     r->in.domain_name, nt_errstr(status));
+                                                     r->in.account_name, nt_errstr(status));
                talloc_free(tmp_ctx);
                return status;
        }
@@ -1004,7 +715,9 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                        /* We created a new user, but they didn't come out the right type?!? */
                        r->out.error_string
                                = talloc_asprintf(mem_ctx,
-                                                 "We asked to create a new machine account (%s) of type %s, but we got an account of type %s.  This is unexpected.  Perhaps delete the account and try again.\n",
+                                                 "We asked to create a new machine account (%s) of type %s, "
+                                                 "but we got an account of type %s.  This is unexpected.  "
+                                                 "Perhaps delete the account and try again.\n",
                                                  r->in.account_name, new_account_type, old_account_type);
                        talloc_free(tmp_ctx);
                        return NT_STATUS_INVALID_PARAMETER;
@@ -1014,8 +727,10 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                        /* TODO: We should allow a --force option to override, and redo this from the top setting r.in.recreate_account */
                        r->out.error_string
                                = talloc_asprintf(mem_ctx,
-                                                 "The machine account (%s) already exists in the domain %s, but is a %s.  You asked to join as a %s.  Please delete the account and try again.\n",
-                                                 r->in.account_name, domain_name, old_account_type, new_account_type);
+                                                 "The machine account (%s) already exists in the domain %s, "
+                                                 "but is a %s.  You asked to join as a %s.  Please delete "
+                                                 "the account and try again.\n",
+                                                 r->in.account_name, connect_with_info->out.domain_name, old_account_type, new_account_type);
                        talloc_free(tmp_ctx);
                        return NT_STATUS_USER_EXISTS;
                }
@@ -1051,7 +766,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        }
 
        /* reset flags (if required) */
-       if (acct_flags != qui.out.info->info16.acct_flags) {    
+       if (acct_flags != qui.out.info->info16.acct_flags) {
                ZERO_STRUCT(u_info);
                u_info.info16.acct_flags = acct_flags;
 
@@ -1070,7 +785,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                }
        }
 
-       account_sid = dom_sid_add_rid(mem_ctx, domain_sid, rid);
+       account_sid = dom_sid_add_rid(mem_ctx, connect_with_info->out.domain_sid, rid);
        if (!account_sid) {
                r->out.error_string = NULL;
                talloc_free(tmp_ctx);
@@ -1079,24 +794,22 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
 
        /* Finish out by pushing various bits of status data out for the caller to use */
        r->out.join_password = password_str;
-       talloc_steal(mem_ctx, password_str);
+       talloc_steal(mem_ctx, r->out.join_password);
 
-       r->out.domain_sid = domain_sid;
-       talloc_steal(mem_ctx, domain_sid);
+       r->out.domain_sid = connect_with_info->out.domain_sid;
+       talloc_steal(mem_ctx, r->out.domain_sid);
 
        r->out.account_sid = account_sid;
-       talloc_steal(mem_ctx, account_sid);
-
-       r->out.domain_name = domain_name;
-       talloc_steal(mem_ctx, domain_name);
-       r->out.realm = realm;
-       talloc_steal(mem_ctx, realm);
-       r->out.lsa_pipe = lsa_pipe;
-       talloc_steal(mem_ctx, lsa_pipe);
+       talloc_steal(mem_ctx, r->out.account_sid);
+
+       r->out.domain_name = connect_with_info->out.domain_name;
+       talloc_steal(mem_ctx, r->out.domain_name);
+       r->out.realm = connect_with_info->out.realm;
+       talloc_steal(mem_ctx, r->out.realm);
        r->out.samr_pipe = samr_pipe;
        talloc_steal(mem_ctx, samr_pipe);
-       r->out.samr_binding = samr_binding;
-       talloc_steal(mem_ctx, samr_binding);
+       r->out.samr_binding = samr_pipe->binding;
+       talloc_steal(mem_ctx, r->out.samr_binding);
        r->out.user_handle = u_handle;
        talloc_steal(mem_ctx, u_handle);
        r->out.error_string = r2.samr_handle.out.error_string;
@@ -1107,7 +820,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
 
        /* Now, if it was AD, then we want to start looking changing a
         * few more things.  Otherwise, we are done. */
-       if (realm) {
+       if (r->out.realm) {
                status = libnet_JoinADSDomain(ctx, r);
                return status;
        }
@@ -1132,6 +845,8 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                "secret",
                "priorSecret",
                "priorChanged",
+               "krb5Keytab",
+               "privateKeytab",
                NULL
        };
        uint32_t acct_type = 0;
@@ -1153,9 +868,9 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return NT_STATUS_NO_MEMORY;
        }
        
-       if (r->in.secure_channel_type == SEC_CHAN_BDC) {
+       if (r->in.join_type == SEC_CHAN_BDC) {
                acct_type = ACB_SVRTRUST;
-       } else if (r->in.secure_channel_type == SEC_CHAN_WKSTA) {
+       } else if (r->in.join_type == SEC_CHAN_WKSTA) {
                acct_type = ACB_WSTRUST;
        } else {
                r->out.error_string = NULL;
@@ -1163,10 +878,10 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if ((r->in.netbios_name != NULL) && (r->in.level != LIBNET_JOIN_AUTOMATIC)) {
+       if (r->in.netbios_name != NULL) {
                netbios_name = r->in.netbios_name;
        } else {
-               netbios_name = talloc_asprintf(tmp_mem, "%s", lp_netbios_name());
+               netbios_name = talloc_reference(tmp_mem, lp_netbios_name());
                if (!netbios_name) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
@@ -1214,7 +929,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
        /*
         * now prepare the record for secrets.ldb
         */
-       sct = talloc_asprintf(tmp_mem, "%d", r->in.secure_channel_type); 
+       sct = talloc_asprintf(tmp_mem, "%d", r->in.join_type); 
        if (!sct) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
@@ -1324,6 +1039,12 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                           "(|" SECRETS_PRIMARY_DOMAIN_FILTER "(realm=%s))",
                           r2->out.domain_name, r2->out.realm);
        if (ret == 0) {
+               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secretsKeytab", "secrets.keytab");
+               if (rtn == -1) {
+                       r->out.error_string = NULL;
+                       talloc_free(tmp_mem);
+                       return NT_STATUS_NO_MEMORY;
+               }
        } else if (ret == -1) {
                r->out.error_string
                        = talloc_asprintf(mem_ctx, 
@@ -1332,6 +1053,8 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                talloc_free(tmp_mem);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
+               const struct ldb_val *private_keytab;
+               const struct ldb_val *krb5_keytab;
                const struct ldb_val *prior_secret;
                const struct ldb_val *prior_modified_time;
                int i;
@@ -1381,6 +1104,26 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                        talloc_free(tmp_mem);
                        return NT_STATUS_NO_MEMORY;
                }
+
+               /* We will want to keep the keytab names */
+               private_keytab = ldb_msg_find_ldb_val(msgs[0], "privateKeytab");
+               if (private_keytab) {
+                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, "privateKeytab", private_keytab);
+                       if (rtn == -1) {
+                               r->out.error_string = NULL;
+                               talloc_free(tmp_mem);
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
+               krb5_keytab = ldb_msg_find_ldb_val(msgs[0], "krb5Keytab");
+               if (krb5_keytab) {
+                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, "krb5Keytab", krb5_keytab);
+                       if (rtn == -1) {
+                               r->out.error_string = NULL;
+                               talloc_free(tmp_mem);
+                               return NT_STATUS_NO_MEMORY;
+                       }
+               }
        }
 
        /* create the secret */
@@ -1433,7 +1176,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
 
 NTSTATUS libnet_Join(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_Join *r)
 {
-       switch (r->in.secure_channel_type) {
+       switch (r->in.join_type) {
                case SEC_CHAN_WKSTA:
                        return libnet_Join_primary_domain(ctx, mem_ctx, r);
                case SEC_CHAN_BDC:
@@ -1443,9 +1186,7 @@ NTSTATUS libnet_Join(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct lib
        }
 
        r->out.error_string = talloc_asprintf(mem_ctx,
-                               "Invalid secure channel type specified (%08X) attempting to join domain %s",
-                               r->in.secure_channel_type, r->in.domain_name);
+                                             "Invalid join type specified (%08X) attempting to join domain %s",
+                                             r->in.join_type, r->in.domain_name);
        return NT_STATUS_INVALID_PARAMETER;
 }
-
-