[PATCH] Make NetBIOS traffic always go through nmbd

Volker Lendecke Volker.Lendecke at SerNet.DE
Wed Mar 21 11:09:21 UTC 2018


Hi!

Attached find a patchset that makes us more like Windows regarding
netbios traffic: All outgoing packets go through nmbd or nbt_server,
making them come from port 137/138. This is done by opening the
already existing "unexpected" pipe also for outgoing packets.

This should in the future obsolete the "disable netbios" parameter.
Either you run nmbd/nbt_server or you don't.

It has survived a few private autobuilds.

Review appreciated!

Thanks, Volker

-- 
Besuchen Sie die verinice.XP 2018 in Berlin,
Anwenderkonferenz für Informationssicherheit
vom 21.-23.03.2018 im Sofitel Kurfürstendamm
Info & Anmeldung hier: http://veriniceXP.org

SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From 0e4bcedee653105a8cff8560548fff56a2117fb4 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 16 Jan 2018 16:47:00 +0100
Subject: [PATCH 01/32] libnmb: Factor out nb_packet_recv_send

This only replaces the nb_packet_reader parameter with a
tstream_context. nb_packet_read_send is the used API, and we'll use the
core logic in nmbd as well.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/unexpected.c | 98 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 77 insertions(+), 21 deletions(-)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index ced46969b88..55e2a1007db 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -654,40 +654,40 @@ NTSTATUS nb_packet_reader_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
-struct nb_packet_read_state {
+struct nb_packet_recv_state {
 	struct nb_packet_client_header hdr;
 	uint8_t *buf;
 	size_t buflen;
 };
 
-static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p);
-static void nb_packet_read_done(struct tevent_req *subreq);
+static ssize_t nb_packet_recv_more(uint8_t *buf, size_t buflen, void *p);
+static void nb_packet_recv_done(struct tevent_req *subreq);
 
-struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
-				       struct tevent_context *ev,
-				       struct nb_packet_reader *reader)
+static struct tevent_req *nb_packet_recv_send(TALLOC_CTX *mem_ctx,
+					      struct tevent_context *ev,
+					      struct tstream_context *sock)
 {
 	struct tevent_req *req, *subreq;
-	struct nb_packet_read_state *state;
+	struct nb_packet_recv_state *state;
 
-	req = tevent_req_create(mem_ctx, &state, struct nb_packet_read_state);
+	req = tevent_req_create(mem_ctx, &state, struct nb_packet_recv_state);
 	if (req == NULL) {
 		return NULL;
 	}
-	subreq = tstream_read_packet_send(state, ev, reader->sock,
+	subreq = tstream_read_packet_send(state, ev, sock,
 					  sizeof(struct nb_packet_client_header),
-					  nb_packet_read_more, state);
+					  nb_packet_recv_more, state);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, nb_packet_read_done, req);
+	tevent_req_set_callback(subreq, nb_packet_recv_done, req);
 	return req;
 }
 
-static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p)
+static ssize_t nb_packet_recv_more(uint8_t *buf, size_t buflen, void *p)
 {
-	struct nb_packet_read_state *state = talloc_get_type_abort(
-		p, struct nb_packet_read_state);
+	struct nb_packet_recv_state *state = talloc_get_type_abort(
+		p, struct nb_packet_recv_state);
 
 	if (buflen > sizeof(struct nb_packet_client_header)) {
 		/*
@@ -699,12 +699,12 @@ static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p)
 	return state->hdr.len;
 }
 
-static void nb_packet_read_done(struct tevent_req *subreq)
+static void nb_packet_recv_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
 		subreq, struct tevent_req);
-	struct nb_packet_read_state *state = tevent_req_data(
-		req, struct nb_packet_read_state);
+	struct nb_packet_recv_state *state = tevent_req_data(
+		req, struct nb_packet_recv_state);
 	ssize_t nread;
 	int err;
 
@@ -717,11 +717,12 @@ static void nb_packet_read_done(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			     struct packet_struct **ppacket)
+static NTSTATUS nb_packet_recv_recv(struct tevent_req *req,
+				    TALLOC_CTX *mem_ctx,
+				    struct packet_struct **ppacket)
 {
-	struct nb_packet_read_state *state = tevent_req_data(
-		req, struct nb_packet_read_state);
+	struct nb_packet_recv_state *state = tevent_req_data(
+		req, struct nb_packet_recv_state);
 	struct nb_packet_client_header hdr;
 	struct packet_struct *packet;
 	NTSTATUS status;
@@ -747,3 +748,58 @@ NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
+
+struct nb_packet_read_state {
+	struct packet_struct *pkt;
+};
+
+static void nb_packet_read_done(struct tevent_req *subreq);
+
+struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
+				       struct tevent_context *ev,
+				       struct nb_packet_reader *reader)
+{
+	struct tevent_req *req, *subreq;
+	struct nb_packet_read_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct nb_packet_read_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	subreq = nb_packet_recv_send(state, ev, reader->sock);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, nb_packet_read_done, req);
+	return req;
+}
+
+static void nb_packet_read_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct nb_packet_read_state *state = tevent_req_data(
+		req, struct nb_packet_read_state);
+	NTSTATUS status;
+
+	status = nb_packet_recv_recv(subreq, state, &state->pkt);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	tevent_req_done(req);
+}
+
+NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+			     struct packet_struct **ppacket)
+{
+	struct nb_packet_read_state *state = tevent_req_data(
+		req, struct nb_packet_read_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*ppacket = talloc_move(mem_ctx, &state->pkt);
+	return NT_STATUS_OK;
+}
-- 
2.11.0


From 7e78a421eee313460d67159130868e475dd8f379 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 21:26:28 +0100
Subject: [PATCH 02/32] libnmb: Add "pkt_receiver" to nb_packet_server

This is the nmbd side of the "unexpected" socket that is right now used
to push unexpected, incoming 137/138 packets to netbios clients. This is
the first step to replace the MSG_SEND_PACKET mechanism for nmbd to
proxy packets.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/unexpected.c | 15 +++++++++++----
 source3/libsmb/unexpected.h | 11 +++++++----
 source3/nmbd/nmbd_packets.c |  1 +
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index 55e2a1007db..bf23d4959c5 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -46,6 +46,8 @@ struct nb_packet_server {
 	struct tevent_fd *listen_fde;
 	int max_clients;
 	int num_clients;
+	void (*pkt_receiver)(struct packet_struct *pkt, void *private_data);
+	void *private_data;
 	struct nb_packet_client *clients;
 };
 
@@ -72,10 +74,13 @@ static void nb_packet_server_listener(struct tevent_context *ev,
 				      uint16_t flags,
 				      void *private_data);
 
-NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
-				 struct tevent_context *ev,
-				 int max_clients,
-				 struct nb_packet_server **presult)
+NTSTATUS nb_packet_server_create(
+	TALLOC_CTX *mem_ctx,
+	struct tevent_context *ev,
+	int max_clients,
+	void (*pkt_receiver)(struct packet_struct *pkt, void *private_data),
+	void *private_data,
+	struct nb_packet_server **presult)
 {
 	struct nb_packet_server *result;
 	NTSTATUS status;
@@ -88,6 +93,8 @@ NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
 	}
 	result->ev = ev;
 	result->max_clients = max_clients;
+	result->pkt_receiver = pkt_receiver;
+	result->private_data = private_data;
 
 	result->listen_sock = create_pipe_sock(
 		nmbd_socket_dir(), "unexpected", 0755);
diff --git a/source3/libsmb/unexpected.h b/source3/libsmb/unexpected.h
index 270976b7f65..b06b8763549 100644
--- a/source3/libsmb/unexpected.h
+++ b/source3/libsmb/unexpected.h
@@ -27,10 +27,13 @@
 struct nb_packet_server;
 struct nb_packet_reader;
 
-NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
-				 struct tevent_context *ev,
-				 int max_clients,
-				 struct nb_packet_server **presult);
+NTSTATUS nb_packet_server_create(
+	TALLOC_CTX *mem_ctx,
+	struct tevent_context *ev,
+	int max_clients,
+	void (*pkt_receiver)(struct packet_struct *pkt, void *private_data),
+	void *private_data,
+	struct nb_packet_server **presult);
 void nb_packet_dispatch(struct nb_packet_server *server,
 			struct packet_struct *p);
 struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index bbcb9582ec5..48d135ac1f8 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -43,6 +43,7 @@ bool nmbd_init_packet_server(void)
 	status = nb_packet_server_create(
 		NULL, nmbd_event_context(),
 		lp_parm_int(-1, "nmbd", "unexpected_clients", 200),
+		NULL, NULL,
 		&packet_server);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("ERROR: nb_packet_server_create failed: %s\n",
-- 
2.11.0


From d049a01a7e66224ebf79f83740a934f40c70d159 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 21:41:58 +0100
Subject: [PATCH 03/32] libnmb: Read packets from the unexpected pipe in nmbd

Not hooked into nmbd yet, stay tuned

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/unexpected.c | 45 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index bf23d4959c5..6d7a8452073 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -73,6 +73,12 @@ static void nb_packet_server_listener(struct tevent_context *ev,
 				      struct tevent_fd *fde,
 				      uint16_t flags,
 				      void *private_data);
+static struct tevent_req *nb_packet_recv_send(TALLOC_CTX *mem_ctx,
+					      struct tevent_context *ev,
+					      struct tstream_context *sock);
+static NTSTATUS nb_packet_recv_recv(struct tevent_req *req,
+				    TALLOC_CTX *mem_ctx,
+				    struct packet_struct **ppacket);
 
 NTSTATUS nb_packet_server_create(
 	TALLOC_CTX *mem_ctx,
@@ -299,11 +305,9 @@ static void nb_packet_got_query(struct tevent_req *req)
 	}
 	tevent_req_set_callback(req, nb_packet_client_ack_done, client);
 
-	req = tstream_read_packet_send(client, client->server->ev,
-				       client->sock, 1, NULL, NULL);
+	req = nb_packet_recv_send(client, client->server->ev, client->sock);
 	if (req == NULL) {
-		DEBUG(10, ("Could not activate reader for client exit "
-			   "detection\n"));
+		DBG_DEBUG("nb_packet_recv_send for client packets failed\n");
 		TALLOC_FREE(client);
 		return;
 	}
@@ -334,17 +338,32 @@ static void nb_packet_client_read_done(struct tevent_req *req)
 {
 	struct nb_packet_client *client = tevent_req_callback_data(
 		req, struct nb_packet_client);
-	ssize_t nread;
-	uint8_t *buf;
-	int err;
+	struct nb_packet_server *server = client->server;
+	struct packet_struct *pkt;
+	NTSTATUS status;
 
-	nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
-	TALLOC_FREE(req);
-	if (nread == 1) {
-		DEBUG(10, ("Protocol error, received data on write-only "
-			   "unexpected socket: 0x%2.2x\n", (*buf)));
+	status = nb_packet_recv_recv(req, client, &pkt);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("Failed to read client packet: %s\n",
+			  nt_errstr(status));
+		TALLOC_FREE(client);
+		return;
+	}
+
+	if (server->pkt_receiver != NULL) {
+		server->pkt_receiver(pkt, server->private_data);
 	}
-	TALLOC_FREE(client);
+
+	TALLOC_FREE(pkt);
+
+	req = nb_packet_recv_send(client, client->server->ev, client->sock);
+	if (req == NULL) {
+		DBG_DEBUG("nb_packet_recv_send for client packets failed\n");
+		TALLOC_FREE(client);
+		return;
+	}
+	tevent_req_set_callback(req, nb_packet_client_read_done,
+				client);
 }
 
 static void nb_packet_client_send(struct nb_packet_client *client,
-- 
2.11.0


From 929127cf9d5ddd75d1d6f9fb74888ff6d74b4cc5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 21:53:29 +0100
Subject: [PATCH 04/32] nmbd: Accept packets and on the unexpected pipe

One semantic change from the SEND_PACKET message is that packet_proxy
does the broadcasting for NMB packets. This will be useful in broadcast
lookup: The netbios client code (nmblookup et al) don't have to
enumerate interfaces anymore, this will be done by nmbd.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/nmbd/nmbd_packets.c | 64 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index 48d135ac1f8..45c967d75fb 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -36,6 +36,68 @@ bool rescan_listen_set = False;
 
 static struct nb_packet_server *packet_server;
 
+static void packet_proxy(struct packet_struct *pkt, void *private_data)
+{
+	struct subnet_record *subrec;
+	struct sockaddr_storage ss;
+	const struct sockaddr_storage *pss;
+	const struct in_addr *local_ip;
+
+	if ((pkt->packet_type != NMB_PACKET) &&
+	    (pkt->packet_type != DGRAM_PACKET)) {
+		DBG_NOTICE("Discarding invalid packet type %d\n",
+			   pkt->packet_type);
+		return;
+	}
+
+	in_addr_to_sockaddr_storage(&ss, pkt->ip);
+
+	if ((pkt->packet_type == NMB_PACKET) &&
+	    pkt->packet.nmb.header.nm_flags.bcast) {
+		/* Broadcast packet */
+		for (subrec = FIRST_SUBNET; subrec != NULL;
+		     subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+			pkt->send_fd = (pkt->packet_type == NMB_PACKET) ?
+				subrec->nmb_sock : subrec->dgram_sock;
+			pkt->ip = subrec->bcast_ip;
+			pkt->port = 137;
+			send_packet(pkt);
+		}
+		return;
+	}
+
+	pss = iface_ip((struct sockaddr *)(void *)&ss);
+
+	if (pss == NULL) {
+		DBG_NOTICE("Could not find ip for packet\n");
+		return;
+	}
+
+	local_ip = &((const struct sockaddr_in *)pss)->sin_addr;
+	subrec = FIRST_SUBNET;
+
+	pkt->recv_fd = -1;
+	pkt->send_fd = (pkt->packet_type == NMB_PACKET) ?
+		subrec->nmb_sock : subrec->dgram_sock;
+
+	for (subrec = FIRST_SUBNET; subrec != NULL;
+	     subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
+		if (ip_equal_v4(*local_ip, subrec->myip)) {
+			pkt->send_fd = (pkt->packet_type == NMB_PACKET) ?
+				subrec->nmb_sock : subrec->dgram_sock;
+			break;
+		}
+	}
+
+	if (pkt->packet_type == DGRAM_PACKET) {
+		pkt->port = 138;
+		pkt->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
+		pkt->packet.dgram.header.source_port = 138;
+	}
+
+	send_packet(pkt);
+}
+
 bool nmbd_init_packet_server(void)
 {
 	NTSTATUS status;
@@ -43,7 +105,7 @@ bool nmbd_init_packet_server(void)
 	status = nb_packet_server_create(
 		NULL, nmbd_event_context(),
 		lp_parm_int(-1, "nmbd", "unexpected_clients", 200),
-		NULL, NULL,
+		packet_proxy, NULL,
 		&packet_server);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("ERROR: nb_packet_server_create failed: %s\n",
-- 
2.11.0


From 6e278560d2a3814aeb9b674547cefc3113609635 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 25 Jan 2018 15:13:38 +0100
Subject: [PATCH 05/32] nmbd: Queue broadcast packets also locally

This will make nmbd answer locally if it can

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/nmbd/nmbd_packets.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/source3/nmbd/nmbd_packets.c b/source3/nmbd/nmbd_packets.c
index 45c967d75fb..4cb2eb2b9d2 100644
--- a/source3/nmbd/nmbd_packets.c
+++ b/source3/nmbd/nmbd_packets.c
@@ -54,6 +54,8 @@ static void packet_proxy(struct packet_struct *pkt, void *private_data)
 
 	if ((pkt->packet_type == NMB_PACKET) &&
 	    pkt->packet.nmb.header.nm_flags.bcast) {
+		struct packet_struct *pkt_copy;
+
 		/* Broadcast packet */
 		for (subrec = FIRST_SUBNET; subrec != NULL;
 		     subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
@@ -63,6 +65,13 @@ static void packet_proxy(struct packet_struct *pkt, void *private_data)
 			pkt->port = 137;
 			send_packet(pkt);
 		}
+
+		pkt_copy = copy_packet(pkt);
+		if (pkt_copy != NULL) {
+			pkt_copy->recv_fd = -1;
+			pkt_copy->send_fd = -1;
+			queue_packet(pkt_copy);
+		}
 		return;
 	}
 
@@ -1079,6 +1088,11 @@ void reply_netbios_packet(struct packet_struct *orig_packet,
 
 	debug_nmb_packet(&packet);
 
+	if (packet.send_fd == -1) {
+		nb_packet_dispatch(packet_server, &packet);
+		return;
+	}
+
 	if(loopback_this_packet) {
 		struct packet_struct *lo_packet;
 		DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
-- 
2.11.0


From b6a4ce28e5ba3f8fc74ba0a68d4dc32462d985f0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 29 Jan 2018 19:23:53 +0100
Subject: [PATCH 06/32] nbt_server: Shorten a line in wscript_build

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/nbt_server/wscript_build | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/source4/nbt_server/wscript_build b/source4/nbt_server/wscript_build
index 9d0c24a14e2..632d5fbe41d 100644
--- a/source4/nbt_server/wscript_build
+++ b/source4/nbt_server/wscript_build
@@ -36,7 +36,14 @@ bld.SAMBA_SUBSYSTEM('NBTD_DGRAM',
 
 
 bld.SAMBA_SUBSYSTEM('NBT_SERVER',
-	source='interfaces.c register.c query.c nodestatus.c defense.c packet.c irpc.c',
+	source='''
+            interfaces.c
+            register.c
+            query.c
+            nodestatus.c
+            defense.c
+            packet.c
+            irpc.c''',
 	autoproto='nbt_server_proto.h',
 	deps='cli-nbt NBTD_WINS NBTD_DGRAM service',
 	enabled=bld.AD_DC_BUILD_IS_ENABLED()
-- 
2.11.0


From d994a8129f6bf43c4c1b12b3f1d1dd0b97e9cd49 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 2 Feb 2018 13:30:44 +0100
Subject: [PATCH 07/32] nbt_server: Factor out nbtd_name_query_reply_packet

Separate logic from transport

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/nbt_server/packet.c | 101 +++++++++++++++++++++++++++++---------------
 1 file changed, 67 insertions(+), 34 deletions(-)

diff --git a/source4/nbt_server/packet.c b/source4/nbt_server/packet.c
index 2857f1aa9b4..e6b36022972 100644
--- a/source4/nbt_server/packet.c
+++ b/source4/nbt_server/packet.c
@@ -94,32 +94,27 @@ bool nbtd_self_packet(struct nbt_name_socket *nbtsock,
 	return false;
 }
 
-
-/*
-  send a name query reply
-*/
-void nbtd_name_query_reply(struct nbt_name_socket *nbtsock, 
-			   struct nbt_name_packet *request_packet, 
-			   struct socket_address *src,
-			   struct nbt_name *name, uint32_t ttl,
-			   uint16_t nb_flags, const char **addresses)
+struct nbt_name_packet *nbtd_name_query_reply_packet(
+	TALLOC_CTX *mem_ctx, uint16_t trn_id, uint32_t ttl, uint16_t nb_flags,
+	const struct nbt_name *name,
+	const char **addresses, size_t num_addresses)
 {
 	struct nbt_name_packet *packet;
-	size_t num_addresses = str_list_length(addresses);
-	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
-						       struct nbtd_interface);
-	struct nbtd_server *nbtsrv = iface->nbtsrv;
-	int i;
+	size_t i;
+	struct nbt_res_rec *answer;
+	struct nbt_rdata_netbios *rdata;
+	NTSTATUS status;
 
 	if (num_addresses == 0) {
-		DEBUG(3,("No addresses in name query reply - failing\n"));
-		return;
+		return NULL;
 	}
 
-	packet = talloc_zero(nbtsock, struct nbt_name_packet);
-	if (packet == NULL) return;
+	packet = talloc_zero(mem_ctx, struct nbt_name_packet);
+	if (packet == NULL) {
+		return NULL;
+	}
 
-	packet->name_trn_id = request_packet->name_trn_id;
+	packet->name_trn_id = trn_id;
 	packet->ancount = 1;
 	packet->operation =
 		NBT_FLAG_REPLY |
@@ -129,23 +124,62 @@ void nbtd_name_query_reply(struct nbt_name_socket *nbtsock,
 		NBT_FLAG_RECURSION_AVAIL;
 
 	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
-	if (packet->answers == NULL) goto failed;
+	if (packet->answers == NULL) {
+		goto failed;
+	}
+	answer = packet->answers;
 
-	packet->answers[0].name     = *name;
-	packet->answers[0].rr_type  = NBT_QTYPE_NETBIOS;
-	packet->answers[0].rr_class = NBT_QCLASS_IP;
-	packet->answers[0].ttl      = ttl;
-	packet->answers[0].rdata.netbios.length = num_addresses*6;
-	packet->answers[0].rdata.netbios.addresses = 
-		talloc_array(packet->answers, struct nbt_rdata_address, num_addresses);
-	if (packet->answers[0].rdata.netbios.addresses == NULL) goto failed;
-
-	for (i=0;i<num_addresses;i++) {
-		struct nbt_rdata_address *addr = 
-			&packet->answers[0].rdata.netbios.addresses[i];
+	status = nbt_name_dup(packet->answers, name, &answer->name);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto failed;
+	}
+	answer->rr_type  = NBT_QTYPE_NETBIOS;
+	answer->rr_class = NBT_QCLASS_IP;
+	answer->ttl      = ttl;
+
+	rdata = &answer->rdata.netbios;
+	rdata->length = num_addresses*6;
+	rdata->addresses = talloc_array(
+		packet->answers, struct nbt_rdata_address, num_addresses);
+	if (rdata->addresses == NULL) {
+		goto failed;
+	}
+
+	for (i=0; i<num_addresses; i++) {
+		struct nbt_rdata_address *addr = &rdata->addresses[i];
 		addr->nb_flags = nb_flags;
 		addr->ipaddr = talloc_strdup(packet->answers, addresses[i]);
-		if (addr->ipaddr == NULL) goto failed;
+		if (addr->ipaddr == NULL) {
+			goto failed;
+		}
+	}
+
+	return packet;
+
+failed:
+	TALLOC_FREE(packet);
+	return NULL;
+}
+
+/*
+  send a name query reply
+*/
+void nbtd_name_query_reply(struct nbt_name_socket *nbtsock,
+			   struct nbt_name_packet *request_packet,
+			   struct socket_address *src,
+			   struct nbt_name *name, uint32_t ttl,
+			   uint16_t nb_flags, const char **addresses)
+{
+	struct nbt_name_packet *packet;
+	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
+						       struct nbtd_interface);
+	struct nbtd_server *nbtsrv = iface->nbtsrv;
+
+	packet = nbtd_name_query_reply_packet(
+		nbtsock, request_packet->name_trn_id, ttl, nb_flags,
+		name, addresses, str_list_length(addresses));
+	if (packet == NULL) {
+		return;
 	}
 
 	DEBUG(7,("Sending name query reply for %s at %s to %s:%d\n", 
@@ -154,7 +188,6 @@ void nbtd_name_query_reply(struct nbt_name_socket *nbtsock,
 	nbtsrv->stats.total_sent++;
 	nbt_name_reply_send(nbtsock, src, packet);
 
-failed:
 	talloc_free(packet);
 }
 
-- 
2.11.0


From 27f5aa7f1de6e3bbb9eb433711d31b67f31d6a7e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 2 Feb 2018 15:03:16 +0100
Subject: [PATCH 08/32] nbt_server: Factor out nbtd_node_status_reply_packet

Separate logic from transport

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/nbt_server/nodestatus.c | 135 ++++++++++++++++++++++++++--------------
 1 file changed, 90 insertions(+), 45 deletions(-)

diff --git a/source4/nbt_server/nodestatus.c b/source4/nbt_server/nodestatus.c
index f71746ab300..42a5357214d 100644
--- a/source4/nbt_server/nodestatus.c
+++ b/source4/nbt_server/nodestatus.c
@@ -26,6 +26,92 @@
 #include "lib/socket/socket.h"
 #include "librpc/gen_ndr/ndr_nbt.h"
 
+struct nbt_name_packet *nbtd_node_status_reply_packet(
+	TALLOC_CTX *mem_ctx, uint16_t trn_id,
+	const struct nbt_name *name, struct nbtd_interface *iface)
+{
+	struct nbtd_iface_name *iname;
+	struct nbt_name_packet *packet;
+	struct nbt_res_rec *answer;
+	struct nbt_rdata_status *stat;
+	uint32_t num_names;
+	NTSTATUS status;
+
+	num_names = 0;
+	for (iname = iface->names; iname != NULL; iname = iname->next) {
+		if ((iname->nb_flags & NBT_NM_ACTIVE) == 0) {
+			continue;
+		}
+		if (strcmp(iname->name.name, "*") == 0) {
+			continue;
+		}
+		num_names += 1;
+	}
+
+	packet = talloc_zero(mem_ctx, struct nbt_name_packet);
+	if (packet == NULL) {
+		return NULL;
+	}
+
+	packet->name_trn_id = trn_id;
+	packet->ancount = 1;
+	packet->operation = NBT_OPCODE_QUERY | NBT_FLAG_REPLY
+		| NBT_FLAG_AUTHORITATIVE;
+
+	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
+	if (packet->answers == NULL) {
+		goto failed;
+	}
+
+	answer = &packet->answers[0];
+
+	status = nbt_name_dup(packet->answers, name, &answer->name);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto failed;
+	}
+
+	answer->rr_type  = NBT_QTYPE_STATUS;
+	answer->rr_class = NBT_QCLASS_IP;
+	answer->ttl      = 0;
+
+	stat = &packet->answers[0].rdata.status;
+
+	stat->num_names = num_names;
+	stat->names = talloc_zero_array(
+		packet->answers, struct nbt_status_name, num_names);
+	if (stat->names == NULL) {
+		goto failed;
+	}
+
+	num_names = 0;
+	for (iname = iface->names; iname != NULL; iname = iname->next) {
+		struct nbt_status_name *n = &stat->names[num_names];
+
+		if ((iname->nb_flags & NBT_NM_ACTIVE) == 0) {
+			continue;
+		}
+		if (strcmp(iname->name.name, "*") == 0) {
+			continue;
+		}
+
+		n->name = talloc_asprintf(stat->names, "%-15s",
+					  iname->name.name);
+		if (n->name == NULL) {
+			goto failed;
+		}
+		n->type = iname->name.type;
+		n->nb_flags = iname->nb_flags;
+
+		num_names += 1;
+	}
+
+	return packet;
+
+failed:
+	TALLOC_FREE(packet);
+	return NULL;
+}
+
 /*
   send a name status reply
 */
@@ -36,53 +122,13 @@ static void nbtd_node_status_reply(struct nbt_name_socket *nbtsock,
 				   struct nbtd_interface *iface)
 {
 	struct nbt_name_packet *packet;
-	uint32_t name_count;
-	struct nbtd_iface_name *iname;
 	struct nbtd_server *nbtsrv = iface->nbtsrv;
-	
-	/* work out how many names to send */
-	name_count = 0;
-	for (iname=iface->names;iname;iname=iname->next) {
-		if ((iname->nb_flags & NBT_NM_ACTIVE) && 
-		    strcmp(iname->name.name, "*") != 0) {
-			name_count++;
-		}
-	}
-
-	packet = talloc_zero(nbtsock, struct nbt_name_packet);
-	if (packet == NULL) return;
 
-	packet->name_trn_id = request_packet->name_trn_id;
-	packet->ancount = 1;
-	packet->operation = NBT_OPCODE_QUERY | NBT_FLAG_REPLY | NBT_FLAG_AUTHORITATIVE;
-
-	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
-	if (packet->answers == NULL) goto failed;
-
-	packet->answers[0].name     = *name;
-	packet->answers[0].rr_type  = NBT_QTYPE_STATUS;
-	packet->answers[0].rr_class = NBT_QCLASS_IP;
-	packet->answers[0].ttl      = 0;
-	packet->answers[0].rdata.status.num_names = name_count;
-	packet->answers[0].rdata.status.names = talloc_array(packet->answers,
-							     struct nbt_status_name, name_count);
-	if (packet->answers[0].rdata.status.names == NULL) goto failed;
-
-	name_count = 0;
-	for (iname=iface->names;iname;iname=iname->next) {
-		if ((iname->nb_flags & NBT_NM_ACTIVE) && 
-		    strcmp(iname->name.name, "*") != 0) {
-			struct nbt_status_name *n = &packet->answers[0].rdata.status.names[name_count];
-			n->name = talloc_asprintf(packet->answers, "%-15s", iname->name.name);
-			if (n->name == NULL) goto failed;
-			n->type     = iname->name.type;
-			n->nb_flags = iname->nb_flags;
-			name_count++;
-		}
+	packet = nbtd_node_status_reply_packet(
+		nbtsock, request_packet->name_trn_id, name, iface);
+	if (packet == NULL) {
+		return;
 	}
-	/* we deliberately don't fill in the statistics structure as
-	   it could lead to giving attackers too much information */
-	ZERO_STRUCT(packet->answers[0].rdata.status.statistics);
 
 	DEBUG(7,("Sending node status reply for %s to %s:%d\n", 
 		 nbt_name_string(packet, name), src->addr, src->port));
@@ -90,7 +136,6 @@ static void nbtd_node_status_reply(struct nbt_name_socket *nbtsock,
 	nbtsrv->stats.total_sent++;
 	nbt_name_reply_send(nbtsock, src, packet);
 
-failed:
 	talloc_free(packet);
 }
 
-- 
2.11.0


From b4a91902f6844e34e644a916d59ca2e03f600245 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 4 Feb 2018 12:16:14 +0000
Subject: [PATCH 09/32] libnbt: Add an explicit "mem_ctx" to name_request_send

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/nbt/namequery.c    | 4 ++--
 libcli/nbt/namerefresh.c  | 2 +-
 libcli/nbt/nameregister.c | 2 +-
 libcli/nbt/namerelease.c  | 2 +-
 libcli/nbt/nbt_proto.h    | 3 ++-
 libcli/nbt/nbtsocket.c    | 5 +++--
 6 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/libcli/nbt/namequery.c b/libcli/nbt/namequery.c
index e344235faa8..49ab10c3c02 100644
--- a/libcli/nbt/namequery.c
+++ b/libcli/nbt/namequery.c
@@ -56,7 +56,7 @@ _PUBLIC_ struct nbt_name_request *nbt_name_query_send(struct nbt_name_socket *nb
 	dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
 					   io->in.dest_addr, io->in.dest_port);
 	if (dest == NULL) goto failed;
-	req = nbt_name_request_send(nbtsock, dest, packet,
+	req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
 				    io->in.timeout, io->in.retries, false);
 	if (req == NULL) goto failed;
 
@@ -160,7 +160,7 @@ _PUBLIC_ struct nbt_name_request *nbt_name_status_send(struct nbt_name_socket *n
 	dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
 					   io->in.dest_addr, io->in.dest_port);
 	if (dest == NULL) goto failed;
-	req = nbt_name_request_send(nbtsock, dest, packet,
+	req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
 				    io->in.timeout, io->in.retries, false);
 	if (req == NULL) goto failed;
 
diff --git a/libcli/nbt/namerefresh.c b/libcli/nbt/namerefresh.c
index b525356c747..b3aef76a5c6 100644
--- a/libcli/nbt/namerefresh.c
+++ b/libcli/nbt/namerefresh.c
@@ -72,7 +72,7 @@ struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock,
 					   nbtsock->sock->backend_name,
 					   io->in.dest_addr, io->in.dest_port);
 	if (dest == NULL) goto failed;
-	req = nbt_name_request_send(nbtsock, dest, packet,
+	req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
 				    io->in.timeout, io->in.retries, false);
 	if (req == NULL) goto failed;
 
diff --git a/libcli/nbt/nameregister.c b/libcli/nbt/nameregister.c
index ff5418c85e5..8e8271d5731 100644
--- a/libcli/nbt/nameregister.c
+++ b/libcli/nbt/nameregister.c
@@ -80,7 +80,7 @@ struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
 	dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
 					   io->in.dest_addr, io->in.dest_port);
 	if (dest == NULL) goto failed;
-	req = nbt_name_request_send(nbtsock, dest, packet,
+	req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
 				    io->in.timeout, io->in.retries, false);
 	if (req == NULL) goto failed;
 
diff --git a/libcli/nbt/namerelease.c b/libcli/nbt/namerelease.c
index 8f4698169d8..68c8252078b 100644
--- a/libcli/nbt/namerelease.c
+++ b/libcli/nbt/namerelease.c
@@ -69,7 +69,7 @@ _PUBLIC_ struct nbt_name_request *nbt_name_release_send(struct nbt_name_socket *
 	dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
 					   io->in.dest_addr, io->in.dest_port);
 	if (dest == NULL) goto failed;
-	req = nbt_name_request_send(nbtsock, dest, packet,
+	req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
 				    io->in.timeout, io->in.retries, false);
 	if (req == NULL) goto failed;
 
diff --git a/libcli/nbt/nbt_proto.h b/libcli/nbt/nbt_proto.h
index 281ce25a864..e6ee46bab86 100644
--- a/libcli/nbt/nbt_proto.h
+++ b/libcli/nbt/nbt_proto.h
@@ -33,7 +33,8 @@
 
 /* The following definitions come from ../libcli/nbt/nbtsocket.c  */
 
-struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
+struct nbt_name_request *nbt_name_request_send(TALLOC_CTX *mem_ctx,
+					       struct nbt_name_socket *nbtsock,
 					       struct socket_address *dest,
 					       struct nbt_name_packet *request,
 					       int timeout, int retries,
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
index 711e39cbdc5..94ec4627d80 100644
--- a/libcli/nbt/nbtsocket.c
+++ b/libcli/nbt/nbtsocket.c
@@ -367,7 +367,8 @@ failed:
 /*
   send off a nbt name request
 */
-struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
+struct nbt_name_request *nbt_name_request_send(TALLOC_CTX *mem_ctx,
+					       struct nbt_name_socket *nbtsock,
 					       struct socket_address *dest,
 					       struct nbt_name_packet *request,
 					       int timeout, int retries,
@@ -377,7 +378,7 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
 	int id;
 	enum ndr_err_code ndr_err;
 
-	req = talloc_zero(nbtsock, struct nbt_name_request);
+	req = talloc_zero(mem_ctx, struct nbt_name_request);
 	if (req == NULL) goto failed;
 
 	req->nbtsock                = nbtsock;
-- 
2.11.0


From 40ad1ac30ddb9b96e89b5a469dce35c00b90eda0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 25 Feb 2018 13:00:39 +0100
Subject: [PATCH 10/32] libdgram: Fix an error path memleak

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/libcli/dgram/mailslot.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source4/libcli/dgram/mailslot.c b/source4/libcli/dgram/mailslot.c
index 466c603432d..bae26e06c8c 100644
--- a/source4/libcli/dgram/mailslot.c
+++ b/source4/libcli/dgram/mailslot.c
@@ -171,6 +171,7 @@ NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
 	packet.dgram_id = generate_random() % UINT16_MAX;
 	src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
 	if (!src) {
+		talloc_free(tmp_ctx);
 		return NT_STATUS_NO_MEMORY;
 	}
 	packet.src_addr = src->addr;
-- 
2.11.0


From b98cd4c4220c9783e60d8b2bba8b3d051e046bb1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 25 Feb 2018 13:06:52 +0100
Subject: [PATCH 11/32] libnbt: Factor out dgram_mailslot_init

Separate logic from transport

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/libcli/dgram/libdgram.h |   8 +++
 source4/libcli/dgram/mailslot.c | 116 ++++++++++++++++++++++++++++------------
 2 files changed, 90 insertions(+), 34 deletions(-)

diff --git a/source4/libcli/dgram/libdgram.h b/source4/libcli/dgram/libdgram.h
index 0f313a67cf5..1aa0c65958e 100644
--- a/source4/libcli/dgram/libdgram.h
+++ b/source4/libcli/dgram/libdgram.h
@@ -83,6 +83,14 @@ struct dgram_mailslot_handler {
 
 
 /* prototypes */
+struct nbt_dgram_packet *dgram_mailslot_init(
+	TALLOC_CTX *mem_ctx,
+	enum dgram_msg_type msg_type,
+	struct nbt_name *src_name,
+	const char *src_address,
+	struct nbt_name *dest_name,
+	const char *mailslot_name,
+	DATA_BLOB *request);
 NTSTATUS nbt_dgram_send(struct nbt_dgram_socket *dgmsock,
 			struct nbt_dgram_packet *packet,
 			struct socket_address *dest);
diff --git a/source4/libcli/dgram/mailslot.c b/source4/libcli/dgram/mailslot.c
index bae26e06c8c..3d65e4c6f00 100644
--- a/source4/libcli/dgram/mailslot.c
+++ b/source4/libcli/dgram/mailslot.c
@@ -36,6 +36,7 @@
 #include "../lib/util/dlinklist.h"
 #include "libcli/dgram/libdgram.h"
 #include "lib/socket/socket.h"
+#include "libcli/nbt/libnbt.h"
 
 /*
   destroy a mailslot handler
@@ -141,50 +142,48 @@ struct dgram_mailslot_handler *dgram_mailslot_temp(struct nbt_dgram_socket *dgms
 	return NULL;
 }
 
-
-/*
-  send a mailslot request
-*/
-NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
-			     enum dgram_msg_type msg_type,
-			     const char *mailslot_name,
-			     struct nbt_name *dest_name,
-			     struct socket_address *dest,
-			     struct nbt_name *src_name,
-			     DATA_BLOB *request)
+struct nbt_dgram_packet *dgram_mailslot_init(
+	TALLOC_CTX *mem_ctx,
+	enum dgram_msg_type msg_type,
+	struct nbt_name *src_name,
+	const char *src_address,
+	struct nbt_name *dest_name,
+	const char *mailslot_name,
+	DATA_BLOB *request)
 {
-	TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
-	struct nbt_dgram_packet packet;
+	struct nbt_dgram_packet *packet;
 	struct dgram_message *msg;
 	struct dgram_smb_packet *smb;
 	struct smb_trans_body *trans;
-	struct socket_address *src;
 	NTSTATUS status;
 
-	if (dest->port == 0) {
-		return NT_STATUS_INVALID_PARAMETER;
+	packet = talloc_zero(mem_ctx, struct nbt_dgram_packet);
+	if (packet == NULL) {
+		return NULL;
 	}
 
-	ZERO_STRUCT(packet);
-	packet.msg_type = msg_type;
-	packet.flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
-	packet.dgram_id = generate_random() % UINT16_MAX;
-	src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
-	if (!src) {
-		talloc_free(tmp_ctx);
-		return NT_STATUS_NO_MEMORY;
-	}
-	packet.src_addr = src->addr;
-	packet.src_port = src->port;
+	packet->msg_type = msg_type;
+	packet->flags = DGRAM_FLAG_FIRST | DGRAM_NODE_NBDD;
+	packet->dgram_id = generate_random() % UINT16_MAX;
+	packet->src_addr = src_address;
+	packet->src_port = NBT_DGRAM_SERVICE_PORT;
 
-	msg = &packet.data.msg;
-	/* this length calculation is very crude - it should be based on gensize
-	   calls */
+	msg = &packet->data.msg;
+	/*
+	 * This length calculation is very crude - it should be based
+	 * on gensize calls
+	 */
 	msg->length = 138 + strlen(mailslot_name) + request->length;
 	msg->offset = 0;
 
-	msg->source_name = *src_name;
-	msg->dest_name = *dest_name;
+	status = nbt_name_dup(packet, src_name, &msg->source_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
+	status = nbt_name_dup(packet, dest_name, &msg->dest_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		goto fail;
+	}
 	msg->dgram_body_type = DGRAM_SMB;
 
 	smb = &msg->body.smb;
@@ -199,9 +198,58 @@ NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
 	trans->priority    = 1;
 	trans->_class      = 2;
 	trans->mailslot_name = mailslot_name;
-	trans->data = *request;
 
-	status = nbt_dgram_send(dgmsock, &packet, dest);
+	trans->data = data_blob_talloc(packet,
+				       request->data,
+				       request->length);
+	if (trans->data.data == NULL) {
+		goto fail;
+	}
+
+	return packet;
+fail:
+	TALLOC_FREE(packet);
+	return NULL;
+}
+
+/*
+  send a mailslot request
+*/
+NTSTATUS dgram_mailslot_send(struct nbt_dgram_socket *dgmsock,
+			     enum dgram_msg_type msg_type,
+			     const char *mailslot_name,
+			     struct nbt_name *dest_name,
+			     struct socket_address *dest,
+			     struct nbt_name *src_name,
+			     DATA_BLOB *request)
+{
+	TALLOC_CTX *tmp_ctx = talloc_new(dgmsock);
+	struct nbt_dgram_packet *packet;
+	struct socket_address *src;
+	NTSTATUS status;
+
+	if (dest->port == 0) {
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	src = socket_get_my_addr(dgmsock->sock, tmp_ctx);
+	if (!src) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	packet = dgram_mailslot_init(tmp_ctx,
+				     msg_type,
+				     src_name,
+				     src->addr,
+				     dest_name,
+				     mailslot_name,
+				     request);
+	if (packet == NULL) {
+		talloc_free(tmp_ctx);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	status = nbt_dgram_send(dgmsock, packet, dest);
 
 	talloc_free(tmp_ctx);
 
-- 
2.11.0


From ff5b465f1c033f527aa7dd561c5fae8ff950367f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 5 Mar 2018 14:55:50 +0100
Subject: [PATCH 12/32] nbt_server: Make nbtd_mailslot_netlogon_reply public

Will be used in the next commit

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/nbt_server/dgram/netlogon.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/nbt_server/dgram/netlogon.c b/source4/nbt_server/dgram/netlogon.c
index 1fee1d8cc1e..52ae96de727 100644
--- a/source4/nbt_server/dgram/netlogon.c
+++ b/source4/nbt_server/dgram/netlogon.c
@@ -179,7 +179,7 @@ static NTSTATUS nbtd_netlogon_samlogon(
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS nbtd_mailslot_netlogon_reply(
+NTSTATUS nbtd_mailslot_netlogon_reply(
 	struct nbtd_interface *iface,
 	struct nbt_dgram_packet *packet,
 	struct socket_address *src,
-- 
2.11.0


From a72220c61ee729764a2e25a7870a77d584d0d6d2 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 29 Jan 2018 19:25:34 +0100
Subject: [PATCH 13/32] nbt_server: Add "unexpected" pipe server

This adds the same functionality to the source4 nbt server that nmbd does as
well: It offers the "unexpected" socket to send and receive netbios port 137
and 138 udp packets. The structure of the nbt_server is significantly different
from nmbd, so we have to implement a bit of the logic in this server piece.

We need this for the AD DC case.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source4/nbt_server/nbt_server.c      |   16 +
 source4/nbt_server/nbt_server.h      |    4 +
 source4/nbt_server/unexpected_pipe.c | 1014 ++++++++++++++++++++++++++++++++++
 source4/nbt_server/wscript_build     |    1 +
 4 files changed, 1035 insertions(+)
 create mode 100644 source4/nbt_server/unexpected_pipe.c

diff --git a/source4/nbt_server/nbt_server.c b/source4/nbt_server/nbt_server.c
index 834c72f5f7c..ffe9dbee7c0 100644
--- a/source4/nbt_server/nbt_server.c
+++ b/source4/nbt_server/nbt_server.c
@@ -29,6 +29,7 @@
 #include "auth/auth.h"
 #include "dsdb/samdb/samdb.h"
 #include "param/param.h"
+#include "dynconfig.h"
 
 NTSTATUS server_service_nbtd_init(TALLOC_CTX *);
 
@@ -40,6 +41,7 @@ static void nbtd_task_init(struct task_server *task)
 	struct nbtd_server *nbtsrv;
 	NTSTATUS status;
 	struct interface *ifaces;
+	const char *nmbd_socket_dir;
 
 	load_interface_list(task, task->lp_ctx, &ifaces);
 
@@ -86,6 +88,20 @@ static void nbtd_task_init(struct task_server *task)
 		return;
 	}
 
+	nmbd_socket_dir = lpcfg_parm_string(
+		task->lp_ctx, NULL, "nmbd", "socket dir");
+
+	status = nbtd_server_init_unexpected_pipe(
+		nbtsrv, task->event_ctx, nbtsrv,
+		nmbd_socket_dir ? nmbd_socket_dir : get_dyn_NMBDSOCKETDIR(),
+		&nbtsrv->unexpected);
+	if (!NT_STATUS_IS_OK(status)) {
+		task_server_terminate(
+			task, "nbtd failed to listen on the unexpected pipe",
+			true);
+		return;
+	}
+
 	nbtd_register_irpc(nbtsrv);
 
 	/* start the process of registering our names on all interfaces */
diff --git a/source4/nbt_server/nbt_server.h b/source4/nbt_server/nbt_server.h
index c80e5bfca07..b93938484eb 100644
--- a/source4/nbt_server/nbt_server.h
+++ b/source4/nbt_server/nbt_server.h
@@ -25,6 +25,8 @@
 #include "librpc/gen_ndr/irpc.h"
 #include "lib/messaging/irpc.h"
 
+struct nbtd_unexpected_server;
+
 /* 
    a list of our registered names on each interface
 */
@@ -78,6 +80,8 @@ struct nbtd_server {
 	struct nbtd_statistics stats;
 
 	struct ldb_context *sam_ctx;
+
+	struct nbtd_unexpected_server *unexpected;
 };
 
 
diff --git a/source4/nbt_server/unexpected_pipe.c b/source4/nbt_server/unexpected_pipe.c
new file mode 100644
index 00000000000..7b75ede7669
--- /dev/null
+++ b/source4/nbt_server/unexpected_pipe.c
@@ -0,0 +1,1014 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * "unexpected" pipe server
+ *
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "../lib/util/dlinklist.h"
+#include "system/network.h"
+#include "nbt_server/nbt_server.h"
+#include "lib/socket/socket.h"
+#include "lib/tsocket/tsocket.h"
+#include "smbd/service_task.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "libcli/nbt/nbt_proto.h"
+#include "source4/nbt_server/dgram/proto.h"
+
+struct nbtd_unexpected_client;
+
+struct nbtd_unexpected_server {
+	struct nbtd_server *nbtd;
+	struct tevent_fd *listen_fde;
+	int sock;
+	struct nbtd_unexpected_client *clients;
+};
+
+/*
+ * Copy from source3/libsmb/unexpected.c
+ */
+enum packet_type {NMB_PACKET, DGRAM_PACKET};
+struct nb_packet_query {
+	enum packet_type type;
+	size_t mailslot_namelen;
+	int trn_id;
+};
+struct nb_packet_client_header {
+	size_t len;
+	enum packet_type type;
+	time_t timestamp;
+	struct in_addr ip;
+	int port;
+};
+
+struct nbtd_unexpected_client {
+	struct nbtd_unexpected_client *prev, *next;
+	struct nbtd_unexpected_server *server;
+	struct tstream_context *sock;
+	struct tevent_queue *out_queue;
+
+	size_t nread;
+
+	struct nb_packet_query query;
+	char *mailslot;
+	struct iovec ack_iov;
+
+	struct nb_packet_client_header hdr;
+	uint8_t buf[1024];
+};
+
+static int nbtd_unexpected_server_destructor(struct nbtd_unexpected_server *s);
+static void nb_unexpected_server_listener(
+	struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags,
+	void *private_data);
+
+NTSTATUS nbtd_server_init_unexpected_pipe(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct nbtd_server *nbtd, const char *socket_dir,
+	struct nbtd_unexpected_server **psrv)
+{
+	struct nbtd_unexpected_server *srv;
+	struct sockaddr_un sunaddr = { .sun_family = AF_UNIX };
+	int len, ret;
+	NTSTATUS status;
+	bool ok;
+
+	srv = talloc_zero(mem_ctx, struct nbtd_unexpected_server);
+	if (srv == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	srv->nbtd = nbtd;
+
+	len = snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
+		       "%s/unexpected", socket_dir);
+	if ((size_t)len >= sizeof(sunaddr.sun_path)) {
+		status = NT_STATUS_NAME_TOO_LONG;
+		goto done;
+	}
+
+	ok = directory_create_or_exist(socket_dir, 0755);
+	if (!ok) {
+		status = map_nt_error_from_unix_common(errno);
+		goto done;
+	}
+
+	srv->sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (srv->sock == -1) {
+		status = map_nt_error_from_unix_common(errno);
+		goto done;
+	}
+	talloc_set_destructor(srv, nbtd_unexpected_server_destructor);
+
+	unlink(sunaddr.sun_path);
+
+	ret = bind(srv->sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
+	if (ret == -1) {
+		status = map_nt_error_from_unix_common(errno);
+		goto done;
+	}
+
+	ret = listen(srv->sock, 5);
+	if (ret == -1) {
+		status = map_nt_error_from_unix_common(errno);
+		goto done;
+	}
+
+	srv->listen_fde = tevent_add_fd(
+		ev, srv, srv->sock, TEVENT_FD_READ,
+		nb_unexpected_server_listener, srv);
+	if (srv->listen_fde == NULL) {
+		status = NT_STATUS_NO_MEMORY;
+		goto done;
+	}
+
+	status = NT_STATUS_OK;
+done:
+	if (NT_STATUS_IS_OK(status)) {
+		*psrv = srv;
+	} else {
+		TALLOC_FREE(srv);
+	}
+	return status;
+}
+
+static int nbtd_unexpected_client_destructor(struct nbtd_unexpected_client *c);
+static int nbtd_unexpected_client_next_vec(struct tstream_context *stream,
+					   void *private_data,
+					   TALLOC_CTX *mem_ctx,
+					   struct iovec **_vector,
+					   size_t *_count);
+static void nbtd_unexpected_client_got_query(struct tevent_req *req);
+static void nbtd_unexpected_client_ack_done(struct tevent_req *req);
+static int nbtd_unexpected_client_pkt_next_vec(struct tstream_context *stream,
+					       void *private_data,
+					       TALLOC_CTX *mem_ctx,
+					       struct iovec **_vector,
+					       size_t *_count);
+static void nbtd_unexpected_client_got_pkt(struct tevent_req *req);
+
+static void nb_unexpected_server_listener(
+	struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags,
+	void *private_data)
+{
+	struct nbtd_unexpected_server *srv = talloc_get_type_abort(
+		private_data, struct nbtd_unexpected_server);
+	struct nbtd_unexpected_client *client;
+	struct tevent_req *req;
+	int ret, sock;
+
+	sock = accept(srv->sock, NULL, NULL);
+	if (sock == -1) {
+		return;
+	}
+	smb_set_close_on_exec(sock);
+
+	client = talloc_zero(srv, struct nbtd_unexpected_client);
+	if (client == NULL) {
+		close(sock);
+		return;
+	}
+	ret = tstream_bsd_existing_socket(client, sock, &client->sock);
+	if (ret == -1) {
+		close(sock);
+		TALLOC_FREE(client);
+		return;
+	}
+	sock = -1;
+
+	client->server = srv;
+	DLIST_ADD(srv->clients, client);
+	talloc_set_destructor(client, nbtd_unexpected_client_destructor);
+
+	client->out_queue = tevent_queue_create(
+		client, "unexpected packet output");
+	if (client->out_queue == NULL) {
+		DEBUG(10, ("tevent_queue_create failed\n"));
+		TALLOC_FREE(client);
+		return;
+	}
+
+	req = tstream_readv_pdu_send(
+		client, client->server->nbtd->task->event_ctx, client->sock,
+		nbtd_unexpected_client_next_vec, client);
+	if (req == NULL) {
+		TALLOC_FREE(client);
+		return;
+	}
+	tevent_req_set_callback(req, nbtd_unexpected_client_got_query, client);
+}
+
+static int nbtd_unexpected_server_destructor(struct nbtd_unexpected_server *s)
+{
+	while (s->clients != NULL) {
+		TALLOC_FREE(s->clients);
+	}
+
+	TALLOC_FREE(s->listen_fde);
+
+	if (s->sock != -1) {
+		close(s->sock);
+		s->sock = -1;
+	}
+
+	return 0;
+}
+
+static int nbtd_unexpected_client_destructor(struct nbtd_unexpected_client *c)
+{
+	DLIST_REMOVE(c->server->clients, c);
+	return 0;
+}
+
+static int nbtd_unexpected_client_next_vec(struct tstream_context *stream,
+					   void *private_data,
+					   TALLOC_CTX *mem_ctx,
+					   struct iovec **_vector,
+					   size_t *_count)
+{
+	struct nbtd_unexpected_client *client = talloc_get_type_abort(
+		private_data, struct nbtd_unexpected_client);
+	struct iovec *vector;
+
+	if (client->nread == 0) {
+		vector = talloc_array(mem_ctx, struct iovec, 1);
+		if (vector == NULL) {
+			return -1;
+		}
+		vector[0] = (struct iovec) {
+			.iov_base = &client->query,
+			.iov_len = sizeof(client->query)
+		};
+		client->nread = sizeof(client->query);
+
+		*_vector = vector;
+		*_count = 1;
+		return 0;
+	}
+
+	if (client->nread == sizeof(client->query)) {
+		size_t mailslot_namelen = client->query.mailslot_namelen;
+
+		if (mailslot_namelen > 1024) {
+			return -1;
+		}
+		if (mailslot_namelen == 0) {
+			*_vector = NULL;
+			*_count = 0;
+			return 0;
+		}
+
+		client->mailslot = talloc_array(client, char,
+						mailslot_namelen+1);
+		if (client->mailslot == NULL) {
+			return -1;
+		}
+		client->mailslot[mailslot_namelen] = '\0';
+
+		vector = talloc_array(mem_ctx, struct iovec, 1);
+		if (vector == 0) {
+			return -1;
+		}
+		vector[0] = (struct iovec) {
+			.iov_base = client->mailslot,
+			.iov_len = mailslot_namelen
+		};
+		client->nread += mailslot_namelen;
+
+		*_vector = vector;
+		*_count = 1;
+		return 0;
+	}
+
+	*_vector = NULL;
+	*_count = 0;
+	return 0;
+}
+
+static void nbtd_unexpected_write_dgm(struct nbtd_unexpected_client *client,
+				      struct in_addr from,
+				      struct nbt_dgram_packet *packet);
+
+static void nbtd_unexpected_mailslot_handler(
+	struct dgram_mailslot_handler *handler,
+	struct nbt_dgram_packet *packet,
+	struct socket_address *from)
+{
+	struct nbtd_unexpected_client *client = talloc_get_type_abort(
+		handler->private_data, struct nbtd_unexpected_client);
+	struct sockaddr_in *from_in;
+
+	if ((from->sockaddr == NULL) ||
+	    (from->sockaddrlen != sizeof(struct sockaddr_in))) {
+		DBG_DEBUG("Invalid from: %p/%zu\n", from->sockaddr,
+			  (size_t)from->sockaddrlen);
+		return;
+	}
+	from_in = (struct sockaddr_in *)from->sockaddr;
+
+	nbtd_unexpected_write_dgm(client, from_in->sin_addr, packet);
+}
+
+struct nbtd_unexpected_write_dgm_state {
+	struct iovec iov[2];
+	struct nb_packet_client_header hdr;
+};
+
+static void nbtd_unexpected_write_dgm_written(struct tevent_req *req);
+
+static void nbtd_unexpected_write_dgm(struct nbtd_unexpected_client *client,
+				      struct in_addr from,
+				      struct nbt_dgram_packet *packet)
+{
+	struct nbtd_unexpected_write_dgm_state *state;
+	struct tevent_req *req;
+	enum ndr_err_code ndr_err;
+	DATA_BLOB blob;
+
+	{
+		char fromstr[INET_ADDRSTRLEN];
+		inet_ntop(AF_INET, &from, fromstr, sizeof(fromstr));
+		DBG_DEBUG("Sending DGM from %s to unexpected client\n",
+			  fromstr);
+	}
+
+	state = talloc(client, struct nbtd_unexpected_write_dgm_state);
+	if (state == NULL) {
+		return;
+	}
+	state->hdr = (struct nb_packet_client_header) {
+		.type = DGRAM_PACKET, .timestamp = time(NULL), .ip = from
+	};
+
+	ndr_err = ndr_push_struct_blob(
+		&blob, state, packet,
+		(ndr_push_flags_fn_t)ndr_push_nbt_dgram_packet);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		talloc_free(state);
+		return;
+	}
+	state->hdr.len = blob.length;
+
+	state->iov[0] = (struct iovec) {
+		.iov_base = &state->hdr, .iov_len = sizeof(state->hdr)
+	};
+	state->iov[1] = (struct iovec) {
+		.iov_base = blob.data, .iov_len = blob.length
+	};
+
+	req = tstream_writev_queue_send(
+		state, client->server->nbtd->task->event_ctx,
+		client->sock, client->out_queue,
+		state->iov, ARRAY_SIZE(state->iov));
+	if (req == NULL) {
+		TALLOC_FREE(state);
+		return;
+	}
+	tevent_req_set_callback(req, nbtd_unexpected_write_dgm_written, state);
+}
+
+static void nbtd_unexpected_write_dgm_written(struct tevent_req *req)
+{
+	struct nbtd_unexpected_write_dgm_state *state =
+		tevent_req_callback_data(
+			req, struct nbtd_unexpected_write_dgm_state);
+	TALLOC_FREE(state);
+}
+
+static bool nbtd_unexpected_setup_mailslots(struct nbtd_unexpected_client *c,
+					    const char *mailslot_name)
+{
+	struct nbtd_server *srv = c->server->nbtd;
+	struct nbtd_interface *interface;
+
+	for (interface = srv->interfaces; interface != NULL;
+	     interface = interface->next) {
+		struct dgram_mailslot_handler *dgmslot;
+
+		if (interface->dgmsock == NULL) {
+			continue;
+		}
+
+		dgmslot = dgram_mailslot_listen(
+			interface->dgmsock, mailslot_name,
+			nbtd_unexpected_mailslot_handler, c);
+		if (dgmslot == NULL) {
+			DBG_DEBUG("dgram_mailslot_listen failed\n");
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static void nbtd_unexpected_client_got_query(struct tevent_req *req)
+{
+	struct nbtd_unexpected_client *client = tevent_req_callback_data(
+		req, struct nbtd_unexpected_client);
+	int ret, err;
+
+	ret = tstream_readv_pdu_recv(req, &err);
+	TALLOC_FREE(req);
+	if (ret == -1) {
+		TALLOC_FREE(client);
+		return;
+	}
+
+	if (client->mailslot != NULL) {
+		bool ok;
+
+		DBG_WARNING("Listening on mailslot %s\n", client->mailslot);
+
+		ok = nbtd_unexpected_setup_mailslots(client, client->mailslot);
+		if (!ok) {
+			TALLOC_FREE(client);
+			return;
+		}
+	}
+
+	client->nread = 0;
+
+	req = tstream_readv_pdu_send(
+		client, client->server->nbtd->task->event_ctx, client->sock,
+		nbtd_unexpected_client_pkt_next_vec, client);
+	if (req == NULL) {
+		TALLOC_FREE(client);
+		return;
+	}
+	tevent_req_set_callback(req, nbtd_unexpected_client_got_pkt, client);
+
+	client->ack_iov = (struct iovec) {
+		.iov_base = &client->nread, /* Just *any* byte that's there */
+		.iov_len = 1
+	};
+
+	req = tstream_writev_queue_send(
+		client, client->server->nbtd->task->event_ctx,
+		client->sock, client->out_queue, &client->ack_iov, 1);
+	if (req == NULL) {
+		TALLOC_FREE(client);
+		return;
+	}
+	tevent_req_set_callback(req, nbtd_unexpected_client_ack_done, client);
+}
+
+static void nbtd_unexpected_client_ack_done(struct tevent_req *req)
+{
+	struct nbtd_unexpected_client *client = tevent_req_callback_data(
+		req, struct nbtd_unexpected_client);
+	ssize_t nwritten;
+	int err;
+
+	nwritten = tstream_writev_queue_recv(req, &err);
+
+	TALLOC_FREE(req);
+
+	if (nwritten == -1) {
+		DEBUG(10, ("tstream_writev_queue_recv failed: %s\n",
+			   strerror(err)));
+		TALLOC_FREE(client);
+		return;
+	}
+}
+
+static int nbtd_unexpected_client_pkt_next_vec(struct tstream_context *stream,
+					       void *private_data,
+					       TALLOC_CTX *mem_ctx,
+					       struct iovec **_vector,
+					       size_t *_count)
+{
+	struct nbtd_unexpected_client *client = talloc_get_type_abort(
+		private_data, struct nbtd_unexpected_client);
+	struct iovec *vector;
+
+	if (client->nread == 0) {
+		vector = talloc_array(mem_ctx, struct iovec, 1);
+		if (vector == NULL) {
+			return -1;
+		}
+		vector[0] = (struct iovec) {
+			.iov_base = &client->hdr,
+			.iov_len = sizeof(client->hdr)
+		};
+		client->nread = sizeof(client->hdr);
+
+		*_vector = vector;
+		*_count = 1;
+		return 0;
+	}
+
+	if (client->nread == sizeof(client->hdr)) {
+		size_t len = client->hdr.len;
+
+		if ((len == 0) || (len > sizeof(client->buf))) {
+			return -1;
+		}
+
+		vector = talloc_array(mem_ctx, struct iovec, 1);
+		if (vector == 0) {
+			return -1;
+		}
+		vector[0] = (struct iovec) {
+			.iov_base = client->buf, .iov_len = len
+		};
+		client->nread += len;
+
+		*_vector = vector;
+		*_count = 1;
+		return 0;
+	}
+
+	*_vector = NULL;
+	*_count = 0;
+	return 0;
+}
+
+static void nbtd_unexpected_handle_nmb(struct nbtd_server *srv,
+				       struct nbtd_unexpected_client *client,
+				       struct nb_packet_client_header *hdr,
+				       struct nbt_name_packet *packet);
+static void nbtd_unexpected_handle_dgm(struct nbtd_server *srv,
+				       struct nbtd_unexpected_client *client,
+				       struct nb_packet_client_header *hdr,
+				       struct nbt_dgram_packet *packet);
+
+static void nbtd_unexpected_client_got_pkt(struct tevent_req *req)
+{
+	struct nbtd_unexpected_client *client = tevent_req_callback_data(
+		req, struct nbtd_unexpected_client);
+	int ret, err;
+	enum ndr_err_code ndr_err;
+	DATA_BLOB blob = { .data = client->buf, .length = client->hdr.len };
+
+	ret = tstream_readv_pdu_recv(req, &err);
+	TALLOC_FREE(req);
+	if (ret == -1) {
+		TALLOC_FREE(client);
+		return;
+	}
+
+	if (client->hdr.type == NMB_PACKET) {
+		struct nbt_name_packet *packet;
+
+		packet = talloc(client, struct nbt_name_packet);
+		if (packet == NULL) {
+			goto next;
+		}
+
+		ndr_err = ndr_pull_struct_blob(
+			&blob, packet, packet,
+			(ndr_pull_flags_fn_t)ndr_pull_nbt_name_packet);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			DBG_NOTICE("Failed to parse packet: %s, "
+				   "dropping client\n",
+				   ndr_errstr(ndr_err));
+			TALLOC_FREE(client);
+			return;
+		}
+
+		DBG_DEBUG("Got nmb packet: %s\n", ndr_errstr(ndr_err));
+
+		nbtd_unexpected_handle_nmb(client->server->nbtd, client,
+					   &client->hdr, packet);
+
+		TALLOC_FREE(packet);
+	}
+
+	if (client->hdr.type == DGRAM_PACKET) {
+		struct nbt_dgram_packet *packet;
+
+		packet = talloc(client, struct nbt_dgram_packet);
+		if (packet == NULL) {
+			goto next;
+		}
+
+		ndr_err = ndr_pull_struct_blob(
+			&blob, packet, packet,
+			(ndr_pull_flags_fn_t)ndr_pull_nbt_dgram_packet);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			DBG_NOTICE("Failed to parse packet: %s, "
+				   "dropping client\n",
+				   ndr_errstr(ndr_err));
+			TALLOC_FREE(client);
+			return;
+		}
+
+		DBG_DEBUG("Got dgm packet for %s\n", ndr_errstr(ndr_err));
+
+		if (DEBUGLEVEL >= 10) {
+			NDR_PRINT_DEBUG(nbt_dgram_packet, packet);
+		}
+
+		nbtd_unexpected_handle_dgm(client->server->nbtd, client,
+					   &client->hdr, packet);
+
+		TALLOC_FREE(packet);
+	}
+
+next:
+	client->nread = 0;
+
+	req = tstream_readv_pdu_send(
+		client, client->server->nbtd->task->event_ctx, client->sock,
+		nbtd_unexpected_client_pkt_next_vec, client);
+	if (req == NULL) {
+		TALLOC_FREE(client);
+		return;
+	}
+	tevent_req_set_callback(req, nbtd_unexpected_client_got_pkt, client);
+}
+
+static void nbtd_unexpected_write_nmb(struct nbtd_unexpected_client *client,
+				      struct in_addr from,
+				      struct nbt_name_packet *packet);
+static void nbtd_unexpected_sent_nmb(struct nbt_name_request *req);
+
+static void nbtd_unexpected_handle_nmb(struct nbtd_server *srv,
+				       struct nbtd_unexpected_client *client,
+				       struct nb_packet_client_header *hdr,
+				       struct nbt_name_packet *packet)
+{
+	if (((packet->operation & NBT_OPCODE) == NBT_OPCODE_QUERY) &&
+	    (packet->qdcount == 1) &&
+	    (packet->questions[0].question_type == NBT_QTYPE_NETBIOS) &&
+	    (packet->questions[0].question_class == NBT_QCLASS_IP)) {
+
+		/*
+		 * Try to answer name queries locally
+		 */
+
+		struct nbt_name *qname = &packet->questions[0].name;
+		struct nbtd_interface *interface;
+		struct nbtd_iface_name *iname = NULL;
+
+		for (interface = srv->interfaces; interface != NULL;
+		     interface = interface->next) {
+			if (interface->ip_address == NULL) {
+				/* Not sure this can happen */
+				continue;
+			}
+
+			iname = nbtd_find_iname(interface, qname, 0);
+
+			if (iname != NULL) {
+				break;
+			}
+		}
+
+		if (iname != NULL) {
+			struct nbt_name_packet *reply;
+			struct in_addr from;
+			int ret;
+
+			ret = inet_pton(AF_INET, interface->ip_address, &from);
+			if (ret != 1) {
+				return;
+			}
+
+			reply = nbtd_name_query_reply_packet(
+				packet, packet->name_trn_id, iname->ttl,
+				iname->nb_flags, qname,
+				&interface->ip_address, 1);
+			if (reply == NULL) {
+				return;
+			}
+
+			nbtd_unexpected_write_nmb(client, from, reply);
+
+			TALLOC_FREE(reply);
+			return;
+		}
+	}
+
+	if (((packet->operation & NBT_OPCODE) == NBT_OPCODE_QUERY) &&
+	    (packet->qdcount == 1) &&
+	    (packet->questions[0].question_type == NBT_QTYPE_STATUS) &&
+	    (packet->questions[0].question_class == NBT_QCLASS_IP)) {
+
+		/*
+		 * Do a node status request locally
+		 */
+
+		struct nbt_name *qname = &packet->questions[0].name;
+		struct nbtd_interface *interface;
+		struct nbtd_iface_name *iname = NULL;
+
+		for (interface = srv->interfaces; interface != NULL;
+		     interface = interface->next) {
+			iname = nbtd_find_iname(interface, qname, 0);
+			if (iname != NULL) {
+				break;
+			}
+		}
+
+		if (iname != NULL) {
+			struct nbt_name_packet *reply;
+			struct in_addr from;
+			int ret;
+
+			ret = inet_pton(AF_INET, interface->ip_address, &from);
+			if (ret != 1) {
+				return;
+			}
+
+			reply = nbtd_node_status_reply_packet(
+				packet, packet->name_trn_id, qname, interface);
+			if (reply == NULL) {
+				return;
+			}
+
+			nbtd_unexpected_write_nmb(client, from, reply);
+
+			TALLOC_FREE(reply);
+			return;
+		}
+	}
+
+	if (packet->operation & NBT_FLAG_BROADCAST) {
+
+		/*
+		 * Broadcast to all interfaces
+		 */
+
+		struct nbtd_interface *interface;
+
+		for (interface = srv->interfaces; interface != NULL;
+		     interface = interface->next) {
+			struct socket_address *addr;
+			struct nbt_name_request *req;
+
+			addr = socket_address_from_strings(
+				packet, "ip", interface->bcast_address,
+				NBT_NAME_SERVICE_PORT);
+			if (addr == NULL) {
+				continue;
+			}
+
+			/*
+			 * "false" here is wrong, but nmblookup4 does
+			 * the same. Also, nbt_name_request_send/recv
+			 * does not have the capability to intercept
+			 * replies as they come in. For "make test"
+			 * and winbind it should be good enough.
+			 *
+			 * When winbind on a AD DC needs to connect to
+			 * NT4 domains, choosing between multiple
+			 * group-registered DCs, this will become
+			 * relevant. Then we need to enhance
+			 * libcli/nbt.
+			 */
+			req = nbt_name_request_send(
+				client, interface->nbtsock, addr,
+				packet, 1, 0, false);
+
+			/* nbt_name_request_send takes a reference */
+			talloc_unlink(packet, addr);
+
+			if (req != NULL) {
+				req->async.fn = nbtd_unexpected_sent_nmb;
+				req->async.private_data = client;
+			}
+		}
+
+		return;
+	}
+
+	/* TODO: Proxy WINS requests -- do we still need those? */
+}
+
+struct nbtd_unexpected_write_nmb_state {
+	struct iovec iov[2];
+	struct nb_packet_client_header hdr;
+};
+
+static void nbtd_unexpected_write_nmb_written(struct tevent_req *req);
+
+static void nbtd_unexpected_write_nmb(struct nbtd_unexpected_client *client,
+				      struct in_addr from,
+				      struct nbt_name_packet *packet)
+{
+	struct nbtd_unexpected_write_nmb_state *state;
+	struct tevent_req *req;
+	enum ndr_err_code ndr_err;
+	DATA_BLOB blob;
+
+	state = talloc(client, struct nbtd_unexpected_write_nmb_state);
+	if (state == NULL) {
+		return;
+	}
+	state->hdr = (struct nb_packet_client_header) {
+		.type = NMB_PACKET, .timestamp = time(NULL), .ip = from
+	};
+
+	ndr_err = ndr_push_struct_blob(
+		&blob, state, packet,
+		(ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		talloc_free(state);
+		return;
+	}
+	state->hdr.len = blob.length;
+
+	state->iov[0] = (struct iovec) {
+		.iov_base = &state->hdr, .iov_len = sizeof(state->hdr)
+	};
+	state->iov[1] = (struct iovec) {
+		.iov_base = blob.data, .iov_len = blob.length
+	};
+
+	req = tstream_writev_queue_send(
+		state, client->server->nbtd->task->event_ctx,
+		client->sock, client->out_queue,
+		state->iov, ARRAY_SIZE(state->iov));
+	if (req == NULL) {
+		TALLOC_FREE(state);
+		return;
+	}
+	tevent_req_set_callback(req, nbtd_unexpected_write_nmb_written, state);
+}
+
+static void nbtd_unexpected_write_nmb_written(struct tevent_req *req)
+{
+	struct nbtd_unexpected_write_nmb_state *state =
+		tevent_req_callback_data(
+			req, struct nbtd_unexpected_write_nmb_state);
+	TALLOC_FREE(state);
+}
+
+static void nbtd_unexpected_sent_nmb(struct nbt_name_request *req)
+{
+	struct nbtd_unexpected_client *client = talloc_get_type_abort(
+		req->async.private_data, struct nbtd_unexpected_client);
+	unsigned int i;
+
+	for (i=0; i<req->num_replies; i++) {
+		struct nbt_name_reply *reply = &req->replies[i];
+		struct socket_address *from = reply->dest;
+		struct sockaddr_in *from_in;
+
+		if ((from->sockaddr == NULL) ||
+		    (from->sockaddrlen != sizeof(struct sockaddr_in))) {
+			continue;
+		}
+		from_in = (struct sockaddr_in *)from->sockaddr;
+
+		nbtd_unexpected_write_nmb(client, from_in->sin_addr,
+					  reply->packet);
+	}
+
+	TALLOC_FREE(req);
+}
+
+static bool nbtd_unexpected_handle_local_dgm(
+	struct nbtd_server *srv,
+	struct nbtd_unexpected_client *client,
+	struct nbtd_interface *interface,
+	struct nb_packet_client_header *hdr,
+	struct nbt_dgram_packet *packet);
+
+static void nbtd_unexpected_handle_dgm(struct nbtd_server *srv,
+				       struct nbtd_unexpected_client *client,
+				       struct nb_packet_client_header *hdr,
+				       struct nbt_dgram_packet *packet)
+{
+	struct nbtd_interface *interface;
+	char addr[INET_ADDRSTRLEN];
+	struct socket_address *dest;
+	NTSTATUS status;
+	bool ok;
+
+	inet_ntop(AF_INET, &client->hdr.ip, addr, sizeof(addr));
+
+	interface = nbtd_find_request_iface(client->server->nbtd,
+					    addr, true);
+	if (interface == NULL) {
+		DBG_DEBUG("Failed to find iface for %s\n", addr);
+		return;
+	}
+
+	ok = nbtd_unexpected_handle_local_dgm(srv, client, interface, hdr,
+					      packet);
+	if (ok) {
+		DBG_DEBUG("Packet for %s handled locally\n", addr);
+		return;
+	}
+
+	dest = socket_address_from_strings(
+		packet, "ip", addr, NBT_DGRAM_SERVICE_PORT);
+	if (dest == NULL) {
+		DBG_DEBUG("socket_address_from_strings for %s "
+			  "failed\n", addr);
+		return;
+	}
+
+	status = nbt_dgram_send(interface->dgmsock, packet, dest);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("nbt_dgram_send to %s failed: %s\n", addr,
+			  nt_errstr(status));
+		return;
+	}
+}
+
+static bool nbtd_unexpected_handle_local_dgm(
+	struct nbtd_server *srv,
+	struct nbtd_unexpected_client *client,
+	struct nbtd_interface *interface,
+	struct nb_packet_client_header *hdr,
+	struct nbt_dgram_packet *packet)
+{
+	struct dgram_message *msg;
+	struct nbtd_iface_name *iname;
+	struct socket_address *src;
+	struct nbt_netlogon_response *reply = NULL;
+	DATA_BLOB reply_blob;
+	struct nbt_dgram_packet *reply_packet;
+	char *reply_mailslot = NULL;
+	struct in_addr from;
+	NTSTATUS status;
+	int ret;
+
+	ret = inet_pton(AF_INET, interface->ip_address, &from);
+	if (ret != 1) {
+		DBG_DEBUG("inet_pton failed\n");
+		return false;
+	}
+
+	if (packet->msg_type != DGRAM_DIRECT_GROUP) {
+		DBG_DEBUG("packet->msg_type = %d\n", (int)packet->msg_type);
+		return false;
+	}
+
+	msg = &packet->data.msg;
+
+	iname = nbtd_find_iname(interface, &msg->dest_name, 0);
+	if (iname == NULL) {
+		DBG_DEBUG("Local name %s not found\n", msg->dest_name.name);
+		return false;
+	}
+
+	DBG_DEBUG("Found Interface address %s\n", interface->ip_address);
+
+	src = socket_address_from_strings(packet,
+					  "ip",
+					  interface->ip_address,
+					  NBT_DGRAM_SERVICE_PORT);
+	if (src == NULL) {
+		DBG_DEBUG("socket_address_from_strings failed\n");
+		return false;
+	}
+
+	status = nbtd_mailslot_netlogon_reply(interface,
+					      packet,
+					      src,
+					      packet,
+					      &reply,
+					      &reply_mailslot);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("nbtd_mailslot_netlogon_reply failed: %s\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	DBG_DEBUG("Sending reply to mailslot %s\n", reply_mailslot);
+
+	status = push_nbt_netlogon_response(&reply_blob, packet, reply);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("push_nbt_netlogon_response failed: %s\n",
+			  nt_errstr(status));
+		return false;
+	}
+
+	reply_packet = dgram_mailslot_init(packet,
+					   DGRAM_DIRECT_UNIQUE,
+					   &msg->dest_name,
+					   interface->ip_address,
+					   &msg->source_name,
+					   reply_mailslot,
+					   &reply_blob);
+	if (reply_packet == NULL) {
+		DBG_DEBUG("dgram_mailslot_init failed\n");
+		return false;
+	}
+
+	if (DEBUGLEVEL >= 10) {
+		NDR_PRINT_DEBUG(nbt_dgram_packet, reply_packet);
+	}
+
+	nbtd_unexpected_write_dgm(client, from, reply_packet);
+
+	return true;
+}
diff --git a/source4/nbt_server/wscript_build b/source4/nbt_server/wscript_build
index 632d5fbe41d..45e972c6bc0 100644
--- a/source4/nbt_server/wscript_build
+++ b/source4/nbt_server/wscript_build
@@ -43,6 +43,7 @@ bld.SAMBA_SUBSYSTEM('NBT_SERVER',
             nodestatus.c
             defense.c
             packet.c
+            unexpected_pipe.c
             irpc.c''',
 	autoproto='nbt_server_proto.h',
 	deps='cli-nbt NBTD_WINS NBTD_DGRAM service',
-- 
2.11.0


From afb54a7de4d359fd8b6c2fd98650e6a2534d8eae Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 22:02:16 +0100
Subject: [PATCH 14/32] libsmb: Add nb_packet_write_send/recv

This is the client end of the packet proxy into nmbd
---
 source3/libsmb/unexpected.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
 source3/libsmb/unexpected.h |  5 ++++
 2 files changed, 73 insertions(+)

diff --git a/source3/libsmb/unexpected.c b/source3/libsmb/unexpected.c
index 6d7a8452073..3283a0b6e77 100644
--- a/source3/libsmb/unexpected.c
+++ b/source3/libsmb/unexpected.c
@@ -503,6 +503,7 @@ static void nb_packet_client_send_done(struct tevent_req *req)
 
 struct nb_packet_reader {
 	struct tstream_context *sock;
+	struct tevent_queue *out_queue;
 };
 
 struct nb_packet_reader_state {
@@ -549,6 +550,12 @@ struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	state->reader->out_queue = tevent_queue_create(
+		state->reader, "nb_packet_reader send queue");
+	if (tevent_req_nomem(state->reader->out_queue, req)) {
+		return tevent_req_post(req, ev);
+	}
+
 	ret = tsocket_address_unix_from_path(state, NULL, &laddr);
 	if (ret != 0) {
 		tevent_req_nterror(req, map_nt_error_from_unix(errno));
@@ -829,3 +836,64 @@ NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	*ppacket = talloc_move(mem_ctx, &state->pkt);
 	return NT_STATUS_OK;
 }
+
+struct nb_packet_write_state {
+	struct iovec iov[2];
+	struct nb_packet_client_header hdr;
+	char buf[1024];
+};
+
+static void nb_packet_write_done(struct tevent_req *subreq);
+
+struct tevent_req *nb_packet_write_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct nb_packet_reader *reader,
+					struct packet_struct *packet)
+{
+	struct tevent_req *req, *subreq;
+	struct nb_packet_write_state *state;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct nb_packet_write_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->hdr.ip = packet->ip;
+	state->hdr.port = packet->port;
+	state->hdr.timestamp = packet->timestamp;
+	state->hdr.type = packet->packet_type;
+	state->hdr.len = build_packet(state->buf, sizeof(state->buf), packet);
+
+	state->iov[0].iov_base = (char *)&state->hdr;
+	state->iov[0].iov_len = sizeof(state->hdr);
+	state->iov[1].iov_base = state->buf;
+	state->iov[1].iov_len = state->hdr.len;
+
+	subreq = tstream_writev_queue_send(state, ev, reader->sock,
+					   reader->out_queue, state->iov, 2);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(req, nb_packet_write_done, state);
+	return req;
+}
+
+static void nb_packet_write_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	int ret, err;
+
+	ret = tstream_writev_queue_recv(subreq, &err);
+	TALLOC_FREE(subreq);
+	if (ret == -1) {
+		tevent_req_nterror(req, map_nt_error_from_unix_common(err));
+		return;
+	}
+	tevent_req_done(req);
+}
+
+NTSTATUS nb_packet_write_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
diff --git a/source3/libsmb/unexpected.h b/source3/libsmb/unexpected.h
index b06b8763549..cd0a1058cba 100644
--- a/source3/libsmb/unexpected.h
+++ b/source3/libsmb/unexpected.h
@@ -48,5 +48,10 @@ struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
 				       struct nb_packet_reader *reader);
 NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 			     struct packet_struct **ppacket);
+struct tevent_req *nb_packet_write_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct nb_packet_reader *reader,
+					struct packet_struct *packet);
+NTSTATUS nb_packet_write_recv(struct tevent_req *req);
 
 #endif
-- 
2.11.0


From 27754af0861c4895f8261dbd2a368620cbd9009c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 20 Jan 2018 09:31:15 +0000
Subject: [PATCH 15/32] libsmb: Add nb_call_send/recv

This wraps connecting to the "unexpected" nmbd pipe, sending and re-sending a
packet and listening for replies.

The difference to nb_trans_send_recv is that we hand a packet_struct down, so
that we don't have to do the build_packet in the caller.
---
 source3/libsmb/nb_call.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++
 source3/libsmb/nb_call.h |  39 +++++++++
 source3/wscript_build    |   1 +
 3 files changed, 241 insertions(+)
 create mode 100644 source3/libsmb/nb_call.c
 create mode 100644 source3/libsmb/nb_call.h

diff --git a/source3/libsmb/nb_call.c b/source3/libsmb/nb_call.c
new file mode 100644
index 00000000000..ba229082ff5
--- /dev/null
+++ b/source3/libsmb/nb_call.c
@@ -0,0 +1,201 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  Do a NetBIOS call via nmbd
+ *  Copyright (C) Volker Lendecke 2018
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include <tevent.h>
+#include "libsmb/nb_call.h"
+#include "nameserv.h"
+#include "libsmb/unexpected.h"
+#include "lib/util/tevent_ntstatus.h"
+
+struct nb_call_state {
+	struct tevent_context *ev;
+	struct nb_packet_reader *reader;
+
+	struct packet_struct *pkt;
+	bool (*validator)(struct packet_struct *p, void *private_data);
+	void *private_data;
+
+	struct packet_struct *result;
+};
+
+static void nb_call_got_reader(struct tevent_req *subreq);
+static void nb_call_got_pkt(struct tevent_req *subreq);
+static void nb_call_written(struct tevent_req *subreq);
+static void nb_call_resend(struct tevent_req *subreq);
+
+struct tevent_req *nb_call_send(TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct packet_struct *pkt,
+				int trn_id, const char *mailslot_name,
+				bool (*validator)(struct packet_struct *p,
+						  void *private_data),
+				void *private_data)
+{
+	struct tevent_req *req, *subreq;
+	struct nb_call_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct nb_call_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->pkt = pkt;
+	state->validator = validator;
+	state->private_data = private_data;
+
+	subreq = nb_packet_reader_send(state, ev, pkt->packet_type,
+				       trn_id, mailslot_name);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, nb_call_got_reader, req);
+	return req;
+}
+
+static void nb_call_got_reader(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct nb_call_state *state = tevent_req_data(
+		req, struct nb_call_state);
+	NTSTATUS status;
+
+	status = nb_packet_reader_recv(subreq, state, &state->reader);
+	TALLOC_FREE(subreq);
+
+	if (NT_STATUS_EQUAL(NT_STATUS_CONNECTION_REFUSED, status)) {
+		/*
+		 * At a higher level this might be seen as a network
+		 * error. Use a more specific error message for "nmbd
+		 * not around".
+		 */
+		status = NT_STATUS_PIPE_NOT_AVAILABLE;
+	}
+
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	subreq = nb_packet_read_send(state, state->ev, state->reader);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, nb_call_got_pkt, req);
+
+	subreq = nb_packet_write_send(state, state->ev, state->reader,
+				      state->pkt);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, nb_call_written, req);
+}
+
+static void nb_call_got_pkt(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct nb_call_state *state = tevent_req_data(
+		req, struct nb_call_state);
+	NTSTATUS status;
+	bool done = true;
+
+	status = nb_packet_read_recv(subreq, state, &state->result);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	if (state->validator != NULL) {
+		done = state->validator(state->result, state->private_data);
+	}
+
+	if (done) {
+		tevent_req_done(req);
+		return;
+	}
+
+	subreq = nb_packet_read_send(state, state->ev, state->reader);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, nb_call_got_pkt, req);
+}
+
+static void nb_call_written(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct nb_call_state *state = tevent_req_data(
+		req, struct nb_call_state);
+	NTSTATUS status;
+
+	status = nb_packet_write_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	subreq = tevent_wakeup_send(state, state->ev,
+				    timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, nb_call_resend, req);
+}
+
+static void nb_call_resend(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct nb_call_state *state = tevent_req_data(
+		req, struct nb_call_state);
+	bool ret;
+
+	ret = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+
+	subreq = nb_packet_write_send(state, state->ev, state->reader,
+				      state->pkt);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, nb_call_written, req);
+}
+
+NTSTATUS nb_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		      struct packet_struct **ppacket)
+{
+	struct nb_call_state *state = tevent_req_data(
+		req, struct nb_call_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	if (ppacket != NULL) {
+		*ppacket = talloc_move(mem_ctx, &state->result);
+	}
+	tevent_req_received(req);
+	return NT_STATUS_OK;
+}
diff --git a/source3/libsmb/nb_call.h b/source3/libsmb/nb_call.h
new file mode 100644
index 00000000000..e38451a1aa6
--- /dev/null
+++ b/source3/libsmb/nb_call.h
@@ -0,0 +1,39 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  Do a NetBIOS call via nmbd
+ *  Copyright (C) Volker Lendecke 2018
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMB_NB_CALL_H__
+#define __LIBSMB_NB_CALL_H__
+
+#include "replace.h"
+#include <tevent.h>
+#include "libcli/util/ntstatus.h"
+
+struct packet_struct;
+
+struct tevent_req *nb_call_send(TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct packet_struct *pkt,
+				int trn_id, const char *mailslot_name,
+				bool (*validator)(struct packet_struct *p,
+						  void *private_data),
+				void *private_data);
+NTSTATUS nb_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+		      struct packet_struct **ppacket);
+
+#endif
diff --git a/source3/wscript_build b/source3/wscript_build
index ed9ed24fae2..4debf7f845a 100644
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -875,6 +875,7 @@ bld.SAMBA3_SUBSYSTEM('LIBNMB',
                             libsmb/nmblib.c
                             libsmb/namequery.c
                             libsmb/conncache.c
+                            libsmb/nb_call.c
                             libads/sitename_cache.c
                             ''',
                      deps='''
-- 
2.11.0


From 7d29d1d9c1622f7aa17903b77f5f16d5e3569b2b Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 22:11:00 +0100
Subject: [PATCH 16/32] libsmb: Use nb_call_send/recv in clidgram

This was the one user of the messaging_send proxy mechanism via
nmbd. This has to come from port 137, so it was required to go via the
daemon.
---
 source3/libsmb/clidgram.c | 68 +++++++++++++----------------------------------
 1 file changed, 19 insertions(+), 49 deletions(-)

diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
index 4ae57a30d33..34eb9720d86 100644
--- a/source3/libsmb/clidgram.c
+++ b/source3/libsmb/clidgram.c
@@ -24,7 +24,7 @@
 #include "../lib/util/tevent_ntstatus.h"
 #include "libsmb/clidgram.h"
 #include "libsmb/nmblib.h"
-#include "libsmb/unexpected.h"
+#include "libsmb/nb_call.h"
 #include "messages.h"
 #include "librpc/gen_ndr/samr.h"
 #include "../lib/util/pidfile.h"
@@ -294,8 +294,9 @@ struct nbt_getdc_state {
 	struct packet_struct p;
 };
 
-static void nbt_getdc_got_reader(struct tevent_req *subreq);
-static void nbt_getdc_got_response(struct tevent_req *subreq);
+static void nbt_getdc_done(struct tevent_req *subreq);
+static bool nbt_getdc_validator(struct packet_struct *pkt,
+				void *private_data);
 
 struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 				  struct tevent_context *ev,
@@ -346,70 +347,39 @@ struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	subreq = nb_packet_reader_send(state, ev, DGRAM_PACKET, -1,
-				       state->my_mailslot);
+	subreq = nb_call_send(state, ev, &state->p, 0, state->my_mailslot,
+			      nbt_getdc_validator, state);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, nbt_getdc_got_reader, req);
+	tevent_req_set_callback(subreq, nbt_getdc_done, req);
 	return req;
 }
 
-static void nbt_getdc_got_reader(struct tevent_req *subreq)
+static bool nbt_getdc_validator(struct packet_struct *pkt,
+				void *private_data)
 {
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct nbt_getdc_state *state = tevent_req_data(
-		req, struct nbt_getdc_state);
-	NTSTATUS status;
-
-	status = nb_packet_reader_recv(subreq, state, &state->reader);
-	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, status)) {
-		DEBUG(10, ("nb_packet_reader_recv returned %s\n",
-			   nt_errstr(status)));
-		return;
-	}
-
-	status = messaging_send_buf(
-		state->msg_ctx, pid_to_procid(state->nmbd_pid),
-		MSG_SEND_PACKET, (uint8_t *)&state->p, sizeof(state->p));
-
-	if (tevent_req_nterror(req, status)) {
-		DEBUG(10, ("messaging_send_buf returned %s\n",
-			   nt_errstr(status)));
-		return;
-	}
-	subreq = nb_packet_read_send(state, state->ev, state->reader);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, nbt_getdc_got_response, req);
+	struct nbt_getdc_state *state = talloc_get_type_abort(
+		private_data, struct nbt_getdc_state);
+	bool ok;
+
+	ok = parse_getdc_response(pkt, state, state->domain_name,
+				  &state->nt_version, &state->dc_name,
+				  &state->samlogon_response);
+	return ok;
 }
 
-static void nbt_getdc_got_response(struct tevent_req *subreq)
+static void nbt_getdc_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
 		subreq, struct tevent_req);
-	struct nbt_getdc_state *state = tevent_req_data(
-		req, struct nbt_getdc_state);
-	struct packet_struct *p;
 	NTSTATUS status;
-	bool ret;
 
-	status = nb_packet_read_recv(subreq, state, &p);
+	status = nb_call_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
-
-	ret = parse_getdc_response(p, state, state->domain_name,
-				   &state->nt_version, &state->dc_name,
-				   &state->samlogon_response);
-	if (!ret) {
-		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
-		return;
-	}
 	tevent_req_done(req);
 }
 
-- 
2.11.0


From d62ee7aef9ea549e783124d61a16a09b2059ecbc Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 22:15:33 +0100
Subject: [PATCH 17/32] smbcontrol: Remove the "nodestatus" command

This was only a pure test command that did not fulfill any sensible
purpose. It did not wait for a reply at all. It wasn't documented in
smbcontrol.1 either.
---
 source3/utils/smbcontrol.c | 50 ----------------------------------------------
 1 file changed, 50 deletions(-)

diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index bd89b9ebf0a..aacc5fadd6a 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -1310,55 +1310,6 @@ static bool do_reload_printers(struct tevent_context *ev_ctx,
 	return send_message(msg_ctx, pid, MSG_PRINTER_PCAP, NULL, 0);
 }
 
-static void my_make_nmb_name( struct nmb_name *n, const char *name, int type)
-{
-	fstring unix_name;
-	memset( (char *)n, '\0', sizeof(struct nmb_name) );
-	fstrcpy(unix_name, name);
-	(void)strupper_m(unix_name);
-	push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
-	n->name_type = (unsigned int)type & 0xFF;
-	push_ascii(n->scope,  lp_netbios_scope(), 64, STR_TERMINATE);
-}
-
-static bool do_nodestatus(struct tevent_context *ev_ctx,
-			  struct messaging_context *msg_ctx,
-			  const struct server_id pid,
-			  const int argc, const char **argv)
-{
-	struct packet_struct p;
-
-	if (argc != 2) {
-		fprintf(stderr, "Usage: smbcontrol nmbd nodestatus <ip>\n");
-		return False;
-	}
-
-	ZERO_STRUCT(p);
-
-	p.ip = interpret_addr2(argv[1]);
-	p.port = 137;
-	p.packet_type = NMB_PACKET;
-
-	p.packet.nmb.header.name_trn_id = 10;
-	p.packet.nmb.header.opcode = 0;
-	p.packet.nmb.header.response = False;
-	p.packet.nmb.header.nm_flags.bcast = False;
-	p.packet.nmb.header.nm_flags.recursion_available = False;
-	p.packet.nmb.header.nm_flags.recursion_desired = False;
-	p.packet.nmb.header.nm_flags.trunc = False;
-	p.packet.nmb.header.nm_flags.authoritative = False;
-	p.packet.nmb.header.rcode = 0;
-	p.packet.nmb.header.qdcount = 1;
-	p.packet.nmb.header.ancount = 0;
-	p.packet.nmb.header.nscount = 0;
-	p.packet.nmb.header.arcount = 0;
-	my_make_nmb_name(&p.packet.nmb.question.question_name, "*", 0x00);
-	p.packet.nmb.question.question_type = 0x21;
-	p.packet.nmb.question.question_class = 0x1;
-
-	return send_message(msg_ctx, pid, MSG_SEND_PACKET, &p, sizeof(p));
-}
-
 static bool do_notify_cleanup(struct tevent_context *ev_ctx,
 			      struct messaging_context *msg_ctx,
 			      const struct server_id pid,
@@ -1408,7 +1359,6 @@ static const struct {
 	{ "drvupgrade", do_drvupgrade, "Notify a printer driver has changed" },
 	{ "reload-config", do_reload_config, "Force smbd or winbindd to reload config file"},
 	{ "reload-printers", do_reload_printers, "Force smbd to reload printers"},
-	{ "nodestatus", do_nodestatus, "Ask nmbd to do a node status request"},
 	{ "online", do_winbind_online, "Ask winbind to go into online state"},
 	{ "offline", do_winbind_offline, "Ask winbind to go into offline state"},
 	{ "onlinestatus", do_winbind_onlinestatus, "Request winbind online status"},
-- 
2.11.0


From ffacb55fa8ad868b20d1142bed08e21a283f36c8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 23 Jan 2018 22:19:27 +0100
Subject: [PATCH 18/32] nmbd: Remove MSG_SEND_PACKET

---
 librpc/idl/messaging.idl |  1 -
 source3/nmbd/nmbd.c      | 63 ------------------------------------------------
 2 files changed, 64 deletions(-)

diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index 14a6f92d583..4d029a9f9a3 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -51,7 +51,6 @@ interface messaging
 		/* nmbd messages */
 		MSG_FORCE_ELECTION		= 0x0101,
 		MSG_WINS_NEW_ENTRY		= 0x0102,
-		MSG_SEND_PACKET			= 0x0103,
 
 		/* printing messages */
 		/* MSG_PRINTER_NOTIFY		= 0x2001,  Obsoleted */
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index 9be708a9c02..62f0c277db2 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -436,67 +436,6 @@ static void msg_reload_nmbd_services(struct messaging_context *msg,
 	reload_interfaces(0);
 }
 
-static void msg_nmbd_send_packet(struct messaging_context *msg,
-				 void *private_data,
-				 uint32_t msg_type,
-				 struct server_id src,
-				 DATA_BLOB *data)
-{
-	struct packet_struct *p = (struct packet_struct *)data->data;
-	struct subnet_record *subrec;
-	struct sockaddr_storage ss;
-	const struct sockaddr_storage *pss;
-	const struct in_addr *local_ip;
-
-	DEBUG(10, ("Received send_packet from %u\n", (unsigned int)procid_to_pid(&src)));
-
-	if (data->length != sizeof(struct packet_struct)) {
-		DEBUG(2, ("Discarding invalid packet length from %u\n",
-			  (unsigned int)procid_to_pid(&src)));
-		return;
-	}
-
-	if ((p->packet_type != NMB_PACKET) &&
-	    (p->packet_type != DGRAM_PACKET)) {
-		DEBUG(2, ("Discarding invalid packet type from %u: %d\n",
-			  (unsigned int)procid_to_pid(&src), p->packet_type));
-		return;
-	}
-
-	in_addr_to_sockaddr_storage(&ss, p->ip);
-	pss = iface_ip((struct sockaddr *)(void *)&ss);
-
-	if (pss == NULL) {
-		DEBUG(2, ("Could not find ip for packet from %u\n",
-			  (unsigned int)procid_to_pid(&src)));
-		return;
-	}
-
-	local_ip = &((const struct sockaddr_in *)pss)->sin_addr;
-	subrec = FIRST_SUBNET;
-
-	p->recv_fd = -1;
-	p->send_fd = (p->packet_type == NMB_PACKET) ?
-		subrec->nmb_sock : subrec->dgram_sock;
-
-	for (subrec = FIRST_SUBNET; subrec != NULL;
-	     subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
-		if (ip_equal_v4(*local_ip, subrec->myip)) {
-			p->send_fd = (p->packet_type == NMB_PACKET) ?
-				subrec->nmb_sock : subrec->dgram_sock;
-			break;
-		}
-	}
-
-	if (p->packet_type == DGRAM_PACKET) {
-		p->port = 138;
-		p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
-		p->packet.dgram.header.source_port = 138;
-	}
-
-	send_packet(p);
-}
-
 /**************************************************************************** **
  The main select loop.
  **************************************************************************** */
@@ -1025,8 +964,6 @@ static bool open_sockets(bool isdaemon, int port)
 			   nmbd_terminate);
 	messaging_register(msg, NULL, MSG_SMB_CONF_UPDATED,
 			   msg_reload_nmbd_services);
-	messaging_register(msg, NULL, MSG_SEND_PACKET,
-			   msg_nmbd_send_packet);
 
 	TimeInit();
 
-- 
2.11.0


From a511f99f4c4b45f7f5f2076a64658949336c0da9 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 24 Jan 2018 11:05:43 +0100
Subject: [PATCH 19/32] libsmb: Remove the "msg_ctx" from nbt_getdc

This was needed for injecting packets into nmbd for sending
---
 source3/libsmb/clidgram.c      | 9 ++-------
 source3/libsmb/clidgram.h      | 4 +---
 source3/libsmb/dsgetdcname.c   | 2 +-
 source3/winbindd/winbindd_cm.c | 2 +-
 4 files changed, 5 insertions(+), 12 deletions(-)

diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
index 34eb9720d86..8d33ee1719a 100644
--- a/source3/libsmb/clidgram.c
+++ b/source3/libsmb/clidgram.c
@@ -279,7 +279,6 @@ static bool parse_getdc_response(
 
 struct nbt_getdc_state {
 	struct tevent_context *ev;
-	struct messaging_context *msg_ctx;
 	struct nb_packet_reader *reader;
 	const char *my_mailslot;
 	pid_t nmbd_pid;
@@ -300,7 +299,6 @@ static bool nbt_getdc_validator(struct packet_struct *pkt,
 
 struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 				  struct tevent_context *ev,
-				  struct messaging_context *msg_ctx,
 				  const struct sockaddr_storage *dc_addr,
 				  const char *domain_name,
 				  const struct dom_sid *sid,
@@ -315,7 +313,6 @@ struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 	state->ev = ev;
-	state->msg_ctx = msg_ctx;
 	state->dc_addr = dc_addr;
 	state->domain_name = domain_name;
 	state->sid = sid;
@@ -407,8 +404,7 @@ NTSTATUS nbt_getdc_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
-NTSTATUS nbt_getdc(struct messaging_context *msg_ctx,
-		   uint32_t timeout_in_seconds,
+NTSTATUS nbt_getdc(uint32_t timeout_in_seconds,
 		   const struct sockaddr_storage *dc_addr,
 		   const char *domain_name,
 		   const struct dom_sid *sid,
@@ -427,8 +423,7 @@ NTSTATUS nbt_getdc(struct messaging_context *msg_ctx,
 	if (ev == NULL) {
 		goto fail;
 	}
-	req = nbt_getdc_send(ev, ev, msg_ctx, dc_addr, domain_name,
-			     sid, nt_version);
+	req = nbt_getdc_send(ev, ev, dc_addr, domain_name, sid, nt_version);
 	if (req == NULL) {
 		goto fail;
 	}
diff --git a/source3/libsmb/clidgram.h b/source3/libsmb/clidgram.h
index 6cd6222df68..a80d5a5ad72 100644
--- a/source3/libsmb/clidgram.h
+++ b/source3/libsmb/clidgram.h
@@ -28,7 +28,6 @@
 
 struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 				  struct tevent_context *ev,
-				  struct messaging_context *msg_ctx,
 				  const struct sockaddr_storage *dc_addr,
 				  const char *domain_name,
 				  const struct dom_sid *sid,
@@ -36,8 +35,7 @@ struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 NTSTATUS nbt_getdc_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 			uint32_t *nt_version, const char **dc_name,
 			struct netlogon_samlogon_response **samlogon_response);
-NTSTATUS nbt_getdc(struct messaging_context *msg_ctx,
-		   uint32_t timeout_in_seconds,
+NTSTATUS nbt_getdc(uint32_t timeout_in_seconds,
 		   const struct sockaddr_storage *dc_addr,
 		   const char *domain_name,
 		   const struct dom_sid *sid,
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index a7fe5a1e748..31326c9fe13 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -934,7 +934,7 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
 			return NT_STATUS_UNSUCCESSFUL;
 		}
 
-		status = nbt_getdc(msg_ctx, 10, &dclist[i].ss, domain_name,
+		status = nbt_getdc(10, &dclist[i].ss, domain_name,
 				   NULL, nt_version,
 				   mem_ctx, &nt_version, &dc_name, &r);
 		if (NT_STATUS_IS_OK(status)) {
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index bf5a2b4d7b1..fdff8fe5baf 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -1465,7 +1465,7 @@ static bool dcip_check_name(TALLOC_CTX *mem_ctx,
 	}
 #endif
 
-	status = nbt_getdc(server_messaging_context(), 10, pss, domain->name,
+	status = nbt_getdc(10, pss, domain->name,
 			   &domain->sid, nt_version, mem_ctx, &nt_version,
 			   &dc_name, NULL);
 	if (NT_STATUS_IS_OK(status)) {
-- 
2.11.0


From 72fb21b29cda4c60f7196a359cd4811e60c19e47 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 24 Jan 2018 11:07:27 +0100
Subject: [PATCH 20/32] libsmb: "process_dc_netbios" doesn't need the msg_ctx
 anymore

---
 source3/libsmb/dsgetdcname.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index 31326c9fe13..6ea5957278d 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -890,7 +890,6 @@ static NTSTATUS process_dc_dns(TALLOC_CTX *mem_ctx,
 ****************************************************************/
 
 static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
-				   struct messaging_context *msg_ctx,
 				   const char *domain_name,
 				   uint32_t flags,
 				   struct ip_service_name *dclist,
@@ -910,10 +909,6 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
 			      NETLOGON_NT_VERSION_5 |
 			      NETLOGON_NT_VERSION_5EX_WITH_IP;
 
-	if (msg_ctx == NULL) {
-		return NT_STATUS_INVALID_PARAMETER;
-	}
-
 	if (flags & DS_PDC_REQUIRED) {
 		name_type = NBT_NAME_PDC;
 	}
@@ -1015,7 +1010,7 @@ static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
 					     &dclist, &num_dcs);
 		NT_STATUS_NOT_OK_RETURN(status);
 
-		return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags,
+		return process_dc_netbios(mem_ctx, domain_name, flags,
 					  dclist, num_dcs, info);
 	}
 
@@ -1049,7 +1044,7 @@ static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
 				     &num_dcs);
 	NT_STATUS_NOT_OK_RETURN(status);
 
-	return process_dc_netbios(mem_ctx, msg_ctx, domain_name, flags, dclist,
+	return process_dc_netbios(mem_ctx, domain_name, flags, dclist,
 				  num_dcs, info);
 }
 
-- 
2.11.0


From d924b30033d65b3e84d340118f24feb818a4f5cb Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 24 Jan 2018 11:08:56 +0100
Subject: [PATCH 21/32] libsmb: "dsgetdcname_rediscover" doesn't need "msg_ctx"
 anymore

---
 source3/libsmb/dsgetdcname.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index 6ea5957278d..855a9518e76 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -987,7 +987,6 @@ static NTSTATUS process_dc_netbios(TALLOC_CTX *mem_ctx,
 ****************************************************************/
 
 static NTSTATUS dsgetdcname_rediscover(TALLOC_CTX *mem_ctx,
-				       struct messaging_context *msg_ctx,
 				       const char *domain_name,
 				       const struct GUID *domain_guid,
 				       uint32_t flags,
@@ -1114,7 +1113,7 @@ static NTSTATUS dsgetdcname_internal(TALLOC_CTX *mem_ctx,
 	}
 
  rediscover:
-	status = dsgetdcname_rediscover(mem_ctx, msg_ctx, domain_name,
+	status = dsgetdcname_rediscover(mem_ctx, domain_name,
 					domain_guid, flags, site_name,
 					&myinfo);
 
-- 
2.11.0


From edd578cde6669fec63a3e25cc0bd9ead1737c6ac Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 24 Jan 2018 11:18:25 +0100
Subject: [PATCH 22/32] libsmb: "dsgetcname" doesn't need "msg_ctx" anymore

---
 source3/include/proto.h                     |  1 -
 source3/lib/netapi/getdc.c                  |  5 -----
 source3/lib/netapi/joindomain.c             | 18 +++---------------
 source3/libnet/libnet_join.c                |  2 --
 source3/libsmb/dsgetdcname.c                |  9 ++-------
 source3/rpc_server/netlogon/srv_netlog_nt.c |  4 +---
 source3/utils/net_lookup.c                  |  2 +-
 source3/utils/net_rpc.c                     |  1 -
 source3/winbindd/winbindd_dual_srv.c        |  2 +-
 9 files changed, 8 insertions(+), 36 deletions(-)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index fa87407ff24..21225bf0104 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -681,7 +681,6 @@ void flush_negative_conn_cache_for_domain(const char *domain);
 struct netr_DsRGetDCNameInfo;
 
 NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
-		     struct messaging_context *msg_ctx,
 		     const char *domain_name,
 		     const struct GUID *domain_guid,
 		     const char *site_name,
diff --git a/source3/lib/netapi/getdc.c b/source3/lib/netapi/getdc.c
index 2d47ee45840..ad95e60bbcd 100644
--- a/source3/lib/netapi/getdc.c
+++ b/source3/lib/netapi/getdc.c
@@ -141,13 +141,8 @@ WERROR DsGetDcName_l(struct libnetapi_ctx *ctx,
 		     struct DsGetDcName *r)
 {
 	NTSTATUS status;
-	struct libnetapi_private_ctx *priv;
-
-	priv = talloc_get_type_abort(ctx->private_data,
-		struct libnetapi_private_ctx);
 
 	status = dsgetdcname(ctx,
-			     priv->msg_ctx,
 			     r->in.domain_name,
 			     r->in.domain_guid,
 			     r->in.site_name,
diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c
index 7d27bd9d0fe..a096e594a8b 100644
--- a/source3/lib/netapi/joindomain.c
+++ b/source3/lib/netapi/joindomain.c
@@ -37,12 +37,8 @@ WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
 		       struct NetJoinDomain *r)
 {
 	struct libnet_JoinCtx *j = NULL;
-	struct libnetapi_private_ctx *priv;
 	WERROR werr;
 
-	priv = talloc_get_type_abort(mem_ctx->private_data,
-		struct libnetapi_private_ctx);
-
 	if (!r->in.domain) {
 		return WERR_INVALID_PARAMETER;
 	}
@@ -60,7 +56,7 @@ WERROR NetJoinDomain_l(struct libnetapi_ctx *mem_ctx,
 		uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
 				 DS_WRITABLE_REQUIRED |
 				 DS_RETURN_DNS_NAME;
-		status = dsgetdcname(mem_ctx, priv->msg_ctx, r->in.domain,
+		status = dsgetdcname(mem_ctx, r->in.domain,
 				     NULL, NULL, flags, &info);
 		if (!NT_STATUS_IS_OK(status)) {
 			libnetapi_set_error_string(mem_ctx,
@@ -174,12 +170,8 @@ WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
 	struct dom_sid domain_sid;
 	const char *domain = NULL;
 	WERROR werr;
-	struct libnetapi_private_ctx *priv;
 	const char *realm = lp_realm();
 
-	priv = talloc_get_type_abort(mem_ctx->private_data,
-		struct libnetapi_private_ctx);
-
 	if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
 		return WERR_NERR_SETUPNOTJOINED;
 	}
@@ -203,7 +195,7 @@ WERROR NetUnjoinDomain_l(struct libnetapi_ctx *mem_ctx,
 		uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
 				 DS_WRITABLE_REQUIRED |
 				 DS_RETURN_DNS_NAME;
-		status = dsgetdcname(mem_ctx, priv->msg_ctx, domain,
+		status = dsgetdcname(mem_ctx, domain,
 				     NULL, NULL, flags, &info);
 		if (!NT_STATUS_IS_OK(status)) {
 			libnetapi_set_error_string(mem_ctx,
@@ -393,14 +385,10 @@ WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx,
 	const char *dc = NULL;
 	uint32_t flags = DS_DIRECTORY_SERVICE_REQUIRED |
 			 DS_RETURN_DNS_NAME;
-	struct libnetapi_private_ctx *priv;
 	char **p;
 	size_t s;
 
-	priv = talloc_get_type_abort(ctx->private_data,
-		struct libnetapi_private_ctx);
-
-	status = dsgetdcname(ctx, priv->msg_ctx, r->in.domain,
+	status = dsgetdcname(ctx, r->in.domain,
 			     NULL, NULL, flags, &info);
 	if (!NT_STATUS_IS_OK(status)) {
 		libnetapi_set_error_string(ctx, "%s",
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 5db2ca09ccc..587dc874f7e 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -2540,7 +2540,6 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx,
 			name_type_flags = DS_IS_FLAT_NAME;
 		}
 		status = dsgetdcname(mem_ctx,
-				     r->in.msg_ctx,
 				     r->in.domain_name,
 				     NULL,
 				     NULL,
@@ -2801,7 +2800,6 @@ static WERROR libnet_DomainUnjoin(TALLOC_CTX *mem_ctx,
 		struct netr_DsRGetDCNameInfo *info;
 		const char *dc;
 		status = dsgetdcname(mem_ctx,
-				     r->in.msg_ctx,
 				     r->in.domain_name,
 				     NULL,
 				     NULL,
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index 855a9518e76..e68b0c031ac 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -348,7 +348,6 @@ static NTSTATUS dsgetdcname_cache_fetch(TALLOC_CTX *mem_ctx,
 ****************************************************************/
 
 static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
-				   struct messaging_context *msg_ctx,
 				   const char *domain_name,
 				   const struct GUID *domain_guid,
 				   uint32_t flags,
@@ -373,7 +372,7 @@ static NTSTATUS dsgetdcname_cached(TALLOC_CTX *mem_ctx,
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 		struct netr_DsRGetDCNameInfo *dc_info;
 
-		status = dsgetdcname(mem_ctx, msg_ctx, domain_name,
+		status = dsgetdcname(mem_ctx, domain_name,
 				     domain_guid, site_name,
 				     flags | DS_FORCE_REDISCOVERY,
 				     &dc_info);
@@ -1073,7 +1072,6 @@ static bool is_closest_site(struct netr_DsRGetDCNameInfo *info)
 ********************************************************************/
 
 static NTSTATUS dsgetdcname_internal(TALLOC_CTX *mem_ctx,
-		     struct messaging_context *msg_ctx,
 		     const char *domain_name,
 		     const struct GUID *domain_guid,
 		     const char *site_name,
@@ -1102,7 +1100,7 @@ static NTSTATUS dsgetdcname_internal(TALLOC_CTX *mem_ctx,
 		goto rediscover;
 	}
 
-	status = dsgetdcname_cached(mem_ctx, msg_ctx, domain_name, domain_guid,
+	status = dsgetdcname_cached(mem_ctx, domain_name, domain_guid,
 				    flags, site_name, &myinfo);
 	if (NT_STATUS_IS_OK(status)) {
 		goto done;
@@ -1147,7 +1145,6 @@ static NTSTATUS dsgetdcname_internal(TALLOC_CTX *mem_ctx,
 ********************************************************************/
 
 NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
-		     struct messaging_context *msg_ctx,
 		     const char *domain_name,
 		     const struct GUID *domain_guid,
 		     const char *site_name,
@@ -1170,7 +1167,6 @@ NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
 	}
 
 	status = dsgetdcname_internal(mem_ctx,
-				msg_ctx,
 				domain_name,
 				domain_guid,
 				query_site,
@@ -1186,7 +1182,6 @@ NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
 	/* Should we try again with site_name == NULL ? */
 	if (retry_query_with_null) {
 		status = dsgetdcname_internal(mem_ctx,
-					msg_ctx,
 					domain_name,
 					domain_guid,
 					NULL,
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index 83e68417c76..6227895b955 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -318,7 +318,7 @@ WERROR _netr_LogonControl2Ex(struct pipes_struct *p,
 			break;
 		}
 
-		status = dsgetdcname(p->mem_ctx, p->msg_ctx, domain, NULL, NULL,
+		status = dsgetdcname(p->mem_ctx, domain, NULL, NULL,
 				     DS_FORCE_REDISCOVERY | DS_RETURN_FLAT_NAME,
 				     &dc_info);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -2071,7 +2071,6 @@ WERROR _netr_GetDcName(struct pipes_struct *p,
 	flags = DS_PDC_REQUIRED | DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME;
 
 	status = dsgetdcname(p->mem_ctx,
-			     p->msg_ctx,
 			     r->in.domainname,
 			     NULL,
 			     NULL,
@@ -2116,7 +2115,6 @@ WERROR _netr_GetAnyDCName(struct pipes_struct *p,
 	flags = DS_IS_FLAT_NAME | DS_RETURN_FLAT_NAME;
 
 	status = dsgetdcname(p->mem_ctx,
-			     p->msg_ctx,
 			     r->in.domainname,
 			     NULL,
 			     NULL,
diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c
index 597e098e2e1..f8a5ac61ee8 100644
--- a/source3/utils/net_lookup.c
+++ b/source3/utils/net_lookup.c
@@ -423,7 +423,7 @@ static int net_lookup_dsgetdcname(struct net_context *c, int argc, const char **
 		return -1;
         }
 
-	status = dsgetdcname(mem_ctx, c->msg_ctx, domain_name, NULL, site_name,
+	status = dsgetdcname(mem_ctx, domain_name, NULL, site_name,
 			     flags, &info);
 	if (!NT_STATUS_IS_OK(status)) {
 		d_printf(_("failed with: %s\n"), nt_errstr(status));
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 8a989d790f2..11cc0c49849 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -497,7 +497,6 @@ int net_rpc_testjoin(struct net_context *c, int argc, const char **argv)
 		}
 
 		status = dsgetdcname(mem_ctx,
-				     c->msg_ctx,
 				     domain,
 				     NULL,
 				     NULL,
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 4cea73feaf9..481b29262d8 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -551,7 +551,7 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 	bool try_dsrgetdcname = false;
 
 	if (domain == NULL) {
-		return dsgetdcname(p->mem_ctx, server_messaging_context(),
+		return dsgetdcname(p->mem_ctx,
 				   r->in.domain_name, r->in.domain_guid,
 				   r->in.site_name ? r->in.site_name : "",
 				   r->in.flags,
-- 
2.11.0


From 64e3676e48d22ac93b84c1fb11f6bf5f3ae0f0f8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 5 Jan 2018 14:21:05 +0100
Subject: [PATCH 23/32] libsmb: Give dsgetdcname.c its own header

---
 source3/include/proto.h                     | 11 ---------
 source3/lib/netapi/getdc.c                  |  1 +
 source3/lib/netapi/joindomain.c             |  1 +
 source3/lib/netapi/serverinfo.c             |  1 +
 source3/libnet/libnet_join.c                |  1 +
 source3/libsmb/dsgetdcname.c                |  1 +
 source3/libsmb/dsgetdcname.h                | 36 +++++++++++++++++++++++++++++
 source3/rpc_server/netlogon/srv_netlog_nt.c |  1 +
 source3/utils/net_lookup.c                  |  1 +
 source3/utils/net_rpc.c                     |  1 +
 source3/winbindd/winbindd_dual_srv.c        |  1 +
 11 files changed, 45 insertions(+), 11 deletions(-)
 create mode 100644 source3/libsmb/dsgetdcname.h

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 21225bf0104..abdfdcc4bdd 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -676,17 +676,6 @@ NTSTATUS check_negative_conn_cache( const char *domain, const char *server);
 void add_failed_connection_entry(const char *domain, const char *server, NTSTATUS result) ;
 void flush_negative_conn_cache_for_domain(const char *domain);
 
-/* The following definitions come from libsmb/dsgetdcname.c  */
-
-struct netr_DsRGetDCNameInfo;
-
-NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
-		     const char *domain_name,
-		     const struct GUID *domain_guid,
-		     const char *site_name,
-		     uint32_t flags,
-		     struct netr_DsRGetDCNameInfo **info);
-
 /* The following definitions come from libsmb/errormap.c  */
 
 NTSTATUS dos_to_ntstatus(uint8_t eclass, uint32_t ecode);
diff --git a/source3/lib/netapi/getdc.c b/source3/lib/netapi/getdc.c
index ad95e60bbcd..3b837e79c82 100644
--- a/source3/lib/netapi/getdc.c
+++ b/source3/lib/netapi/getdc.c
@@ -24,6 +24,7 @@
 #include "lib/netapi/netapi.h"
 #include "lib/netapi/netapi_private.h"
 #include "lib/netapi/libnetapi.h"
+#include "libsmb/dsgetdcname.h"
 
 /********************************************************************
 ********************************************************************/
diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c
index a096e594a8b..e8ed19eef3e 100644
--- a/source3/lib/netapi/joindomain.c
+++ b/source3/lib/netapi/joindomain.c
@@ -29,6 +29,7 @@
 #include "../librpc/gen_ndr/ndr_wkssvc_c.h"
 #include "rpc_client/cli_pipe.h"
 #include "secrets.h"
+#include "libsmb/dsgetdcname.h"
 
 /****************************************************************
 ****************************************************************/
diff --git a/source3/lib/netapi/serverinfo.c b/source3/lib/netapi/serverinfo.c
index 2fd7668c682..7d9cc481c8c 100644
--- a/source3/lib/netapi/serverinfo.c
+++ b/source3/lib/netapi/serverinfo.c
@@ -26,6 +26,7 @@
 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
 #include "lib/smbconf/smbconf.h"
 #include "lib/smbconf/smbconf_reg.h"
+#include "libsmb/dsgetdcname.h"
 
 /****************************************************************
 ****************************************************************/
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 587dc874f7e..694a09db33d 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -43,6 +43,7 @@
 #include "libcli/auth/netlogon_creds_cli.h"
 #include "auth/credentials/credentials.h"
 #include "krb5_env.h"
+#include "libsmb/dsgetdcname.h"
 
 /****************************************************************
 ****************************************************************/
diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c
index e68b0c031ac..179222de64c 100644
--- a/source3/libsmb/dsgetdcname.c
+++ b/source3/libsmb/dsgetdcname.c
@@ -21,6 +21,7 @@
 */
 
 #include "includes.h"
+#include "libsmb/dsgetdcname.h"
 #include "libads/sitename_cache.h"
 #include "../librpc/gen_ndr/ndr_netlogon.h"
 #include "libads/cldap.h"
diff --git a/source3/libsmb/dsgetdcname.h b/source3/libsmb/dsgetdcname.h
new file mode 100644
index 00000000000..36948c2cb1e
--- /dev/null
+++ b/source3/libsmb/dsgetdcname.h
@@ -0,0 +1,36 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LIBSMB_DSGETDCNAME_H__
+#define __LIBSMB_DSGETDCNAME_H__
+
+#include "replace.h"
+#include <talloc.h>
+#include "source3/include/messages.h"
+#include "librpc/gen_ndr/misc.h"
+
+struct netr_DsRGetDCNameInfo;
+
+NTSTATUS dsgetdcname(TALLOC_CTX *mem_ctx,
+		     const char *domain_name,
+		     const struct GUID *domain_guid,
+		     const char *site_name,
+		     uint32_t flags,
+		     struct netr_DsRGetDCNameInfo **info);
+
+#endif
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index 6227895b955..c377e529cd1 100644
--- a/source3/rpc_server/netlogon/srv_netlog_nt.c
+++ b/source3/rpc_server/netlogon/srv_netlog_nt.c
@@ -47,6 +47,7 @@
 #include "messages.h"
 #include "../lib/tsocket/tsocket.h"
 #include "lib/param/param.h"
+#include "libsmb/dsgetdcname.h"
 
 extern userdom_struct current_user_info;
 
diff --git a/source3/utils/net_lookup.c b/source3/utils/net_lookup.c
index f8a5ac61ee8..0f5fefe581c 100644
--- a/source3/utils/net_lookup.c
+++ b/source3/utils/net_lookup.c
@@ -24,6 +24,7 @@
 #include "smb_krb5.h"
 #include "../libcli/security/security.h"
 #include "passdb/lookup_sid.h"
+#include "libsmb/dsgetdcname.h"
 
 int net_lookup_usage(struct net_context *c, int argc, const char **argv)
 {
diff --git a/source3/utils/net_rpc.c b/source3/utils/net_rpc.c
index 11cc0c49849..6c69ffb9670 100644
--- a/source3/utils/net_rpc.c
+++ b/source3/utils/net_rpc.c
@@ -46,6 +46,7 @@
 #include "nsswitch/libwbclient/wbclient.h"
 #include "passdb.h"
 #include "../libcli/smb/smbXcli_base.h"
+#include "libsmb/dsgetdcname.h"
 
 static int net_mode_share;
 static NTSTATUS sync_files(struct copy_clistate *cp_clistate, const char *mask);
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 481b29262d8..e18a1ce5a40 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -35,6 +35,7 @@
 #include "../source4/dsdb/samdb/samdb.h"
 #include "rpc_client/cli_netlogon.h"
 #include "rpc_client/util_netlogon.h"
+#include "libsmb/dsgetdcname.h"
 
 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
 {
-- 
2.11.0


From 5c00ecb80f835e2e5ce032c21a8752b0e8df54e6 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 24 Jan 2018 21:59:30 +0100
Subject: [PATCH 24/32] Use nb_call in name_query_send

---
 source3/libsmb/namequery.c | 38 ++++++++++++++++++--------------------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index b616a64b896..6f00985957b 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -27,6 +27,7 @@
 #include "lib/tsocket/tsocket.h"
 #include "libsmb/nmblib.h"
 #include "libsmb/unexpected.h"
+#include "libsmb/nb_call.h"
 #include "../libcli/nbt/libnbt.h"
 #include "libads/kerberos_proto.h"
 
@@ -1220,9 +1221,7 @@ struct name_query_state {
 	struct sockaddr_storage addr;
 	bool bcast;
 
-
-	uint8_t buf[1024];
-	ssize_t buflen;
+	struct packet_struct pkt;
 
 	NTSTATUS validate_error;
 	uint8_t flags;
@@ -1242,8 +1241,7 @@ struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
 {
 	struct tevent_req *req, *subreq;
 	struct name_query_state *state;
-	struct packet_struct p;
-	struct nmb_packet *nmb = &p.packet.nmb;
+	struct nmb_packet *nmb;
 	struct sockaddr_in *in_addr;
 
 	req = tevent_req_create(mem_ctx, &state, struct name_query_state);
@@ -1271,7 +1269,17 @@ struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
 
 	set_socket_addr_v4(&state->my_addr);
 
-	ZERO_STRUCT(p);
+	state->addr = *addr;
+	in_addr = (struct sockaddr_in *)(void *)&state->addr;
+	in_addr->sin_port = htons(NMB_PORT);
+
+	set_socket_addr_v4(&state->my_addr);
+
+	state->pkt.ip = in_addr->sin_addr;
+	state->pkt.port = 137;
+
+	nmb = &state->pkt.packet.nmb;
+
 	nmb->header.name_trn_id = generate_trn_id();
 	nmb->header.opcode = 0;
 	nmb->header.response = false;
@@ -1291,18 +1299,9 @@ struct tevent_req *name_query_send(TALLOC_CTX *mem_ctx,
 	nmb->question.question_type = 0x20;
 	nmb->question.question_class = 0x1;
 
-	state->buflen = build_packet((char *)state->buf, sizeof(state->buf),
-				     &p);
-	if (state->buflen == 0) {
-		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
-		DEBUG(10, ("build_packet failed\n"));
-		return tevent_req_post(req, ev);
-	}
-
-	subreq = nb_trans_send(state, ev, &state->my_addr, &state->addr, bcast,
-			       state->buf, state->buflen,
-			       NMB_PACKET, nmb->header.name_trn_id,
-			       name_query_validator, state);
+	subreq = nb_call_send(state, ev, &state->pkt,
+			      nmb->header.name_trn_id, NULL,
+			      name_query_validator, state);
 	if (tevent_req_nomem(subreq, req)) {
 		DEBUG(10, ("nb_trans_send failed\n"));
 		return tevent_req_post(req, ev);
@@ -1460,9 +1459,8 @@ static void name_query_done(struct tevent_req *subreq)
 	struct name_query_state *state = tevent_req_data(
 		req, struct name_query_state);
 	NTSTATUS status;
-	struct packet_struct *p = NULL;
 
-	status = nb_trans_recv(subreq, state, &p);
+	status = nb_call_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
-- 
2.11.0


From 2619a98876d63d54dbd4259474a64be69d745cca Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 24 Jan 2018 21:58:51 +0100
Subject: [PATCH 25/32] Use nb_call in node_status_query

---
 source3/libsmb/namequery.c | 445 ++-------------------------------------------
 1 file changed, 13 insertions(+), 432 deletions(-)

diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 6f00985957b..e18745bec1c 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -290,418 +290,6 @@ static struct node_status *parse_node_status(TALLOC_CTX *mem_ctx, char *p,
 	return ret;
 }
 
-struct sock_packet_read_state {
-	struct tevent_context *ev;
-	enum packet_type type;
-	int trn_id;
-
-	struct nb_packet_reader *reader;
-	struct tevent_req *reader_req;
-
-	struct tdgram_context *sock;
-	struct tevent_req *socket_req;
-	uint8_t *buf;
-	struct tsocket_address *addr;
-
-	bool (*validator)(struct packet_struct *p,
-			  void *private_data);
-	void *private_data;
-
-	struct packet_struct *packet;
-};
-
-static void sock_packet_read_got_packet(struct tevent_req *subreq);
-static void sock_packet_read_got_socket(struct tevent_req *subreq);
-
-static struct tevent_req *sock_packet_read_send(
-	TALLOC_CTX *mem_ctx,
-	struct tevent_context *ev,
-	struct tdgram_context *sock,
-	struct nb_packet_reader *reader,
-	enum packet_type type,
-	int trn_id,
-	bool (*validator)(struct packet_struct *p, void *private_data),
-	void *private_data)
-{
-	struct tevent_req *req;
-	struct sock_packet_read_state *state;
-
-	req = tevent_req_create(mem_ctx, &state,
-				struct sock_packet_read_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->ev = ev;
-	state->reader = reader;
-	state->sock = sock;
-	state->type = type;
-	state->trn_id = trn_id;
-	state->validator = validator;
-	state->private_data = private_data;
-
-	if (reader != NULL) {
-		state->reader_req = nb_packet_read_send(state, ev, reader);
-		if (tevent_req_nomem(state->reader_req, req)) {
-			return tevent_req_post(req, ev);
-		}
-		tevent_req_set_callback(
-			state->reader_req, sock_packet_read_got_packet, req);
-	}
-
-	state->socket_req = tdgram_recvfrom_send(state, ev, state->sock);
-	if (tevent_req_nomem(state->socket_req, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(state->socket_req, sock_packet_read_got_socket,
-				req);
-
-	return req;
-}
-
-static void sock_packet_read_got_packet(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct sock_packet_read_state *state = tevent_req_data(
-		req, struct sock_packet_read_state);
-	NTSTATUS status;
-
-	status = nb_packet_read_recv(subreq, state, &state->packet);
-
-	TALLOC_FREE(state->reader_req);
-
-	if (!NT_STATUS_IS_OK(status)) {
-		if (state->socket_req != NULL) {
-			/*
-			 * Still waiting for socket
-			 */
-			return;
-		}
-		/*
-		 * Both socket and packet reader failed
-		 */
-		tevent_req_nterror(req, status);
-		return;
-	}
-
-	if ((state->validator != NULL) &&
-	    !state->validator(state->packet, state->private_data)) {
-		DEBUG(10, ("validator failed\n"));
-
-		TALLOC_FREE(state->packet);
-
-		state->reader_req = nb_packet_read_send(state, state->ev,
-							state->reader);
-		if (tevent_req_nomem(state->reader_req, req)) {
-			return;
-		}
-		tevent_req_set_callback(
-			state->reader_req, sock_packet_read_got_packet, req);
-		return;
-	}
-
-	TALLOC_FREE(state->socket_req);
-	tevent_req_done(req);
-}
-
-static void sock_packet_read_got_socket(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct sock_packet_read_state *state = tevent_req_data(
-		req, struct sock_packet_read_state);
-	union {
-		struct sockaddr sa;
-		struct sockaddr_in sin;
-	} addr;
-	ssize_t ret;
-	ssize_t received;
-	int err;
-	bool ok;
-
-	received = tdgram_recvfrom_recv(subreq, &err, state,
-					&state->buf, &state->addr);
-
-	TALLOC_FREE(state->socket_req);
-
-	if (received == -1) {
-		if (state->reader_req != NULL) {
-			/*
-			 * Still waiting for reader
-			 */
-			return;
-		}
-		/*
-		 * Both socket and reader failed
-		 */
-		tevent_req_nterror(req, map_nt_error_from_unix(err));
-		return;
-	}
-	ok = tsocket_address_is_inet(state->addr, "ipv4");
-	if (!ok) {
-		goto retry;
-	}
-	ret = tsocket_address_bsd_sockaddr(state->addr,
-					   &addr.sa,
-					   sizeof(addr.sin));
-	if (ret == -1) {
-		tevent_req_nterror(req, map_nt_error_from_unix(errno));
-		return;
-	}
-
-	state->packet = parse_packet_talloc(
-		state, (char *)state->buf, received, state->type,
-		addr.sin.sin_addr, addr.sin.sin_port);
-	if (state->packet == NULL) {
-		DEBUG(10, ("parse_packet failed\n"));
-		goto retry;
-	}
-	if ((state->trn_id != -1) &&
-	    (state->trn_id != packet_trn_id(state->packet))) {
-		DEBUG(10, ("Expected transaction id %d, got %d\n",
-			   state->trn_id, packet_trn_id(state->packet)));
-		goto retry;
-	}
-
-	if ((state->validator != NULL) &&
-	    !state->validator(state->packet, state->private_data)) {
-		DEBUG(10, ("validator failed\n"));
-		goto retry;
-	}
-
-	tevent_req_done(req);
-	return;
-
-retry:
-	TALLOC_FREE(state->packet);
-	TALLOC_FREE(state->buf);
-	TALLOC_FREE(state->addr);
-
-	state->socket_req = tdgram_recvfrom_send(state, state->ev, state->sock);
-	if (tevent_req_nomem(state->socket_req, req)) {
-		return;
-	}
-	tevent_req_set_callback(state->socket_req, sock_packet_read_got_socket,
-				req);
-}
-
-static NTSTATUS sock_packet_read_recv(struct tevent_req *req,
-				      TALLOC_CTX *mem_ctx,
-				      struct packet_struct **ppacket)
-{
-	struct sock_packet_read_state *state = tevent_req_data(
-		req, struct sock_packet_read_state);
-	NTSTATUS status;
-
-	if (tevent_req_is_nterror(req, &status)) {
-		return status;
-	}
-	*ppacket = talloc_move(mem_ctx, &state->packet);
-	return NT_STATUS_OK;
-}
-
-struct nb_trans_state {
-	struct tevent_context *ev;
-	struct tdgram_context *sock;
-	struct nb_packet_reader *reader;
-
-	struct tsocket_address *src_addr;
-	struct tsocket_address *dst_addr;
-	uint8_t *buf;
-	size_t buflen;
-	enum packet_type type;
-	int trn_id;
-
-	bool (*validator)(struct packet_struct *p,
-			  void *private_data);
-	void *private_data;
-
-	struct packet_struct *packet;
-};
-
-static void nb_trans_got_reader(struct tevent_req *subreq);
-static void nb_trans_done(struct tevent_req *subreq);
-static void nb_trans_sent(struct tevent_req *subreq);
-static void nb_trans_send_next(struct tevent_req *subreq);
-
-static struct tevent_req *nb_trans_send(
-	TALLOC_CTX *mem_ctx,
-	struct tevent_context *ev,
-	const struct sockaddr_storage *_my_addr,
-	const struct sockaddr_storage *_dst_addr,
-	bool bcast,
-	uint8_t *buf, size_t buflen,
-	enum packet_type type, int trn_id,
-	bool (*validator)(struct packet_struct *p,
-			  void *private_data),
-	void *private_data)
-{
-	const struct sockaddr *my_addr =
-		discard_const_p(const struct sockaddr, _my_addr);
-	size_t my_addr_len = sizeof(*_my_addr);
-	const struct sockaddr *dst_addr =
-		discard_const_p(const struct sockaddr, _dst_addr);
-	size_t dst_addr_len = sizeof(*_dst_addr);
-	struct tevent_req *req, *subreq;
-	struct nb_trans_state *state;
-	int ret;
-
-	req = tevent_req_create(mem_ctx, &state, struct nb_trans_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->ev = ev;
-	state->buf = buf;
-	state->buflen = buflen;
-	state->type = type;
-	state->trn_id = trn_id;
-	state->validator = validator;
-	state->private_data = private_data;
-
-	ret = tsocket_address_bsd_from_sockaddr(state,
-						my_addr, my_addr_len,
-						&state->src_addr);
-	if (ret == -1) {
-		tevent_req_nterror(req, map_nt_error_from_unix(errno));
-		return tevent_req_post(req, ev);
-	}
-
-	ret = tsocket_address_bsd_from_sockaddr(state,
-						dst_addr, dst_addr_len,
-						&state->dst_addr);
-	if (ret == -1) {
-		tevent_req_nterror(req, map_nt_error_from_unix(errno));
-		return tevent_req_post(req, ev);
-	}
-
-	ret = tdgram_inet_udp_broadcast_socket(state->src_addr, state,
-					       &state->sock);
-	if (ret == -1) {
-		tevent_req_nterror(req, map_nt_error_from_unix(errno));
-		return tevent_req_post(req, ev);
-	}
-
-	subreq = nb_packet_reader_send(state, ev, type, state->trn_id, NULL);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, nb_trans_got_reader, req);
-	return req;
-}
-
-static void nb_trans_got_reader(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct nb_trans_state *state = tevent_req_data(
-		req, struct nb_trans_state);
-	NTSTATUS status;
-
-	status = nb_packet_reader_recv(subreq, state, &state->reader);
-	TALLOC_FREE(subreq);
-
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10, ("nmbd not around\n"));
-		state->reader = NULL;
-	}
-
-	subreq = sock_packet_read_send(
-		state, state->ev, state->sock,
-		state->reader, state->type, state->trn_id,
-		state->validator, state->private_data);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, nb_trans_done, req);
-
-	subreq = tdgram_sendto_send(state, state->ev,
-				    state->sock,
-				    state->buf, state->buflen,
-				    state->dst_addr);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, nb_trans_sent, req);
-}
-
-static void nb_trans_sent(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct nb_trans_state *state = tevent_req_data(
-		req, struct nb_trans_state);
-	ssize_t sent;
-	int err;
-
-	sent = tdgram_sendto_recv(subreq, &err);
-	TALLOC_FREE(subreq);
-	if (sent == -1) {
-		DEBUG(10, ("sendto failed: %s\n", strerror(err)));
-		tevent_req_nterror(req, map_nt_error_from_unix(err));
-		return;
-	}
-	subreq = tevent_wakeup_send(state, state->ev,
-				    timeval_current_ofs(1, 0));
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, nb_trans_send_next, req);
-}
-
-static void nb_trans_send_next(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct nb_trans_state *state = tevent_req_data(
-		req, struct nb_trans_state);
-	bool ret;
-
-	ret = tevent_wakeup_recv(subreq);
-	TALLOC_FREE(subreq);
-	if (!ret) {
-		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
-		return;
-	}
-	subreq = tdgram_sendto_send(state, state->ev,
-				    state->sock,
-				    state->buf, state->buflen,
-				    state->dst_addr);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, nb_trans_sent, req);
-}
-
-static void nb_trans_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct nb_trans_state *state = tevent_req_data(
-		req, struct nb_trans_state);
-	NTSTATUS status;
-
-	status = sock_packet_read_recv(subreq, state, &state->packet);
-	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, status)) {
-		return;
-	}
-	tevent_req_done(req);
-}
-
-static NTSTATUS nb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			      struct packet_struct **ppacket)
-{
-	struct nb_trans_state *state = tevent_req_data(
-		req, struct nb_trans_state);
-	NTSTATUS status;
-
-	if (tevent_req_is_nterror(req, &status)) {
-		return status;
-	}
-	*ppacket = talloc_move(mem_ctx, &state->packet);
-	return NT_STATUS_OK;
-}
-
 /****************************************************************************
  Do a NBT node status query on an open socket and return an array of
  structures holding the returned names or NULL if the query failed.
@@ -710,9 +298,8 @@ static NTSTATUS nb_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 struct node_status_query_state {
 	struct sockaddr_storage my_addr;
 	struct sockaddr_storage addr;
-	uint8_t buf[1024];
-	ssize_t buflen;
-	struct packet_struct *packet;
+	struct packet_struct pkt;
+	struct packet_struct *result;
 };
 
 static bool node_status_query_validator(struct packet_struct *p,
@@ -726,8 +313,7 @@ struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
 {
 	struct tevent_req *req, *subreq;
 	struct node_status_query_state *state;
-	struct packet_struct p;
-	struct nmb_packet *nmb = &p.packet.nmb;
+	struct nmb_packet *nmb;
 	struct sockaddr_in *in_addr;
 
 	req = tevent_req_create(mem_ctx, &state,
@@ -748,7 +334,11 @@ struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
 
 	set_socket_addr_v4(&state->my_addr);
 
-	ZERO_STRUCT(p);
+	state->pkt.ip = in_addr->sin_addr;
+	state->pkt.port = 137;
+
+	nmb = &state->pkt.packet.nmb;
+
 	nmb->header.name_trn_id = generate_trn_id();
 	nmb->header.opcode = 0;
 	nmb->header.response = false;
@@ -766,18 +356,9 @@ struct tevent_req *node_status_query_send(TALLOC_CTX *mem_ctx,
 	nmb->question.question_type = 0x21;
 	nmb->question.question_class = 0x1;
 
-	state->buflen = build_packet((char *)state->buf, sizeof(state->buf),
-				     &p);
-	if (state->buflen == 0) {
-		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
-		DEBUG(10, ("build_packet failed\n"));
-		return tevent_req_post(req, ev);
-	}
-
-	subreq = nb_trans_send(state, ev, &state->my_addr, &state->addr, false,
-			       state->buf, state->buflen,
-			       NMB_PACKET, nmb->header.name_trn_id,
-			       node_status_query_validator, NULL);
+	subreq = nb_call_send(state, ev, &state->pkt,
+			      nmb->header.name_trn_id, NULL,
+			      node_status_query_validator, NULL);
 	if (tevent_req_nomem(subreq, req)) {
 		DEBUG(10, ("nb_trans_send failed\n"));
 		return tevent_req_post(req, ev);
@@ -817,7 +398,7 @@ static void node_status_query_done(struct tevent_req *subreq)
 		req, struct node_status_query_state);
 	NTSTATUS status;
 
-	status = nb_trans_recv(subreq, state, &state->packet);
+	status = nb_call_recv(subreq, state, &state->result);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
@@ -840,7 +421,7 @@ NTSTATUS node_status_query_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 		return status;
 	}
 	node_status = parse_node_status(
-		mem_ctx, &state->packet->packet.nmb.answers->rdata[0],
+		mem_ctx, &state->result->packet.nmb.answers->rdata[0],
 		&num_names, extra);
 	if (node_status == NULL) {
 		return NT_STATUS_NO_MEMORY;
-- 
2.11.0


From 822ab8de8be7d19ceec337ab7f4b897557396da3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sat, 20 Jan 2018 14:49:45 +0000
Subject: [PATCH 26/32] Use nb_call in name_resolve_bcast

---
 source3/libsmb/namequery.c | 350 ++++++++++++++++-----------------------------
 1 file changed, 124 insertions(+), 226 deletions(-)

diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index e18745bec1c..564d4d19be5 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -1175,286 +1175,184 @@ static bool convert_ss2service(struct ip_service **return_iplist,
 	return true;
 }
 
-struct name_queries_state {
-	struct tevent_context *ev;
-	const char *name;
-	int name_type;
-	bool bcast;
-	bool recurse;
-	const struct sockaddr_storage *addrs;
-	int num_addrs;
-	int wait_msec;
-	int timeout_msec;
+/********************************************************
+ Resolve via "bcast" method.
+*********************************************************/
 
-	struct tevent_req **subreqs;
-	int num_received;
-	int num_sent;
+struct name_resolve_bcast_state {
+	struct packet_struct pkt;
 
-	int received_index;
-	struct sockaddr_storage *result_addrs;
-	int num_result_addrs;
-	uint8_t flags;
+	struct sockaddr_storage *addrs;
+	size_t num_addrs;
 };
 
-static void name_queries_done(struct tevent_req *subreq);
-static void name_queries_next(struct tevent_req *subreq);
-
-/*
- * Send a name query to multiple destinations with a wait time in between
- */
+static bool name_resolve_bcast_validator(struct packet_struct *p,
+					 void *private_data);
+static void name_resolve_bcast_waited(struct tevent_req *subreq);
+static void name_resolve_bcast_done(struct tevent_req *subreq);
 
-static struct tevent_req *name_queries_send(
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	const char *name, int name_type,
-	bool bcast, bool recurse,
-	const struct sockaddr_storage *addrs,
-	int num_addrs, int wait_msec, int timeout_msec)
+struct tevent_req *name_resolve_bcast_send(TALLOC_CTX *mem_ctx,
+					   struct tevent_context *ev,
+					   const char *name,
+					   int name_type)
 {
 	struct tevent_req *req, *subreq;
-	struct name_queries_state *state;
+	struct name_resolve_bcast_state *state;
+	struct nmb_packet *nmb;
+
+	/*
+	 * "bcast" means do a broadcast lookup on all the local interfaces.
+	 */
+
+	DEBUG(3, ("name_resolve_bcast: Attempting broadcast lookup "
+		  "for name %s<0x%x>\n", name, name_type));
 
 	req = tevent_req_create(mem_ctx, &state,
-				struct name_queries_state);
+				struct name_resolve_bcast_state);
 	if (req == NULL) {
 		return NULL;
 	}
-	state->ev = ev;
-	state->name = name;
-	state->name_type = name_type;
-	state->bcast = bcast;
-	state->recurse = recurse;
-	state->addrs = addrs;
-	state->num_addrs = num_addrs;
-	state->wait_msec = wait_msec;
-	state->timeout_msec = timeout_msec;
-
-	state->subreqs = talloc_zero_array(
-		state, struct tevent_req *, num_addrs);
-	if (tevent_req_nomem(state->subreqs, req)) {
-		return tevent_req_post(req, ev);
-	}
-	state->num_sent = 0;
 
-	subreq = name_query_send(
-		state->subreqs, state->ev, name, name_type, bcast, recurse,
-		&state->addrs[state->num_sent]);
+	nmb = &state->pkt.packet.nmb;
+
+	nmb->header.name_trn_id = generate_trn_id();
+	nmb->header.opcode = NMB_NAME_QUERY_OPCODE;
+	nmb->header.nm_flags.bcast = true;
+
+	make_nmb_name(&nmb->question.question_name,name,name_type);
+	nmb->question.question_type = RR_TYPE_NB;
+	nmb->question.question_class = RR_CLASS_IN;
+
+	nmb->header.qdcount = 1;
+
+	subreq = nb_call_send(state, ev, &state->pkt,
+			      nmb->header.name_trn_id, NULL,
+			      name_resolve_bcast_validator, state);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	if (!tevent_req_set_endtime(
-		    subreq, state->ev,
-		    timeval_current_ofs(0, state->timeout_msec * 1000))) {
-		tevent_req_oom(req);
+	tevent_req_set_callback(subreq, name_resolve_bcast_done, req);
+
+	/*
+	 * Wait one second for group names
+	 */
+	subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(1, 0));
+	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
-	tevent_req_set_callback(subreq, name_queries_done, req);
-
-	state->subreqs[state->num_sent] = subreq;
-	state->num_sent += 1;
+	tevent_req_set_callback(subreq, name_resolve_bcast_waited, req);
 
-	if (state->num_sent < state->num_addrs) {
-		subreq = tevent_wakeup_send(
-			state, state->ev,
-			timeval_current_ofs(0, state->wait_msec * 1000));
-		if (tevent_req_nomem(subreq, req)) {
-			return tevent_req_post(req, ev);
-		}
-		tevent_req_set_callback(subreq, name_queries_next, req);
-	}
 	return req;
 }
 
-static void name_queries_done(struct tevent_req *subreq)
+static bool name_resolve_bcast_validator(struct packet_struct *pkt,
+					 void *private_data)
 {
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct name_queries_state *state = tevent_req_data(
-		req, struct name_queries_state);
-	int i;
-	NTSTATUS status;
-
-	status = name_query_recv(subreq, state, &state->result_addrs,
-				 &state->num_result_addrs, &state->flags);
-
-	for (i=0; i<state->num_sent; i++) {
-		if (state->subreqs[i] == subreq) {
-			break;
-		}
-	}
-	if (i == state->num_sent) {
-		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
-		return;
-	}
-	TALLOC_FREE(state->subreqs[i]);
-
-	state->num_received += 1;
-
-	if (!NT_STATUS_IS_OK(status)) {
+	struct name_resolve_bcast_state *state = talloc_get_type_abort(
+		private_data, struct name_resolve_bcast_state);
+	struct nmb_packet *nmb;
+	struct res_rec *answer;
+	size_t i, num_addr_entries;
+	struct sockaddr_storage *tmp;
+	bool got_unique_netbios_name = false;
 
-		if (state->num_received >= state->num_addrs) {
-			tevent_req_nterror(req, status);
-			return;
-		}
-		/*
-		 * Still outstanding requests, just wait
-		 */
-		return;
+	if (pkt->packet_type != NMB_PACKET) {
+		return false;
 	}
-	state->received_index = i;
-	tevent_req_done(req);
-}
-
-static void name_queries_next(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct name_queries_state *state = tevent_req_data(
-		req, struct name_queries_state);
+	nmb = &pkt->packet.nmb;
 
-	if (!tevent_wakeup_recv(subreq)) {
-		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
-		return;
+	if ((nmb->header.opcode != NMB_NAME_QUERY_OPCODE) ||
+	    !nmb->header.response ||
+	    nmb->header.nm_flags.bcast ||
+	    (nmb->header.rcode != 0) ||
+	    (nmb->header.ancount != 1)) {
+		return false;
 	}
 
-	subreq = name_query_send(
-		state->subreqs, state->ev,
-		state->name, state->name_type, state->bcast, state->recurse,
-		&state->addrs[state->num_sent]);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, name_queries_done, req);
-	if (!tevent_req_set_endtime(
-		    subreq, state->ev,
-		    timeval_current_ofs(0, state->timeout_msec * 1000))) {
-		tevent_req_oom(req);
-		return;
-	}
-	state->subreqs[state->num_sent] = subreq;
-	state->num_sent += 1;
+	/*
+	 * NetBIOS only has one answer record
+	 */
+	answer = nmb->answers;
 
-	if (state->num_sent < state->num_addrs) {
-		subreq = tevent_wakeup_send(
-			state, state->ev,
-			timeval_current_ofs(0, state->wait_msec * 1000));
-		if (tevent_req_nomem(subreq, req)) {
-			return;
-		}
-		tevent_req_set_callback(subreq, name_queries_next, req);
+	if ((answer->rdlength % 6) != 0) {
+		return false;
 	}
-}
-
-static NTSTATUS name_queries_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-				  struct sockaddr_storage **result_addrs,
-				  int *num_result_addrs, uint8_t *flags,
-				  int *received_index)
-{
-	struct name_queries_state *state = tevent_req_data(
-		req, struct name_queries_state);
-	NTSTATUS status;
 
-	if (tevent_req_is_nterror(req, &status)) {
-		return status;
-	}
+	num_addr_entries = answer->rdlength / 6;
 
-	if (result_addrs != NULL) {
-		*result_addrs = talloc_move(mem_ctx, &state->result_addrs);
-	}
-	if (num_result_addrs != NULL) {
-		*num_result_addrs = state->num_result_addrs;
-	}
-	if (flags != NULL) {
-		*flags = state->flags;
-	}
-	if (received_index != NULL) {
-		*received_index = state->received_index;
+	tmp = talloc_realloc(state, state->addrs, struct sockaddr_storage,
+			     state->num_addrs + num_addr_entries);
+	if (tmp == NULL) {
+		/* Exit without addrs */
+		return true;
 	}
-	return NT_STATUS_OK;
-}
+	state->addrs = tmp;
 
-/********************************************************
- Resolve via "bcast" method.
-*********************************************************/
+	for (i=0; i<num_addr_entries; i++) {
+		char *addr_entry = answer->rdata + (i*6);
+		uint16_t flags;
+		struct sockaddr_storage *addr =
+			&state->addrs[state->num_addrs];
+		struct in_addr ip;
+		size_t j;
 
-struct name_resolve_bcast_state {
-	struct sockaddr_storage *addrs;
-	int num_addrs;
-};
+		flags = RSVAL(addr_entry, 0);
+		got_unique_netbios_name |= ((flags & 0x8000) == 0);
 
-static void name_resolve_bcast_done(struct tevent_req *subreq);
+		putip((char *)&ip, addr_entry+2);
+		in_addr_to_sockaddr_storage(addr, ip);
 
-struct tevent_req *name_resolve_bcast_send(TALLOC_CTX *mem_ctx,
-					   struct tevent_context *ev,
-					   const char *name,
-					   int name_type)
-{
-	struct tevent_req *req, *subreq;
-	struct name_resolve_bcast_state *state;
-	struct sockaddr_storage *bcast_addrs;
-	int i, num_addrs, num_bcast_addrs;
+		if (is_zero_addr(addr)) {
+			continue;
+		}
+		for (j=0; j<state->num_addrs; j++) {
+			struct sockaddr_storage *cmp = &state->addrs[j];
 
-	req = tevent_req_create(mem_ctx, &state,
-				struct name_resolve_bcast_state);
-	if (req == NULL) {
-		return NULL;
-	}
+			if (sockaddr_equal((struct sockaddr *)(void *)cmp,
+					   (struct sockaddr *)(void *)addr)) {
+				break;
+			}
+		}
+		if (j < state->num_addrs) {
+			/* Already got it */
+			continue;
+		}
 
-	if (lp_disable_netbios()) {
-		DEBUG(5, ("name_resolve_bcast(%s#%02x): netbios is disabled\n",
-			  name, name_type));
-		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-		return tevent_req_post(req, ev);
+		state->num_addrs += 1;
 	}
 
-	/*
-	 * "bcast" means do a broadcast lookup on all the local interfaces.
-	 */
-
-	DEBUG(3, ("name_resolve_bcast: Attempting broadcast lookup "
-		  "for name %s<0x%x>\n", name, name_type));
-
-	num_addrs = iface_count();
-	bcast_addrs = talloc_array(state, struct sockaddr_storage, num_addrs);
-	if (tevent_req_nomem(bcast_addrs, req)) {
-		return tevent_req_post(req, ev);
+	if (got_unique_netbios_name) {
+		return true;
 	}
 
-	/*
-	 * Lookup the name on all the interfaces, return on
-	 * the first successful match.
-	 */
-	num_bcast_addrs = 0;
-
-	for (i=0; i<num_addrs; i++) {
-		const struct sockaddr_storage *pss = iface_n_bcast(i);
+	return false;
+}
 
-		if (pss->ss_family != AF_INET) {
-			continue;
-		}
-		bcast_addrs[num_bcast_addrs] = *pss;
-		num_bcast_addrs += 1;
-	}
+static void name_resolve_bcast_waited(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	bool ret;
 
-	subreq = name_queries_send(state, ev, name, name_type, true, true,
-				   bcast_addrs, num_bcast_addrs, 0, 1000);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
+	ret = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
 	}
-	tevent_req_set_callback(subreq, name_resolve_bcast_done, req);
-	return req;
+	tevent_req_done(req);
 }
 
 static void name_resolve_bcast_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
 		subreq, struct tevent_req);
-	struct name_resolve_bcast_state *state = tevent_req_data(
-		req, struct name_resolve_bcast_state);
 	NTSTATUS status;
 
-	status = name_queries_recv(subreq, state,
-				   &state->addrs, &state->num_addrs,
-				   NULL, NULL);
+	/*
+	 * We've collected the addresses in the validator
+	 */
+	status = nb_call_recv(subreq, NULL, NULL);
 	TALLOC_FREE(subreq);
 	if (tevent_req_nterror(req, status)) {
 		return;
-- 
2.11.0


From ea1d85288eb1f674f0c9a48430e2c87c61b926b2 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 25 Jan 2018 12:48:54 +0100
Subject: [PATCH 27/32] libsmb: Remove unused #includes

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/libsmb/namequery.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/source3/libsmb/namequery.c b/source3/libsmb/namequery.c
index 564d4d19be5..59c7cf0c2e2 100644
--- a/source3/libsmb/namequery.c
+++ b/source3/libsmb/namequery.c
@@ -23,10 +23,7 @@
 #include "libads/sitename_cache.h"
 #include "../lib/addns/dnsquery.h"
 #include "../libcli/netlogon/netlogon.h"
-#include "lib/async_req/async_sock.h"
-#include "lib/tsocket/tsocket.h"
 #include "libsmb/nmblib.h"
-#include "libsmb/unexpected.h"
 #include "libsmb/nb_call.h"
 #include "../libcli/nbt/libnbt.h"
 #include "libads/kerberos_proto.h"
-- 
2.11.0


From fcd559832887e41285629000ef6de21013075203 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 25 Jan 2018 13:02:20 +0100
Subject: [PATCH 28/32] nmblookup: We don't need receiving sockets anymore

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/utils/nmblookup.c | 37 -------------------------------------
 1 file changed, 37 deletions(-)

diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c
index dadd30fdb74..4435cc54412 100644
--- a/source3/utils/nmblookup.c
+++ b/source3/utils/nmblookup.c
@@ -29,41 +29,10 @@ static bool got_bcast = false;
 static struct sockaddr_storage bcast_addr;
 static bool recursion_desired = false;
 static bool translate_addresses = false;
-static int ServerFD= -1;
 static bool RootPort = false;
 static bool find_status = false;
 
 /****************************************************************************
- Open the socket communication.
-**************************************************************************/
-
-static bool open_sockets(void)
-{
-	struct sockaddr_storage ss;
-	const char *sock_addr = lp_nbt_client_socket_address();
-
-	if (!interpret_string_addr(&ss, sock_addr,
-				AI_NUMERICHOST|AI_PASSIVE)) {
-		DEBUG(0,("open_sockets: unable to get socket address "
-					"from string %s", sock_addr));
-		return false;
-	}
-	ServerFD = open_socket_in( SOCK_DGRAM,
-				(RootPort ? 137 : 0),
-				(RootPort ?   0 : 3),
-				&ss, true );
-
-	if (ServerFD == -1) {
-		return false;
-	}
-
-	set_socket_options( ServerFD, "SO_BROADCAST" );
-
-	DEBUG(3, ("Socket opened.\n"));
-	return true;
-}
-
-/****************************************************************************
 turn a node status flags field into a string
 ****************************************************************************/
 static char *node_status_flags(unsigned char flags)
@@ -311,12 +280,6 @@ int main(int argc, const char *argv[])
 				get_dyn_CONFIGFILE());
 	}
 
-	load_interfaces();
-	if (!open_sockets()) {
-		rc = 1;
-		goto out;
-	}
-
 	while(poptPeekArg(pc)) {
 		char *p;
 		struct in_addr ip;
-- 
2.11.0


From 301b34d9d4d3cefb71c79ac1b47b14900049a1d3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 25 Jan 2018 13:24:00 +0100
Subject: [PATCH 29/32] nmblookup: Remove unneeded option "-r"

---
 docs-xml/manpages/nmblookup.1.xml | 14 --------------
 source3/utils/nmblookup.c         |  4 ----
 2 files changed, 18 deletions(-)

diff --git a/docs-xml/manpages/nmblookup.1.xml b/docs-xml/manpages/nmblookup.1.xml
index c633e072146..4f1c0d93c8b 100644
--- a/docs-xml/manpages/nmblookup.1.xml
+++ b/docs-xml/manpages/nmblookup.1.xml
@@ -23,7 +23,6 @@
 		<arg choice="opt">-M|--master-browser</arg>
 		<arg choice="opt">-R|--recursion</arg>
 		<arg choice="opt">-S|--status</arg>
-		<arg choice="opt">-r|--root-port</arg>
 		<arg choice="opt">-A|--lookup-by-ip</arg>
 		<arg choice="opt">-B|--broadcast <broadcast address></arg>
 		<arg choice="opt">-U|--unicast <unicast address></arg>
@@ -86,19 +85,6 @@
 
 
 		<varlistentry>
-		<term>-r|--root-port</term>
-		<listitem><para>Try and bind to UDP port 137 to send and receive UDP
-		datagrams. The reason for this option is a bug in Windows 95 
-		where it ignores the source port of the requesting packet 
-	 	and only replies to UDP port 137. Unfortunately, on most UNIX 
-		systems root privilege is needed to bind to this port, and 
-		in addition, if the <citerefentry><refentrytitle>nmbd</refentrytitle>
-		<manvolnum>8</manvolnum></citerefentry> daemon is running on this machine it also binds to this port.
-		</para></listitem>
-		</varlistentry>
-
-
-		<varlistentry>
 		<term>-A|--lookup-by-ip</term>
 		<listitem><para>Interpret <replaceable>name</replaceable> as 
 		an IP Address and do a node status query on this address.</para>
diff --git a/source3/utils/nmblookup.c b/source3/utils/nmblookup.c
index 4435cc54412..eb887f85349 100644
--- a/source3/utils/nmblookup.c
+++ b/source3/utils/nmblookup.c
@@ -29,7 +29,6 @@ static bool got_bcast = false;
 static struct sockaddr_storage bcast_addr;
 static bool recursion_desired = false;
 static bool translate_addresses = false;
-static bool RootPort = false;
 static bool find_status = false;
 
 /****************************************************************************
@@ -239,9 +238,6 @@ int main(int argc, const char *argv[])
 		case 'S':
 			find_status = true;
 			break;
-		case 'r':
-			RootPort = true;
-			break;
 		case 'A':
 			lookup_by_ip = true;
 			break;
-- 
2.11.0


From adc824236f1ede5669fc627f342399d16900b331 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 28 Jan 2018 16:16:52 +0100
Subject: [PATCH 30/32] selftest: Start nmbd before net join in nt4_member

---
 selftest/target/Samba3.pm | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index 8914507c12e..d502f7fbf72 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -308,6 +308,10 @@ sub setup_nt4_member
 
 	$ret or return undef;
 
+	if (not $self->check_or_start($ret, "yes", "no", "no")) {
+	       return undef;
+	}
+
 	my $nmblookup = Samba::bindir_path($self, "nmblookup");
 	do {
 		print "Waiting for the LOGON SERVER registration ...\n";
@@ -345,7 +349,7 @@ sub setup_nt4_member
 	    return undef;
 	}
 
-	if (not $self->check_or_start($ret, "yes", "yes", "yes")) {
+	if (not $self->check_or_start($ret, "no", "yes", "yes")) {
 	       return undef;
 	}
 
-- 
2.11.0


From c88427eb906c54449aaa1a6343a3ecde16b4a19a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 30 Jan 2018 13:46:52 +0100
Subject: [PATCH 31/32] direct nmbd socket dir in testenvs

---
 selftest/target/Samba3.pm | 1 +
 selftest/target/Samba4.pm | 1 +
 2 files changed, 2 insertions(+)

diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index d502f7fbf72..a8f92cbe140 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -1662,6 +1662,7 @@ sub provision($$$$$$$$$)
 	binddns dir = $binddnsdir
 	pid directory = $piddir
 	lock directory = $lockdir
+        nmbd:socket dir = $lockdir
 	log file = $logdir/log.\%m
 	log level = 1
 	debug pid = yes
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 842cd1e1bb6..15e12986bed 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -612,6 +612,7 @@ sub provision_raw_step1($$)
 	state directory = $ctx->{statedir}
 	cache directory = $ctx->{cachedir}
 	winbindd socket directory = $ctx->{winbindd_socket_dir}
+	nmbd:socket dir = $ctx->{winbindd_socket_dir}
 	ntp signd socket directory = $ctx->{ntp_signd_socket_dir}
 	winbind separator = /
 	interfaces = $ctx->{interfaces}
-- 
2.11.0


From 2181e164d65719a1d29c1f4e82e37521661a24e3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 5 Mar 2018 13:04:14 +0100
Subject: [PATCH 32/32] libdgram: We don't need the check for nmbd

Failing to connect to the "unexpected" pipe is sufficient here
---
 source3/libsmb/clidgram.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/source3/libsmb/clidgram.c b/source3/libsmb/clidgram.c
index 8d33ee1719a..d3986de8d09 100644
--- a/source3/libsmb/clidgram.c
+++ b/source3/libsmb/clidgram.c
@@ -281,7 +281,6 @@ struct nbt_getdc_state {
 	struct tevent_context *ev;
 	struct nb_packet_reader *reader;
 	const char *my_mailslot;
-	pid_t nmbd_pid;
 
 	const struct sockaddr_storage *dc_addr;
 	const char *domain_name;
@@ -327,12 +326,6 @@ struct tevent_req *nbt_getdc_send(TALLOC_CTX *mem_ctx,
 	if (tevent_req_nomem(state->my_mailslot, req)) {
 		return tevent_req_post(req, ev);
 	}
-	state->nmbd_pid = pidfile_pid(lp_pid_directory(), "nmbd");
-	if (state->nmbd_pid == 0) {
-		DEBUG(3, ("No nmbd found\n"));
-		tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
-		return tevent_req_post(req, ev);
-	}
 
 	generate_random_buffer((uint8_t *)(void *)&dgm_id, sizeof(dgm_id));
 
-- 
2.11.0



More information about the samba-technical mailing list