diff options
Diffstat (limited to 'source4/torture/libnet')
-rw-r--r-- | source4/torture/libnet/domain.c | 113 | ||||
-rw-r--r-- | source4/torture/libnet/groupinfo.c | 123 | ||||
-rw-r--r-- | source4/torture/libnet/groupman.c | 91 | ||||
-rw-r--r-- | source4/torture/libnet/grouptest.h | 20 | ||||
-rw-r--r-- | source4/torture/libnet/libnet.c | 70 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_BecomeDC.c | 709 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_domain.c | 447 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_group.c | 393 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_lookup.c | 189 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_rpc.c | 226 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_share.c | 233 | ||||
-rw-r--r-- | source4/torture/libnet/libnet_user.c | 736 | ||||
-rw-r--r-- | source4/torture/libnet/userinfo.c | 202 | ||||
-rw-r--r-- | source4/torture/libnet/userman.c | 461 | ||||
-rw-r--r-- | source4/torture/libnet/usertest.h | 38 | ||||
-rw-r--r-- | source4/torture/libnet/utils.c | 293 | ||||
-rw-r--r-- | source4/torture/libnet/utils.h | 45 |
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); |