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 pstring global_myname;
27 extern int DEBUGLEVEL;
29 /* nmbd.c sets this to True. */
30 BOOL global_in_nmbd = False;
32 static int name_trn_id = 0;
34 /****************************************************************************
35 interpret a node status response
36 ****************************************************************************/
37 static void _interpret_node_status(char *p, char *master,char *rname)
39 int numnames = CVAL(p,0);
40 DEBUG(1,("received %d names\n",numnames));
42 if (rname) *rname = 0;
43 if (master) *master = 0;
57 fstrcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
58 if ((p[0] & 0x60) == 0x00) fstrcat(flags,"B ");
59 if ((p[0] & 0x60) == 0x20) fstrcat(flags,"P ");
60 if ((p[0] & 0x60) == 0x40) fstrcat(flags,"M ");
61 if ((p[0] & 0x60) == 0x60) fstrcat(flags,"H ");
62 if (p[0] & 0x10) fstrcat(flags,"<DEREGISTERING> ");
63 if (p[0] & 0x08) fstrcat(flags,"<CONFLICT> ");
64 if (p[0] & 0x04) fstrcat(flags,"<ACTIVE> ");
65 if (p[0] & 0x02) fstrcat(flags,"<PERMANENT> ");
67 if (master && !*master && type == 0x1d) {
68 StrnCpy(master,qname,15);
69 trim_string(master,NULL," ");
72 if (rname && !*rname && type == 0x20 && !(p[0]&0x80)) {
73 StrnCpy(rname,qname,15);
74 trim_string(rname,NULL," ");
77 for (i = strlen( qname) ; --i >= 0 ; ) {
78 if (!isprint((int)qname[i])) qname[i] = '.';
80 DEBUG(1,("\t%-15s <%02x> - %s\n",qname,type,flags));
83 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
84 IVAL(p,20),IVAL(p,24)));
88 /****************************************************************************
89 do a netbios name status query on a host
91 the "master" parameter is a hack used for finding workgroups.
92 **************************************************************************/
93 BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
94 struct in_addr to_ip,char *master,char *rname,
95 void (*fn)(struct packet_struct *))
99 int retry_time = 5000;
101 struct packet_struct p;
102 struct packet_struct *p2;
103 struct nmb_packet *nmb = &p.packet.nmb;
104 int packet_type = NMB_PACKET;
109 packet_type = NMB_SOCK_PACKET;
117 bzero((char *)&p,sizeof(p));
119 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
120 ((unsigned)getpid()%(unsigned)100);
121 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
123 nmb->header.name_trn_id = name_trn_id;
124 nmb->header.opcode = 0;
125 nmb->header.response = False;
126 nmb->header.nm_flags.bcast = False;
127 nmb->header.nm_flags.recursion_available = False;
128 nmb->header.nm_flags.recursion_desired = False;
129 nmb->header.nm_flags.trunc = False;
130 nmb->header.nm_flags.authoritative = False;
131 nmb->header.rcode = 0;
132 nmb->header.qdcount = 1;
133 nmb->header.ancount = 0;
134 nmb->header.nscount = 0;
135 nmb->header.arcount = 0;
137 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
139 nmb->question.question_type = 0x21;
140 nmb->question.question_class = 0x1;
145 p.timestamp = time(NULL);
146 p.packet_type = packet_type;
150 if (!send_packet(&p))
152 if (packet_type == NMB_SOCK_PACKET) close(fd);
160 struct timeval tval2;
161 GetTimeOfDay(&tval2);
162 if (TvalDiff(&tval,&tval2) > retry_time) {
164 if (!found && !send_packet(&p))
166 if (packet_type == NMB_SOCK_PACKET) close(fd);
173 if ((p2=receive_packet(fd,packet_type,90)))
175 struct nmb_packet *nmb2 = &p2->packet.nmb;
176 debug_nmb_packet(p2);
178 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
179 !nmb2->header.response) {
180 /* its not for us - maybe deal with it later */
188 if (nmb2->header.opcode != 0 ||
189 nmb2->header.nm_flags.bcast ||
190 nmb2->header.rcode ||
191 !nmb2->header.ancount ||
192 nmb2->answers->rr_type != 0x21) {
193 /* XXXX what do we do with this? could be a redirect, but
194 we'll discard it for the moment */
199 _interpret_node_status(&nmb2->answers->rdata[0], master,rname);
201 if (packet_type == NMB_SOCK_PACKET) close(fd);
207 DEBUG(0,("No status response (this is not unusual)\n"));
209 if (packet_type == NMB_SOCK_PACKET) close(fd);
214 /****************************************************************************
215 do a netbios name query to find someones IP
216 returns an array of IP addresses or NULL if none
217 *count will be set to the number of addresses returned
218 ****************************************************************************/
219 struct in_addr *name_query(int fd,const char *name,int name_type, BOOL bcast,BOOL recurse,
220 struct in_addr to_ip, int *count, void (*fn)(struct packet_struct *))
224 int retry_time = bcast?250:2000;
226 struct packet_struct p;
227 struct packet_struct *p2;
228 struct nmb_packet *nmb = &p.packet.nmb;
229 struct in_addr *ip_list = NULL;
230 BOOL packet_type = NMB_PACKET;
235 packet_type = NMB_SOCK_PACKET;
244 bzero((char *)&p,sizeof(p));
247 if (!name_trn_id) name_trn_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) +
248 ((unsigned)getpid()%(unsigned)100);
249 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
251 nmb->header.name_trn_id = name_trn_id;
252 nmb->header.opcode = 0;
253 nmb->header.response = False;
254 nmb->header.nm_flags.bcast = bcast;
255 nmb->header.nm_flags.recursion_available = False;
256 nmb->header.nm_flags.recursion_desired = recurse;
257 nmb->header.nm_flags.trunc = False;
258 nmb->header.nm_flags.authoritative = False;
259 nmb->header.rcode = 0;
260 nmb->header.qdcount = 1;
261 nmb->header.ancount = 0;
262 nmb->header.nscount = 0;
263 nmb->header.arcount = 0;
265 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
267 nmb->question.question_type = 0x20;
268 nmb->question.question_class = 0x1;
273 p.timestamp = time(NULL);
274 p.packet_type = packet_type;
278 if (!send_packet(&p))
280 if (packet_type == NMB_SOCK_PACKET) close(fd);
286 struct timeval tval2;
290 GetTimeOfDay(&tval2);
291 if (TvalDiff(&tval,&tval2) > retry_time)
293 if (!found && !send_packet(&p))
295 if (packet_type == NMB_SOCK_PACKET) close(fd);
301 if ((p2=receive_packet(fd,packet_type,90)))
303 struct nmb_packet *nmb2 = &p2->packet.nmb;
304 debug_nmb_packet(p2);
306 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
307 !nmb2->header.response)
309 DEBUG(10,("packet not for us (received %d, expected %d\n",
310 nmb2->header.name_trn_id, nmb->header.name_trn_id));
312 * Its not for us - maybe deal with it later
313 * (put it on the queue?).
322 if (nmb2->header.opcode != 0 ||
323 nmb2->header.nm_flags.bcast ||
324 nmb2->header.rcode ||
325 !nmb2->header.ancount)
328 * XXXX what do we do with this? Could be a redirect, but
329 * we'll discard it for the moment.
335 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
336 ((*count)+nmb2->answers->rdlength/6));
339 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
341 for (i=0;i<nmb2->answers->rdlength/6;i++)
343 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
344 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
347 DEBUG(fn?3:2,(")\n"));
358 DEBUG(10,("returning OK\n"));
364 if (packet_type == NMB_SOCK_PACKET) close(fd);
368 /********************************************************
369 Start parsing the lmhosts file.
370 *********************************************************/
372 FILE *startlmhosts(char *fname)
374 FILE *fp = sys_fopen(fname,"r");
376 DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
377 fname, strerror(errno)));
383 /********************************************************
384 Parse the next line in the lmhosts file.
385 *********************************************************/
386 BOOL getlmhostsent( FILE *fp, pstring name, int *name_type, struct in_addr *ipaddr)
390 while(!feof(fp) && !ferror(fp)) {
391 pstring ip,flags,extra;
397 if (!fgets_slash(line,sizeof(pstring),fp))
409 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
411 if (next_token(&ptr,name ,NULL, sizeof(pstring)))
413 if (next_token(&ptr,flags,NULL, sizeof(flags)))
415 if (next_token(&ptr,extra,NULL, sizeof(extra)))
421 if (count > 0 && count < 2)
423 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
429 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
433 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
435 if (strchr(flags,'G') || strchr(flags,'S'))
437 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
441 *ipaddr = *interpret_addr2(ip);
443 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
444 then only add that name type. */
445 if((ptr = strchr(name, '#')) != NULL)
450 *name_type = (int)strtol(ptr, &endptr,0);
452 if(!*ptr || (endptr == ptr))
454 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
458 *(--ptr) = '\0'; /* Truncate at the '#' */
467 /********************************************************
468 Finish parsing the lmhosts file.
469 *********************************************************/
471 void endlmhosts(FILE *fp)
478 /********************************************************
479 resolve via "bcast" method
480 *********************************************************/
481 static BOOL resolve_bcast(const char *name, struct in_addr *return_ip, int name_type)
486 * "bcast" means do a broadcast lookup on all the local interfaces.
489 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
491 sock = open_socket_in( SOCK_DGRAM, 0, 3,
492 interpret_addr(lp_socket_address()) );
495 struct in_addr *iplist = NULL;
497 int num_interfaces = iface_count();
498 set_socket_options(sock,"SO_BROADCAST");
500 * Lookup the name on all the interfaces, return on
501 * the first successful match.
503 for( i = 0; i < num_interfaces; i++) {
504 struct in_addr sendto_ip;
505 /* Done this way to fix compiler error on IRIX 5.x */
506 sendto_ip = *iface_bcast(*iface_n_ip(i));
507 iplist = name_query(sock, name, name_type, True,
508 True, sendto_ip, &count, NULL);
510 *return_ip = iplist[0];
511 free((char *)iplist);
524 /********************************************************
525 resolve via "wins" method
526 *********************************************************/
527 static BOOL resolve_wins(const char *name, struct in_addr *return_ip, int name_type)
530 struct in_addr wins_ip;
534 * "wins" means do a unicast lookup to the WINS server.
535 * Ignore if there is no WINS server specified or if the
536 * WINS server is one of our interfaces (if we're being
537 * called from within nmbd - we can't do this call as we
541 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
543 if(!*lp_wins_server()) {
544 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
548 wins_ip = *interpret_addr2(lp_wins_server());
549 wins_ismyip = ismyip(wins_ip);
551 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
552 sock = open_socket_in( SOCK_DGRAM, 0, 3,
553 interpret_addr(lp_socket_address()) );
556 struct in_addr *iplist = NULL;
558 iplist = name_query(sock, name, name_type, False,
559 True, wins_ip, &count, NULL);
561 *return_ip = iplist[0];
562 free((char *)iplist);
574 /********************************************************
575 resolve via "lmhosts" method
576 *********************************************************/
577 static BOOL resolve_lmhosts(const char *name, struct in_addr *return_ip, int name_type)
580 * "lmhosts" means parse the local lmhosts file.
587 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
589 fp = startlmhosts( LMHOSTSFILE );
591 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
592 if (strequal(name, lmhost_name) &&
593 name_type == name_type2) {
604 /********************************************************
605 resolve via "hosts" method
606 *********************************************************/
607 static BOOL resolve_hosts(const char *name, struct in_addr *return_ip)
610 * "host" means do a localhost, or dns lookup.
614 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
616 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
617 putip((char *)return_ip,(char *)hp->h_addr);
624 /********************************************************
625 Resolve a name into an IP address. Use this function if
626 the string is either an IP address, DNS or host name
627 or NetBIOS name. This uses the name switch in the
628 smb.conf to determine the order of name resolution.
629 *********************************************************/
630 BOOL is_ip_address(const char *name)
633 for (i=0; name[i]; i++)
634 if (!(isdigit((int)name[i]) || name[i] == '.'))
640 /********************************************************
641 Resolve a name into an IP address. Use this function if
642 the string is either an IP address, DNS or host name
643 or NetBIOS name. This uses the name switch in the
644 smb.conf to determine the order of name resolution.
645 *********************************************************/
646 BOOL resolve_name(const char *name, struct in_addr *return_ip, int name_type)
648 pstring name_resolve_list;
652 if (strcmp(name,"0.0.0.0") == 0) {
653 return_ip->s_addr = 0;
656 if (strcmp(name,"255.255.255.255") == 0) {
657 return_ip->s_addr = 0xFFFFFFFF;
661 /* if it's in the form of an IP address then get the lib to interpret it */
662 if (is_ip_address(name)) {
663 return_ip->s_addr = inet_addr(name);
667 pstrcpy(name_resolve_list, lp_name_resolve_order());
668 ptr = name_resolve_list;
669 if (!ptr || !*ptr) ptr = "host";
671 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
672 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
673 if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
676 } else if(strequal( tok, "lmhosts")) {
677 if (resolve_lmhosts(name, return_ip, name_type)) {
680 } else if(strequal( tok, "wins")) {
681 /* don't resolve 1D via WINS */
682 if (name_type != 0x1D &&
683 resolve_wins(name, return_ip, name_type)) {
686 } else if(strequal( tok, "bcast")) {
687 if (resolve_bcast(name, return_ip, name_type)) {
691 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
698 /********************************************************
699 resolve a name of format \\server_name or \\ipaddress
700 into a name. also, cut the \\ from the front for us.
701 *********************************************************/
702 BOOL resolve_srv_name(const char* srv_name, fstring dest_host,
706 const char *sv_name = srv_name;
708 DEBUG(10,("resolve_srv_name: %s\n", srv_name));
710 if (srv_name == NULL || strequal("\\\\.", srv_name))
712 fstrcpy(dest_host, global_myname);
713 ip = interpret_addr2("127.0.0.1");
717 if (strnequal("\\\\", srv_name, 2))
719 sv_name = &srv_name[2];
722 fstrcpy(dest_host, sv_name);
723 ret = resolve_name(dest_host, ip, 0x20);
725 if (is_ip_address(dest_host))
727 fstrcpy(dest_host, "*SMBSERVER");
733 /********************************************************
734 find the IP address of the master browser or DMB for a workgroup
735 *********************************************************/
736 BOOL find_master_ip(char *group, struct in_addr *master_ip)
738 if (resolve_name(group, master_ip, 0x1D)) return True;
740 return resolve_name(group, master_ip, 0x1B);