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,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) {
255 if (!found && !send_packet(&p))
261 if ((p2=receive_packet(fd,NMB_PACKET,90)))
263 struct nmb_packet *nmb2 = &p2->packet.nmb;
264 debug_nmb_packet(p2);
266 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
267 !nmb2->header.response) {
268 /* its not for us - maybe deal with it later
269 (put it on the queue?) */
277 if (nmb2->header.opcode != 0 ||
278 nmb2->header.nm_flags.bcast ||
279 nmb2->header.rcode ||
280 !nmb2->header.ancount) {
281 /* XXXX what do we do with this? could be a redirect, but
282 we'll discard it for the moment */
287 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
288 ((*count)+nmb2->answers->rdlength/6));
290 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
292 for (i=0;i<nmb2->answers->rdlength/6;i++) {
293 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
294 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
297 DEBUG(fn?3:2,(")\n"));
299 found=True; retries=0;
308 /********************************************************
309 Start parsing the lmhosts file.
310 *********************************************************/
312 FILE *startlmhosts(char *fname)
314 FILE *fp = fopen(fname,"r");
316 DEBUG(4,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
317 fname, strerror(errno)));
323 /********************************************************
324 Parse the next line in the lmhosts file.
325 *********************************************************/
327 BOOL getlmhostsent( FILE *fp, char *name, int *name_type, struct in_addr *ipaddr)
331 while(!feof(fp) && !ferror(fp)) {
332 pstring ip,flags,extra;
338 if (!fgets_slash(line,sizeof(pstring),fp))
350 if (next_token(&ptr,ip ,NULL,sizeof(ip)))
352 if (next_token(&ptr,name ,NULL, sizeof(name)))
354 if (next_token(&ptr,flags,NULL, sizeof(flags)))
356 if (next_token(&ptr,extra,NULL, sizeof(extra)))
362 if (count > 0 && count < 2)
364 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
370 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
374 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
376 if (strchr(flags,'G') || strchr(flags,'S'))
378 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
382 *ipaddr = *interpret_addr2(ip);
384 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
385 then only add that name type. */
386 if((ptr = strchr(name, '#')) != NULL)
391 *name_type = (int)strtol(ptr, &endptr,0);
393 if(!*ptr || (endptr == ptr))
395 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
399 *(--ptr) = '\0'; /* Truncate at the '#' */
408 /********************************************************
409 Finish parsing the lmhosts file.
410 *********************************************************/
412 void endlmhosts(FILE *fp)
419 /********************************************************
420 resolve via "bcast" method
421 *********************************************************/
422 static BOOL resolve_bcast(char *name, struct in_addr *return_ip, int name_type)
427 * "bcast" means do a broadcast lookup on all the local interfaces.
430 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
432 sock = open_socket_in( SOCK_DGRAM, 0, 3,
433 interpret_addr(lp_socket_address()) );
436 struct in_addr *iplist = NULL;
438 int num_interfaces = iface_count();
439 set_socket_options(sock,"SO_BROADCAST");
441 * Lookup the name on all the interfaces, return on
442 * the first successful match.
444 for( i = 0; i < num_interfaces; i++) {
445 struct in_addr sendto_ip;
446 /* Done this way to fix compiler error on IRIX 5.x */
447 sendto_ip = *iface_bcast(*iface_n_ip(i));
448 iplist = name_query(sock, name, name_type, True,
449 False, sendto_ip, &count, NULL);
451 *return_ip = iplist[0];
452 free((char *)iplist);
465 /********************************************************
466 resolve via "wins" method
467 *********************************************************/
468 static BOOL resolve_wins(char *name, struct in_addr *return_ip, int name_type)
471 struct in_addr wins_ip;
475 * "wins" means do a unicast lookup to the WINS server.
476 * Ignore if there is no WINS server specified or if the
477 * WINS server is one of our interfaces (if we're being
478 * called from within nmbd - we can't do this call as we
482 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
484 if(!*lp_wins_server()) {
485 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
489 wins_ip = *interpret_addr2(lp_wins_server());
490 wins_ismyip = ismyip(wins_ip);
492 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
493 sock = open_socket_in( SOCK_DGRAM, 0, 3,
494 interpret_addr(lp_socket_address()) );
497 struct in_addr *iplist = NULL;
499 iplist = name_query(sock, name, name_type, False,
500 True, wins_ip, &count, NULL);
502 *return_ip = iplist[0];
503 free((char *)iplist);
515 /********************************************************
516 resolve via "lmhosts" method
517 *********************************************************/
518 static BOOL resolve_lmhosts(char *name, struct in_addr *return_ip, int name_type)
521 * "lmhosts" means parse the local lmhosts file.
528 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
530 fp = startlmhosts( LMHOSTSFILE );
532 while (getlmhostsent(fp, lmhost_name, &name_type2, return_ip)) {
533 if (strequal(name, lmhost_name) &&
534 name_type == name_type2) {
545 /********************************************************
546 resolve via "hosts" method
547 *********************************************************/
548 static BOOL resolve_hosts(char *name, struct in_addr *return_ip)
551 * "host" means do a localhost, or dns lookup.
555 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
557 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
558 putip((char *)return_ip,(char *)hp->h_addr);
565 /********************************************************
566 Resolve a name into an IP address. Use this function if
567 the string is either an IP address, DNS or host name
568 or NetBIOS name. This uses the name switch in the
569 smb.conf to determine the order of name resolution.
570 *********************************************************/
571 BOOL resolve_name(char *name, struct in_addr *return_ip, int name_type)
574 BOOL pure_address = True;
575 pstring name_resolve_list;
579 if (strcmp(name,"0.0.0.0") == 0) {
580 return_ip->s_addr = 0;
583 if (strcmp(name,"255.255.255.255") == 0) {
584 return_ip->s_addr = 0xFFFFFFFF;
588 for (i=0; pure_address && name[i]; i++)
589 if (!(isdigit((int)name[i]) || name[i] == '.'))
590 pure_address = False;
592 /* if it's in the form of an IP address then get the lib to interpret it */
594 return_ip->s_addr = inet_addr(name);
598 pstrcpy(name_resolve_list, lp_name_resolve_order());
599 ptr = name_resolve_list;
600 if (!ptr || !*ptr) ptr = "host";
602 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
603 if((strequal(tok, "host") || strequal(tok, "hosts"))) {
604 if (name_type == 0x20 && resolve_hosts(name, return_ip)) {
607 } else if(strequal( tok, "lmhosts")) {
608 if (resolve_lmhosts(name, return_ip, name_type)) {
611 } else if(strequal( tok, "wins")) {
612 /* don't resolve 1D via WINS */
613 if (name_type != 0x1D &&
614 resolve_wins(name, return_ip, name_type)) {
617 } else if(strequal( tok, "bcast")) {
618 if (resolve_bcast(name, return_ip, name_type)) {
622 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
631 /********************************************************
632 find the IP address of the master browser or DMB for a workgroup
633 *********************************************************/
634 BOOL find_master(char *group, struct in_addr *master_ip)
636 if (resolve_name(group, master_ip, 0x1D)) return True;
638 return resolve_name(group, master_ip, 0x1B);