Ticket #1649: Prepare for prerelease mc-4.7.0-pre3 (code cleanup)
[midnight-commander.git] / vfs / samba / libsmb / namequery.c
blobb15174404ca96e681a84b2b47d3cbd2dbfcda0eb
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 name query routines
5 Copyright (C) Andrew Tridgell 1994-1998
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "includes.h"
25 extern pstring scope;
26 extern int DEBUGLEVEL;
28 /* nmbd.c sets this to True. */
29 const BOOL global_in_nmbd = False;
30 #if 0
31 /****************************************************************************
32 interpret a node status response
33 ****************************************************************************/
34 static void _interpret_node_status(char *p, char *master,char *rname)
36 int numnames = CVAL(p,0);
37 DEBUG(1,("received %d names\n",numnames));
39 if (rname) *rname = 0;
40 if (master) *master = 0;
42 p += 1;
43 while (numnames--)
45 char qname[17];
46 int type;
47 fstring flags;
48 int i;
49 *flags = 0;
50 StrnCpy(qname,p,15);
51 type = CVAL(p,15);
52 p += 16;
54 fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
55 if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
56 if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
57 if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
58 if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
59 if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
60 if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
61 if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
62 if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
64 if (master && !*master && type == 0x1d) {
65 StrnCpy(master,qname,15);
66 trim_string(master,NULL," ");
69 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
70 StrnCpy(rname,qname,15);
71 trim_string(rname,NULL," ");
74 for (i = strlen( qname) ; --i >= 0 ; ) {
75 if (!isprint((int)qname[i])) qname[i] = '.';
77 DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
78 p+=2;
80 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
81 IVAL(p,20),IVAL(p,24)));
83 #endif /* 0 */
85 /****************************************************************************
86 do a netbios name query to find someones IP
87 returns an array of IP addresses or NULL if none
88 *count will be set to the number of addresses returned
89 ****************************************************************************/
90 struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
91 struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
93 BOOL found=False;
94 int i, retries = 3;
95 int retry_time = bcast?250:2000;
96 struct timeval tval;
97 struct packet_struct p;
98 struct packet_struct *p2;
99 struct nmb_packet *nmb = &p.packet.nmb;
100 static int name_trn_id = 0;
101 struct in_addr *ip_list = NULL;
103 memset((char *)&p,'\0',sizeof(p));
104 (*count) = 0;
106 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
107 ((unsigned)getpid()%(unsigned)100);
108 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
110 nmb->header.name_trn_id = name_trn_id;
111 nmb->header.opcode = 0;
112 nmb->header.response = False;
113 nmb->header.nm_flags.bcast = bcast;
114 nmb->header.nm_flags.recursion_available = False;
115 nmb->header.nm_flags.recursion_desired = recurse;
116 nmb->header.nm_flags.trunc = False;
117 nmb->header.nm_flags.authoritative = False;
118 nmb->header.rcode = 0;
119 nmb->header.qdcount = 1;
120 nmb->header.ancount = 0;
121 nmb->header.nscount = 0;
122 nmb->header.arcount = 0;
124 make_nmb_name(&nmb->question.question_name,name,name_type);
126 nmb->question.question_type = 0x20;
127 nmb->question.question_class = 0x1;
129 p.ip = to_ip;
130 p.port = NMB_PORT;
131 p.fd = fd;
132 p.timestamp = time(NULL);
133 p.packet_type = NMB_PACKET;
135 GetTimeOfDay(&tval);
137 if (!send_packet(&p))
138 return NULL;
140 retries--;
142 while (1)
144 struct timeval tval2;
145 GetTimeOfDay(&tval2);
146 if (TvalDiff(&tval,&tval2) > retry_time)
148 if (!retries)
149 break;
150 if (!found && !send_packet(&p))
151 return NULL;
152 GetTimeOfDay(&tval);
153 retries--;
156 if ((p2=receive_packet(fd,NMB_PACKET,90)))
158 struct nmb_packet *nmb2 = &p2->packet.nmb;
159 debug_nmb_packet(p2);
161 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
162 !nmb2->header.response)
165 * Its not for us - maybe deal with it later
166 * (put it on the queue?).
168 if (fn)
169 fn(p2);
170 else
171 free_packet(p2);
172 continue;
175 if (nmb2->header.opcode != 0 ||
176 nmb2->header.nm_flags.bcast ||
177 nmb2->header.rcode ||
178 !nmb2->header.ancount)
181 * XXXX what do we do with this? Could be a redirect, but
182 * we'll discard it for the moment.
184 free_packet(p2);
185 continue;
188 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
189 ((*count)+nmb2->answers->rdlength/6));
190 if (ip_list)
192 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
193 inet_ntoa(p2->ip)));
194 for (i=0;i<nmb2->answers->rdlength/6;i++)
196 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
197 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
198 (*count)++;
200 DEBUG(fn?3:2,(")\n"));
203 found=True;
204 retries=0;
205 free_packet(p2);
206 if (fn)
207 break;
210 * If we're doing a unicast lookup we only
211 * expect one reply. Don't wait the full 2
212 * seconds if we got one. JRA.
214 if(!bcast && found)
215 break;
219 return ip_list;
222 /********************************************************
223 Start parsing the lmhosts file.
224 *********************************************************/
226 FILE *startlmhosts(const char *fname)
228 FILE *fp = sys_fopen(fname,"r");
229 if (!fp) {
230 DEBUG(4,("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
231 fname, strerror(errno)));
232 return NULL;
234 return fp;
237 /********************************************************
238 Parse the next line in the lmhosts file.
239 *********************************************************/
240 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
242 pstring line;
244 while(!feof(fp) && !ferror(fp)) {
245 pstring ip,flags,extra;
246 char *ptr;
247 int count = 0;
249 *name_type = -1;
251 if (!fgets_slash(line,sizeof(pstring),fp))
252 continue;
254 if (*line == '#')
255 continue;
257 pstrcpy(ip,"");
258 pstrcpy(name,"");
259 pstrcpy(flags,"");
261 ptr = line;
263 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
264 ++count;
265 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
266 ++count;
267 if (next_token(&ptr,flags,NULL, sizeof(flags)))
268 ++count;
269 if (next_token(&ptr,extra,NULL, sizeof(extra)))
270 ++count;
272 if (count <= 0)
273 continue;
275 if (count > 0 && count < 2)
277 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
278 continue;
281 if (count >= 4)
283 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
284 continue;
287 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
289 if (strchr(flags,'G') || strchr(flags,'S'))
291 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
292 continue;
295 *ipaddr = *interpret_addr2(ip);
297 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
298 then only add that name type. */
299 if((ptr = strchr(name, '#')) != NULL)
301 char *endptr;
303 ptr++;
304 *name_type = (int)strtol(ptr, &endptr, 16);
306 if(!*ptr || (endptr == ptr))
308 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
309 continue;
312 *(--ptr) = '\0'; /* Truncate at the '#' */
315 return True;
318 return False;
321 /********************************************************
322 Finish parsing the lmhosts file.
323 *********************************************************/
325 void endlmhosts(FILE *fp)
327 fclose(fp);
330 /********************************************************
331 resolve via "bcast" method
332 *********************************************************/
333 static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
335 int sock, i;
338 * "bcast" means do a broadcast lookup on all the local interfaces.
341 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
343 sock = open_socket_in( SOCK_DGRAM, 0, 3,
344 interpret_addr(lp_socket_address()), True );
346 if (sock != -1) {
347 struct in_addr *iplist = NULL;
348 int count;
349 int num_interfaces = iface_count();
350 static char so_broadcast[] = "SO_BROADCAST";
351 set_socket_options(sock, so_broadcast);
353 * Lookup the name on all the interfaces, return on
354 * the first successful match.
356 for( i = 0; i < num_interfaces; i++) {
357 struct in_addr sendto_ip;
358 /* Done this way to fix compiler error on IRIX 5.x */
359 sendto_ip = *iface_bcast(*iface_n_ip(i));
360 iplist = name_query(sock, name, name_type, True,
361 True, sendto_ip, &count, NULL);
362 if(iplist != NULL) {
363 *return_ip = iplist[0];
364 free((char *)iplist);
365 close(sock);
366 return True;
369 close(sock);
372 return False;
377 /********************************************************
378 resolve via "wins" method
379 *********************************************************/
380 static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
382 int sock;
383 struct in_addr wins_ip;
384 BOOL wins_ismyip;
387 * "wins" means do a unicast lookup to the WINS server.
388 * Ignore if there is no WINS server specified or if the
389 * WINS server is one of our interfaces (if we're being
390 * called from within nmbd - we can't do this call as we
391 * would then block).
394 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
396 if(!*lp_wins_server()) {
397 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
398 return False;
401 wins_ip = *interpret_addr2(lp_wins_server());
402 wins_ismyip = ismyip(wins_ip);
404 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
405 sock = open_socket_in( SOCK_DGRAM, 0, 3,
406 interpret_addr(lp_socket_address()), True );
408 if (sock != -1) {
409 struct in_addr *iplist = NULL;
410 int count;
411 iplist = name_query(sock, name, name_type, False,
412 True, wins_ip, &count, NULL);
413 if(iplist != NULL) {
414 *return_ip = iplist[0];
415 free((char *)iplist);
416 close(sock);
417 return True;
419 close(sock);
423 return False;
427 /********************************************************
428 resolve via "lmhosts" method
429 *********************************************************/
430 static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
433 * "lmhosts" means parse the local lmhosts file.
436 FILE *fp;
437 pstring lmhost_name;
438 int name_type2;
440 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
442 fp = startlmhosts( LMHOSTSFILE );
443 if(fp) {
444 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
445 if (strequal(name, lmhost_name) &&
446 ((name_type2 == -1) || (name_type == name_type2))
448 endlmhosts(fp);
449 return True;
452 endlmhosts(fp);
454 return False;
458 /********************************************************
459 resolve via "hosts" method
460 *********************************************************/
461 static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
464 * "host" means do a localhost, or dns lookup.
466 struct hostent *hp;
468 DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name));
470 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
471 putip((char *)return_ip,(char *)hp->h_addr);
472 return True;
474 return False;
478 /********************************************************
479 Resolve a name into an IP address. Use this function if
480 the string is either an IP address, DNS or host name
481 or NetBIOS name. This uses the name switch in the
482 smb.conf to determine the order of name resolution.
483 *********************************************************/
484 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
486 int i;
487 BOOL pure_address = True;
488 pstring name_resolve_list;
489 fstring tok;
490 char *ptr;
492 if (strcmp(name,"0.0.0.0") == 0) {
493 return_ip->s_addr = 0;
494 return True;
496 if (strcmp(name,"255.255.255.255") == 0) {
497 return_ip->s_addr = 0xFFFFFFFF;
498 return True;
501 for (i=0; pure_address && name[i]; i++)
502 if (!(isdigit((int)name[i]) || name[i] == '.'))
503 pure_address = False;
505 /* if it's in the form of an IP address then get the lib to interpret it */
506 if (pure_address) {
507 return_ip->s_addr = inet_addr(name);
508 return True;
511 pstrcpy(name_resolve_list, lp_name_resolve_order());
512 if (name_resolve_list == NULL || *name_resolve_list == '\0')
513 pstrcpy(name_resolve_list, "host");
514 ptr = name_resolve_list;
516 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
517 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
518 if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
519 return True;
521 } else if(strequal( tok, "lmhosts")) {
522 if (resolve_lmhosts(name, return_ip, name_type)) {
523 return True;
525 } else if(strequal( tok, "wins")) {
526 /* don't resolve 1D via WINS */
527 if (name_type != 0x1D &&
528 resolve_wins(name, return_ip, name_type)) {
529 return True;
531 } else if(strequal( tok, "bcast")) {
532 if (resolve_bcast(name, return_ip, name_type)) {
533 return True;
535 } else {
536 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
540 return False;
544 #if 0
545 /********************************************************
546 find the IP address of the master browser or DMB for a workgroup
547 *********************************************************/
548 BOOL find_master_ip(char *group, struct in_addr *master_ip)
550 if (resolve_name(group, master_ip, 0x1D)) return True;
552 return resolve_name(group, master_ip, 0x1B);
554 #endif /* 0 */