|
|
Brad Henry wrote:
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.
The problem was that I was incorrectly passing the machine_password
variable into torture_join_domain(). Everything is working now as it
should, so let me know what you think.
I know this patch is pretty big, I promise to break it up a little next
time. :)
Brad
=== source/libnet/config.mk
==================================================================
--- source/libnet/config.mk (revision 5928)
+++ source/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
#################################
=== source/libnet/libnet_join.c
==================================================================
--- source/libnet/libnet_join.c (revision 5928)
+++ source/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;
}
=== source/libnet/libnet_join.h
==================================================================
--- source/libnet/libnet_join.h (revision 5928)
+++ source/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;
};
=== source/torture/config.mk
==================================================================
--- source/torture/config.mk (revision 5928)
+++ source/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 \
=== source/torture/rpc/testjoin.c
==================================================================
--- source/torture/rpc/testjoin.c (revision 5928)
+++ source/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,57 @@
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);
+ if (!tj) return NULL;
+
+ libnet_r = talloc(tj, struct libnet_JoinDomain);
+ if (!libnet_r) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ libnet_ctx = libnet_context_init(NULL);
+ if (!libnet_ctx) {
+ talloc_free(tj);
+ return 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);
+ if (!libnet_r->in.account_name) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ 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)));
+ talloc_free(tj);
+ 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 = libnet_r->out.join_password;
return tj;
}
@@ -292,24 +342,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);
}
=== source/torture/rpc/join.c
==================================================================
--- source/torture/rpc/join.c (revision 5928)
+++ source/torture/rpc/join.c (local)
@@ -0,0 +1,53 @@
+#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;
+
+}
+
+
=== source/torture/torture.c
==================================================================
--- source/torture/torture.c (revision 5928)
+++ source/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},
=== source/utils/net/net_join.c
==================================================================
--- source/utils/net/net_join.c (revision 5928)
+++ source/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,31 @@
return -1;
}
libnetctx->cred = ctx->credentials;
-
+ r = talloc(ctx->mem_ctx, struct libnet_Join);
+ if (!r) {
+ return -1;
+ }
/* 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;
}
|
|