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 *********************************************************/
424 BOOL resolve_name(char *name, struct in_addr *return_ip)
427 BOOL pure_address = True;
428 pstring name_resolve_list;
432 if (strcmp(name,"0.0.0.0") == 0) {
433 return_ip->s_addr = 0;
436 if (strcmp(name,"255.255.255.255") == 0) {
437 return_ip->s_addr = 0xFFFFFFFF;
441 for (i=0; pure_address && name[i]; i++)
442 if (!(isdigit((int)name[i]) || name[i] == '.'))
443 pure_address = False;
445 /* if it's in the form of an IP address then get the lib to interpret it */
447 return_ip->s_addr = inet_addr(name);
451 pstrcpy(name_resolve_list, lp_name_resolve_order());
452 ptr = name_resolve_list;
453 if (!ptr || !*ptr) ptr = "host";
455 while (next_token(&ptr, tok, LIST_SEP, sizeof(tok))) {
456 if(strequal(tok, "host") || strequal(tok, "hosts")) {
459 * "host" means do a localhost, or dns lookup.
464 DEBUG(3,("resolve_name: Attempting host lookup for name %s\n", name));
466 if (((hp = Get_Hostbyname(name)) != NULL) && (hp->h_addr != NULL)) {
467 putip((char *)return_ip,(char *)hp->h_addr);
471 } else if(strequal( tok, "lmhosts")) {
474 * "lmhosts" means parse the local lmhosts file.
481 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s\n", name));
483 fp = startlmhosts( LMHOSTSFILE );
485 while( getlmhostsent(fp, lmhost_name, &name_type, return_ip ) ) {
486 if( strequal(name, lmhost_name )) {
494 } else if(strequal( tok, "wins")) {
499 * "wins" means do a unicast lookup to the WINS server.
500 * Ignore if there is no WINS server specified or if the
501 * WINS server is one of our interfaces (if we're being
502 * called from within nmbd - we can't do this call as we
506 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x20>\n", name));
508 if(*lp_wins_server()) {
509 struct in_addr wins_ip = *interpret_addr2(lp_wins_server());
510 BOOL wins_ismyip = ismyip(wins_ip);
512 if((wins_ismyip && !global_in_nmbd) || !wins_ismyip) {
513 sock = open_socket_in( SOCK_DGRAM, 0, 3,
514 interpret_addr(lp_socket_address()) );
517 struct in_addr *iplist = NULL;
519 iplist = name_query(sock, name, 0x20, False, True, wins_ip, &count, NULL);
521 *return_ip = iplist[0];
522 free((char *)iplist);
530 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
532 } else if(strequal( tok, "bcast")) {
537 * "bcast" means do a broadcast lookup on all the local interfaces.
540 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x20>\n", name));
542 sock = open_socket_in( SOCK_DGRAM, 0, 3,
543 interpret_addr(lp_socket_address()) );
546 struct in_addr *iplist = NULL;
548 int num_interfaces = iface_count();
549 set_socket_options(sock,"SO_BROADCAST");
551 * Lookup the name on all the interfaces, return on
552 * the first successful match.
554 for( i = 0; i < num_interfaces; i++) {
555 struct in_addr sendto_ip;
556 /* Done this way to fix compiler error on IRIX 5.x */
557 sendto_ip = *iface_bcast(*iface_n_ip(i));
558 iplist = name_query(sock, name, 0x20, True, False, sendto_ip, &count, NULL);
560 *return_ip = iplist[0];
561 free((char *)iplist);
570 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok));