2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1996
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.
21 Module name: namedbname.c
25 14 jan 96: lkcl@pires.co.uk
26 added multiple workgroup domain master support
28 04 jul 96: lkcl@pires.co.uk
29 created module namedbname containing name database functions
34 extern int DEBUGLEVEL
;
37 extern struct in_addr ipzero
;
38 extern struct in_addr ipgrp
;
40 extern struct subnet_record
*subnetlist
;
42 #define WINS_LIST "wins.dat"
45 /****************************************************************************
46 true if two netbios names are equal
47 ****************************************************************************/
48 BOOL
name_equal(struct nmb_name
*n1
,struct nmb_name
*n2
)
50 return n1
->name_type
== n2
->name_type
&&
51 strequal(n1
->name
,n2
->name
) &&
52 strequal(n1
->scope
,n2
->scope
);
56 /****************************************************************************
57 true if the netbios name is ^1^2__MSBROWSE__^2^1
59 note: this name is registered if as a master browser or backup browser
60 you are responsible for a workgroup (when you announce a domain by
61 broadcasting on your local subnet, you announce it as coming from this
62 name: see announce_host()).
64 **************************************************************************/
65 BOOL
ms_browser_name(char *name
, int type
)
67 return strequal(name
,MSBROWSE
) && type
== 0x01;
71 /****************************************************************************
72 add a netbios name into the namelist
73 **************************************************************************/
74 static void add_name(struct subnet_record
*d
, struct name_record
*n
)
76 struct name_record
*n2
;
88 for (n2
= d
->namelist
; n2
->next
; n2
= n2
->next
) ;
96 /****************************************************************************
97 remove a name from the namelist. The pointer must be an element just
99 **************************************************************************/
100 void remove_name(struct subnet_record
*d
, struct name_record
*n
)
102 struct name_record
*nlist
;
107 while (nlist
&& nlist
!= n
) nlist
= nlist
->next
;
111 if (nlist
->next
) nlist
->next
->prev
= nlist
->prev
;
112 if (nlist
->prev
) nlist
->prev
->next
= nlist
->next
;
118 /****************************************************************************
119 find a name in a namelist.
120 **************************************************************************/
121 struct name_record
*find_name(struct name_record
*n
,
122 struct nmb_name
*name
,
123 int search
, struct in_addr ip
)
125 struct name_record
*ret
;
127 for (ret
= n
; ret
; ret
= ret
->next
)
129 if (name_equal(&ret
->name
,name
))
131 /* self search: self names only */
132 if ((search
&FIND_SELF
) == FIND_SELF
&& ret
->source
!= SELF
)
135 /* zero ip is either samba's ip or a way of finding a
136 name without needing to know the ip address */
137 if (zero_ip(ip
) || ip_equal(ip
, ret
->ip
))
147 /****************************************************************************
148 find a name in the domain database namelist
149 search can be any of:
150 FIND_SELF - look exclusively for names the samba server has added for itself
151 FIND_LOCAL - look for names in the local subnet record.
152 FIND_WINS - look for names in the WINS record
153 **************************************************************************/
154 struct name_record
*find_name_search(struct subnet_record
**d
,
155 struct nmb_name
*name
,
156 int search
, struct in_addr ip
)
158 if (d
== NULL
) return NULL
; /* bad error! */
160 if ((search
& FIND_LOCAL
) == FIND_LOCAL
)
164 return find_name((*d
)->namelist
, name
, search
, ip
);
168 DEBUG(4,("local find_name_search with a NULL subnet pointer\n"));
173 if ((search
& FIND_WINS
) != FIND_WINS
) return NULL
;
177 /* find WINS subnet record */
178 *d
= find_subnet(ipgrp
);
181 if (*d
== NULL
) return NULL
;
183 return find_name((*d
)->namelist
, name
, search
, ip
);
187 /****************************************************************************
188 dump a copy of the name table
189 **************************************************************************/
190 void dump_names(void)
192 struct name_record
*n
;
193 struct subnet_record
*d
;
194 fstring fname
, fnamenew
;
195 time_t t
= time(NULL
);
199 strcpy(fname
,lp_lockdir());
200 trim_string(fname
,NULL
,"/");
202 strcat(fname
,WINS_LIST
);
203 strcpy(fnamenew
,fname
);
204 strcat(fnamenew
,".");
206 f
= fopen(fnamenew
,"w");
210 DEBUG(4,("Can't open %s - %s\n",fnamenew
,strerror(errno
)));
213 DEBUG(3,("Dump of local name table:\n"));
215 for (d
= subnetlist
; d
; d
= d
->next
)
216 for (n
= d
->namelist
; n
; n
= n
->next
)
218 if (f
&& ip_equal(d
->bcast_ip
, ipgrp
) && n
->source
== REGISTER
)
222 /* XXXX i have little imagination as to how to output nb_flags as
223 anything other than as a hexadecimal number :-) */
225 sprintf(data
, "%s#%02x %s %2x %ld",
226 n
->name
.name
,n
->name
.name_type
, /* XXXX ignore the scope for now */
230 fprintf(f
, "%s\n", data
);
233 DEBUG(3,("%15s ", inet_ntoa(d
->bcast_ip
)));
234 DEBUG(3,("%15s ", inet_ntoa(d
->mask_ip
)));
235 DEBUG(3,("%-19s %15s NB=%2x TTL=%ld \n",
239 n
->death_time
?n
->death_time
-t
:0));
244 chmod(fnamenew
,0644);
245 rename(fnamenew
,fname
);
247 DEBUG(3,("Wrote wins database %s\n",fname
));
251 /****************************************************************************
252 load a netbios name database file
253 ****************************************************************************/
254 void load_netbios_names(void)
256 struct subnet_record
*d
= find_subnet(ipgrp
);
264 strcpy(fname
,lp_lockdir());
265 trim_string(fname
,NULL
,"/");
267 strcat(fname
,WINS_LIST
);
269 f
= fopen(fname
,"r");
272 DEBUG(2,("Can't open wins database file %s\n",fname
));
278 pstring name_str
, ip_str
, ttd_str
, nb_flags_str
;
284 struct in_addr ipaddr
;
286 enum name_source source
;
293 if (!fgets_slash(line
,sizeof(pstring
),f
)) continue;
295 if (*line
== '#') continue;
299 if (next_token(&ptr
,name_str
,NULL
)) ++count
;
300 if (next_token(&ptr
,ip_str
,NULL
)) ++count
;
301 if (next_token(&ptr
,ttd_str
,NULL
)) ++count
;
302 if (next_token(&ptr
,nb_flags_str
,NULL
)) ++count
;
304 if (count
<= 0) continue;
307 DEBUG(0,("Ill formed wins line"));
308 DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line
));
312 /* netbios name. # divides the name from the type (hex): netbios#xx */
313 strcpy(name
,name_str
);
315 p
= strchr(name
,'#');
319 sscanf(p
+1,"%x",&type
);
322 /* decode the netbios flags (hex) and the time-to-die (seconds) */
323 sscanf(nb_flags_str
,"%x",&nb_flags
);
324 sscanf(ttd_str
,"%ld",&ttd
);
326 ipaddr
= *interpret_addr2(ip_str
);
328 if (ip_equal(ipaddr
,ipzero
)) {
336 DEBUG(4, ("add WINS line: %s#%02x %s %ld %2x\n",
337 name
,type
, inet_ntoa(ipaddr
), ttd
, nb_flags
));
339 /* add all entries that have 60 seconds or more to live */
340 if (ttd
- 60 < time(NULL
) || ttd
== 0)
342 time_t t
= (ttd
?ttd
-time(NULL
):0) / 3;
344 /* add netbios entry read from the wins.dat file. IF it's ok */
345 add_netbios_entry(d
,name
,type
,nb_flags
,t
,source
,ipaddr
,True
,True
);
353 /****************************************************************************
354 remove an entry from the name list
355 ****************************************************************************/
356 void remove_netbios_name(struct subnet_record
*d
,
357 char *name
,int type
, enum name_source source
,
361 struct name_record
*n
;
363 make_nmb_name(&nn
, name
, type
, scope
);
364 n
= find_name_search(&d
, &nn
, FIND_LOCAL
, ip
);
366 if (n
&& n
->source
== source
) remove_name(d
,n
);
370 /****************************************************************************
371 add an entry to the name list.
373 this is a multi-purpose function.
375 it adds samba's own names in to its records on each interface, keeping a
376 record of whether it is a master browser, domain master, or WINS server.
378 it also keeps a record of WINS entries.
380 ****************************************************************************/
381 struct name_record
*add_netbios_entry(struct subnet_record
*d
,
382 char *name
, int type
, int nb_flags
,
383 int ttl
, enum name_source source
, struct in_addr ip
,
384 BOOL new_only
,BOOL wins
)
386 struct name_record
*n
;
387 struct name_record
*n2
=NULL
;
389 BOOL self
= source
== SELF
;
391 /* add the name to the WINS list if the name comes from a directed query */
392 search
|= wins
? FIND_WINS
: FIND_LOCAL
;
393 /* search for SELF names only */
394 search
|= self
? FIND_SELF
: 0;
398 if (!wins
&& type
!= 0x1b)
400 /* the only broadcast (non-WINS) names we are adding are ours
401 (SELF) and PDC type names */
406 n
= (struct name_record
*)malloc(sizeof(*n
));
407 if (!n
) return(NULL
);
409 bzero((char *)n
,sizeof(*n
));
411 make_nmb_name(&n
->name
,name
,type
,scope
);
413 if ((n2
= find_name_search(&d
, &n
->name
, search
, new_only
?ipzero
:ip
)))
416 if (new_only
|| (n2
->source
==SELF
&& source
!=SELF
)) return n2
;
421 n
->death_time
= time(NULL
)+ttl
*3;
422 n
->refresh_time
= time(NULL
)+GET_TTL(ttl
);
425 n
->nb_flags
= nb_flags
;
428 if (!n2
) add_name(d
,n
);
430 DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
431 namestr(&n
->name
),inet_ntoa(ip
),ttl
,nb_flags
));
437 /*******************************************************************
438 expires old names in the namelist
439 ******************************************************************/
440 void expire_names(time_t t
)
442 struct name_record
*n
;
443 struct name_record
*next
;
444 struct subnet_record
*d
;
446 /* expire old names */
447 for (d
= subnetlist
; d
; d
= d
->next
)
449 for (n
= d
->namelist
; n
; n
= next
)
451 if (n
->death_time
&& n
->death_time
< t
)
453 DEBUG(3,("Removing dead name %s\n", namestr(&n
->name
)));
457 if (n
->prev
) n
->prev
->next
= n
->next
;
458 if (n
->next
) n
->next
->prev
= n
->prev
;
460 if (d
->namelist
== n
) d
->namelist
= n
->next
;
473 /***************************************************************************
474 reply to a name query
475 ****************************************************************************/
476 struct name_record
*search_for_name(struct subnet_record
**d
,
477 struct nmb_name
*question
,
478 struct in_addr ip
, int Time
, int search
)
480 int name_type
= question
->name_type
;
481 char *qname
= question
->name
;
482 BOOL dns_type
= name_type
== 0x20 || name_type
== 0;
484 struct name_record
*n
;
486 DEBUG(3,("Search for %s from %s - ", namestr(question
), inet_ntoa(ip
)));
488 /* first look up name in cache */
489 n
= find_name_search(d
,question
,search
,ip
);
491 if (*d
== NULL
) return NULL
;
493 DEBUG(4,("subnet %s ", inet_ntoa((*d
)->bcast_ip
)));
495 /* now try DNS lookup. */
498 struct in_addr dns_ip
;
501 /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
502 if (!dns_type
&& name_type
!= 0x1b)
504 DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
508 /* look it up with DNS */
509 a
= interpret_addr(qname
);
511 putip((char *)&dns_ip
,(char *)&a
);
515 /* no luck with DNS. We could possibly recurse here XXXX */
516 DEBUG(3,("no recursion.\n"));
517 /* add the fail to our WINS cache of names. give it 1 hour in the cache */
518 add_netbios_entry(*d
,qname
,name_type
,NB_ACTIVE
,60*60,DNSFAIL
,dns_ip
,
523 /* add it to our WINS cache of names. give it 2 hours in the cache */
524 n
= add_netbios_entry(*d
,qname
,name_type
,NB_ACTIVE
,2*60*60,DNS
,dns_ip
,
527 /* failed to add it? yikes! */
531 /* is our entry already dead? */
534 if (n
->death_time
< Time
) return False
;
537 /* it may have been an earlier failure */
538 if (n
->source
== DNSFAIL
)
540 DEBUG(3,("DNSFAIL\n"));
544 DEBUG(3,("OK %s\n",inet_ntoa(n
->ip
)));