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)
429 BOOL pure_address = True;
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(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 for (p=strtok(lp_name_resolve_order(),LIST_SEP); p; p = strtok(NULL,LIST_SEP)) {
451 if(strequal(p, "host") || strequal(p, "hosts")) {
454 * "host" means do a localhost, or dns lookup.
459 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n"));
461 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
462 putip((char *)return_ip,(char *)hp->h_addr);
466 } else if(strequal( p, "lmhosts")) {
469 * "lmhosts" means parse the local lmhosts file.
476 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n"));
478 fp = startlmhosts( LMHOSTSFILE );
480 while( getlmhostsent(fp, lmhost_name, &name_type, return_ip ) ) {
481 if( strequal(name, lmhost_name )) {
489 } else if(strequal( p, "wins")) {
494 * "wins" means do a unicast lookup to the WINS server.
495 * Ignore if there is no WINS server specified or if the
496 * WINS server is one of our interfaces (if we're being
497 * called from within nmbd - we can't do this call as we
501 DEBUG(3,("resolve_name: Attempting wins lookup for name %s\n"));
503 if(*lp_wins_server()) {
504 struct in_addr wins_ip = *interpret_addr2(lp_wins_server());
505 BOOL wins_ismyip = ismyip(wins_ip);
507 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
508 sock = open_socket_in( SOCK_DGRAM, 0, 3,
509 interpret_addr(lp_socket_address()) );
512 struct in_addr *iplist = NULL;
514 iplist = name_query(sock, name, 0x20, False, True, wins_ip, &count, NULL);
516 *return_ip = iplist[0];
517 free((char *)iplist);
525 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
527 } else if(strequal( p, "bcast")) {
532 * "bcast" means do a broadcast lookup on all the local interfaces.
535 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s\n"));
537 sock = open_socket_in( SOCK_DGRAM, 0, 3,
538 interpret_addr(lp_socket_address()) );
541 struct in_addr *iplist = NULL;
543 int num_interfaces = iface_count();
544 set_socket_options(sock,"SO_BROADCAST");
546 * Lookup the name on all the interfaces, return on
547 * the first successful match.
549 for( i = 0; i < num_interfaces; i++) {
550 struct in_addr sendto_ip = *iface_bcast(*iface_n_ip(i));
551 iplist = name_query(sock, name, 0x20, True, False, sendto_ip, &count, NULL);
553 *return_ip = iplist[0];
554 free((char *)iplist);
563 DEBUG(0,("resolve_name: unknown name switch type %s\n", p));