From 16b7ba3488c1207d2229b0b51bfa709b80cf7a1f Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Wed, 30 Oct 2013 11:54:21 +0100 Subject: s4:dsdb/rootdse: Netlogon maybe requested with other attrs MS AD allows netlogon requests to request other attributes, as long as the search parameter is correct, e.g: ldapsearch -h 192.168.122.2 -x -b '' -s base \ "(&(NtVer=\06\00\00\00)(AAC=\00\00\00\00))" \ supportedLDAPPolicies netlogon This also removes an old check that for requests having a netlogon attribute returned zero elements. This is not true, if there is a valid netlogon filter. This patch is to be squashed into "s4:dsdb/rootdse: Support netlogon request". --- source4/cldap_server/cldap_server.h | 3 +- source4/cldap_server/netlogon.c | 43 ++++++++++++- source4/dsdb/samdb/ldb_modules/rootdse.c | 101 ++++++++++++------------------- 3 files changed, 81 insertions(+), 66 deletions(-) diff --git a/source4/cldap_server/cldap_server.h b/source4/cldap_server/cldap_server.h index 995ceed3a2..181edbd176 100644 --- a/source4/cldap_server/cldap_server.h +++ b/source4/cldap_server/cldap_server.h @@ -56,6 +56,7 @@ NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, const char **domain_guid, struct dom_sid **domain_sid, int *acct_control, - int *version); + int *version, + bool filter_from_tree); #include "cldap_server/proto.h" diff --git a/source4/cldap_server/netlogon.c b/source4/cldap_server/netlogon.c index 0894b2bea7..a5c12df1fb 100644 --- a/source4/cldap_server/netlogon.c +++ b/source4/cldap_server/netlogon.c @@ -38,6 +38,7 @@ #include "../lib/tsocket/tsocket.h" #include "libds/common/flag_mapping.h" #include "lib/util/util_net.h" +#include "lib/ldb/include/ldb_module.h" /* fill in the cldap netlogon union for a given version @@ -369,6 +370,21 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, return NT_STATUS_OK; } +/* + create a always matching node from a equality node + */ +static void set_parse_tree_true(struct ldb_parse_tree *tree) +{ + const char *attr = tree->u.equality.attr; + struct ldb_val value = tree->u.equality.value; + + tree->operation = LDB_OP_EXTENDED; + tree->u.extended.attr = attr; + tree->u.extended.value = value; + tree->u.extended.rule_id = SAMBA_LDAP_MATCH_ALWAYS_TRUE; + tree->u.extended.dnAttributes = 0; +} + NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, struct loadparm_context *lp_ctx, TALLOC_CTX *tmp_ctx, @@ -378,7 +394,8 @@ NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, const char **domain_guid, struct dom_sid **domain_sid, int *acct_control, - int *version) + int *version, + bool filter_from_tree) { unsigned int i; @@ -400,11 +417,17 @@ NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, *domain = talloc_strndup(tmp_ctx, (const char *)t->u.equality.value.data, t->u.equality.value.length); + if (filter_from_tree) { + set_parse_tree_true(t); + } } if (strcasecmp(t->u.equality.attr, "Host") == 0) { *host = talloc_strndup(tmp_ctx, (const char *)t->u.equality.value.data, t->u.equality.value.length); + if (filter_from_tree) { + set_parse_tree_true(t); + } } if (strcasecmp(t->u.equality.attr, "DomainGuid") == 0) { NTSTATUS enc_status; @@ -413,6 +436,9 @@ NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, t->u.equality.value, &guid); if (NT_STATUS_IS_OK(enc_status)) { *domain_guid = GUID_string(tmp_ctx, &guid); + if (filter_from_tree) { + set_parse_tree_true(t); + } } } if (strcasecmp(t->u.equality.attr, "DomainSid") == 0) { @@ -429,19 +455,31 @@ NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, talloc_free(*domain_sid); goto failed; } + if (filter_from_tree) { + set_parse_tree_true(t); + } } if (strcasecmp(t->u.equality.attr, "User") == 0) { *user = talloc_strndup(tmp_ctx, (const char *)t->u.equality.value.data, t->u.equality.value.length); + if (filter_from_tree) { + set_parse_tree_true(t); + } } if (strcasecmp(t->u.equality.attr, "NtVer") == 0 && t->u.equality.value.length == 4) { *version = IVAL(t->u.equality.value.data, 0); + if (filter_from_tree) { + set_parse_tree_true(t); + } } if (strcasecmp(t->u.equality.attr, "AAC") == 0 && t->u.equality.value.length == 4) { *acct_control = IVAL(t->u.equality.value.data, 0); + if (filter_from_tree) { + set_parse_tree_true(t); + } } } @@ -480,7 +518,8 @@ void cldapd_netlogon_request(struct cldap_socket *cldap, status = parse_netlogon_request(tree, cldapd->task->lp_ctx, tmp_ctx, &domain, &host, &user, &domain_guid, - &domain_sid, &acct_control, &version); + &domain_sid, &acct_control, &version, + false); if (!NT_STATUS_IS_OK(status)) { goto failed; } diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index baffd1766c..3ec6248302 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -45,6 +45,12 @@ struct private_data { bool block_anonymous; }; +struct rootdse_context { + struct ldb_module *module; + struct ldb_request *req; + struct ldb_val netlogon; +}; + /* return 1 if a specific attribute has been requested */ @@ -556,11 +562,6 @@ failed: handle search requests */ -struct rootdse_context { - struct ldb_module *module; - struct ldb_request *req; -}; - static struct rootdse_context *rootdse_init_context(struct ldb_module *module, struct ldb_request *req) { @@ -599,16 +600,6 @@ static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares) switch (ares->type) { case LDB_REPLY_ENTRY: - /* - * if the client explicit asks for the 'netlogon' attribute - * the reply_entry needs to be skipped - */ - if (ac->req->op.search.attrs && - ldb_attr_in_list(ac->req->op.search.attrs, "netlogon")) { - talloc_free(ares); - return LDB_SUCCESS; - } - /* for each record returned post-process to add any dynamic attributes that have been asked for */ ret = rootdse_add_dynamic(ac, ares->message, @@ -618,6 +609,17 @@ static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares) return ldb_module_done(ac->req, NULL, NULL, ret); } + /* This should of cause be in rootdse_add_dynamic, + * but therefore we need ac there. */ + if (ac->netlogon.length > 0) { + ret = ldb_msg_add_value(ares->message, "netlogon", + &ac->netlogon, NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + } + + return ldb_module_send_entry(ac->req, ares->message, ares->controls); case LDB_REPLY_REFERRAL: @@ -760,9 +762,7 @@ static int rootdse_handle_netlogon(struct rootdse_context *ac) int version = -1; NTSTATUS status; struct netlogon_samlogon_response netlogon; - struct ldb_message *msg = NULL; - int ret, error = LDB_ERR_OPERATIONS_ERROR; - struct ldb_val blob; + int ret = LDB_SUCCESS; ldb = ldb_module_get_ctx(ac->module); tree = ac->req->op.search.tree; @@ -774,9 +774,12 @@ static int rootdse_handle_netlogon(struct rootdse_context *ac) status = parse_netlogon_request(tree, lp_ctx, tmp_ctx, &domain, &host, &user, &domain_guid, - &domain_sid, &acct_control, &version); + &domain_sid, &acct_control, &version, + true); if (!NT_STATUS_IS_OK(status)) { - goto failed; + /* We have to return an empty search if the filter + * does not match, no an error. */ + goto done; } status = fill_netlogon_samlogon_response(ldb, tmp_ctx, @@ -787,50 +790,19 @@ static int rootdse_handle_netlogon(struct rootdse_context *ac) version, lp_ctx, &netlogon, false); if (!NT_STATUS_IS_OK(status)) { - goto failed; + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; } - status = push_netlogon_samlogon_response(&blob, tmp_ctx, &netlogon); + status = push_netlogon_samlogon_response(&ac->netlogon, ac, &netlogon); if (!NT_STATUS_IS_OK(status)) { - goto failed; - } - - msg = ldb_msg_new(tmp_ctx); - if (!msg) { - error = ldb_oom(ldb); - goto failed; - } - - msg->dn = ldb_dn_new(msg, ldb, ""); - if (!msg->dn) { - error = ldb_oom(ldb); - goto failed; - } - - ret = ldb_msg_add_value(msg, "netlogon", &blob, NULL); - if (ret != LDB_SUCCESS) { - error = ret; - goto failed; - } - - ret = ldb_module_send_entry(ac->req, msg, NULL); - if (ret != LDB_SUCCESS) { - error = ret; - goto failed; - } - - ret = ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS); - if (ret != LDB_SUCCESS) { - error = ret; - goto failed; + ret = LDB_ERR_OPERATIONS_ERROR; + goto done; } +done: talloc_free(tmp_ctx); - return LDB_SUCCESS; - -failed: - talloc_free(tmp_ctx); - return ldb_module_done(ac->req, NULL, NULL, error); + return ret; } static int rootdse_search(struct ldb_module *module, struct ldb_request *req) @@ -863,11 +835,14 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req) return ldb_operr(ldb); } - if (req->op.search.attrs && - req->op.search.attrs[0] && - req->op.search.attrs[1] == NULL && - ldb_attr_cmp(req->op.search.attrs[0], "netlogon") == 0) { - return rootdse_handle_netlogon(ac); + if (do_attribute_explicit(req->op.search.attrs, "netlogon")) { + ret = rootdse_handle_netlogon(ac); + /* Finish with an empty reply here, either if: + * - An error was returned, or + * - No valid netlogon generated (i.e filter didn't match). */ + if (ret != LDB_SUCCESS || ac->netlogon.length == 0) { + return ldb_module_done(ac->req, NULL, NULL, ret); + } } /* in our db we store the rootDSE with a DN of @ROOTDSE */ -- cgit