summaryrefslogtreecommitdiff
path: root/source4/libcli/nbt
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2005-01-31 01:57:58 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:09:23 -0500
commit414f6c80b22b128c25d947d62f6b5d1ec13091b6 (patch)
treeda147a6c2802a7af79b5dfcdf3d3f6508287520e /source4/libcli/nbt
parent37449657a8d335097b3f3559f8b5bf084b50b85a (diff)
downloadsamba-414f6c80b22b128c25d947d62f6b5d1ec13091b6.tar.gz
samba-414f6c80b22b128c25d947d62f6b5d1ec13091b6.tar.bz2
samba-414f6c80b22b128c25d947d62f6b5d1ec13091b6.zip
r5114: the nbtd task can now act as a basic B-node server. It registers its
names on the network and answers name queries. Lots of details are still missing, but at least this now means you don't need a Samba3 nmbd to use Samba4. missing pieces include: - name registrations should be "shout 3 times, then demand" - no WINS server yet - no master browser code (This used to be commit d7d31fdc6670f026f96b50e51a4de19f0b920e5b)
Diffstat (limited to 'source4/libcli/nbt')
-rw-r--r--source4/libcli/nbt/libnbt.h23
-rw-r--r--source4/libcli/nbt/namequery.c27
-rw-r--r--source4/libcli/nbt/nameregister.c140
-rw-r--r--source4/libcli/nbt/nbtsocket.c52
4 files changed, 226 insertions, 16 deletions
diff --git a/source4/libcli/nbt/libnbt.h b/source4/libcli/nbt/libnbt.h
index 82069f0390..3bfffa25d0 100644
--- a/source4/libcli/nbt/libnbt.h
+++ b/source4/libcli/nbt/libnbt.h
@@ -113,7 +113,8 @@ struct nbt_name_query {
struct {
const char *reply_from;
struct nbt_name name;
- const char *reply_addr;
+ int16_t num_addrs;
+ const char **reply_addrs;
} out;
};
@@ -130,3 +131,23 @@ struct nbt_name_status {
struct nbt_rdata_status status;
} out;
};
+
+/* a name registration request */
+struct nbt_name_register {
+ struct {
+ struct nbt_name name;
+ const char *dest_addr;
+ const char *address;
+ uint16_t nb_flags;
+ BOOL register_demand;
+ BOOL broadcast;
+ uint32_t ttl;
+ int timeout; /* in seconds */
+ } in;
+ struct {
+ const char *reply_from;
+ struct nbt_name name;
+ const char *reply_addr;
+ uint8_t rcode;
+ } out;
+};
diff --git a/source4/libcli/nbt/namequery.c b/source4/libcli/nbt/namequery.c
index 6f549e6241..f6744e9f14 100644
--- a/source4/libcli/nbt/namequery.c
+++ b/source4/libcli/nbt/namequery.c
@@ -66,7 +66,7 @@ failed:
}
/*
- wait for a name query replu
+ wait for a name query reply
*/
NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
@@ -75,6 +75,7 @@ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
struct nbt_name_packet *packet;
const char *addr;
struct in_addr in;
+ int i;
status = nbt_name_request_recv(req);
if (!NT_STATUS_IS_OK(status) ||
@@ -94,13 +95,23 @@ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
}
io->out.name = packet->answers[0].name;
- in.s_addr = htonl(packet->answers[0].rdata.netbios.ipaddr);
- addr = inet_ntoa(in);
- if (addr == NULL) {
+ io->out.num_addrs = packet->answers[0].rdata.netbios.length / 6;
+ io->out.reply_addrs = talloc_array(mem_ctx, const char *, io->out.num_addrs);
+ if (io->out.reply_addrs == NULL) {
talloc_free(req);
return NT_STATUS_NO_MEMORY;
}
- io->out.reply_addr = talloc_strdup(mem_ctx, addr);
+
+ for (i=0;i<io->out.num_addrs;i++) {
+ in.s_addr = htonl(packet->answers[0].rdata.netbios.addresses[i].ipaddr);
+ addr = inet_ntoa(in);
+ if (addr == NULL) {
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ io->out.reply_addrs[i] = talloc_strdup(mem_ctx, addr);
+ }
+
talloc_steal(mem_ctx, io->out.name.name);
talloc_steal(mem_ctx, io->out.name.scope);
@@ -110,7 +121,7 @@ NTSTATUS nbt_name_query_recv(struct nbt_name_request *req,
}
/*
- wait for a name query replu
+ wait for a name query reply
*/
NTSTATUS nbt_name_query(struct nbt_name_socket *nbtsock,
TALLOC_CTX *mem_ctx, struct nbt_name_query *io)
@@ -156,7 +167,7 @@ failed:
}
/*
- wait for a name status replu
+ wait for a name status reply
*/
NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
@@ -199,7 +210,7 @@ NTSTATUS nbt_name_status_recv(struct nbt_name_request *req,
}
/*
- wait for a name status replu
+ wait for a name status reply
*/
NTSTATUS nbt_name_status(struct nbt_name_socket *nbtsock,
TALLOC_CTX *mem_ctx, struct nbt_name_status *io)
diff --git a/source4/libcli/nbt/nameregister.c b/source4/libcli/nbt/nameregister.c
new file mode 100644
index 0000000000..2d1e964977
--- /dev/null
+++ b/source4/libcli/nbt/nameregister.c
@@ -0,0 +1,140 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ send out a name registration request
+
+ Copyright (C) Andrew Tridgell 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "libcli/nbt/libnbt.h"
+#include "system/network.h"
+
+/*
+ send a nbt name registration request
+*/
+struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
+ struct nbt_name_register *io)
+{
+ struct nbt_name_request *req;
+ struct nbt_name_packet *packet;
+
+ packet = talloc_zero(nbtsock, struct nbt_name_packet);
+ if (packet == NULL) return NULL;
+
+ packet->qdcount = 1;
+ packet->arcount = 1;
+ packet->operation = NBT_OPCODE_REGISTER;
+ if (io->in.broadcast) {
+ packet->operation |= NBT_FLAG_BROADCAST;
+ }
+ if (io->in.register_demand) {
+ packet->operation |= NBT_FLAG_RECURSION_DESIRED;
+ }
+
+ packet->questions = talloc_array(packet, struct nbt_name_question, 1);
+ if (packet->questions == NULL) goto failed;
+
+ packet->questions[0].name = io->in.name;
+ packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
+ packet->questions[0].question_class = NBT_QCLASS_IP;
+
+ packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
+ if (packet->additional == NULL) goto failed;
+
+ packet->additional[0].name = io->in.name;
+ packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
+ packet->additional[0].rr_class = NBT_QCLASS_IP;
+ packet->additional[0].ttl = io->in.ttl;
+ packet->additional[0].rdata.netbios.length = 6;
+ packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
+ struct nbt_rdata_address, 1);
+ if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
+ packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
+ packet->additional[0].rdata.netbios.addresses[0].ipaddr = htonl(inet_addr(io->in.address));
+
+ req = nbt_name_request_send(nbtsock, io->in.dest_addr, lp_nbt_port(), packet,
+ timeval_current_ofs(io->in.timeout, 0), False);
+ if (req == NULL) goto failed;
+
+ talloc_steal(req, packet);
+
+ return req;
+
+failed:
+ talloc_free(packet);
+ return NULL;
+}
+
+/*
+ wait for a registration reply
+*/
+NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+ NTSTATUS status;
+ struct nbt_name_packet *packet;
+ const char *addr;
+ struct in_addr in;
+
+ status = nbt_name_request_recv(req);
+ if (!NT_STATUS_IS_OK(status) ||
+ req->num_replies == 0) {
+ talloc_free(req);
+ return status;
+ }
+
+ packet = req->replies[0].packet;
+ io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].reply_addr);
+
+ if (packet->ancount != 1 ||
+ packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
+ packet->answers[0].rr_class != NBT_QCLASS_IP) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ io->out.rcode = packet->operation & NBT_RCODE;
+ io->out.name = packet->answers[0].name;
+ if (packet->answers[0].rdata.netbios.length < 6) {
+ talloc_free(req);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ in.s_addr = htonl(packet->answers[0].rdata.netbios.addresses[0].ipaddr);
+ addr = inet_ntoa(in);
+ if (addr == NULL) {
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+ }
+ io->out.reply_addr = talloc_strdup(mem_ctx, addr);
+ talloc_steal(mem_ctx, io->out.name.name);
+ talloc_steal(mem_ctx, io->out.name.scope);
+
+ talloc_free(req);
+
+ return NT_STATUS_OK;
+}
+
+/*
+ synchronous name registration request
+*/
+NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
+ TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
+{
+ struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
+ return nbt_name_register_recv(req, mem_ctx, io);
+}
diff --git a/source4/libcli/nbt/nbtsocket.c b/source4/libcli/nbt/nbtsocket.c
index f1964b7158..90b4f6e029 100644
--- a/source4/libcli/nbt/nbtsocket.c
+++ b/source4/libcli/nbt/nbtsocket.c
@@ -41,7 +41,8 @@ static int nbt_name_request_destructor(void *ptr)
if (req->state == NBT_REQUEST_WAIT) {
req->nbtsock->num_pending--;
}
- if (req->request->name_trn_id != 0) {
+ if (req->request->name_trn_id != 0 &&
+ !(req->request->operation & NBT_FLAG_REPLY)) {
idr_remove(req->nbtsock->idr, req->request->name_trn_id);
req->request->name_trn_id = 0;
}
@@ -65,7 +66,7 @@ static int nbt_name_request_destructor(void *ptr)
static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
{
struct nbt_name_request *req = nbtsock->send_queue;
- TALLOC_CTX *tmp_ctx = talloc_new(req);
+ TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
NTSTATUS status;
while ((req = nbtsock->send_queue)) {
@@ -98,9 +99,13 @@ static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
}
DLIST_REMOVE(nbtsock->send_queue, req);
- req->state = NBT_REQUEST_WAIT;
- nbtsock->fde->flags |= EVENT_FD_READ;
- nbtsock->num_pending++;
+ if (req->request->operation & NBT_FLAG_REPLY) {
+ talloc_free(req);
+ } else {
+ req->state = NBT_REQUEST_WAIT;
+ nbtsock->fde->flags |= EVENT_FD_READ;
+ nbtsock->num_pending++;
+ }
}
nbtsock->fde->flags &= ~EVENT_FD_WRITE;
@@ -317,7 +322,8 @@ struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock,
if (req == NULL) goto failed;
req->nbtsock = nbtsock;
- req->dest_addr = dest_addr;
+ req->dest_addr = talloc_strdup(req, dest_addr);
+ if (req->dest_addr == NULL) goto failed;
req->dest_port = dest_port;
req->request = talloc_reference(req, request);
req->allow_multiple_replies = allow_multiple_replies;
@@ -361,6 +367,39 @@ failed:
return NULL;
}
+
+/*
+ send off a nbt name reply
+*/
+NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock,
+ const char *dest_addr, int dest_port,
+ struct nbt_name_packet *request)
+{
+ struct nbt_name_request *req;
+
+ req = talloc_zero(nbtsock, struct nbt_name_request);
+ NT_STATUS_HAVE_NO_MEMORY(req);
+
+ req->nbtsock = nbtsock;
+ req->dest_addr = talloc_strdup(req, dest_addr);
+ if (req->dest_addr == NULL) goto failed;
+ req->dest_port = dest_port;
+ req->request = talloc_reference(req, request);
+ req->state = NBT_REQUEST_SEND;
+
+ talloc_set_destructor(req, nbt_name_request_destructor);
+
+ DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
+
+ nbtsock->fde->flags |= EVENT_FD_WRITE;
+
+ return NT_STATUS_OK;
+
+failed:
+ talloc_free(req);
+ return NT_STATUS_NO_MEMORY;
+}
+
/*
wait for a nbt request to complete
*/
@@ -392,7 +431,6 @@ NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
nbtsock->incoming.handler = handler;
nbtsock->incoming.private = private;
nbtsock->fde->flags |= EVENT_FD_READ;
- socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
return NT_STATUS_OK;
}