Merge ldb_search() and ldb_search_exp_fmt() into a simgle function.
[tprouty/samba.git] / source4 / libnet / libnet_join.c
index 9185015da0a703205c5b59ebf5cdcc892eb0fd54..43f86489217cf2e64f21f2624eadb89ba76c88d4 100644 (file)
@@ -7,7 +7,7 @@
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -16,8 +16,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
-#include "passdb/secrets.h"
+#include "param/secrets.h"
 #include "dsdb/samdb/samdb.h"
-#include "db_wrap.h"
+#include "ldb_wrap.h"
+#include "util/util_ldb.h"
 #include "libcli/security/security.h"
 #include "auth/credentials/credentials.h"
+#include "auth/credentials/credentials_krb5.h"
 #include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
 
 /*
  * complete a domain join, when joining to a AD domain:
@@ -61,7 +63,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        struct GUID drsuapi_bind_guid;
 
        struct ldb_context *remote_ldb;
-       const struct ldb_dn *account_dn;
+       struct ldb_dn *account_dn;
        const char *account_dn_str;
        const char *remote_ldb_url;
        struct ldb_result *res;
@@ -69,12 +71,11 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
 
        int ret, rtn;
 
-       unsigned int kvno;
-       
        const char * const attrs[] = {
                "msDS-KeyVersionNumber",
                "servicePrincipalName",
                "dNSHostName",
+               "objectGUID",
                NULL,
        };
 
@@ -111,13 +112,14 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        status = dcerpc_pipe_connect_b(tmp_ctx, 
                                       &drsuapi_pipe,
                                       drsuapi_binding,
-                                      &dcerpc_table_drsuapi,
+                                      &ndr_table_drsuapi,
                                       ctx->cred, 
-                                      ctx->event_ctx);
+                                      ctx->event_ctx,
+                                      ctx->lp_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(r,
                                        "Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s",
-                                       r->in.domain_name,
+                                       r->out.domain_name,
                                        nt_errstr(status));
                talloc_free(tmp_ctx);
                return status;
@@ -135,14 +137,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 failed - %s\n", 
+                                                 "dcerpc_drsuapi_DsBind failed - %s", 
                                                  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 failed - %s\n", 
+                                                 "dcerpc_drsuapi_DsBind failed - %s", 
                                                  nt_errstr(status));
                        talloc_free(tmp_ctx);
                        return status;
@@ -150,7 +152,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        } else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) {
                r->out.error_string
                                = talloc_asprintf(r,
-                                                 "DsBind failed - %s\n", 
+                                                 "DsBind failed - %s", 
                                                  win_errstr(r_drsuapi_bind.out.result));
                        talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
@@ -160,8 +162,8 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        ZERO_STRUCT(r_crack_names);
        r_crack_names.in.bind_handle            = &drsuapi_bind_handle;
        r_crack_names.in.level                  = 1;
-       r_crack_names.in.req.req1.unknown1      = 0x000004e4;
-       r_crack_names.in.req.req1.unknown2      = 0x00000407;
+       r_crack_names.in.req.req1.codepage      = 1252; /* western european */
+       r_crack_names.in.req.req1.language      = 0x00000407; /* german */
        r_crack_names.in.req.req1.count         = 1;
        r_crack_names.in.req.req1.names         = names;
        r_crack_names.in.req.req1.format_flags  = DRSUAPI_DS_NAME_FLAG_NO_FLAGS;
@@ -179,7 +181,7 @@ 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_DsCrackNames for [%s] failed - %s\n", 
+                                                 "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 
                                                  names[0].str,
                                                  dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code));
                        talloc_free(tmp_ctx);
@@ -187,7 +189,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                } else {
                        r->out.error_string
                                = talloc_asprintf(r,
-                                                 "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s\n", 
+                                                 "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 
                                                  names[0].str,
                                                  nt_errstr(status));
                        talloc_free(tmp_ctx);
@@ -196,41 +198,40 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
                r->out.error_string
                                = talloc_asprintf(r,
-                                                 "DsCrackNames failed - %s\n", win_errstr(r_crack_names.out.result));
+                                                 "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));
                talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        } else if (r_crack_names.out.level != 1 
                   || !r_crack_names.out.ctr.ctr1 
-                  || r_crack_names.out.ctr.ctr1->count != 1 
-                  || !r_crack_names.out.ctr.ctr1->array[0].result_name
-                  || r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
-               r->out.error_string = talloc_asprintf(r, "DsCrackNames failed\n");
+                  || r_crack_names.out.ctr.ctr1->count != 1) {
+               r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");
+               talloc_free(tmp_ctx);
+               return NT_STATUS_INVALID_PARAMETER;
+       } else if (r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
+               r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr.ctr1->array[0].status);
                talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
+       } else if (r_crack_names.out.ctr.ctr1->array[0].result_name == NULL) {
+               r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name");
+               talloc_free(tmp_ctx);
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
        /* Store the DN of our machine account. */
        account_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name;
 
-       account_dn = ldb_dn_explode(tmp_ctx, account_dn_str);
-       if (!account_dn) {
-               r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",
-                                                     account_dn_str);
-               talloc_free(tmp_ctx);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
        /* Now we know the user's DN, open with LDAP, read and modify a few things */
 
        remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", 
-                                        drsuapi_binding->host);
+                                        drsuapi_binding->target_hostname);
        if (!remote_ldb_url) {
                r->out.error_string = NULL;
                talloc_free(tmp_ctx);
                return NT_STATUS_NO_MEMORY;
        }
 
-       remote_ldb = ldb_wrap_connect(tmp_ctx, remote_ldb_url, 
+       remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx, 
+                                     remote_ldb_url, 
                                      NULL, ctx->cred, 0, NULL);
        if (!remote_ldb) {
                r->out.error_string = NULL;
@@ -238,18 +239,30 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str);
+       if (! ldb_dn_validate(account_dn)) {
+               r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",
+                                                     account_dn_str);
+               talloc_free(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
        /* search for the user's record */
-       ret = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, 
-                            NULL, attrs, &res);
-       if (ret != LDB_SUCCESS || res->count != 1) {
-               r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s\n",
+       ret = ldb_search(remote_ldb, tmp_ctx, &res,
+                        account_dn, LDB_SCOPE_BASE, attrs, NULL);
+       if (ret != LDB_SUCCESS) {
+               r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s",
                                                      account_dn_str, ldb_errstring(remote_ldb));
                talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       /* If we have a kvno recorded in AD, we need it locally as well */
-       kvno = ldb_msg_find_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);
+       if (res->count != 1) {
+               r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries",
+                                                     account_dn_str, res->count);
+               talloc_free(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
 
        /* Prepare a new message, for the modify */
        msg = ldb_msg_new(tmp_ctx);
@@ -307,8 +320,8 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                if (rtn != 0) {
                        r->out.error_string
                                = talloc_asprintf(r, 
-                                                 "Failed to replace entries on %s\n", 
-                                                 ldb_dn_linearize(tmp_ctx, msg->dn));
+                                                 "Failed to replace entries on %s", 
+                                                 ldb_dn_get_linearized(msg->dn));
                        talloc_free(tmp_ctx);
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
@@ -329,7 +342,7 @@ 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_DsCrackNames for [%s] failed - %s\n", 
+                                                 "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 
                                                  r->in.domain_name, 
                                                  dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code));
                        talloc_free(tmp_ctx);
@@ -337,7 +350,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                } else {
                        r->out.error_string
                                = talloc_asprintf(r,
-                                                 "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s\n", 
+                                                 "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 
                                                  r->in.domain_name, 
                                                  nt_errstr(status));
                        talloc_free(tmp_ctx);
@@ -346,7 +359,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
                r->out.error_string
                        = talloc_asprintf(r,
-                                         "DsCrackNames failed - %s\n", win_errstr(r_crack_names.out.result));
+                                         "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));
                talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        } else if (r_crack_names.out.level != 1 
@@ -354,7 +367,7 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
                   || r_crack_names.out.ctr.ctr1->count != 1
                   || !r_crack_names.out.ctr.ctr1->array[0].result_name           
                   || r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {
-               r->out.error_string = talloc_asprintf(r, "DsCrackNames failed\n");
+               r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");
                talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        }
@@ -367,10 +380,15 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
        r->out.domain_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name;
        talloc_steal(r, r_crack_names.out.ctr.ctr1->array[0].result_name);
 
-       r->out.kvno = kvno;
+       /* Store the KVNO of the account, critical for some kerberos
+        * operations */
+       r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);
+
+       /* Store the account GUID. */
+       r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID");
 
        if (r->in.acct_type == ACB_SVRTRUST) {
-               status = libnet_JoinSite(remote_ldb, r);
+               status = libnet_JoinSite(ctx, remote_ldb, r);
        }
        talloc_free(tmp_ctx);
 
@@ -392,9 +410,9 @@ static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_J
  * - potentially delete and recreate the user
  * - assert the account is of the right type with samrQueryUserInfo
  * 
- * - call libnet_SetPassword_samr_handle to set the password
+ * - call libnet_SetPassword_samr_handle to set the password,
+ *   and pass a samr_UserInfo21 struct to set full_name and the account flags
  *
- * - 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
  */
@@ -404,7 +422,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
 
        NTSTATUS status, cu_status;
 
-       struct libnet_RpcConnectDCInfo *connect_with_info;
+       struct libnet_RpcConnect *connect_with_info;
        struct dcerpc_pipe *samr_pipe;
 
        struct samr_Connect sc;
@@ -416,8 +434,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        struct samr_CreateUser2 cu;
        struct policy_handle *u_handle = NULL;
        struct samr_QueryUserInfo qui;
-       struct samr_SetUserInfo sui;
-       union samr_UserInfo u_info;
+       struct samr_UserInfo21 u_info21;
        union libnet_SetPassword r2;
        struct samr_GetUserPwInfo pwp;
        struct lsa_String samr_account_name;
@@ -445,28 +462,31 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return NT_STATUS_NO_MEMORY;
        }
        
-       connect_with_info = talloc(tmp_ctx, struct libnet_RpcConnectDCInfo);
+       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;
        }
 
-       /* prepare connect to the LSA pipe of PDC */
+       /* prepare connect to the SAMR pipe of PDC */
        if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
-               connect_with_info->level      = LIBNET_RPC_CONNECT_PDC;
+               connect_with_info->in.binding = NULL;
                connect_with_info->in.name    = r->in.domain_name;
        } else {
-               connect_with_info->level      = LIBNET_RPC_CONNECT_BINDING;
                connect_with_info->in.binding = r->in.binding;
+               connect_with_info->in.name    = NULL;
        }
 
-       connect_with_info->in.dcerpc_iface    = &dcerpc_table_samr;
+       /* This level makes a connection to the LSA pipe on the way,
+        * to get some useful bits of information about the domain */
+       connect_with_info->level              = LIBNET_RPC_CONNECT_DC_INFO;
+       connect_with_info->in.dcerpc_iface    = &ndr_table_samr;
+
        /*
-         establish a SAMR connection, on the same CIFS transport
+         establish the SAMR connection
        */
-       
-       status = libnet_RpcConnectDCInfo(ctx, connect_with_info);
+       status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info);
        if (!NT_STATUS_IS_OK(status)) {
                if (r->in.binding) {
                        r->out.error_string = talloc_asprintf(mem_ctx,
@@ -481,11 +501,11 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return status;
        }
 
-       samr_pipe = connect_with_info->out.dcerpc_pipe
+       samr_pipe = connect_with_info->out.dcerpc_pipe;
 
-       status = dcerpc_pipe_auth(samr_pipe,
+       status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe,
                                  connect_with_info->out.dcerpc_pipe->binding, 
-                                 &dcerpc_table_samr, ctx->cred);
+                                 &ndr_table_samr, ctx->cred, ctx->lp_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                "SAMR bind failed: %s",
@@ -516,7 +536,8 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                        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());
+                       connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lp_workgroup(ctx->lp_ctx));
+                       connect_with_info->out.realm = talloc_strdup(tmp_ctx, lp_realm(ctx->lp_ctx));
                }
        }
 
@@ -597,7 +618,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                /* check if we got one RID for the user */
                if (ln.out.rids.count != 1) {
                        r->out.error_string = talloc_asprintf(mem_ctx,
-                                                             "samr_LookupNames for [%s] returns %d RIDs\n",
+                                                             "samr_LookupNames for [%s] returns %d RIDs",
                                                              r->in.account_name, ln.out.rids.count);
                        talloc_free(tmp_ctx);
                        return NT_STATUS_INVALID_PARAMETER;
@@ -642,16 +663,16 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                        status = dcerpc_samr_CreateUser2(samr_pipe, tmp_ctx, &cu);                      
                        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));
+                                                                     "samr_CreateUser2 (recreate) for [%s] failed: %s",
+                                                                     r->in.account_name, nt_errstr(status));
                                talloc_free(tmp_ctx);
                                return status;
                        }
                }
        } 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));
+                                                     "samr_CreateUser2 for [%s] failed: %s",
+                                                     r->in.account_name, nt_errstr(status));
                talloc_free(tmp_ctx);
                return status;
        }
@@ -674,7 +695,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                status = NT_STATUS_INVALID_PARAMETER;
                r->out.error_string
                        = talloc_asprintf(mem_ctx,
-                                         "samr_QueryUserInfo failed to return qui.out.info for [%s]: %s\n",
+                                         "samr_QueryUserInfo failed to return qui.out.info for [%s]: %s",
                                          r->in.account_name, nt_errstr(status));
                talloc_free(tmp_ctx);
                return status;
@@ -718,7 +739,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                                = 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",
+                                                 "Perhaps delete the account and try again.",
                                                  r->in.account_name, new_account_type, old_account_type);
                        talloc_free(tmp_ctx);
                        return NT_STATUS_INVALID_PARAMETER;
@@ -730,7 +751,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                                = 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",
+                                                 "the account and try again.",
                                                  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;
@@ -739,7 +760,7 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                acct_flags = qui.out.info->info16.acct_flags;
        }
        
-       acct_flags = (acct_flags & ~ACB_DISABLED);
+       acct_flags = (acct_flags & ~(ACB_DISABLED|ACB_PWNOTREQ));
 
        /* Find out what password policy this user has */
        pwp.in.user_handle = u_handle;
@@ -753,11 +774,18 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        
        password_str = generate_random_str(tmp_ctx, MAX(8, policy_min_pw_len)); 
 
+       /* set full_name and reset flags */
+       ZERO_STRUCT(u_info21);
+       u_info21.full_name.string       = r->in.account_name;
+       u_info21.acct_flags             = acct_flags;
+       u_info21.fields_present         = SAMR_FIELD_FULL_NAME | SAMR_FIELD_ACCT_FLAGS;
+
        r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
        r2.samr_handle.in.account_name  = r->in.account_name;
        r2.samr_handle.in.newpassword   = password_str;
        r2.samr_handle.in.user_handle   = u_handle;
        r2.samr_handle.in.dcerpc_pipe   = samr_pipe;
+       r2.samr_handle.in.info21        = &u_info21;
 
        status = libnet_SetPassword(ctx, tmp_ctx, &r2); 
        if (!NT_STATUS_IS_OK(status)) {
@@ -766,26 +794,6 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
                return status;
        }
 
-       /* reset flags (if required) */
-       if (acct_flags != qui.out.info->info16.acct_flags) {
-               ZERO_STRUCT(u_info);
-               u_info.info16.acct_flags = acct_flags;
-
-               sui.in.user_handle = u_handle;
-               sui.in.info = &u_info;
-               sui.in.level = 16;
-               
-               dcerpc_samr_SetUserInfo(samr_pipe, tmp_ctx, &sui);
-               if (!NT_STATUS_IS_OK(status)) {
-                       r->out.error_string = talloc_asprintf(mem_ctx,
-                                                       "samr_SetUserInfo for [%s] failed to remove ACB_DISABLED flag: %s",
-                                                       r->in.account_name,
-                                                       nt_errstr(status));
-                       talloc_free(tmp_ctx);
-                       return status;
-               }
-       }
-
        account_sid = dom_sid_add_rid(mem_ctx, connect_with_info->out.domain_sid, rid);
        if (!account_sid) {
                r->out.error_string = NULL;
@@ -829,16 +837,14 @@ NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, stru
        return status;
 }
 
-static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx, 
-                                          TALLOC_CTX *mem_ctx, 
-                                          struct libnet_Join *r)
+NTSTATUS libnet_set_join_secrets(struct libnet_context *ctx, 
+                                TALLOC_CTX *mem_ctx, 
+                                struct libnet_set_join_secrets *r)
 {
-       NTSTATUS status;
        TALLOC_CTX *tmp_mem;
-       struct libnet_JoinDomain *r2;
        int ret, rtn;
        struct ldb_context *ldb;
-       const struct ldb_dn *base_dn;
+       struct ldb_dn *base_dn;
        struct ldb_message **msgs, *msg;
        const char *sct;
        const char * const attrs[] = {
@@ -850,83 +856,22 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                "privateKeytab",
                NULL
        };
-       uint32_t acct_type = 0;
-       const char *account_name;
-       const char *netbios_name;
-       char *filter;
-       
-       r->out.error_string = NULL;
 
        tmp_mem = talloc_new(mem_ctx);
        if (!tmp_mem) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       r2 = talloc(tmp_mem, struct libnet_JoinDomain);
-       if (!r2) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-       
-       if (r->in.join_type == SEC_CHAN_BDC) {
-               acct_type = ACB_SVRTRUST;
-       } else if (r->in.join_type == SEC_CHAN_WKSTA) {
-               acct_type = ACB_WSTRUST;
-       } else {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);   
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (r->in.netbios_name != NULL) {
-               netbios_name = r->in.netbios_name;
-       } else {
-               netbios_name = talloc_reference(tmp_mem, lp_netbios_name());
-               if (!netbios_name) {
-                       r->out.error_string = NULL;
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
-       account_name = talloc_asprintf(tmp_mem, "%s$", netbios_name);
-       if (!account_name) {
-               r->out.error_string = NULL;
-               talloc_free(tmp_mem);
-               return NT_STATUS_NO_MEMORY;
-       }
-       
-       /*
-        * Local secrets are stored in secrets.ldb 
-        * open it to make sure we can write the info into it after the join
-        */
-       ldb = secrets_db_connect(tmp_mem);
+       /* Open the secrets database */
+       ldb = secrets_db_connect(tmp_mem, ctx->event_ctx, ctx->lp_ctx);
        if (!ldb) {
                r->out.error_string
                        = talloc_asprintf(mem_ctx, 
-                                         "Could not open secrets database\n");
+                                         "Could not open secrets database");
                talloc_free(tmp_mem);
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
-       /*
-        * join the domain
-        */
-       ZERO_STRUCTP(r2);
-       r2->in.domain_name      = r->in.domain_name;
-       r2->in.account_name     = account_name;
-       r2->in.netbios_name     = netbios_name;
-       r2->in.level            = LIBNET_JOINDOMAIN_AUTOMATIC;
-       r2->in.acct_type        = acct_type;
-       r2->in.recreate_account = False;
-       status = libnet_JoinDomain(ctx, r2, r2);
-       if (!NT_STATUS_IS_OK(status)) {
-               r->out.error_string = talloc_steal(mem_ctx, r2->out.error_string);
-               talloc_free(tmp_mem);
-               return status;
-       }
-       
        /*
         * now prepare the record for secrets.ldb
         */
@@ -944,29 +889,29 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
-       base_dn = ldb_dn_explode(tmp_mem, "cn=Primary Domains");
+       base_dn = ldb_dn_new(tmp_mem, ldb, "cn=Primary Domains");
        if (!base_dn) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
                return NT_STATUS_NO_MEMORY;
        }
 
-       msg->dn = ldb_dn_build_child(tmp_mem, "flatname", r2->out.domain_name, base_dn);
-       if (!msg->dn) {
+       msg->dn = ldb_dn_copy(tmp_mem, base_dn);
+       if ( ! ldb_dn_add_child_fmt(msg->dn, "flatname=%s", r->in.domain_name)) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
                return NT_STATUS_NO_MEMORY;
        }
        
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "flatname", r2->out.domain_name);
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "flatname", r->in.domain_name);
        if (rtn == -1) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (r2->out.realm) {
-               rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "realm", r2->out.realm);
+       if (r->in.realm) {
+               rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "realm", r->in.realm);
                if (rtn == -1) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
@@ -988,14 +933,14 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "secret", r2->out.join_password);
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "secret", r->in.join_password);
        if (rtn == -1) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
                return NT_STATUS_NO_MEMORY;
        }
 
-       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "samAccountName", r2->in.account_name);
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "samAccountName", r->in.account_name);
        if (rtn == -1) {
                r->out.error_string = NULL;
                talloc_free(tmp_mem);
@@ -1009,9 +954,9 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (r2->out.kvno) {
+       if (r->in.kvno) {
                rtn = samdb_msg_add_uint(ldb, tmp_mem, msg, "msDS-KeyVersionNumber",
-                                        r2->out.kvno);
+                                        r->in.kvno);
                if (rtn == -1) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
@@ -1019,9 +964,9 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                }
        }
 
-       if (r2->out.domain_sid) {
+       if (r->in.domain_sid) {
                rtn = samdb_msg_add_dom_sid(ldb, tmp_mem, msg, "objectSid",
-                                           r2->out.domain_sid);
+                                           r->in.domain_sid);
                if (rtn == -1) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
@@ -1038,7 +983,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                           tmp_mem, base_dn,
                           &msgs, attrs,
                           "(|" SECRETS_PRIMARY_DOMAIN_FILTER "(realm=%s))",
-                          r2->out.domain_name, r2->out.realm);
+                          r->in.domain_name, r->in.realm);
        if (ret == 0) {
                rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secretsKeytab", "secrets.keytab");
                if (rtn == -1) {
@@ -1050,12 +995,12 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                r->out.error_string
                        = talloc_asprintf(mem_ctx, 
                                          "Search for domain: %s and realm: %s failed: %s", 
-                                         r2->out.domain_name, r2->out.realm, ldb_errstring(ldb));
+                                         r->in.domain_name, r->in.realm, ldb_errstring(ldb));
                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 *krb5_main_keytab;
                const struct ldb_val *prior_secret;
                const struct ldb_val *prior_modified_time;
                int i;
@@ -1073,7 +1018,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                                return NT_STATUS_NO_MEMORY;
                        }
                }
-               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secret", r2->out.join_password);
+               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secret", r->in.join_password);
                if (rtn == -1) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
@@ -1092,7 +1037,7 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                        }
                }
 
-               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "samAccountName", r2->in.account_name);
+               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "samAccountName", r->in.account_name);
                if (rtn == -1) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
@@ -1116,9 +1061,10 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
                                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);
+               krb5_main_keytab = ldb_msg_find_ldb_val(msgs[0], "krb5Keytab");
+               if (krb5_main_keytab) {
+                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg,
+                                       "krb5Keytab", krb5_main_keytab);
                        if (rtn == -1) {
                                r->out.error_string = NULL;
                                talloc_free(tmp_mem);
@@ -1128,39 +1074,110 @@ static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx,
        }
 
        /* create the secret */
-       ret = samdb_add(ldb, tmp_mem, msg);
+       ret = ldb_add(ldb, msg);
        if (ret != 0) {
-               r->out.error_string = talloc_asprintf(mem_ctx, "Failed to create secret record %s\n", 
-                                                     ldb_dn_linearize(ldb, msg->dn));
+               r->out.error_string = talloc_asprintf(mem_ctx, "Failed to create secret record %s", 
+                                                     ldb_dn_get_linearized(msg->dn));
                talloc_free(tmp_mem);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       if (r2->out.realm) {
-               struct cli_credentials *creds;
-               /* Make a credentials structure from it */
-               creds = cli_credentials_init(mem_ctx);
-               if (!creds) {
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx, 
+                                          TALLOC_CTX *mem_ctx, 
+                                          struct libnet_Join *r)
+{
+       NTSTATUS status;
+       TALLOC_CTX *tmp_mem;
+       struct libnet_JoinDomain *r2;
+       struct libnet_set_join_secrets *r3;
+       uint32_t acct_type = 0;
+       const char *account_name;
+       const char *netbios_name;
+       
+       r->out.error_string = NULL;
+
+       tmp_mem = talloc_new(mem_ctx);
+       if (!tmp_mem) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       r2 = talloc(tmp_mem, struct libnet_JoinDomain);
+       if (!r2) {
+               r->out.error_string = NULL;
+               talloc_free(tmp_mem);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       if (r->in.join_type == SEC_CHAN_BDC) {
+               acct_type = ACB_SVRTRUST;
+       } else if (r->in.join_type == SEC_CHAN_WKSTA) {
+               acct_type = ACB_WSTRUST;
+       } else {
+               r->out.error_string = NULL;
+               talloc_free(tmp_mem);   
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (r->in.netbios_name != NULL) {
+               netbios_name = r->in.netbios_name;
+       } else {
+               netbios_name = talloc_reference(tmp_mem, lp_netbios_name(ctx->lp_ctx));
+               if (!netbios_name) {
                        r->out.error_string = NULL;
                        talloc_free(tmp_mem);
                        return NT_STATUS_NO_MEMORY;
                }
-               cli_credentials_set_conf(creds);
-               filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_linearize(mem_ctx, msg->dn));
-               status = cli_credentials_set_secrets(creds, NULL, filter);
-               if (!NT_STATUS_IS_OK(status)) {
-                       r->out.error_string = talloc_asprintf(mem_ctx, "Failed to read secrets for keytab update for %s\n", 
-                                                             filter);
-                       talloc_free(tmp_mem);
-                       return status;
-               } 
-               ret = cli_credentials_update_keytab(creds);
-               if (ret != 0) {
-                       r->out.error_string = talloc_asprintf(mem_ctx, "Failed to update keytab for %s\n", 
-                                                             filter);
-                       talloc_free(tmp_mem);
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
+       }
+
+       account_name = talloc_asprintf(tmp_mem, "%s$", netbios_name);
+       if (!account_name) {
+               r->out.error_string = NULL;
+               talloc_free(tmp_mem);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       /*
+        * join the domain
+        */
+       ZERO_STRUCTP(r2);
+       r2->in.domain_name      = r->in.domain_name;
+       r2->in.account_name     = account_name;
+       r2->in.netbios_name     = netbios_name;
+       r2->in.level            = LIBNET_JOINDOMAIN_AUTOMATIC;
+       r2->in.acct_type        = acct_type;
+       r2->in.recreate_account = false;
+       status = libnet_JoinDomain(ctx, r2, r2);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->out.error_string = talloc_steal(mem_ctx, r2->out.error_string);
+               talloc_free(tmp_mem);
+               return status;
+       }
+
+       r3 = talloc(tmp_mem, struct libnet_set_join_secrets);
+       if (!r3) {
+               r->out.error_string = NULL;
+               talloc_free(tmp_mem);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       ZERO_STRUCTP(r3);
+       r3->in.domain_name = r2->out.domain_name;
+       r3->in.realm = r2->out.realm;
+       r3->in.account_name = account_name;
+       r3->in.netbios_name = netbios_name;
+       r3->in.join_type = r->in.join_type;
+       r3->in.join_password = r2->out.join_password;
+       r3->in.kvno = r2->out.kvno;
+       r3->in.domain_sid = r2->out.domain_sid;
+       
+       status = libnet_set_join_secrets(ctx, r3, r3);
+       if (!NT_STATUS_IS_OK(status)) {
+               r->out.error_string = talloc_steal(mem_ctx, r3->out.error_string);
+               talloc_free(tmp_mem);
+               return status;
        }
 
        /* move all out parameter to the callers TALLOC_CTX */