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 strcat(flags, (p[0] & 0x80) ? "<GROUP> " : " ");
55 if ((p[0] & 0x60) == 0x00) strcat(flags,"B ");
56 if ((p[0] & 0x60) == 0x20) strcat(flags,"P ");
57 if ((p[0] & 0x60) == 0x40) strcat(flags,"M ");
58 if ((p[0] & 0x60) == 0x60) strcat(flags,"H ");
59 if (p[0] & 0x10) strcat(flags,"<DEREGISTERING> ");
60 if (p[0] & 0x08) strcat(flags,"<CONFLICT> ");
61 if (p[0] & 0x04) strcat(flags,"<ACTIVE> ");
62 if (p[0] & 0x02) strcat(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(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,
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 = (time(NULL)%(unsigned)0x7FFF) +
106 (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,
198 BOOL bcast,BOOL recurse,
199 struct in_addr to_ip, int *count, void (*fn)())
203 int retry_time = bcast?250:2000;
205 struct packet_struct p;
206 struct packet_struct *p2;
207 struct nmb_packet *nmb = &p.packet.nmb;
208 static int name_trn_id = 0;
209 struct in_addr *ip_list = NULL;
211 bzero((char *)&p,sizeof(p));
214 if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
215 (getpid()%(unsigned)100);
216 name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
218 nmb->header.name_trn_id = name_trn_id;
219 nmb->header.opcode = 0;
220 nmb->header.response = False;
221 nmb->header.nm_flags.bcast = bcast;
222 nmb->header.nm_flags.recursion_available = False;
223 nmb->header.nm_flags.recursion_desired = recurse;
224 nmb->header.nm_flags.trunc = False;
225 nmb->header.nm_flags.authoritative = False;
226 nmb->header.rcode = 0;
227 nmb->header.qdcount = 1;
228 nmb->header.ancount = 0;
229 nmb->header.nscount = 0;
230 nmb->header.arcount = 0;
232 make_nmb_name(&nmb->question.question_name,name,name_type,scope);
234 nmb->question.question_type = 0x20;
235 nmb->question.question_class = 0x1;
240 p.timestamp = time(NULL);
241 p.packet_type = NMB_PACKET;
245 if (!send_packet(&p))
252 struct timeval tval2;
253 GetTimeOfDay(&tval2);
254 if (TvalDiff(&tval,&tval2) > retry_time) {
256 if (!found && !send_packet(&p))
262 if ((p2=receive_packet(fd,NMB_PACKET,90)))
264 struct nmb_packet *nmb2 = &p2->packet.nmb;
265 debug_nmb_packet(p2);
267 if (nmb->header.name_trn_id != nmb2->header.name_trn_id ||
268 !nmb2->header.response) {
269 /* its not for us - maybe deal with it later
270 (put it on the queue?) */
278 if (nmb2->header.opcode != 0 ||
279 nmb2->header.nm_flags.bcast ||
280 nmb2->header.rcode ||
281 !nmb2->header.ancount) {
282 /* XXXX what do we do with this? could be a redirect, but
283 we'll discard it for the moment */
288 ip_list = (struct in_addr *)Realloc(ip_list, sizeof(ip_list[0]) *
289 ((*count)+nmb2->answers->rdlength/6));
291 DEBUG(fn?3:2,("Got a positive name query response from %s ( ",
293 for (i=0;i<nmb2->answers->rdlength/6;i++) {
294 putip((char *)&ip_list[(*count)],&nmb2->answers->rdata[2+i*6]);
295 DEBUG(fn?3:2,("%s ",inet_ntoa(ip_list[(*count)])));
298 DEBUG(fn?3:2,(")\n"));
300 found=True; retries=0;
309 /********************************************************
310 Start parsing the lmhosts file.
311 *********************************************************/
313 FILE *startlmhosts(char *fname)
315 FILE *fp = fopen(fname,"r");
317 DEBUG(2,("startlmhosts: Can't open lmhosts file %s. Error was %s\n",
318 fname, strerror(errno)));
324 /********************************************************
325 Parse the next line in the lmhosts file.
326 *********************************************************/
328 BOOL getlmhostsent( FILE *fp, char *name, int *name_type, struct in_addr *ipaddr)
332 while(!feof(fp) && !ferror(fp)) {
333 pstring ip,flags,extra;
339 if (!fgets_slash(line,sizeof(pstring),fp))
351 if (next_token(&ptr,ip ,NULL))
353 if (next_token(&ptr,name ,NULL))
355 if (next_token(&ptr,flags,NULL))
357 if (next_token(&ptr,extra,NULL))
363 if (count > 0 && count < 2)
365 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line));
371 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
375 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip, name, flags));
377 if (strchr(flags,'G') || strchr(flags,'S'))
379 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
383 *ipaddr = *interpret_addr2(ip);
385 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
386 then only add that name type. */
387 if((ptr = strchr(name, '#')) != NULL)
392 *name_type = (int)strtol(ptr, &endptr,0);
394 if(!*ptr || (endptr == ptr))
396 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name));
400 *(--ptr) = '\0'; /* Truncate at the '#' */
409 /********************************************************
410 Finish parsing the lmhosts file.
411 *********************************************************/
413 void endlmhosts(FILE *fp)
418 /********************************************************
419 Resolve a name into an IP address. Use this function if
420 the string is either an IP address, DNS or host name
421 or NetBIOS name. This uses the name switch in the
422 smb.conf to determine the order of name resolution.
423 *********************************************************/
425 BOOL resolve_name(char *name, struct in_addr *return_ip)
428 BOOL pure_address = True;
429 pstring name_resolve_list;
433 if (strcmp(name,"0.0.0.0") == 0) {
434 return_ip->s_addr = 0;
437 if (strcmp(name,"255.255.255.255") == 0) {
438 return_ip->s_addr = 0xFFFFFFFF;
442 for (i=0; pure_address && name[i]; i++)
443 if (!(isdigit(name[i]) || name[i] == '.'))
444 pure_address = False;
446 /* if it's in the form of an IP address then get the lib to interpret it */
448 return_ip->s_addr = inet_addr(name);
452 pstrcpy(name_resolve_list, lp_name_resolve_order());
453 ptr = name_resolve_list;
454 if (!ptr || !*ptr) ptr = "host";
456 while (next_token(&ptr, tok, LIST_SEP)) {
457 if(strequal(tok, "host") || strequal(tok, "hosts")) {
460 * "host" means do a localhost, or dns lookup.
465 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
467 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
468 putip((char *)return_ip,(char *)hp->h_addr);
472 } else if(strequal( tok, "lmhosts")) {
475 * "lmhosts" means parse the local lmhosts file.
482 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
484 fp = startlmhosts( LMHOSTSFILE );
486 while( getlmhostsent(fp, lmhost_name, &name_type, return_ip ) ) {
487 if( strequal(name, lmhost_name )) {
495 } else if(strequal( tok, "wins")) {
500 * "wins" means do a unicast lookup to the WINS server.
501 * Ignore if there is no WINS server specified or if the
502 * WINS server is one of our interfaces (if we're being
503 * called from within nmbd - we can't do this call as we
507 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
509 if(*lp_wins_server()) {
510 struct in_addr wins_ip = *interpret_addr2(lp_wins_server());
511 BOOL wins_ismyip = ismyip(wins_ip);
513 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
514 sock = open_socket_in( SOCK_DGRAM, 0, 3,
515 interpret_addr(lp_socket_address()) );
518 struct in_addr *iplist = NULL;
520 iplist = name_query(sock, name, 0x20, False, True, wins_ip, &count, NULL);
522 *return_ip = iplist[0];
523 free((char *)iplist);
531 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
533 } else if(strequal( tok, "bcast")) {
538 * "bcast" means do a broadcast lookup on all the local interfaces.
541 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
543 sock = open_socket_in( SOCK_DGRAM, 0, 3,
544 interpret_addr(lp_socket_address()) );
547 struct in_addr *iplist = NULL;
549 int num_interfaces = iface_count();
550 set_socket_options(sock,"SO_BROADCAST");
552 * Lookup the name on all the interfaces, return on
553 * the first successful match.
555 for( i = 0; i < num_interfaces; i++) {
556 struct in_addr 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));