2 Unix SMB/Netbios implementation.
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.
26 extern int DEBUGLEVEL;
28 /* nmbd.c sets this to True. */
29 BOOL global_in_nmbd = False;
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;
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));
80 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
81 IVAL(p,20),IVAL(p,24)));
85 /****************************************************************************
86 do a netbios name status query on a host
88 the "master" parameter is a hack used for finding workgroups.
89 **************************************************************************/
90 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
91 struct in_addr to_ip,char *master,char *rname,
92 void (*fn)(struct packet_struct *))
96 int retry_time = 5000;
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;
103 bzero((char *)&p,sizeof(p));
105 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
106 ((unsigned)getpid()%(unsigned)100);
107 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
109 nmb->header.name_trn_id = name_trn_id;
110 nmb->header.opcode = 0;
111 nmb->header.response = False;
112 nmb->header.nm_flags.bcast = False;
113 nmb->header.nm_flags.recursion_available = False;
114 nmb->header.nm_flags.recursion_desired = False;
115 nmb->header.nm_flags.trunc = False;
116 nmb->header.nm_flags.authoritative = False;
117 nmb->header.rcode = 0;
118 nmb->header.qdcount = 1;
119 nmb->header.ancount = 0;
120 nmb->header.nscount = 0;
121 nmb->header.arcount = 0;
123 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
125 nmb->question.question_type = 0x21;
126 nmb->question.question_class = 0x1;
131 p.timestamp = time(NULL);
132 p.packet_type = NMB_PACKET;
136 if (!send_packet(&p))
143 struct timeval tval2;
144 GetTimeOfDay(&tval2);
145 if (TvalDiff(&tval,&tval2) > retry_time) {
147 if (!found && !send_packet(&p))
153 if ((p2=receive_packet(fd,NMB_PACKET,90)))
155 struct nmb_packet *nmb2 = &p2->packet.nmb;
156 debug_nmb_packet(p2);
158 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
159 !nmb2->header.response) {
160 /* its not for us - maybe deal with it later */
168 if (nmb2->header.opcode != 0 ||
169 nmb2->header.nm_flags.bcast ||
170 nmb2->header.rcode ||
171 !nmb2->header.ancount ||
172 nmb2->answers->rr_type != 0x21) {
173 /* XXXX what do we do with this? could be a redirect, but
174 we'll discard it for the moment */
179 _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
186 DEBUG(0,("No status response (this is not unusual)\n"));
192 /****************************************************************************
193 do a netbios name query to find someones IP
194 returns an array of IP addresses or NULL if none
195 *count will be set to the number of addresses returned
196 ****************************************************************************/
197 struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
198 struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
202 int retry_time = bcast?250:2000;
204 struct packet_struct p;
205 struct packet_struct *p2;
206 struct nmb_packet *nmb = &p.packet.nmb;
207 static int name_trn_id = 0;
208 struct in_addr *ip_list = NULL;
210 bzero((char *)&p,sizeof(p));
213 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
214 ((unsigned)getpid()%(unsigned)100);
215 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
217 nmb->header.name_trn_id = name_trn_id;
218 nmb->header.opcode = 0;
219 nmb->header.response = False;
220 nmb->header.nm_flags.bcast = bcast;
221 nmb->header.nm_flags.recursion_available = False;
222 nmb->header.nm_flags.recursion_desired = recurse;
223 nmb->header.nm_flags.trunc = False;
224 nmb->header.nm_flags.authoritative = False;
225 nmb->header.rcode = 0;
226 nmb->header.qdcount = 1;
227 nmb->header.ancount = 0;
228 nmb->header.nscount = 0;
229 nmb->header.arcount = 0;
231 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
233 nmb->question.question_type = 0x20;
234 nmb->question.question_class = 0x1;
239 p.timestamp = time(NULL);
240 p.packet_type = NMB_PACKET;
244 if (!send_packet(&p))
251 struct timeval tval2;
252 GetTimeOfDay(&tval2);
253 if (TvalDiff(&tval,&tval2) > retry_time)
257 if (!found && !send_packet(&p))
263 if ((p2=receive_packet(fd,NMB_PACKET,90)))
265 struct nmb_packet *nmb2 = &p2->packet.nmb;
266 debug_nmb_packet(p2);
268 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
269 !nmb2->header.response)
272 * Its not for us - maybe deal with it later
273 * (put it on the queue?).
282 if (nmb2->header.opcode != 0 ||
283 nmb2->header.nm_flags.bcast ||
284 nmb2->header.rcode ||
285 !nmb2->header.ancount)
288 * XXXX what do we do with this? Could be a redirect, but
289 * we'll discard it for the moment.
295 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
296 ((*count)+nmb2->answers->rdlength/6));
299 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
301 for (i=0;i<nmb2->answers->rdlength/6;i++)
303 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
304 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
307 DEBUG(fn?3:2,(")\n"));
317 * If we're doing a unicast lookup we only
318 * expect one reply. Don't wait the full 2
319 * seconds if we got one. JRA.
329 /********************************************************
330 Start parsing the lmhosts file.
331 *********************************************************/
333 FILE *startlmhosts(char *fname)
335 FILE *fp = fopen(fname,"r");
337 DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
338 fname, strerror(errno)));
344 /********************************************************
345 Parse the next line in the lmhosts file.
346 *********************************************************/
347 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
351 while(!feof(fp) && !ferror(fp)) {
352 pstring ip,flags,extra;
358 if (!fgets_slash(line,sizeof(pstring),fp))
370 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
372 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
374 if (next_token(&ptr,flags,NULL, sizeof(flags)))
376 if (next_token(&ptr,extra,NULL, sizeof(extra)))
382 if (count > 0 && count < 2)
384 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
390 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
394 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
396 if (strchr(flags,'G') || strchr(flags,'S'))
398 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
402 *ipaddr = *interpret_addr2(ip);
404 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
405 then only add that name type. */
406 if((ptr = strchr(name, '#')) != NULL)
411 *name_type = (int)strtol(ptr, &endptr,0);
413 if(!*ptr || (endptr == ptr))
415 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
419 *(--ptr) = '\0'; /* Truncate at the '#' */
428 /********************************************************
429 Finish parsing the lmhosts file.
430 *********************************************************/
432 void endlmhosts(FILE *fp)
439 /********************************************************
440 resolve via "bcast" method
441 *********************************************************/
442 static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
447 * "bcast" means do a broadcast lookup on all the local interfaces.
450 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
452 sock = open_socket_in( SOCK_DGRAM, 0, 3,
453 interpret_addr(lp_socket_address()) );
456 struct in_addr *iplist = NULL;
458 int num_interfaces = iface_count();
459 set_socket_options(sock,"SO_BROADCAST");
461 * Lookup the name on all the interfaces, return on
462 * the first successful match.
464 for( i = 0; i < num_interfaces; i++) {
465 struct in_addr sendto_ip;
466 /* Done this way to fix compiler error on IRIX 5.x */
467 sendto_ip = *iface_bcast(*iface_n_ip(i));
468 iplist = name_query(sock, name, name_type, True,
469 True, sendto_ip, &count, NULL);
471 *return_ip = iplist[0];
472 free((char *)iplist);
485 /********************************************************
486 resolve via "wins" method
487 *********************************************************/
488 static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
491 struct in_addr wins_ip;
495 * "wins" means do a unicast lookup to the WINS server.
496 * Ignore if there is no WINS server specified or if the
497 * WINS server is one of our interfaces (if we're being
498 * called from within nmbd - we can't do this call as we
502 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
504 if(!*lp_wins_server()) {
505 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
509 wins_ip = *interpret_addr2(lp_wins_server());
510 wins_ismyip = ismyip(wins_ip);
512 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
513 sock = open_socket_in( SOCK_DGRAM, 0, 3,
514 interpret_addr(lp_socket_address()) );
517 struct in_addr *iplist = NULL;
519 iplist = name_query(sock, name, name_type, False,
520 True, wins_ip, &count, NULL);
522 *return_ip = iplist[0];
523 free((char *)iplist);
535 /********************************************************
536 resolve via "lmhosts" method
537 *********************************************************/
538 static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
541 * "lmhosts" means parse the local lmhosts file.
548 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
550 fp = startlmhosts( LMHOSTSFILE );
552 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
553 if (strequal(name, lmhost_name) &&
554 name_type == name_type2) {
565 /********************************************************
566 resolve via "hosts" method
567 *********************************************************/
568 static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
571 * "host" means do a localhost, or dns lookup.
575 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
577 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
578 putip((char *)return_ip,(char *)hp->h_addr);
585 /********************************************************
586 Resolve a name into an IP address. Use this function if
587 the string is either an IP address, DNS or host name
588 or NetBIOS name. This uses the name switch in the
589 smb.conf to determine the order of name resolution.
590 *********************************************************/
591 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
594 BOOL pure_address = True;
595 pstring name_resolve_list;
599 if (strcmp(name,"0.0.0.0") == 0) {
600 return_ip->s_addr = 0;
603 if (strcmp(name,"255.255.255.255") == 0) {
604 return_ip->s_addr = 0xFFFFFFFF;
608 for (i=0; pure_address && name[i]; i++)
609 if (!(isdigit((int)name[i]) || name[i] == '.'))
610 pure_address = False;
612 /* if it's in the form of an IP address then get the lib to interpret it */
614 return_ip->s_addr = inet_addr(name);
618 pstrcpy(name_resolve_list, lp_name_resolve_order());
619 ptr = name_resolve_list;
620 if (!ptr || !*ptr) ptr = "host";
622 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
623 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
624 if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
627 } else if(strequal( tok, "lmhosts")) {
628 if (resolve_lmhosts(name, return_ip, name_type)) {
631 } else if(strequal( tok, "wins")) {
632 /* don't resolve 1D via WINS */
633 if (name_type != 0x1D &&
634 resolve_wins(name, return_ip, name_type)) {
637 } else if(strequal( tok, "bcast")) {
638 if (resolve_bcast(name, return_ip, name_type)) {
642 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
651 /********************************************************
652 find the IP address of the master browser or DMB for a workgroup
653 *********************************************************/
654 BOOL find_master_ip(char *group, struct in_addr *master_ip)
656 if (resolve_name(group, master_ip, 0x1D)) return True;
658 return resolve_name(group, master_ip, 0x1B);