This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
*/
#include "includes.h"
-#include "librpc/gen_ndr/ndr_samr.h"
+#include "torture/torture.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"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+
+#include "libcli/auth/libcli_auth.h"
+#include "torture/rpc/rpc.h"
+#include "libcli/security/security.h"
struct test_join {
struct dcerpc_pipe *p;
struct policy_handle user_handle;
- const char *dom_sid;
+ struct libnet_JoinDomain *libnet_r;
+ struct dom_sid *dom_sid;
+ const char *dom_netbios_name;
+ const char *dom_dns_name;
+ struct dom_sid *user_sid;
+ struct GUID user_guid;
+ const char *netbios_name;
};
uint32_t rid;
DATA_BLOB session_key;
struct lsa_String name;
- struct lsa_String comment;
- struct lsa_String full_name;
int policy_min_pw_len = 0;
struct test_join *join;
char *random_pw;
+ const char *dc_binding = lp_parm_string(-1, "torture", "dc_binding");
join = talloc(NULL, struct test_join);
if (join == NULL) {
ZERO_STRUCTP(join);
printf("Connecting to SAMR\n");
-
- status = torture_rpc_connection(join,
- &join->p,
- DCERPC_SAMR_NAME,
- DCERPC_SAMR_UUID,
- DCERPC_SAMR_VERSION);
+
+ if (dc_binding) {
+ status = dcerpc_pipe_connect(join,
+ &join->p,
+ dc_binding,
+ &dcerpc_table_samr,
+ cmdline_credentials, NULL);
+
+ } else {
+ status = torture_rpc_connection(join,
+ &join->p,
+ &dcerpc_table_samr);
+ }
if (!NT_STATUS_IS_OK(status)) {
- goto failed;
+ return NULL;
}
c.in.system_name = NULL;
errstr = dcerpc_errstr(join, join->p->last_fault_code);
}
printf("samr_Connect failed - %s\n", errstr);
- goto failed;
+ return NULL;
}
printf("Opening domain %s\n", domain);
goto failed;
}
- join->dom_sid = dom_sid_string(join, l.out.sid);
+ talloc_steal(join, l.out.sid);
+ join->dom_sid = l.out.sid;
+ join->dom_netbios_name = talloc_strdup(join, domain);
+ if (!join->dom_netbios_name) goto failed;
o.in.connect_handle = &handle;
o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
goto failed;
}
+ join->user_sid = dom_sid_add_rid(join, join->dom_sid, rid);
+
pwp.in.user_handle = &join->user_handle;
status = dcerpc_samr_GetUserPwInfo(join->p, join, &pwp);
s.in.info = &u;
s.in.level = 21;
- u.info21.acct_flags = acct_type;
+ u.info21.acct_flags = acct_type | ACB_PWNOEXP;
u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
- comment.string = talloc_asprintf(join,
- "Tortured by Samba4: %s",
- timestring(join, time(NULL)));
- u.info21.comment = comment;
- full_name.string = talloc_asprintf(join,
- "Torture account for Samba4: %s",
- timestring(join, time(NULL)));
- u.info21.full_name = full_name;
+ u.info21.comment.string = talloc_asprintf(join,
+ "Tortured by Samba4: %s",
+ timestring(join, time(NULL)));
+
+ u.info21.full_name.string = talloc_asprintf(join,
+ "Torture account for Samba4: %s",
+ timestring(join, time(NULL)));
+
u.info21.description.string = talloc_asprintf(join,
"Samba4 torture account created by host %s: %s",
lp_netbios_name(), timestring(join, time(NULL)));
}
-struct test_join *torture_join_domain(const char *machine_name,
- const char *domain,
- uint16_t acct_flags,
- const char **machine_password)
+_PUBLIC_ struct test_join *torture_join_domain(const char *machine_name,
+ uint32_t acct_flags,
+ struct cli_credentials **machine_credentials)
{
- 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;
+ struct samr_SetUserInfo s;
+ union samr_UserInfo u;
+
+ 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.binding = lp_parm_string(-1, "torture", "binding");
+ if (!libnet_r->in.binding) {
+ libnet_r->in.binding = talloc_asprintf(libnet_r, "ncacn_np:%s", lp_parm_string(-1, "torture", "host"));
+ }
+ libnet_r->in.level = LIBNET_JOINDOMAIN_SPECIFIED;
+ libnet_r->in.netbios_name = machine_name;
+ libnet_r->in.account_name = talloc_asprintf(libnet_r, "%s$", machine_name);
+ if (!libnet_r->in.account_name) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ libnet_r->in.acct_type = acct_flags;
+ libnet_r->in.recreate_account = True;
+
+ status = libnet_JoinDomain(libnet_ctx, libnet_r, libnet_r);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (libnet_r->out.error_string) {
+ DEBUG(0, ("Domain join failed - %s\n", libnet_r->out.error_string));
+ } else {
+ DEBUG(0, ("Domain join failed - %s\n", nt_errstr(status)));
+ }
+ talloc_free(tj);
+ return NULL;
+ }
+ tj->p = libnet_r->out.samr_pipe;
+ tj->user_handle = *libnet_r->out.user_handle;
+ tj->dom_sid = libnet_r->out.domain_sid;
+ talloc_steal(tj, libnet_r->out.domain_sid);
+ tj->dom_netbios_name = libnet_r->out.domain_name;
+ talloc_steal(tj, libnet_r->out.domain_name);
+ tj->dom_dns_name = libnet_r->out.realm;
+ talloc_steal(tj, libnet_r->out.realm);
+ tj->user_guid = libnet_r->out.account_guid;
+ tj->netbios_name = talloc_strdup(tj, machine_name);
+ if (!tj->netbios_name) {
+ talloc_free(tj);
+ return NULL;
+ }
+
+ ZERO_STRUCT(u);
+ s.in.user_handle = &tj->user_handle;
+ s.in.info = &u;
+ s.in.level = 21;
+
+ u.info21.fields_present = SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
+ u.info21.comment.string = talloc_asprintf(tj,
+ "Tortured by Samba4: %s",
+ timestring(tj, time(NULL)));
+ u.info21.full_name.string = talloc_asprintf(tj,
+ "Torture account for Samba4: %s",
+ timestring(tj, time(NULL)));
+
+ u.info21.description.string = talloc_asprintf(tj,
+ "Samba4 torture account created by host %s: %s",
+ lp_netbios_name(), timestring(tj, time(NULL)));
+
+ status = dcerpc_samr_SetUserInfo(tj->p, tj, &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("SetUserInfo (non-critical) failed - %s\n", nt_errstr(status));
+ }
+
+ *machine_credentials = cli_credentials_init(tj);
+ cli_credentials_set_conf(*machine_credentials);
+ cli_credentials_set_workstation(*machine_credentials, machine_name, CRED_SPECIFIED);
+ cli_credentials_set_domain(*machine_credentials, libnet_r->out.domain_name, CRED_SPECIFIED);
+ if (libnet_r->out.realm) {
+ cli_credentials_set_realm(*machine_credentials, libnet_r->out.realm, CRED_SPECIFIED);
+ }
+ cli_credentials_set_username(*machine_credentials, libnet_r->in.account_name, CRED_SPECIFIED);
+ cli_credentials_set_password(*machine_credentials, libnet_r->out.join_password, CRED_SPECIFIED);
+ if (acct_flags & ACB_SVRTRUST) {
+ cli_credentials_set_secure_channel_type(*machine_credentials,
+ SEC_CHAN_BDC);
+ } else if (acct_flags & ACB_WSTRUST) {
+ cli_credentials_set_secure_channel_type(*machine_credentials,
+ SEC_CHAN_WKSTA);
+ } else {
+ DEBUG(0, ("Invalid account type specificed to torture_join_domain\n"));
+ talloc_free(*machine_credentials);
+ return NULL;
+ }
+
return tj;
}
return &join->user_handle;
}
+NTSTATUS torture_leave_ads_domain(TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *libnet_r)
+{
+ int rtn;
+ TALLOC_CTX *tmp_ctx;
+
+ struct ldb_dn *server_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) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Remove CN=Servers,... entry from the AD. */
+ server_dn = ldb_dn_new(tmp_ctx, ldb_ctx, libnet_r->out.server_dn_str);
+ if (! ldb_dn_validate(server_dn)) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ 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;
+ }
+
+ ldb_set_opaque(ldb_ctx, "credentials", cmdline_credentials);
+
+ rtn = ldb_connect(ldb_ctx, remote_ldb_url, 0, NULL);
+ if (rtn != 0) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ rtn = ldb_delete(ldb_ctx, server_dn);
+ if (rtn != 0) {
+ libnet_r->out.error_string = NULL;
+ talloc_free(tmp_ctx);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(0, ("%s removed successfully.\n", libnet_r->out.server_dn_str));
+
+ talloc_free(tmp_ctx);
+ return NT_STATUS_OK;
+}
+
/*
leave the domain, deleting the machine acct
*/
-void torture_leave_domain(struct test_join *join)
+
+_PUBLIC_ 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");
- }
+ if (!join) {
+ return;
+ }
+ 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);
}
/*
return the dom sid for a test join
*/
-const char *torture_join_sid(struct test_join *join)
+_PUBLIC_ const struct dom_sid *torture_join_sid(struct test_join *join)
{
return join->dom_sid;
}
+const struct dom_sid *torture_join_user_sid(struct test_join *join)
+{
+ return join->user_sid;
+}
+
+const char *torture_join_netbios_name(struct test_join *join)
+{
+ return join->netbios_name;
+}
+
+const struct GUID *torture_join_user_guid(struct test_join *join)
+{
+ return &join->user_guid;
+}
+
+const char *torture_join_dom_netbios_name(struct test_join *join)
+{
+ return join->dom_netbios_name;
+}
+
+const char *torture_join_dom_dns_name(struct test_join *join)
+{
+ return join->dom_dns_name;
+}
+
struct test_join_ads_dc {
struct test_join *join;
struct test_join_ads_dc *torture_join_domain_ads_dc(const char *machine_name,
const char *domain,
- const char **machine_password)
+ struct cli_credentials **machine_credentials)
{
struct test_join_ads_dc *join;
return NULL;
}
- join->join = torture_join_domain(machine_name, domain,
+ join->join = torture_join_domain(machine_name,
ACB_SVRTRUST,
- machine_password);
+ machine_credentials);
if (!join->join) {
return NULL;
}
- /* do netlogon DrsEnumerateDomainTrusts */
-
- /* modify userAccountControl from 4096 to 532480 */
+/* W2K: */
+ /* W2K: modify userAccountControl from 4096 to 532480 */
- /* modify RDN to OU=Domain Controllers and skip the $ from server name */
+ /* W2K: modify RDN to OU=Domain Controllers and skip the $ from server name */
/* ask objectVersion of Schema Partition */
* serverReferenz = CN=<machine_name>,OU=Domain Controllers,...
*/
- /* DsReplicaAdd to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
- * needs to be tested
+ /* DsAddEntry to create the CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
+ *
+ */
+
+ /* replicate CN=Schema,CN=Configuration,...
+ * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
+ *
+ */
+
+ /* replicate CN=Configuration,...
+ * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
+ *
+ */
+
+ /* replicate Domain Partition
+ * using DRSUAPI_DS_BIND_GUID_W2K ("6abec3d1-3054-41c8-a362-5a0c5b7d5d71")
+ *
+ */
+
+ /* call DsReplicaUpdateRefs() for all partitions like this:
+ * req1: struct drsuapi_DsReplicaUpdateRefsRequest1
+ * naming_context : *
+ * naming_context: struct drsuapi_DsReplicaObjectIdentifier
+ * __ndr_size : 0x000000ae (174)
+ * __ndr_size_sid : 0x00000000 (0)
+ * guid : 00000000-0000-0000-0000-000000000000
+ * sid : S-0-0
+ * dn : 'CN=Schema,CN=Configuration,DC=w2k3,DC=vmnet1,DC=vm,DC=base'
+ * dest_dsa_dns_name : *
+ * dest_dsa_dns_name : '4a0df188-a0b8-47ea-bbe5-e614723f16dd._msdcs.w2k3.vmnet1.vm.base'
+ * dest_dsa_guid : 4a0df188-a0b8-47ea-bbe5-e614723f16dd
+ * options : 0x0000001c (28)
+ * 0: DRSUAPI_DS_REPLICA_UPDATE_ASYNCHRONOUS_OPERATION
+ * 0: DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE
+ * 1: DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE
+ * 1: DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE
+ * 1: DRSUAPI_DS_REPLICA_UPDATE_0x00000010
+ *
+ * 4a0df188-a0b8-47ea-bbe5-e614723f16dd is the objectGUID the DsAddEntry() returned for the
+ * CN=NTDS Settings,CN=<machine_name>,CN=Servers,CN=Default-First-Site-Name, ...
*/
+/* W2K3: see libnet/libnet_become_dc.c */
return join;
}
void torture_leave_domain_ads_dc(struct test_join_ads_dc *join)
{
+/* W2K3: see libnet/libnet_unbecome_dc.c */
if (join->join) {
torture_leave_domain(join->join);