r5118: added support for node status replies in nbtd. nmblookup -S now works against...
authorAndrew Tridgell <tridge@samba.org>
Mon, 31 Jan 2005 04:15:58 +0000 (04:15 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:09:24 +0000 (13:09 -0500)
Also added support for the '*' wildcard name

source/librpc/idl/nbt.idl
source/librpc/ndr/ndr_basic.c
source/nbt_server/config.mk
source/nbt_server/nbt_server.h
source/nbt_server/nodestatus.c [new file with mode: 0644]
source/nbt_server/query.c
source/nbt_server/register.c

index 35fc7d90c4042086e63481e0a93f62d544fcbb55..caca7fa336eb25653cfe8ab446670eac676eed20 100644 (file)
@@ -139,8 +139,8 @@ interface nbt
                nb_flags  nb_flags;
        } nbt_status_name;
 
-       typedef [gensize] struct {
-               [value(ndr_size_nbt_rdata_status(r, ndr->flags)-2)] uint16 length;
+       typedef struct {
+               [value(r->num_names * 18 + 47)] uint16 length;
                uint8 num_names;
                nbt_status_name names[num_names];
                nbt_statistics  statistics;
index e38b9d394aa7adc79dfe35c296ebe32a95d587a1..61b3c9ec4dcaaea8f11f23dee4db20d7caed4061 100644 (file)
@@ -887,7 +887,7 @@ NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
                d_len = (flags & LIBNDR_FLAG_STR_FIXLEN32)?32:15;
                NDR_PUSH_NEED_BYTES(ndr, byte_mul*d_len);
                ret = convert_string(CH_UNIX, chset, 
-                                    s, s_len + 1,
+                                    s, s_len,
                                     ndr->data+ndr->offset, byte_mul*d_len);
                if (ret == -1) {
                        return ndr_push_error(ndr, NDR_ERR_CHARCNV, 
index e3f52a64e6e44ec8075dd790fc7878d128eb3f2f..2501c014176d3bd34de0d296cc0b1207e5a7b937 100644 (file)
@@ -9,6 +9,7 @@ ADD_OBJ_FILES = \
                nbt_server/interfaces.o \
                nbt_server/register.o \
                nbt_server/query.o \
+               nbt_server/nodestatus.o \
                nbt_server/winsserver.o \
                nbt_server/packet.o
 REQUIRED_SUBSYSTEMS = \
index 49a07ca95e522361713d3a40511534cf41610e78..602d7b2e46569b73693cde0282a88a6681680baf 100644 (file)
@@ -62,3 +62,10 @@ struct nbt_server {
 
 
 
+/* check a condition on an incoming packet */
+#define NBT_ASSERT_PACKET(packet, src_address, test) do { \
+       if (!(test)) { \
+               nbt_bad_packet(packet, src_address, #test); \
+               return; \
+       } \
+} while (0)
diff --git a/source/nbt_server/nodestatus.c b/source/nbt_server/nodestatus.c
new file mode 100644 (file)
index 0000000..f57c86d
--- /dev/null
@@ -0,0 +1,124 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   answer node status queries
+
+   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 "dlinklist.h"
+#include "system/network.h"
+#include "nbt_server/nbt_server.h"
+
+/*
+  send a name status reply
+*/
+static void nbt_node_status_reply(struct nbt_name_socket *nbtsock, 
+                                 struct nbt_name_packet *request_packet, 
+                                 const char *src_address, int src_port,
+                                 struct nbt_name *name, 
+                                 struct nbt_interface *iface)
+{
+       struct nbt_name_packet *packet;
+       uint32_t name_count;
+       struct nbt_iface_name *iname;
+       
+       /* 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_AUTHORITIVE;
+
+       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++;
+               }
+       }
+       /* 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<%02x> to %s:%d\n", 
+                name->name, name->type, src_address, src_port));
+       
+       nbt_name_reply_send(nbtsock, src_address, src_port, packet);
+
+failed:
+       talloc_free(packet);
+}
+
+
+/*
+  answer a node status query
+*/
+void nbt_query_status(struct nbt_name_socket *nbtsock, 
+                     struct nbt_name_packet *packet, 
+                     const char *src_address, int src_port)
+{
+       struct nbt_interface *iface;
+       struct nbt_name *name;
+       struct nbt_iface_name *iname;
+
+       /* find the interface for this query */
+       iface = nbt_iface_find(nbtsock, src_address);
+
+       NBT_ASSERT_PACKET(packet, src_address, packet->qdcount == 1);
+       NBT_ASSERT_PACKET(packet, src_address, packet->questions[0].question_type == NBT_QTYPE_STATUS);
+       NBT_ASSERT_PACKET(packet, src_address, packet->questions[0].question_class == NBT_QCLASS_IP);
+
+       /* see if we have the requested name on this interface */
+       name = &packet->questions[0].name;
+
+       iname = nbt_find_iname(iface, name, NBT_NM_ACTIVE);
+       if (iname == NULL) {
+               DEBUG(7,("Node status query for %s<%02x> from %s - not found on %s\n",
+                        name->name, name->type, src_address, iface->ip_address));
+               return;
+       }
+
+       nbt_node_status_reply(nbtsock, packet, src_address, src_port, &iname->name, iface);
+}
index c962a691c637182a6f3a617fffb5bd840ccbb1fe..859a9c7f26bcd742efce860e12043a0bb16a3f33 100644 (file)
 #include "system/network.h"
 #include "nbt_server/nbt_server.h"
 
-/* check a condition on an incoming packet */
-#define NBT_ASSERT_PACKET(packet, src_address, test) do { \
-       if (!(test)) { \
-               nbt_bad_packet(packet, src_address, #test); \
-               return; \
-       } \
-} while (0)
-
-
 /*
   send a name query reply
 */
@@ -92,6 +83,13 @@ void nbt_request_query(struct nbt_name_socket *nbtsock,
        struct nbt_iface_name *iname;
        struct nbt_name *name;
 
+       /* see if its a node status query */
+       if (packet->qdcount == 1 &&
+           packet->questions[0].question_type == NBT_QTYPE_STATUS) {
+               nbt_query_status(nbtsock, packet, src_address, src_port);
+               return;
+       }
+
        /* if its a WINS query then direct to our WINS server */
        if ((packet->operation & NBT_FLAG_RECURSION_DESIRED) &&
            !(packet->operation & NBT_FLAG_BROADCAST)) {
index 7f7c291cf0f3ba92f6246db0c5fd8ebe802ceb8b..e5033f4f5eb5176d90572e607ad174af9dde3802 100644 (file)
@@ -88,7 +88,7 @@ static void nbt_register_name_iface(struct nbt_interface *iface,
        iname->ttl               = lp_parm_int(-1, "nbtd", "bcast_ttl", 300000);
        iname->registration_time = timeval_zero();
 
-       DLIST_ADD(iface->names, iname);
+       DLIST_ADD_END(iface->names, iname, struct nbt_iface_name *);
 
        if (nb_flags & NBT_NM_PERMANENT) {
                /* permanent names are not announced and are immediately active */
@@ -145,8 +145,12 @@ void nbt_register_names(struct nbt_server *nbtsrv)
        nbt_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_CLIENT, nb_flags);
        nbt_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_USER,   nb_flags);
        nbt_register_name(nbtsrv, lp_netbios_name(), NBT_NAME_SERVER, nb_flags);
-       nbt_register_name(nbtsrv, lp_workgroup(),    NBT_NAME_CLIENT, nb_flags | NBT_NM_GROUP);
-       nbt_register_name(nbtsrv, lp_workgroup(),    NBT_NAME_SERVER, nb_flags | NBT_NM_GROUP);
-       nbt_register_name(nbtsrv, "__SAMBA__",       NBT_NAME_CLIENT, nb_flags | NBT_NM_PERMANENT);
-       nbt_register_name(nbtsrv, "__SAMBA__",       NBT_NAME_SERVER, nb_flags | NBT_NM_PERMANENT);
+
+       nb_flags |= NBT_NM_GROUP;
+       nbt_register_name(nbtsrv, lp_workgroup(),    NBT_NAME_CLIENT, nb_flags);
+
+       nb_flags |= NBT_NM_PERMANENT;
+       nbt_register_name(nbtsrv, "__SAMBA__",       NBT_NAME_CLIENT, nb_flags);
+       nbt_register_name(nbtsrv, "__SAMBA__",       NBT_NAME_SERVER, nb_flags);
+       nbt_register_name(nbtsrv, "*",               NBT_NAME_CLIENT, nb_flags);
 }