root/src/vfs/smbfs/helpers/libsmb/namequery.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. name_query
  2. startlmhosts
  3. getlmhostsent
  4. endlmhosts
  5. resolve_bcast
  6. resolve_wins
  7. resolve_lmhosts
  8. resolve_hosts
  9. resolve_name
  10. find_master_ip

   1 /*
   2    Unix SMB/Netbios implementation.
   3    Version 1.9.
   4    name query routines
   5 
   6    Copyright (C) Andrew Tridgell 1994-1998
   7 
   8    Copyright (C) 2011-2019
   9    Free Software Foundation, Inc.
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 #include "includes.h"
  28 
  29 const char *unix_error_string (int error_num);
  30 extern pstring scope;
  31 extern int DEBUGLEVEL;
  32 
  33 /* nmbd.c sets this to True. */
  34 const BOOL global_in_nmbd = False;
  35 
  36 /****************************************************************************
  37   do a netbios name query to find someones IP
  38   returns an array of IP addresses or NULL if none
  39   *count will be set to the number of addresses returned
  40   ****************************************************************************/
  41 struct in_addr *
  42 name_query (int fd, const char *name, int name_type, BOOL bcast, BOOL recurse,
     /* [previous][next][first][last][top][bottom][index][help]  */
  43             struct in_addr to_ip, int *count, void (*fn) (struct packet_struct *))
  44 {
  45     BOOL found = False;
  46     int i, retries = 3;
  47     int retry_time = bcast ? 250 : 2000;
  48     struct timeval tval;
  49     struct packet_struct p;
  50     struct packet_struct *p2;
  51     struct nmb_packet *nmb = &p.packet.nmb;
  52     static int name_trn_id = 0;
  53     struct in_addr *ip_list = NULL;
  54 
  55     memset ((char *) &p, '\0', sizeof (p));
  56     (*count) = 0;
  57 
  58     if (!name_trn_id)
  59         name_trn_id = ((unsigned) time (NULL) % (unsigned) 0x7FFF) +
  60             ((unsigned) getpid () % (unsigned) 100);
  61     name_trn_id = (name_trn_id + 1) % (unsigned) 0x7FFF;
  62 
  63     nmb->header.name_trn_id = name_trn_id;
  64     nmb->header.opcode = 0;
  65     nmb->header.response = False;
  66     nmb->header.nm_flags.bcast = bcast;
  67     nmb->header.nm_flags.recursion_available = False;
  68     nmb->header.nm_flags.recursion_desired = recurse;
  69     nmb->header.nm_flags.trunc = False;
  70     nmb->header.nm_flags.authoritative = False;
  71     nmb->header.rcode = 0;
  72     nmb->header.qdcount = 1;
  73     nmb->header.ancount = 0;
  74     nmb->header.nscount = 0;
  75     nmb->header.arcount = 0;
  76 
  77     make_nmb_name (&nmb->question.question_name, name, name_type);
  78 
  79     nmb->question.question_type = 0x20;
  80     nmb->question.question_class = 0x1;
  81 
  82     p.ip = to_ip;
  83     p.port = NMB_PORT;
  84     p.fd = fd;
  85     p.timestamp = time (NULL);
  86     p.packet_type = NMB_PACKET;
  87 
  88     GetTimeOfDay (&tval);
  89 
  90     if (!send_packet (&p))
  91         return NULL;
  92 
  93     retries--;
  94 
  95     while (1)
  96     {
  97         struct timeval tval2;
  98         GetTimeOfDay (&tval2);
  99         if (TvalDiff (&tval, &tval2) > retry_time)
 100         {
 101             if (!retries)
 102                 break;
 103             if (!found && !send_packet (&p))
 104                 return NULL;
 105             GetTimeOfDay (&tval);
 106             retries--;
 107         }
 108 
 109         if ((p2 = receive_packet (fd, NMB_PACKET, 90)))
 110         {
 111             struct nmb_packet *nmb2 = &p2->packet.nmb;
 112             debug_nmb_packet (p2);
 113 
 114             if (nmb->header.name_trn_id != nmb2->header.name_trn_id || !nmb2->header.response)
 115             {
 116                 /* 
 117                  * Its not for us - maybe deal with it later 
 118                  * (put it on the queue?).
 119                  */
 120                 if (fn)
 121                     fn (p2);
 122                 else
 123                     free_packet (p2);
 124                 continue;
 125             }
 126 
 127             if (nmb2->header.opcode != 0 ||
 128                 nmb2->header.nm_flags.bcast || nmb2->header.rcode || !nmb2->header.ancount)
 129             {
 130                 /* 
 131                  * XXXX what do we do with this? Could be a redirect, but
 132                  * we'll discard it for the moment.
 133                  */
 134                 free_packet (p2);
 135                 continue;
 136             }
 137 
 138             ip_list = (struct in_addr *) Realloc (ip_list, sizeof (ip_list[0]) *
 139                                                   ((*count) + nmb2->answers->rdlength / 6));
 140             if (ip_list)
 141             {
 142                 DEBUG (fn ? 3 : 2, ("Got a positive name query response from %s ( ",
 143                                     inet_ntoa (p2->ip)));
 144                 for (i = 0; i < nmb2->answers->rdlength / 6; i++)
 145                 {
 146                     putip ((char *) &ip_list[(*count)], &nmb2->answers->rdata[2 + i * 6]);
 147                     DEBUG (fn ? 3 : 2, ("%s ", inet_ntoa (ip_list[(*count)])));
 148                     (*count)++;
 149                 }
 150                 DEBUG (fn ? 3 : 2, (")\n"));
 151             }
 152 
 153             found = True;
 154             retries = 0;
 155             free_packet (p2);
 156             if (fn)
 157                 break;
 158 
 159             /*
 160              * If we're doing a unicast lookup we only
 161              * expect one reply. Don't wait the full 2
 162              * seconds if we got one. JRA.
 163              */
 164             if (!bcast && found)
 165                 break;
 166         }
 167     }
 168 
 169     return ip_list;
 170 }
 171 
 172 /********************************************************
 173  Start parsing the lmhosts file.
 174 *********************************************************/
 175 
 176 FILE *
 177 startlmhosts (const char *fname)
     /* [previous][next][first][last][top][bottom][index][help]  */
 178 {
 179     FILE *fp = sys_fopen (fname, "r");
 180     if (!fp)
 181     {
 182         DEBUG (4, ("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
 183                    fname, unix_error_string (errno)));
 184         return NULL;
 185     }
 186     return fp;
 187 }
 188 
 189 /********************************************************
 190  Parse the next line in the lmhosts file.
 191 *********************************************************/
 192 BOOL
 193 getlmhostsent (FILE * fp, pstring name, int *name_type, struct in_addr * ipaddr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 194 {
 195     pstring line;
 196 
 197     while (!feof (fp) && !ferror (fp))
 198     {
 199         pstring ip, flags, extra;
 200         char *ptr;
 201         int count = 0;
 202 
 203         *name_type = -1;
 204 
 205         if (!fgets_slash (line, sizeof (pstring), fp))
 206             continue;
 207 
 208         if (*line == '#')
 209             continue;
 210 
 211         pstrcpy (ip, "");
 212         pstrcpy (name, "");
 213         pstrcpy (flags, "");
 214 
 215         ptr = line;
 216 
 217         if (next_token (&ptr, ip, NULL, sizeof (ip)))
 218             ++count;
 219         if (next_token (&ptr, name, NULL, sizeof (pstring)))
 220             ++count;
 221         if (next_token (&ptr, flags, NULL, sizeof (flags)))
 222             ++count;
 223         if (next_token (&ptr, extra, NULL, sizeof (extra)))
 224             ++count;
 225 
 226         if (count <= 0)
 227             continue;
 228 
 229         if (count > 0 && count < 2)
 230         {
 231             DEBUG (0, ("getlmhostsent: Ill formed hosts line [%s]\n", line));
 232             continue;
 233         }
 234 
 235         if (count >= 4)
 236         {
 237             DEBUG (0, ("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
 238             continue;
 239         }
 240 
 241         DEBUG (4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
 242 
 243         if (strchr (flags, 'G') || strchr (flags, 'S'))
 244         {
 245             DEBUG (0, ("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
 246             continue;
 247         }
 248 
 249         *ipaddr = *interpret_addr2 (ip);
 250 
 251         /* Extra feature. If the name ends in '#XX', where XX is a hex number,
 252            then only add that name type. */
 253         if ((ptr = strchr (name, '#')) != NULL)
 254         {
 255             char *endptr;
 256 
 257             ptr++;
 258             *name_type = (int) strtol (ptr, &endptr, 16);
 259 
 260             if (!*ptr || (endptr == ptr))
 261             {
 262                 DEBUG (0, ("getlmhostsent: invalid name %s containing '#'.\n", name));
 263                 continue;
 264             }
 265 
 266             *(--ptr) = '\0';    /* Truncate at the '#' */
 267         }
 268 
 269         return True;
 270     }
 271 
 272     return False;
 273 }
 274 
 275 /********************************************************
 276  Finish parsing the lmhosts file.
 277 *********************************************************/
 278 
 279 void
 280 endlmhosts (FILE * fp)
     /* [previous][next][first][last][top][bottom][index][help]  */
 281 {
 282     fclose (fp);
 283 }
 284 
 285 /********************************************************
 286 resolve via "bcast" method
 287 *********************************************************/
 288 static BOOL
 289 resolve_bcast (const char *name, struct in_addr *return_ip, int name_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 290 {
 291     int sock, i;
 292 
 293     /*
 294      * "bcast" means do a broadcast lookup on all the local interfaces.
 295      */
 296 
 297     DEBUG (3, ("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
 298 
 299     sock = open_socket_in (SOCK_DGRAM, 0, 3, interpret_addr (lp_socket_address ()), True);
 300 
 301     if (sock != -1)
 302     {
 303         struct in_addr *iplist = NULL;
 304         int count;
 305         int num_interfaces = iface_count ();
 306         set_socket_options (sock, "SO_BROADCAST");
 307         /*
 308          * Lookup the name on all the interfaces, return on
 309          * the first successful match.
 310          */
 311         for (i = 0; i < num_interfaces; i++)
 312         {
 313             struct in_addr sendto_ip;
 314             /* Done this way to fix compiler error on IRIX 5.x */
 315             sendto_ip = *iface_bcast (*iface_n_ip (i));
 316             iplist = name_query (sock, name, name_type, True, True, sendto_ip, &count, NULL);
 317             if (iplist != NULL)
 318             {
 319                 *return_ip = iplist[0];
 320                 free ((char *) iplist);
 321                 close (sock);
 322                 return True;
 323             }
 324         }
 325         close (sock);
 326     }
 327 
 328     return False;
 329 }
 330 
 331 
 332 
 333 /********************************************************
 334 resolve via "wins" method
 335 *********************************************************/
 336 static BOOL
 337 resolve_wins (const char *name, struct in_addr *return_ip, int name_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 338 {
 339     int sock;
 340     struct in_addr wins_ip;
 341     BOOL wins_ismyip;
 342 
 343     /*
 344      * "wins" means do a unicast lookup to the WINS server.
 345      * Ignore if there is no WINS server specified or if the
 346      * WINS server is one of our interfaces (if we're being
 347      * called from within nmbd - we can't do this call as we
 348      * would then block).
 349      */
 350 
 351     DEBUG (3, ("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
 352 
 353     if (!*lp_wins_server ())
 354     {
 355         DEBUG (3, ("resolve_name: WINS server resolution selected and no WINS server present.\n"));
 356         return False;
 357     }
 358 
 359     wins_ip = *interpret_addr2 (lp_wins_server ());
 360     wins_ismyip = ismyip (wins_ip);
 361 
 362     if ((wins_ismyip && !global_in_nmbd) || !wins_ismyip)
 363     {
 364         sock = open_socket_in (SOCK_DGRAM, 0, 3, interpret_addr (lp_socket_address ()), True);
 365 
 366         if (sock != -1)
 367         {
 368             struct in_addr *iplist = NULL;
 369             int count;
 370             iplist = name_query (sock, name, name_type, False, True, wins_ip, &count, NULL);
 371             if (iplist != NULL)
 372             {
 373                 *return_ip = iplist[0];
 374                 free ((char *) iplist);
 375                 close (sock);
 376                 return True;
 377             }
 378             close (sock);
 379         }
 380     }
 381 
 382     return False;
 383 }
 384 
 385 
 386 /********************************************************
 387 resolve via "lmhosts" method
 388 *********************************************************/
 389 static BOOL
 390 resolve_lmhosts (const char *name, struct in_addr *return_ip, int name_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 391 {
 392     /*
 393      * "lmhosts" means parse the local lmhosts file.
 394      */
 395 
 396     FILE *fp;
 397     pstring lmhost_name;
 398     int name_type2;
 399 
 400     DEBUG (3, ("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
 401 
 402     fp = startlmhosts (LMHOSTSFILE);
 403     if (fp)
 404     {
 405         while (getlmhostsent (fp, lmhost_name, &name_type2, return_ip))
 406         {
 407             if (strequal (name, lmhost_name) && ((name_type2 == -1) || (name_type == name_type2)))
 408             {
 409                 endlmhosts (fp);
 410                 return True;
 411             }
 412         }
 413         endlmhosts (fp);
 414     }
 415     return False;
 416 }
 417 
 418 
 419 /********************************************************
 420 resolve via "hosts" method
 421 *********************************************************/
 422 static BOOL
 423 resolve_hosts (const char *name, struct in_addr *return_ip)
     /* [previous][next][first][last][top][bottom][index][help]  */
 424 {
 425     /*
 426      * "host" means do a localhost, or dns lookup.
 427      */
 428     struct hostent *hp;
 429 
 430     DEBUG (3, ("resolve_name: Attempting host lookup for name %s<0x20>\n", name));
 431 
 432     if (((hp = Get_Hostbyname (name)) != NULL) && (hp->h_addr != NULL))
 433     {
 434         putip ((char *) return_ip, (char *) hp->h_addr);
 435         return True;
 436     }
 437     return False;
 438 }
 439 
 440 
 441 /********************************************************
 442  Resolve a name into an IP address. Use this function if
 443  the string is either an IP address, DNS or host name
 444  or NetBIOS name. This uses the name switch in the
 445  smb.conf to determine the order of name resolution.
 446 *********************************************************/
 447 BOOL
 448 resolve_name (const char *name, struct in_addr * return_ip, int name_type)
     /* [previous][next][first][last][top][bottom][index][help]  */
 449 {
 450     int i;
 451     BOOL pure_address = True;
 452     pstring name_resolve_list;
 453     fstring tok;
 454     char *ptr;
 455 
 456     if (strcmp (name, "0.0.0.0") == 0)
 457     {
 458         return_ip->s_addr = 0;
 459         return True;
 460     }
 461     if (strcmp (name, "255.255.255.255") == 0)
 462     {
 463         return_ip->s_addr = 0xFFFFFFFF;
 464         return True;
 465     }
 466 
 467     for (i = 0; pure_address && name[i]; i++)
 468         if (!(isdigit ((int) name[i]) || name[i] == '.'))
 469             pure_address = False;
 470 
 471     /* if it's in the form of an IP address then get the lib to interpret it */
 472     if (pure_address)
 473     {
 474         return_ip->s_addr = inet_addr (name);
 475         return True;
 476     }
 477 
 478     pstrcpy (name_resolve_list, lp_name_resolve_order ());
 479     if (name_resolve_list == NULL || *name_resolve_list == '\0')
 480         pstrcpy (name_resolve_list, "host");
 481     ptr = name_resolve_list;
 482 
 483     while (next_token (&ptr, tok, LIST_SEP, sizeof (tok)))
 484     {
 485         if ((strequal (tok, "host") || strequal (tok, "hosts")))
 486         {
 487             if (name_type == 0x20 && resolve_hosts (name, return_ip))
 488             {
 489                 return True;
 490             }
 491         }
 492         else if (strequal (tok, "lmhosts"))
 493         {
 494             if (resolve_lmhosts (name, return_ip, name_type))
 495             {
 496                 return True;
 497             }
 498         }
 499         else if (strequal (tok, "wins"))
 500         {
 501             /* don't resolve 1D via WINS */
 502             if (name_type != 0x1D && resolve_wins (name, return_ip, name_type))
 503             {
 504                 return True;
 505             }
 506         }
 507         else if (strequal (tok, "bcast"))
 508         {
 509             if (resolve_bcast (name, return_ip, name_type))
 510             {
 511                 return True;
 512             }
 513         }
 514         else
 515         {
 516             DEBUG (0, ("resolve_name: unknown name switch type %s\n", tok));
 517         }
 518     }
 519 
 520     return False;
 521 }
 522 
 523 
 524 #if 0
 525 /********************************************************
 526 find the IP address of the master browser or DMB for a workgroup
 527 *********************************************************/
 528 BOOL
 529 find_master_ip (char *group, struct in_addr * master_ip)
     /* [previous][next][first][last][top][bottom][index][help]  */
 530 {
 531     if (resolve_name (group, master_ip, 0x1D))
 532         return True;
 533 
 534     return resolve_name (group, master_ip, 0x1B);
 535 }
 536 #endif /* 0 */

/* [previous][next][first][last][top][bottom][index][help]  */