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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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(const 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 static char so_broadcast
[] = "SO_BROADCAST";
351 set_socket_options(sock
, so_broadcast
);
353 * Lookup the name on all the interfaces, return on
354 * the first successful match.
356 for( i
= 0; i
< num_interfaces
; i
++) {
357 struct in_addr sendto_ip
;
358 /* Done this way to fix compiler error on IRIX 5.x */
359 sendto_ip
= *iface_bcast(*iface_n_ip(i
));
360 iplist
= name_query(sock
, name
, name_type
, True
,
361 True
, sendto_ip
, &count
, NULL
);
363 *return_ip
= iplist
[0];
364 free((char *)iplist
);
377 /********************************************************
378 resolve via "wins" method
379 *********************************************************/
380 static BOOL
resolve_wins(const char *name
, struct in_addr
*return_ip
, int name_type
)
383 struct in_addr wins_ip
;
387 * "wins" means do a unicast lookup to the WINS server.
388 * Ignore if there is no WINS server specified or if the
389 * WINS server is one of our interfaces (if we're being
390 * called from within nmbd - we can't do this call as we
394 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name
, name_type
));
396 if(!*lp_wins_server()) {
397 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
401 wins_ip
= *interpret_addr2(lp_wins_server());
402 wins_ismyip
= ismyip(wins_ip
);
404 if((wins_ismyip
&& !global_in_nmbd
) || !wins_ismyip
) {
405 sock
= open_socket_in( SOCK_DGRAM
, 0, 3,
406 interpret_addr(lp_socket_address()), True
);
409 struct in_addr
*iplist
= NULL
;
411 iplist
= name_query(sock
, name
, name_type
, False
,
412 True
, wins_ip
, &count
, NULL
);
414 *return_ip
= iplist
[0];
415 free((char *)iplist
);
427 /********************************************************
428 resolve via "lmhosts" method
429 *********************************************************/
430 static BOOL
resolve_lmhosts(const char *name
, struct in_addr
*return_ip
, int name_type
)
433 * "lmhosts" means parse the local lmhosts file.
440 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name
, name_type
));
442 fp
= startlmhosts( LMHOSTSFILE
);
444 while (getlmhostsent(fp
, lmhost_name
, &name_type2
, return_ip
)) {
445 if (strequal(name
, lmhost_name
) &&
446 ((name_type2
== -1) || (name_type
== name_type2
))
458 /********************************************************
459 resolve via "hosts" method
460 *********************************************************/
461 static BOOL
resolve_hosts(const char *name
, struct in_addr
*return_ip
)
464 * "host" means do a localhost, or dns lookup.
468 DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name
));
470 if (((hp
= Get_Hostbyname(name
)) != NULL
) && (hp
->h_addr
!= NULL
)) {
471 putip((char *)return_ip
,(char *)hp
->h_addr
);
478 /********************************************************
479 Resolve a name into an IP address. Use this function if
480 the string is either an IP address, DNS or host name
481 or NetBIOS name. This uses the name switch in the
482 smb.conf to determine the order of name resolution.
483 *********************************************************/
484 BOOL
resolve_name(const char *name
, struct in_addr
*return_ip
, int name_type
)
487 BOOL pure_address
= True
;
488 pstring name_resolve_list
;
492 if (strcmp(name
,"0.0.0.0") == 0) {
493 return_ip
->s_addr
= 0;
496 if (strcmp(name
,"255.255.255.255") == 0) {
497 return_ip
->s_addr
= 0xFFFFFFFF;
501 for (i
=0; pure_address
&& name
[i
]; i
++)
502 if (!(isdigit((int)name
[i
]) || name
[i
] == '.'))
503 pure_address
= False
;
505 /* if it's in the form of an IP address then get the lib to interpret it */
507 return_ip
->s_addr
= inet_addr(name
);
511 pstrcpy(name_resolve_list
, lp_name_resolve_order());
512 if (name_resolve_list
== NULL
|| *name_resolve_list
== '\0')
513 pstrcpy(name_resolve_list
, "host");
514 ptr
= name_resolve_list
;
516 while (next_token(&ptr
, tok
, LIST_SEP
, sizeof(tok
))) {
517 if((strequal(tok
, "host") || strequal(tok
, "hosts"))) {
518 if (name_type
== 0x20 && resolve_hosts(name
, return_ip
)) {
521 } else if(strequal( tok
, "lmhosts")) {
522 if (resolve_lmhosts(name
, return_ip
, name_type
)) {
525 } else if(strequal( tok
, "wins")) {
526 /* don't resolve 1D via WINS */
527 if (name_type
!= 0x1D &&
528 resolve_wins(name
, return_ip
, name_type
)) {
531 } else if(strequal( tok
, "bcast")) {
532 if (resolve_bcast(name
, return_ip
, name_type
)) {
536 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok
));
545 /********************************************************
546 find the IP address of the master browser or DMB for a workgroup
547 *********************************************************/
548 BOOL
find_master_ip(char *group
, struct in_addr
*master_ip
)
550 if (resolve_name(group
, master_ip
, 0x1D)) return True
;
552 return resolve_name(group
, master_ip
, 0x1B);