summaryrefslogtreecommitdiff
path: root/source4/torture/libnet
diff options
context:
space:
mode:
Diffstat (limited to 'source4/torture/libnet')
-rw-r--r--source4/torture/libnet/domain.c113
-rw-r--r--source4/torture/libnet/groupinfo.c123
-rw-r--r--source4/torture/libnet/groupman.c91
-rw-r--r--source4/torture/libnet/grouptest.h20
-rw-r--r--source4/torture/libnet/libnet.c70
-rw-r--r--source4/torture/libnet/libnet_BecomeDC.c709
-rw-r--r--source4/torture/libnet/libnet_domain.c447
-rw-r--r--source4/torture/libnet/libnet_group.c393
-rw-r--r--source4/torture/libnet/libnet_lookup.c189
-rw-r--r--source4/torture/libnet/libnet_rpc.c226
-rw-r--r--source4/torture/libnet/libnet_share.c233
-rw-r--r--source4/torture/libnet/libnet_user.c736
-rw-r--r--source4/torture/libnet/userinfo.c202
-rw-r--r--source4/torture/libnet/userman.c461
-rw-r--r--source4/torture/libnet/usertest.h38
-rw-r--r--source4/torture/libnet/utils.c293
-rw-r--r--source4/torture/libnet/utils.h45
17 files changed, 4389 insertions, 0 deletions
diff --git a/source4/torture/libnet/domain.c b/source4/torture/libnet/domain.c
new file mode 100644
index 0000000000..ab7846e5e1
--- /dev/null
+++ b/source4/torture/libnet/domain.c
@@ -0,0 +1,113 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "lib/events/events.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+
+static bool test_domainopen(struct libnet_context *net_ctx, TALLOC_CTX *mem_ctx,
+ struct lsa_String *domname,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct libnet_DomainOpen io;
+
+ printf("opening domain\n");
+
+ io.in.domain_name = talloc_strdup(mem_ctx, domname->string);
+ io.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ status = libnet_DomainOpen(net_ctx, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Composite domain open failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ *domain_handle = io.out.domain_handle;
+ return true;
+}
+
+
+static bool test_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct samr_Close r;
+ struct policy_handle handle;
+
+ r.in.handle = domain_handle;
+ r.out.handle = &handle;
+
+ printf("closing domain handle\n");
+
+ status = dcerpc_samr_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_domainopen(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct libnet_context *net_ctx;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct policy_handle h;
+ struct lsa_String name;
+
+ mem_ctx = talloc_init("test_domain_open");
+
+ net_ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+
+ status = torture_rpc_connection(torture,
+ &net_ctx->samr.pipe,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ name.string = lp_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ if (!test_domainopen(net_ctx, mem_ctx, &name, &h)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_cleanup(net_ctx->samr.pipe, mem_ctx, &h)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/groupinfo.c b/source4/torture/libnet/groupinfo.c
new file mode 100644
index 0000000000..4ddb1cefbe
--- /dev/null
+++ b/source4/torture/libnet/groupinfo.c
@@ -0,0 +1,123 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "libnet/libnet.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/utils.h"
+
+#define TEST_GROUPNAME "libnetgroupinfotest"
+
+
+static bool test_groupinfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 *domain_sid, const char* group_name,
+ uint32_t *rid)
+{
+ const uint16_t level = 5;
+ NTSTATUS status;
+ struct libnet_rpc_groupinfo group;
+ struct dom_sid *group_sid;
+
+ group_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid);
+
+ group.in.domain_handle = *domain_handle;
+ group.in.sid = dom_sid_string(mem_ctx, group_sid);
+ group.in.level = level; /* this should be extended */
+
+ printf("Testing sync libnet_rpc_groupinfo (SID argument)\n");
+ status = libnet_rpc_groupinfo(p, mem_ctx, &group);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_userinfo - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ZERO_STRUCT(group);
+
+ group.in.domain_handle = *domain_handle;
+ group.in.sid = NULL;
+ group.in.groupname = TEST_GROUPNAME;
+ group.in.level = level;
+
+ printf("Testing sync libnet_rpc_groupinfo (groupname argument)\n");
+ status = libnet_rpc_groupinfo(p, mem_ctx, &group);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_groupinfo - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_groupinfo(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct policy_handle h;
+ struct lsa_String name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+
+ mem_ctx = talloc_init("test_userinfo");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ name.string = lp_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ if (!test_opendomain(torture, p, mem_ctx, &h, &name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_create(p, mem_ctx, &h, TEST_GROUPNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_groupinfo(p, mem_ctx, &h, &sid, TEST_GROUPNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_cleanup(p, mem_ctx, &h, TEST_GROUPNAME)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/groupman.c b/source4/torture/libnet/groupman.c
new file mode 100644
index 0000000000..51b1c65b30
--- /dev/null
+++ b/source4/torture/libnet/groupman.c
@@ -0,0 +1,91 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "torture/libnet/grouptest.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/utils.h"
+
+
+static bool test_groupadd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_rpc_groupadd group;
+
+ group.in.domain_handle = *domain_handle;
+ group.in.groupname = name;
+
+ printf("Testing libnet_rpc_groupadd\n");
+
+ status = libnet_rpc_groupadd(p, mem_ctx, &group);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_groupadd - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return ret;
+}
+
+
+bool torture_groupadd(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ const char *name = TEST_GROUPNAME;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_groupadd");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ torture_assert_ntstatus_ok(torture, status, "RPC connection");
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_groupadd(p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_group_cleanup(p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/grouptest.h b/source4/torture/libnet/grouptest.h
new file mode 100644
index 0000000000..9d030acd17
--- /dev/null
+++ b/source4/torture/libnet/grouptest.h
@@ -0,0 +1,20 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#define TEST_GROUPNAME "libnetgrptest"
diff --git a/source4/torture/libnet/libnet.c b/source4/torture/libnet/libnet.c
new file mode 100644
index 0000000000..8c8353e8d6
--- /dev/null
+++ b/source4/torture/libnet/libnet.c
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ Copyright (C) Jelmer Vernooij 2006
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/smbtorture.h"
+#include "librpc/rpc/dcerpc.h"
+#include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/lsa.h"
+#include "libnet/composite.h"
+#include "torture/libnet/proto.h"
+
+NTSTATUS torture_net_init(void)
+{
+ struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "NET");
+
+ torture_suite_add_simple_test(suite, "USERINFO", torture_userinfo);
+ torture_suite_add_simple_test(suite, "USERADD", torture_useradd);
+ torture_suite_add_simple_test(suite, "USERDEL", torture_userdel);
+ torture_suite_add_simple_test(suite, "USERMOD", torture_usermod);
+ torture_suite_add_simple_test(suite, "DOMOPEN", torture_domainopen);
+ torture_suite_add_simple_test(suite, "GROUPINFO", torture_groupinfo);
+ torture_suite_add_simple_test(suite, "GROUPADD", torture_groupadd);
+ torture_suite_add_simple_test(suite, "API-LOOKUP", torture_lookup);
+ torture_suite_add_simple_test(suite, "API-LOOKUPHOST", torture_lookup_host);
+ torture_suite_add_simple_test(suite, "API-LOOKUPPDC", torture_lookup_pdc);
+ torture_suite_add_simple_test(suite, "API-LOOKUPNAME", torture_lookup_sam_name);
+ torture_suite_add_simple_test(suite, "API-CREATEUSER", torture_createuser);
+ torture_suite_add_simple_test(suite, "API-DELETEUSER", torture_deleteuser);
+ torture_suite_add_simple_test(suite, "API-MODIFYUSER", torture_modifyuser);
+ torture_suite_add_simple_test(suite, "API-USERINFO", torture_userinfo_api);
+ torture_suite_add_simple_test(suite, "API-USERLIST", torture_userlist);
+ torture_suite_add_simple_test(suite, "API-GROUPINFO", torture_groupinfo_api);
+ torture_suite_add_simple_test(suite, "API-GROUPLIST", torture_grouplist);
+ torture_suite_add_simple_test(suite, "API-CREATEGROUP", torture_creategroup);
+ torture_suite_add_simple_test(suite, "API-RPCCONN-BIND", torture_rpc_connect_binding);
+ torture_suite_add_simple_test(suite, "API-RPCCONN-SRV", torture_rpc_connect_srv);
+ torture_suite_add_simple_test(suite, "API-RPCCONN-PDC", torture_rpc_connect_pdc);
+ torture_suite_add_simple_test(suite, "API-RPCCONN-DC", torture_rpc_connect_dc);
+ torture_suite_add_simple_test(suite, "API-RPCCONN-DCINFO", torture_rpc_connect_dc_info);
+ torture_suite_add_simple_test(suite, "API-LISTSHARES", torture_listshares);
+ torture_suite_add_simple_test(suite, "API-DELSHARE", torture_delshare);
+ torture_suite_add_simple_test(suite, "API-DOMOPENLSA", torture_domain_open_lsa);
+ torture_suite_add_simple_test(suite, "API-DOMCLOSELSA", torture_domain_close_lsa);
+ torture_suite_add_simple_test(suite, "API-DOMOPENSAMR", torture_domain_open_samr);
+ torture_suite_add_simple_test(suite, "API-DOMCLOSESAMR", torture_domain_close_samr);
+ torture_suite_add_simple_test(suite, "API-BECOME-DC", torture_net_become_dc);
+ torture_suite_add_simple_test(suite, "API-DOMLIST", torture_domain_list);
+
+ suite->description = talloc_strdup(suite, "libnet convenience interface tests");
+
+ torture_register_suite(suite);
+
+ return NT_STATUS_OK;
+}
diff --git a/source4/torture/libnet/libnet_BecomeDC.c b/source4/torture/libnet/libnet_BecomeDC.c
new file mode 100644
index 0000000000..463d2a5000
--- /dev/null
+++ b/source4/torture/libnet/libnet_BecomeDC.c
@@ -0,0 +1,709 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ libnet_BecomeDC() tests
+
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 2006
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "torture/torture.h"
+#include "torture/rpc/rpc.h"
+#include "libnet/libnet.h"
+#include "lib/events/events.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/util/dlinklist.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_drsuapi.h"
+#include "librpc/gen_ndr/ndr_drsblobs.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "system/time.h"
+#include "lib/ldb_wrap.h"
+#include "auth/auth.h"
+#include "param/param.h"
+#include "torture/util.h"
+#include "param/provision.h"
+
+struct test_become_dc_state {
+ struct libnet_context *ctx;
+ struct torture_context *tctx;
+ const char *netbios_name;
+ struct test_join *tj;
+ struct cli_credentials *machine_account;
+ struct dsdb_schema *self_made_schema;
+ const struct dsdb_schema *schema;
+
+ struct ldb_context *ldb;
+
+ struct {
+ uint32_t object_count;
+ struct drsuapi_DsReplicaObjectListItemEx *first_object;
+ struct drsuapi_DsReplicaObjectListItemEx *last_object;
+ } schema_part;
+
+ const char *targetdir;
+
+ struct loadparm_context *lp_ctx;
+};
+
+static NTSTATUS test_become_dc_prepare_db(void *private_data,
+ const struct libnet_BecomeDC_PrepareDB *p)
+{
+ struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
+ struct provision_settings settings;
+ struct provision_result result;
+ NTSTATUS status;
+
+ settings.site_name = p->dest_dsa->site_name;
+ settings.root_dn_str = p->forest->root_dn_str;
+ settings.domain_dn_str = p->domain->dn_str;
+ settings.config_dn_str = p->forest->config_dn_str;
+ settings.schema_dn_str = p->forest->schema_dn_str;
+ settings.server_dn_str = torture_join_server_dn_str(s->tj);
+ settings.invocation_id = &p->dest_dsa->invocation_id;
+ settings.netbios_name = p->dest_dsa->netbios_name;
+ settings.host_ip = NULL;
+ settings.realm = torture_join_dom_dns_name(s->tj);
+ settings.domain = torture_join_dom_netbios_name(s->tj);
+ settings.ntds_dn_str = p->dest_dsa->ntds_dn_str;
+ settings.machine_password = cli_credentials_get_password(s->machine_account);
+ settings.targetdir = s->targetdir;
+
+ status = provision_bare(s, s->lp_ctx, &settings, &result);
+
+ s->ldb = result.samdb;
+ s->lp_ctx = result.lp_ctx;
+ return NT_STATUS_OK;
+
+
+}
+
+static NTSTATUS test_become_dc_check_options(void *private_data,
+ const struct libnet_BecomeDC_CheckOptions *o)
+{
+ struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
+
+ DEBUG(0,("Become DC [%s] of Domain[%s]/[%s]\n",
+ s->netbios_name,
+ o->domain->netbios_name, o->domain->dns_name));
+
+ DEBUG(0,("Promotion Partner is Server[%s] from Site[%s]\n",
+ o->source_dsa->dns_name, o->source_dsa->site_name));
+
+ DEBUG(0,("Options:crossRef behavior_version[%u]\n"
+ "\tschema object_version[%u]\n"
+ "\tdomain behavior_version[%u]\n"
+ "\tdomain w2k3_update_revision[%u]\n",
+ o->forest->crossref_behavior_version,
+ o->forest->schema_object_version,
+ o->domain->behavior_version,
+ o->domain->w2k3_update_revision));
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_apply_schema(struct test_become_dc_state *s,
+ const struct libnet_BecomeDC_StoreChunk *c)
+{
+ WERROR status;
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
+ uint32_t object_count;
+ struct drsuapi_DsReplicaObjectListItemEx *first_object;
+ struct drsuapi_DsReplicaObjectListItemEx *cur;
+ uint32_t linked_attributes_count;
+ struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
+ const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
+ struct dsdb_extended_replicated_objects *objs;
+ struct repsFromTo1 *s_dsa;
+ char *tmp_dns_name;
+ struct ldb_message *msg;
+ struct ldb_val prefixMap_val;
+ struct ldb_message_element *prefixMap_el;
+ struct ldb_val schemaInfo_val;
+ char *sam_ldb_path;
+ uint32_t i;
+ int ret;
+ bool ok;
+
+ DEBUG(0,("Analyze and apply schema objects\n"));
+
+ s_dsa = talloc_zero(s, struct repsFromTo1);
+ NT_STATUS_HAVE_NO_MEMORY(s_dsa);
+ s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
+ NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
+
+ switch (c->ctr_level) {
+ case 1:
+ mapping_ctr = &c->ctr1->mapping_ctr;
+ object_count = s->schema_part.object_count;
+ first_object = s->schema_part.first_object;
+ linked_attributes_count = 0;
+ linked_attributes = NULL;
+ s_dsa->highwatermark = c->ctr1->new_highwatermark;
+ s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
+ s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
+ uptodateness_vector = NULL; /* TODO: map it */
+ break;
+ case 6:
+ mapping_ctr = &c->ctr6->mapping_ctr;
+ object_count = s->schema_part.object_count;
+ first_object = s->schema_part.first_object;
+ linked_attributes_count = 0; /* TODO: ! */
+ linked_attributes = NULL; /* TODO: ! */;
+ s_dsa->highwatermark = c->ctr6->new_highwatermark;
+ s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
+ s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
+ uptodateness_vector = c->ctr6->uptodateness_vector;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ s_dsa->replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+ | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+ | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
+ memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
+
+ tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+ tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+ s_dsa->other_info->dns_name = tmp_dns_name;
+
+ for (cur = first_object; cur; cur = cur->next_object) {
+ bool is_attr = false;
+ bool is_class = false;
+
+ for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
+ struct drsuapi_DsReplicaAttribute *a;
+ uint32_t j;
+ const char *oid = NULL;
+
+ a = &cur->object.attribute_ctr.attributes[i];
+ status = dsdb_map_int2oid(s->self_made_schema, a->attid, s, &oid);
+ if (!W_ERROR_IS_OK(status)) {
+ return werror_to_ntstatus(status);
+ }
+
+ switch (a->attid) {
+ case DRSUAPI_ATTRIBUTE_objectClass:
+ for (j=0; j < a->value_ctr.num_values; j++) {
+ uint32_t val = 0xFFFFFFFF;
+
+ if (a->value_ctr.values[i].blob
+ && a->value_ctr.values[i].blob->length == 4) {
+ val = IVAL(a->value_ctr.values[i].blob->data,0);
+ }
+
+ if (val == DRSUAPI_OBJECTCLASS_attributeSchema) {
+ is_attr = true;
+ }
+ if (val == DRSUAPI_OBJECTCLASS_classSchema) {
+ is_class = true;
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (is_attr) {
+ struct dsdb_attribute *sa;
+
+ sa = talloc_zero(s->self_made_schema, struct dsdb_attribute);
+ NT_STATUS_HAVE_NO_MEMORY(sa);
+
+ status = dsdb_attribute_from_drsuapi(s->self_made_schema, &cur->object, s, sa);
+ if (!W_ERROR_IS_OK(status)) {
+ return werror_to_ntstatus(status);
+ }
+
+ DLIST_ADD_END(s->self_made_schema->attributes, sa, struct dsdb_attribute *);
+ }
+
+ if (is_class) {
+ struct dsdb_class *sc;
+
+ sc = talloc_zero(s->self_made_schema, struct dsdb_class);
+ NT_STATUS_HAVE_NO_MEMORY(sc);
+
+ status = dsdb_class_from_drsuapi(s->self_made_schema, &cur->object, s, sc);
+ if (!W_ERROR_IS_OK(status)) {
+ return werror_to_ntstatus(status);
+ }
+
+ DLIST_ADD_END(s->self_made_schema->classes, sc, struct dsdb_class *);
+ }
+ }
+
+ /* attach the schema to the ldb */
+ ret = dsdb_set_schema(s->ldb, s->self_made_schema);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_FOOBAR;
+ }
+ /* we don't want to access the self made schema anymore */
+ s->self_made_schema = NULL;
+ s->schema = dsdb_get_schema(s->ldb);
+
+ status = dsdb_extended_replicated_objects_commit(s->ldb,
+ c->partition->nc.dn,
+ mapping_ctr,
+ object_count,
+ first_object,
+ linked_attributes_count,
+ linked_attributes,
+ s_dsa,
+ uptodateness_vector,
+ c->gensec_skey,
+ s, &objs);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
+ return werror_to_ntstatus(status);
+ }
+
+ if (lp_parm_bool(s->tctx->lp_ctx, NULL, "become dc", "dump objects", false)) {
+ for (i=0; i < objs->num_objects; i++) {
+ struct ldb_ldif ldif;
+ fprintf(stdout, "#\n");
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = objs->objects[i].msg;
+ ldb_ldif_write_file(s->ldb, stdout, &ldif);
+ NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
+ }
+ }
+
+ msg = ldb_msg_new(objs);
+ NT_STATUS_HAVE_NO_MEMORY(msg);
+ msg->dn = objs->partition_dn;
+
+ status = dsdb_get_oid_mappings_ldb(s->schema, msg, &prefixMap_val, &schemaInfo_val);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("Failed dsdb_get_oid_mappings_ldb(%s)\n", win_errstr(status)));
+ return werror_to_ntstatus(status);
+ }
+
+ /* we only add prefixMap here, because schemaInfo is a replicated attribute and already applied */
+ ret = ldb_msg_add_value(msg, "prefixMap", &prefixMap_val, &prefixMap_el);
+ if (ret != LDB_SUCCESS) {
+ return NT_STATUS_FOOBAR;
+ }
+ prefixMap_el->flags = LDB_FLAG_MOD_REPLACE;
+
+ ret = ldb_modify(s->ldb, msg);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(0,("Failed to add prefixMap and schemaInfo %s\n", ldb_strerror(ret)));
+ return NT_STATUS_FOOBAR;
+ }
+
+ talloc_free(s_dsa);
+ talloc_free(objs);
+
+ /* reopen the ldb */
+ talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */
+ s->schema = NULL;
+
+ sam_ldb_path = talloc_asprintf(s, "%s/%s", s->targetdir, "private/sam.ldb");
+ DEBUG(0,("Reopen the SAM LDB with system credentials and a already stored schema: %s\n", sam_ldb_path));
+ s->ldb = ldb_wrap_connect(s, s->tctx->ev, s->tctx->lp_ctx, sam_ldb_path,
+ system_session(s, s->tctx->lp_ctx),
+ NULL, 0, NULL);
+ if (!s->ldb) {
+ DEBUG(0,("Failed to open '%s'\n",
+ sam_ldb_path));
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ ok = samdb_set_ntds_invocation_id(s->ldb, &c->dest_dsa->invocation_id);
+ if (!ok) {
+ DEBUG(0,("Failed to set cached ntds invocationId\n"));
+ return NT_STATUS_FOOBAR;
+ }
+ ok = samdb_set_ntds_objectGUID(s->ldb, &c->dest_dsa->ntds_guid);
+ if (!ok) {
+ DEBUG(0,("Failed to set cached ntds objectGUID\n"));
+ return NT_STATUS_FOOBAR;
+ }
+
+ s->schema = dsdb_get_schema(s->ldb);
+ if (!s->schema) {
+ DEBUG(0,("Failed to get loaded dsdb_schema\n"));
+ return NT_STATUS_FOOBAR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_become_dc_schema_chunk(void *private_data,
+ const struct libnet_BecomeDC_StoreChunk *c)
+{
+ struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
+ WERROR status;
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
+ uint32_t nc_object_count;
+ uint32_t object_count;
+ struct drsuapi_DsReplicaObjectListItemEx *first_object;
+ struct drsuapi_DsReplicaObjectListItemEx *cur;
+ uint32_t nc_linked_attributes_count;
+ uint32_t linked_attributes_count;
+
+ switch (c->ctr_level) {
+ case 1:
+ mapping_ctr = &c->ctr1->mapping_ctr;
+ nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
+ object_count = c->ctr1->object_count;
+ first_object = c->ctr1->first_object;
+ nc_linked_attributes_count = 0;
+ linked_attributes_count = 0;
+ break;
+ case 6:
+ mapping_ctr = &c->ctr6->mapping_ctr;
+ nc_object_count = c->ctr6->nc_object_count;
+ object_count = c->ctr6->object_count;
+ first_object = c->ctr6->first_object;
+ nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
+ linked_attributes_count = c->ctr6->linked_attributes_count;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (nc_object_count) {
+ DEBUG(0,("Schema-DN[%s] objects[%u/%u] linked_values[%u/%u]\n",
+ c->partition->nc.dn, object_count, nc_object_count,
+ linked_attributes_count, nc_linked_attributes_count));
+ } else {
+ DEBUG(0,("Schema-DN[%s] objects[%u] linked_values[%u\n",
+ c->partition->nc.dn, object_count, linked_attributes_count));
+ }
+
+ if (!s->schema) {
+ s->self_made_schema = dsdb_new_schema(s, lp_iconv_convenience(s->lp_ctx));
+
+ NT_STATUS_HAVE_NO_MEMORY(s->self_made_schema);
+
+ status = dsdb_load_oid_mappings_drsuapi(s->self_made_schema, mapping_ctr);
+ if (!W_ERROR_IS_OK(status)) {
+ return werror_to_ntstatus(status);
+ }
+
+ s->schema = s->self_made_schema;
+ } else {
+ status = dsdb_verify_oid_mappings_drsuapi(s->schema, mapping_ctr);
+ if (!W_ERROR_IS_OK(status)) {
+ return werror_to_ntstatus(status);
+ }
+ }
+
+ if (!s->schema_part.first_object) {
+ s->schema_part.object_count = object_count;
+ s->schema_part.first_object = talloc_steal(s, first_object);
+ } else {
+ s->schema_part.object_count += object_count;
+ s->schema_part.last_object->next_object = talloc_steal(s->schema_part.last_object,
+ first_object);
+ }
+ for (cur = first_object; cur->next_object; cur = cur->next_object) {}
+ s->schema_part.last_object = cur;
+
+ if (!c->partition->more_data) {
+ return test_apply_schema(s, c);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS test_become_dc_store_chunk(void *private_data,
+ const struct libnet_BecomeDC_StoreChunk *c)
+{
+ struct test_become_dc_state *s = talloc_get_type(private_data, struct test_become_dc_state);
+ WERROR status;
+ const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
+ uint32_t nc_object_count;
+ uint32_t object_count;
+ struct drsuapi_DsReplicaObjectListItemEx *first_object;
+ uint32_t nc_linked_attributes_count;
+ uint32_t linked_attributes_count;
+ struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
+ const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
+ struct dsdb_extended_replicated_objects *objs;
+ struct repsFromTo1 *s_dsa;
+ char *tmp_dns_name;
+ uint32_t i;
+
+ s_dsa = talloc_zero(s, struct repsFromTo1);
+ NT_STATUS_HAVE_NO_MEMORY(s_dsa);
+ s_dsa->other_info = talloc(s_dsa, struct repsFromTo1OtherInfo);
+ NT_STATUS_HAVE_NO_MEMORY(s_dsa->other_info);
+
+ switch (c->ctr_level) {
+ case 1:
+ mapping_ctr = &c->ctr1->mapping_ctr;
+ nc_object_count = c->ctr1->extended_ret; /* maybe w2k send this unexpected? */
+ object_count = c->ctr1->object_count;
+ first_object = c->ctr1->first_object;
+ nc_linked_attributes_count = 0;
+ linked_attributes_count = 0;
+ linked_attributes = NULL;
+ s_dsa->highwatermark = c->ctr1->new_highwatermark;
+ s_dsa->source_dsa_obj_guid = c->ctr1->source_dsa_guid;
+ s_dsa->source_dsa_invocation_id = c->ctr1->source_dsa_invocation_id;
+ uptodateness_vector = NULL; /* TODO: map it */
+ break;
+ case 6:
+ mapping_ctr = &c->ctr6->mapping_ctr;
+ nc_object_count = c->ctr6->nc_object_count;
+ object_count = c->ctr6->object_count;
+ first_object = c->ctr6->first_object;
+ nc_linked_attributes_count = c->ctr6->nc_linked_attributes_count;
+ linked_attributes_count = c->ctr6->linked_attributes_count;
+ linked_attributes = c->ctr6->linked_attributes;
+ s_dsa->highwatermark = c->ctr6->new_highwatermark;
+ s_dsa->source_dsa_obj_guid = c->ctr6->source_dsa_guid;
+ s_dsa->source_dsa_invocation_id = c->ctr6->source_dsa_invocation_id;
+ uptodateness_vector = c->ctr6->uptodateness_vector;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ s_dsa->replica_flags = DRSUAPI_DS_REPLICA_NEIGHBOUR_WRITEABLE
+ | DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP
+ | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS;
+ memset(s_dsa->schedule, 0x11, sizeof(s_dsa->schedule));
+
+ tmp_dns_name = GUID_string(s_dsa->other_info, &s_dsa->source_dsa_obj_guid);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+ tmp_dns_name = talloc_asprintf_append_buffer(tmp_dns_name, "._msdcs.%s", c->forest->dns_name);
+ NT_STATUS_HAVE_NO_MEMORY(tmp_dns_name);
+ s_dsa->other_info->dns_name = tmp_dns_name;
+
+ if (nc_object_count) {
+ DEBUG(0,("Partition[%s] objects[%u/%u] linked_values[%u/%u]\n",
+ c->partition->nc.dn, object_count, nc_object_count,
+ linked_attributes_count, nc_linked_attributes_count));
+ } else {
+ DEBUG(0,("Partition[%s] objects[%u] linked_values[%u\n",
+ c->partition->nc.dn, object_count, linked_attributes_count));
+ }
+
+ status = dsdb_extended_replicated_objects_commit(s->ldb,
+ c->partition->nc.dn,
+ mapping_ctr,
+ object_count,
+ first_object,
+ linked_attributes_count,
+ linked_attributes,
+ s_dsa,
+ uptodateness_vector,
+ c->gensec_skey,
+ s, &objs);
+ if (!W_ERROR_IS_OK(status)) {
+ DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
+ return werror_to_ntstatus(status);
+ }
+
+ if (lp_parm_bool(s->tctx->lp_ctx, NULL, "become dc", "dump objects", false)) {
+ for (i=0; i < objs->num_objects; i++) {
+ struct ldb_ldif ldif;
+ fprintf(stdout, "#\n");
+ ldif.changetype = LDB_CHANGETYPE_NONE;
+ ldif.msg = objs->objects[i].msg;
+ ldb_ldif_write_file(s->ldb, stdout, &ldif);
+ NDR_PRINT_DEBUG(replPropertyMetaDataBlob, objs->objects[i].meta_data);
+ }
+ }
+ talloc_free(s_dsa);
+ talloc_free(objs);
+
+ for (i=0; i < linked_attributes_count; i++) {
+ const struct dsdb_attribute *sa;
+
+ if (!linked_attributes[i].identifier) {
+ return NT_STATUS_FOOBAR;
+ }
+
+ if (!linked_attributes[i].value.blob) {
+ return NT_STATUS_FOOBAR;
+ }
+
+ sa = dsdb_attribute_by_attributeID_id(s->schema,
+ linked_attributes[i].attid);
+ if (!sa) {
+ return NT_STATUS_FOOBAR;
+ }
+
+ if (lp_parm_bool(s->tctx->lp_ctx, NULL, "become dc", "dump objects", false)) {
+ DEBUG(0,("# %s\n", sa->lDAPDisplayName));
+ NDR_PRINT_DEBUG(drsuapi_DsReplicaLinkedAttribute, &linked_attributes[i]);
+ dump_data(0,
+ linked_attributes[i].value.blob->data,
+ linked_attributes[i].value.blob->length);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+bool torture_net_become_dc(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ struct libnet_BecomeDC b;
+ struct libnet_UnbecomeDC u;
+ struct test_become_dc_state *s;
+ struct ldb_message *msg;
+ int ldb_ret;
+ uint32_t i;
+ char *sam_ldb_path;
+
+ char *location = NULL;
+ torture_assert_ntstatus_ok(torture, torture_temp_dir(torture, "libnet_BecomeDC", &location),
+ "torture_temp_dir should return NT_STATUS_OK" );
+
+ s = talloc_zero(torture, struct test_become_dc_state);
+ if (!s) return false;
+
+ s->tctx = torture;
+ s->lp_ctx = torture->lp_ctx;
+
+ s->netbios_name = lp_parm_string(torture->lp_ctx, NULL, "become dc", "smbtorture dc");
+ if (!s->netbios_name || !s->netbios_name[0]) {
+ s->netbios_name = "smbtorturedc";
+ }
+
+ s->targetdir = location;
+
+ /* Join domain as a member server. */
+ s->tj = torture_join_domain(torture, s->netbios_name,
+ ACB_WSTRUST,
+ &s->machine_account);
+ if (!s->tj) {
+ DEBUG(0, ("%s failed to join domain as workstation\n",
+ s->netbios_name));
+ return false;
+ }
+
+ s->ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ s->ctx->cred = cmdline_credentials;
+
+ s->ldb = ldb_init(s, torture->ev);
+
+ ZERO_STRUCT(b);
+ b.in.domain_dns_name = torture_join_dom_dns_name(s->tj);
+ b.in.domain_netbios_name = torture_join_dom_netbios_name(s->tj);
+ b.in.domain_sid = torture_join_sid(s->tj);
+ b.in.source_dsa_address = torture_setting_string(torture, "host", NULL);
+ b.in.dest_dsa_netbios_name = s->netbios_name;
+
+ b.in.callbacks.private_data = s;
+ b.in.callbacks.check_options = test_become_dc_check_options;
+ b.in.callbacks.prepare_db = test_become_dc_prepare_db;
+ b.in.callbacks.schema_chunk = test_become_dc_schema_chunk;
+ b.in.callbacks.config_chunk = test_become_dc_store_chunk;
+ b.in.callbacks.domain_chunk = test_become_dc_store_chunk;
+
+ status = libnet_BecomeDC(s->ctx, s, &b);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_BecomeDC() failed - %s\n", nt_errstr(status));
+ ret = false;
+ goto cleanup;
+ }
+
+ msg = ldb_msg_new(s);
+ if (!msg) {
+ printf("ldb_msg_new() failed\n");
+ ret = false;
+ goto cleanup;
+ }
+ msg->dn = ldb_dn_new(msg, s->ldb, "@ROOTDSE");
+ if (!msg->dn) {
+ printf("ldb_msg_new(@ROOTDSE) failed\n");
+ ret = false;
+ goto cleanup;
+ }
+
+ ldb_ret = ldb_msg_add_string(msg, "isSynchronized", "TRUE");
+ if (ldb_ret != LDB_SUCCESS) {
+ printf("ldb_msg_add_string(msg, isSynchronized, TRUE) failed: %d\n", ldb_ret);
+ ret = false;
+ goto cleanup;
+ }
+
+ for (i=0; i < msg->num_elements; i++) {
+ msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+ }
+
+ printf("mark ROOTDSE with isSynchronized=TRUE\n");
+ ldb_ret = ldb_modify(s->ldb, msg);
+ if (ldb_ret != LDB_SUCCESS) {
+ printf("ldb_modify() failed: %d\n", ldb_ret);
+ ret = false;
+ goto cleanup;
+ }
+
+ /* reopen the ldb */
+ talloc_free(s->ldb); /* this also free's the s->schema, because dsdb_set_schema() steals it */
+ s->schema = NULL;
+
+ sam_ldb_path = talloc_asprintf(s, "%s/%s", s->targetdir, "private/sam.ldb");
+ DEBUG(0,("Reopen the SAM LDB with system credentials and all replicated data: %s\n", sam_ldb_path));
+ s->ldb = ldb_wrap_connect(s, s->tctx->ev, s->lp_ctx, sam_ldb_path,
+ system_session(s, s->lp_ctx),
+ NULL, 0, NULL);
+ if (!s->ldb) {
+ DEBUG(0,("Failed to open '%s'\n",
+ sam_ldb_path));
+ ret = false;
+ goto cleanup;
+ }
+
+ s->schema = dsdb_get_schema(s->ldb);
+ if (!s->schema) {
+ DEBUG(0,("Failed to get loaded dsdb_schema\n"));
+ ret = false;
+ goto cleanup;
+ }
+
+ /* Make sure we get this from the command line */
+ if (lp_parm_bool(torture->lp_ctx, NULL, "become dc", "do not unjoin", false)) {
+ talloc_free(s);
+ return ret;
+ }
+
+cleanup:
+ ZERO_STRUCT(u);
+ u.in.domain_dns_name = torture_join_dom_dns_name(s->tj);
+ u.in.domain_netbios_name = torture_join_dom_netbios_name(s->tj);
+ u.in.source_dsa_address = torture_setting_string(torture, "host", NULL);
+ u.in.dest_dsa_netbios_name = s->netbios_name;
+
+ status = libnet_UnbecomeDC(s->ctx, s, &u);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_UnbecomeDC() failed - %s\n", nt_errstr(status));
+ ret = false;
+ }
+
+ /* Leave domain. */
+ torture_leave_domain(torture, s->tj);
+
+ talloc_free(s);
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_domain.c b/source4/torture/libnet/libnet_domain.c
new file mode 100644
index 0000000000..7d5be368c2
--- /dev/null
+++ b/source4/torture/libnet/libnet_domain.c
@@ -0,0 +1,447 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2006
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "lib/events/events.h"
+#include "auth/credentials/credentials.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "libcli/security/security.h"
+#include "librpc/rpc/dcerpc.h"
+#include "torture/torture.h"
+#include "torture/rpc/rpc.h"
+#include "param/param.h"
+
+
+static bool test_opendomain_samr(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname,
+ uint32_t *access_mask, struct dom_sid **sid)
+{
+ NTSTATUS status;
+ struct policy_handle h, domain_handle;
+ struct samr_Connect r1;
+ struct samr_LookupDomain r2;
+ struct samr_OpenDomain r3;
+
+ printf("connecting\n");
+
+ *access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ r1.in.system_name = 0;
+ r1.in.access_mask = *access_mask;
+ r1.out.connect_handle = &h;
+
+ status = dcerpc_samr_Connect(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r2.in.connect_handle = &h;
+ r2.in.domain_name = domname;
+
+ printf("domain lookup on %s\n", domname->string);
+
+ status = dcerpc_samr_LookupDomain(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupDomain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r3.in.connect_handle = &h;
+ r3.in.access_mask = *access_mask;
+ r3.in.sid = *sid = r2.out.sid;
+ r3.out.domain_handle = &domain_handle;
+
+ printf("opening domain\n");
+
+ status = dcerpc_samr_OpenDomain(p, mem_ctx, &r3);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("OpenDomain failed - %s\n", nt_errstr(status));
+ return false;
+ } else {
+ *handle = domain_handle;
+ }
+
+ return true;
+}
+
+
+static bool test_opendomain_lsa(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname,
+ uint32_t *access_mask)
+{
+ NTSTATUS status;
+ struct lsa_OpenPolicy2 open;
+ struct lsa_ObjectAttribute attr;
+ struct lsa_QosInfo qos;
+
+ *access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ ZERO_STRUCT(attr);
+ ZERO_STRUCT(qos);
+
+ qos.len = 0;
+ qos.impersonation_level = 2;
+ qos.context_mode = 1;
+ qos.effective_only = 0;
+
+ attr.sec_qos = &qos;
+
+ open.in.system_name = domname->string;
+ open.in.attr = &attr;
+ open.in.access_mask = *access_mask;
+ open.out.handle = handle;
+
+ status = dcerpc_lsa_OpenPolicy2(p, mem_ctx, &open);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool torture_domain_open_lsa(struct torture_context *torture)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_context *ctx;
+ struct libnet_DomainOpen r;
+ struct lsa_Close lsa_close;
+ struct policy_handle h;
+ const char *domain_name;
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lp_workgroup(torture->lp_ctx);
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ d_printf("failed to create libnet context\n");
+ return false;
+ }
+
+ ctx->cred = cmdline_credentials;
+
+ ZERO_STRUCT(r);
+ r.in.type = DOMAIN_LSA;
+ r.in.domain_name = domain_name;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ status = libnet_DomainOpen(ctx, torture, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to open domain on lsa service: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ZERO_STRUCT(lsa_close);
+ lsa_close.in.handle = &ctx->lsa.handle;
+ lsa_close.out.handle = &h;
+
+ status = dcerpc_lsa_Close(ctx->lsa.pipe, ctx, &lsa_close);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to close domain on lsa service: %s\n", nt_errstr(status));
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ return ret;
+}
+
+
+bool torture_domain_close_lsa(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx=NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct dcerpc_binding *binding;
+ uint32_t access_mask;
+ struct policy_handle h;
+ struct dcerpc_pipe *p;
+ struct libnet_DomainClose r;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ d_printf("failed to create libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->cred = cmdline_credentials;
+
+ mem_ctx = talloc_init("torture_domain_close_lsa");
+ status = dcerpc_pipe_connect_b(mem_ctx, &p, binding, &ndr_table_lsarpc,
+ cmdline_credentials, torture->ev, torture->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to connect to server: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+
+ if (!test_opendomain_lsa(p, torture, &h, &domain_name, &access_mask)) {
+ d_printf("failed to open domain on lsa service\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->lsa.pipe = p;
+ ctx->lsa.name = domain_name.string;
+ ctx->lsa.access_mask = access_mask;
+ ctx->lsa.handle = h;
+ /* we have to use pipe's event context, otherwise the call will
+ hang indefinitely */
+ ctx->event_ctx = p->conn->event_ctx;
+
+ ZERO_STRUCT(r);
+ r.in.type = DOMAIN_LSA;
+ r.in.domain_name = domain_name.string;
+
+ status = libnet_DomainClose(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+ return ret;
+}
+
+
+bool torture_domain_open_samr(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct libnet_context *ctx;
+ TALLOC_CTX *mem_ctx;
+ struct policy_handle domain_handle, handle;
+ struct libnet_DomainOpen io;
+ struct samr_Close r;
+ const char *domain_name;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_domainopen_lsa");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lp_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ printf("opening domain\n");
+
+ io.in.type = DOMAIN_SAMR;
+ io.in.domain_name = domain_name;
+ io.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+
+ status = libnet_DomainOpen(ctx, mem_ctx, &io);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Composite domain open failed - %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ domain_handle = ctx->samr.handle;
+
+ r.in.handle = &domain_handle;
+ r.out.handle = &handle;
+
+ printf("closing domain handle\n");
+
+ status = dcerpc_samr_Close(ctx->samr.pipe, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+
+ return ret;
+}
+
+
+bool torture_domain_close_samr(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct dcerpc_binding *binding;
+ uint32_t access_mask;
+ struct policy_handle h;
+ struct dcerpc_pipe *p;
+ struct libnet_DomainClose r;
+ struct dom_sid *sid;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ d_printf("failed to create libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->cred = cmdline_credentials;
+
+ mem_ctx = talloc_init("torture_domain_close_samr");
+ status = dcerpc_pipe_connect_b(mem_ctx, &p, binding, &ndr_table_samr,
+ ctx->cred, torture->ev, torture->lp_ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("failed to connect to server: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ domain_name.string = talloc_strdup(mem_ctx, lp_workgroup(torture->lp_ctx));
+
+ if (!test_opendomain_samr(p, torture, &h, &domain_name, &access_mask, &sid)) {
+ d_printf("failed to open domain on samr service\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->samr.pipe = p;
+ ctx->samr.name = talloc_steal(ctx, domain_name.string);
+ ctx->samr.access_mask = access_mask;
+ ctx->samr.handle = h;
+ ctx->samr.sid = talloc_steal(ctx, sid);
+ /* we have to use pipe's event context, otherwise the call will
+ hang indefinitely - this wouldn't be the case if pipe was opened
+ by means of libnet call */
+ ctx->event_ctx = p->conn->event_ctx;
+
+ ZERO_STRUCT(r);
+ r.in.type = DOMAIN_SAMR;
+ r.in.domain_name = domain_name.string;
+
+ status = libnet_DomainClose(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+ return ret;
+}
+
+
+bool torture_domain_list(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct dcerpc_binding *binding;
+ struct libnet_context *ctx;
+ struct libnet_DomainList r;
+ int i;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (ctx == NULL) {
+ d_printf("failed to create libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ ctx->cred = cmdline_credentials;
+
+ mem_ctx = talloc_init("torture_domain_close_samr");
+
+ /*
+ * querying the domain list using default buffer size
+ */
+
+ ZERO_STRUCT(r);
+ r.in.hostname = binding->host;
+
+ status = libnet_DomainList(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ d_printf("Received list or domains (everything in one piece):\n");
+
+ for (i = 0; i < r.out.count; i++) {
+ d_printf("Name[%d]: %s\n", i, r.out.domains[i].name);
+ }
+
+ /*
+ * querying the domain list using specified (much smaller) buffer size
+ */
+
+ ctx->samr.buf_size = 32;
+
+ ZERO_STRUCT(r);
+ r.in.hostname = binding->host;
+
+ status = libnet_DomainList(ctx, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ d_printf("Received list or domains (collected in more than one round):\n");
+
+ for (i = 0; i < r.out.count; i++) {
+ d_printf("Name[%d]: %s\n", i, r.out.domains[i].name);
+ }
+
+done:
+ d_printf("\nStatus: %s\n", nt_errstr(status));
+
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_group.c b/source4/torture/libnet/libnet_group.c
new file mode 100644
index 0000000000..12b8167a86
--- /dev/null
+++ b/source4/torture/libnet/libnet_group.c
@@ -0,0 +1,393 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "torture/torture.h"
+#include "torture/rpc/rpc.h"
+#include "param/param.h"
+
+
+#define TEST_GROUPNAME "libnetgrouptest"
+
+
+static bool test_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle, const char *groupname)
+{
+ NTSTATUS status;
+ struct samr_LookupNames r1;
+ struct samr_OpenGroup r2;
+ struct samr_DeleteDomainGroup r3;
+ struct lsa_String names[2];
+ uint32_t rid;
+ struct policy_handle group_handle;
+
+ names[0].string = groupname;
+
+ r1.in.domain_handle = domain_handle;
+ r1.in.num_names = 1;
+ r1.in.names = names;
+
+ printf("group account lookup '%s'\n", groupname);
+
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupNames failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ rid = r1.out.rids.ids[0];
+
+ r2.in.domain_handle = domain_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.rid = rid;
+ r2.out.group_handle = &group_handle;
+
+ printf("opening group account\n");
+
+ status = dcerpc_samr_OpenGroup(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("OpenGroup failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r3.in.group_handle = &group_handle;
+ r3.out.group_handle = &group_handle;
+
+ printf("deleting group account\n");
+
+ status = dcerpc_samr_DeleteDomainGroup(p, mem_ctx, &r3);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("DeleteGroup failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_creategroup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *name)
+{
+ NTSTATUS status;
+ struct lsa_String groupname;
+ struct samr_CreateDomainGroup r;
+ struct policy_handle group_handle;
+ uint32_t group_rid;
+
+ groupname.string = name;
+
+ r.in.domain_handle = handle;
+ r.in.name = &groupname;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.group_handle = &group_handle;
+ r.out.rid = &group_rid;
+
+ printf("creating group account %s\n", name);
+
+ status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateGroup failed - %s\n", nt_errstr(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_GROUP_EXISTS)) {
+ printf("Group (%s) already exists - attempting to delete and recreate group again\n", name);
+ if (!test_cleanup(p, mem_ctx, handle, TEST_GROUPNAME)) {
+ return false;
+ }
+
+ printf("creating group account\n");
+
+ status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateGroup failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_opendomain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname)
+{
+ NTSTATUS status;
+ struct policy_handle h, domain_handle;
+ struct samr_Connect r1;
+ struct samr_LookupDomain r2;
+ struct samr_OpenDomain r3;
+
+ printf("connecting\n");
+
+ r1.in.system_name = 0;
+ r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r1.out.connect_handle = &h;
+
+ status = dcerpc_samr_Connect(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r2.in.connect_handle = &h;
+ r2.in.domain_name = domname;
+
+ printf("domain lookup on %s\n", domname->string);
+
+ status = dcerpc_samr_LookupDomain(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupDomain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r3.in.connect_handle = &h;
+ r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r3.in.sid = r2.out.sid;
+ r3.out.domain_handle = &domain_handle;
+
+ printf("opening domain\n");
+
+ status = dcerpc_samr_OpenDomain(p, mem_ctx, &r3);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("OpenDomain failed - %s\n", nt_errstr(status));
+ return false;
+ } else {
+ *handle = domain_handle;
+ }
+
+ return true;
+}
+
+
+static bool test_samr_close(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct samr_Close r;
+
+ r.in.handle = domain_handle;
+ r.out.handle = domain_handle;
+
+ status = dcerpc_samr_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close samr domain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_lsa_close(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct lsa_Close r;
+
+ r.in.handle = domain_handle;
+ r.out.handle = domain_handle;
+
+ status = dcerpc_lsa_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close lsa domain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_groupinfo_api(struct torture_context *torture)
+{
+ const char *name = TEST_GROUPNAME;
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL, *prep_mem_ctx;
+ struct libnet_context *ctx;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct libnet_GroupInfo req;
+
+ prep_mem_ctx = talloc_init("prepare torture group info");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_creategroup(p, prep_mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ mem_ctx = talloc_init("torture group info");
+
+ ZERO_STRUCT(req);
+
+ req.in.domain_name = domain_name.string;
+ req.in.group_name = name;
+
+ status = libnet_GroupInfo(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_GroupInfo call failed: %s\n", nt_errstr(status));
+ ret = false;
+ talloc_free(mem_ctx);
+ goto done;
+ }
+
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, TEST_GROUPNAME)) {
+ printf("cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = false;
+ }
+
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_grouplist(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct libnet_GroupList req;
+ int i;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ mem_ctx = talloc_init("torture group list");
+
+ ZERO_STRUCT(req);
+
+ printf("listing group accounts:\n");
+
+ do {
+ req.in.domain_name = domain_name.string;
+ req.in.page_size = 128;
+ req.in.resume_index = req.out.resume_index;
+
+ status = libnet_GroupList(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) break;
+
+ for (i = 0; i < req.out.count; i++) {
+ printf("\tgroup: %s, sid=%s\n",
+ req.out.groups[i].groupname, req.out.groups[i].sid);
+ }
+
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (!(NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES))) {
+ printf("libnet_GroupList call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = false;
+ }
+
+ if (!test_lsa_close(ctx->lsa.pipe, mem_ctx, &ctx->lsa.handle)) {
+ printf("lsa domain close failed\n");
+ ret = false;
+ }
+
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_creategroup(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct libnet_CreateGroup req;
+
+ mem_ctx = talloc_init("test_creategroup");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ req.in.group_name = TEST_GROUPNAME;
+ req.in.domain_name = lp_workgroup(torture->lp_ctx);
+ req.out.error_string = NULL;
+
+ status = libnet_CreateGroup(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_CreateGroup call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, TEST_GROUPNAME)) {
+ printf("cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_lookup.c b/source4/torture/libnet/libnet_lookup.c
new file mode 100644
index 0000000000..b25b51b7d9
--- /dev/null
+++ b/source4/torture/libnet/libnet_lookup.c
@@ -0,0 +1,189 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/nbt.h"
+#include "librpc/rpc/dcerpc.h"
+#include "libcli/libcli.h"
+#include "torture/rpc/rpc.h"
+#include "torture/torture.h"
+#include "param/param.h"
+
+
+bool torture_lookup(struct torture_context *torture)
+{
+ bool ret;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_Lookup lookup;
+ struct dcerpc_binding *binding;
+
+ mem_ctx = talloc_init("test_lookup");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ lookup.in.hostname = torture_setting_string(torture, "host", NULL);
+ if (lookup.in.hostname == NULL) {
+ status = torture_rpc_binding(torture, &binding);
+ if (NT_STATUS_IS_OK(status)) {
+ lookup.in.hostname = binding->host;
+ }
+ }
+
+ lookup.in.type = NBT_NAME_CLIENT;
+ lookup.in.resolve_ctx = NULL;
+ lookup.out.address = NULL;
+
+ status = libnet_Lookup(ctx, mem_ctx, &lookup);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Couldn't lookup name %s: %s\n", lookup.in.hostname, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ret = true;
+
+ printf("Name [%s] found at address: %s.\n", lookup.in.hostname, *lookup.out.address);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_lookup_host(struct torture_context *torture)
+{
+ bool ret;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_Lookup lookup;
+ struct dcerpc_binding *binding;
+
+ mem_ctx = talloc_init("test_lookup_host");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ lookup.in.hostname = torture_setting_string(torture, "host", NULL);
+ if (lookup.in.hostname == NULL) {
+ status = torture_rpc_binding(torture, &binding);
+ if (NT_STATUS_IS_OK(status)) {
+ lookup.in.hostname = binding->host;
+ }
+ }
+
+ lookup.in.resolve_ctx = NULL;
+ lookup.out.address = NULL;
+
+ status = libnet_LookupHost(ctx, mem_ctx, &lookup);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Couldn't lookup host %s: %s\n", lookup.in.hostname, nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ret = true;
+
+ printf("Host [%s] found at address: %s.\n", lookup.in.hostname, *lookup.out.address);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_lookup_pdc(struct torture_context *torture)
+{
+ bool ret;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_LookupDCs *lookup;
+ int i;
+
+ mem_ctx = talloc_init("test_lookup_pdc");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ talloc_steal(ctx, mem_ctx);
+
+ lookup = talloc(mem_ctx, struct libnet_LookupDCs);
+ if (!lookup) {
+ ret = false;
+ goto done;
+ }
+
+ lookup->in.domain_name = lp_workgroup(torture->lp_ctx);
+ lookup->in.name_type = NBT_NAME_PDC;
+
+ status = libnet_LookupDCs(ctx, mem_ctx, lookup);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Couldn't lookup pdc %s: %s\n", lookup->in.domain_name,
+ nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ ret = true;
+
+ printf("DCs of domain [%s] found.\n", lookup->in.domain_name);
+ for (i = 0; i < lookup->out.num_dcs; i++) {
+ printf("\tDC[%d]: name=%s, address=%s\n", i, lookup->out.dcs[i].name,
+ lookup->out.dcs[i].address);
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_lookup_sam_name(struct torture_context *torture)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_LookupName r;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ mem_ctx = talloc_init("torture lookup sam name");
+ if (mem_ctx == NULL) return false;
+
+ r.in.name = "Administrator";
+ r.in.domain_name = lp_workgroup(torture->lp_ctx);
+
+ status = libnet_LookupName(ctx, mem_ctx, &r);
+
+ talloc_free(mem_ctx);
+ talloc_free(ctx);
+
+ return true;
+}
diff --git a/source4/torture/libnet/libnet_rpc.c b/source4/torture/libnet/libnet_rpc.c
new file mode 100644
index 0000000000..f25c1ecc48
--- /dev/null
+++ b/source4/torture/libnet/libnet_rpc.c
@@ -0,0 +1,226 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/cmdline/popt_common.h"
+#include "auth/credentials/credentials.h"
+#include "libnet/libnet.h"
+#include "libcli/security/security.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_lsa.h"
+#include "librpc/gen_ndr/ndr_samr.h"
+#include "librpc/gen_ndr/ndr_srvsvc.h"
+#include "librpc/rpc/dcerpc.h"
+#include "torture/rpc/rpc.h"
+#include "torture/torture.h"
+#include "param/param.h"
+
+
+static bool test_connect_service(struct libnet_context *ctx,
+ const struct ndr_interface_table *iface,
+ const char *binding_string,
+ const char *hostname,
+ const enum libnet_RpcConnect_level level,
+ bool badcreds, NTSTATUS expected_status)
+{
+ NTSTATUS status;
+ struct libnet_RpcConnect connect;
+ connect.level = level;
+ connect.in.binding = binding_string;
+ connect.in.name = hostname;
+ connect.in.dcerpc_iface = iface;
+
+ /* if bad credentials are needed, set baduser%badpassword instead
+ of default commandline-passed credentials */
+ if (badcreds) {
+ cli_credentials_set_username(ctx->cred, "baduser", CRED_SPECIFIED);
+ cli_credentials_set_password(ctx->cred, "badpassword", CRED_SPECIFIED);
+ }
+
+ status = libnet_RpcConnect(ctx, ctx, &connect);
+
+ if (!NT_STATUS_EQUAL(status, expected_status)) {
+ d_printf("Connecting to rpc service %s on %s.\n\tFAILED. Expected: %s."
+ "Received: %s\n",
+ connect.in.dcerpc_iface->name, connect.in.binding, nt_errstr(expected_status),
+ nt_errstr(status));
+
+ return false;
+ }
+
+ d_printf("PASSED. Expected: %s, received: %s\n", nt_errstr(expected_status),
+ nt_errstr(status));
+
+ if (connect.level == LIBNET_RPC_CONNECT_DC_INFO && NT_STATUS_IS_OK(status)) {
+ d_printf("Domain Controller Info:\n");
+ d_printf("\tDomain Name:\t %s\n", connect.out.domain_name);
+ d_printf("\tDomain SID:\t %s\n", dom_sid_string(ctx, connect.out.domain_sid));
+ d_printf("\tRealm:\t\t %s\n", connect.out.realm);
+ d_printf("\tGUID:\t\t %s\n", GUID_string(ctx, connect.out.guid));
+
+ } else if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Error string: %s\n", connect.out.error_string);
+ }
+
+ return true;
+}
+
+
+static bool torture_rpc_connect(struct torture_context *torture,
+ const enum libnet_RpcConnect_level level,
+ const char *bindstr, const char *hostname)
+{
+ struct libnet_context *ctx;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ d_printf("Testing connection to LSA interface\n");
+ if (!test_connect_service(ctx, &ndr_table_lsarpc, bindstr,
+ hostname, level, false, NT_STATUS_OK)) {
+ d_printf("failed to connect LSA interface\n");
+ return false;
+ }
+
+ d_printf("Testing connection to SAMR interface\n");
+ if (!test_connect_service(ctx, &ndr_table_samr, bindstr,
+ hostname, level, false, NT_STATUS_OK)) {
+ d_printf("failed to connect SAMR interface\n");
+ return false;
+ }
+
+ d_printf("Testing connection to SRVSVC interface\n");
+ if (!test_connect_service(ctx, &ndr_table_srvsvc, bindstr,
+ hostname, level, false, NT_STATUS_OK)) {
+ d_printf("failed to connect SRVSVC interface\n");
+ return false;
+ }
+
+ d_printf("Testing connection to LSA interface with wrong credentials\n");
+ if (!test_connect_service(ctx, &ndr_table_lsarpc, bindstr,
+ hostname, level, true, NT_STATUS_LOGON_FAILURE)) {
+ d_printf("failed to test wrong credentials on LSA interface\n");
+ return false;
+ }
+
+ d_printf("Testing connection to SAMR interface with wrong credentials\n");
+ if (!test_connect_service(ctx, &ndr_table_samr, bindstr,
+ hostname, level, true, NT_STATUS_LOGON_FAILURE)) {
+ d_printf("failed to test wrong credentials on SAMR interface\n");
+ return false;
+ }
+
+ talloc_free(ctx);
+
+ return true;
+}
+
+
+bool torture_rpc_connect_srv(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_SERVER;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ return torture_rpc_connect(torture, level, NULL, binding->host);
+}
+
+
+bool torture_rpc_connect_pdc(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_PDC;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *domain_name;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lp_workgroup(torture->lp_ctx);
+ return torture_rpc_connect(torture, level, NULL, domain_name);
+}
+
+
+bool torture_rpc_connect_dc(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_DC;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *domain_name;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lp_workgroup(torture->lp_ctx);
+ return torture_rpc_connect(torture, level, NULL, domain_name);
+}
+
+
+bool torture_rpc_connect_dc_info(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_DC_INFO;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *domain_name;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ /* we're accessing domain controller so the domain name should be
+ passed (it's going to be resolved to dc name and address) instead
+ of specific server name. */
+ domain_name = lp_workgroup(torture->lp_ctx);
+ return torture_rpc_connect(torture, level, NULL, domain_name);
+}
+
+
+bool torture_rpc_connect_binding(struct torture_context *torture)
+{
+ const enum libnet_RpcConnect_level level = LIBNET_RPC_CONNECT_BINDING;
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ const char *bindstr;
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ bindstr = dcerpc_binding_string(torture, binding);
+
+ return torture_rpc_connect(torture, level, bindstr, NULL);
+}
diff --git a/source4/torture/libnet/libnet_share.c b/source4/torture/libnet/libnet_share.c
new file mode 100644
index 0000000000..6bc5be40a6
--- /dev/null
+++ b/source4/torture/libnet/libnet_share.c
@@ -0,0 +1,233 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Gregory LEOCADIE <gleocadie@idealx.com> 2005
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "libnet/libnet.h"
+#include "lib/cmdline/popt_common.h"
+#include "librpc/gen_ndr/ndr_srvsvc_c.h"
+
+
+#define TEST_SHARENAME "libnetsharetest"
+
+
+static void test_displayshares(struct libnet_ListShares s)
+{
+ int i, j;
+
+ struct share_type {
+ enum srvsvc_ShareType type;
+ const char *desc;
+ } share_types[] = {
+ { STYPE_DISKTREE, "STYPE_DISKTREE" },
+ { STYPE_DISKTREE_TEMPORARY, "STYPE_DISKTREE_TEMPORARY" },
+ { STYPE_DISKTREE_HIDDEN, "STYPE_DISKTREE_HIDDEN" },
+ { STYPE_PRINTQ, "STYPE_PRINTQ" },
+ { STYPE_PRINTQ_TEMPORARY, "STYPE_PRINTQ_TEMPORARY" },
+ { STYPE_PRINTQ_HIDDEN, "STYPE_PRINTQ_HIDDEN" },
+ { STYPE_DEVICE, "STYPE_DEVICE" },
+ { STYPE_DEVICE_TEMPORARY, "STYPE_DEVICE_TEMPORARY" },
+ { STYPE_DEVICE_HIDDEN, "STYPE_DEVICE_HIDDEN" },
+ { STYPE_IPC, "STYPE_IPC" },
+ { STYPE_IPC_TEMPORARY, "STYPE_IPC_TEMPORARY" },
+ { STYPE_IPC_HIDDEN, "STYPE_IPC_HIDDEN" }
+ };
+
+ switch (s.in.level) {
+ case 0:
+ for (i = 0; i < s.out.ctr.ctr0->count; i++) {
+ struct srvsvc_NetShareInfo0 *info = &s.out.ctr.ctr0->array[i];
+ d_printf("\t[%d] %s\n", i, info->name);
+ }
+ break;
+
+ case 1:
+ for (i = 0; i < s.out.ctr.ctr1->count; i++) {
+ struct srvsvc_NetShareInfo1 *info = &s.out.ctr.ctr1->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) break;
+ }
+ d_printf("\t[%d] %s (%s)\t%s\n", i, info->name,
+ info->comment, share_types[j].desc);
+ }
+ break;
+
+ case 2:
+ for (i = 0; i < s.out.ctr.ctr2->count; i++) {
+ struct srvsvc_NetShareInfo2 *info = &s.out.ctr.ctr2->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) break;
+ }
+ d_printf("\t[%d] %s\t%s\n\t %s\n\t [perms=0x%08x, max_usr=%d, cur_usr=%d, path=%s, pass=%s]\n",
+ i, info->name, share_types[j].desc, info->comment,
+ info->permissions, info->max_users,
+ info->current_users, info->path,
+ info->password);
+ }
+ break;
+
+ case 501:
+ for (i = 0; i < s.out.ctr.ctr501->count; i++) {
+ struct srvsvc_NetShareInfo501 *info = &s.out.ctr.ctr501->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) break;
+ }
+ d_printf("\t[%d] %s\t%s [csc_policy=0x%08x]\n\t %s\n", i, info->name,
+ share_types[j].desc, info->csc_policy,
+ info->comment);
+ }
+ break;
+
+ case 502:
+ for (i = 0; i < s.out.ctr.ctr502->count; i++) {
+ struct srvsvc_NetShareInfo502 *info = &s.out.ctr.ctr502->array[i];
+ for (j = 0; j < ARRAY_SIZE(share_types); j++) {
+ if (share_types[j].type == info->type) break;
+ }
+ d_printf("\t[%d] %s\t%s\n\t %s\n\t [perms=0x%08x, max_usr=%d, cur_usr=%d, path=%s, pass=%s, unknown=0x%08x]\n",
+ i, info->name, share_types[j].desc, info->comment,
+ info->permissions, info->max_users,
+ info->current_users, info->path,
+ info->password, info->unknown);
+ }
+ break;
+ }
+}
+
+
+bool torture_listshares(struct torture_context *torture)
+{
+ struct libnet_ListShares share;
+ NTSTATUS status;
+ uint32_t levels[] = { 0, 1, 2, 501, 502 };
+ int i;
+ bool ret = true;
+ struct libnet_context* libnetctx;
+ struct dcerpc_binding *binding;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("test_listshares");
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ libnetctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ if (!libnetctx) {
+ printf("Couldn't allocate libnet context\n");
+ ret = false;
+ goto done;
+ }
+
+ libnetctx->cred = cmdline_credentials;
+
+ printf("Testing libnet_ListShare\n");
+
+ share.in.server_name = talloc_asprintf(mem_ctx, "%s", binding->host);
+
+ for (i = 0; i < ARRAY_SIZE(levels); i++) {
+ share.in.level = levels[i];
+ printf("testing libnet_ListShare level %u\n", share.in.level);
+
+ status = libnet_ListShares(libnetctx, mem_ctx, &share);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_ListShare level %u failed - %s\n", share.in.level, share.out.error_string);
+ ret = false;
+ goto done;
+ }
+
+ printf("listing shares:\n");
+ test_displayshares(share);
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+static bool test_addshare(struct dcerpc_pipe *svc_pipe, TALLOC_CTX *mem_ctx, const char *host,
+ const char* share)
+{
+ NTSTATUS status;
+ struct srvsvc_NetShareAdd add;
+ struct srvsvc_NetShareInfo2 i;
+
+ i.name = share;
+ i.type = STYPE_DISKTREE;
+ i.path = "C:\\WINDOWS\\TEMP";
+ i.max_users = 5;
+ i.comment = "Comment to the test share";
+ i.password = NULL;
+ i.permissions = 0x0;
+
+ add.in.server_unc = host;
+ add.in.level = 2;
+ add.in.info.info2 = &i;
+ add.in.parm_error = NULL;
+
+ status = dcerpc_srvsvc_NetShareAdd(svc_pipe, mem_ctx, &add);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to add a new share\n");
+ return false;
+ }
+
+ printf("share added\n");
+ return true;
+}
+
+
+bool torture_delshare(struct torture_context *torture)
+{
+ struct dcerpc_pipe *p;
+ struct dcerpc_binding *binding;
+ struct libnet_context* libnetctx;
+ const char *host;
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_DelShare share;
+
+ host = torture_setting_string(torture, "host", NULL);
+ status = torture_rpc_binding(torture, &binding);
+ torture_assert_ntstatus_ok(torture, status, "Failed to get binding");
+
+ libnetctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ libnetctx->cred = cmdline_credentials;
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_srvsvc);
+
+ torture_assert_ntstatus_ok(torture, status, "Failed to get rpc connection");
+
+ if (!test_addshare(p, torture, host, TEST_SHARENAME)) {
+ return false;
+ }
+
+ share.in.server_name = binding->host;
+ share.in.share_name = TEST_SHARENAME;
+
+ status = libnet_DelShare(libnetctx, torture, &share);
+ torture_assert_ntstatus_ok(torture, status, "Failed to delete share");
+
+ return ret;
+}
diff --git a/source4/torture/libnet/libnet_user.c b/source4/torture/libnet/libnet_user.c
new file mode 100644
index 0000000000..6d3e682976
--- /dev/null
+++ b/source4/torture/libnet/libnet_user.c
@@ -0,0 +1,736 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/time.h"
+#include "lib/cmdline/popt_common.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "librpc/gen_ndr/ndr_lsa_c.h"
+#include "torture/torture.h"
+#include "torture/rpc/rpc.h"
+#include "torture/libnet/usertest.h"
+#include "param/param.h"
+
+
+static bool test_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle, const char *username)
+{
+ NTSTATUS status;
+ struct samr_LookupNames r1;
+ struct samr_OpenUser r2;
+ struct samr_DeleteUser r3;
+ struct lsa_String names[2];
+ uint32_t rid;
+ struct policy_handle user_handle;
+
+ names[0].string = username;
+
+ r1.in.domain_handle = domain_handle;
+ r1.in.num_names = 1;
+ r1.in.names = names;
+
+ printf("user account lookup '%s'\n", username);
+
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupNames failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ rid = r1.out.rids.ids[0];
+
+ r2.in.domain_handle = domain_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.rid = rid;
+ r2.out.user_handle = &user_handle;
+
+ printf("opening user account\n");
+
+ status = dcerpc_samr_OpenUser(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("OpenUser failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r3.in.user_handle = &user_handle;
+ r3.out.user_handle = &user_handle;
+
+ printf("deleting user account\n");
+
+ status = dcerpc_samr_DeleteUser(p, mem_ctx, &r3);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("DeleteUser failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_opendomain(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname)
+{
+ NTSTATUS status;
+ struct policy_handle h, domain_handle;
+ struct samr_Connect r1;
+ struct samr_LookupDomain r2;
+ struct samr_OpenDomain r3;
+
+ printf("connecting\n");
+
+ r1.in.system_name = 0;
+ r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r1.out.connect_handle = &h;
+
+ status = dcerpc_samr_Connect(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Connect failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r2.in.connect_handle = &h;
+ r2.in.domain_name = domname;
+
+ printf("domain lookup on %s\n", domname->string);
+
+ status = dcerpc_samr_LookupDomain(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupDomain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r3.in.connect_handle = &h;
+ r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r3.in.sid = r2.out.sid;
+ r3.out.domain_handle = &domain_handle;
+
+ printf("opening domain\n");
+
+ status = dcerpc_samr_OpenDomain(p, mem_ctx, &r3);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("OpenDomain failed - %s\n", nt_errstr(status));
+ return false;
+ } else {
+ *handle = domain_handle;
+ }
+
+ return true;
+}
+
+
+static bool test_samr_close(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct samr_Close r;
+
+ r.in.handle = domain_handle;
+ r.out.handle = domain_handle;
+
+ status = dcerpc_samr_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close samr domain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_lsa_close(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle)
+{
+ NTSTATUS status;
+ struct lsa_Close r;
+
+ r.in.handle = domain_handle;
+ r.out.handle = domain_handle;
+
+ status = dcerpc_lsa_Close(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close lsa domain failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_createuser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char* user)
+{
+ NTSTATUS status;
+ struct policy_handle user_handle;
+ struct lsa_String username;
+ struct samr_CreateUser r1;
+ struct samr_Close r2;
+ uint32_t user_rid;
+
+ username.string = user;
+
+ r1.in.domain_handle = handle;
+ r1.in.account_name = &username;
+ r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r1.out.user_handle = &user_handle;
+ r1.out.rid = &user_rid;
+
+ printf("creating user '%s'\n", username.string);
+
+ status = dcerpc_samr_CreateUser(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateUser failed - %s\n", nt_errstr(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ printf("User (%s) already exists - attempting to delete and recreate account again\n", user);
+ if (!test_cleanup(p, mem_ctx, handle, TEST_USERNAME)) {
+ return false;
+ }
+
+ printf("creating user account\n");
+
+ status = dcerpc_samr_CreateUser(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateUser failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ r2.in.handle = &user_handle;
+ r2.out.handle = &user_handle;
+
+ printf("closing user '%s'\n", username.string);
+
+ status = dcerpc_samr_Close(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Close failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_createuser(struct torture_context *torture)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+ struct libnet_context *ctx;
+ struct libnet_CreateUser req;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_createuser");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ req.in.user_name = TEST_USERNAME;
+ req.in.domain_name = lp_workgroup(torture->lp_ctx);
+ req.out.error_string = NULL;
+
+ status = libnet_CreateUser(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_CreateUser call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, TEST_USERNAME)) {
+ printf("cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_deleteuser(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *prep_mem_ctx, *mem_ctx;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ const char *name = TEST_USERNAME;
+ struct libnet_context *ctx;
+ struct libnet_DeleteUser req;
+ bool ret = true;
+
+ prep_mem_ctx = talloc_init("prepare test_deleteuser");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ req.in.user_name = TEST_USERNAME;
+ req.in.domain_name = lp_workgroup(torture->lp_ctx);
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_createuser(p, prep_mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ mem_ctx = talloc_init("test_deleteuser");
+
+ status = libnet_DeleteUser(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_DeleteUser call failed: %s\n", nt_errstr(status));
+ ret = false;
+ }
+
+ talloc_free(mem_ctx);
+
+done:
+ talloc_free(ctx);
+ talloc_free(prep_mem_ctx);
+ return ret;
+}
+
+
+/*
+ Generate testing set of random changes
+*/
+
+static void set_test_changes(TALLOC_CTX *mem_ctx, struct libnet_ModifyUser *r,
+ int num_changes, char **user_name, enum test_fields req_change)
+{
+ const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
+ const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
+ const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
+ const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED),
+ (ACB_NORMAL | ACB_PWNOEXP),
+ (ACB_NORMAL | ACB_PW_EXPIRED) };
+ const char *homedir, *homedrive, *logonscript;
+ struct timeval now;
+ int i, testfld;
+
+ printf("Fields to change: [");
+
+ for (i = 0; i < num_changes && i < FIELDS_NUM; i++) {
+ const char *fldname;
+
+ testfld = (req_change == none) ? (random() % FIELDS_NUM) : req_change;
+
+ /* get one in case we hit time field this time */
+ gettimeofday(&now, NULL);
+
+ switch (testfld) {
+ case account_name:
+ continue_if_field_set(r->in.account_name);
+ r->in.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
+ (int)(random() % 100));
+ fldname = "account_name";
+
+ /* update the test's user name in case it's about to change */
+ *user_name = talloc_strdup(mem_ctx, r->in.account_name);
+ break;
+
+ case full_name:
+ continue_if_field_set(r->in.full_name);
+ r->in.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME,
+ (unsigned int)random(), (unsigned int)random());
+ fldname = "full_name";
+ break;
+
+ case description:
+ continue_if_field_set(r->in.description);
+ r->in.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION,
+ (long)random());
+ fldname = "description";
+ break;
+
+ case home_directory:
+ continue_if_field_set(r->in.home_directory);
+ homedir = home_dirs[random() % ARRAY_SIZE(home_dirs)];
+ r->in.home_directory = talloc_strdup(mem_ctx, homedir);
+ fldname = "home_dir";
+ break;
+
+ case home_drive:
+ continue_if_field_set(r->in.home_drive);
+ homedrive = home_drives[random() % ARRAY_SIZE(home_drives)];
+ r->in.home_drive = talloc_strdup(mem_ctx, homedrive);
+ fldname = "home_drive";
+ break;
+
+ case comment:
+ continue_if_field_set(r->in.comment);
+ r->in.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT,
+ (unsigned long)random(), (unsigned long)random());
+ fldname = "comment";
+ break;
+
+ case logon_script:
+ continue_if_field_set(r->in.logon_script);
+ logonscript = logon_scripts[random() % ARRAY_SIZE(logon_scripts)];
+ r->in.logon_script = talloc_strdup(mem_ctx, logonscript);
+ fldname = "logon_script";
+ break;
+
+ case profile_path:
+ continue_if_field_set(r->in.profile_path);
+ r->in.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH,
+ (unsigned long)random(), (unsigned int)random());
+ fldname = "profile_path";
+ break;
+
+ case acct_expiry:
+ continue_if_field_set(r->in.acct_expiry);
+ now = timeval_add(&now, (random() % (31*24*60*60)), 0);
+ r->in.acct_expiry = (struct timeval *)talloc_memdup(mem_ctx, &now, sizeof(now));
+ fldname = "acct_expiry";
+ break;
+
+ case acct_flags:
+ continue_if_field_set(r->in.acct_flags);
+ r->in.acct_flags = flags[random() % ARRAY_SIZE(flags)];
+ fldname = "acct_flags";
+ break;
+
+ default:
+ fldname = "unknown_field";
+ }
+
+ printf(((i < num_changes - 1) ? "%s," : "%s"), fldname);
+
+ /* disable requested field (it's supposed to be the only one used) */
+ if (req_change != none) req_change = none;
+ }
+
+ printf("]\n");
+}
+
+
+#define TEST_STR_FLD(fld) \
+ if (!strequal(req.in.fld, user_req.out.fld)) { \
+ printf("failed to change '%s'\n", #fld); \
+ ret = false; \
+ goto cleanup; \
+ }
+
+#define TEST_TIME_FLD(fld) \
+ if (timeval_compare(req.in.fld, user_req.out.fld)) { \
+ printf("failed to change '%s'\n", #fld); \
+ ret = false; \
+ goto cleanup; \
+ }
+
+#define TEST_NUM_FLD(fld) \
+ if (req.in.fld != user_req.out.fld) { \
+ printf("failed to change '%s'\n", #fld); \
+ ret = false; \
+ goto cleanup; \
+ }
+
+
+bool torture_modifyuser(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_binding *binding;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *prep_mem_ctx;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ char *name;
+ struct libnet_context *ctx;
+ struct libnet_ModifyUser req;
+ struct libnet_UserInfo user_req;
+ int fld;
+ bool ret = true;
+
+ prep_mem_ctx = talloc_init("prepare test_deleteuser");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ name = talloc_strdup(prep_mem_ctx, TEST_USERNAME);
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_createuser(p, prep_mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ status = torture_rpc_binding(torture, &binding);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ goto done;
+ }
+
+ printf("Testing change of all fields - each single one in turn\n");
+
+ for (fld = 1; fld < FIELDS_NUM - 1; fld++) {
+ ZERO_STRUCT(req);
+ req.in.domain_name = lp_workgroup(torture->lp_ctx);
+ req.in.user_name = name;
+
+ set_test_changes(torture, &req, 1, &name, fld);
+
+ status = libnet_ModifyUser(ctx, torture, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status));
+ ret = false;
+ continue;
+ }
+
+ ZERO_STRUCT(user_req);
+ user_req.in.domain_name = lp_workgroup(torture->lp_ctx);
+ user_req.in.data.user_name = name;
+ user_req.in.level = USER_INFO_BY_NAME;
+
+ status = libnet_UserInfo(ctx, torture, &user_req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_UserInfo call failed: %s\n", nt_errstr(status));
+ ret = false;
+ continue;
+ }
+
+ switch (fld) {
+ case account_name: TEST_STR_FLD(account_name);
+ break;
+ case full_name: TEST_STR_FLD(full_name);
+ break;
+ case comment: TEST_STR_FLD(comment);
+ break;
+ case description: TEST_STR_FLD(description);
+ break;
+ case home_directory: TEST_STR_FLD(home_directory);
+ break;
+ case home_drive: TEST_STR_FLD(home_drive);
+ break;
+ case logon_script: TEST_STR_FLD(logon_script);
+ break;
+ case profile_path: TEST_STR_FLD(profile_path);
+ break;
+ case acct_expiry: TEST_TIME_FLD(acct_expiry);
+ break;
+ case acct_flags: TEST_NUM_FLD(acct_flags);
+ break;
+ default:
+ break;
+ }
+
+ if (fld == account_name) {
+ /* restore original testing username - it's useful when test fails
+ because it prevents from problems with recreating account */
+ ZERO_STRUCT(req);
+ req.in.domain_name = lp_workgroup(torture->lp_ctx);
+ req.in.user_name = name;
+ req.in.account_name = TEST_USERNAME;
+
+ status = libnet_ModifyUser(ctx, torture, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_ModifyUser call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ name = talloc_strdup(torture, TEST_USERNAME);
+ }
+ }
+
+cleanup:
+ if (!test_cleanup(ctx->samr.pipe, torture, &ctx->samr.handle, name)) {
+ printf("cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, torture, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = false;
+ }
+
+done:
+ talloc_free(ctx);
+ talloc_free(prep_mem_ctx);
+ return ret;
+}
+
+
+bool torture_userinfo_api(struct torture_context *torture)
+{
+ const char *name = TEST_USERNAME;
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL, *prep_mem_ctx;
+ struct libnet_context *ctx;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct libnet_UserInfo req;
+
+ prep_mem_ctx = talloc_init("prepare torture user info");
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(p, prep_mem_ctx, &h, &domain_name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_createuser(p, prep_mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ mem_ctx = talloc_init("torture user info");
+
+ ZERO_STRUCT(req);
+
+ req.in.domain_name = domain_name.string;
+ req.in.data.user_name = name;
+ req.in.level = USER_INFO_BY_NAME;
+
+ status = libnet_UserInfo(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("libnet_UserInfo call failed: %s\n", nt_errstr(status));
+ ret = false;
+ talloc_free(mem_ctx);
+ goto done;
+ }
+
+ if (!test_cleanup(ctx->samr.pipe, mem_ctx, &ctx->samr.handle, TEST_USERNAME)) {
+ printf("cleanup failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("domain close failed\n");
+ ret = false;
+ }
+
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_userlist(struct torture_context *torture)
+{
+ bool ret = true;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct libnet_context *ctx;
+ struct lsa_String domain_name;
+ struct libnet_UserList req;
+ int i;
+
+ ctx = libnet_context_init(torture->ev, torture->lp_ctx);
+ ctx->cred = cmdline_credentials;
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ mem_ctx = talloc_init("torture user list");
+
+ ZERO_STRUCT(req);
+
+ printf("listing user accounts:\n");
+
+ do {
+
+ req.in.domain_name = domain_name.string;
+ req.in.page_size = 128;
+ req.in.resume_index = req.out.resume_index;
+
+ status = libnet_UserList(ctx, mem_ctx, &req);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) break;
+
+ for (i = 0; i < req.out.count; i++) {
+ printf("\tuser: %s, sid=%s\n",
+ req.out.users[i].username, req.out.users[i].sid);
+ }
+
+ } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
+
+ if (!(NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES))) {
+ printf("libnet_UserList call failed: %s\n", nt_errstr(status));
+ ret = false;
+ goto done;
+ }
+
+ if (!test_samr_close(ctx->samr.pipe, mem_ctx, &ctx->samr.handle)) {
+ printf("samr domain close failed\n");
+ ret = false;
+ goto done;
+ }
+
+ if (!test_lsa_close(ctx->lsa.pipe, mem_ctx, &ctx->lsa.handle)) {
+ printf("lsa domain close failed\n");
+ ret = false;
+ }
+
+ talloc_free(ctx);
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/userinfo.c b/source4/torture/libnet/userinfo.c
new file mode 100644
index 0000000000..11e57f852d
--- /dev/null
+++ b/source4/torture/libnet/userinfo.c
@@ -0,0 +1,202 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "libnet/libnet.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+#include "torture/libnet/utils.h"
+
+
+#define TEST_USERNAME "libnetuserinfotest"
+
+static bool test_userinfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 *domain_sid, const char* user_name,
+ uint32_t *rid)
+{
+ const uint16_t level = 5;
+ NTSTATUS status;
+ struct libnet_rpc_userinfo user;
+ struct dom_sid *user_sid;
+
+ user_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = dom_sid_string(mem_ctx, user_sid);
+ user.in.level = level; /* this should be extended */
+
+ printf("Testing sync libnet_rpc_userinfo (SID argument)\n");
+ status = libnet_rpc_userinfo(p, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_userinfo - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = NULL;
+ user.in.username = TEST_USERNAME;
+ user.in.level = level;
+
+ printf("Testing sync libnet_rpc_userinfo (username argument)\n");
+ status = libnet_rpc_userinfo(p, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_userinfo - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool test_userinfo_async(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ struct dom_sid2 *domain_sid, const char* user_name,
+ uint32_t *rid)
+{
+ const uint16_t level = 10;
+ NTSTATUS status;
+ struct composite_context *c;
+ struct libnet_rpc_userinfo user;
+ struct dom_sid *user_sid;
+
+ user_sid = dom_sid_add_rid(mem_ctx, domain_sid, *rid);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = dom_sid_string(mem_ctx, user_sid);
+ user.in.level = level; /* this should be extended */
+
+ printf("Testing async libnet_rpc_userinfo (SID argument)\n");
+
+ c = libnet_rpc_userinfo_send(p, &user, msg_handler);
+ if (!c) {
+ printf("Failed to call sync libnet_rpc_userinfo_send\n");
+ return false;
+ }
+
+ status = libnet_rpc_userinfo_recv(c, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Calling async libnet_rpc_userinfo failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ ZERO_STRUCT(user);
+
+ user.in.domain_handle = *domain_handle;
+ user.in.sid = NULL;
+ user.in.username = TEST_USERNAME;
+ user.in.level = level;
+
+ printf("Testing async libnet_rpc_userinfo (username argument)\n");
+
+ c = libnet_rpc_userinfo_send(p, &user, msg_handler);
+ if (!c) {
+ printf("Failed to call sync libnet_rpc_userinfo_send\n");
+ return false;
+ }
+
+ status = libnet_rpc_userinfo_recv(c, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Calling async libnet_rpc_userinfo failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool torture_userinfo(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+ struct policy_handle h;
+ struct lsa_String name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+
+ mem_ctx = talloc_init("test_userinfo");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ name.string = lp_workgroup(torture->lp_ctx);
+
+ /*
+ * Testing synchronous version
+ */
+ if (!test_opendomain(torture, p, mem_ctx, &h, &name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, p, mem_ctx, &h, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_userinfo(p, mem_ctx, &h, &sid, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, p, mem_ctx, &h, TEST_USERNAME)) {
+ ret = false;
+ goto done;
+ }
+
+ /*
+ * Testing asynchronous version and monitor messages
+ */
+ if (!test_opendomain(torture, p, mem_ctx, &h, &name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, p, mem_ctx, &h, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_userinfo_async(p, mem_ctx, &h, &sid, TEST_USERNAME, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, p, mem_ctx, &h, TEST_USERNAME)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+
+ return ret;
+}
diff --git a/source4/torture/libnet/userman.c b/source4/torture/libnet/userman.c
new file mode 100644
index 0000000000..a5d8540d7b
--- /dev/null
+++ b/source4/torture/libnet/userman.c
@@ -0,0 +1,461 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 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
+ 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,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "torture/libnet/usertest.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+
+#include "torture/libnet/utils.h"
+
+
+static bool test_useradd(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ bool ret = true;
+ struct libnet_rpc_useradd user;
+
+ user.in.domain_handle = *domain_handle;
+ user.in.username = name;
+
+ printf("Testing libnet_rpc_useradd\n");
+
+ status = libnet_rpc_useradd(p, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call libnet_rpc_useradd - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return ret;
+}
+
+
+static bool test_useradd_async(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char* username)
+{
+ NTSTATUS status;
+ struct composite_context *c;
+ struct libnet_rpc_useradd user;
+
+ user.in.domain_handle = *handle;
+ user.in.username = username;
+
+ printf("Testing async libnet_rpc_useradd\n");
+
+ c = libnet_rpc_useradd_send(p, &user, msg_handler);
+ if (!c) {
+ printf("Failed to call async libnet_rpc_useradd\n");
+ return false;
+ }
+
+ status = libnet_rpc_useradd_recv(c, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Calling async libnet_rpc_useradd failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+
+}
+
+static bool test_usermod(struct torture_context *tctx, struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, int num_changes,
+ struct libnet_rpc_usermod *mod, char **username)
+{
+ const char* logon_scripts[] = { "start_login.cmd", "login.bat", "start.cmd" };
+ const char* home_dirs[] = { "\\\\srv\\home", "\\\\homesrv\\home\\user", "\\\\pdcsrv\\domain" };
+ const char* home_drives[] = { "H:", "z:", "I:", "J:", "n:" };
+ const char *homedir, *homedrive, *logonscript;
+ const uint32_t flags[] = { (ACB_DISABLED | ACB_NORMAL | ACB_PW_EXPIRED),
+ (ACB_NORMAL | ACB_PWNOEXP),
+ (ACB_NORMAL | ACB_PW_EXPIRED) };
+
+ NTSTATUS status;
+ struct timeval now;
+ enum test_fields testfld;
+ int i;
+
+ ZERO_STRUCT(*mod);
+ srandom((unsigned)time(NULL));
+
+ mod->in.username = talloc_strdup(mem_ctx, *username);
+ mod->in.domain_handle = *handle;
+
+ torture_comment(tctx, "modifying user (%d simultaneous change(s))\n",
+ num_changes);
+
+ torture_comment(tctx, "fields to change: [");
+
+ for (i = 0; i < num_changes && i < FIELDS_NUM - 1; i++) {
+ const char *fldname;
+
+ testfld = (random() % (FIELDS_NUM - 1)) + 1;
+
+ gettimeofday(&now, NULL);
+
+ switch (testfld) {
+ case account_name:
+ continue_if_field_set(mod->in.change.account_name);
+ mod->in.change.account_name = talloc_asprintf(mem_ctx, TEST_CHG_ACCOUNTNAME,
+ (int)(random() % 100));
+ mod->in.change.fields |= USERMOD_FIELD_ACCOUNT_NAME;
+ fldname = "account_name";
+ *username = talloc_strdup(mem_ctx, mod->in.change.account_name);
+ break;
+
+ case full_name:
+ continue_if_field_set(mod->in.change.full_name);
+ mod->in.change.full_name = talloc_asprintf(mem_ctx, TEST_CHG_FULLNAME,
+ (int)random(), (int)random());
+ mod->in.change.fields |= USERMOD_FIELD_FULL_NAME;
+ fldname = "full_name";
+ break;
+
+ case description:
+ continue_if_field_set(mod->in.change.description);
+ mod->in.change.description = talloc_asprintf(mem_ctx, TEST_CHG_DESCRIPTION,
+ random());
+ mod->in.change.fields |= USERMOD_FIELD_DESCRIPTION;
+ fldname = "description";
+ break;
+
+ case home_directory:
+ continue_if_field_set(mod->in.change.home_directory);
+ homedir = home_dirs[random() % (sizeof(home_dirs)/sizeof(char*))];
+ mod->in.change.home_directory = talloc_strdup(mem_ctx, homedir);
+ mod->in.change.fields |= USERMOD_FIELD_HOME_DIRECTORY;
+ fldname = "home_directory";
+ break;
+
+ case home_drive:
+ continue_if_field_set(mod->in.change.home_drive);
+ homedrive = home_drives[random() % (sizeof(home_drives)/sizeof(char*))];
+ mod->in.change.home_drive = talloc_strdup(mem_ctx, homedrive);
+ mod->in.change.fields |= USERMOD_FIELD_HOME_DRIVE;
+ fldname = "home_drive";
+ break;
+
+ case comment:
+ continue_if_field_set(mod->in.change.comment);
+ mod->in.change.comment = talloc_asprintf(mem_ctx, TEST_CHG_COMMENT,
+ random(), random());
+ mod->in.change.fields |= USERMOD_FIELD_COMMENT;
+ fldname = "comment";
+ break;
+
+ case logon_script:
+ continue_if_field_set(mod->in.change.logon_script);
+ logonscript = logon_scripts[random() % (sizeof(logon_scripts)/sizeof(char*))];
+ mod->in.change.logon_script = talloc_strdup(mem_ctx, logonscript);
+ mod->in.change.fields |= USERMOD_FIELD_LOGON_SCRIPT;
+ fldname = "logon_script";
+ break;
+
+ case profile_path:
+ continue_if_field_set(mod->in.change.profile_path);
+ mod->in.change.profile_path = talloc_asprintf(mem_ctx, TEST_CHG_PROFILEPATH,
+ (long int)random(), (unsigned int)random());
+ mod->in.change.fields |= USERMOD_FIELD_PROFILE_PATH;
+ fldname = "profile_path";
+ break;
+
+ case acct_expiry:
+ continue_if_field_set(mod->in.change.acct_expiry);
+ now = timeval_add(&now, (random() % (31*24*60*60)), 0);
+ mod->in.change.acct_expiry = (struct timeval *)talloc_memdup(mem_ctx, &now, sizeof(now));
+ mod->in.change.fields |= USERMOD_FIELD_ACCT_EXPIRY;
+ fldname = "acct_expiry";
+ break;
+
+ case acct_flags:
+ continue_if_field_set(mod->in.change.acct_flags);
+ mod->in.change.acct_flags = flags[random() % ARRAY_SIZE(flags)];
+ mod->in.change.fields |= USERMOD_FIELD_ACCT_FLAGS;
+ fldname = "acct_flags";
+ break;
+
+ default:
+ fldname = talloc_asprintf(mem_ctx, "unknown_field (%d)", testfld);
+ break;
+ }
+
+ torture_comment(tctx, ((i < num_changes - 1) ? "%s," : "%s"), fldname);
+ }
+ torture_comment(tctx, "]\n");
+
+ status = libnet_rpc_usermod(p, mem_ctx, mod);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to call sync libnet_rpc_usermod");
+
+ return true;
+}
+
+
+static bool test_userdel(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *username)
+{
+ NTSTATUS status;
+ struct libnet_rpc_userdel user;
+
+ user.in.domain_handle = *handle;
+ user.in.username = username;
+
+ status = libnet_rpc_userdel(p, mem_ctx, &user);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("Failed to call sync libnet_rpc_userdel - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+#define CMP_LSA_STRING_FLD(fld, flags) \
+ if ((mod->in.change.fields & flags) && \
+ !strequal(i->fld.string, mod->in.change.fld)) { \
+ printf("'%s' field does not match\n", #fld); \
+ printf("received: '%s'\n", i->fld.string); \
+ printf("expected: '%s'\n", mod->in.change.fld); \
+ return false; \
+ }
+
+
+#define CMP_TIME_FLD(fld, flags) \
+ if (mod->in.change.fields & flags) { \
+ nttime_to_timeval(&t, i->fld); \
+ if (timeval_compare(&t, mod->in.change.fld)) { \
+ printf("'%s' field does not match\n", #fld); \
+ printf("received: '%s (+%ld us)'\n", \
+ timestring(mem_ctx, t.tv_sec), t.tv_usec); \
+ printf("expected: '%s (+%ld us)'\n", \
+ timestring(mem_ctx, mod->in.change.fld->tv_sec), \
+ mod->in.change.fld->tv_usec); \
+ return false; \
+ } \
+ }
+
+#define CMP_NUM_FLD(fld, flags) \
+ if ((mod->in.change.fields & flags) && \
+ (i->fld != mod->in.change.fld)) { \
+ printf("'%s' field does not match\n", #fld); \
+ printf("received: '%04x'\n", i->fld); \
+ printf("expected: '%04x'\n", mod->in.change.fld); \
+ return false; \
+ }
+
+
+static bool test_compare(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct libnet_rpc_usermod *mod,
+ const char *username)
+{
+ NTSTATUS status;
+ struct libnet_rpc_userinfo info;
+ struct samr_UserInfo21 *i;
+ struct timeval t;
+
+ ZERO_STRUCT(info);
+
+ info.in.username = username;
+ info.in.domain_handle = *handle;
+ info.in.level = 21; /* the most rich infolevel available */
+
+ status = libnet_rpc_userinfo(p, mem_ctx, &info);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to call sync libnet_rpc_userinfo");
+
+ i = &info.out.info.info21;
+
+ CMP_LSA_STRING_FLD(account_name, USERMOD_FIELD_ACCOUNT_NAME);
+ CMP_LSA_STRING_FLD(full_name, USERMOD_FIELD_FULL_NAME);
+ CMP_LSA_STRING_FLD(description, USERMOD_FIELD_DESCRIPTION);
+ CMP_LSA_STRING_FLD(comment, USERMOD_FIELD_COMMENT);
+ CMP_LSA_STRING_FLD(logon_script, USERMOD_FIELD_LOGON_SCRIPT);
+ CMP_LSA_STRING_FLD(profile_path, USERMOD_FIELD_PROFILE_PATH);
+ CMP_LSA_STRING_FLD(home_directory, USERMOD_FIELD_HOME_DIRECTORY);
+ CMP_LSA_STRING_FLD(home_drive, USERMOD_FIELD_HOME_DRIVE);
+ CMP_TIME_FLD(acct_expiry, USERMOD_FIELD_ACCT_EXPIRY);
+ CMP_NUM_FLD(acct_flags, USERMOD_FIELD_ACCT_FLAGS)
+
+ return true;
+}
+
+
+bool torture_useradd(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ const char *name = TEST_USERNAME;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_useradd");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ torture_assert_ntstatus_ok(torture, status, "RPC connect failed");
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_useradd(p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_useradd_async(p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_cleanup(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_userdel(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+ const char *name = TEST_USERNAME;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_userdel");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, p, mem_ctx, &h, name, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_userdel(p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
+
+bool torture_usermod(struct torture_context *torture)
+{
+ NTSTATUS status;
+ struct dcerpc_pipe *p;
+ struct policy_handle h;
+ struct lsa_String domain_name;
+ struct dom_sid2 sid;
+ uint32_t rid;
+ int i;
+ char *name;
+ TALLOC_CTX *mem_ctx;
+ bool ret = true;
+
+ mem_ctx = talloc_init("test_userdel");
+
+ status = torture_rpc_connection(torture,
+ &p,
+ &ndr_table_samr);
+
+ torture_assert_ntstatus_ok(torture, status, "RPC connect");
+
+ domain_name.string = lp_workgroup(torture->lp_ctx);
+ name = talloc_strdup(mem_ctx, TEST_USERNAME);
+
+ if (!test_opendomain(torture, p, mem_ctx, &h, &domain_name, &sid)) {
+ ret = false;
+ goto done;
+ }
+
+ if (!test_user_create(torture, p, mem_ctx, &h, name, &rid)) {
+ ret = false;
+ goto done;
+ }
+
+ for (i = 1; i < FIELDS_NUM; i++) {
+ struct libnet_rpc_usermod m;
+
+ if (!test_usermod(torture, p, mem_ctx, &h, i, &m, &name)) {
+ ret = false;
+ goto cleanup;
+ }
+
+ if (!test_compare(torture, p, mem_ctx, &h, &m, name)) {
+ ret = false;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (!test_user_cleanup(torture, p, mem_ctx, &h, name)) {
+ ret = false;
+ goto done;
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
diff --git a/source4/torture/libnet/usertest.h b/source4/torture/libnet/usertest.h
new file mode 100644
index 0000000000..19d56415b3
--- /dev/null
+++ b/source4/torture/libnet/usertest.h
@@ -0,0 +1,38 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Copyright (C) Rafal Szczesniak 2006
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#define TEST_USERNAME "libnetusertest"
+
+#define continue_if_field_set(field) \
+ if (field != 0) { \
+ i--; \
+ continue; \
+ }
+
+
+#define FIELDS_NUM 11
+enum test_fields { none = 0, account_name, full_name, description, home_directory, home_drive,
+ comment, logon_script, profile_path, acct_expiry, acct_flags };
+
+
+#define TEST_CHG_ACCOUNTNAME "newlibnetusertest%02d"
+#define TEST_CHG_DESCRIPTION "Sample description %ld"
+#define TEST_CHG_FULLNAME "First%04x Last%04x"
+#define TEST_CHG_COMMENT "Comment[%04lu%04lu]"
+#define TEST_CHG_PROFILEPATH "\\\\srv%04ld\\profile%02u\\prof"
diff --git a/source4/torture/libnet/utils.c b/source4/torture/libnet/utils.c
new file mode 100644
index 0000000000..d4124cc823
--- /dev/null
+++ b/source4/torture/libnet/utils.c
@@ -0,0 +1,293 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * These are more general use functions shared among the tests.
+ */
+
+#include "includes.h"
+#include "torture/rpc/rpc.h"
+#include "libnet/libnet.h"
+#include "librpc/gen_ndr/ndr_samr_c.h"
+#include "param/param.h"
+
+
+bool test_opendomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname,
+ struct dom_sid2 *sid)
+{
+ NTSTATUS status;
+ struct policy_handle h, domain_handle;
+ struct samr_Connect r1;
+ struct samr_LookupDomain r2;
+ struct samr_OpenDomain r3;
+
+ torture_comment(tctx, "connecting\n");
+
+ r1.in.system_name = 0;
+ r1.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r1.out.connect_handle = &h;
+
+ status = dcerpc_samr_Connect(p, mem_ctx, &r1);
+ torture_assert_ntstatus_ok(tctx, status, "Connect failed");
+
+ r2.in.connect_handle = &h;
+ r2.in.domain_name = domname;
+
+ torture_comment(tctx, "domain lookup on %s\n", domname->string);
+
+ status = dcerpc_samr_LookupDomain(p, mem_ctx, &r2);
+ torture_assert_ntstatus_ok(tctx, status, "LookupDomain failed");
+
+ r3.in.connect_handle = &h;
+ r3.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r3.in.sid = r2.out.sid;
+ r3.out.domain_handle = &domain_handle;
+
+ torture_comment(tctx, "opening domain\n");
+
+ status = dcerpc_samr_OpenDomain(p, mem_ctx, &r3);
+ torture_assert_ntstatus_ok(tctx, status, "OpenDomain failed");
+ *handle = domain_handle;
+
+ *sid = *r2.out.sid;
+ return true;
+}
+
+
+bool test_user_cleanup(struct torture_context *tctx, struct dcerpc_pipe *p,
+ TALLOC_CTX *mem_ctx, struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ struct samr_LookupNames r1;
+ struct samr_OpenUser r2;
+ struct samr_DeleteUser r3;
+ struct lsa_String names[2];
+ uint32_t rid;
+ struct policy_handle user_handle;
+
+ names[0].string = name;
+
+ r1.in.domain_handle = domain_handle;
+ r1.in.num_names = 1;
+ r1.in.names = names;
+
+ torture_comment(tctx, "user account lookup '%s'\n", name);
+
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &r1);
+ torture_assert_ntstatus_ok(tctx, status, "LookupNames failed");
+
+ rid = r1.out.rids.ids[0];
+
+ r2.in.domain_handle = domain_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.rid = rid;
+ r2.out.user_handle = &user_handle;
+
+ torture_comment(tctx, "opening user account\n");
+
+ status = dcerpc_samr_OpenUser(p, mem_ctx, &r2);
+ torture_assert_ntstatus_ok(tctx, status, "OpenUser failed");
+
+ r3.in.user_handle = &user_handle;
+ r3.out.user_handle = &user_handle;
+
+ torture_comment(tctx, "deleting user account\n");
+
+ status = dcerpc_samr_DeleteUser(p, mem_ctx, &r3);
+ torture_assert_ntstatus_ok(tctx, status, "DeleteUser failed");
+
+ return true;
+}
+
+
+bool test_user_create(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *name,
+ uint32_t *rid)
+{
+ NTSTATUS status;
+ struct lsa_String username;
+ struct samr_CreateUser r;
+ struct policy_handle user_handle;
+
+ username.string = name;
+
+ r.in.domain_handle = handle;
+ r.in.account_name = &username;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.user_handle = &user_handle;
+ r.out.rid = rid;
+
+ torture_comment(tctx, "creating user account %s\n", name);
+
+ status = dcerpc_samr_CreateUser(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateUser failed - %s\n", nt_errstr(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ torture_comment(tctx, "User (%s) already exists - attempting to delete and recreate account again\n", name);
+ if (!test_user_cleanup(tctx, p, mem_ctx, handle, name)) {
+ return false;
+ }
+
+ torture_comment(tctx, "creating user account\n");
+
+ status = dcerpc_samr_CreateUser(p, mem_ctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "CreateUser failed");
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+bool test_group_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name)
+{
+ NTSTATUS status;
+ struct samr_LookupNames r1;
+ struct samr_OpenGroup r2;
+ struct samr_DeleteDomainGroup r3;
+ struct lsa_String names[2];
+ uint32_t rid;
+ struct policy_handle group_handle;
+
+ names[0].string = name;
+
+ r1.in.domain_handle = domain_handle;
+ r1.in.num_names = 1;
+ r1.in.names = names;
+
+ printf("group account lookup '%s'\n", name);
+
+ status = dcerpc_samr_LookupNames(p, mem_ctx, &r1);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("LookupNames failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ rid = r1.out.rids.ids[0];
+
+ r2.in.domain_handle = domain_handle;
+ r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r2.in.rid = rid;
+ r2.out.group_handle = &group_handle;
+
+ printf("opening group account\n");
+
+ status = dcerpc_samr_OpenGroup(p, mem_ctx, &r2);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("OpenGroup failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ r3.in.group_handle = &group_handle;
+ r3.out.group_handle = &group_handle;
+
+ printf("deleting group account\n");
+
+ status = dcerpc_samr_DeleteDomainGroup(p, mem_ctx, &r3);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("DeleteGroup failed - %s\n", nt_errstr(status));
+ return false;
+ }
+
+ return true;
+}
+
+
+bool test_group_create(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *name,
+ uint32_t *rid)
+{
+ NTSTATUS status;
+ struct lsa_String groupname;
+ struct samr_CreateDomainGroup r;
+ struct policy_handle group_handle;
+
+ groupname.string = name;
+
+ r.in.domain_handle = handle;
+ r.in.name = &groupname;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.group_handle = &group_handle;
+ r.out.rid = rid;
+
+ printf("creating group account %s\n", name);
+
+ status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateGroup failed - %s\n", nt_errstr(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
+ printf("Group (%s) already exists - attempting to delete and recreate account again\n", name);
+ if (!test_group_cleanup(p, mem_ctx, handle, name)) {
+ return false;
+ }
+
+ printf("creating group account\n");
+
+ status = dcerpc_samr_CreateDomainGroup(p, mem_ctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("CreateGroup failed - %s\n", nt_errstr(status));
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+void msg_handler(struct monitor_msg *m)
+{
+ struct msg_rpc_open_user *msg_open;
+ struct msg_rpc_query_user *msg_query;
+ struct msg_rpc_close_user *msg_close;
+ struct msg_rpc_create_user *msg_create;
+
+ switch (m->type) {
+ case mon_SamrOpenUser:
+ msg_open = (struct msg_rpc_open_user*)m->data;
+ printf("monitor_msg: user opened (rid=%d, access_mask=0x%08x)\n",
+ msg_open->rid, msg_open->access_mask);
+ break;
+ case mon_SamrQueryUser:
+ msg_query = (struct msg_rpc_query_user*)m->data;
+ printf("monitor_msg: user queried (level=%d)\n", msg_query->level);
+ break;
+ case mon_SamrCloseUser:
+ msg_close = (struct msg_rpc_close_user*)m->data;
+ printf("monitor_msg: user closed (rid=%d)\n", msg_close->rid);
+ break;
+ case mon_SamrCreateUser:
+ msg_create = (struct msg_rpc_create_user*)m->data;
+ printf("monitor_msg: user created (rid=%d)\n", msg_create->rid);
+ break;
+ }
+}
diff --git a/source4/torture/libnet/utils.h b/source4/torture/libnet/utils.h
new file mode 100644
index 0000000000..b513b1a29e
--- /dev/null
+++ b/source4/torture/libnet/utils.h
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/CIFS implementation.
+ Test suite for libnet calls.
+
+ Copyright (C) Rafal Szczesniak 2007
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+
+
+bool test_opendomain(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, struct lsa_String *domname,
+ struct dom_sid2 *sid);
+
+bool test_user_create(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *name,
+ uint32_t *rid);
+
+bool test_user_cleanup(struct torture_context *tctx,
+ struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name);
+
+bool test_group_create(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *handle, const char *name,
+ uint32_t *rid);
+
+bool test_group_cleanup(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
+ struct policy_handle *domain_handle,
+ const char *name);
+
+void msg_handler(struct monitor_msg *m);