From 2b3eb11befb59add03be8134173563aba3571377 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Mon, 28 Oct 2013 11:57:01 +0100 Subject: [WIP] Add tcp ldap netlogon torture --- libcli/cldap/cldap.c | 64 ++++++ libcli/cldap/cldap.h | 2 + source4/torture/ldap/common.c | 1 + source4/torture/ldap/netlogon.c | 458 ++++++++++++++++++++++++++++++++++++++++ source4/torture/wscript_build | 2 +- 5 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 source4/torture/ldap/netlogon.c diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c index 24ce39fefb..809fa2352b 100644 --- a/libcli/cldap/cldap.c +++ b/libcli/cldap/cldap.c @@ -882,6 +882,70 @@ struct cldap_netlogon_state { struct cldap_search search; }; +char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx, + const struct cldap_netlogon *io) +{ + char *filter; + + filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)", + ldap_encode_ndr_uint32(mem_ctx, io->in.version)); + if (filter == NULL) + return NULL; + + if (io->in.user) { + filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user); + if (filter == NULL) { + return NULL; + } + } + if (io->in.host) { + filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host); + if (filter == NULL) { + return NULL; + } + } + if (io->in.realm) { + filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm); + if (filter == NULL) { + return NULL; + } + } + if (io->in.acct_control != -1) { + filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", + ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control)); + if (filter == NULL) { + return NULL; + } + } + if (io->in.domain_sid) { + struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid); + if (filter == NULL) { + return NULL; + } + filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)", + ldap_encode_ndr_dom_sid(mem_ctx, sid)); + if (filter == NULL) { + return NULL; + } + } + if (io->in.domain_guid) { + struct GUID guid; + NTSTATUS status; + status = GUID_from_string(io->in.domain_guid, &guid); + if (filter == NULL) { + return NULL; + } + filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)", + ldap_encode_ndr_GUID(mem_ctx, &guid)); + if (filter == NULL) { + return NULL; + } + } + filter = talloc_asprintf_append_buffer(filter, ")"); + + return filter; +} + static void cldap_netlogon_state_done(struct tevent_req *subreq); /* queue a cldap netlogon for send diff --git a/libcli/cldap/cldap.h b/libcli/cldap/cldap.h index 0bc9454f80..cd76fee60f 100644 --- a/libcli/cldap/cldap.h +++ b/libcli/cldap/cldap.h @@ -123,6 +123,8 @@ NTSTATUS cldap_netlogon_recv(struct tevent_req *req, NTSTATUS cldap_netlogon(struct cldap_socket *cldap, TALLOC_CTX *mem_ctx, struct cldap_netlogon *io); +char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx, + const struct cldap_netlogon *io); NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap, uint32_t message_id, diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c index 3af3d02491..586b85eca0 100644 --- a/source4/torture/ldap/common.c +++ b/source4/torture/ldap/common.c @@ -136,6 +136,7 @@ NTSTATUS torture_ldap_init(void) torture_suite_add_simple_test(suite, "basic", torture_ldap_basic); torture_suite_add_simple_test(suite, "sort", torture_ldap_sort); torture_suite_add_simple_test(suite, "cldap", torture_cldap); + torture_suite_add_simple_test(suite, "netlogon", torture_netlogon); torture_suite_add_simple_test(suite, "schema", torture_ldap_schema); torture_suite_add_simple_test(suite, "uptodatevector", torture_ldap_uptodatevector); torture_suite_add_simple_test(suite, "nested-search", test_ldap_nested_search); diff --git a/source4/torture/ldap/netlogon.c b/source4/torture/ldap/netlogon.c new file mode 100644 index 0000000000..7da0c30115 --- /dev/null +++ b/source4/torture/ldap/netlogon.c @@ -0,0 +1,458 @@ +/* + Unix SMB/CIFS mplementation. + LDAP protocol helper functions for SAMBA + + Copyright (C) Stefan Metzmacher 2004 + Copyright (C) Simo Sorce 2004 + Copyright (C) Matthias Dieter Wallnöfer 2009-2010 + + 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 . + +*/ + +#include "includes.h" +#include "ldb_wrap.h" +#include "libcli/ldap/ldap_client.h" +#include "lib/cmdline/popt_common.h" + +#include "torture/torture.h" +#include "torture/ldap/proto.h" + +#include "libcli/cldap/cldap.h" +#include "librpc/gen_ndr/netlogon.h" + +#define CHECK_STATUS(status, correct) torture_assert_ntstatus_equal(tctx, status, correct, "incorrect status") + +#define CHECK_VAL(v, correct) torture_assert_int_equal(tctx, (v), (correct), "incorrect value"); + +#define CHECK_STRING(v, correct) torture_assert_str_equal(tctx, v, correct, "incorrect value"); + +static NTSTATUS ldap_netlogon(struct ldap_connection *conn, + TALLOC_CTX *mem_ctx, + struct cldap_netlogon *io) +{ + char *filter; + struct ldap_message *msg, *result; + struct ldap_request *req; + struct ldap_SearchResEntry *res; + DATA_BLOB *data; + NTSTATUS status; + int ret; + + filter = cldap_netlogon_create_filter(mem_ctx, io); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; + } + + msg = new_ldap_message(mem_ctx); + if (!msg) { + return NT_STATUS_NO_MEMORY; + } + + msg->type = LDAP_TAG_SearchRequest; + msg->r.SearchRequest.basedn = ""; + msg->r.SearchRequest.scope = LDAP_SEARCH_SCOPE_BASE; + msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER; + msg->r.SearchRequest.timelimit = 0; + msg->r.SearchRequest.sizelimit = 0; + msg->r.SearchRequest.attributesonly = false; + msg->r.SearchRequest.tree = ldb_parse_tree(msg, filter); + msg->r.SearchRequest.num_attributes = 1; + msg->r.SearchRequest.attributes = (const char *[]) { "netlogon" }; + + req = ldap_request_send(conn, msg); + if (req == NULL) { + printf("Could not setup ldap search\n"); + return NT_STATUS_UNSUCCESSFUL; + } + + status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry); + if (!NT_STATUS_IS_OK(status)) { + /* Throw same error as cldap_netlogon. */ + if (NT_STATUS_EQUAL(status, NT_STATUS_UNEXPECTED_NETWORK_ERROR)) { + return NT_STATUS_NOT_FOUND; + } else { + return status; + } + } + + res = &result->r.SearchResultEntry; + if (res->num_attributes != 1 || + strcasecmp(res->attributes[0].name, "netlogon") != 0 || + res->attributes[0].num_values != 1 || + res->attributes[0].values->length < 2) { + return NT_STATUS_UNEXPECTED_NETWORK_ERROR; + } + + data = res->attributes[0].values; + status = pull_netlogon_samlogon_response(data, mem_ctx, + &io->out.netlogon); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (io->in.map_response) { + map_netlogon_samlogon_response(&io->out.netlogon); + } + + return NT_STATUS_OK; +} + +/* + test netlogon operations +*/ +static bool test_ldap_netlogon(struct torture_context *tctx, + struct ldap_connection *cldap, + const char *dest) +{ + NTSTATUS status; + struct cldap_netlogon search, empty_search; + struct netlogon_samlogon_response n1; + struct GUID guid; + int i; + struct tsocket_address *dest_addr; + int ret; + + ZERO_STRUCT(search); + search.in.dest_address = NULL; + search.in.dest_port = 0; + search.in.acct_control = -1; + search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; + search.in.map_response = true; + + empty_search = search; + + printf("Trying without any attributes\n"); + search = empty_search; + status = ldap_netlogon(cldap, tctx, &search); + CHECK_STATUS(status, NT_STATUS_OK); + + n1 = search.out.netlogon; + + search.in.user = "Administrator"; + search.in.realm = n1.data.nt5_ex.dns_domain; + search.in.host = "__cldap_torture__"; + + printf("Scanning for netlogon levels\n"); + for (i=0;i<256;i++) { + search.in.version = i; + printf("Trying netlogon level %d\n", i); + status = ldap_netlogon(cldap, tctx, &search); + CHECK_STATUS(status, NT_STATUS_OK); + } + + printf("Scanning for netlogon level bits\n"); + for (i=0;i<31;i++) { + search.in.version = (1<lp_ctx), + &dest_addr); + CHECK_VAL(ret, 0); + + /* cldap_socket_init should now know about the dest. address */ + status = cldap_socket_init(tctx, NULL, dest_addr, &cldap); + CHECK_STATUS(status, NT_STATUS_OK); +#endif + + printf("Printing out netlogon server type flags: %s\n", dest); + + ZERO_STRUCT(search); + search.in.dest_address = NULL; + search.in.dest_port = 0; + search.in.acct_control = -1; + search.in.version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX; + search.in.map_response = true; + + status = ldap_netlogon(cldap, tctx, &search); + CHECK_STATUS(status, NT_STATUS_OK); + + n1 = search.out.netlogon; + if (n1.ntver == NETLOGON_NT_VERSION_5) + server_type = n1.data.nt5.server_type; + else if (n1.ntver == NETLOGON_NT_VERSION_5EX) + server_type = n1.data.nt5_ex.server_type; + + printf("The word is: %i\n", server_type); + if (server_type & NBT_SERVER_PDC) + printf("NBT_SERVER_PDC "); + if (server_type & NBT_SERVER_GC) + printf("NBT_SERVER_GC "); + if (server_type & NBT_SERVER_LDAP) + printf("NBT_SERVER_LDAP "); + if (server_type & NBT_SERVER_DS) + printf("NBT_SERVER_DS "); + if (server_type & NBT_SERVER_KDC) + printf("NBT_SERVER_KDC "); + if (server_type & NBT_SERVER_TIMESERV) + printf("NBT_SERVER_TIMESERV "); + if (server_type & NBT_SERVER_CLOSEST) + printf("NBT_SERVER_CLOSEST "); + if (server_type & NBT_SERVER_WRITABLE) + printf("NBT_SERVER_WRITABLE "); + if (server_type & NBT_SERVER_GOOD_TIMESERV) + printf("NBT_SERVER_GOOD_TIMESERV "); + if (server_type & NBT_SERVER_NDNC) + printf("NBT_SERVER_NDNC "); + if (server_type & NBT_SERVER_SELECT_SECRET_DOMAIN_6) + printf("NBT_SERVER_SELECT_SECRET_DOMAIN_6"); + if (server_type & NBT_SERVER_FULL_SECRET_DOMAIN_6) + printf("NBT_SERVER_FULL_SECRET_DOMAIN_6"); + if (server_type & DS_DNS_CONTROLLER) + printf("DS_DNS_CONTROLLER "); + if (server_type & DS_DNS_DOMAIN) + printf("DS_DNS_DOMAIN "); + if (server_type & DS_DNS_FOREST_ROOT) + printf("DS_DNS_FOREST_ROOT "); + + printf("\n"); + + return true; +} + +bool torture_netlogon(struct torture_context *torture) +{ + bool ret = true; + NTSTATUS status; + struct ldap_connection *conn; + TALLOC_CTX *mem_ctx; + const char *host = torture_setting_string(torture, "host", NULL); + //const char *userdn = torture_setting_string(torture, "ldap_userdn", NULL); + //const char *secret = torture_setting_string(torture, "ldap_secret", NULL); + const char *url; + //const char *basedn; + //const char **partitions; + + mem_ctx = talloc_init("torture_ldap_netlogon"); + + url = talloc_asprintf(mem_ctx, "ldap://%s/", host); + + status = torture_ldap_connection(torture, &conn, url); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + ret &= test_ldap_netlogon(torture, conn, host); + ret &= test_ldap_netlogon_flags(torture, conn, host); + + return ret; +} diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build index c3c997ada2..61c3a09148 100755 --- a/source4/torture/wscript_build +++ b/source4/torture/wscript_build @@ -108,7 +108,7 @@ bld.SAMBA_MODULE('TORTURE_UNIX', bld.SAMBA_MODULE('TORTURE_LDAP', - source='ldap/common.c ldap/basic.c ldap/schema.c ldap/uptodatevector.c ldap/cldap.c ldap/cldapbench.c ldap/ldap_sort.c ldap/nested_search.c', + source='ldap/common.c ldap/basic.c ldap/schema.c ldap/uptodatevector.c ldap/cldap.c ldap/netlogon.c ldap/cldapbench.c ldap/ldap_sort.c ldap/nested_search.c', subsystem='smbtorture', deps='cli-ldap cli_cldap samdb POPT_CREDENTIALS torture ldbsamba', internal_module=True, -- cgit