2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1997
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
;
39 extern BOOL updatedlists
;
41 extern struct subnet_record
*subnetlist
;
43 #define WINS_LIST "wins.dat"
45 uint16 nb_type
= 0; /* samba's NetBIOS name type */
48 /****************************************************************************
49 samba's NetBIOS name type
51 XXXX maybe functionality could be set: B, M, P or H name registration
52 and resolution could be set through nb_type. just a thought.
53 ****************************************************************************/
54 void set_samba_nb_type(void)
56 if (lp_wins_support() || (*lp_wins_server()))
58 nb_type
= NB_MFLAG
; /* samba is a 'hybrid' node type */
62 nb_type
= NB_BFLAG
; /* samba is broadcast-only node type */
67 /****************************************************************************
68 true if two netbios names are equal
69 ****************************************************************************/
70 BOOL
name_equal(struct nmb_name
*n1
,struct nmb_name
*n2
)
72 return n1
->name_type
== n2
->name_type
&&
73 strequal(n1
->name
,n2
->name
) &&
74 strequal(n1
->scope
,n2
->scope
);
78 /****************************************************************************
79 true if the netbios name is ^1^2__MSBROWSE__^2^1
81 note: this name is registered if as a master browser or backup browser
82 you are responsible for a workgroup (when you announce a domain by
83 broadcasting on your local subnet, you announce it as coming from this
84 name: see announce_host()).
86 **************************************************************************/
87 BOOL
ms_browser_name(char *name
, int type
)
89 return strequal(name
,MSBROWSE
) && type
== 0x01;
93 /****************************************************************************
94 add a netbios name into the namelist
95 **************************************************************************/
96 static void add_name(struct subnet_record
*d
, struct name_record
*n
)
98 struct name_record
*n2
;
110 for (n2
= d
->namelist
; n2
->next
; n2
= n2
->next
) ;
116 if((d
== wins_client_subnet
) && lp_wins_support())
121 /****************************************************************************
122 remove a name from the namelist. The pointer must be an element just
124 **************************************************************************/
125 void remove_name(struct subnet_record
*d
, struct name_record
*n
)
127 struct name_record
*nlist
;
132 while (nlist
&& nlist
!= n
) nlist
= nlist
->next
;
136 if (nlist
->next
) nlist
->next
->prev
= nlist
->prev
;
137 if (nlist
->prev
) nlist
->prev
->next
= nlist
->next
;
139 if(nlist
== d
->namelist
)
140 d
->namelist
= nlist
->next
;
142 if(nlist
->ip_flgs
!= NULL
)
143 free(nlist
->ip_flgs
);
147 if((d
== wins_client_subnet
) && lp_wins_support())
152 /****************************************************************************
153 find a name in a subnet.
154 **************************************************************************/
155 struct name_record
*find_name_on_subnet(struct subnet_record
*d
,
156 struct nmb_name
*name
, BOOL self_only
)
158 struct name_record
*n
= d
->namelist
;
159 struct name_record
*ret
;
161 for (ret
= n
; ret
; ret
= ret
->next
)
163 if (name_equal(&ret
->name
,name
))
165 /* self search: self names only */
166 if (self_only
&& (ret
->source
!= SELF
))
170 DEBUG(9,("find_name_on_subnet: on subnet %s - found name %s(%02x) source=%d\n",
171 inet_ntoa(d
->bcast_ip
), name
->name
, name
->name_type
, ret
->source
));
175 DEBUG(9,("find_name_on_subnet: on subnet %s - name %s(%02x) NOT FOUND\n",
176 inet_ntoa(d
->bcast_ip
), name
->name
, name
->name_type
));
180 /****************************************************************************
181 dump a copy of the name table
182 **************************************************************************/
183 void dump_names(void)
185 struct name_record
*n
;
186 fstring fname
, fnamenew
;
187 time_t t
= time(NULL
);
191 if(lp_wins_support() == False
|| wins_client_subnet
== NULL
)
194 fstrcpy(fname
,lp_lockdir());
195 trim_string(fname
,NULL
,"/");
197 strcat(fname
,WINS_LIST
);
198 fstrcpy(fnamenew
,fname
);
199 strcat(fnamenew
,".");
201 f
= fopen(fnamenew
,"w");
205 DEBUG(3,("Can't open %s - %s\n",fnamenew
,strerror(errno
)));
209 DEBUG(4,("Dump of WINS name table:\n"));
211 for (n
= wins_client_subnet
->namelist
; n
; n
= n
->next
)
215 DEBUG(4,("%15s ", inet_ntoa(wins_client_subnet
->bcast_ip
)));
216 DEBUG(4,("%15s ", inet_ntoa(wins_client_subnet
->mask_ip
)));
217 DEBUG(4,("%-19s TTL=%ld ",
219 n
->death_time
?n
->death_time
-t
:0));
221 for (i
= 0; i
< n
->num_ips
; i
++)
223 DEBUG(4,("%15s NB=%2x source=%d",
224 inet_ntoa(n
->ip_flgs
[i
].ip
),
225 n
->ip_flgs
[i
].nb_flags
,n
->source
));
230 if (f
&& ((n
->source
== REGISTER
) || (n
->source
== SELF
)))
232 /* XXXX i have little imagination as to how to output nb_flags as
233 anything other than as a hexadecimal number :-) */
235 fprintf(f
, "%s#%02x %ld ",
236 n
->name
.name
,n
->name
.name_type
, /* XXXX ignore scope for now */
239 for (i
= 0; i
< n
->num_ips
; i
++)
241 fprintf(f
, "%s %2x%c ",
242 inet_ntoa(n
->ip_flgs
[i
].ip
),
243 n
->ip_flgs
[i
].nb_flags
, (n
->source
== REGISTER
? 'R' : 'S'));
252 chmod(fnamenew
,0644);
253 rename(fnamenew
,fname
);
255 DEBUG(3,("Wrote wins database %s\n",fname
));
259 /****************************************************************************
260 load a netbios name database file
262 XXXX we cannot cope with loading Internet Group names, yet
263 ****************************************************************************/
264 void load_netbios_names(void)
266 struct subnet_record
*d
= wins_client_subnet
;
274 fstrcpy(fname
,lp_lockdir());
275 trim_string(fname
,NULL
,"/");
277 strcat(fname
,WINS_LIST
);
279 f
= fopen(fname
,"r");
282 DEBUG(2,("Can't open wins database file %s\n",fname
));
288 pstring name_str
, ip_str
, ttd_str
, nb_flags_str
;
292 unsigned int nb_flags
;
294 struct in_addr ipaddr
;
296 enum name_source source
;
303 if (!fgets_slash(line
,sizeof(pstring
),f
)) continue;
305 if (*line
== '#') continue;
309 if (next_token(&ptr
,name_str
,NULL
)) ++count
;
310 if (next_token(&ptr
,ttd_str
,NULL
)) ++count
;
311 if (next_token(&ptr
,ip_str
,NULL
)) ++count
;
312 if (next_token(&ptr
,nb_flags_str
,NULL
)) ++count
;
314 if (count
<= 0) continue;
317 DEBUG(0,("Ill formed wins line"));
318 DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line
));
322 /* Deal with SELF or REGISTER name encoding. Default is REGISTER
323 for compatibility with old nmbds. */
324 if(nb_flags_str
[strlen(nb_flags_str
)-1] == 'S')
326 DEBUG(5,("Ignoring SELF name %s\n", line
));
330 if(nb_flags_str
[strlen(nb_flags_str
)-1] == 'R')
331 nb_flags_str
[strlen(nb_flags_str
)-1] = '\0';
333 /* netbios name. # divides the name from the type (hex): netbios#xx */
334 pstrcpy(name
,name_str
);
336 p
= strchr(name
,'#');
340 sscanf(p
+1,"%x",&type
);
343 /* decode the netbios flags (hex) and the time-to-die (seconds) */
344 sscanf(nb_flags_str
,"%x",&nb_flags
);
345 sscanf(ttd_str
,"%ld",&ttd
);
347 ipaddr
= *interpret_addr2(ip_str
);
349 if (ip_equal(ipaddr
,ipzero
)) {
357 DEBUG(4, ("add WINS line: %s#%02x %ld %s %2x\n",
358 name
,type
, ttd
, inet_ntoa(ipaddr
), nb_flags
));
360 /* add all entries that have 60 seconds or more to live */
361 if (ttd
- 60 > time(NULL
) || ttd
== 0)
363 time_t t
= (ttd
?ttd
-time(NULL
):0) / 3;
365 /* add netbios entry read from the wins.dat file. IF it's ok */
366 add_netbios_entry(d
,name
,type
,nb_flags
,t
,source
,ipaddr
,True
);
374 /****************************************************************************
375 remove an entry from the name list
376 ****************************************************************************/
377 void remove_netbios_name(struct subnet_record
*d
,
378 char *name
,int type
, enum name_source source
)
381 struct name_record
*n
;
383 make_nmb_name(&nn
, name
, type
, scope
);
384 n
= find_name_on_subnet(d
, &nn
, FIND_ANY_NAME
);
386 if (n
&& n
->source
== source
) remove_name(d
,n
);
390 /****************************************************************************
391 add an entry to the name list.
393 this is a multi-purpose function.
395 it adds samba's own names in to its records on each interface, keeping a
396 record of whether it is a master browser, domain master, or WINS server.
398 it also keeps a record of WINS entries.
400 ****************************************************************************/
401 struct name_record
*add_netbios_entry(struct subnet_record
*d
,
402 char *name
, int type
, int nb_flags
, int ttl
,
403 enum name_source source
, struct in_addr ip
, BOOL new_only
)
405 struct name_record
*n
;
406 struct name_record
*n2
=NULL
;
407 BOOL self
= (source
== SELF
) ? FIND_SELF_NAME
: FIND_ANY_NAME
;
408 /* It's a WINS add if we're adding to the wins_client_subnet. */
409 BOOL wins
= ( wins_client_subnet
&& (d
== wins_client_subnet
));
413 DEBUG(0,("add_netbios_entry: called with NULL subnet record. This is a bug - \
414 please report this.!\n"));
420 if (!wins
&& (type
!= 0x1b))
422 /* the only broadcast (non-WINS) names we are adding are ours
423 (SELF) and Domain Master type names */
426 if(wins
&& (type
== 0x1d))
428 /* Do not allow any 0x1d names to be registered in a WINS,
429 database although we return success for them.
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 bzero((char *)n
->ip_flgs
, sizeof(*n
->ip_flgs
) * n
->num_ips
);
450 make_nmb_name(&n
->name
,name
,type
,scope
);
452 if ((n2
= find_name_on_subnet(d
, &n
->name
, self
)))
456 if (new_only
|| (n2
->source
==SELF
&& source
!=SELF
)) return n2
;
461 n
->death_time
= time(NULL
)+ttl
*3;
462 n
->refresh_time
= time(NULL
)+GET_TTL(ttl
);
464 /* XXXX only one entry expected with this function */
465 n
->ip_flgs
[0].ip
= ip
;
466 n
->ip_flgs
[0].nb_flags
= nb_flags
;
470 if (!n2
) add_name(d
,n
);
472 DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x to interface %s\n",
473 namestr(&n
->name
),inet_ntoa(ip
),ttl
,nb_flags
,
474 wins
? "WINS" : (char *)inet_ntoa(d
->bcast_ip
)));
480 /*******************************************************************
481 expires old names in the namelist
482 ******************************************************************/
483 void expire_names(time_t t
)
485 struct name_record
*n
;
486 struct name_record
*next
;
487 struct subnet_record
*d
;
489 /* expire old names */
490 for (d
= FIRST_SUBNET
; d
; d
= NEXT_SUBNET_INCLUDING_WINS(d
))
492 for (n
= d
->namelist
; n
; n
= next
)
495 if (n
->death_time
&& n
->death_time
< t
)
497 if (n
->source
== SELF
)
499 DEBUG(3,("not expiring SELF name %s\n", namestr(&n
->name
)));
500 n
->death_time
+= 300;
503 DEBUG(3,("Removing dead name %s\n", namestr(&n
->name
)));
505 if (n
->prev
) n
->prev
->next
= n
->next
;
506 if (n
->next
) n
->next
->prev
= n
->prev
;
508 if (d
->namelist
== n
) d
->namelist
= n
->next
;
510 if(n
->ip_flgs
!= NULL
)