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 wins_ip
;
40 extern struct subnet_record
*subnetlist
;
42 #define WINS_LIST "wins.dat"
44 uint16 nb_type
= 0; /* samba's NetBIOS name type */
47 /****************************************************************************
48 samba's NetBIOS name type
50 XXXX maybe functionality could be set: B, M, P or H name registration
51 and resolution could be set through nb_type. just a thought.
52 ****************************************************************************/
53 void set_samba_nb_type(void)
55 if (lp_wins_support() || (*lp_wins_server()))
57 nb_type
= NB_MFLAG
; /* samba is a 'hybrid' node type */
61 nb_type
= NB_BFLAG
; /* samba is broadcast-only node type */
66 /****************************************************************************
67 true if two netbios names are equal
68 ****************************************************************************/
69 BOOL
name_equal(struct nmb_name
*n1
,struct nmb_name
*n2
)
71 return n1
->name_type
== n2
->name_type
&&
72 strequal(n1
->name
,n2
->name
) &&
73 strequal(n1
->scope
,n2
->scope
);
77 /****************************************************************************
78 true if the netbios name is ^1^2__MSBROWSE__^2^1
80 note: this name is registered if as a master browser or backup browser
81 you are responsible for a workgroup (when you announce a domain by
82 broadcasting on your local subnet, you announce it as coming from this
83 name: see announce_host()).
85 **************************************************************************/
86 BOOL
ms_browser_name(char *name
, int type
)
88 return strequal(name
,MSBROWSE
) && type
== 0x01;
92 /****************************************************************************
93 add a netbios name into the namelist
94 **************************************************************************/
95 static void add_name(struct subnet_record
*d
, struct name_record
*n
)
97 struct name_record
*n2
;
109 for (n2
= d
->namelist
; n2
->next
; n2
= n2
->next
) ;
117 /****************************************************************************
118 remove a name from the namelist. The pointer must be an element just
120 **************************************************************************/
121 void remove_name(struct subnet_record
*d
, struct name_record
*n
)
123 struct name_record
*nlist
;
128 while (nlist
&& nlist
!= n
) nlist
= nlist
->next
;
132 if (nlist
->next
) nlist
->next
->prev
= nlist
->prev
;
133 if (nlist
->prev
) nlist
->prev
->next
= nlist
->next
;
139 /****************************************************************************
140 find a name in a namelist.
141 **************************************************************************/
142 struct name_record
*find_name(struct name_record
*n
,
143 struct nmb_name
*name
, int search
)
145 struct name_record
*ret
;
147 for (ret
= n
; ret
; ret
= ret
->next
)
149 if (name_equal(&ret
->name
,name
))
151 /* self search: self names only */
152 if ((search
&FIND_SELF
) == FIND_SELF
&& ret
->source
!= SELF
)
156 DEBUG(9,("find_name: found name %s\n", name
->name
));
160 DEBUG(9,("find_name: name %s NOT FOUND\n", name
->name
));
165 /****************************************************************************
166 find a name in the domain database namelist
167 search can be any of:
168 FIND_SELF - look exclusively for names the samba server has added for itself
169 FIND_LOCAL - look for names in the local subnet record.
170 FIND_WINS - look for names in the WINS record
171 **************************************************************************/
172 struct name_record
*find_name_search(struct subnet_record
**d
,
173 struct nmb_name
*name
,
174 int search
, struct in_addr ip
)
176 if (d
== NULL
) return NULL
; /* bad error! */
178 if (search
& FIND_LOCAL
) {
180 struct name_record
*n
= find_name((*d
)->namelist
, name
, search
);
181 DEBUG(4,("find_name on local: %s %s search %x\n",
182 namestr(name
),inet_ntoa(ip
), search
));
187 if (!(search
& FIND_WINS
)) return NULL
;
189 /* find WINS subnet record. */
190 *d
= find_subnet(wins_ip
);
192 if (*d
== NULL
) return NULL
;
194 DEBUG(4,("find_name on WINS: %s %s search %x\n",
195 namestr(name
),inet_ntoa(ip
), search
));
196 return find_name((*d
)->namelist
, name
, search
);
200 /****************************************************************************
201 dump a copy of the name table
202 **************************************************************************/
203 void dump_names(void)
205 struct name_record
*n
;
206 struct subnet_record
*d
;
207 fstring fname
, fnamenew
;
208 time_t t
= time(NULL
);
212 strcpy(fname
,lp_lockdir());
213 trim_string(fname
,NULL
,"/");
215 strcat(fname
,WINS_LIST
);
216 strcpy(fnamenew
,fname
);
217 strcat(fnamenew
,".");
219 f
= fopen(fnamenew
,"w");
223 DEBUG(3,("Can't open %s - %s\n",fnamenew
,strerror(errno
)));
227 DEBUG(4,("Dump of local name table:\n"));
229 for (d
= subnetlist
; d
; d
= d
->next
)
230 for (n
= d
->namelist
; n
; n
= n
->next
)
234 DEBUG(4,("%15s ", inet_ntoa(d
->bcast_ip
)));
235 DEBUG(4,("%15s ", inet_ntoa(d
->mask_ip
)));
236 DEBUG(4,("%-19s TTL=%ld ",
238 n
->death_time
?n
->death_time
-t
:0));
240 for (i
= 0; i
< n
->num_ips
; i
++)
242 DEBUG(4,("%15s NB=%2x source=%d",
243 inet_ntoa(n
->ip_flgs
[i
].ip
),
244 n
->ip_flgs
[i
].nb_flags
,n
->source
));
249 if (f
&& ip_equal(d
->bcast_ip
, wins_ip
) && n
->source
== REGISTER
)
251 /* XXXX i have little imagination as to how to output nb_flags as
252 anything other than as a hexadecimal number :-) */
254 fprintf(f
, "%s#%02x %ld ",
255 n
->name
.name
,n
->name
.name_type
, /* XXXX ignore scope for now */
258 for (i
= 0; i
< n
->num_ips
; i
++)
260 fprintf(f
, "%s %2x ",
261 inet_ntoa(n
->ip_flgs
[i
].ip
),
262 n
->ip_flgs
[i
].nb_flags
);
271 chmod(fnamenew
,0644);
272 rename(fnamenew
,fname
);
274 DEBUG(3,("Wrote wins database %s\n",fname
));
278 /****************************************************************************
279 load a netbios name database file
281 XXXX we cannot cope with loading Internet Group names, yet
282 ****************************************************************************/
283 void load_netbios_names(void)
285 struct subnet_record
*d
= find_subnet(wins_ip
);
293 strcpy(fname
,lp_lockdir());
294 trim_string(fname
,NULL
,"/");
296 strcat(fname
,WINS_LIST
);
298 f
= fopen(fname
,"r");
301 DEBUG(2,("Can't open wins database file %s\n",fname
));
307 pstring name_str
, ip_str
, ttd_str
, nb_flags_str
;
311 unsigned int nb_flags
;
313 struct in_addr ipaddr
;
315 enum name_source source
;
322 if (!fgets_slash(line
,sizeof(pstring
),f
)) continue;
324 if (*line
== '#') continue;
328 if (next_token(&ptr
,name_str
,NULL
)) ++count
;
329 if (next_token(&ptr
,ttd_str
,NULL
)) ++count
;
330 if (next_token(&ptr
,ip_str
,NULL
)) ++count
;
331 if (next_token(&ptr
,nb_flags_str
,NULL
)) ++count
;
333 if (count
<= 0) continue;
336 DEBUG(0,("Ill formed wins line"));
337 DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line
));
341 /* netbios name. # divides the name from the type (hex): netbios#xx */
342 strcpy(name
,name_str
);
344 p
= strchr(name
,'#');
348 sscanf(p
+1,"%x",&type
);
351 /* decode the netbios flags (hex) and the time-to-die (seconds) */
352 sscanf(nb_flags_str
,"%x",&nb_flags
);
353 sscanf(ttd_str
,"%ld",&ttd
);
355 ipaddr
= *interpret_addr2(ip_str
);
357 if (ip_equal(ipaddr
,ipzero
)) {
365 DEBUG(4, ("add WINS line: %s#%02x %ld %s %2x\n",
366 name
,type
, ttd
, inet_ntoa(ipaddr
), nb_flags
));
368 /* add all entries that have 60 seconds or more to live */
369 if (ttd
- 60 > time(NULL
) || ttd
== 0)
371 time_t t
= (ttd
?ttd
-time(NULL
):0) / 3;
373 /* add netbios entry read from the wins.dat file. IF it's ok */
374 add_netbios_entry(d
,name
,type
,nb_flags
,t
,source
,ipaddr
,True
,True
);
382 /****************************************************************************
383 remove an entry from the name list
384 ****************************************************************************/
385 void remove_netbios_name(struct subnet_record
*d
,
386 char *name
,int type
, enum name_source source
,
390 struct name_record
*n
;
392 make_nmb_name(&nn
, name
, type
, scope
);
393 n
= find_name_search(&d
, &nn
, FIND_LOCAL
, ip
);
395 if (n
&& n
->source
== source
) remove_name(d
,n
);
399 /****************************************************************************
400 add an entry to the name list.
402 this is a multi-purpose function.
404 it adds samba's own names in to its records on each interface, keeping a
405 record of whether it is a master browser, domain master, or WINS server.
407 it also keeps a record of WINS entries.
409 ****************************************************************************/
410 struct name_record
*add_netbios_entry(struct subnet_record
*d
,
411 char *name
, int type
, int nb_flags
,
412 int ttl
, enum name_source source
, struct in_addr ip
,
413 BOOL new_only
,BOOL wins
)
415 struct name_record
*n
;
416 struct name_record
*n2
=NULL
;
418 BOOL self
= source
== SELF
;
420 /* add the name to the WINS list if the name comes from a directed query */
421 search
|= wins
? FIND_WINS
: FIND_LOCAL
;
422 /* search for SELF names only */
423 search
|= self
? FIND_SELF
: 0;
427 if (!wins
&& type
!= 0x1b)
429 /* the only broadcast (non-WINS) names we are adding are ours
430 (SELF) and Domain Master type names */
435 n
= (struct name_record
*)malloc(sizeof(*n
));
436 if (!n
) return(NULL
);
438 bzero((char *)n
,sizeof(*n
));
440 n
->num_ips
= 1; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
441 n
->ip_flgs
= (struct nmb_ip
*)malloc(sizeof(*n
->ip_flgs
) * n
->num_ips
);
448 make_nmb_name(&n
->name
,name
,type
,scope
);
450 if ((n2
= find_name_search(&d
, &n
->name
, search
, new_only
?ipzero
:ip
)))
454 if (new_only
|| (n2
->source
==SELF
&& source
!=SELF
)) return n2
;
459 n
->death_time
= time(NULL
)+ttl
*3;
460 n
->refresh_time
= time(NULL
)+GET_TTL(ttl
);
462 /* XXXX only one entry expected with this function */
463 n
->ip_flgs
[0].ip
= ip
;
464 n
->ip_flgs
[0].nb_flags
= nb_flags
;
468 if (!n2
) add_name(d
,n
);
470 DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
471 namestr(&n
->name
),inet_ntoa(ip
),ttl
,nb_flags
,
472 ip_equal(d
->bcast_ip
, wins_ip
) ? "WINS" : inet_ntoa(d
->bcast_ip
)));
478 /*******************************************************************
479 expires old names in the namelist
480 ******************************************************************/
481 void expire_names(time_t t
)
483 struct name_record
*n
;
484 struct name_record
*next
;
485 struct subnet_record
*d
;
487 /* expire old names */
488 for (d
= subnetlist
; d
; d
= d
->next
)
490 for (n
= d
->namelist
; n
; n
= next
)
493 if (n
->death_time
&& n
->death_time
< t
)
495 if (n
->source
== SELF
) {
496 DEBUG(3,("not expiring SELF name %s\n", namestr(&n
->name
)));
497 n
->death_time
+= 300;
500 DEBUG(3,("Removing dead name %s\n", namestr(&n
->name
)));
502 if (n
->prev
) n
->prev
->next
= n
->next
;
503 if (n
->next
) n
->next
->prev
= n
->prev
;
505 if (d
->namelist
== n
) d
->namelist
= n
->next
;
515 /***************************************************************************
516 assume a WINS name is a dns name, and do a gethostbyname() on it.
517 ****************************************************************************/
518 struct name_record
*dns_name_search(struct nmb_name
*question
, int Time
)
520 int name_type
= question
->name_type
;
521 char *qname
= question
->name
;
523 BOOL dns_type
= (name_type
== 0x20 || name_type
== 0);
524 struct in_addr dns_ip
;
525 struct subnet_record
*d
= find_subnet(wins_ip
);
527 if (d
== NULL
) return NULL
;
529 DEBUG(3,("Search for %s - ", namestr(question
)));
531 /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
534 DEBUG(3,("types 0x20 0x0 only: name not found\n"));
538 /* look it up with DNS */
539 dns_ip
.s_addr
= interpret_addr(qname
);
543 /* no luck with DNS. We could possibly recurse here XXXX */
544 DEBUG(3,("not found. no recursion.\n"));
545 /* add the fail to WINS cache of names. give it 1 hour in the cache */
546 add_netbios_entry(d
,qname
,name_type
,NB_ACTIVE
,60*60,DNSFAIL
,dns_ip
,
551 DEBUG(3,("found with DNS: %s\n", inet_ntoa(dns_ip
)));
553 /* add it to our WINS cache of names. give it 2 hours in the cache */
554 return add_netbios_entry(d
,qname
,name_type
,NB_ACTIVE
,2*60*60,DNS
,dns_ip
,