Code indentation.
[midnight-commander.git] / src / vfs / smbfs / helpers / libsmb / namequery.c
blob79bcbccb90a26545f72f126aeca6505bae4e808b
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 name query routines
6 Copyright (C) Andrew Tridgell 1994-1998
8 Copyright (C) 2011
9 The Free Software Foundation, Inc.
11 This file is part of the Midnight Commander.
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.
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.
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/>.
27 #include "includes.h"
29 const char *unix_error_string (int error_num);
30 extern pstring scope;
31 extern int DEBUGLEVEL;
33 /* nmbd.c sets this to True. */
34 const BOOL global_in_nmbd = False;
35 #if 0
36 /****************************************************************************
37 interpret a node status response
38 ****************************************************************************/
39 static void
40 _interpret_node_status (char *p, char *master, char *rname)
42 int numnames = CVAL (p, 0);
43 DEBUG (1, ("received %d names\n", numnames));
45 if (rname)
46 *rname = 0;
47 if (master)
48 *master = 0;
50 p += 1;
51 while (numnames--)
53 char qname[17];
54 int type;
55 fstring flags;
56 int i;
57 *flags = 0;
58 StrnCpy (qname, p, 15);
59 type = CVAL (p, 15);
60 p += 16;
62 fstrcat (flags, (p[0] & 0x80) ? "<GROUP> " : " ");
63 if ((p[0] & 0x60) == 0x00)
64 fstrcat (flags, "B ");
65 if ((p[0] & 0x60) == 0x20)
66 fstrcat (flags, "P ");
67 if ((p[0] & 0x60) == 0x40)
68 fstrcat (flags, "M ");
69 if ((p[0] & 0x60) == 0x60)
70 fstrcat (flags, "H ");
71 if (p[0] & 0x10)
72 fstrcat (flags, "<DEREGISTERING> ");
73 if (p[0] & 0x08)
74 fstrcat (flags, "<CONFLICT> ");
75 if (p[0] & 0x04)
76 fstrcat (flags, "<ACTIVE> ");
77 if (p[0] & 0x02)
78 fstrcat (flags, "<PERMANENT> ");
80 if (master && !*master && type == 0x1d)
82 StrnCpy (master, qname, 15);
83 trim_string (master, NULL, " ");
86 if (rname && !*rname && type == 0x20 && !(p[0] & 0x80))
88 StrnCpy (rname, qname, 15);
89 trim_string (rname, NULL, " ");
92 for (i = strlen (qname); --i >= 0;)
94 if (!isprint ((int) qname[i]))
95 qname[i] = '.';
97 DEBUG (1, ("\t%-15s <%02x> - %s\n", qname, type, flags));
98 p += 2;
100 DEBUG (1, ("num_good_sends=%d num_good_receives=%d\n", IVAL (p, 20), IVAL (p, 24)));
102 #endif /* 0 */
104 /****************************************************************************
105 do a netbios name query to find someones IP
106 returns an array of IP addresses or NULL if none
107 *count will be set to the number of addresses returned
108 ****************************************************************************/
109 struct in_addr *
110 name_query (int fd, const char *name, int name_type, BOOL bcast, BOOL recurse,
111 struct in_addr to_ip, int *count, void (*fn) (struct packet_struct *))
113 BOOL found = False;
114 int i, retries = 3;
115 int retry_time = bcast ? 250 : 2000;
116 struct timeval tval;
117 struct packet_struct p;
118 struct packet_struct *p2;
119 struct nmb_packet *nmb = &p.packet.nmb;
120 static int name_trn_id = 0;
121 struct in_addr *ip_list = NULL;
123 memset ((char *) &p, '\0', sizeof (p));
124 (*count) = 0;
126 if (!name_trn_id)
127 name_trn_id = ((unsigned) time (NULL) % (unsigned) 0x7FFF) +
128 ((unsigned) getpid () % (unsigned) 100);
129 name_trn_id = (name_trn_id + 1) % (unsigned) 0x7FFF;
131 nmb->header.name_trn_id = name_trn_id;
132 nmb->header.opcode = 0;
133 nmb->header.response = False;
134 nmb->header.nm_flags.bcast = bcast;
135 nmb->header.nm_flags.recursion_available = False;
136 nmb->header.nm_flags.recursion_desired = recurse;
137 nmb->header.nm_flags.trunc = False;
138 nmb->header.nm_flags.authoritative = False;
139 nmb->header.rcode = 0;
140 nmb->header.qdcount = 1;
141 nmb->header.ancount = 0;
142 nmb->header.nscount = 0;
143 nmb->header.arcount = 0;
145 make_nmb_name (&nmb->question.question_name, name, name_type);
147 nmb->question.question_type = 0x20;
148 nmb->question.question_class = 0x1;
150 p.ip = to_ip;
151 p.port = NMB_PORT;
152 p.fd = fd;
153 p.timestamp = time (NULL);
154 p.packet_type = NMB_PACKET;
156 GetTimeOfDay (&tval);
158 if (!send_packet (&p))
159 return NULL;
161 retries--;
163 while (1)
165 struct timeval tval2;
166 GetTimeOfDay (&tval2);
167 if (TvalDiff (&tval, &tval2) > retry_time)
169 if (!retries)
170 break;
171 if (!found && !send_packet (&p))
172 return NULL;
173 GetTimeOfDay (&tval);
174 retries--;
177 if ((p2 = receive_packet (fd, NMB_PACKET, 90)))
179 struct nmb_packet *nmb2 = &p2->packet.nmb;
180 debug_nmb_packet (p2);
182 if (nmb->header.name_trn_id != nmb2->header.name_trn_id || !nmb2->header.response)
185 * Its not for us - maybe deal with it later
186 * (put it on the queue?).
188 if (fn)
189 fn (p2);
190 else
191 free_packet (p2);
192 continue;
195 if (nmb2->header.opcode != 0 ||
196 nmb2->header.nm_flags.bcast || nmb2->header.rcode || !nmb2->header.ancount)
199 * XXXX what do we do with this? Could be a redirect, but
200 * we'll discard it for the moment.
202 free_packet (p2);
203 continue;
206 ip_list = (struct in_addr *) Realloc (ip_list, sizeof (ip_list[0]) *
207 ((*count) + nmb2->answers->rdlength / 6));
208 if (ip_list)
210 DEBUG (fn ? 3 : 2, ("Got a positive name query response from %s ( ",
211 inet_ntoa (p2->ip)));
212 for (i = 0; i < nmb2->answers->rdlength / 6; i++)
214 putip ((char *) &ip_list[(*count)], &nmb2->answers->rdata[2 + i * 6]);
215 DEBUG (fn ? 3 : 2, ("%s ", inet_ntoa (ip_list[(*count)])));
216 (*count)++;
218 DEBUG (fn ? 3 : 2, (")\n"));
221 found = True;
222 retries = 0;
223 free_packet (p2);
224 if (fn)
225 break;
228 * If we're doing a unicast lookup we only
229 * expect one reply. Don't wait the full 2
230 * seconds if we got one. JRA.
232 if (!bcast && found)
233 break;
237 return ip_list;
240 /********************************************************
241 Start parsing the lmhosts file.
242 *********************************************************/
244 FILE *
245 startlmhosts (const char *fname)
247 FILE *fp = sys_fopen (fname, "r");
248 if (!fp)
250 DEBUG (4, ("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
251 fname, unix_error_string (errno)));
252 return NULL;
254 return fp;
257 /********************************************************
258 Parse the next line in the lmhosts file.
259 *********************************************************/
260 BOOL
261 getlmhostsent (FILE * fp, pstring name, int *name_type, struct in_addr * ipaddr)
263 pstring line;
265 while (!feof (fp) && !ferror (fp))
267 pstring ip, flags, extra;
268 char *ptr;
269 int count = 0;
271 *name_type = -1;
273 if (!fgets_slash (line, sizeof (pstring), fp))
274 continue;
276 if (*line == '#')
277 continue;
279 pstrcpy (ip, "");
280 pstrcpy (name, "");
281 pstrcpy (flags, "");
283 ptr = line;
285 if (next_token (&ptr, ip, NULL, sizeof (ip)))
286 ++count;
287 if (next_token (&ptr, name, NULL, sizeof (pstring)))
288 ++count;
289 if (next_token (&ptr, flags, NULL, sizeof (flags)))
290 ++count;
291 if (next_token (&ptr, extra, NULL, sizeof (extra)))
292 ++count;
294 if (count <= 0)
295 continue;
297 if (count > 0 && count < 2)
299 DEBUG (0, ("getlmhostsent: Ill formed hosts line [%s]\n", line));
300 continue;
303 if (count >= 4)
305 DEBUG (0, ("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
306 continue;
309 DEBUG (4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
311 if (strchr (flags, 'G') || strchr (flags, 'S'))
313 DEBUG (0, ("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
314 continue;
317 *ipaddr = *interpret_addr2 (ip);
319 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
320 then only add that name type. */
321 if ((ptr = strchr (name, '#')) != NULL)
323 char *endptr;
325 ptr++;
326 *name_type = (int) strtol (ptr, &endptr, 16);
328 if (!*ptr || (endptr == ptr))
330 DEBUG (0, ("getlmhostsent: invalid name %s containing '#'.\n", name));
331 continue;
334 *(--ptr) = '\0'; /* Truncate at the '#' */
337 return True;
340 return False;
343 /********************************************************
344 Finish parsing the lmhosts file.
345 *********************************************************/
347 void
348 endlmhosts (FILE * fp)
350 fclose (fp);
353 /********************************************************
354 resolve via "bcast" method
355 *********************************************************/
356 static BOOL
357 resolve_bcast (const char *name, struct in_addr *return_ip, int name_type)
359 int sock, i;
362 * "bcast" means do a broadcast lookup on all the local interfaces.
365 DEBUG (3, ("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
367 sock = open_socket_in (SOCK_DGRAM, 0, 3, interpret_addr (lp_socket_address ()), True);
369 if (sock != -1)
371 struct in_addr *iplist = NULL;
372 int count;
373 int num_interfaces = iface_count ();
374 static char so_broadcast[] = "SO_BROADCAST";
375 set_socket_options (sock, so_broadcast);
377 * Lookup the name on all the interfaces, return on
378 * the first successful match.
380 for (i = 0; i < num_interfaces; i++)
382 struct in_addr sendto_ip;
383 /* Done this way to fix compiler error on IRIX 5.x */
384 sendto_ip = *iface_bcast (*iface_n_ip (i));
385 iplist = name_query (sock, name, name_type, True, True, sendto_ip, &count, NULL);
386 if (iplist != NULL)
388 *return_ip = iplist[0];
389 free ((char *) iplist);
390 close (sock);
391 return True;
394 close (sock);
397 return False;
402 /********************************************************
403 resolve via "wins" method
404 *********************************************************/
405 static BOOL
406 resolve_wins (const char *name, struct in_addr *return_ip, int name_type)
408 int sock;
409 struct in_addr wins_ip;
410 BOOL wins_ismyip;
413 * "wins" means do a unicast lookup to the WINS server.
414 * Ignore if there is no WINS server specified or if the
415 * WINS server is one of our interfaces (if we're being
416 * called from within nmbd - we can't do this call as we
417 * would then block).
420 DEBUG (3, ("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
422 if (!*lp_wins_server ())
424 DEBUG (3, ("resolve_name: WINS server resolution selected and no WINS server present.\n"));
425 return False;
428 wins_ip = *interpret_addr2 (lp_wins_server ());
429 wins_ismyip = ismyip (wins_ip);
431 if ((wins_ismyip && !global_in_nmbd) || !wins_ismyip)
433 sock = open_socket_in (SOCK_DGRAM, 0, 3, interpret_addr (lp_socket_address ()), True);
435 if (sock != -1)
437 struct in_addr *iplist = NULL;
438 int count;
439 iplist = name_query (sock, name, name_type, False, True, wins_ip, &count, NULL);
440 if (iplist != NULL)
442 *return_ip = iplist[0];
443 free ((char *) iplist);
444 close (sock);
445 return True;
447 close (sock);
451 return False;
455 /********************************************************
456 resolve via "lmhosts" method
457 *********************************************************/
458 static BOOL
459 resolve_lmhosts (const char *name, struct in_addr *return_ip, int name_type)
462 * "lmhosts" means parse the local lmhosts file.
465 FILE *fp;
466 pstring lmhost_name;
467 int name_type2;
469 DEBUG (3, ("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
471 fp = startlmhosts (LMHOSTSFILE);
472 if (fp)
474 while (getlmhostsent (fp, lmhost_name, &name_type2, return_ip))
476 if (strequal (name, lmhost_name) && ((name_type2 == -1) || (name_type == name_type2)))
478 endlmhosts (fp);
479 return True;
482 endlmhosts (fp);
484 return False;
488 /********************************************************
489 resolve via "hosts" method
490 *********************************************************/
491 static BOOL
492 resolve_hosts (const char *name, struct in_addr *return_ip)
495 * "host" means do a localhost, or dns lookup.
497 struct hostent *hp;
499 DEBUG (3, ("resolve_name: Attempting host lookup for name %s<0x20>\n", name));
501 if (((hp = Get_Hostbyname (name)) != NULL) && (hp->h_addr != NULL))
503 putip ((char *) return_ip, (char *) hp->h_addr);
504 return True;
506 return False;
510 /********************************************************
511 Resolve a name into an IP address. Use this function if
512 the string is either an IP address, DNS or host name
513 or NetBIOS name. This uses the name switch in the
514 smb.conf to determine the order of name resolution.
515 *********************************************************/
516 BOOL
517 resolve_name (const char *name, struct in_addr * return_ip, int name_type)
519 int i;
520 BOOL pure_address = True;
521 pstring name_resolve_list;
522 fstring tok;
523 char *ptr;
525 if (strcmp (name, "0.0.0.0") == 0)
527 return_ip->s_addr = 0;
528 return True;
530 if (strcmp (name, "255.255.255.255") == 0)
532 return_ip->s_addr = 0xFFFFFFFF;
533 return True;
536 for (i = 0; pure_address && name[i]; i++)
537 if (!(isdigit ((int) name[i]) || name[i] == '.'))
538 pure_address = False;
540 /* if it's in the form of an IP address then get the lib to interpret it */
541 if (pure_address)
543 return_ip->s_addr = inet_addr (name);
544 return True;
547 pstrcpy (name_resolve_list, lp_name_resolve_order ());
548 if (name_resolve_list == NULL || *name_resolve_list == '\0')
549 pstrcpy (name_resolve_list, "host");
550 ptr = name_resolve_list;
552 while (next_token (&ptr, tok, LIST_SEP, sizeof (tok)))
554 if ((strequal (tok, "host") || strequal (tok, "hosts")))
556 if (name_type == 0x20 && resolve_hosts (name, return_ip))
558 return True;
561 else if (strequal (tok, "lmhosts"))
563 if (resolve_lmhosts (name, return_ip, name_type))
565 return True;
568 else if (strequal (tok, "wins"))
570 /* don't resolve 1D via WINS */
571 if (name_type != 0x1D && resolve_wins (name, return_ip, name_type))
573 return True;
576 else if (strequal (tok, "bcast"))
578 if (resolve_bcast (name, return_ip, name_type))
580 return True;
583 else
585 DEBUG (0, ("resolve_name: unknown name switch type %s\n", tok));
589 return False;
593 #if 0
594 /********************************************************
595 find the IP address of the master browser or DMB for a workgroup
596 *********************************************************/
597 BOOL
598 find_master_ip (char *group, struct in_addr * master_ip)
600 if (resolve_name (group, master_ip, 0x1D))
601 return True;
603 return resolve_name (group, master_ip, 0x1B);
605 #endif /* 0 */