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)
417 /********************************************************
418 Resolve a name into an IP address. Use this function if
419 the string is either an IP address, DNS or host name
420 or NetBIOS name. This uses the name switch in the
421 smb.conf to determine the order of name resolution.
422 *********************************************************/
423 BOOL resolve_name(char *name, struct in_addr *return_ip)
426 BOOL pure_address = True;
427 pstring name_resolve_list;
431 if (strcmp(name,"0.0.0.0") == 0) {
432 return_ip->s_addr = 0;
435 if (strcmp(name,"255.255.255.255") == 0) {
436 return_ip->s_addr = 0xFFFFFFFF;
440 for (i=0; pure_address && name[i]; i++)
441 if (!(isdigit((int)name[i]) || name[i] == '.'))
442 pure_address = False;
444 /* if it's in the form of an IP address then get the lib to interpret it */
446 return_ip->s_addr = inet_addr(name);
450 pstrcpy(name_resolve_list, lp_name_resolve_order());
451 ptr = name_resolve_list;
452 if (!ptr || !*ptr) ptr = "host";
454 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
455 if(strequal(tok, "host") || strequal(tok, "hosts")) {
458 * "host" means do a localhost, or dns lookup.
463 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
465 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
466 putip((char *)return_ip,(char *)hp->h_addr);
470 } else if(strequal( tok, "lmhosts")) {
473 * "lmhosts" means parse the local lmhosts file.
480 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
482 fp = startlmhosts( LMHOSTSFILE );
484 while( getlmhostsent(fp, lmhost_name, &name_type, return_ip ) ) {
485 if( strequal(name, lmhost_name )) {
493 } else if(strequal( tok, "wins")) {
498 * "wins" means do a unicast lookup to the WINS server.
499 * Ignore if there is no WINS server specified or if the
500 * WINS server is one of our interfaces (if we're being
501 * called from within nmbd - we can't do this call as we
505 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
507 if(*lp_wins_server()) {
508 struct in_addr wins_ip = *interpret_addr2(lp_wins_server());
509 BOOL wins_ismyip = ismyip(wins_ip);
511 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
512 sock = open_socket_in( SOCK_DGRAM, 0, 3,
513 interpret_addr(lp_socket_address()) );
516 struct in_addr *iplist = NULL;
518 iplist = name_query(sock, name, 0x20, False, True, wins_ip, &count, NULL);
520 *return_ip = iplist[0];
521 free((char *)iplist);
529 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
531 } else if(strequal( tok, "bcast")) {
536 * "bcast" means do a broadcast lookup on all the local interfaces.
539 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
541 sock = open_socket_in( SOCK_DGRAM, 0, 3,
542 interpret_addr(lp_socket_address()) );
545 struct in_addr *iplist = NULL;
547 int num_interfaces = iface_count();
548 set_socket_options(sock,"SO_BROADCAST");
550 * Lookup the name on all the interfaces, return on
551 * the first successful match.
553 for( i = 0; i < num_interfaces; i++) {
554 struct in_addr sendto_ip;
555 /* Done this way to fix compiler error on IRIX 5.x */
556 sendto_ip = *iface_bcast(*iface_n_ip(i));
557 iplist = name_query(sock, name, 0x20, True, False, sendto_ip, &count, NULL);
559 *return_ip = iplist[0];
560 free((char *)iplist);
569 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));
578 /********************************************************
579 find the IP address of the master browser for a workgroup
580 *********************************************************/
581 BOOL find_master(char *group, struct in_addr *master_ip)
584 struct in_addr *iplist = NULL;
586 int num_interfaces = iface_count();
588 sock = open_socket_in( SOCK_DGRAM, 0, 3,
589 interpret_addr(lp_socket_address()) );
591 if (sock == -1) return False;
593 set_socket_options(sock,"SO_BROADCAST");
596 * Lookup the name on all the interfaces, return on
597 * the first successful match.
599 for( i = 0; i < num_interfaces; i++) {
600 struct in_addr sendto_ip;
601 /* Done this way to fix compiler error on IRIX 5.x */
602 sendto_ip = *iface_bcast(*iface_n_ip(i));
603 iplist = name_query(sock, group, 0x1D, True, False,
604 sendto_ip, &count, NULL);
606 *master_ip = iplist[0];
607 free((char *)iplist);