LCOV - code coverage report
Current view: top level - source3/utils - nmblookup.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 76 189 40.2 %
Date: 2024-04-21 15:09:00 Functions: 3 6 50.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    NBT client - used to lookup netbios names
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             :    Copyright (C) Jelmer Vernooij 2003 (Conversion to popt)
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : 
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "lib/cmdline/cmdline.h"
      24             : #include "libsmb/nmblib.h"
      25             : #include "libsmb/namequery.h"
      26             : #include "lib/util/string_wrappers.h"
      27             : 
      28             : static bool give_flags = false;
      29             : static bool use_bcast = true;
      30             : static bool got_bcast = false;
      31             : static struct sockaddr_storage bcast_addr;
      32             : static bool recursion_desired = false;
      33             : static bool translate_addresses = false;
      34             : static int ServerFD= -1;
      35             : static bool RootPort = false;
      36             : static bool find_status = false;
      37             : 
      38             : /****************************************************************************
      39             :  Open the socket communication.
      40             : **************************************************************************/
      41             : 
      42         333 : static bool open_sockets(void)
      43             : {
      44             :         struct sockaddr_storage ss;
      45         333 :         const char *sock_addr = lp_nbt_client_socket_address();
      46             : 
      47         333 :         if (!interpret_string_addr(&ss, sock_addr,
      48             :                                 AI_NUMERICHOST|AI_PASSIVE)) {
      49           0 :                 DEBUG(0,("open_sockets: unable to get socket address "
      50             :                                         "from string %s\n", sock_addr));
      51           0 :                 return false;
      52             :         }
      53         333 :         ServerFD = open_socket_in(
      54         333 :                 SOCK_DGRAM, &ss, (RootPort ? 137 : 0), true);
      55         333 :         if (ServerFD < 0) {
      56           0 :                 if (RootPort) {
      57           0 :                         DBG_ERR("open_socket_in failed: %s\n",
      58             :                                 strerror(-ServerFD));
      59             :                 } else {
      60           0 :                         DBG_NOTICE("open_socket_in failed: %s\n",
      61             :                                    strerror(-ServerFD));
      62             :                 }
      63           0 :                 return false;
      64             :         }
      65             : 
      66         333 :         set_socket_options( ServerFD, "SO_BROADCAST" );
      67             : 
      68         333 :         DEBUG(3, ("Socket opened.\n"));
      69         333 :         return true;
      70             : }
      71             : 
      72             : /****************************************************************************
      73             : turn a node status flags field into a string
      74             : ****************************************************************************/
      75           0 : static char *node_status_flags(unsigned char flags)
      76             : {
      77             :         static fstring ret;
      78           0 :         fstrcpy(ret,"");
      79             : 
      80           0 :         fstrcat(ret, (flags & 0x80) ? "<GROUP> " : "        ");
      81           0 :         if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
      82           0 :         if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
      83           0 :         if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
      84           0 :         if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
      85           0 :         if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
      86           0 :         if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
      87           0 :         if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
      88           0 :         if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
      89             : 
      90           0 :         return ret;
      91             : }
      92             : 
      93             : /****************************************************************************
      94             :  Turn the NMB Query flags into a string.
      95             : ****************************************************************************/
      96             : 
      97           0 : static char *query_flags(int flags)
      98             : {
      99             :         static fstring ret1;
     100           0 :         fstrcpy(ret1, "");
     101             : 
     102           0 :         if (flags & NM_FLAGS_RS) fstrcat(ret1, "Response ");
     103           0 :         if (flags & NM_FLAGS_AA) fstrcat(ret1, "Authoritative ");
     104           0 :         if (flags & NM_FLAGS_TC) fstrcat(ret1, "Truncated ");
     105           0 :         if (flags & NM_FLAGS_RD) fstrcat(ret1, "Recursion_Desired ");
     106           0 :         if (flags & NM_FLAGS_RA) fstrcat(ret1, "Recursion_Available ");
     107           0 :         if (flags & NM_FLAGS_B)  fstrcat(ret1, "Broadcast ");
     108             : 
     109           0 :         return ret1;
     110             : }
     111             : 
     112             : /****************************************************************************
     113             :  Do a node status query.
     114             : ****************************************************************************/
     115             : 
     116           0 : static bool do_node_status(const char *name,
     117             :                 int type,
     118             :                 struct sockaddr_storage *pss)
     119             : {
     120             :         struct nmb_name nname;
     121           0 :         size_t count = 0;
     122             :         size_t i, j;
     123             :         struct node_status *addrs;
     124             :         struct node_status_extra extra;
     125             :         fstring cleanname;
     126             :         char addr[INET6_ADDRSTRLEN];
     127             :         NTSTATUS status;
     128             : 
     129           0 :         print_sockaddr(addr, sizeof(addr), pss);
     130           0 :         d_printf("Looking up status of %s\n",addr);
     131           0 :         make_nmb_name(&nname, name, type);
     132           0 :         status = node_status_query(talloc_tos(), &nname, pss,
     133             :                                    &addrs, &count, &extra);
     134           0 :         if (NT_STATUS_IS_OK(status)) {
     135           0 :                 for (i=0;i<count;i++) {
     136           0 :                         pull_ascii_fstring(cleanname, addrs[i].name);
     137           0 :                         for (j=0;cleanname[j];j++) {
     138           0 :                                 if (!isprint((int)cleanname[j])) {
     139           0 :                                         cleanname[j] = '.';
     140             :                                 }
     141             :                         }
     142           0 :                         d_printf("\t%-15s <%02x> - %s\n",
     143           0 :                                cleanname,addrs[i].type,
     144           0 :                                node_status_flags(addrs[i].flags));
     145             :                 }
     146           0 :                 d_printf("\n\tMAC Address = %02X-%02X-%02X-%02X-%02X-%02X\n",
     147           0 :                                 extra.mac_addr[0], extra.mac_addr[1],
     148           0 :                                 extra.mac_addr[2], extra.mac_addr[3],
     149           0 :                                 extra.mac_addr[4], extra.mac_addr[5]);
     150           0 :                 d_printf("\n");
     151           0 :                 TALLOC_FREE(addrs);
     152           0 :                 return true;
     153             :         } else {
     154           0 :                 d_printf("No reply from %s\n\n",addr);
     155           0 :                 return false;
     156             :         }
     157             : }
     158             : 
     159             : 
     160             : /****************************************************************************
     161             :  Send out one query.
     162             : ****************************************************************************/
     163             : 
     164         333 : static bool query_one(const char *lookup, unsigned int lookup_type)
     165             : {
     166         333 :         size_t j, count = 0;
     167         333 :         uint8_t flags = 0;
     168         333 :         struct sockaddr_storage *ip_list=NULL;
     169         333 :         NTSTATUS status = NT_STATUS_NOT_FOUND;
     170             : 
     171         333 :         if (got_bcast) {
     172             :                 char addr[INET6_ADDRSTRLEN];
     173         129 :                 print_sockaddr(addr, sizeof(addr), &bcast_addr);
     174         129 :                 d_printf("querying %s on %s\n", lookup, addr);
     175         258 :                 status = name_query(lookup,lookup_type,use_bcast,
     176         129 :                                     use_bcast?true:recursion_desired,
     177             :                                     &bcast_addr, talloc_tos(),
     178             :                                     &ip_list, &count, &flags);
     179             :         } else {
     180         204 :                 status = name_resolve_bcast(talloc_tos(),
     181             :                                             lookup,
     182             :                                             lookup_type,
     183             :                                             &ip_list,
     184             :                                             &count);
     185             :         }
     186             : 
     187         333 :         if (!NT_STATUS_IS_OK(status)) {
     188         115 :                 return false;
     189             :         }
     190             : 
     191         218 :         if (give_flags) {
     192           0 :                 d_printf("Flags: %s\n", query_flags(flags));
     193             :         }
     194             : 
     195         440 :         for (j=0;j<count;j++) {
     196             :                 char addr[INET6_ADDRSTRLEN];
     197         222 :                 if (translate_addresses) {
     198             :                         char h_name[MAX_DNS_NAME_LENGTH];
     199           0 :                         h_name[0] = '\0';
     200           0 :                         if (sys_getnameinfo((const struct sockaddr *)&ip_list[j],
     201             :                                         sizeof(struct sockaddr_storage),
     202             :                                         h_name, sizeof(h_name),
     203             :                                         NULL, 0,
     204             :                                         NI_NAMEREQD)) {
     205           0 :                                 continue;
     206             :                         }
     207           0 :                         d_printf("%s, ", h_name);
     208             :                 }
     209         222 :                 print_sockaddr(addr, sizeof(addr), &ip_list[j]);
     210         222 :                 d_printf("%s %s<%02x>\n", addr,lookup, lookup_type);
     211             :                 /* We can only do find_status if the ip address returned
     212             :                    was valid - ie. name_query returned true.
     213             :                  */
     214         222 :                 if (find_status) {
     215           0 :                         if (!do_node_status(lookup, lookup_type, &ip_list[j])) {
     216           0 :                                 status = NT_STATUS_UNSUCCESSFUL;
     217             :                         }
     218             :                 }
     219             :         }
     220             : 
     221         218 :         TALLOC_FREE(ip_list);
     222             : 
     223         218 :         return NT_STATUS_IS_OK(status);
     224             : }
     225             : 
     226             : 
     227             : /****************************************************************************
     228             :   main program
     229             : ****************************************************************************/
     230             : enum nmblookup_cmdline_options {
     231             :         CMDLINE_RECURSIVE = 1,
     232             : };
     233             : 
     234         333 : int main(int argc, const char *argv[])
     235             : {
     236             :         int opt;
     237         333 :         unsigned int lookup_type = 0x0;
     238             :         fstring lookup;
     239             :         static bool find_master=False;
     240             :         static bool lookup_by_ip = False;
     241         333 :         poptContext pc = NULL;
     242         333 :         TALLOC_CTX *frame = talloc_stackframe();
     243         333 :         int rc = 0;
     244             :         bool ok;
     245             : 
     246        1332 :         struct poptOption long_options[] = {
     247             :                 POPT_AUTOHELP
     248             :                 {
     249             :                         .longName   = "broadcast",
     250             :                         .shortName  = 'B',
     251             :                         .argInfo    = POPT_ARG_STRING,
     252             :                         .arg        = NULL,
     253             :                         .val        = 'B',
     254             :                         .descrip    = "Specify address to use for broadcasts",
     255             :                         .argDescrip = "BROADCAST-ADDRESS",
     256             :                 },
     257             :                 {
     258             :                         .longName   = "flags",
     259             :                         .shortName  = 'f',
     260             :                         .argInfo    = POPT_ARG_NONE,
     261             :                         .arg        = NULL,
     262             :                         .val        = 'f',
     263             :                         .descrip    = "List the NMB flags returned",
     264             :                 },
     265             :                 {
     266             :                         .longName   = "unicast",
     267             :                         .shortName  = 'U',
     268             :                         .argInfo    = POPT_ARG_STRING,
     269             :                         .arg        = NULL,
     270             :                         .val        = 'U',
     271             :                         .descrip    = "Specify address to use for unicast",
     272             :                 },
     273             :                 {
     274             :                         .longName   = "master-browser",
     275             :                         .shortName  = 'M',
     276             :                         .argInfo    = POPT_ARG_NONE,
     277             :                         .arg        = NULL,
     278             :                         .val        = 'M',
     279             :                         .descrip    = "Search for a master browser",
     280             :                 },
     281             :                 {
     282             :                         .longName   = "recursion",
     283             :                         .shortName  = 0,
     284             :                         .argInfo    = POPT_ARG_NONE,
     285             :                         .arg        = NULL,
     286             :                         .val        = CMDLINE_RECURSIVE,
     287             :                         .descrip    = "Set recursion desired in package",
     288             :                 },
     289             :                 {
     290             :                         .longName   = "status",
     291             :                         .shortName  = 'S',
     292             :                         .argInfo    = POPT_ARG_NONE,
     293             :                         .arg        = NULL,
     294             :                         .val        = 'S',
     295             :                         .descrip    = "Lookup node status as well",
     296             :                 },
     297             :                 {
     298             :                         .longName   = "translate",
     299             :                         .shortName  = 'T',
     300             :                         .argInfo    = POPT_ARG_NONE,
     301             :                         .arg        = NULL,
     302             :                         .val        = 'T',
     303             :                         .descrip    = "Translate IP addresses into names",
     304             :                 },
     305             :                 {
     306             :                         .longName   = "root-port",
     307             :                         .shortName  = 'r',
     308             :                         .argInfo    = POPT_ARG_NONE,
     309             :                         .arg        = NULL,
     310             :                         .val        = 'r',
     311             :                         .descrip    = "Use root port 137 (Win95 only replies to this)",
     312             :                 },
     313             :                 {
     314             :                         .longName   = "lookup-by-ip",
     315             :                         .shortName  = 'A',
     316             :                         .argInfo    = POPT_ARG_NONE,
     317             :                         .arg        = NULL,
     318             :                         .val        = 'A',
     319             :                         .descrip    = "Do a node status on <name> as an IP Address",
     320             :                 },
     321         333 :                 POPT_COMMON_SAMBA
     322         333 :                 POPT_COMMON_CONNECTION
     323         333 :                 POPT_COMMON_VERSION
     324             :                 POPT_TABLEEND
     325             :         };
     326             : 
     327         333 :         *lookup = 0;
     328             : 
     329         333 :         smb_init_locale();
     330             : 
     331         333 :         ok = samba_cmdline_init(frame,
     332             :                                 SAMBA_CMDLINE_CONFIG_CLIENT,
     333             :                                 false /* require_smbconf */);
     334         333 :         if (!ok) {
     335           0 :                 DBG_ERR("Failed to init cmdline parser!\n");
     336           0 :                 TALLOC_FREE(frame);
     337           0 :                 exit(1);
     338             :         }
     339             : 
     340         333 :         pc = samba_popt_get_context(getprogname(),
     341             :                                     argc,
     342             :                                     argv,
     343             :                                     long_options,
     344             :                                     POPT_CONTEXT_KEEP_FIRST);
     345         333 :         if (pc == NULL) {
     346           0 :                 DBG_ERR("Failed to setup popt context!\n");
     347           0 :                 TALLOC_FREE(frame);
     348           0 :                 exit(1);
     349             :         }
     350             : 
     351         333 :         poptSetOtherOptionHelp(pc, "<NODE> ...");
     352             : 
     353         539 :         while ((opt = poptGetNextOpt(pc)) != -1) {
     354         129 :                 switch (opt) {
     355           0 :                 case 'f':
     356           0 :                         give_flags = true;
     357           0 :                         break;
     358           0 :                 case 'M':
     359           0 :                         find_master = true;
     360           0 :                         break;
     361           0 :                 case CMDLINE_RECURSIVE:
     362           0 :                         recursion_desired = true;
     363           0 :                         break;
     364           0 :                 case 'S':
     365           0 :                         find_status = true;
     366           0 :                         break;
     367           0 :                 case 'r':
     368           0 :                         RootPort = true;
     369           0 :                         break;
     370           0 :                 case 'A':
     371           0 :                         lookup_by_ip = true;
     372           0 :                         break;
     373           0 :                 case 'B':
     374           0 :                         if (interpret_string_addr(&bcast_addr,
     375           0 :                                         poptGetOptArg(pc),
     376             :                                         NI_NUMERICHOST)) {
     377           0 :                                 got_bcast = True;
     378           0 :                                 use_bcast = True;
     379             :                         }
     380           0 :                         break;
     381         129 :                 case 'U':
     382         129 :                         if (interpret_string_addr(&bcast_addr,
     383         129 :                                         poptGetOptArg(pc),
     384             :                                         0)) {
     385         129 :                                 got_bcast = True;
     386         129 :                                 use_bcast = False;
     387             :                         }
     388         129 :                         break;
     389           0 :                 case 'T':
     390           0 :                         translate_addresses = !translate_addresses;
     391           0 :                         break;
     392           0 :                 case POPT_ERROR_BADOPT:
     393           0 :                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
     394             :                                 poptBadOption(pc, 0), poptStrerror(opt));
     395           0 :                         poptPrintUsage(pc, stderr, 0);
     396           0 :                         exit(1);
     397             :                 }
     398             :         }
     399             : 
     400         333 :         poptGetArg(pc); /* Remove argv[0] */
     401             : 
     402         333 :         if(!poptPeekArg(pc)) {
     403           0 :                 poptPrintUsage(pc, stderr, 0);
     404           0 :                 rc = 1;
     405           0 :                 goto out;
     406             :         }
     407             : 
     408         333 :         if (!open_sockets()) {
     409           0 :                 rc = 1;
     410           0 :                 goto out;
     411             :         }
     412             : 
     413         666 :         while(poptPeekArg(pc)) {
     414             :                 char *p;
     415             :                 struct in_addr ip;
     416             :                 size_t nbt_len;
     417             : 
     418         333 :                 fstrcpy(lookup,poptGetArg(pc));
     419             : 
     420         333 :                 if(lookup_by_ip) {
     421             :                         struct sockaddr_storage ss;
     422           0 :                         ip = interpret_addr2(lookup);
     423           0 :                         in_addr_to_sockaddr_storage(&ss, ip);
     424           0 :                         fstrcpy(lookup,"*");
     425           0 :                         if (!do_node_status(lookup, lookup_type, &ss)) {
     426           0 :                                 rc = 1;
     427             :                         }
     428           0 :                         continue;
     429             :                 }
     430             : 
     431         333 :                 if (find_master) {
     432           0 :                         if (*lookup == '-') {
     433           0 :                                 fstrcpy(lookup,"\01\02__MSBROWSE__\02");
     434           0 :                                 lookup_type = 1;
     435             :                         } else {
     436           0 :                                 lookup_type = 0x1d;
     437             :                         }
     438             :                 }
     439             : 
     440         333 :                 p = strchr_m(lookup,'#');
     441         333 :                 if (p) {
     442           3 :                         *p = '\0';
     443           3 :                         sscanf(++p,"%x",&lookup_type);
     444             :                 }
     445             : 
     446         333 :                 nbt_len = strlen(lookup);
     447         333 :                 if (nbt_len > MAX_NETBIOSNAME_LEN - 1) {
     448           0 :                         d_printf("The specified netbios name [%s] is too long!\n",
     449             :                                  lookup);
     450           0 :                         continue;
     451             :                 }
     452             : 
     453             : 
     454         333 :                 if (!query_one(lookup, lookup_type)) {
     455         115 :                         rc = 1;
     456         115 :                         d_printf( "name_query failed to find name %s", lookup );
     457         115 :                         if( 0 != lookup_type ) {
     458           0 :                                 d_printf( "#%02x", lookup_type );
     459             :                         }
     460         115 :                         d_printf( "\n" );
     461             :                 }
     462             :         }
     463             : 
     464         333 : out:
     465         333 :         poptFreeContext(pc);
     466         333 :         TALLOC_FREE(frame);
     467         333 :         return rc;
     468             : }

Generated by: LCOV version 1.14