Removed calls to strerror() function from own libsamba implementation.
[midnight-commander.git] / vfs / samba / libsmb / namequery.c
blobf18b94ebd2decce57e831ce7628b8381b5e17f56
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 const char *unix_error_string (int error_num);
26 extern pstring scope;
27 extern int DEBUGLEVEL;
29 /* nmbd.c sets this to True. */
30 const BOOL global_in_nmbd = False;
31 #if 0
32 /****************************************************************************
33 interpret a node status response
34 ****************************************************************************/
35 static void _interpret_node_status(char *p, char *master,char *rname)
37 int numnames = CVAL(p,0);
38 DEBUG(1,("received %d names\n",numnames));
40 if (rname) *rname = 0;
41 if (master) *master = 0;
43 p += 1;
44 while (numnames--)
46 char qname[17];
47 int type;
48 fstring flags;
49 int i;
50 *flags = 0;
51 StrnCpy(qname,p,15);
52 type = CVAL(p,15);
53 p += 16;
55 fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
56 if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
57 if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
58 if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
59 if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
60 if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
61 if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
62 if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
63 if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
65 if (master && !*master && type == 0x1d) {
66 StrnCpy(master,qname,15);
67 trim_string(master,NULL," ");
70 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
71 StrnCpy(rname,qname,15);
72 trim_string(rname,NULL," ");
75 for (i = strlen( qname) ; --i >= 0 ; ) {
76 if (!isprint((int)qname[i])) qname[i] = '.';
78 DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
79 p+=2;
81 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
82 IVAL(p,20),IVAL(p,24)));
84 #endif /* 0 */
86 /****************************************************************************
87 do a netbios name query to find someones IP
88 returns an array of IP addresses or NULL if none
89 *count will be set to the number of addresses returned
90 ****************************************************************************/
91 struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
92 struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
94 BOOL found=False;
95 int i, retries = 3;
96 int retry_time = bcast?250:2000;
97 struct timeval tval;
98 struct packet_struct p;
99 struct packet_struct *p2;
100 struct nmb_packet *nmb = &p.packet.nmb;
101 static int name_trn_id = 0;
102 struct in_addr *ip_list = NULL;
104 memset((char *)&p,'\0',sizeof(p));
105 (*count) = 0;
107 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
108 ((unsigned)getpid()%(unsigned)100);
109 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
111 nmb->header.name_trn_id = name_trn_id;
112 nmb->header.opcode = 0;
113 nmb->header.response = False;
114 nmb->header.nm_flags.bcast = bcast;
115 nmb->header.nm_flags.recursion_available = False;
116 nmb->header.nm_flags.recursion_desired = recurse;
117 nmb->header.nm_flags.trunc = False;
118 nmb->header.nm_flags.authoritative = False;
119 nmb->header.rcode = 0;
120 nmb->header.qdcount = 1;
121 nmb->header.ancount = 0;
122 nmb->header.nscount = 0;
123 nmb->header.arcount = 0;
125 make_nmb_name(&nmb->question.question_name,name,name_type);
127 nmb->question.question_type = 0x20;
128 nmb->question.question_class = 0x1;
130 p.ip = to_ip;
131 p.port = NMB_PORT;
132 p.fd = fd;
133 p.timestamp = time(NULL);
134 p.packet_type = NMB_PACKET;
136 GetTimeOfDay(&tval);
138 if (!send_packet(&p))
139 return NULL;
141 retries--;
143 while (1)
145 struct timeval tval2;
146 GetTimeOfDay(&tval2);
147 if (TvalDiff(&tval,&tval2) > retry_time)
149 if (!retries)
150 break;
151 if (!found && !send_packet(&p))
152 return NULL;
153 GetTimeOfDay(&tval);
154 retries--;
157 if ((p2=receive_packet(fd,NMB_PACKET,90)))
159 struct nmb_packet *nmb2 = &p2->packet.nmb;
160 debug_nmb_packet(p2);
162 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
163 !nmb2->header.response)
166 * Its not for us - maybe deal with it later
167 * (put it on the queue?).
169 if (fn)
170 fn(p2);
171 else
172 free_packet(p2);
173 continue;
176 if (nmb2->header.opcode != 0 ||
177 nmb2->header.nm_flags.bcast ||
178 nmb2->header.rcode ||
179 !nmb2->header.ancount)
182 * XXXX what do we do with this? Could be a redirect, but
183 * we'll discard it for the moment.
185 free_packet(p2);
186 continue;
189 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
190 ((*count)+nmb2->answers->rdlength/6));
191 if (ip_list)
193 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
194 inet_ntoa(p2->ip)));
195 for (i=0;i<nmb2->answers->rdlength/6;i++)
197 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
198 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
199 (*count)++;
201 DEBUG(fn?3:2,(")\n"));
204 found=True;
205 retries=0;
206 free_packet(p2);
207 if (fn)
208 break;
211 * If we're doing a unicast lookup we only
212 * expect one reply. Don't wait the full 2
213 * seconds if we got one. JRA.
215 if(!bcast && found)
216 break;
220 return ip_list;
223 /********************************************************
224 Start parsing the lmhosts file.
225 *********************************************************/
227 FILE *startlmhosts(const char *fname)
229 FILE *fp = sys_fopen(fname,"r");
230 if (!fp) {
231 DEBUG(4,("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
232 fname, unix_error_string (errno)));
233 return NULL;
235 return fp;
238 /********************************************************
239 Parse the next line in the lmhosts file.
240 *********************************************************/
241 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
243 pstring line;
245 while(!feof(fp) && !ferror(fp)) {
246 pstring ip,flags,extra;
247 char *ptr;
248 int count = 0;
250 *name_type = -1;
252 if (!fgets_slash(line,sizeof(pstring),fp))
253 continue;
255 if (*line == '#')
256 continue;
258 pstrcpy(ip,"");
259 pstrcpy(name,"");
260 pstrcpy(flags,"");
262 ptr = line;
264 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
265 ++count;
266 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
267 ++count;
268 if (next_token(&ptr,flags,NULL, sizeof(flags)))
269 ++count;
270 if (next_token(&ptr,extra,NULL, sizeof(extra)))
271 ++count;
273 if (count <= 0)
274 continue;
276 if (count > 0 && count < 2)
278 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
279 continue;
282 if (count >= 4)
284 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
285 continue;
288 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
290 if (strchr(flags,'G') || strchr(flags,'S'))
292 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
293 continue;
296 *ipaddr = *interpret_addr2(ip);
298 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
299 then only add that name type. */
300 if((ptr = strchr(name, '#')) != NULL)
302 char *endptr;
304 ptr++;
305 *name_type = (int)strtol(ptr, &endptr, 16);
307 if(!*ptr || (endptr == ptr))
309 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
310 continue;
313 *(--ptr) = '\0'; /* Truncate at the '#' */
316 return True;
319 return False;
322 /********************************************************
323 Finish parsing the lmhosts file.
324 *********************************************************/
326 void endlmhosts(FILE *fp)
328 fclose(fp);
331 /********************************************************
332 resolve via "bcast" method
333 *********************************************************/
334 static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
336 int sock, i;
339 * "bcast" means do a broadcast lookup on all the local interfaces.
342 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name, name_type));
344 sock = open_socket_in( SOCK_DGRAM, 0, 3,
345 interpret_addr(lp_socket_address()), True );
347 if (sock != -1) {
348 struct in_addr *iplist = NULL;
349 int count;
350 int num_interfaces = iface_count();
351 static char so_broadcast[] = "SO_BROADCAST";
352 set_socket_options(sock, so_broadcast);
354 * Lookup the name on all the interfaces, return on
355 * the first successful match.
357 for( i = 0; i < num_interfaces; i++) {
358 struct in_addr sendto_ip;
359 /* Done this way to fix compiler error on IRIX 5.x */
360 sendto_ip = *iface_bcast(*iface_n_ip(i));
361 iplist = name_query(sock, name, name_type, True,
362 True, sendto_ip, &count, NULL);
363 if(iplist != NULL) {
364 *return_ip = iplist[0];
365 free((char *)iplist);
366 close(sock);
367 return True;
370 close(sock);
373 return False;
378 /********************************************************
379 resolve via "wins" method
380 *********************************************************/
381 static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
383 int sock;
384 struct in_addr wins_ip;
385 BOOL wins_ismyip;
388 * "wins" means do a unicast lookup to the WINS server.
389 * Ignore if there is no WINS server specified or if the
390 * WINS server is one of our interfaces (if we're being
391 * called from within nmbd - we can't do this call as we
392 * would then block).
395 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
397 if(!*lp_wins_server()) {
398 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
399 return False;
402 wins_ip = *interpret_addr2(lp_wins_server());
403 wins_ismyip = ismyip(wins_ip);
405 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
406 sock = open_socket_in( SOCK_DGRAM, 0, 3,
407 interpret_addr(lp_socket_address()), True );
409 if (sock != -1) {
410 struct in_addr *iplist = NULL;
411 int count;
412 iplist = name_query(sock, name, name_type, False,
413 True, wins_ip, &count, NULL);
414 if(iplist != NULL) {
415 *return_ip = iplist[0];
416 free((char *)iplist);
417 close(sock);
418 return True;
420 close(sock);
424 return False;
428 /********************************************************
429 resolve via "lmhosts" method
430 *********************************************************/
431 static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
434 * "lmhosts" means parse the local lmhosts file.
437 FILE *fp;
438 pstring lmhost_name;
439 int name_type2;
441 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
443 fp = startlmhosts( LMHOSTSFILE );
444 if(fp) {
445 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
446 if (strequal(name, lmhost_name) &&
447 ((name_type2 == -1) || (name_type == name_type2))
449 endlmhosts(fp);
450 return True;
453 endlmhosts(fp);
455 return False;
459 /********************************************************
460 resolve via "hosts" method
461 *********************************************************/
462 static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
465 * "host" means do a localhost, or dns lookup.
467 struct hostent *hp;
469 DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name));
471 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
472 putip((char *)return_ip,(char *)hp->h_addr);
473 return True;
475 return False;
479 /********************************************************
480 Resolve a name into an IP address. Use this function if
481 the string is either an IP address, DNS or host name
482 or NetBIOS name. This uses the name switch in the
483 smb.conf to determine the order of name resolution.
484 *********************************************************/
485 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
487 int i;
488 BOOL pure_address = True;
489 pstring name_resolve_list;
490 fstring tok;
491 char *ptr;
493 if (strcmp(name,"0.0.0.0") == 0) {
494 return_ip->s_addr = 0;
495 return True;
497 if (strcmp(name,"255.255.255.255") == 0) {
498 return_ip->s_addr = 0xFFFFFFFF;
499 return True;
502 for (i=0; pure_address && name[i]; i++)
503 if (!(isdigit((int)name[i]) || name[i] == '.'))
504 pure_address = False;
506 /* if it's in the form of an IP address then get the lib to interpret it */
507 if (pure_address) {
508 return_ip->s_addr = inet_addr(name);
509 return True;
512 pstrcpy(name_resolve_list, lp_name_resolve_order());
513 if (name_resolve_list == NULL || *name_resolve_list == '\0')
514 pstrcpy(name_resolve_list, "host");
515 ptr = name_resolve_list;
517 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
518 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
519 if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
520 return True;
522 } else if(strequal( tok, "lmhosts")) {
523 if (resolve_lmhosts(name, return_ip, name_type)) {
524 return True;
526 } else if(strequal( tok, "wins")) {
527 /* don't resolve 1D via WINS */
528 if (name_type != 0x1D &&
529 resolve_wins(name, return_ip, name_type)) {
530 return True;
532 } else if(strequal( tok, "bcast")) {
533 if (resolve_bcast(name, return_ip, name_type)) {
534 return True;
536 } else {
537 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
541 return False;
545 #if 0
546 /********************************************************
547 find the IP address of the master browser or DMB for a workgroup
548 *********************************************************/
549 BOOL find_master_ip(char *group, struct in_addr *master_ip)
551 if (resolve_name(group, master_ip, 0x1D)) return True;
553 return resolve_name(group, master_ip, 0x1B);
555 #endif /* 0 */