summaryrefslogtreecommitdiff
path: root/source4/cldap_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/cldap_server')
-rw-r--r--source4/cldap_server/cldap_server.c20
-rw-r--r--source4/cldap_server/cldap_server.h1
-rw-r--r--source4/cldap_server/config.mk2
-rw-r--r--source4/cldap_server/netlogon.c233
4 files changed, 251 insertions, 5 deletions
diff --git a/source4/cldap_server/cldap_server.c b/source4/cldap_server/cldap_server.c
index 8397a624c0..ad4779da01 100644
--- a/source4/cldap_server/cldap_server.c
+++ b/source4/cldap_server/cldap_server.c
@@ -27,7 +27,6 @@
#include "smbd/service_task.h"
#include "cldap_server/cldap_server.h"
-
/*
handle incoming cldap requests
*/
@@ -35,16 +34,27 @@ static void cldapd_request_handler(struct cldap_socket *cldap,
struct ldap_message *ldap_msg,
const char *src_address, int src_port)
{
- struct cldapd_server *cldapd = talloc_get_type(cldap->incoming.private,
- struct cldapd_server);
+ struct ldap_SearchRequest *search;
if (ldap_msg->type != LDAP_TAG_SearchRequest) {
DEBUG(0,("Invalid CLDAP request type %d from %s:%d\n",
ldap_msg->type, src_address, src_port));
return;
}
- DEBUG(0,("CLDAP search for '%s'\n", ldap_msg->r.SearchRequest.filter));
+
+ search = &ldap_msg->r.SearchRequest;
+
+ if (search->num_attributes == 1 &&
+ strcasecmp(search->attributes[0], "netlogon") == 0) {
+ cldapd_netlogon_request(cldap, ldap_msg->messageid,
+ search->filter, src_address, src_port);
+ } else {
+ DEBUG(0,("Unknown CLDAP search for '%s'\n",
+ ldap_msg->r.SearchRequest.filter));
+ cldap_empty_reply(cldap, ldap_msg->messageid, src_address, src_port);
+ }
}
+
/*
start listening on the given address
*/
@@ -81,7 +91,7 @@ NTSTATUS cldapd_startup_interfaces(struct cldapd_server *cldapd)
NTSTATUS status;
/* if we are allowing incoming packets from any address, then
- we also need to bind to the wildcard address */
+ we need to bind to the wildcard address */
if (!lp_bind_interfaces_only()) {
status = cldapd_add_socket(cldapd, "0.0.0.0");
NT_STATUS_NOT_OK_RETURN(status);
diff --git a/source4/cldap_server/cldap_server.h b/source4/cldap_server/cldap_server.h
index f110d05d16..e3d7c06ab3 100644
--- a/source4/cldap_server/cldap_server.h
+++ b/source4/cldap_server/cldap_server.h
@@ -27,4 +27,5 @@
*/
struct cldapd_server {
struct task_server *task;
+ const char *dns_domain;
};
diff --git a/source4/cldap_server/config.mk b/source4/cldap_server/config.mk
index 225fb1cf08..a2042cecc5 100644
--- a/source4/cldap_server/config.mk
+++ b/source4/cldap_server/config.mk
@@ -5,6 +5,8 @@
[SUBSYSTEM::CLDAPD]
INIT_OBJ_FILES = \
cldap_server/cldap_server.o
+ADD_OBJ_FILES = \
+ cldap_server/netlogon.o
REQUIRED_SUBSYSTEMS = \
LIBCLI_CLDAP
# End SUBSYSTEM CLDAPD
diff --git a/source4/cldap_server/netlogon.c b/source4/cldap_server/netlogon.c
new file mode 100644
index 0000000000..ca77ea17b2
--- /dev/null
+++ b/source4/cldap_server/netlogon.c
@@ -0,0 +1,233 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ CLDAP server - netlogon handling
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "libcli/ldap/ldap.h"
+#include "lib/events/events.h"
+#include "lib/socket/socket.h"
+#include "smbd/service_task.h"
+#include "cldap_server/cldap_server.h"
+
+/*
+ fill in the cldap netlogon union for a given version
+*/
+static NTSTATUS cldapd_netlogon_fill(struct cldap_socket *cldap,
+ TALLOC_CTX *mem_ctx,
+ const char *domain,
+ const char *src_address,
+ uint32_t version,
+ union nbt_cldap_netlogon *netlogon)
+{
+ struct ldb_context *samctx;
+ const char *attrs[] = {"realm", "dnsDomain", "objectGUID", "name", NULL};
+ struct ldb_message **res;
+ int ret;
+ const char **services = lp_server_services();
+ uint32_t server_type;
+ const char *pdc_name;
+ struct GUID domain_uuid;
+ const char *realm;
+ const char *dns_domain;
+ const char *pdc_dns_name;
+ const char *flatname;
+ const char *site_name;
+ const char *site_name2;
+ const char *pdc_ip;
+
+ samctx = samdb_connect(mem_ctx);
+ if (samctx == NULL) {
+ DEBUG(2,("Unable to open sam in cldap netlogon reply\n"));
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ /* try and find the domain */
+ ret = gendb_search(samctx, samctx, NULL, &res, attrs,
+ "(&(dnsDomain=%s)(objectClass=domainDNS))", domain);
+ if (ret != 1) {
+ DEBUG(2,("Unable to find domain '%s' in sam\n", domain));
+ return NT_STATUS_NO_SUCH_DOMAIN;
+ }
+
+ server_type =
+ NBT_SERVER_PDC | NBT_SERVER_GC |
+ NBT_SERVER_DS | NBT_SERVER_TIMESERV |
+ NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE |
+ NBT_SERVER_GOOD_TIMESERV;
+
+ if (lp_parm_bool(-1, "gensec", "krb5", True)) {
+ server_type |= NBT_SERVER_KDC;
+ }
+ if (str_list_check(services, "ldap")) {
+ server_type |= NBT_SERVER_LDAP;
+ }
+
+ pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name());
+ domain_uuid = samdb_result_guid(res[0], "objectGUID");
+ realm = samdb_result_string(res[0], "realm", lp_realm());
+ dns_domain = samdb_result_string(res[0], "dnsDomain", lp_realm());
+ pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s",
+ lp_netbios_name(), dns_domain);
+ flatname = samdb_result_string(res[0], "name", lp_workgroup());
+ site_name = "Default-First-Site-Name";
+ site_name2 = "";
+ pdc_ip = iface_best_ip(src_address);
+
+ ZERO_STRUCTP(netlogon);
+
+ switch (version & 0xF) {
+ case 0:
+ case 1:
+ netlogon->logon1.pdc_name = pdc_name;
+ netlogon->logon1.unknown = "";
+ netlogon->logon1.domain_name = flatname;
+ netlogon->logon1.nt_version = 1;
+ netlogon->logon1.lmnt_token = 0xFFFF;
+ netlogon->logon1.lm20_token = 0xFFFF;
+ break;
+ case 2:
+ case 3:
+ netlogon->logon2.pdc_name = pdc_name;
+ netlogon->logon2.unknown = "";
+ netlogon->logon2.domain_name = flatname;
+ netlogon->logon2.domain_uuid = domain_uuid;
+ netlogon->logon2.forest = realm;
+ netlogon->logon2.dns_domain = dns_domain;
+ netlogon->logon2.pdc_dns_name = pdc_dns_name;
+ netlogon->logon2.pdc_ip = pdc_ip;
+ netlogon->logon2.server_type = server_type;
+ netlogon->logon2.nt_version = 3;
+ netlogon->logon2.lmnt_token = 0xFFFF;
+ netlogon->logon2.lm20_token = 0xFFFF;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ netlogon->logon3.server_type = server_type;
+ netlogon->logon3.domain_uuid = domain_uuid;
+ netlogon->logon3.forest = realm;
+ netlogon->logon3.dns_domain = dns_domain;
+ netlogon->logon3.pdc_dns_name = pdc_dns_name;
+ netlogon->logon3.domain = flatname;
+ netlogon->logon3.pdc_name = pdc_name;
+ netlogon->logon3.user_name = "";
+ netlogon->logon3.site_name = site_name;
+ netlogon->logon3.site_name2 = site_name2;
+ netlogon->logon3.nt_version = 3;
+ netlogon->logon3.lmnt_token = 0xFFFF;
+ netlogon->logon3.lm20_token = 0xFFFF;
+ break;
+ default:
+ netlogon->logon4.server_type = server_type;
+ netlogon->logon4.domain_uuid = domain_uuid;
+ netlogon->logon4.forest = realm;
+ netlogon->logon4.dns_domain = dns_domain;
+ netlogon->logon4.pdc_dns_name = pdc_dns_name;
+ netlogon->logon4.domain = flatname;
+ netlogon->logon4.pdc_name = lp_netbios_name();
+ netlogon->logon4.user_name = "";
+ netlogon->logon4.site_name = site_name;
+ netlogon->logon4.site_name2 = site_name2;
+ netlogon->logon4.unknown = 10;
+ netlogon->logon4.unknown2 = 2;
+ netlogon->logon4.pdc_ip = pdc_ip;
+ netlogon->logon4.nt_version = 5;
+ netlogon->logon4.lmnt_token = 0xFFFF;
+ netlogon->logon4.lm20_token = 0xFFFF;
+ break;
+ }
+
+ return NT_STATUS_OK;
+}
+
+
+/*
+ handle incoming cldap requests
+*/
+void cldapd_netlogon_request(struct cldap_socket *cldap,
+ uint32_t message_id,
+ const char *filter,
+ const char *src_address, int src_port)
+{
+ struct ldap_parse_tree *tree;
+ int i;
+ const char *domain = NULL;
+ const char *host = NULL;
+ int version = -1;
+ union nbt_cldap_netlogon netlogon;
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(cldap);
+
+ tree = ldap_parse_filter_string(tmp_ctx, filter);
+ if (tree == NULL) goto failed;
+
+ if (tree->operation != LDAP_OP_AND) goto failed;
+
+ /* extract the query elements */
+ for (i=0;i<tree->u.list.num_elements;i++) {
+ struct ldap_parse_tree *t = tree->u.list.elements[i];
+ if (t->operation != LDAP_OP_SIMPLE) goto failed;
+ if (strcasecmp(t->u.simple.attr, "DnsDomain") == 0) {
+ domain = talloc_strndup(tmp_ctx,
+ t->u.simple.value.data,
+ t->u.simple.value.length);
+ }
+ if (strcasecmp(t->u.simple.attr, "Host") == 0) {
+ host = talloc_strndup(tmp_ctx,
+ t->u.simple.value.data,
+ t->u.simple.value.length);
+ }
+ if (strcasecmp(t->u.simple.attr, "NtVer") == 0 &&
+ t->u.simple.value.length == 4) {
+ version = IVAL(t->u.simple.value.data, 0);
+ }
+ }
+
+ if (domain == NULL || host == NULL || version == -1) {
+ goto failed;
+ }
+
+ DEBUG(2,("cldap netlogon query domain=%s host=%s version=%d\n",
+ domain, host, version));
+
+ status = cldapd_netlogon_fill(cldap, tmp_ctx, domain, src_address,
+ version, &netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ status = cldap_netlogon_reply(cldap, message_id, src_address, src_port, version,
+ &netlogon);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ talloc_free(tmp_ctx);
+ return;
+
+failed:
+ DEBUG(0,("cldap netlogon query failed domain=%s host=%s version=%d - %s\n",
+ domain, host, version, nt_errstr(status)));
+ talloc_free(tmp_ctx);
+ cldap_empty_reply(cldap, message_id, src_address, src_port);
+}