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.
25 const char *unix_error_string (int error_num
);
27 extern int DEBUGLEVEL
;
29 /* nmbd.c sets this to True. */
30 const BOOL global_in_nmbd
= False
;
32 /****************************************************************************
33 interpret a node status response
34 ****************************************************************************/
35 static void _interpret_node_status(char *p
, char *master
,char *rname
)
37 int numnames
= CVAL(p
,0);
38 DEBUG(1,("received %d names\n",numnames
));
40 if (rname
) *rname
= 0;
41 if (master
) *master
= 0;
55 fstrcat(flags
, (p
[0] & 0x80) ? "<GROUP> " : " ");
56 if ((p
[0] & 0x60) == 0x00) fstrcat(flags
,"B ");
57 if ((p
[0] & 0x60) == 0x20) fstrcat(flags
,"P ");
58 if ((p
[0] & 0x60) == 0x40) fstrcat(flags
,"M ");
59 if ((p
[0] & 0x60) == 0x60) fstrcat(flags
,"H ");
60 if (p
[0] & 0x10) fstrcat(flags
,"<DEREGISTERING> ");
61 if (p
[0] & 0x08) fstrcat(flags
,"<CONFLICT> ");
62 if (p
[0] & 0x04) fstrcat(flags
,"<ACTIVE> ");
63 if (p
[0] & 0x02) fstrcat(flags
,"<PERMANENT> ");
65 if (master
&& !*master
&& type
== 0x1d) {
66 StrnCpy(master
,qname
,15);
67 trim_string(master
,NULL
," ");
70 if (rname
&& !*rname
&& type
== 0x20 && !(p
[0]&0x80)) {
71 StrnCpy(rname
,qname
,15);
72 trim_string(rname
,NULL
," ");
75 for (i
= strlen( qname
) ; --i
>= 0 ; ) {
76 if (!isprint((int)qname
[i
])) qname
[i
] = '.';
78 DEBUG(1,("\t%-15s <%02x> - %s\n",qname
,type
,flags
));
81 DEBUG(1,("num_good_sends=%d num_good_receives=%d\n",
82 IVAL(p
,20),IVAL(p
,24)));
86 /****************************************************************************
87 do a netbios name query to find someones IP
88 returns an array of IP addresses or NULL if none
89 *count will be set to the number of addresses returned
90 ****************************************************************************/
91 struct in_addr
*name_query(int fd
,const char *name
,int name_type
, BOOL bcast
,BOOL recurse
,
92 struct in_addr to_ip
, int *count
, void (*fn
)(struct packet_struct
*))
96 int retry_time
= bcast
?250:2000;
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;
102 struct in_addr
*ip_list
= NULL
;
104 memset((char *)&p
,'\0',sizeof(p
));
107 if (!name_trn_id
) name_trn_id
= ((unsigned)time(NULL
)%(unsigned)0x7FFF) +
108 ((unsigned)getpid()%(unsigned)100);
109 name_trn_id
= (name_trn_id
+1) % (unsigned)0x7FFF;
111 nmb
->header
.name_trn_id
= name_trn_id
;
112 nmb
->header
.opcode
= 0;
113 nmb
->header
.response
= False
;
114 nmb
->header
.nm_flags
.bcast
= bcast
;
115 nmb
->header
.nm_flags
.recursion_available
= False
;
116 nmb
->header
.nm_flags
.recursion_desired
= recurse
;
117 nmb
->header
.nm_flags
.trunc
= False
;
118 nmb
->header
.nm_flags
.authoritative
= False
;
119 nmb
->header
.rcode
= 0;
120 nmb
->header
.qdcount
= 1;
121 nmb
->header
.ancount
= 0;
122 nmb
->header
.nscount
= 0;
123 nmb
->header
.arcount
= 0;
125 make_nmb_name(&nmb
->question
.question_name
,name
,name_type
);
127 nmb
->question
.question_type
= 0x20;
128 nmb
->question
.question_class
= 0x1;
133 p
.timestamp
= time(NULL
);
134 p
.packet_type
= NMB_PACKET
;
138 if (!send_packet(&p
))
145 struct timeval tval2
;
146 GetTimeOfDay(&tval2
);
147 if (TvalDiff(&tval
,&tval2
) > retry_time
)
151 if (!found
&& !send_packet(&p
))
157 if ((p2
=receive_packet(fd
,NMB_PACKET
,90)))
159 struct nmb_packet
*nmb2
= &p2
->packet
.nmb
;
160 debug_nmb_packet(p2
);
162 if (nmb
->header
.name_trn_id
!= nmb2
->header
.name_trn_id
||
163 !nmb2
->header
.response
)
166 * Its not for us - maybe deal with it later
167 * (put it on the queue?).
176 if (nmb2
->header
.opcode
!= 0 ||
177 nmb2
->header
.nm_flags
.bcast
||
178 nmb2
->header
.rcode
||
179 !nmb2
->header
.ancount
)
182 * XXXX what do we do with this? Could be a redirect, but
183 * we'll discard it for the moment.
189 ip_list
= (struct in_addr
*)Realloc(ip_list
, sizeof(ip_list
[0]) *
190 ((*count
)+nmb2
->answers
->rdlength
/6));
193 DEBUG(fn
?3:2,("Got a positive name query response from %s ( ",
195 for (i
=0;i
<nmb2
->answers
->rdlength
/6;i
++)
197 putip((char *)&ip_list
[(*count
)],&nmb2
->answers
->rdata
[2+i
*6]);
198 DEBUG(fn
?3:2,("%s ",inet_ntoa(ip_list
[(*count
)])));
201 DEBUG(fn
?3:2,(")\n"));
211 * If we're doing a unicast lookup we only
212 * expect one reply. Don't wait the full 2
213 * seconds if we got one. JRA.
223 /********************************************************
224 Start parsing the lmhosts file.
225 *********************************************************/
227 FILE *startlmhosts(const char *fname
)
229 FILE *fp
= sys_fopen(fname
,"r");
231 DEBUG(4,("startlmhosts: Cannot open lmhosts file %s. Error was %s\n",
232 fname
, unix_error_string (errno
)));
238 /********************************************************
239 Parse the next line in the lmhosts file.
240 *********************************************************/
241 BOOL
getlmhostsent( FILE *fp
, pstring name
, int *name_type
, struct in_addr
*ipaddr
)
245 while(!feof(fp
) && !ferror(fp
)) {
246 pstring ip
,flags
,extra
;
252 if (!fgets_slash(line
,sizeof(pstring
),fp
))
264 if (next_token(&ptr
,ip
,NULL
,sizeof(ip
)))
266 if (next_token(&ptr
,name
,NULL
, sizeof(pstring
)))
268 if (next_token(&ptr
,flags
,NULL
, sizeof(flags
)))
270 if (next_token(&ptr
,extra
,NULL
, sizeof(extra
)))
276 if (count
> 0 && count
< 2)
278 DEBUG(0,("getlmhostsent: Ill formed hosts line [%s]\n",line
));
284 DEBUG(0,("getlmhostsent: too many columns in lmhosts file (obsolete syntax)\n"));
288 DEBUG(4, ("getlmhostsent: lmhost entry: %s %s %s\n", ip
, name
, flags
));
290 if (strchr(flags
,'G') || strchr(flags
,'S'))
292 DEBUG(0,("getlmhostsent: group flag in lmhosts ignored (obsolete)\n"));
296 *ipaddr
= *interpret_addr2(ip
);
298 /* Extra feature. If the name ends in '#XX', where XX is a hex number,
299 then only add that name type. */
300 if((ptr
= strchr(name
, '#')) != NULL
)
305 *name_type
= (int)strtol(ptr
, &endptr
, 16);
307 if(!*ptr
|| (endptr
== ptr
))
309 DEBUG(0,("getlmhostsent: invalid name %s containing '#'.\n", name
));
313 *(--ptr
) = '\0'; /* Truncate at the '#' */
322 /********************************************************
323 Finish parsing the lmhosts file.
324 *********************************************************/
326 void endlmhosts(FILE *fp
)
331 /********************************************************
332 resolve via "bcast" method
333 *********************************************************/
334 static BOOL
resolve_bcast(const char *name
, struct in_addr
*return_ip
, int name_type
)
339 * "bcast" means do a broadcast lookup on all the local interfaces.
342 DEBUG(3,("resolve_name: Attempting broadcast lookup for name %s<0x%x>\n", name
, name_type
));
344 sock
= open_socket_in( SOCK_DGRAM
, 0, 3,
345 interpret_addr(lp_socket_address()), True
);
348 struct in_addr
*iplist
= NULL
;
350 int num_interfaces
= iface_count();
351 static char so_broadcast
[] = "SO_BROADCAST";
352 set_socket_options(sock
, so_broadcast
);
354 * Lookup the name on all the interfaces, return on
355 * the first successful match.
357 for( i
= 0; i
< num_interfaces
; i
++) {
358 struct in_addr sendto_ip
;
359 /* Done this way to fix compiler error on IRIX 5.x */
360 sendto_ip
= *iface_bcast(*iface_n_ip(i
));
361 iplist
= name_query(sock
, name
, name_type
, True
,
362 True
, sendto_ip
, &count
, NULL
);
364 *return_ip
= iplist
[0];
365 free((char *)iplist
);
378 /********************************************************
379 resolve via "wins" method
380 *********************************************************/
381 static BOOL
resolve_wins(const char *name
, struct in_addr
*return_ip
, int name_type
)
384 struct in_addr wins_ip
;
388 * "wins" means do a unicast lookup to the WINS server.
389 * Ignore if there is no WINS server specified or if the
390 * WINS server is one of our interfaces (if we're being
391 * called from within nmbd - we can't do this call as we
395 DEBUG(3,("resolve_name: Attempting wins lookup for name %s<0x%x>\n", name
, name_type
));
397 if(!*lp_wins_server()) {
398 DEBUG(3,("resolve_name: WINS server resolution selected and no WINS server present.\n"));
402 wins_ip
= *interpret_addr2(lp_wins_server());
403 wins_ismyip
= ismyip(wins_ip
);
405 if((wins_ismyip
&& !global_in_nmbd
) || !wins_ismyip
) {
406 sock
= open_socket_in( SOCK_DGRAM
, 0, 3,
407 interpret_addr(lp_socket_address()), True
);
410 struct in_addr
*iplist
= NULL
;
412 iplist
= name_query(sock
, name
, name_type
, False
,
413 True
, wins_ip
, &count
, NULL
);
415 *return_ip
= iplist
[0];
416 free((char *)iplist
);
428 /********************************************************
429 resolve via "lmhosts" method
430 *********************************************************/
431 static BOOL
resolve_lmhosts(const char *name
, struct in_addr
*return_ip
, int name_type
)
434 * "lmhosts" means parse the local lmhosts file.
441 DEBUG(3,("resolve_name: Attempting lmhosts lookup for name %s<0x%x>\n", name
, name_type
));
443 fp
= startlmhosts( LMHOSTSFILE
);
445 while (getlmhostsent(fp
, lmhost_name
, &name_type2
, return_ip
)) {
446 if (strequal(name
, lmhost_name
) &&
447 ((name_type2
== -1) || (name_type
== name_type2
))
459 /********************************************************
460 resolve via "hosts" method
461 *********************************************************/
462 static BOOL
resolve_hosts(const char *name
, struct in_addr
*return_ip
)
465 * "host" means do a localhost, or dns lookup.
469 DEBUG(3,("resolve_name: Attempting host lookup for name %s<0x20>\n", name
));
471 if (((hp
= Get_Hostbyname(name
)) != NULL
) && (hp
->h_addr
!= NULL
)) {
472 putip((char *)return_ip
,(char *)hp
->h_addr
);
479 /********************************************************
480 Resolve a name into an IP address. Use this function if
481 the string is either an IP address, DNS or host name
482 or NetBIOS name. This uses the name switch in the
483 smb.conf to determine the order of name resolution.
484 *********************************************************/
485 BOOL
resolve_name(const char *name
, struct in_addr
*return_ip
, int name_type
)
488 BOOL pure_address
= True
;
489 pstring name_resolve_list
;
493 if (strcmp(name
,"0.0.0.0") == 0) {
494 return_ip
->s_addr
= 0;
497 if (strcmp(name
,"255.255.255.255") == 0) {
498 return_ip
->s_addr
= 0xFFFFFFFF;
502 for (i
=0; pure_address
&& name
[i
]; i
++)
503 if (!(isdigit((int)name
[i
]) || name
[i
] == '.'))
504 pure_address
= False
;
506 /* if it's in the form of an IP address then get the lib to interpret it */
508 return_ip
->s_addr
= inet_addr(name
);
512 pstrcpy(name_resolve_list
, lp_name_resolve_order());
513 if (name_resolve_list
== NULL
|| *name_resolve_list
== '\0')
514 pstrcpy(name_resolve_list
, "host");
515 ptr
= name_resolve_list
;
517 while (next_token(&ptr
, tok
, LIST_SEP
, sizeof(tok
))) {
518 if((strequal(tok
, "host") || strequal(tok
, "hosts"))) {
519 if (name_type
== 0x20 && resolve_hosts(name
, return_ip
)) {
522 } else if(strequal( tok
, "lmhosts")) {
523 if (resolve_lmhosts(name
, return_ip
, name_type
)) {
526 } else if(strequal( tok
, "wins")) {
527 /* don't resolve 1D via WINS */
528 if (name_type
!= 0x1D &&
529 resolve_wins(name
, return_ip
, name_type
)) {
532 } else if(strequal( tok
, "bcast")) {
533 if (resolve_bcast(name
, return_ip
, name_type
)) {
537 DEBUG(0,("resolve_name: unknown name switch type %s\n", tok
));
546 /********************************************************
547 find the IP address of the master browser or DMB for a workgroup
548 *********************************************************/
549 BOOL
find_master_ip(char *group
, struct in_addr
*master_ip
)
551 if (resolve_name(group
, master_ip
, 0x1D)) return True
;
553 return resolve_name(group
, master_ip
, 0x1B);