From 414f6c80b22b128c25d947d62f6b5d1ec13091b6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 31 Jan 2005 01:57:58 +0000 Subject: 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) --- source4/libcli/nbt/libnbt.h | 23 ++++++- source4/libcli/nbt/namequery.c | 27 +++++--- source4/libcli/nbt/nameregister.c | 140 ++++++++++++++++++++++++++++++++++++++ source4/libcli/nbt/nbtsocket.c | 52 ++++++++++++-- 4 files changed, 226 insertions(+), 16 deletions(-) create mode 100644 source4/libcli/nbt/nameregister.c (limited to 'source4/libcli/nbt') 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;iout.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; } -- cgit