LCOV - code coverage report
Current view: top level - libcli/nbt/tools - nmblookup.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 80 196 40.8 %
Date: 2021-09-23 10:06:22 Functions: 4 7 57.1 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    NBT client - used to lookup netbios names
       5             : 
       6             :    Copyright (C) Andrew Tridgell 1994-2005
       7             :    Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
       8             :    
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             :    
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             :    
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             :    
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "lib/cmdline/cmdline.h"
      26             : #include "lib/socket/socket.h"
      27             : #include "lib/events/events.h"
      28             : #include "system/network.h"
      29             : #include "system/locale.h"
      30             : #include "lib/socket/netif.h"
      31             : #include "librpc/gen_ndr/nbt.h"
      32             : #include "../libcli/nbt/libnbt.h"
      33             : #include "param/param.h"
      34             : 
      35             : #include <string.h>
      36             : 
      37             : #define MAX_NETBIOSNAME_LEN 16
      38             : 
      39             : /* command line options */
      40             : static struct {
      41             :         const char *broadcast_address;
      42             :         const char *unicast_address;
      43             :         bool find_master;
      44             :         bool wins_lookup;
      45             :         bool node_status;
      46             :         bool root_port;
      47             :         bool lookup_by_ip;
      48             :         bool case_sensitive;
      49             : } options;
      50             : 
      51             : /*
      52             :   clean any binary from a node name
      53             : */
      54           0 : static const char *clean_name(TALLOC_CTX *mem_ctx, const char *name)
      55             : {
      56           0 :         char *ret = talloc_strdup(mem_ctx, name);
      57             :         int i;
      58           0 :         for (i=0;ret[i];i++) {
      59           0 :                 if (!isprint((unsigned char)ret[i])) ret[i] = '.';
      60             :         }
      61           0 :         return ret;
      62             : }
      63             : 
      64             : /*
      65             :   turn a node status flags field into a string
      66             : */
      67           0 : static char *node_status_flags(TALLOC_CTX *mem_ctx, uint16_t flags)
      68             : {
      69             :         char *ret;
      70           0 :         const char *group = "       ";
      71           0 :         const char *type = "B";
      72             : 
      73           0 :         if (flags & NBT_NM_GROUP) {
      74           0 :                 group = "<GROUP>";
      75             :         }
      76             : 
      77           0 :         switch (flags & NBT_NM_OWNER_TYPE) {
      78           0 :         case NBT_NODE_B: 
      79           0 :                 type = "B";
      80           0 :                 break;
      81           0 :         case NBT_NODE_P: 
      82           0 :                 type = "P";
      83           0 :                 break;
      84           0 :         case NBT_NODE_M: 
      85           0 :                 type = "M";
      86           0 :                 break;
      87           0 :         case NBT_NODE_H: 
      88           0 :                 type = "H";
      89           0 :                 break;
      90             :         }
      91             : 
      92           0 :         ret = talloc_asprintf(mem_ctx, "%s %s", group, type);
      93             : 
      94           0 :         if (flags & NBT_NM_DEREGISTER) {
      95           0 :                 ret = talloc_asprintf_append_buffer(ret, " <DEREGISTERING>");
      96             :         }
      97           0 :         if (flags & NBT_NM_CONFLICT) {
      98           0 :                 ret = talloc_asprintf_append_buffer(ret, " <CONFLICT>");
      99             :         }
     100           0 :         if (flags & NBT_NM_ACTIVE) {
     101           0 :                 ret = talloc_asprintf_append_buffer(ret, " <ACTIVE>");
     102             :         }
     103           0 :         if (flags & NBT_NM_PERMANENT) {
     104           0 :                 ret = talloc_asprintf_append_buffer(ret, " <PERMANENT>");
     105             :         }
     106             :         
     107           0 :         return ret;
     108             : }
     109             : 
     110             : /* do a single node status */
     111           0 : static bool do_node_status(struct nbt_name_socket *nbtsock,
     112             :                            const char *addr, uint16_t port)
     113             : {
     114             :         struct nbt_name_status io;
     115             :         NTSTATUS status;
     116             : 
     117           0 :         io.in.name.name = "*";
     118           0 :         io.in.name.type = NBT_NAME_CLIENT;
     119           0 :         io.in.name.scope = NULL;
     120           0 :         io.in.dest_addr = addr;
     121           0 :         io.in.dest_port = port;
     122           0 :         io.in.timeout = 1;
     123           0 :         io.in.retries = 2;
     124             : 
     125           0 :         status = nbt_name_status(nbtsock, nbtsock, &io);
     126           0 :         if (NT_STATUS_IS_OK(status)) {
     127             :                 int i;
     128           0 :                 printf("Node status reply from %s\n",
     129             :                        io.out.reply_from);
     130           0 :                 for (i=0;i<io.out.status.num_names;i++) {
     131           0 :                         d_printf("\t%-16s <%02x>  %s\n", 
     132           0 :                                  clean_name(nbtsock, io.out.status.names[i].name),
     133           0 :                                  io.out.status.names[i].type,
     134           0 :                                  node_status_flags(nbtsock, io.out.status.names[i].nb_flags));
     135             :                 }
     136           0 :                 printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
     137           0 :                        io.out.status.statistics.unit_id[0],
     138           0 :                        io.out.status.statistics.unit_id[1],
     139           0 :                        io.out.status.statistics.unit_id[2],
     140           0 :                        io.out.status.statistics.unit_id[3],
     141           0 :                        io.out.status.statistics.unit_id[4],
     142           0 :                        io.out.status.statistics.unit_id[5]);
     143           0 :                 return true;
     144             :         }
     145             : 
     146           0 :         return false;
     147             : }
     148             : 
     149             : /* do a single node query */
     150         896 : static NTSTATUS do_node_query(struct nbt_name_socket *nbtsock,
     151             :                               const char *addr, 
     152             :                               uint16_t port,
     153             :                               const char *node_name, 
     154             :                               enum nbt_name_type node_type,
     155             :                               bool broadcast)
     156             : {
     157             :         struct nbt_name_query io;
     158             :         NTSTATUS status;
     159             :         int i;
     160             : 
     161         896 :         io.in.name.name = node_name;
     162         896 :         io.in.name.type = node_type;
     163         896 :         io.in.name.scope = NULL;
     164         896 :         io.in.dest_addr = addr;
     165         896 :         io.in.dest_port = port;
     166         896 :         io.in.broadcast = broadcast;
     167         896 :         io.in.wins_lookup = options.wins_lookup;
     168         896 :         io.in.timeout = 1;
     169         896 :         io.in.retries = 2;
     170             : 
     171         896 :         status = nbt_name_query(nbtsock, nbtsock, &io);
     172         896 :         NT_STATUS_NOT_OK_RETURN(status);
     173             : 
     174        1500 :         for (i=0;i<io.out.num_addrs;i++) {
     175        1320 :                 printf("%s %s<%02x>\n",
     176         762 :                        io.out.reply_addrs[i],
     177             :                        io.out.name.name,
     178         762 :                        io.out.name.type);
     179             :         }
     180         762 :         if (options.node_status && io.out.num_addrs > 0) {
     181           0 :                 do_node_status(nbtsock, io.out.reply_addrs[0], port);
     182             :         }
     183             : 
     184         762 :         return status;
     185             : }
     186             : 
     187             : 
     188         829 : static bool process_one(struct loadparm_context *lp_ctx, struct tevent_context *ev,
     189             :                         struct interface *ifaces, const char *name, int nbt_port)
     190             : {
     191         829 :         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
     192         829 :         enum nbt_name_type node_type = NBT_NAME_CLIENT;
     193             :         char *node_name, *p;
     194             :         struct socket_address *all_zero_addr;
     195             :         struct nbt_name_socket *nbtsock;
     196         829 :         NTSTATUS status = NT_STATUS_OK;
     197             :         size_t nbt_len;
     198         829 :         bool ret = true;
     199             : 
     200         829 :         if (!options.case_sensitive) {
     201         829 :                 name = strupper_talloc(tmp_ctx, name);
     202             :         }
     203             :         
     204         829 :         if (options.find_master) {
     205           0 :                 node_type = NBT_NAME_MASTER;
     206           0 :                 if (*name == '-' || *name == '_') {
     207           0 :                         name = "\01\02__MSBROWSE__\02";
     208           0 :                         node_type = NBT_NAME_MS;
     209             :                 }
     210             :         }
     211             : 
     212         829 :         p = strchr(name, '#');
     213         829 :         if (p) {
     214           0 :                 node_name = talloc_strndup(tmp_ctx, name, PTR_DIFF(p,name));
     215           0 :                 node_type = (enum nbt_name_type)strtol(p+1, NULL, 16);
     216             :         } else {
     217         829 :                 node_name = talloc_strdup(tmp_ctx, name);
     218             :         }
     219             : 
     220         829 :         nbt_len = strlen(node_name);
     221         829 :         if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
     222           0 :                 printf("The specified netbios name [%s] is too long.\n",
     223             :                        node_name);
     224           0 :                 talloc_free(tmp_ctx);
     225           0 :                 return false;
     226             :         }
     227             : 
     228         829 :         nbtsock = nbt_name_socket_init(tmp_ctx, ev);
     229             :         
     230         829 :         if (options.root_port) {
     231           0 :                 all_zero_addr = socket_address_from_strings(tmp_ctx, nbtsock->sock->backend_name, 
     232             :                                                             "0.0.0.0", NBT_NAME_SERVICE_PORT);
     233             :                 
     234           0 :                 if (!all_zero_addr) {
     235           0 :                         talloc_free(tmp_ctx);
     236           0 :                         return false;
     237             :                 }
     238             : 
     239           0 :                 status = socket_listen(nbtsock->sock, all_zero_addr, 0, 0);
     240           0 :                 if (!NT_STATUS_IS_OK(status)) {
     241           0 :                         printf("Failed to bind to local port 137 - %s\n", nt_errstr(status));
     242           0 :                         talloc_free(tmp_ctx);
     243           0 :                         return false;
     244             :                 }
     245             :         }
     246             : 
     247         829 :         if (options.lookup_by_ip) {
     248           0 :                 ret = do_node_status(nbtsock, name, nbt_port);
     249           0 :                 talloc_free(tmp_ctx);
     250           0 :                 return ret;
     251             :         }
     252             : 
     253         829 :         if (options.broadcast_address) {
     254           0 :                 status = do_node_query(nbtsock, options.broadcast_address, nbt_port,
     255             :                                        node_name, node_type, true);
     256         829 :         } else if (options.unicast_address) {
     257         381 :                 status = do_node_query(nbtsock, options.unicast_address, 
     258             :                                        nbt_port, node_name, node_type, false);
     259             :         } else {
     260             :                 int i, num_interfaces;
     261             : 
     262         448 :                 num_interfaces = iface_list_count(ifaces);
     263         582 :                 for (i=0;i<num_interfaces;i++) {
     264         515 :                         const char *bcast = iface_list_n_bcast(ifaces, i);
     265         515 :                         if (bcast == NULL) continue;
     266         515 :                         status = do_node_query(nbtsock, bcast, nbt_port, 
     267             :                                                node_name, node_type, true);
     268         515 :                         if (NT_STATUS_IS_OK(status)) break;
     269             :                 }
     270             :         }
     271             : 
     272         829 :         if (!NT_STATUS_IS_OK(status)) {
     273          69 :                 printf("Lookup failed - %s\n", nt_errstr(status));
     274          67 :                 ret = false;
     275             :         }
     276             : 
     277         829 :         talloc_free(tmp_ctx);
     278         803 :         return ret;
     279             : }
     280             : 
     281             : /*
     282             :   main program
     283             : */
     284         829 : int main(int argc, const char *argv[])
     285             : {
     286         829 :         bool ret = true;
     287             :         struct interface *ifaces;
     288             :         struct tevent_context *ev;
     289             :         poptContext pc;
     290             :         int opt;
     291         829 :         struct loadparm_context *lp_ctx = NULL;
     292         829 :         TALLOC_CTX *mem_ctx = NULL;
     293             :         bool ok;
     294             :         enum {
     295             :                 OPT_BROADCAST_ADDRESS   = 1000,
     296             :                 OPT_UNICAST_ADDRESS,
     297             :                 OPT_FIND_MASTER,
     298             :                 OPT_WINS_LOOKUP,
     299             :                 OPT_NODE_STATUS,
     300             :                 OPT_ROOT_PORT,
     301             :                 OPT_LOOKUP_BY_IP,
     302             :                 OPT_CASE_SENSITIVE
     303             :         };
     304        2487 :         struct poptOption long_options[] = {
     305             :                 POPT_AUTOHELP
     306             :                 {
     307             :                         .longName   = "broadcast",
     308             :                         .shortName  = 'B',
     309             :                         .argInfo    = POPT_ARG_STRING,
     310             :                         .arg        = NULL,
     311             :                         .val        = OPT_BROADCAST_ADDRESS,
     312             :                         .descrip    = "Specify address to use for broadcasts",
     313             :                         .argDescrip = "BROADCAST-ADDRESS"
     314             :                 },
     315             :                 {
     316             :                         .longName   = "unicast",
     317             :                         .shortName  = 'U',
     318             :                         .argInfo    = POPT_ARG_STRING,
     319             :                         .arg        = NULL,
     320             :                         .val        = OPT_UNICAST_ADDRESS,
     321             :                         .descrip    = "Specify address to use for unicast",
     322             :                         .argDescrip = NULL
     323             :                 },
     324             :                 {
     325             :                         .longName   = "master-browser",
     326             :                         .shortName  = 'M',
     327             :                         .argInfo    = POPT_ARG_NONE,
     328             :                         .arg        = NULL,
     329             :                         .val        = OPT_FIND_MASTER,
     330             :                         .descrip    = "Search for a master browser",
     331             :                         .argDescrip = NULL
     332             :                 },
     333             :                 {
     334             :                         .longName   = "wins",
     335             :                         .shortName  = 'W',
     336             :                         .argInfo    = POPT_ARG_NONE,
     337             :                         .arg        = NULL,
     338             :                         .val        = OPT_WINS_LOOKUP,
     339             :                         .descrip    = "Do a WINS lookup",
     340             :                         .argDescrip = NULL
     341             :                 },
     342             :                 {
     343             :                         .longName   = "status",
     344             :                         .shortName  = 'S',
     345             :                         .argInfo    = POPT_ARG_NONE,
     346             :                         .arg        = NULL,
     347             :                         .val        = OPT_NODE_STATUS,
     348             :                         .descrip    = "Lookup node status as well",
     349             :                         .argDescrip = NULL
     350             :                 },
     351             :                 {
     352             :                         .longName   = "root-port",
     353             :                         .shortName  = 'r',
     354             :                         .argInfo    = POPT_ARG_NONE,
     355             :                         .arg        = NULL,
     356             :                         .val        = OPT_ROOT_PORT,
     357             :                         .descrip    = "Use root port 137 (Win95 only replies to this)",
     358             :                         .argDescrip = NULL
     359             :                 },
     360             :                 {
     361             :                         .longName   = "lookup-by-ip",
     362             :                         .shortName  = 'A',
     363             :                         .argInfo    = POPT_ARG_NONE,
     364             :                         .arg        = NULL,
     365             :                         .val        = OPT_LOOKUP_BY_IP,
     366             :                         .descrip    = "Do a node status on <name> as an IP Address",
     367             :                         .argDescrip = NULL
     368             :                 },
     369             :                 {
     370             :                         .longName   = "case-sensitive",
     371             :                         .shortName  = 0,
     372             :                         .argInfo    = POPT_ARG_NONE,
     373             :                         .arg        = NULL,
     374             :                         .val        = OPT_CASE_SENSITIVE,
     375             :                         .descrip    = "Don't uppercase the name before sending",
     376             :                         .argDescrip = NULL
     377             :                 },
     378         829 :                 POPT_COMMON_SAMBA
     379         829 :                 POPT_COMMON_VERSION
     380             :                 POPT_TABLEEND
     381             :         };
     382             : 
     383         829 :         mem_ctx = talloc_init("nmblookup.c/main");
     384         829 :         if (mem_ctx == NULL) {
     385           0 :                 exit(ENOMEM);
     386             :         }
     387             : 
     388         829 :         ok = samba_cmdline_init(mem_ctx,
     389             :                                 SAMBA_CMDLINE_CONFIG_CLIENT,
     390             :                                 false /* require_smbconf */);
     391         829 :         if (!ok) {
     392           0 :                 DBG_ERR("Failed to init cmdline parser!\n");
     393           0 :                 TALLOC_FREE(mem_ctx);
     394           0 :                 exit(1);
     395             :         }
     396             : 
     397         829 :         pc = samba_popt_get_context(getprogname(),
     398             :                                     argc,
     399             :                                     argv,
     400             :                                     long_options,
     401             :                                     POPT_CONTEXT_KEEP_FIRST);
     402         829 :         if (pc == NULL) {
     403           0 :                 DBG_ERR("Failed to setup popt context!\n");
     404           0 :                 TALLOC_FREE(mem_ctx);
     405           0 :                 exit(1);
     406             :         }
     407             : 
     408         829 :         poptSetOtherOptionHelp(pc, "<NODE> ...");
     409             : 
     410         981 :         while ((opt = poptGetNextOpt(pc)) != -1) {
     411         381 :                 switch(opt) {
     412           0 :                 case OPT_BROADCAST_ADDRESS:
     413           0 :                         options.broadcast_address = poptGetOptArg(pc);
     414           0 :                         break;
     415         381 :                 case OPT_UNICAST_ADDRESS:
     416         381 :                         options.unicast_address = poptGetOptArg(pc);
     417         381 :                         break;
     418           0 :                 case OPT_FIND_MASTER:
     419           0 :                         options.find_master = true;
     420           0 :                         break;
     421           0 :                 case OPT_WINS_LOOKUP:
     422           0 :                         options.wins_lookup = true;
     423           0 :                         break;
     424           0 :                 case OPT_NODE_STATUS:
     425           0 :                         options.node_status = true;
     426           0 :                         break;
     427           0 :                 case OPT_ROOT_PORT:
     428           0 :                         options.root_port = true;
     429           0 :                         break;
     430           0 :                 case OPT_LOOKUP_BY_IP:
     431           0 :                         options.lookup_by_ip = true;
     432           0 :                         break;
     433           0 :                 case OPT_CASE_SENSITIVE:
     434           0 :                         options.case_sensitive = true;
     435           0 :                         break;
     436           0 :                 case POPT_ERROR_BADOPT:
     437           0 :                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
     438             :                                 poptBadOption(pc, 0), poptStrerror(opt));
     439           0 :                         poptPrintUsage(pc, stderr, 0);
     440           0 :                         exit(1);
     441             :                 }
     442             :         }
     443             : 
     444             :         /* swallow argv[0] */
     445         829 :         poptGetArg(pc);
     446             : 
     447         829 :         if(!poptPeekArg(pc)) { 
     448           0 :                 poptPrintUsage(pc, stderr, 0);
     449           0 :                 TALLOC_FREE(mem_ctx);
     450           0 :                 exit(1);
     451             :         }
     452             : 
     453         829 :         lp_ctx = samba_cmdline_get_lp_ctx();
     454             : 
     455         829 :         load_interface_list(mem_ctx, lp_ctx, &ifaces);
     456             : 
     457         829 :         ev = s4_event_context_init(mem_ctx);
     458             : 
     459        2239 :         while (poptPeekArg(pc)) {
     460         829 :                 const char *name = poptGetArg(pc);
     461             : 
     462         829 :                 ret &= process_one(lp_ctx,
     463             :                                    ev,
     464             :                                    ifaces,
     465             :                                    name,
     466             :                                    lpcfg_nbt_port(lp_ctx));
     467             :         }
     468             : 
     469         829 :         poptFreeContext(pc);
     470         829 :         TALLOC_FREE(mem_ctx);
     471             : 
     472         829 :         if (!ret) {
     473          65 :                 return 1;
     474             :         }
     475             : 
     476         762 :         return 0;
     477             : }

Generated by: LCOV version 1.13