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 const 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 query to find someones IP
87 returns an array of IP addresses or NULL if none
88 *count will be set to the number of addresses returned
89 ****************************************************************************/
90 struct in_addr
*name_query(int fd
,const char *name
,int name_type
, BOOL bcast
,BOOL recurse
,
91 struct in_addr to_ip
, int *count
, void (*fn
)(struct packet_struct
*))
95 int retry_time
= bcast
?250:2000;
97 struct packet_struct p
;
98 struct packet_struct
*p2
;
99 struct nmb_packet
*nmb
= &p
.packet
.nmb
;
100 static int name_trn_id
= 0;
101 struct in_addr
*ip_list
= NULL
;
103 memset((char *)&p
,'\0',sizeof(p
));
106 if (!name_trn_id
) name_trn_id
= ((unsigned)time(NULL
)%(unsigned)0x7FFF) +
107 ((unsigned)getpid()%(unsigned)100);
108 name_trn_id
= (name_trn_id
+1) % (unsigned)0x7FFF;
110 nmb
->header
.name_trn_id
= name_trn_id
;
111 nmb
->header
.opcode
= 0;
112 nmb
->header
.response
= False
;
113 nmb
->header
.nm_flags
.bcast
= bcast
;
114 nmb
->header
.nm_flags
.recursion_available
= False
;
115 nmb
->header
.nm_flags
.recursion_desired
= recurse
;
116 nmb
->header
.nm_flags
.trunc
= False
;
117 nmb
->header
.nm_flags
.authoritative
= False
;
118 nmb
->header
.rcode
= 0;
119 nmb
->header
.qdcount
= 1;
120 nmb
->header
.ancount
= 0;
121 nmb
->header
.nscount
= 0;
122 nmb
->header
.arcount
= 0;
124 make_nmb_name(&nmb
->question
.question_name
,name
,name_type
);
126 nmb
->question
.question_type
= 0x20;
127 nmb
->question
.question_class
= 0x1;
132 p
.timestamp
= time(NULL
);
133 p
.packet_type
= NMB_PACKET
;
137 if (!send_packet(&p
))
144 struct timeval tval2
;
145 GetTimeOfDay(&tval2
);
146 if (TvalDiff(&tval
,&tval2
) > retry_time
)
150 if (!found
&& !send_packet(&p
))
156 if ((p2
=receive_packet(fd
,NMB_PACKET
,90)))
158 struct nmb_packet
*nmb2
= &p2
->packet
.nmb
;
159 debug_nmb_packet(p2
);
161 if (nmb
->header
.name_trn_id
!= nmb2
->header
.name_trn_id
||
162 !nmb2
->header
.response
)
165 * Its not for us - maybe deal with it later
166 * (put it on the queue?).
175 if (nmb2
->header
.opcode
!= 0 ||
176 nmb2
->header
.nm_flags
.bcast
||
177 nmb2
->header
.rcode
||
178 !nmb2
->header
.ancount
)
181 * XXXX what do we do with this? Could be a redirect, but
182 * we'll discard it for the moment.
188 ip_list
= (struct in_addr
*)Realloc(ip_list
, sizeof(ip_list
[0]) *
189 ((*count
)+nmb2
->answers
->rdlength
/6));
192 DEBUG(fn
?3:2,("Got a positive name query response from %s ( ",
194 for (i
=0;i
<nmb2
->answers
->rdlength
/6;i
++)
196 putip((char *)&ip_list
[(*count
)],&nmb2
->answers
->rdata
[2+i
*6]);
197 DEBUG(fn
?3:2,("%s ",inet_ntoa(ip_list
[(*count
)])));
200 DEBUG(fn
?3:2,(")\n"));
210 * If we're doing a unicast lookup we only
211 * expect one reply. Don't wait the full 2
212 * seconds if we got one. JRA.
222 /********************************************************
223 Start parsing the lmhosts file.
224 *********************************************************/
226 FILE *startlmhosts(char *fname
)
228 FILE *fp
= sys_fopen(fname
,"r");
230 DEBUG(4,("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
231 fname
, strerror(errno
)));
237 /********************************************************
238 Parse the next line in the lmhosts file.
239 *********************************************************/
240 BOOL
getlmhostsent( FILE *fp
, pstring name
, int *name_type
, struct in_addr
*ipaddr
)
244 while(!feof(fp
) && !ferror(fp
)) {
245 pstring ip
,flags
,extra
;
251 if (!fgets_slash(line
,sizeof(pstring
),fp
))
263 if (next_token(&ptr
,ip
,NULL
,sizeof(ip
)))
265 if (next_token(&ptr
,name
,NULL
, sizeof(pstring
)))
267 if (next_token(&ptr
,flags
,NULL
, sizeof(flags
)))
269 if (next_token(&ptr
,extra
,NULL
, sizeof(extra
)))
275 if (count
> 0 && count
< 2)
277 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line
));
283 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
287 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip
, name
, flags
));
289 if (strchr(flags
,'G') || strchr(flags
,'S'))
291 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
295 *ipaddr
= *interpret_addr2(ip
);
297 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
298 then only add that name type. */
299 if((ptr
= strchr(name
, '#')) != NULL
)
304 *name_type
= (int)strtol(ptr
, &endptr
, 16);
306 if(!*ptr
|| (endptr
== ptr
))
308 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name
));
312 *(--ptr
) = '\0'; /* Truncate at the '#' */
321 /********************************************************
322 Finish parsing the lmhosts file.
323 *********************************************************/
325 void endlmhosts(FILE *fp
)
330 /********************************************************
331 resolve via "bcast" method
332 *********************************************************/
333 static BOOL
resolve_bcast(const char *name
, struct in_addr
*return_ip
, int name_type
)
338 * "bcast" means do a broadcast lookup on all the local interfaces.
341 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name
, name_type
));
343 sock
= open_socket_in( SOCK_DGRAM
, 0, 3,
344 interpret_addr(lp_socket_address()), True
);
347 struct in_addr
*iplist
= NULL
;
349 int num_interfaces
= iface_count();
350 set_socket_options(sock
,"SO_BROADCAST");
352 * Lookup the name on all the interfaces, return on
353 * the first successful match.
355 for( i
= 0; i
< num_interfaces
; i
++) {
356 struct in_addr sendto_ip
;
357 /* Done this way to fix compiler error on IRIX 5.x */
358 sendto_ip
= *iface_bcast(*iface_n_ip(i
));
359 iplist
= name_query(sock
, name
, name_type
, True
,
360 True
, sendto_ip
, &count
, NULL
);
362 *return_ip
= iplist
[0];
363 free((char *)iplist
);
376 /********************************************************
377 resolve via "wins" method
378 *********************************************************/
379 static BOOL
resolve_wins(const char *name
, struct in_addr
*return_ip
, int name_type
)
382 struct in_addr wins_ip
;
386 * "wins" means do a unicast lookup to the WINS server.
387 * Ignore if there is no WINS server specified or if the
388 * WINS server is one of our interfaces (if we're being
389 * called from within nmbd - we can't do this call as we
393 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name
, name_type
));
395 if(!*lp_wins_server()) {
396 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
400 wins_ip
= *interpret_addr2(lp_wins_server());
401 wins_ismyip
= ismyip(wins_ip
);
403 if((wins_ismyip
&& !global_in_nmbd
) || !wins_ismyip
) {
404 sock
= open_socket_in( SOCK_DGRAM
, 0, 3,
405 interpret_addr(lp_socket_address()), True
);
408 struct in_addr
*iplist
= NULL
;
410 iplist
= name_query(sock
, name
, name_type
, False
,
411 True
, wins_ip
, &count
, NULL
);
413 *return_ip
= iplist
[0];
414 free((char *)iplist
);
426 /********************************************************
427 resolve via "lmhosts" method
428 *********************************************************/
429 static BOOL
resolve_lmhosts(const char *name
, struct in_addr
*return_ip
, int name_type
)
432 * "lmhosts" means parse the local lmhosts file.
439 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name
, name_type
));
441 fp
= startlmhosts( LMHOSTSFILE
);
443 while (getlmhostsent(fp
, lmhost_name
, &name_type2
, return_ip
)) {
444 if (strequal(name
, lmhost_name
) &&
445 ((name_type2
== -1) || (name_type
== name_type2
))
457 /********************************************************
458 resolve via "hosts" method
459 *********************************************************/
460 static BOOL
resolve_hosts(const char *name
, struct in_addr
*return_ip
)
463 * "host" means do a localhost, or dns lookup.
467 DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name
));
469 if (((hp
= Get_Hostbyname(name
)) != NULL
) && (hp
->h_addr
!= NULL
)) {
470 putip((char *)return_ip
,(char *)hp
->h_addr
);
477 /********************************************************
478 Resolve a name into an IP address. Use this function if
479 the string is either an IP address, DNS or host name
480 or NetBIOS name. This uses the name switch in the
481 smb.conf to determine the order of name resolution.
482 *********************************************************/
483 BOOL
resolve_name(const char *name
, struct in_addr
*return_ip
, int name_type
)
486 BOOL pure_address
= True
;
487 pstring name_resolve_list
;
491 if (strcmp(name
,"0.0.0.0") == 0) {
492 return_ip
->s_addr
= 0;
495 if (strcmp(name
,"255.255.255.255") == 0) {
496 return_ip
->s_addr
= 0xFFFFFFFF;
500 for (i
=0; pure_address
&& name
[i
]; i
++)
501 if (!(isdigit((int)name
[i
]) || name
[i
] == '.'))
502 pure_address
= False
;
504 /* if it's in the form of an IP address then get the lib to interpret it */
506 return_ip
->s_addr
= inet_addr(name
);
510 pstrcpy(name_resolve_list
, lp_name_resolve_order());
511 ptr
= name_resolve_list
;
512 if (!ptr
|| !*ptr
) ptr
= "host";
514 while (next_token(&ptr
, tok
, LIST_SEP
, sizeof(tok
))) {
515 if((strequal(tok
, "host") || strequal(tok
, "hosts"))) {
516 if (name_type
== 0x20 && resolve_hosts(name
, return_ip
)) {
519 } else if(strequal( tok
, "lmhosts")) {
520 if (resolve_lmhosts(name
, return_ip
, name_type
)) {
523 } else if(strequal( tok
, "wins")) {
524 /* don't resolve 1D via WINS */
525 if (name_type
!= 0x1D &&
526 resolve_wins(name
, return_ip
, name_type
)) {
529 } else if(strequal( tok
, "bcast")) {
530 if (resolve_bcast(name
, return_ip
, name_type
)) {
534 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok
));
543 /********************************************************
544 find the IP address of the master browser or DMB for a workgroup
545 *********************************************************/
546 BOOL
find_master_ip(char *group
, struct in_addr
*master_ip
)
548 if (resolve_name(group
, master_ip
, 0x1D)) return True
;
550 return resolve_name(group
, master_ip
, 0x1B);