samba-technical@lists.samba.org
[Top] [All Lists]

Samba 4 libnet_join and RPC-JOIN torture test

Subject: Samba 4 libnet_join and RPC-JOIN torture test
From: Brad Henry
Date: Thu, 08 Sep 2005 22:31:51 -0600
Hello all,

This patch contains the changes i've made to the libnet join code. I've also created a new torture test RPC-JOIN, and changed torture/rpc/testjoin.c to use this code as well.

The patch is an 'svk diff' against current SAMBA_4_0. There is still a problem which causes the test to segfault once the test is completed and it has returned back to torture.c, but I wanted to get this out and get some responses.

Thanks!
Brad
=== libnet/config.mk
==================================================================
--- libnet/config.mk  (revision 5907)
+++ libnet/config.mk  (local)
@@ -17,6 +17,6 @@
                libnet/userinfo.o \
                libnet/userman.o \
                libnet/domain.o 
-REQUIRED_SUBSYSTEMS = RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI 
LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBSAMBA3
+REQUIRED_SUBSYSTEMS = RPC_NDR_SAMR RPC_NDR_LSA RPC_NDR_SRVSVC RPC_NDR_DRSUAPI 
LIBCLI_COMPOSITE LIBCLI_RESOLVE LIBSAMBA3 LIBCLI_CLDAP
 # End SUBSYSTEM LIBNET
 #################################
=== libnet/libnet_join.c
==================================================================
--- libnet/libnet_join.c  (revision 5907)
+++ libnet/libnet_join.c  (local)
@@ -3,6 +3,7 @@
    
    Copyright (C) Stefan Metzmacher     2004
    Copyright (C) Andrew Bartlett <abartlet@xxxxxxxxx> 2005
+   Copyright (C) Brad Henry 2005
  
    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
@@ -25,8 +26,9 @@
 #include "librpc/gen_ndr/ndr_lsa.h"
 #include "librpc/gen_ndr/ndr_drsuapi.h"
 #include "lib/ldb/include/ldb.h"
+#include "libcli/cldap/cldap.h"
 #include "include/secrets.h"
-
+#include "librpc/gen_ndr/drsuapi.h"
 /*
  * do a domain join using DCERPC/SAMR calls
  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server 
or workstation)
@@ -48,8 +50,8 @@
 {
        TALLOC_CTX *tmp_ctx;
 
-       NTSTATUS status;
-       struct libnet_RpcConnect c;
+       NTSTATUS status, cu_status;
+       struct libnet_RpcConnect *c;
        struct lsa_ObjectAttribute attr;
        struct lsa_QosInfo qos;
        struct lsa_OpenPolicy2 lsa_open_policy;
@@ -59,6 +61,7 @@
 
        struct dcerpc_binding *samr_binding;
        struct dcerpc_pipe *samr_pipe;
+       struct dcerpc_pipe *dcerpc_pipe;
        struct samr_Connect sc;
        struct policy_handle p_handle;
        struct samr_OpenDomain od;
@@ -66,60 +69,47 @@
        struct samr_LookupNames ln;
        struct samr_OpenUser ou;
        struct samr_CreateUser2 cu;
-       struct policy_handle u_handle;
+       struct policy_handle *u_handle = NULL;
        struct samr_QueryUserInfo qui;
        struct samr_SetUserInfo sui;
        union samr_UserInfo u_info;
        union libnet_SetPassword r2;
        struct samr_GetUserPwInfo pwp;
        struct lsa_String samr_account_name;
-
-       struct dcerpc_pipe *drsuapi_pipe;
-       struct dcerpc_binding *drsuapi_binding;
-       struct drsuapi_DsBind r_drsuapi_bind;
-       struct drsuapi_DsCrackNames r_crack_names;
-       struct drsuapi_DsNameString names[1];
-       struct policy_handle drsuapi_bind_handle;
-       struct GUID drsuapi_bind_guid;
-
-       struct ldb_context *remote_ldb;
-
+       
        uint32_t acct_flags;
        uint32_t rid, access_granted;
        int policy_min_pw_len = 0;
 
-       struct dom_sid *domain_sid;
-       const char *domain_name;
+       struct dom_sid *domain_sid = NULL;
+       const char *domain_name = NULL;
+       const char *password_str = NULL;
        const char *realm = NULL; /* Also flag for remote being AD */
-       const struct ldb_dn *account_dn;
-
-       char *remote_ldb_url;
-       struct ldb_message **msgs, *msg;
-       int ldb_ret;
-
-       const char *attrs[] = {
-               "msDS-KeyVersionNumber",
-               "servicePrincipalName",
-               "dNSHostName",
-               NULL,
-       };
-
+       
+       
+       r->out.error_string = NULL;
+       r2.samr_handle.out.error_string = NULL;
+       
        tmp_ctx = talloc_named(mem_ctx, 0, "libnet_Join temp context");
        if (!tmp_ctx) {
                r->out.error_string = NULL;
                return NT_STATUS_NO_MEMORY;
        }
-
-
+       
+       u_handle = talloc(tmp_ctx, struct policy_handle);
+       samr_pipe = talloc(tmp_ctx, struct dcerpc_pipe);
+       c = talloc(tmp_ctx, struct libnet_RpcConnect);
+       
        /* prepare connect to the LSA pipe of PDC */
-       c.level                     = LIBNET_RPC_CONNECT_PDC;
-       c.in.domain_name            = r->in.domain_name;
-       c.in.dcerpc_iface_name      = DCERPC_LSARPC_NAME;
-       c.in.dcerpc_iface_uuid      = DCERPC_LSARPC_UUID;
-       c.in.dcerpc_iface_version   = DCERPC_LSARPC_VERSION;
+       c->level                     = LIBNET_RPC_CONNECT_PDC;
+       c->in.domain_name            = r->in.domain_name;
+       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 */
 
-       /* connect to the LSA pipe of the PDC */
-       status = libnet_RpcConnect(ctx, tmp_ctx, &c);
+       status = libnet_RpcConnect(ctx, tmp_ctx, c);                    
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                "Connection to LSA pipe of PDC 
of domain '%s' failed: %s",
@@ -127,7 +117,7 @@
                talloc_free(tmp_ctx);
                return status;
        }
-
+       dcerpc_pipe = c->out.dcerpc_pipe;
        
        /* Get an LSA policy handle */
 
@@ -145,11 +135,18 @@
        attr.sec_qos = &qos;
 
        lsa_open_policy.in.attr = &attr;
-       lsa_open_policy.in.system_name = talloc_asprintf(tmp_ctx, "\\%s", 
lp_netbios_name());
+       
+       lsa_open_policy.in.system_name = talloc_asprintf(tmp_ctx, "\\%s", 
r->in.netbios_name); 
+       if (!lsa_open_policy.in.system_name) {
+               r->out.error_string = NULL;                             
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
        lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
        lsa_open_policy.out.handle = &lsa_p_handle;
 
-       status = dcerpc_lsa_OpenPolicy2(c.out.dcerpc_pipe, tmp_ctx, 
&lsa_open_policy);
+       status = dcerpc_lsa_OpenPolicy2(dcerpc_pipe, tmp_ctx, 
&lsa_open_policy); 
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                "lsa_OpenPolicy2 failed: %s",
@@ -163,7 +160,7 @@
        lsa_query_info2.in.handle = &lsa_p_handle;
        lsa_query_info2.in.level = LSA_POLICY_INFO_DNS;
 
-       status = dcerpc_lsa_QueryInfoPolicy2(c.out.dcerpc_pipe, tmp_ctx, 
+       status = dcerpc_lsa_QueryInfoPolicy2(dcerpc_pipe, tmp_ctx,              
                                             &lsa_query_info2);
        
        if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
@@ -182,7 +179,7 @@
        lsa_query_info.in.handle = &lsa_p_handle;
        lsa_query_info.in.level = LSA_POLICY_INFO_DOMAIN;
 
-       status = dcerpc_lsa_QueryInfoPolicy(c.out.dcerpc_pipe, tmp_ctx, 
+       status = dcerpc_lsa_QueryInfoPolicy(dcerpc_pipe, tmp_ctx, 
                                             &lsa_query_info);
        
        if (!NT_STATUS_IS_OK(status)) {
@@ -194,30 +191,26 @@
        }
        domain_sid = lsa_query_info.out.info->domain.sid;
        domain_name = lsa_query_info.out.info->domain.name.string;
-       
-       r->out.domain_sid = talloc_steal(mem_ctx, domain_sid);
-       r->out.domain_name = talloc_steal(mem_ctx, domain_name);
-       r->out.realm = talloc_steal(mem_ctx, realm);
 
        /*
          establish a SAMR connection, on the same CIFS transport
        */
 
        /* Find the original binding string */
-       status = dcerpc_parse_binding(tmp_ctx, 
c.out.dcerpc_pipe->conn->binding_string, &samr_binding);
+       status = dcerpc_parse_binding(tmp_ctx, 
dcerpc_pipe->conn->binding_string, &samr_binding);       
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string
                        = talloc_asprintf(mem_ctx,
                                          "Failed to parse dcerpc binding 
'%s'", 
-                                         
c.out.dcerpc_pipe->conn->binding_string);
+                                         dcerpc_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, 
+       status = dcerpc_epm_map_binding(tmp_ctx, samr_binding,                  
                
                                        DCERPC_SAMR_UUID, DCERPC_SAMR_VERSION,
-                                       c.out.dcerpc_pipe->conn->event_ctx);
+                                       dcerpc_pipe->conn->event_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string
                        = talloc_asprintf(mem_ctx,
@@ -228,7 +221,7 @@
        }
 
        /* Setup a SAMR connection */
-       status = dcerpc_secondary_connection(c.out.dcerpc_pipe, &samr_pipe, 
samr_binding);
+       status = dcerpc_secondary_connection(dcerpc_pipe, &samr_pipe, 
samr_binding);
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                      "SAMR secondary 
connection failed: %s",
@@ -254,7 +247,7 @@
        sc.out.connect_handle = &p_handle;
 
        /* 2. do a samr_Connect to get a policy handle */
-       status = dcerpc_samr_Connect(samr_pipe, tmp_ctx, &sc);
+       status = dcerpc_samr_Connect(samr_pipe, tmp_ctx, &sc);                  
        
        if (!NT_STATUS_IS_OK(status)) {
                r->out.error_string = talloc_asprintf(mem_ctx,
                                                "samr_Connect failed: %s\n",
@@ -281,7 +274,7 @@
        od.out.domain_handle = &d_handle;
 
        /* 4. do a samr_OpenDomain to get a domain handle */
-       status = dcerpc_samr_OpenDomain(samr_pipe, tmp_ctx, &od);
+       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\n",
@@ -291,22 +284,23 @@
        }
 
        /* prepare samr_CreateUser2 */
-       ZERO_STRUCT(u_handle);
+       ZERO_STRUCTP(u_handle);
        cu.in.domain_handle  = &d_handle;
        cu.in.access_mask     = SEC_FLAG_MAXIMUM_ALLOWED;
        samr_account_name.string = r->in.account_name;
        cu.in.account_name    = &samr_account_name;
        cu.in.acct_flags      = r->in.acct_type;
-       cu.out.user_handle    = &u_handle;
+       cu.out.user_handle    = u_handle;
        cu.out.rid            = &rid;
        cu.out.access_granted = &access_granted;
 
        /* 4. do a samr_CreateUser2 to get an account handle, or an error */
-       status = dcerpc_samr_CreateUser2(samr_pipe, tmp_ctx, &cu);
+       cu_status = dcerpc_samr_CreateUser2(samr_pipe, tmp_ctx, &cu);           
        
+       status = cu_status;
        if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, 
NT_STATUS_USER_EXISTS)) {
                        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\n",
+                                                               
r->in.domain_name, nt_errstr(status));
                        talloc_free(tmp_ctx);
                        return status;
 
@@ -327,7 +321,7 @@
                if (!NT_STATUS_IS_OK(status)) {
                        r->out.error_string = talloc_asprintf(mem_ctx,
                                                              "samr_LookupNames 
for [%s] failed: %s\n",
-                                               r->in.account_name, 
nt_errstr(status));
+                                                             
r->in.account_name, nt_errstr(status));
                        talloc_free(tmp_ctx);
                        return status;
                }
@@ -344,14 +338,14 @@
                }
                
                /* prepare samr_OpenUser */
-               ZERO_STRUCT(u_handle);
+               ZERO_STRUCTP(u_handle);
                ou.in.domain_handle = &d_handle;
                ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
                ou.in.rid = ln.out.rids.ids[0];
-               ou.out.user_handle = &u_handle;
+               ou.out.user_handle = u_handle;
                
                /* 6. do a samr_OpenUser to get a user handle */
-               status = dcerpc_samr_OpenUser(samr_pipe, tmp_ctx, &ou);
+               status = dcerpc_samr_OpenUser(samr_pipe, tmp_ctx, &ou); 
                if (!NT_STATUS_IS_OK(status)) {
                        r->out.error_string = talloc_asprintf(mem_ctx,
                                                              "samr_OpenUser 
for [%s] failed: %s\n",
@@ -360,35 +354,33 @@
                        return status;
                }
        }
-
        /* Find out what password policy this user has */
-       pwp.in.user_handle = &u_handle;
+       pwp.in.user_handle = u_handle;
 
-       status = dcerpc_samr_GetUserPwInfo(samr_pipe, tmp_ctx, &pwp);
+       status = dcerpc_samr_GetUserPwInfo(samr_pipe, tmp_ctx, &pwp);           
                
        if (NT_STATUS_IS_OK(status)) {
                policy_min_pw_len = pwp.out.info.min_password_length;
        }
        
        /* Grab a password of that minimum length */
-       r->out.join_password = generate_random_str(mem_ctx, MAX(8, 
policy_min_pw_len));
+       
+       password_str = generate_random_str(tmp_ctx, MAX(8, policy_min_pw_len)); 
 
        r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
        r2.samr_handle.in.account_name  = r->in.account_name;
-       r2.samr_handle.in.newpassword   = r->out.join_password;
-       r2.samr_handle.in.user_handle   = &u_handle;
+       r2.samr_handle.in.newpassword   = password_str;
+       r2.samr_handle.in.user_handle   = u_handle;
        r2.samr_handle.in.dcerpc_pipe   = samr_pipe;
 
-       status = libnet_SetPassword(ctx, tmp_ctx, &r2);
+       status = libnet_SetPassword(ctx, tmp_ctx, &r2);                         
                
 
-       r->out.error_string = r2.samr_handle.out.error_string;
-
        if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(tmp_ctx);
                return status;
        }
 
        /* prepare samr_QueryUserInfo (get flags) */
-       qui.in.user_handle = &u_handle;
+       qui.in.user_handle = u_handle;
        qui.in.level = 16;
        
        status = dcerpc_samr_QueryUserInfo(samr_pipe, tmp_ctx, &qui);
@@ -422,11 +414,13 @@
        acct_flags = (acct_flags & ~ACB_DISABLED);
 
        /* reset flags (if required) */
-       if (acct_flags != qui.out.info->info16.acct_flags) {
+       if ((acct_flags != qui.out.info->info16.acct_flags) 
+               && (!NT_STATUS_EQUAL(cu_status, NT_STATUS_USER_EXISTS))) {
+               
                ZERO_STRUCT(u_info);
                u_info.info16.acct_flags = acct_flags;
 
-               sui.in.user_handle = &u_handle;
+               sui.in.user_handle = u_handle;
                sui.in.info = &u_info;
                sui.in.level = 16;
                
@@ -441,24 +435,102 @@
                }
        }
 
+       r->out.join_password = password_str;
+       talloc_steal(r, password_str);
+       r->out.domain_sid = domain_sid;
+       talloc_steal(r, domain_sid);
+       r->out.domain_name = domain_name;
+       talloc_steal(r, domain_name);
+       r->out.realm = realm;
+       talloc_steal(r, realm);
+       r->out.dcerpc_pipe = dcerpc_pipe;
+       talloc_steal(r, dcerpc_pipe);
+       r->out.samr_pipe = samr_pipe;
+       talloc_steal(r, samr_pipe);
+       r->out.samr_binding = samr_binding;
+       talloc_steal(r, samr_binding);
+       r->out.user_handle = cu.out.user_handle;
+       talloc_steal(r, cu.out.user_handle);
+       r->out.error_string = r2.samr_handle.out.error_string;
+       talloc_steal(r, r2.samr_handle.out.error_string);
+
        /* Now, if it was AD, then we want to start looking changing a
         * few more things.  Otherwise, we are done. */
-       if (!realm) {
-               r->out.realm = NULL;
-               r->out.kvno = 0;
+       if ((realm) 
+               && (r->in.acct_type ==  ACB_SVRTRUST) 
+               && (!NT_STATUS_EQUAL(cu_status, NT_STATUS_USER_EXISTS))) {
+               
                talloc_free(tmp_ctx);
-               return NT_STATUS_OK;
+               status = libnet_JoinADSDomain(ctx, mem_ctx, r);
+               return status;
        }
 
+       r->out.realm = NULL;
+       r->out.kvno = 0;
+
+       r->out.error_string = NULL;
+       talloc_free(tmp_ctx); 
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, 
struct libnet_JoinDomain *r)
+{
+       NTSTATUS status;
+       
+       TALLOC_CTX *tmp_ctx;
+       
+       const char *realm = r->out.realm;
+       
+       struct dcerpc_binding *samr_binding = r->out.samr_binding;
+       
+       struct dcerpc_pipe *drsuapi_pipe;
+       struct dcerpc_binding *drsuapi_binding;
+       struct drsuapi_DsBind r_drsuapi_bind;
+       struct drsuapi_DsCrackNames r_crack_names;
+       struct drsuapi_DsNameString names[1];
+       struct policy_handle drsuapi_bind_handle;
+       struct GUID drsuapi_bind_guid;
+
+       struct ldb_context *remote_ldb;
+
+       const struct ldb_dn *account_dn;
+
+       const char *remote_ldb_url;
+       
+       struct ldb_message **msgs, *msg;
+       int rtn;
+       unsigned int kvno;
+       
+       const char * const attrs[] = {
+               "msDS-KeyVersionNumber",
+               "servicePrincipalName",
+               "dNSHostName",
+               NULL,
+       };
+
+       r->out.error_string = NULL;
+       
        /* We need to convert between a samAccountName and domain to a
         * DN in the directory.  The correct way to do this is with
         * DRSUAPI CrackNames */
 
-
        /* Fiddle with the bindings, so get to DRSUAPI on
         * NCACN_IP_TCP, sealed */
+       tmp_ctx = talloc_named(mem_ctx, 0, "libnet_JoinADSDomain temp 
context");  
+       if (!tmp_ctx) {
+           r->out.error_string = NULL;
+           return NT_STATUS_NO_MEMORY;
+       }
+                                                  
        drsuapi_binding = talloc(tmp_ctx, struct dcerpc_binding);
-       *drsuapi_binding = *samr_binding;
+       if (!drsuapi_binding) {
+               r->out.error_string = NULL;
+               free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       drsuapi_binding = samr_binding;
        drsuapi_binding->transport = NCACN_IP_TCP;
        drsuapi_binding->endpoint = NULL;
        drsuapi_binding->flags |= DCERPC_SEAL;
@@ -492,7 +564,7 @@
                        r->out.error_string
                                = talloc_asprintf(mem_ctx,
                                                  "dcerpc_drsuapi_DsBind for 
[%s\\%s] failed - %s\n", 
-                                                 domain_name, 
r->in.account_name, 
+                                                 r->in.domain_name, 
r->in.account_name, 
                                                  dcerpc_errstr(tmp_ctx, 
drsuapi_pipe->last_fault_code));
                        talloc_free(tmp_ctx);
                        return status;
@@ -500,7 +572,7 @@
                        r->out.error_string
                                = talloc_asprintf(mem_ctx,
                                                  "dcerpc_drsuapi_DsBind for 
[%s\\%s] failed - %s\n", 
-                                                 domain_name, 
r->in.account_name, 
+                                                 r->in.domain_name, 
r->in.account_name, 
                                                  nt_errstr(status));
                        talloc_free(tmp_ctx);
                        return status;
@@ -517,14 +589,19 @@
        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.unknown1      = 0x000004e4;
+       r_crack_names.in.req.req1.unknown2      = 0x00000407;
        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;
-       r_crack_names.in.req.req1.format_offered        = 
DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
-       r_crack_names.in.req.req1.format_desired        = 
DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
-       names[0].str = talloc_asprintf(tmp_ctx, "%s\\%s", domain_name, 
r->in.account_name);
+       r_crack_names.in.req.req1.format_offered= 
DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+       r_crack_names.in.req.req1.format_desired= 
DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+       names[0].str = talloc_asprintf(tmp_ctx, "%s\\%s", r->in.domain_name, 
r->in.account_name);
+       if (!names[0].str) {
+               r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, 
&r_crack_names);
        if (!NT_STATUS_IS_OK(status)) {
@@ -532,7 +609,7 @@
                        r->out.error_string
                                = talloc_asprintf(mem_ctx,
                                                  "dcerpc_drsuapi_DsCrackNames 
for [%s\\%s] failed - %s\n", 
-                                                 domain_name, 
r->in.account_name, 
+                                                 r->in.domain_name, 
r->in.account_name, 
                                                  dcerpc_errstr(tmp_ctx, 
drsuapi_pipe->last_fault_code));
                        talloc_free(tmp_ctx);
                        return status;
@@ -540,7 +617,7 @@
                        r->out.error_string
                                = talloc_asprintf(mem_ctx,
                                                  "dcerpc_drsuapi_DsCrackNames 
for [%s\\%s] failed - %s\n", 
-                                                 domain_name, 
r->in.account_name, 
+                                                 r->in.domain_name, 
r->in.account_name, 
                                                  nt_errstr(status));
                        talloc_free(tmp_ctx);
                        return status;
@@ -554,18 +631,23 @@
        } 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(mem_ctx, "DsCrackNames 
failed\n");
                talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        }
-
-       account_dn = ldb_dn_explode(mem_ctx, 
r_crack_names.out.ctr.ctr1->array[0].result_name);
+       
+       /* Store the DN of our machine account. */
+       r->out.account_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);
+       
+       account_dn = ldb_dn_explode(tmp_ctx, r->out.account_dn_str);
        if (account_dn == NULL) {
-               r->out.error_string
-                       = talloc_asprintf(mem_ctx, "Invalid account dn: %s",
-                                         
r_crack_names.out.ctr.ctr1->array[0].result_name);
+               r->out.error_string = talloc_asprintf(mem_ctx, "Invalid account 
dn: %s",
+                                                     r->out.account_dn_str);
+               talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
@@ -573,27 +655,30 @@
 
        remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s";, 
                                         drsuapi_binding->host);
+       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, 0, NULL);
-
        if (!remote_ldb) {
+               talloc_free(tmp_ctx);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
        /* search for the user's record */
-       ldb_ret = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, 
+       rtn = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, 
                             NULL, attrs, &msgs);
-
-       if (ldb_ret != 1) {
-               r->out.error_string
-                       = talloc_asprintf(mem_ctx,
-                                         "ldb_search for %s failed - %s\n",
-                                         ldb_dn_linearize(mem_ctx, account_dn),
-                                         ldb_errstring(remote_ldb));
+       if (rtn != 1) {
+               r->out.error_string = talloc_asprintf(mem_ctx, "ldb_search for 
%s failed - %s\n",
+                                                     r->out.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 */
-       r->out.kvno = ldb_msg_find_uint(msgs[0], "msDS-KeyVersionNumber", 0);
+       kvno = ldb_msg_find_uint(msgs[0], "msDS-KeyVersionNumber", 0);
 
        /* Prepare a new message, for the modify */
        msg = ldb_msg_new(tmp_ctx);
@@ -604,66 +689,318 @@
        msg->dn = msgs[0]->dn;
 
        {
-               char *service_principal_name[2];
-               char *dns_host_name = strlower_talloc(mem_ctx, 
-                                                     talloc_asprintf(mem_ctx, 
-                                                                     "%s.%s", 
lp_netbios_name(), realm));
+               const char *service_principal_name[2];
+               const char *dns_host_name = strlower_talloc(tmp_ctx, 
talloc_asprintf(tmp_ctx, 
+                                                               "%s.%s", 
+                                                               
r->in.netbios_name, 
+                                                               realm));
+               if (!dns_host_name) {
+                       r->out.error_string = NULL;
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
                service_principal_name[0] = talloc_asprintf(tmp_ctx, "host/%s", 
dns_host_name);
-               service_principal_name[1] = talloc_asprintf(tmp_ctx, "host/%s", 
strlower_talloc(mem_ctx, lp_netbios_name()));
+               if (!service_principal_name[0]) {
+                       r->out.error_string = NULL;
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               service_principal_name[1] = talloc_asprintf(tmp_ctx, "host/%s", 
strlower_talloc(tmp_ctx, r->in.netbios_name));
+               if (!service_principal_name[1]) {
+                       r->out.error_string = NULL;
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_NO_MEMORY;
+               }
 
-               samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "dNSHostName", 
dns_host_name);
-               samdb_msg_add_string(remote_ldb, tmp_ctx, msg, 
"servicePrincipalName", service_principal_name[0]);
-               samdb_msg_add_string(remote_ldb, tmp_ctx, msg, 
"servicePrincipalName", service_principal_name[1]);
-               
-               ldb_ret = samdb_replace(remote_ldb, tmp_ctx, msg);
-               if (ldb_ret != 0) {
+               rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, 
"dNSHostName", dns_host_name);
+               if (rtn == -1) {
+                       r->out.error_string = NULL;
+                       return NT_STATUS_NO_MEMORY;
+               }
+               rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, 
"servicePrincipalName", service_principal_name[0]);
+               if (rtn == -1) {
+                       r->out.error_string = NULL;
+                       return NT_STATUS_NO_MEMORY;
+               }
+               rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, 
"servicePrincipalName", service_principal_name[1]);
+               if (rtn == -1) {
+                       r->out.error_string = NULL;
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               rtn = samdb_replace(remote_ldb, tmp_ctx, msg);
+               if (rtn != 0) {
                        r->out.error_string
                                = talloc_asprintf(mem_ctx, 
                                                  "Failed to replace entries on 
%s\n", 
-                                                 ldb_dn_linearize(mem_ctx, 
msg->dn));
+                                                 ldb_dn_linearize(tmp_ctx, 
msg->dn));
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        }
+                               
+       /* DsCrackNames to find out the DN of the domain. */
+       r_crack_names.in.req.req1.format_offered = 
DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;
+       r_crack_names.in.req.req1.format_desired = 
DRSUAPI_DS_NAME_FORMAT_FQDN_1779;
+       names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->in.domain_name);
+       if (!names[0].str) {
+               r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, 
&r_crack_names);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
+                       r->out.error_string
+                               = talloc_asprintf(mem_ctx,
+                                                 "dcerpc_drsuapi_DsCrackNames 
for [%s] failed - %s\n", 
+                                                 r->in.domain_name, 
+                                                 dcerpc_errstr(tmp_ctx, 
drsuapi_pipe->last_fault_code));
+                       talloc_free(tmp_ctx);
+                       return status;
+               } else {
+                       r->out.error_string
+                               = talloc_asprintf(mem_ctx,
+                                                 "dcerpc_drsuapi_DsCrackNames 
for [%s] failed - %s\n", 
+                                                 r->in.domain_name, 
+                                                 nt_errstr(status));
+                       talloc_free(tmp_ctx);
+                       return status;
+               }
+       } else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {
+               r->out.error_string
+                               = talloc_asprintf(mem_ctx,
+                                                 "DsCrackNames failed - %s\n", 
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(mem_ctx, "DsCrackNames 
failed\n");
+               talloc_free(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+       /* Store the domain DN. */
+       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;
+       
+       talloc_free(tmp_ctx);
+       
+       status = libnet_JoinSite(ctx, mem_ctx, drsuapi_pipe, 
drsuapi_bind_handle, r);
+       
+       return status;
+}
 
-       /* close connection */
+NTSTATUS libnet_JoinSite(struct libnet_context *ctx,
+                               TALLOC_CTX *mem_ctx,
+                               struct dcerpc_pipe *drsuapi_pipe,
+                               struct policy_handle drsuapi_bind_handle,
+                               struct libnet_JoinDomain *libnet_r)
+{
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx;
+       
+       struct cldap_socket *cldap = NULL;
+       struct cldap_netlogon search;
+       
+       char *remote_ldb_url;   
+       struct ldb_context *remote_ldb;
+       struct ldb_dn *account_dn;
+       struct ldb_message *msg;
+       int rtn;
+       
+       char *site_name;
+       char *server_dn;
+       char *ntds_dn;
+       char *schema_dn;
+       char *config_dn;
+       
+       tmp_ctx = talloc_named(mem_ctx, 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 = talloc_steal(tmp_ctx, 
search.out.netlogon.logon5.site_name);
+       }
+               
+       config_dn = talloc_asprintf(tmp_ctx, "CN=Configuration,%s", 
libnet_r->out.domain_dn_str);
+       if (!config_dn) {
+               libnet_r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }               
+       server_dn = talloc_asprintf(tmp_ctx, 
+                               "CN=%s,CN=Servers,CN=%s,CN=Sites,%s",
+                               libnet_r->in.netbios_name, site_name, 
config_dn);
+       if (!server_dn) {
+               libnet_r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       schema_dn = talloc_asprintf(tmp_ctx, "CN=Schema,%s", config_dn);
+       if (!schema_dn) {
+               libnet_r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       ntds_dn = talloc_asprintf(tmp_ctx,
+                               "CN=NTDS Settings,%s", server_dn);
+       if (!ntds_dn) {
+               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>.
+       */      
+
+       remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s";, 
+                                         libnet_r->out.samr_binding->host);
+       if (!remote_ldb_url) {
+               libnet_r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       remote_ldb = ldb_wrap_connect(tmp_ctx, remote_ldb_url, 0, NULL);
+       if (!remote_ldb) {
+               libnet_r->out.error_string = NULL;
+               talloc_free(tmp_ctx);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       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(remote_ldb, msg, "objectClass", "server");
+       if (rtn != 0) {
+               libnet_r->out.error_string = NULL;
+               return NT_STATUS_NO_MEMORY;
+       }
+       rtn = ldb_msg_add_string(remote_ldb, msg, "systemFlags", "50000000");
+       if (rtn != 0) {
+               libnet_r->out.error_string = NULL;
+               return NT_STATUS_NO_MEMORY;
+       }
+       rtn = ldb_msg_add_string(remote_ldb, msg, 
"serverReference",libnet_r->out.account_dn_str);
+       if (rtn != 0) {
+               libnet_r->out.error_string = NULL;
+               return NT_STATUS_NO_MEMORY;
+       }
+       account_dn = ldb_dn_explode(tmp_ctx, server_dn);
+       if (account_dn == NULL) {
+               libnet_r->out.error_string = talloc_asprintf(mem_ctx, 
+                                       "Invalid account dn: %s",
+                                       server_dn);
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       msg->dn = account_dn; 
+       msg->elements->flags = LDB_FLAG_MOD_ADD;
+
+       rtn = ldb_add(remote_ldb, msg);
+       if (rtn != 0) {
+               libnet_r->out.error_string
+                       = talloc_asprintf(mem_ctx,
+                               "Failed to add server entry %s: %s.",
+                               server_dn,
+                               ldb_errstring(remote_ldb));
+               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;
+       talloc_steal(libnet_r, server_dn);
+       
        talloc_free(tmp_ctx);
-
-       return NT_STATUS_OK;
+       return status;
 }
 
+
+
 static NTSTATUS libnet_Join_primary_domain(struct libnet_context *ctx, 
                                           TALLOC_CTX *mem_ctx, 
                                           struct libnet_Join *r)
 {
        NTSTATUS status;
-       int ret;
-
+       TALLOC_CTX *tmp_mem = talloc_new(mem_ctx);
+       struct libnet_JoinDomain *r2;
+       int ret, rtn;
        struct ldb_context *ldb;
-       struct libnet_JoinDomain r2;
-       const struct ldb_dn *base_dn = ldb_dn_explode(mem_ctx, "cn=Primary 
Domains");
-       const struct ldb_val *prior_secret;
-       const struct ldb_val *prior_modified_time;
+       const struct ldb_dn *base_dn;
        struct ldb_message **msgs, *msg;
-       char *sct;
-       const char *attrs[] = {
+       const char *sct;
+       const char * const attrs[] = {
                "whenChanged",
                "secret",
-               "priorSecret"
+               "priorSecret",
                "priorChanged",
                NULL
        };
+       uint32_t acct_type = 0;
+       const char *account_name;
+       const char *netbios_name;
 
+       r2 = talloc(tmp_mem, struct libnet_JoinDomain);
+       if (!r2) {
+          r->out.error_string = NULL;
+          return NT_STATUS_NO_MEMORY;                               
+       }
+       
        if (r->in.secure_channel_type == SEC_CHAN_BDC) {
-               r2.in.acct_type = ACB_SVRTRUST;
+               acct_type = ACB_SVRTRUST;
        } else if (r->in.secure_channel_type == SEC_CHAN_WKSTA) {
-               r2.in.acct_type = ACB_WSTRUST;
+               acct_type = ACB_WSTRUST;
+       } else {
+               r->out.error_string = NULL;
+               talloc_free(tmp_mem);   
+               return NT_STATUS_INVALID_PARAMETER;
        }
-       r2.in.domain_name  = r->in.domain_name;
 
-       r2.in.account_name = talloc_asprintf(mem_ctx, "%s$", lp_netbios_name());
+       if ((r->in.netbios_name != NULL) && (r->in.level != 
LIBNET_JOIN_AUTOMATIC)) {
+               netbios_name = r->in.netbios_name;
+       } else {
+               netbios_name = talloc_asprintf(tmp_mem, "%s", 
lp_netbios_name());       
+               if (!netbios_name) goto no_mem;
+       }
 
-       /* Local secrets are stored in secrets.ldb */
-       ldb = secrets_db_connect(mem_ctx);
+       account_name = talloc_asprintf(tmp_mem, "%s$", netbios_name);           
        
+       if (!account_name) goto no_mem;
+       
+       /*
+        * 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);                                      
        
        if (!ldb) {
                r->out.error_string
                        = talloc_asprintf(mem_ctx, 
@@ -671,102 +1008,149 @@
                return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
        }
 
-       /* join domain */
-       status = libnet_JoinDomain(ctx, mem_ctx, &r2);
-
-       r->out.error_string = r2.out.error_string;
+       /*
+        * 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            = r->in.level;
+       r2->in.acct_type                = acct_type;
+       status = libnet_JoinDomain(ctx, tmp_mem, r2);
        if (!NT_STATUS_IS_OK(status)) {
+               r->out.error_string = talloc_steal(mem_ctx, 
r2->out.error_string);
                return status;
        }
 
-       sct = talloc_asprintf(mem_ctx, "%d", r->in.secure_channel_type);
-       msg = ldb_msg_new(mem_ctx);
+       /*
+        * now prepare the record for secrets.ldb
+        */
+       sct = talloc_asprintf(tmp_mem, "%d", r->in.secure_channel_type); 
+       if (!sct) goto no_mem;
+       
+       msg = ldb_msg_new(tmp_mem);
+       if (!msg) goto no_mem;
 
-       /* search for the secret record */
-       ret = gendb_search(ldb,
-                          mem_ctx, base_dn,
-                          &msgs, attrs,
-                          "(|" SECRETS_PRIMARY_DOMAIN_FILTER "(realm=%s))",
-                          r2.out.domain_name, r2.out.realm);
+       base_dn = ldb_dn_explode(tmp_mem, "cn=Primary Domains");
+       if (!base_dn) goto no_mem;
 
-       msg->dn = ldb_dn_build_child(mem_ctx, "flatname", r2.out.domain_name, 
base_dn);
-       
-       samdb_msg_add_string(ldb, mem_ctx, msg, "flatname", r2.out.domain_name);
-       if (r2.out.realm) {
-               samdb_msg_add_string(ldb, mem_ctx, msg, "realm", r2.out.realm);
+       msg->dn = ldb_dn_build_child(tmp_mem, "flatname", r2->out.domain_name, 
base_dn);
+       if (!msg->dn) goto no_mem;
+
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "flatname", 
r2->out.domain_name);
+       if (rtn == -1) goto no_mem;
+
+       if (r2->out.realm) {
+               rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "realm", 
r2->out.realm);
+               if (rtn == -1) goto no_mem;
        }
-       samdb_msg_add_string(ldb, mem_ctx, msg, "objectClass", "primaryDomain");
-       samdb_msg_add_string(ldb, mem_ctx, msg, "secret", r2.out.join_password);
-       
-       samdb_msg_add_string(ldb, mem_ctx, msg, "samAccountName", 
r2.in.account_name);
-       
-       samdb_msg_add_string(ldb, mem_ctx, msg, "secureChannelType", sct);
 
-       if (r2.out.kvno) {
-               samdb_msg_add_uint(ldb, mem_ctx, msg, "msDS-KeyVersionNumber",
-                                  r2.out.kvno);
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "objectClass", 
"primaryDomain");
+       if (rtn == -1) goto no_mem;
+
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "secret", 
r2->out.join_password);
+       if (rtn == -1) goto no_mem;
+
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "samAccountName", 
r2->in.account_name);
+       if (rtn == -1) goto no_mem;
+
+       rtn = samdb_msg_add_string(ldb, tmp_mem, msg, "secureChannelType", sct);
+       if (rtn == -1) goto no_mem;
+
+       if (r2->out.kvno) {
+               rtn = samdb_msg_add_uint(ldb, tmp_mem, msg, 
"msDS-KeyVersionNumber",
+                                        r2->out.kvno);
+               if (rtn == -1) goto no_mem;
        }
 
+       /* 
+        * search for the secret record
+        * - remove the records we find
+        * - and fetch the old secret and store it under priorSecret
+        */
+       ret = gendb_search(ldb,
+                          tmp_mem, base_dn,
+                          &msgs, attrs,
+                          "(|" SECRETS_PRIMARY_DOMAIN_FILTER "(realm=%s))",
+                          r2->out.domain_name, r2->out.realm);
        if (ret == 0) {
        } else if (ret == -1) {
                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));
+                                         r2->out.domain_name, r2->out.realm, 
ldb_errstring(ldb));
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        } else {
+               const struct ldb_val *prior_secret;
+               const struct ldb_val *prior_modified_time;
                int i;
+
                for (i = 0; i < ret; i++) {
                        ldb_delete(ldb, msgs[i]->dn);
                }
 
                prior_secret = ldb_msg_find_ldb_val(msgs[0], "secret");
                if (prior_secret) {
-                       samdb_msg_set_value(ldb, mem_ctx, msg, "priorSecret", 
prior_secret);
+                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, 
"priorSecret", prior_secret);
+                       if (rtn == -1) goto no_mem;
                }
-               samdb_msg_set_string(ldb, mem_ctx, msg, "secret", 
r2.out.join_password);
-               
+               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "secret", 
r2->out.join_password);
+               if (rtn == -1) goto no_mem;
+
                prior_modified_time = ldb_msg_find_ldb_val(msgs[0], 
                                                           "whenChanged");
                if (prior_modified_time) {
-                       samdb_msg_set_value(ldb, mem_ctx, msg, 
"priorWhenChanged", 
-                                           prior_modified_time);
+                       rtn = samdb_msg_set_value(ldb, tmp_mem, msg, 
"priorWhenChanged", 
+                                                 prior_modified_time);
+                       if (rtn == -1) goto no_mem;
                }
-               
-               samdb_msg_set_string(ldb, mem_ctx, msg, "samAccountName", 
r2.in.account_name);
-               samdb_msg_set_string(ldb, mem_ctx, msg, "secureChannelType", 
sct);
+
+               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, "samAccountName", 
r2->in.account_name);
+               if (rtn == -1) goto no_mem;
+
+               rtn = samdb_msg_set_string(ldb, tmp_mem, msg, 
"secureChannelType", sct);
+               if (rtn == -1) goto no_mem;
        }
 
        /* create the secret */
-       ret = samdb_add(ldb, mem_ctx, msg);
+       ret = samdb_add(ldb, tmp_mem, 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\n", 
+                                                     ldb_dn_linearize(ldb, 
msg->dn));
+               talloc_free(tmp_mem);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
+
+       /* move all out parameter to the callers TALLOC_CTX */
+       r->out.error_string     = NULL;
+       r->out.join_password    = r2->out.join_password;
+       talloc_steal(r, r2->out.join_password);
+       r->out.domain_sid       = r2->out.domain_sid;
+       talloc_steal(r, r2->out.domain_sid);
+       talloc_free(tmp_mem);
        return NT_STATUS_OK;
+no_mem:
+       r->out.error_string = NULL;
+       talloc_free(tmp_mem);   
+       return NT_STATUS_NO_MEMORY;
 }
 
 NTSTATUS libnet_Join(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct 
libnet_Join *r)
 {
-       NTSTATUS nt_status;
-       struct libnet_Join r2;
-       r2.in.secure_channel_type = r->in.secure_channel_type;
-       r2.in.domain_name = r->in.domain_name;
-       
-       if ((r->in.secure_channel_type == SEC_CHAN_WKSTA)
-           || (r->in.secure_channel_type == SEC_CHAN_BDC)) {
-               nt_status = libnet_Join_primary_domain(ctx, mem_ctx, &r2);
-       } else {
-               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);
-               return NT_STATUS_INVALID_PARAMETER;
+       switch (r->in.secure_channel_type) {
+               case SEC_CHAN_WKSTA:
+                       return libnet_Join_primary_domain(ctx, mem_ctx, r);
+               case SEC_CHAN_BDC:
+                       return libnet_Join_primary_domain(ctx, mem_ctx, r);
+               case SEC_CHAN_DOMAIN:
+                       break;
        }
-       r->out.error_string = r2.out.error_string;
-       return nt_status;
+
+       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);
+       return NT_STATUS_INVALID_PARAMETER;
 }
 
 
=== libnet/libnet_join.h
==================================================================
--- libnet/libnet_join.h  (revision 5907)
+++ libnet/libnet_join.h  (local)
@@ -3,6 +3,7 @@
    
    Copyright (C) Stefan Metzmacher     2004
    Copyright (C) Andrew Bartlett <abartlet@xxxxxxxxx> 2005
+   Copyright (C) Brad Henry 2005
    
    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
@@ -21,10 +22,17 @@
 
 #include "librpc/gen_ndr/ndr_netlogon.h"
 
+enum libnet_Join_level {
+       LIBNET_JOIN_AUTOMATIC,
+       LIBNET_JOIN_SPECIFIED,
+};
+
 struct libnet_JoinDomain {
        struct {
                const char *domain_name;
                const char *account_name;
+               const char *netbios_name;
+               enum libnet_Join_level level;
                uint32_t  acct_type;
        } in;
 
@@ -34,18 +42,29 @@
                struct dom_sid *domain_sid;
                const char *domain_name;
                const char *realm;
-               unsigned int kvno;
+               const char *domain_dn_str;
+               const char *account_dn_str;
+               const char *server_dn_str;
+               unsigned int kvno; /* msDS-KeyVersionNumber */
+               struct dcerpc_pipe *dcerpc_pipe; 
+               struct dcerpc_pipe *samr_pipe;
+               struct dcerpc_binding *samr_binding;
+               struct policy_handle *user_handle;
        } out;
 };
 
 struct libnet_Join {
        struct {
                const char *domain_name;
+               const char *netbios_name;
                enum netr_SchannelType secure_channel_type;
+               enum libnet_Join_level level;
        } in;
        
        struct {
                const char *error_string;
+               const char *join_password;
+               struct dom_sid *domain_sid;
        } out;
 };
 
=== torture/config.mk
==================================================================
--- torture/config.mk  (revision 5907)
+++ torture/config.mk  (local)
@@ -71,6 +71,7 @@
 # Start SUBSYSTEM TORTURE_RPC
 [SUBSYSTEM::TORTURE_RPC]
 ADD_OBJ_FILES = \
+               torture/rpc/join.o \
                torture/rpc/lsa.o \
                torture/rpc/session_key.o \
                torture/rpc/echo.o \
=== torture/rpc/testjoin.c
==================================================================
--- torture/rpc/testjoin.c  (revision 5907)
+++ torture/rpc/testjoin.c  (local)
@@ -29,10 +29,15 @@
 #include "librpc/gen_ndr/ndr_samr.h"
 #include "system/time.h"
 #include "lib/crypto/crypto.h"
+#include "libnet/libnet.h"
+#include "lib/cmdline/popt_common.h"
+#include "lib/ldb/include/ldb.h"
 
+
 struct test_join {
        struct dcerpc_pipe *p;
        struct policy_handle user_handle;
+       struct libnet_JoinDomain *libnet_r;
        const char *dom_sid;
 };
 
@@ -273,12 +278,43 @@
 
 struct test_join *torture_join_domain(const char *machine_name, 
                                      const char *domain,
-                                     uint16_t acct_flags,
+                                     uint32_t acct_flags,
                                      const char **machine_password)
 {
-       char *username = talloc_asprintf(NULL, "%s$", machine_name);
-       struct test_join *tj = torture_create_testuser(username, domain, 
acct_flags, machine_password);
-       talloc_free(username);
+       NTSTATUS status;
+       struct libnet_context *libnet_ctx;
+       struct libnet_JoinDomain *libnet_r;
+       struct test_join *tj;
+       
+       tj = talloc(NULL, struct test_join);
+       libnet_r = talloc(tj, struct libnet_JoinDomain);
+       //libnet_r = tj->libnet_r;
+       libnet_ctx = libnet_context_init(NULL); 
+       tj->libnet_r = libnet_r;
+       
+       
+       libnet_ctx->cred = cmdline_credentials;
+       libnet_r->in.domain_name = domain;
+       libnet_r->in.level = LIBNET_JOIN_SPECIFIED;
+       libnet_r->in.netbios_name = machine_name;
+       libnet_r->in.account_name = talloc_asprintf(libnet_r, "%s$", 
libnet_r->in.netbios_name);
+       libnet_r->in.acct_type = acct_flags;
+
+       status = libnet_JoinDomain(libnet_ctx, tj, libnet_r);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Domain join failed - %s.\n", nt_errstr(status)));
+                return NULL;
+       }
+        DEBUG(0, ("%s joined domain %s.\n", 
+                       libnet_r->in.netbios_name, 
+                       libnet_r->in.domain_name));
+
+       tj->p = libnet_r->out.samr_pipe;
+       tj->user_handle = *libnet_r->out.user_handle;
+       tj->dom_sid = dom_sid_string(tj, libnet_r->out.domain_sid);
+       *machine_password = NULL;
+       *machine_password = talloc_steal(tj,libnet_r->out.join_password);
+       printf("machine password: %s.\n",*machine_password);
        return tj;
 }
 
@@ -292,24 +328,85 @@
        return &join->user_handle;
 }
 
+NTSTATUS torture_leave_ads_domain(TALLOC_CTX *mem_ctx, struct 
libnet_JoinDomain *libnet_r)
+{
+        NTSTATUS status;
+        int rtn;
+        TALLOC_CTX *tmp_ctx;
+        
+        struct ldb_dn *account_dn;
+        struct ldb_context *ldb_ctx;
+ 
+        char *remote_ldb_url;
+  
+        /* Check if we are a domain controller. If not, exit. */
+        if (!libnet_r->out.server_dn_str) {
+         return NT_STATUS_OK;
+        }
+        
+        tmp_ctx = talloc_named(mem_ctx, 0, "torture_leave temporary context");
+        if (!tmp_ctx) {
+          libnet_r->out.error_string = NULL;
+          return NT_STATUS_NO_MEMORY;
+        }
+    
+        ldb_ctx = ldb_init(tmp_ctx);
+        if (!ldb_ctx) {
+          talloc_free(tmp_ctx);
+          libnet_r->out.error_string = NULL;
+          return NT_STATUS_NO_MEMORY;
+        }
+        
+        /* Remove CN=Servers,... entry from the AD. */ 
+        account_dn = ldb_dn_explode(tmp_ctx, libnet_r->out.server_dn_str);
+        if (!account_dn) goto err;
+ 
+        remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s";, 
libnet_r->out.samr_binding->host);
+        if (!remote_ldb_url) goto err;
+ 
+        rtn = ldb_connect(ldb_ctx, remote_ldb_url, 0, NULL);
+        if (rtn != 0) goto err;
+ 
+        rtn = ldb_delete(ldb_ctx, account_dn);
+        if (rtn != 0) goto err;
+ 
+        DEBUG(0, ("%s removed successfully.\n", libnet_r->out.server_dn_str));
+ 
+        talloc_free(tmp_ctx); 
+        return status;
+
+
+err:
+        talloc_free(tmp_ctx);
+        libnet_r->out.error_string = NULL;
+        return NT_STATUS_UNSUCCESSFUL;
+
+}
+
 /*
   leave the domain, deleting the machine acct
 */
+
 void torture_leave_domain(struct test_join *join)
 {
        struct samr_DeleteUser d;
        NTSTATUS status;
-
-       if (!GUID_all_zero(&join->user_handle.uuid)) {
-               d.in.user_handle = &join->user_handle;
-               d.out.user_handle = &join->user_handle;
-               
-               status = dcerpc_samr_DeleteUser(join->p, join, &d);
-               if (!NT_STATUS_IS_OK(status)) {
-                       printf("Delete of machine account failed\n");
-               }
+                       
+       d.in.user_handle = &join->user_handle;
+       d.out.user_handle = &join->user_handle;
+                                       
+       /* Delete machine account */                                            
                                                                                
                                                                                
                                                                                
                        
+       status = dcerpc_samr_DeleteUser(join->p, join, &d);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Delete of machine account failed\n");
+       } else {
+               printf("Delete of machine account was successful.\n");
        }
-
+       
+       if (join->libnet_r) {
+               status = torture_leave_ads_domain(join, join->libnet_r);
+       }
+       
        talloc_free(join);
 }
 
=== torture/rpc/join.c
==================================================================
--- torture/rpc/join.c  (revision 5907)
+++ torture/rpc/join.c  (local)
@@ -0,0 +1,51 @@
+#include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "libnet/libnet.h"
+#include "lib/ldb/include/ldb.h"
+
+#define TORTURE_NETBIOS_NAME "smbtorturejoin"
+
+
+BOOL torture_rpc_join(void)
+{  
+        BOOL rtn = True;
+              
+        struct test_join *tj;
+        const char **machine_password;
+  
+        /* Join domain as a member server. */
+        tj = torture_join_domain(TORTURE_NETBIOS_NAME,
+                                  lp_workgroup(),
+                                  ACB_WSTRUST,
+                                  machine_password);
+
+        if (!tj) {
+          DEBUG(0, ("%s failed to join domain %s.\n",
+                      TORTURE_NETBIOS_NAME,
+                      lp_workgroup()));
+          return False;
+        }
+        
+        /* Leave domain. */                          
+        torture_leave_domain(tj);
+        
+        /* Join domain as a domain controller. */
+        tj = torture_join_domain(TORTURE_NETBIOS_NAME,
+                                  lp_workgroup(),
+                                  ACB_SVRTRUST,
+                                  machine_password);
+        if (!tj) {
+          DEBUG(0, ("%s failed to join domain %s.\n",
+                      TORTURE_NETBIOS_NAME,
+                      lp_workgroup()));
+          return False;
+        }
+        
+        /* Leave domain. */
+        torture_leave_domain(tj);
+        
+        rtn = torture_rpc_samlogon();
+        return rtn;      
+}
+
+
=== torture/torture.c
==================================================================
--- torture/torture.c  (revision 5907)
+++ torture/torture.c  (local)
@@ -2313,6 +2313,7 @@
        {"RPC-ROT", torture_rpc_rot, 0},
        {"RPC-DSSETUP", torture_rpc_dssetup, 0},
         {"RPC-ALTERCONTEXT", torture_rpc_alter_context, 0},
+        {"RPC-JOIN", torture_rpc_join, 0},
 
        /* local (no server) testers */
        {"LOCAL-NTLMSSP", torture_ntlmssp_self_check, 0},
=== utils/net/net_join.c
==================================================================
--- utils/net/net_join.c  (revision 5907)
+++ utils/net/net_join.c  (local)
@@ -29,7 +29,7 @@
 {
        NTSTATUS status;
        struct libnet_context *libnetctx;
-       struct libnet_Join r;
+       struct libnet_Join *r;
        char *tmp;
        const char *domain_name;
        enum netr_SchannelType secure_channel_type = SEC_CHAN_WKSTA;
@@ -62,23 +62,28 @@
                return -1;      
        }
        libnetctx->cred = ctx->credentials;
-
+       r = talloc(ctx->mem_ctx, struct libnet_Join);
        /* prepare password change */
-       r.in.domain_name         = domain_name;
-       r.in.secure_channel_type = secure_channel_type;
-       r.out.error_string       = NULL;
-
+       r->in.domain_name        = domain_name;
+       r->in.secure_channel_type = secure_channel_type;
+       r->out.error_string       = NULL;
+       r->in.level              = LIBNET_JOIN_AUTOMATIC;
+       /*
+        Valgrind complains about an uninitialized value
+        if we don't set netbios_name here.
+       */
+       r->in.netbios_name       = lp_netbios_name();
+       
        /* do the domain join */
-       status = libnet_Join(libnetctx, ctx->mem_ctx, &r);
+       status = libnet_Join(libnetctx, ctx->mem_ctx, r);
+       
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0,("libnet_Join returned %s: %s\n",
                         nt_errstr(status),
-                        r.out.error_string));
+                        r->out.error_string));
                return -1;
        }
-
        talloc_free(libnetctx);
-
        return 0;
 }
 
<Prev in Thread] Current Thread [Next in Thread>