From 3853a0383a606376f8a66eb1460517a923eca0a1 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 1 Nov 2013 10:24:43 +0100 Subject: [PATCH 01/10] s4:torture/cldap: Fix a typo Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 32ee231da590d7b8aee74728a423b282ae845bce) Signed-off-by: Andrew Bartlett --- source4/torture/ldap/cldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/torture/ldap/cldap.c b/source4/torture/ldap/cldap.c index fc8c337..28859a5 100644 --- a/source4/torture/ldap/cldap.c +++ b/source4/torture/ldap/cldap.c @@ -463,7 +463,7 @@ static bool test_cldap_generic(struct torture_context *tctx, const char *dest) if (DEBUGLVL(3)) cldap_dump_results(&search); printf("Testing objectClass=* and netlogon\n"); - search.in.filter = "(objectclass2=*)"; + search.in.filter = "(objectclass=*)"; search.in.attributes = attrs3; status = cldap_search(cldap, tctx, &search); -- 1.9.0 From 10840b099cc80409c6422035c8e1ffde28629199 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sun, 27 Oct 2013 16:07:04 +0100 Subject: [PATCH 02/10] s4:cldap_server: Move netlogon parsing into utility function To be used later by netlogon-request over ldap. Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 372127416825a8a947cd976f8a4165611c006c43) Signed-off-by: Andrew Bartlett --- source4/cldap_server/cldap_server.h | 11 +++++ source4/cldap_server/netlogon.c | 96 ++++++++++++++++++++++++------------- 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/source4/cldap_server/cldap_server.h b/source4/cldap_server/cldap_server.h index fe7788f..995ceed 100644 --- a/source4/cldap_server/cldap_server.h +++ b/source4/cldap_server/cldap_server.h @@ -47,4 +47,15 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, struct netlogon_samlogon_response *netlogon, bool fill_on_blank_request); +NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, + struct loadparm_context *lp_ctx, + TALLOC_CTX *mem_ctx, + const char **domain, + const char **host, + const char **user, + const char **domain_guid, + struct dom_sid **domain_sid, + int *acct_control, + int *version); + #include "cldap_server/proto.h" diff --git a/source4/cldap_server/netlogon.c b/source4/cldap_server/netlogon.c index 6d5efb5..0894b2b 100644 --- a/source4/cldap_server/netlogon.c +++ b/source4/cldap_server/netlogon.c @@ -369,27 +369,26 @@ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, return NT_STATUS_OK; } - -/* - handle incoming cldap requests -*/ -void cldapd_netlogon_request(struct cldap_socket *cldap, - struct cldapd_server *cldapd, - TALLOC_CTX *tmp_ctx, - uint32_t message_id, - struct ldb_parse_tree *tree, - struct tsocket_address *src) +NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, + struct loadparm_context *lp_ctx, + TALLOC_CTX *tmp_ctx, + const char **domain, + const char **host, + const char **user, + const char **domain_guid, + struct dom_sid **domain_sid, + int *acct_control, + int *version) { unsigned int i; - const char *domain = NULL; - const char *host = NULL; - const char *user = NULL; - const char *domain_guid = NULL; - struct dom_sid *domain_sid = NULL; - int acct_control = -1; - int version = -1; - struct netlogon_samlogon_response netlogon; - NTSTATUS status = NT_STATUS_INVALID_PARAMETER; + + *domain = NULL; + *host = NULL; + *user = NULL; + *domain_guid = NULL; + *domain_sid = NULL; + *acct_control = -1; + *version = -1; if (tree->operation != LDB_OP_AND) goto failed; @@ -398,12 +397,12 @@ void cldapd_netlogon_request(struct cldap_socket *cldap, struct ldb_parse_tree *t = tree->u.list.elements[i]; if (t->operation != LDB_OP_EQUALITY) goto failed; if (strcasecmp(t->u.equality.attr, "DnsDomain") == 0) { - domain = talloc_strndup(tmp_ctx, + *domain = talloc_strndup(tmp_ctx, (const char *)t->u.equality.value.data, t->u.equality.value.length); } if (strcasecmp(t->u.equality.attr, "Host") == 0) { - host = talloc_strndup(tmp_ctx, + *host = talloc_strndup(tmp_ctx, (const char *)t->u.equality.value.data, t->u.equality.value.length); } @@ -413,50 +412,79 @@ void cldapd_netlogon_request(struct cldap_socket *cldap, enc_status = ldap_decode_ndr_GUID(tmp_ctx, t->u.equality.value, &guid); if (NT_STATUS_IS_OK(enc_status)) { - domain_guid = GUID_string(tmp_ctx, &guid); + *domain_guid = GUID_string(tmp_ctx, &guid); } } if (strcasecmp(t->u.equality.attr, "DomainSid") == 0) { enum ndr_err_code ndr_err; - domain_sid = talloc(tmp_ctx, struct dom_sid); - if (domain_sid == NULL) { + *domain_sid = talloc(tmp_ctx, struct dom_sid); + if (*domain_sid == NULL) { goto failed; } ndr_err = ndr_pull_struct_blob(&t->u.equality.value, - domain_sid, domain_sid, + *domain_sid, *domain_sid, (ndr_pull_flags_fn_t)ndr_pull_dom_sid); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - talloc_free(domain_sid); + talloc_free(*domain_sid); goto failed; } } 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); + *user = talloc_strndup(tmp_ctx, + (const char *)t->u.equality.value.data, + t->u.equality.value.length); } if (strcasecmp(t->u.equality.attr, "NtVer") == 0 && t->u.equality.value.length == 4) { - version = IVAL(t->u.equality.value.data, 0); + *version = IVAL(t->u.equality.value.data, 0); } if (strcasecmp(t->u.equality.attr, "AAC") == 0 && t->u.equality.value.length == 4) { - acct_control = IVAL(t->u.equality.value.data, 0); + *acct_control = IVAL(t->u.equality.value.data, 0); } } - if ((domain == NULL) && (domain_guid == NULL) && (domain_sid == NULL)) { - domain = lpcfg_dnsdomain(cldapd->task->lp_ctx); + if ((*domain == NULL) && (*domain_guid == NULL) && (*domain_sid == NULL)) { + *domain = lpcfg_dnsdomain(lp_ctx); } - if (version == -1) { + if (*version == -1) { goto failed; } + return NT_STATUS_OK; + +failed: + return NT_STATUS_UNSUCCESSFUL; +} + +/* + handle incoming cldap requests +*/ +void cldapd_netlogon_request(struct cldap_socket *cldap, + struct cldapd_server *cldapd, + TALLOC_CTX *tmp_ctx, + uint32_t message_id, + struct ldb_parse_tree *tree, + struct tsocket_address *src) +{ + const char *domain, *host, *user, *domain_guid; + struct dom_sid *domain_sid; + int acct_control, version; + struct netlogon_samlogon_response netlogon; + NTSTATUS status = NT_STATUS_INVALID_PARAMETER; + DEBUG(5,("cldap netlogon query domain=%s host=%s user=%s version=%d guid=%s\n", domain, host, user, version, domain_guid)); + status = parse_netlogon_request(tree, cldapd->task->lp_ctx, tmp_ctx, + &domain, &host, &user, &domain_guid, + &domain_sid, &acct_control, &version); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + status = fill_netlogon_samlogon_response(cldapd->samctx, tmp_ctx, domain, NULL, domain_sid, domain_guid, -- 1.9.0 From b287dd9a87c76ec82f940d7626d384f7c2dde142 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 6 Sep 2013 16:20:43 +0200 Subject: [PATCH 03/10] provision: Fix string replacement ordering Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit ca8acb681a1ccaddf85376ff30c9b13b1a4c943d) Signed-off-by: Andrew Bartlett --- python/samba/provision/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py index 4af6b69..46d2cbc 100644 --- a/python/samba/provision/__init__.py +++ b/python/samba/provision/__init__.py @@ -595,7 +595,7 @@ def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None, raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp.configfile) if lp.get("realm").upper() != realm: - raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), realm, lp.configfile)) + raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), lp.configfile, realm)) if lp.get("server role").lower() != serverrole: raise ProvisioningError("guess_names: 'server role=%s' in %s must match chosen server role '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("server role"), lp.configfile, serverrole)) -- 1.9.0 From ebc089d3c96a9868bdbefe05cc6bc41b864474cb Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 1 Nov 2013 06:55:41 +0100 Subject: [PATCH 04/10] s4:dsdb/rootdse: Pass rootdse context to rootdse_add_dynamic This replaced the *module parameter, and uses ac->module in the function instead, same for *req and *attrs. Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 7a5a62547bc10053fb1e4850e0acacb6a837f36f) Signed-off-by: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/rootdse.c | 39 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index 167201e..bcae804 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -43,6 +43,11 @@ struct private_data { bool block_anonymous; }; +struct rootdse_context { + struct ldb_module *module; + struct ldb_request *req; +}; + /* return 1 if a specific attribute has been requested */ @@ -216,11 +221,11 @@ static int dsdb_module_we_are_master(struct ldb_module *module, struct ldb_dn *d /* add dynamically generated attributes to rootDSE result */ -static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *msg, - const char * const *attrs, struct ldb_request *req) +static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *msg) { struct ldb_context *ldb; - struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data); + struct private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct private_data); + const char * const *attrs = ac->req->op.search.attrs; char **server_sasl; const struct dsdb_schema *schema; int *val; @@ -241,7 +246,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms }; unsigned int i; - ldb = ldb_module_get_ctx(module); + ldb = ldb_module_get_ctx(ac->module); schema = dsdb_get_schema(ldb, NULL); msg->dn = ldb_dn_new(msg, ldb, NULL); @@ -262,11 +267,11 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms struct ldb_result *res; int ret; const char *dns_attrs[] = { "dNSHostName", NULL }; - ret = dsdb_module_search_dn(module, msg, &res, samdb_server_dn(ldb, msg), + ret = dsdb_module_search_dn(ac->module, msg, &res, samdb_server_dn(ldb, msg), dns_attrs, DSDB_FLAG_NEXT_MODULE | DSDB_FLAG_AS_SYSTEM, - req); + ac->req); if (ret == LDB_SUCCESS) { const char *hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL); if (hostname != NULL) { @@ -402,7 +407,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms for (i=0; i<3; i++) { bool master; - int ret = dsdb_module_we_are_master(module, dns[i], &master, req); + int ret = dsdb_module_we_are_master(ac->module, dns[i], &master, ac->req); if (ret != LDB_SUCCESS) { goto failed; } @@ -474,7 +479,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms /* TODO: lots more dynamic attributes should be added here */ - edn_control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID); + edn_control = ldb_request_get_control(ac->req, LDB_CONTROL_EXTENDED_DN_OID); /* convert any GUID attributes to be in the right form */ for (i=0; guid_attrs[i]; i++) { @@ -486,17 +491,17 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms if (!do_attribute(attrs, guid_attrs[i])) continue; - attr_dn = ldb_msg_find_attr_as_dn(ldb, req, msg, guid_attrs[i]); + attr_dn = ldb_msg_find_attr_as_dn(ldb, ac->req, msg, guid_attrs[i]); if (attr_dn == NULL) { continue; } - ret = dsdb_module_search_dn(module, req, &res, + ret = dsdb_module_search_dn(ac->module, ac->req, &res, attr_dn, no_attrs, DSDB_FLAG_NEXT_MODULE | DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN, - req); + ac->req); if (ret != LDB_SUCCESS) { return ldb_operr(ldb); } @@ -534,8 +539,8 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms int ret; for (i=0; dn_attrs[i]; i++) { if (!do_attribute(attrs, dn_attrs[i])) continue; - ret = expand_dn_in_message(module, msg, dn_attrs[i], - edn_control, req); + ret = expand_dn_in_message(ac->module, msg, dn_attrs[i], + edn_control, ac->req); if (ret != LDB_SUCCESS) { DEBUG(0,(__location__ ": Failed to expand DN in rootDSE for %s\n", dn_attrs[i])); @@ -554,11 +559,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) { @@ -609,8 +609,7 @@ static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares) /* for each record returned post-process to add any dynamic attributes that have been asked for */ - ret = rootdse_add_dynamic(ac->module, ares->message, - ac->req->op.search.attrs, ac->req); + ret = rootdse_add_dynamic(ac, ares->message); if (ret != LDB_SUCCESS) { talloc_free(ares); return ldb_module_done(ac->req, NULL, NULL, ret); -- 1.9.0 From 15c7ab99f1a28e313b455b49330e5bb35dc06bcb Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sun, 27 Oct 2013 06:55:48 +0100 Subject: [PATCH 05/10] s4:dsdb/rootdse: Support netlogon request This patch adds support for a netlogon ldap style request over the tcp socket. This is available since win2k3+ [1]. The automatic client join & configuration daemon "realmd" makes use of this ability. Realmd can now be used to join a computer to a samba 4 domain. (See also: https://lists.samba.org/archive/samba-technical/2013-October/095606.html) Tested with: ldapsearch -h samba-srv -x -b '' -s base "(&(NtVer=\06\00\00\00)(AAC=\00\00\00\00))" NetLogon And compared the result in wireshark with cldap request issued by examples/misc/cldap.pl. [1]: http://wiki.wireshark.org/MS-CLDAP?action=recall&rev=8 Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 0620c79d76b69811fd6c00d912db05477d894724) Signed-off-by: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/rootdse.c | 83 +++++++++++++++++++--- .../dsdb/samdb/ldb_modules/wscript_build_server | 2 +- source4/ldap_server/ldap_backend.c | 3 + 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index bcae804..f905aa2 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -34,6 +34,8 @@ #include "param/param.h" #include "lib/messaging/irpc.h" #include "librpc/gen_ndr/ndr_irpc_c.h" +#include "lib/tsocket/tsocket.h" +#include "cldap_server/cldap_server.h" struct private_data { unsigned int num_controls; @@ -46,6 +48,7 @@ struct private_data { struct rootdse_context { struct ldb_module *module; struct ldb_request *req; + struct ldb_val netlogon; }; /* @@ -477,6 +480,12 @@ static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *m } } + if (ac->netlogon.length > 0) { + if (ldb_msg_add_steal_value(msg, "netlogon", &ac->netlogon) != LDB_SUCCESS) { + goto failed; + } + } + /* TODO: lots more dynamic attributes should be added here */ edn_control = ldb_request_get_control(ac->req, LDB_CONTROL_EXTENDED_DN_OID); @@ -597,16 +606,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); @@ -743,6 +742,62 @@ static int rootdse_filter_operations(struct ldb_module *module, struct ldb_reque return LDB_ERR_OPERATIONS_ERROR; } +static int rootdse_handle_netlogon(struct rootdse_context *ac) +{ + struct ldb_context *ldb; + struct ldb_parse_tree *tree; + struct loadparm_context *lp_ctx; + struct tsocket_address *src_addr; + TALLOC_CTX *tmp_ctx = talloc_new(ac->req); + const char *domain, *host, *user, *domain_guid; + char *src_addr_s = NULL; + struct dom_sid *domain_sid; + int acct_control = -1; + int version = -1; + NTSTATUS status; + struct netlogon_samlogon_response netlogon; + int ret = LDB_ERR_OPERATIONS_ERROR; + + ldb = ldb_module_get_ctx(ac->module); + tree = ac->req->op.search.tree; + lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"), + struct loadparm_context); + src_addr = talloc_get_type(ldb_get_opaque(ldb, "remoteAddress"), + struct tsocket_address); + if (src_addr) { + src_addr_s = tsocket_address_inet_addr_string(src_addr, + tmp_ctx); + } + + status = parse_netlogon_request(tree, lp_ctx, tmp_ctx, + &domain, &host, &user, &domain_guid, + &domain_sid, &acct_control, &version); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + + status = fill_netlogon_samlogon_response(ldb, tmp_ctx, + domain, NULL, domain_sid, + domain_guid, + user, acct_control, + src_addr_s, + version, lp_ctx, + &netlogon, false); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + + status = push_netlogon_samlogon_response(&ac->netlogon, ac, &netlogon); + if (!NT_STATUS_IS_OK(status)) { + goto failed; + } + + ret = LDB_SUCCESS; +failed: + talloc_free(tmp_ctx); + return ret; +} + static int rootdse_search(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; @@ -773,6 +828,14 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req) return ldb_operr(ldb); } + if (do_attribute_explicit(req->op.search.attrs, "netlogon")) { + ret = rootdse_handle_netlogon(ac); + /* We have to return an empty result, so dont forward `ret' */ + if (ret != LDB_SUCCESS) { + return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS); + } + } + /* in our db we store the rootDSE with a DN of @ROOTDSE */ ret = ldb_build_search_req(&down_req, ldb, ac, ldb_dn_new(ac, ldb, "@ROOTDSE"), diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build_server b/source4/dsdb/samdb/ldb_modules/wscript_build_server index 41eb0f3..7ad1d3b 100755 --- a/source4/dsdb/samdb/ldb_modules/wscript_build_server +++ b/source4/dsdb/samdb/ldb_modules/wscript_build_server @@ -106,7 +106,7 @@ bld.SAMBA_MODULE('ldb_rootdse', init_function='ldb_rootdse_module_init', module_init_name='ldb_init_module', internal_module=False, - deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC' + deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC CLDAPD' ) diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c index f415e9b..4a195e5 100644 --- a/source4/ldap_server/ldap_backend.c +++ b/source4/ldap_server/ldap_backend.c @@ -225,6 +225,9 @@ NTSTATUS ldapsrv_backend_Init(struct ldapsrv_connection *conn) ldb_set_opaque(conn->ldb, "supportedSASLMechanisms", sasl_mechs); } + ldb_set_opaque(conn->ldb, "remoteAddress", + conn->connection->remote_address); + return NT_STATUS_OK; } -- 1.9.0 From 9ef202be0f6c760b5b512db2ca3fc9032625fc18 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Fri, 1 Nov 2013 10:52:02 +0100 Subject: [PATCH 06/10] s4:cldap_server: Do not handle netlogon ourself anymore Netlogon is now handled by the ldb rootdse module. The netlogon files will be moved to dsdb in the next commit. Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 7106dcf2b8525ec653f24e417d846f9d00172b6d) Signed-off-by: Andrew Bartlett --- source4/cldap_server/cldap_server.c | 12 --------- source4/cldap_server/netlogon.c | 50 ------------------------------------- source4/cldap_server/rootdse.c | 5 ++++ 3 files changed, 5 insertions(+), 62 deletions(-) diff --git a/source4/cldap_server/cldap_server.c b/source4/cldap_server/cldap_server.c index a6248d4..774142e 100644 --- a/source4/cldap_server/cldap_server.c +++ b/source4/cldap_server/cldap_server.c @@ -80,18 +80,6 @@ static void cldapd_request_handler(struct cldap_socket *cldap, return; } - if (search->num_attributes == 1 && - strcasecmp(search->attributes[0], "netlogon") == 0) { - cldapd_netlogon_request(cldap, - cldapd, - in, - in->ldap_msg->messageid, - search->tree, - in->src); - talloc_free(in); - return; - } - cldapd_rootdse_request(cldap, cldapd, in, in->ldap_msg->messageid, search, in->src); diff --git a/source4/cldap_server/netlogon.c b/source4/cldap_server/netlogon.c index 0894b2b..231bd16 100644 --- a/source4/cldap_server/netlogon.c +++ b/source4/cldap_server/netlogon.c @@ -458,53 +458,3 @@ NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, failed: return NT_STATUS_UNSUCCESSFUL; } - -/* - handle incoming cldap requests -*/ -void cldapd_netlogon_request(struct cldap_socket *cldap, - struct cldapd_server *cldapd, - TALLOC_CTX *tmp_ctx, - uint32_t message_id, - struct ldb_parse_tree *tree, - struct tsocket_address *src) -{ - const char *domain, *host, *user, *domain_guid; - struct dom_sid *domain_sid; - int acct_control, version; - struct netlogon_samlogon_response netlogon; - NTSTATUS status = NT_STATUS_INVALID_PARAMETER; - - DEBUG(5,("cldap netlogon query domain=%s host=%s user=%s version=%d guid=%s\n", - domain, host, user, version, domain_guid)); - - status = parse_netlogon_request(tree, cldapd->task->lp_ctx, tmp_ctx, - &domain, &host, &user, &domain_guid, - &domain_sid, &acct_control, &version); - if (!NT_STATUS_IS_OK(status)) { - goto failed; - } - - status = fill_netlogon_samlogon_response(cldapd->samctx, tmp_ctx, - domain, NULL, domain_sid, - domain_guid, - user, acct_control, - tsocket_address_inet_addr_string(src, tmp_ctx), - version, cldapd->task->lp_ctx, - &netlogon, false); - if (!NT_STATUS_IS_OK(status)) { - goto failed; - } - - status = cldap_netlogon_reply(cldap, message_id, src, version, &netlogon); - if (!NT_STATUS_IS_OK(status)) { - goto failed; - } - - return; - -failed: - DEBUG(2,("cldap netlogon query failed domain=%s host=%s version=%d - %s\n", - domain, host, version, nt_errstr(status))); - cldap_empty_reply(cldap, message_id, src); -} diff --git a/source4/cldap_server/rootdse.c b/source4/cldap_server/rootdse.c index b895616..3f389ce 100644 --- a/source4/cldap_server/rootdse.c +++ b/source4/cldap_server/rootdse.c @@ -158,6 +158,11 @@ void cldapd_rootdse_request(struct cldap_socket *cldap, reply.response = NULL; reply.result = &result; + /* Note: The remoteAddress should rather be set on a ldb request. + * We can set this savely on the context here, + * since cldapd_rootdse_fill operates synchronously. */ + ldb_set_opaque(cldapd->samctx, "remoteAddress", src); + cldapd_rootdse_fill(cldapd, tmp_ctx, search, &reply.response, reply.result); -- 1.9.0 From 3199d75589dfa0ec3f2247550efed7c3622971ad Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 5 Nov 2013 20:39:56 +0100 Subject: [PATCH 07/10] s4:dsdb: Move cldap netlogon functions into samdb/ldb_modules As netlogon is handled by the samdb now, the corresponding functions should live there as well. Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 68ebb09193e73cff4389ccb9e3b190b12ee0a84a) Signed-off-by: Andrew Bartlett --- source4/cldap_server/cldap_server.h | 26 -- source4/cldap_server/netlogon.c | 460 --------------------- source4/cldap_server/wscript_build | 2 +- source4/dsdb/samdb/ldb_modules/netlogon.c | 460 +++++++++++++++++++++ source4/dsdb/samdb/ldb_modules/util.h | 2 + source4/dsdb/samdb/ldb_modules/wscript_build | 2 +- .../dsdb/samdb/ldb_modules/wscript_build_server | 2 +- source4/nbt_server/dgram/netlogon.c | 2 +- source4/nbt_server/wscript_build | 2 +- source4/rpc_server/netlogon/dcerpc_netlogon.c | 2 +- source4/rpc_server/wscript_build | 2 +- 11 files changed, 469 insertions(+), 493 deletions(-) delete mode 100644 source4/cldap_server/netlogon.c create mode 100644 source4/dsdb/samdb/ldb_modules/netlogon.c diff --git a/source4/cldap_server/cldap_server.h b/source4/cldap_server/cldap_server.h index 995ceed..0725284 100644 --- a/source4/cldap_server/cldap_server.h +++ b/source4/cldap_server/cldap_server.h @@ -32,30 +32,4 @@ struct cldapd_server { struct ldap_SearchRequest; -/* used by netlogon DCE/RPC server */ -NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, - TALLOC_CTX *mem_ctx, - const char *domain, - const char *netbios_domain, - struct dom_sid *domain_sid, - const char *domain_guid, - const char *user, - uint32_t acct_control, - const char *src_address, - uint32_t version, - struct loadparm_context *lp_ctx, - struct netlogon_samlogon_response *netlogon, - bool fill_on_blank_request); - -NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, - struct loadparm_context *lp_ctx, - TALLOC_CTX *mem_ctx, - const char **domain, - const char **host, - const char **user, - const char **domain_guid, - struct dom_sid **domain_sid, - int *acct_control, - int *version); - #include "cldap_server/proto.h" diff --git a/source4/cldap_server/netlogon.c b/source4/cldap_server/netlogon.c deleted file mode 100644 index 231bd16..0000000 --- a/source4/cldap_server/netlogon.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - CLDAP server - netlogon handling - - Copyright (C) Andrew Tridgell 2005 - Copyright (C) Andrew Bartlett 2008 - - 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 -#include -#include "lib/events/events.h" -#include "smbd/service_task.h" -#include "cldap_server/cldap_server.h" -#include "librpc/gen_ndr/ndr_misc.h" -#include "libcli/ldap/ldap_ndr.h" -#include "libcli/security/security.h" -#include "dsdb/samdb/samdb.h" -#include "auth/auth.h" -#include "ldb_wrap.h" -#include "system/network.h" -#include "lib/socket/netif.h" -#include "param/param.h" -#include "../lib/tsocket/tsocket.h" -#include "libds/common/flag_mapping.h" -#include "lib/util/util_net.h" - -/* - fill in the cldap netlogon union for a given version -*/ -NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, - TALLOC_CTX *mem_ctx, - const char *domain, - const char *netbios_domain, - struct dom_sid *domain_sid, - const char *domain_guid, - const char *user, - uint32_t acct_control, - const char *src_address, - uint32_t version, - struct loadparm_context *lp_ctx, - struct netlogon_samlogon_response *netlogon, - bool fill_on_blank_request) -{ - const char *dom_attrs[] = {"objectGUID", NULL}; - const char *none_attrs[] = {NULL}; - struct ldb_result *dom_res = NULL, *user_res = NULL; - int ret; - const char **services = lpcfg_server_services(lp_ctx); - uint32_t server_type; - const char *pdc_name; - struct GUID domain_uuid; - const char *dns_domain; - const char *forest_domain; - const char *pdc_dns_name; - const char *flatname; - const char *server_site; - const char *client_site; - const char *pdc_ip; - struct ldb_dn *domain_dn = NULL; - struct interface *ifaces; - bool user_known = false, am_rodc = false; - NTSTATUS status; - - /* the domain parameter could have an optional trailing "." */ - if (domain && domain[strlen(domain)-1] == '.') { - domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); - NT_STATUS_HAVE_NO_MEMORY(domain); - } - - /* Lookup using long or short domainname */ - if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) { - domain_dn = ldb_get_default_basedn(sam_ctx); - } - if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) { - domain_dn = ldb_get_default_basedn(sam_ctx); - } - if (domain_dn) { - const char *domain_identifier = domain != NULL ? domain - : netbios_domain; - ret = ldb_search(sam_ctx, mem_ctx, &dom_res, - domain_dn, LDB_SCOPE_BASE, dom_attrs, - "objectClass=domain"); - if (ret != LDB_SUCCESS) { - DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", - domain_identifier, - ldb_dn_get_linearized(domain_dn), - ldb_errstring(sam_ctx))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - if (dom_res->count != 1) { - DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", - domain_identifier, - ldb_dn_get_linearized(domain_dn))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - } - - /* Lookup using GUID or SID */ - if ((dom_res == NULL) && (domain_guid || domain_sid)) { - if (domain_guid) { - struct GUID binary_guid; - struct ldb_val guid_val; - - /* By this means, we ensure we don't have funny stuff in the GUID */ - - status = GUID_from_string(domain_guid, &binary_guid); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* And this gets the result into the binary format we want anyway */ - status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - ret = ldb_search(sam_ctx, mem_ctx, &dom_res, - NULL, LDB_SCOPE_SUBTREE, - dom_attrs, - "(&(objectCategory=DomainDNS)(objectGUID=%s))", - ldb_binary_encode(mem_ctx, guid_val)); - } else { /* domain_sid case */ - ret = ldb_search(sam_ctx, mem_ctx, &dom_res, - NULL, LDB_SCOPE_SUBTREE, - dom_attrs, - "(&(objectCategory=DomainDNS)(objectSid=%s))", - dom_sid_string(mem_ctx, domain_sid)); - } - - if (ret != LDB_SUCCESS) { - DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n", - domain_guid, dom_sid_string(mem_ctx, domain_sid), - ldb_errstring(sam_ctx))); - return NT_STATUS_NO_SUCH_DOMAIN; - } else if (dom_res->count == 1) { - /* Ok, now just check it is our domain */ - if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx), - dom_res->msgs[0]->dn) != 0) { - DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n", - domain_guid, - dom_sid_string(mem_ctx, domain_sid))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - } else { - DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n", - domain_guid, dom_sid_string(mem_ctx, domain_sid))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - } - - if (dom_res == NULL && fill_on_blank_request) { - /* blank inputs gives our domain - tested against - w2k8r2. Without this ADUC on Win7 won't start */ - domain_dn = ldb_get_default_basedn(sam_ctx); - ret = ldb_search(sam_ctx, mem_ctx, &dom_res, - domain_dn, LDB_SCOPE_BASE, dom_attrs, - "objectClass=domain"); - if (ret != LDB_SUCCESS) { - DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", - lpcfg_dnsdomain(lp_ctx), - ldb_dn_get_linearized(domain_dn), - ldb_errstring(sam_ctx))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - } - - if (dom_res == NULL) { - DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n")); - return NT_STATUS_NO_SUCH_DOMAIN; - } - - /* work around different inputs for not-specified users */ - if (!user) { - user = ""; - } - - /* Enquire about any valid username with just a CLDAP packet - - * if kerberos didn't also do this, the security folks would - * scream... */ - if (user[0]) { \ - /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */ - if (acct_control == (uint32_t)-1) { - acct_control = 0; - } - acct_control = acct_control & (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); - - /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */ - ret = ldb_search(sam_ctx, mem_ctx, &user_res, - dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, - none_attrs, - "(&(objectClass=user)(samAccountName=%s)" - "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" - "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", - ldb_binary_encode_string(mem_ctx, user), - UF_ACCOUNTDISABLE, ds_acb2uf(acct_control)); - if (ret != LDB_SUCCESS) { - DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n", - user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), - ldb_errstring(sam_ctx))); - return NT_STATUS_NO_SUCH_USER; - } else if (user_res->count == 1) { - user_known = true; - } else { - user_known = false; - } - - } else { - user_known = true; - } - - server_type = DS_SERVER_DS; - - if (samdb_is_pdc(sam_ctx)) { - server_type |= DS_SERVER_PDC; - } - - if (samdb_is_gc(sam_ctx)) { - server_type |= DS_SERVER_GC; - } - - if (str_list_check(services, "ldap")) { - server_type |= DS_SERVER_LDAP; - } - - if (str_list_check(services, "kdc")) { - server_type |= DS_SERVER_KDC; - } - - if (str_list_check(services, "ntp_signd")) { - server_type |= DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV; - } - - if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) { - server_type |= DS_SERVER_WRITABLE; - } - - if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) { - if (server_type & DS_SERVER_WRITABLE) { - server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6; - } else { - server_type |= DS_SERVER_SELECT_SECRET_DOMAIN_6; - } - } - - if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { - pdc_name = lpcfg_netbios_name(lp_ctx); - } else { - pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", - lpcfg_netbios_name(lp_ctx)); - NT_STATUS_HAVE_NO_MEMORY(pdc_name); - } - domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); - dns_domain = lpcfg_dnsdomain(lp_ctx); - forest_domain = samdb_forest_name(sam_ctx, mem_ctx); - NT_STATUS_HAVE_NO_MEMORY(forest_domain); - pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", - strlower_talloc(mem_ctx, - lpcfg_netbios_name(lp_ctx)), - dns_domain); - NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name); - flatname = lpcfg_workgroup(lp_ctx); - - server_site = samdb_server_site_name(sam_ctx, mem_ctx); - NT_STATUS_HAVE_NO_MEMORY(server_site); - client_site = samdb_client_site_name(sam_ctx, mem_ctx, - src_address, NULL); - NT_STATUS_HAVE_NO_MEMORY(client_site); - if (strcasecmp(server_site, client_site) == 0) { - server_type |= DS_SERVER_CLOSEST; - } - - load_interface_list(mem_ctx, lp_ctx, &ifaces); - if (src_address) { - pdc_ip = iface_list_best_ip(ifaces, src_address); - } else { - pdc_ip = iface_list_first_v4(ifaces); - } - if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) { - /* this matches windows behaviour */ - pdc_ip = "127.0.0.1"; - } - - ZERO_STRUCTP(netlogon); - - /* check if either of these bits is present */ - if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { - uint32_t extra_flags = 0; - netlogon->ntver = NETLOGON_NT_VERSION_5EX; - - /* could check if the user exists */ - if (user_known) { - netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX; - } else { - netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX; - } - netlogon->data.nt5_ex.pdc_name = pdc_name; - netlogon->data.nt5_ex.user_name = user; - netlogon->data.nt5_ex.domain_name = flatname; - netlogon->data.nt5_ex.domain_uuid = domain_uuid; - netlogon->data.nt5_ex.forest = forest_domain; - netlogon->data.nt5_ex.dns_domain = dns_domain; - netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name; - netlogon->data.nt5_ex.server_site = server_site; - netlogon->data.nt5_ex.client_site = client_site; - if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) { - /* note that this is always a IPV4 address */ - extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP; - netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2; - netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip; - netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8); - } - netlogon->data.nt5_ex.server_type = server_type; - netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags; - netlogon->data.nt5_ex.lmnt_token = 0xFFFF; - netlogon->data.nt5_ex.lm20_token = 0xFFFF; - - } else if (version & NETLOGON_NT_VERSION_5) { - netlogon->ntver = NETLOGON_NT_VERSION_5; - - /* could check if the user exists */ - if (user_known) { - netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE; - } else { - netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN; - } - netlogon->data.nt5.pdc_name = pdc_name; - netlogon->data.nt5.user_name = user; - netlogon->data.nt5.domain_name = flatname; - netlogon->data.nt5.domain_uuid = domain_uuid; - netlogon->data.nt5.forest = forest_domain; - netlogon->data.nt5.dns_domain = dns_domain; - netlogon->data.nt5.pdc_dns_name = pdc_dns_name; - netlogon->data.nt5.pdc_ip = pdc_ip; - netlogon->data.nt5.server_type = server_type; - netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5; - netlogon->data.nt5.lmnt_token = 0xFFFF; - netlogon->data.nt5.lm20_token = 0xFFFF; - - } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ { - netlogon->ntver = NETLOGON_NT_VERSION_1; - /* could check if the user exists */ - if (user_known) { - netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE; - } else { - netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN; - } - netlogon->data.nt4.pdc_name = pdc_name; - netlogon->data.nt4.user_name = user; - netlogon->data.nt4.domain_name = flatname; - netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1; - netlogon->data.nt4.lmnt_token = 0xFFFF; - netlogon->data.nt4.lm20_token = 0xFFFF; - } - - return NT_STATUS_OK; -} - -NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, - struct loadparm_context *lp_ctx, - TALLOC_CTX *tmp_ctx, - const char **domain, - const char **host, - const char **user, - const char **domain_guid, - struct dom_sid **domain_sid, - int *acct_control, - int *version) -{ - unsigned int i; - - *domain = NULL; - *host = NULL; - *user = NULL; - *domain_guid = NULL; - *domain_sid = NULL; - *acct_control = -1; - *version = -1; - - if (tree->operation != LDB_OP_AND) goto failed; - - /* extract the query elements */ - for (i=0;iu.list.num_elements;i++) { - struct ldb_parse_tree *t = tree->u.list.elements[i]; - if (t->operation != LDB_OP_EQUALITY) goto failed; - if (strcasecmp(t->u.equality.attr, "DnsDomain") == 0) { - *domain = talloc_strndup(tmp_ctx, - (const char *)t->u.equality.value.data, - t->u.equality.value.length); - } - 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 (strcasecmp(t->u.equality.attr, "DomainGuid") == 0) { - NTSTATUS enc_status; - struct GUID guid; - enc_status = ldap_decode_ndr_GUID(tmp_ctx, - t->u.equality.value, &guid); - if (NT_STATUS_IS_OK(enc_status)) { - *domain_guid = GUID_string(tmp_ctx, &guid); - } - } - if (strcasecmp(t->u.equality.attr, "DomainSid") == 0) { - enum ndr_err_code ndr_err; - - *domain_sid = talloc(tmp_ctx, struct dom_sid); - if (*domain_sid == NULL) { - goto failed; - } - ndr_err = ndr_pull_struct_blob(&t->u.equality.value, - *domain_sid, *domain_sid, - (ndr_pull_flags_fn_t)ndr_pull_dom_sid); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - talloc_free(*domain_sid); - goto failed; - } - } - 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 (strcasecmp(t->u.equality.attr, "NtVer") == 0 && - t->u.equality.value.length == 4) { - *version = IVAL(t->u.equality.value.data, 0); - } - if (strcasecmp(t->u.equality.attr, "AAC") == 0 && - t->u.equality.value.length == 4) { - *acct_control = IVAL(t->u.equality.value.data, 0); - } - } - - if ((*domain == NULL) && (*domain_guid == NULL) && (*domain_sid == NULL)) { - *domain = lpcfg_dnsdomain(lp_ctx); - } - - if (*version == -1) { - goto failed; - } - - return NT_STATUS_OK; - -failed: - return NT_STATUS_UNSUCCESSFUL; -} diff --git a/source4/cldap_server/wscript_build b/source4/cldap_server/wscript_build index 6ffdb4a..928b91b 100644 --- a/source4/cldap_server/wscript_build +++ b/source4/cldap_server/wscript_build @@ -10,7 +10,7 @@ bld.SAMBA_MODULE('service_cldap', bld.SAMBA_SUBSYSTEM('CLDAPD', - source='netlogon.c rootdse.c', + source='rootdse.c', autoproto='proto.h', deps='cli_cldap ldbsamba' ) diff --git a/source4/dsdb/samdb/ldb_modules/netlogon.c b/source4/dsdb/samdb/ldb_modules/netlogon.c new file mode 100644 index 0000000..a381da8 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/netlogon.c @@ -0,0 +1,460 @@ +/* + Unix SMB/CIFS implementation. + + CLDAP server - netlogon handling + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Andrew Bartlett 2008 + + 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 +#include +#include "lib/events/events.h" +#include "smbd/service_task.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "libcli/ldap/ldap_ndr.h" +#include "libcli/security/security.h" +#include "dsdb/samdb/samdb.h" +#include "dsdb/samdb/ldb_modules/util.h" +#include "auth/auth.h" +#include "ldb_wrap.h" +#include "system/network.h" +#include "lib/socket/netif.h" +#include "param/param.h" +#include "../lib/tsocket/tsocket.h" +#include "libds/common/flag_mapping.h" +#include "lib/util/util_net.h" + +/* + fill in the cldap netlogon union for a given version +*/ +NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, + TALLOC_CTX *mem_ctx, + const char *domain, + const char *netbios_domain, + struct dom_sid *domain_sid, + const char *domain_guid, + const char *user, + uint32_t acct_control, + const char *src_address, + uint32_t version, + struct loadparm_context *lp_ctx, + struct netlogon_samlogon_response *netlogon, + bool fill_on_blank_request) +{ + const char *dom_attrs[] = {"objectGUID", NULL}; + const char *none_attrs[] = {NULL}; + struct ldb_result *dom_res = NULL, *user_res = NULL; + int ret; + const char **services = lpcfg_server_services(lp_ctx); + uint32_t server_type; + const char *pdc_name; + struct GUID domain_uuid; + const char *dns_domain; + const char *forest_domain; + const char *pdc_dns_name; + const char *flatname; + const char *server_site; + const char *client_site; + const char *pdc_ip; + struct ldb_dn *domain_dn = NULL; + struct interface *ifaces; + bool user_known = false, am_rodc = false; + NTSTATUS status; + + /* the domain parameter could have an optional trailing "." */ + if (domain && domain[strlen(domain)-1] == '.') { + domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); + NT_STATUS_HAVE_NO_MEMORY(domain); + } + + /* Lookup using long or short domainname */ + if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) { + domain_dn = ldb_get_default_basedn(sam_ctx); + } + if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) { + domain_dn = ldb_get_default_basedn(sam_ctx); + } + if (domain_dn) { + const char *domain_identifier = domain != NULL ? domain + : netbios_domain; + ret = ldb_search(sam_ctx, mem_ctx, &dom_res, + domain_dn, LDB_SCOPE_BASE, dom_attrs, + "objectClass=domain"); + if (ret != LDB_SUCCESS) { + DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", + domain_identifier, + ldb_dn_get_linearized(domain_dn), + ldb_errstring(sam_ctx))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + if (dom_res->count != 1) { + DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", + domain_identifier, + ldb_dn_get_linearized(domain_dn))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + } + + /* Lookup using GUID or SID */ + if ((dom_res == NULL) && (domain_guid || domain_sid)) { + if (domain_guid) { + struct GUID binary_guid; + struct ldb_val guid_val; + + /* By this means, we ensure we don't have funny stuff in the GUID */ + + status = GUID_from_string(domain_guid, &binary_guid); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* And this gets the result into the binary format we want anyway */ + status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ret = ldb_search(sam_ctx, mem_ctx, &dom_res, + NULL, LDB_SCOPE_SUBTREE, + dom_attrs, + "(&(objectCategory=DomainDNS)(objectGUID=%s))", + ldb_binary_encode(mem_ctx, guid_val)); + } else { /* domain_sid case */ + ret = ldb_search(sam_ctx, mem_ctx, &dom_res, + NULL, LDB_SCOPE_SUBTREE, + dom_attrs, + "(&(objectCategory=DomainDNS)(objectSid=%s))", + dom_sid_string(mem_ctx, domain_sid)); + } + + if (ret != LDB_SUCCESS) { + DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n", + domain_guid, dom_sid_string(mem_ctx, domain_sid), + ldb_errstring(sam_ctx))); + return NT_STATUS_NO_SUCH_DOMAIN; + } else if (dom_res->count == 1) { + /* Ok, now just check it is our domain */ + if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx), + dom_res->msgs[0]->dn) != 0) { + DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n", + domain_guid, + dom_sid_string(mem_ctx, domain_sid))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + } else { + DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n", + domain_guid, dom_sid_string(mem_ctx, domain_sid))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + } + + if (dom_res == NULL && fill_on_blank_request) { + /* blank inputs gives our domain - tested against + w2k8r2. Without this ADUC on Win7 won't start */ + domain_dn = ldb_get_default_basedn(sam_ctx); + ret = ldb_search(sam_ctx, mem_ctx, &dom_res, + domain_dn, LDB_SCOPE_BASE, dom_attrs, + "objectClass=domain"); + if (ret != LDB_SUCCESS) { + DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", + lpcfg_dnsdomain(lp_ctx), + ldb_dn_get_linearized(domain_dn), + ldb_errstring(sam_ctx))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + } + + if (dom_res == NULL) { + DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n")); + return NT_STATUS_NO_SUCH_DOMAIN; + } + + /* work around different inputs for not-specified users */ + if (!user) { + user = ""; + } + + /* Enquire about any valid username with just a CLDAP packet - + * if kerberos didn't also do this, the security folks would + * scream... */ + if (user[0]) { \ + /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */ + if (acct_control == (uint32_t)-1) { + acct_control = 0; + } + acct_control = acct_control & (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); + + /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */ + ret = ldb_search(sam_ctx, mem_ctx, &user_res, + dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, + none_attrs, + "(&(objectClass=user)(samAccountName=%s)" + "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" + "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", + ldb_binary_encode_string(mem_ctx, user), + UF_ACCOUNTDISABLE, ds_acb2uf(acct_control)); + if (ret != LDB_SUCCESS) { + DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n", + user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), + ldb_errstring(sam_ctx))); + return NT_STATUS_NO_SUCH_USER; + } else if (user_res->count == 1) { + user_known = true; + } else { + user_known = false; + } + + } else { + user_known = true; + } + + server_type = DS_SERVER_DS; + + if (samdb_is_pdc(sam_ctx)) { + server_type |= DS_SERVER_PDC; + } + + if (samdb_is_gc(sam_ctx)) { + server_type |= DS_SERVER_GC; + } + + if (str_list_check(services, "ldap")) { + server_type |= DS_SERVER_LDAP; + } + + if (str_list_check(services, "kdc")) { + server_type |= DS_SERVER_KDC; + } + + if (str_list_check(services, "ntp_signd")) { + server_type |= DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV; + } + + if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) { + server_type |= DS_SERVER_WRITABLE; + } + + if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) { + if (server_type & DS_SERVER_WRITABLE) { + server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6; + } else { + server_type |= DS_SERVER_SELECT_SECRET_DOMAIN_6; + } + } + + if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { + pdc_name = lpcfg_netbios_name(lp_ctx); + } else { + pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", + lpcfg_netbios_name(lp_ctx)); + NT_STATUS_HAVE_NO_MEMORY(pdc_name); + } + domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); + dns_domain = lpcfg_dnsdomain(lp_ctx); + forest_domain = samdb_forest_name(sam_ctx, mem_ctx); + NT_STATUS_HAVE_NO_MEMORY(forest_domain); + pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", + strlower_talloc(mem_ctx, + lpcfg_netbios_name(lp_ctx)), + dns_domain); + NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name); + flatname = lpcfg_workgroup(lp_ctx); + + server_site = samdb_server_site_name(sam_ctx, mem_ctx); + NT_STATUS_HAVE_NO_MEMORY(server_site); + client_site = samdb_client_site_name(sam_ctx, mem_ctx, + src_address, NULL); + NT_STATUS_HAVE_NO_MEMORY(client_site); + if (strcasecmp(server_site, client_site) == 0) { + server_type |= DS_SERVER_CLOSEST; + } + + load_interface_list(mem_ctx, lp_ctx, &ifaces); + if (src_address) { + pdc_ip = iface_list_best_ip(ifaces, src_address); + } else { + pdc_ip = iface_list_first_v4(ifaces); + } + if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) { + /* this matches windows behaviour */ + pdc_ip = "127.0.0.1"; + } + + ZERO_STRUCTP(netlogon); + + /* check if either of these bits is present */ + if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { + uint32_t extra_flags = 0; + netlogon->ntver = NETLOGON_NT_VERSION_5EX; + + /* could check if the user exists */ + if (user_known) { + netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX; + } else { + netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX; + } + netlogon->data.nt5_ex.pdc_name = pdc_name; + netlogon->data.nt5_ex.user_name = user; + netlogon->data.nt5_ex.domain_name = flatname; + netlogon->data.nt5_ex.domain_uuid = domain_uuid; + netlogon->data.nt5_ex.forest = forest_domain; + netlogon->data.nt5_ex.dns_domain = dns_domain; + netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name; + netlogon->data.nt5_ex.server_site = server_site; + netlogon->data.nt5_ex.client_site = client_site; + if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) { + /* note that this is always a IPV4 address */ + extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP; + netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2; + netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip; + netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8); + } + netlogon->data.nt5_ex.server_type = server_type; + netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags; + netlogon->data.nt5_ex.lmnt_token = 0xFFFF; + netlogon->data.nt5_ex.lm20_token = 0xFFFF; + + } else if (version & NETLOGON_NT_VERSION_5) { + netlogon->ntver = NETLOGON_NT_VERSION_5; + + /* could check if the user exists */ + if (user_known) { + netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE; + } else { + netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN; + } + netlogon->data.nt5.pdc_name = pdc_name; + netlogon->data.nt5.user_name = user; + netlogon->data.nt5.domain_name = flatname; + netlogon->data.nt5.domain_uuid = domain_uuid; + netlogon->data.nt5.forest = forest_domain; + netlogon->data.nt5.dns_domain = dns_domain; + netlogon->data.nt5.pdc_dns_name = pdc_dns_name; + netlogon->data.nt5.pdc_ip = pdc_ip; + netlogon->data.nt5.server_type = server_type; + netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5; + netlogon->data.nt5.lmnt_token = 0xFFFF; + netlogon->data.nt5.lm20_token = 0xFFFF; + + } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ { + netlogon->ntver = NETLOGON_NT_VERSION_1; + /* could check if the user exists */ + if (user_known) { + netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE; + } else { + netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN; + } + netlogon->data.nt4.pdc_name = pdc_name; + netlogon->data.nt4.user_name = user; + netlogon->data.nt4.domain_name = flatname; + netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1; + netlogon->data.nt4.lmnt_token = 0xFFFF; + netlogon->data.nt4.lm20_token = 0xFFFF; + } + + return NT_STATUS_OK; +} + +NTSTATUS parse_netlogon_request(struct ldb_parse_tree *tree, + struct loadparm_context *lp_ctx, + TALLOC_CTX *tmp_ctx, + const char **domain, + const char **host, + const char **user, + const char **domain_guid, + struct dom_sid **domain_sid, + int *acct_control, + int *version) +{ + unsigned int i; + + *domain = NULL; + *host = NULL; + *user = NULL; + *domain_guid = NULL; + *domain_sid = NULL; + *acct_control = -1; + *version = -1; + + if (tree->operation != LDB_OP_AND) goto failed; + + /* extract the query elements */ + for (i=0;iu.list.num_elements;i++) { + struct ldb_parse_tree *t = tree->u.list.elements[i]; + if (t->operation != LDB_OP_EQUALITY) goto failed; + if (strcasecmp(t->u.equality.attr, "DnsDomain") == 0) { + *domain = talloc_strndup(tmp_ctx, + (const char *)t->u.equality.value.data, + t->u.equality.value.length); + } + 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 (strcasecmp(t->u.equality.attr, "DomainGuid") == 0) { + NTSTATUS enc_status; + struct GUID guid; + enc_status = ldap_decode_ndr_GUID(tmp_ctx, + t->u.equality.value, &guid); + if (NT_STATUS_IS_OK(enc_status)) { + *domain_guid = GUID_string(tmp_ctx, &guid); + } + } + if (strcasecmp(t->u.equality.attr, "DomainSid") == 0) { + enum ndr_err_code ndr_err; + + *domain_sid = talloc(tmp_ctx, struct dom_sid); + if (*domain_sid == NULL) { + goto failed; + } + ndr_err = ndr_pull_struct_blob(&t->u.equality.value, + *domain_sid, *domain_sid, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(*domain_sid); + goto failed; + } + } + 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 (strcasecmp(t->u.equality.attr, "NtVer") == 0 && + t->u.equality.value.length == 4) { + *version = IVAL(t->u.equality.value.data, 0); + } + if (strcasecmp(t->u.equality.attr, "AAC") == 0 && + t->u.equality.value.length == 4) { + *acct_control = IVAL(t->u.equality.value.data, 0); + } + } + + if ((*domain == NULL) && (*domain_guid == NULL) && (*domain_sid == NULL)) { + *domain = lpcfg_dnsdomain(lp_ctx); + } + + if (*version == -1) { + goto failed; + } + + return NT_STATUS_OK; + +failed: + return NT_STATUS_UNSUCCESSFUL; +} diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index c213042..e407305 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -25,10 +25,12 @@ struct dsdb_attribute; struct dsdb_fsmo_extended_op; struct security_descriptor; struct dom_sid; +struct netlogon_samlogon_response; #include "librpc/gen_ndr/misc.h" #include "dsdb/samdb/ldb_modules/util_proto.h" #include "dsdb/common/util.h" +#include "../libcli/netlogon/netlogon.h" /* extend the dsdb_request_add_controls() flags for module specific functions */ diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build b/source4/dsdb/samdb/ldb_modules/wscript_build index 7e45c60..0df5fe0 100755 --- a/source4/dsdb/samdb/ldb_modules/wscript_build +++ b/source4/dsdb/samdb/ldb_modules/wscript_build @@ -7,7 +7,7 @@ bld.SAMBA_LIBRARY('dsdb-module', grouping_library=True) bld.SAMBA_SUBSYSTEM('DSDB_MODULE_HELPERS', - source='util.c acl_util.c schema_util.c', + source='util.c acl_util.c schema_util.c netlogon.c', autoproto='util_proto.h', deps='ldb ndr samdb-common samba-security' ) diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build_server b/source4/dsdb/samdb/ldb_modules/wscript_build_server index 7ad1d3b..41eb0f3 100755 --- a/source4/dsdb/samdb/ldb_modules/wscript_build_server +++ b/source4/dsdb/samdb/ldb_modules/wscript_build_server @@ -106,7 +106,7 @@ bld.SAMBA_MODULE('ldb_rootdse', init_function='ldb_rootdse_module_init', module_init_name='ldb_init_module', internal_module=False, - deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC CLDAPD' + deps='talloc samdb MESSAGING samba-security DSDB_MODULE_HELPERS RPC_NDR_IRPC' ) diff --git a/source4/nbt_server/dgram/netlogon.c b/source4/nbt_server/dgram/netlogon.c index 3f0fa54..0e5294c 100644 --- a/source4/nbt_server/dgram/netlogon.c +++ b/source4/nbt_server/dgram/netlogon.c @@ -28,7 +28,7 @@ #include "auth/auth.h" #include "param/param.h" #include "smbd/service_task.h" -#include "cldap_server/cldap_server.h" +#include "dsdb/samdb/ldb_modules/util.h" #include "libcli/security/security.h" #include "nbt_server/dgram/proto.h" diff --git a/source4/nbt_server/wscript_build b/source4/nbt_server/wscript_build index 665ccd4..9d0c24a 100644 --- a/source4/nbt_server/wscript_build +++ b/source4/nbt_server/wscript_build @@ -30,7 +30,7 @@ bld.SAMBA_SUBSYSTEM('NBTD_WINS', bld.SAMBA_SUBSYSTEM('NBTD_DGRAM', source='dgram/request.c dgram/netlogon.c dgram/browse.c', autoproto='dgram/proto.h', - deps='LIBCLI_DGRAM CLDAPD', + deps='LIBCLI_DGRAM DSDB_MODULE_HELPERS', enabled=bld.AD_DC_BUILD_IS_ENABLED() ) diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index d463e85..b3b9989 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -33,7 +33,7 @@ #include "lib/messaging/irpc.h" #include "librpc/gen_ndr/ndr_irpc_c.h" #include "../libcli/ldap/ldap_ndr.h" -#include "cldap_server/cldap_server.h" +#include "dsdb/samdb/ldb_modules/util.h" #include "lib/tsocket/tsocket.h" #include "librpc/gen_ndr/ndr_netlogon.h" #include "librpc/gen_ndr/ndr_irpc.h" diff --git a/source4/rpc_server/wscript_build b/source4/rpc_server/wscript_build index cc8efdb..2907f00 100755 --- a/source4/rpc_server/wscript_build +++ b/source4/rpc_server/wscript_build @@ -96,7 +96,7 @@ bld.SAMBA_MODULE('dcerpc_netlogon', source='netlogon/dcerpc_netlogon.c', subsystem='dcerpc_server', init_function='dcerpc_server_netlogon_init', - deps='DCERPC_COMMON RPC_NDR_IRPC COMMON_SCHANNEL ndr-standard auth4_sam samba-hostconfig CLDAPD' + deps='DCERPC_COMMON RPC_NDR_IRPC COMMON_SCHANNEL ndr-standard auth4_sam samba-hostconfig DSDB_MODULE_HELPERS' ) -- 1.9.0 From c44f885e1db54b3fa2c6bcabc0a91465abe28822 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Mon, 28 Oct 2013 14:19:57 +0100 Subject: [PATCH 08/10] libcli/cldap: Add utility to create netlogon filter This utility is splitted of from cldap_netlogon_send. Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit e306250a250d20a43cbe4c72ece34ebd475fa39c) Signed-off-by: Andrew Bartlett --- libcli/cldap/cldap.c | 90 +++++++++++++++++++++++++++++----------------------- libcli/cldap/cldap.h | 2 ++ 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c index 24ce39f..e543091 100644 --- a/libcli/cldap/cldap.c +++ b/libcli/cldap/cldap.c @@ -882,81 +882,91 @@ struct cldap_netlogon_state { struct cldap_search search; }; -static void cldap_netlogon_state_done(struct tevent_req *subreq); -/* - queue a cldap netlogon for send -*/ -struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cldap_socket *cldap, - const struct cldap_netlogon *io) +char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx, + const struct cldap_netlogon *io) { - struct tevent_req *req, *subreq; - struct cldap_netlogon_state *state; char *filter; - static const char * const attr[] = { "NetLogon", NULL }; - req = tevent_req_create(mem_ctx, &state, - struct cldap_netlogon_state); - if (!req) { + filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)", + ldap_encode_ndr_uint32(mem_ctx, io->in.version)); + if (filter == NULL) return NULL; - } - filter = talloc_asprintf(state, "(&(NtVer=%s)", - ldap_encode_ndr_uint32(state, io->in.version)); - if (tevent_req_nomem(filter, req)) { - goto post; - } if (io->in.user) { filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user); - if (tevent_req_nomem(filter, req)) { - goto post; + if (filter == NULL) { + return NULL; } } if (io->in.host) { filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host); - if (tevent_req_nomem(filter, req)) { - goto post; + if (filter == NULL) { + return NULL; } } if (io->in.realm) { filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm); - if (tevent_req_nomem(filter, req)) { - goto post; + if (filter == NULL) { + return NULL; } } if (io->in.acct_control != -1) { filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)", - ldap_encode_ndr_uint32(state, io->in.acct_control)); - if (tevent_req_nomem(filter, req)) { - goto post; + 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(state, io->in.domain_sid); - if (tevent_req_nomem(sid, req)) { - goto post; + 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(state, sid)); - if (tevent_req_nomem(filter, req)) { - goto post; + 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 (tevent_req_nterror(req, status)) { - goto post; + if (filter == NULL) { + return NULL; } filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)", - ldap_encode_ndr_GUID(state, &guid)); - if (tevent_req_nomem(filter, req)) { - goto post; + 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 +*/ +struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cldap_socket *cldap, + const struct cldap_netlogon *io) +{ + struct tevent_req *req, *subreq; + struct cldap_netlogon_state *state; + char *filter; + static const char * const attr[] = { "NetLogon", NULL }; + + req = tevent_req_create(mem_ctx, &state, + struct cldap_netlogon_state); + if (!req) { + return NULL; + } + + filter = cldap_netlogon_create_filter(state, io); if (tevent_req_nomem(filter, req)) { goto post; } diff --git a/libcli/cldap/cldap.h b/libcli/cldap/cldap.h index 0bc9454..cd76fee 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, -- 1.9.0 From 378242e65aac3810d0b079e49dd6d3205a85f4ad Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Mon, 28 Oct 2013 14:21:20 +0100 Subject: [PATCH 09/10] s4:torture/ldap: Add test for netlogon over tcp This patch moves the udp netlogon tests from cldap.c to netlogon.c and passes a generic netlogon-send function as parameter. Therefore a tcp replacement for cldap_netlogon is also added. The two variants tcp and udp are added as 2 new torture tests: ldap.netlogon-udp & ldap.netlogon-tcp Both tests succeed. Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova (cherry picked from commit 767bd6a4d49efce1c554bb0bc8130d74331b0bd8) Signed-off-by: Andrew Bartlett --- source4/torture/ldap/cldap.c | 329 ------------------------- source4/torture/ldap/common.c | 2 + source4/torture/ldap/netlogon.c | 516 ++++++++++++++++++++++++++++++++++++++++ source4/torture/wscript_build | 2 +- 4 files changed, 519 insertions(+), 330 deletions(-) create mode 100644 source4/torture/ldap/netlogon.c diff --git a/source4/torture/ldap/cldap.c b/source4/torture/ldap/cldap.c index 28859a5..6a925cf 100644 --- a/source4/torture/ldap/cldap.c +++ b/source4/torture/ldap/cldap.c @@ -24,7 +24,6 @@ #include "includes.h" #include "libcli/cldap/cldap.h" #include "libcli/ldap/ldap_client.h" -#include "librpc/gen_ndr/netlogon.h" #include "param/param.h" #include "../lib/tsocket/tsocket.h" @@ -36,332 +35,6 @@ #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"); -/* - test netlogon operations -*/ -static bool test_cldap_netlogon(struct torture_context *tctx, const char *dest) -{ - struct cldap_socket *cldap; - 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; - - ret = tsocket_address_inet_from_strings(tctx, "ip", - dest, - lpcfg_cldap_port(tctx->lp_ctx), - &dest_addr); - CHECK_VAL(ret, 0); - - status = cldap_socket_init(tctx, NULL, dest_addr, &cldap); - CHECK_STATUS(status, NT_STATUS_OK); - - 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 = cldap_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 = cldap_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); - - 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 = cldap_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; -} /* convert a ldap result message to a ldb message. This allows us to @@ -488,8 +161,6 @@ bool torture_cldap(struct torture_context *torture) bool ret = true; const char *host = torture_setting_string(torture, "host", NULL); - ret &= test_cldap_netlogon(torture, host); - ret &= test_cldap_netlogon_flags(torture, host); ret &= test_cldap_generic(torture, host); return ret; diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c index 6b13229..e6290ba 100644 --- a/source4/torture/ldap/common.c +++ b/source4/torture/ldap/common.c @@ -136,6 +136,8 @@ 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-udp", torture_netlogon_udp); + torture_suite_add_simple_test(suite, "netlogon-tcp", torture_netlogon_tcp); 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 0000000..9ed058e --- /dev/null +++ b/source4/torture/ldap/netlogon.c @@ -0,0 +1,516 @@ +/* + Unix SMB/CIFS mplementation. + + test CLDAP/LDAP netlogon operations + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Matthias Dieter Wallnöfer 2009 + + 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 "libcli/cldap/cldap.h" +#include "libcli/ldap/ldap_client.h" +#include "librpc/gen_ndr/netlogon.h" +#include "param/param.h" +#include "../lib/tsocket/tsocket.h" + +#include "torture/torture.h" +#include "torture/ldap/proto.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"); + +typedef NTSTATUS (*request_netlogon_t)(void *con, + TALLOC_CTX *mem_ctx, + struct cldap_netlogon *io); + +/* + test netlogon operations +*/ +static bool test_ldap_netlogon(struct torture_context *tctx, + request_netlogon_t request_netlogon, + void *cldap, + const char *dest) +{ + NTSTATUS status; + struct cldap_netlogon search, empty_search; + struct netlogon_samlogon_response n1; + struct GUID guid; + int i; + + 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 = request_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 = request_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<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, io->in.filter); + msg->r.SearchRequest.num_attributes = str_list_length(io->in.attributes); + msg->r.SearchRequest.attributes = io->in.attributes; + + req = ldap_request_send(conn, msg); + if (req == NULL) { + printf("Could not setup ldap search\n"); + return NT_STATUS_UNSUCCESSFUL; + } + + ZERO_STRUCT(io->out); + for (i = 0; i < 2; ++i) { + status = ldap_result_n(req, i, &result); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + switch (result->type) { + case LDAP_TAG_SearchResultEntry: + if (i != 0) { + return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR); + } + io->out.response = &result->r.SearchResultEntry; + break; + case LDAP_TAG_SearchResultDone: + io->out.result = &result->r.SearchResultDone; + if (io->out.result->resultcode != LDAP_SUCCESS) { + return NT_STATUS_LDAP(io->out.result->resultcode); + } + + return NT_STATUS_OK; + default: + return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR); + } + } + + return NT_STATUS_OK; +} + +static NTSTATUS tcp_ldap_netlogon(void *conn, + TALLOC_CTX *mem_ctx, + struct cldap_netlogon *io) +{ + struct cldap_search search; + struct ldap_SearchResEntry *res; + NTSTATUS status; + DATA_BLOB *blob; + + ZERO_STRUCT(search); + search.in.attributes = (const char *[]) { "netlogon", NULL }; + search.in.filter = cldap_netlogon_create_filter(mem_ctx, io); + if (search.in.filter == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = tcp_ldap_rootdse(conn, mem_ctx, &search); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + res = search.out.response; + if (res == NULL) { + return NT_STATUS_NOT_FOUND; + } + + 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; + } + + blob = res->attributes[0].values; + status = pull_netlogon_samlogon_response(blob, 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; +} + +bool torture_netlogon_tcp(struct torture_context *tctx) +{ + const char *host = torture_setting_string(tctx, "host", NULL); + bool ret = true; + NTSTATUS status; + struct ldap_connection *conn; + TALLOC_CTX *mem_ctx; + const char *url; + + mem_ctx = talloc_init("torture_ldap_netlogon"); + + url = talloc_asprintf(mem_ctx, "ldap://%s/", host); + + status = torture_ldap_connection(tctx, &conn, url); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + + ret &= test_ldap_netlogon(tctx, tcp_ldap_netlogon, conn, host); + ret &= test_ldap_netlogon_flags(tctx, tcp_ldap_netlogon, conn, host); + + return ret; +} + +static NTSTATUS udp_ldap_netlogon(void *data, + TALLOC_CTX *mem_ctx, + struct cldap_netlogon *io) +{ + struct cldap_socket *cldap = talloc_get_type(data, + struct cldap_socket); + + return cldap_netlogon(cldap, mem_ctx, io); +} + +bool torture_netlogon_udp(struct torture_context *tctx) +{ + const char *host = torture_setting_string(tctx, "host", NULL); + bool ret = true; + int r; + struct cldap_socket *cldap; + NTSTATUS status; + struct tsocket_address *dest_addr; + + r = tsocket_address_inet_from_strings(tctx, "ip", + host, + lpcfg_cldap_port(tctx->lp_ctx), + &dest_addr); + CHECK_VAL(r, 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); + + ret &= test_ldap_netlogon(tctx, udp_ldap_netlogon, cldap, host); + ret &= test_ldap_netlogon_flags(tctx, udp_ldap_netlogon, cldap, host); + + return ret; +} diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build index c3c997a..61c3a09 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, -- 1.9.0 From fc2ee372a89defe9c34f21e6f1c90f4f948f1bbd Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Thu, 31 Oct 2013 21:23:57 +0100 Subject: [PATCH 10/10] s4:torture/netlogon: Test netlogon with additional attrs Reviewed-by: Andrew Bartlett Reviewed-by: Nadezhda Ivanova se enter the commit message for your changes. Lines starting Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Nov 12 00:57:19 CET 2013 on sn-devel-104 (cherry picked from commit 0dd512eead6dc999511e9e21f5304a224653db85) Signed-off-by: Andrew Bartlett --- source4/torture/ldap/netlogon.c | 83 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/source4/torture/ldap/netlogon.c b/source4/torture/ldap/netlogon.c index 9ed058e..8c6345b 100644 --- a/source4/torture/ldap/netlogon.c +++ b/source4/torture/ldap/netlogon.c @@ -24,6 +24,7 @@ #include "includes.h" #include "libcli/cldap/cldap.h" #include "libcli/ldap/ldap_client.h" +#include "libcli/ldap/ldap_ndr.h" #include "librpc/gen_ndr/netlogon.h" #include "param/param.h" #include "../lib/tsocket/tsocket.h" @@ -41,6 +42,10 @@ typedef NTSTATUS (*request_netlogon_t)(void *con, TALLOC_CTX *mem_ctx, struct cldap_netlogon *io); +typedef NTSTATUS (*request_rootdse_t)(void *con, + TALLOC_CTX *mem_ctx, + struct cldap_search *io); + /* test netlogon operations */ @@ -456,6 +461,82 @@ static NTSTATUS tcp_ldap_netlogon(void *conn, return NT_STATUS_OK; } +static NTSTATUS udp_ldap_rootdse(void *data, TALLOC_CTX *mem_ctx, + struct cldap_search *io) +{ + struct cldap_socket *cldap = talloc_get_type(data, + struct cldap_socket); + + return cldap_search(cldap, mem_ctx, io); +} + +static bool test_netlogon_extra_attrs(struct torture_context *tctx, + request_rootdse_t request_rootdse, + void *conn) +{ + struct cldap_search io; + NTSTATUS status; + const char *attrs[] = { + "netlogon", + "supportedCapabilities", + NULL + }; + const char *attrs2[] = { "netlogon", "*", NULL }; + struct ldb_message ldbmsg = { NULL, 0, NULL }; + + ZERO_STRUCT(io); + io.in.dest_address = NULL; + io.in.dest_port = 0; + io.in.timeout = 2; + io.in.retries = 2; + /* Additional attributes may be requested next to netlogon */ + torture_comment(tctx, "Requesting netlogon with additional attribute\n"); + io.in.filter = + talloc_asprintf(tctx, "(&" + "(NtVer=%s)(AAC=%s)" + /* Query for LDAP_CAP_ACTIVE_DIRECTORY_OID */ + "(supportedCapabilities=1.2.840.113556.1.4.800)" + ")", + ldap_encode_ndr_uint32(tctx, + NETLOGON_NT_VERSION_5EX), + ldap_encode_ndr_uint32(tctx, 0)); + torture_assert(tctx, io.in.filter != NULL, "OOM"); + io.in.attributes = attrs; + status = request_rootdse(conn, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + torture_assert(tctx, io.out.response != NULL, "No Entries found."); + CHECK_VAL(io.out.response->num_attributes, 2); + + /* netlogon + '*' attr return zero results */ + torture_comment(tctx, "Requesting netlogon and '*' attributes\n"); + io.in.attributes = attrs2; + status = request_rootdse(conn, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + torture_assert(tctx, io.out.response != NULL, "No Entries found."); + ldbmsg.num_elements = io.out.response->num_attributes; + ldbmsg.elements = io.out.response->attributes; + torture_assert(tctx, ldb_msg_find_element(&ldbmsg, "netlogon") != NULL, + "Attribute netlogon not found in Result Entry\n"); + + /* Wildcards are not allowed in filters when netlogon is requested. */ + torture_comment(tctx, "Requesting netlogon with invalid attr filter\n"); + io.in.filter = + talloc_asprintf(tctx, + "(&(NtVer=%s)(AAC=%s)(supportedCapabilities=*))", + ldap_encode_ndr_uint32(tctx, + NETLOGON_NT_VERSION_5EX), + ldap_encode_ndr_uint32(tctx, 0)); + torture_assert(tctx, io.in.filter != NULL, "OOM"); + io.in.attributes = attrs; + status = request_rootdse(conn, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + torture_assert(tctx, io.out.response == NULL, + "A wildcard filter should return no entries."); + + return true; +} + + bool torture_netlogon_tcp(struct torture_context *tctx) { const char *host = torture_setting_string(tctx, "host", NULL); @@ -476,6 +557,7 @@ bool torture_netlogon_tcp(struct torture_context *tctx) ret &= test_ldap_netlogon(tctx, tcp_ldap_netlogon, conn, host); ret &= test_ldap_netlogon_flags(tctx, tcp_ldap_netlogon, conn, host); + ret &= test_netlogon_extra_attrs(tctx, tcp_ldap_rootdse, conn); return ret; } @@ -511,6 +593,7 @@ bool torture_netlogon_udp(struct torture_context *tctx) ret &= test_ldap_netlogon(tctx, udp_ldap_netlogon, cldap, host); ret &= test_ldap_netlogon_flags(tctx, udp_ldap_netlogon, cldap, host); + ret &= test_netlogon_extra_attrs(tctx, udp_ldap_rootdse, cldap); return ret; } -- 1.9.0