* samba/lib/util_str.c: Comment out strhasupper(), strhaslower(),
[midnight-commander.git] / vfs / samba / libsmb / namequery.c
blobab86ca1e3a265badf0dd6e23e870a9889125d4ea
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., 675 Mass Ave, Cambridge, MA 02139, 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(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 set_socket_options(sock,"SO_BROADCAST");
352 * Lookup the name on all the interfaces, return on
353 * the first successful match.
355 for( i = 0; i < num_interfaces; i++) {
356 struct in_addr sendto_ip;
357 /* Done this way to fix compiler error on IRIX 5.x */
358 sendto_ip = *iface_bcast(*iface_n_ip(i));
359 iplist = name_query(sock, name, name_type, True,
360 True, sendto_ip, &count, NULL);
361 if(iplist != NULL) {
362 *return_ip = iplist[0];
363 free((char *)iplist);
364 close(sock);
365 return True;
368 close(sock);
371 return False;
376 /********************************************************
377 resolve via "wins" method
378 *********************************************************/
379 static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
381 int sock;
382 struct in_addr wins_ip;
383 BOOL wins_ismyip;
386 * "wins" means do a unicast lookup to the WINS server.
387 * Ignore if there is no WINS server specified or if the
388 * WINS server is one of our interfaces (if we're being
389 * called from within nmbd - we can't do this call as we
390 * would then block).
393 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name, name_type));
395 if(!*lp_wins_server()) {
396 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
397 return False;
400 wins_ip = *interpret_addr2(lp_wins_server());
401 wins_ismyip = ismyip(wins_ip);
403 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
404 sock = open_socket_in( SOCK_DGRAM, 0, 3,
405 interpret_addr(lp_socket_address()), True );
407 if (sock != -1) {
408 struct in_addr *iplist = NULL;
409 int count;
410 iplist = name_query(sock, name, name_type, False,
411 True, wins_ip, &count, NULL);
412 if(iplist != NULL) {
413 *return_ip = iplist[0];
414 free((char *)iplist);
415 close(sock);
416 return True;
418 close(sock);
422 return False;
426 /********************************************************
427 resolve via "lmhosts" method
428 *********************************************************/
429 static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
432 * "lmhosts" means parse the local lmhosts file.
435 FILE *fp;
436 pstring lmhost_name;
437 int name_type2;
439 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name, name_type));
441 fp = startlmhosts( LMHOSTSFILE );
442 if(fp) {
443 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
444 if (strequal(name, lmhost_name) &&
445 ((name_type2 == -1) || (name_type == name_type2))
447 endlmhosts(fp);
448 return True;
451 endlmhosts(fp);
453 return False;
457 /********************************************************
458 resolve via "hosts" method
459 *********************************************************/
460 static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
463 * "host" means do a localhost, or dns lookup.
465 struct hostent *hp;
467 DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name));
469 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
470 putip((char *)return_ip,(char *)hp->h_addr);
471 return True;
473 return False;
477 /********************************************************
478 Resolve a name into an IP address. Use this function if
479 the string is either an IP address, DNS or host name
480 or NetBIOS name. This uses the name switch in the
481 smb.conf to determine the order of name resolution.
482 *********************************************************/
483 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
485 int i;
486 BOOL pure_address = True;
487 pstring name_resolve_list;
488 fstring tok;
489 char *ptr;
491 if (strcmp(name,"0.0.0.0") == 0) {
492 return_ip->s_addr = 0;
493 return True;
495 if (strcmp(name,"255.255.255.255") == 0) {
496 return_ip->s_addr = 0xFFFFFFFF;
497 return True;
500 for (i=0; pure_address && name[i]; i++)
501 if (!(isdigit((int)name[i]) || name[i] == '.'))
502 pure_address = False;
504 /* if it's in the form of an IP address then get the lib to interpret it */
505 if (pure_address) {
506 return_ip->s_addr = inet_addr(name);
507 return True;
510 pstrcpy(name_resolve_list, lp_name_resolve_order());
511 ptr = name_resolve_list;
512 if (!ptr || !*ptr) ptr = "host";
514 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
515 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
516 if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
517 return True;
519 } else if(strequal( tok, "lmhosts")) {
520 if (resolve_lmhosts(name, return_ip, name_type)) {
521 return True;
523 } else if(strequal( tok, "wins")) {
524 /* don't resolve 1D via WINS */
525 if (name_type != 0x1D &&
526 resolve_wins(name, return_ip, name_type)) {
527 return True;
529 } else if(strequal( tok, "bcast")) {
530 if (resolve_bcast(name, return_ip, name_type)) {
531 return True;
533 } else {
534 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
538 return False;
542 #if 0
543 /********************************************************
544 find the IP address of the master browser or DMB for a workgroup
545 *********************************************************/
546 BOOL find_master_ip(char *group, struct in_addr *master_ip)
548 if (resolve_name(group, master_ip, 0x1D)) return True;
550 return resolve_name(group, master_ip, 0x1B);
552 #endif /* 0 */