sorted out various timer delay bugs: nameannounce.c nameserv.c
[Samba.git] / source / namedbname.c
blob82b19077f9d1d1eb66f20bc2d3f9a2d03359a61f
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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
23 Revision History:
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
32 #include "includes.h"
34 extern int DEBUGLEVEL;
36 extern pstring scope;
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;
78 if (!d) return;
80 if (!d->namelist)
82 d->namelist = n;
83 n->prev = NULL;
84 n->next = NULL;
85 return;
88 for (n2 = d->namelist; n2->next; n2 = n2->next) ;
90 n2->next = n;
91 n->next = NULL;
92 n->prev = n2;
96 /****************************************************************************
97 remove a name from the namelist. The pointer must be an element just
98 retrieved
99 **************************************************************************/
100 void remove_name(struct subnet_record *d, struct name_record *n)
102 struct name_record *nlist;
103 if (!d) return;
105 nlist = d->namelist;
107 while (nlist && nlist != n) nlist = nlist->next;
109 if (nlist)
111 if (nlist->next) nlist->next->prev = nlist->prev;
112 if (nlist->prev) nlist->prev->next = nlist->next;
113 free(nlist);
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)
133 continue;
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))
139 return ret;
143 return NULL;
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)
162 if (*d != NULL)
164 return find_name((*d)->namelist, name, search, ip);
166 else
168 DEBUG(4,("local find_name_search with a NULL subnet pointer\n"));
169 return NULL;
173 if ((search & FIND_WINS) != FIND_WINS) return NULL;
175 if (*d == 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);
197 FILE *f;
199 strcpy(fname,lp_lockdir());
200 trim_string(fname,NULL,"/");
201 strcat(fname,"/");
202 strcat(fname,WINS_LIST);
203 strcpy(fnamenew,fname);
204 strcat(fnamenew,".");
206 f = fopen(fnamenew,"w");
208 if (!f)
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)
220 fstring data;
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 */
227 inet_ntoa(n->ip),
228 n->nb_flags,
229 n->death_time);
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",
236 namestr(&n->name),
237 inet_ntoa(n->ip),
238 n->nb_flags,
239 n->death_time?n->death_time-t:0));
242 fclose(f);
243 unlink(fname);
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);
257 fstring fname;
259 FILE *f;
260 pstring line;
262 if (!d) return;
264 strcpy(fname,lp_lockdir());
265 trim_string(fname,NULL,"/");
266 strcat(fname,"/");
267 strcat(fname,WINS_LIST);
269 f = fopen(fname,"r");
271 if (!f) {
272 DEBUG(2,("Can't open wins database file %s\n",fname));
273 return;
276 while (!feof(f))
278 pstring name_str, ip_str, ttd_str, nb_flags_str;
280 pstring name;
281 int type = 0;
282 int nb_flags;
283 time_t ttd;
284 struct in_addr ipaddr;
286 enum name_source source;
288 char *ptr;
289 int count = 0;
291 char *p;
293 if (!fgets_slash(line,sizeof(pstring),f)) continue;
295 if (*line == '#') continue;
297 ptr = line;
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;
306 if (count != 4) {
307 DEBUG(0,("Ill formed wins line"));
308 DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line));
309 continue;
312 /* netbios name. # divides the name from the type (hex): netbios#xx */
313 strcpy(name,name_str);
315 p = strchr(name,'#');
317 if (p) {
318 *p = 0;
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)) {
329 source = SELF;
331 else
333 source = REGISTER;
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);
349 fclose(f);
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,
358 struct in_addr ip)
360 struct nmb_name nn;
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;
388 int search = 0;
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;
396 if (!self)
398 if (!wins && type != 0x1b)
400 /* the only broadcast (non-WINS) names we are adding are ours
401 (SELF) and PDC type names */
402 return NULL;
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)))
415 free(n);
416 if (new_only || (n2->source==SELF && source!=SELF)) return n2;
417 n = n2;
420 if (ttl)
421 n->death_time = time(NULL)+ttl*3;
422 n->refresh_time = time(NULL)+GET_TTL(ttl);
424 n->ip = ip;
425 n->nb_flags = nb_flags;
426 n->source = source;
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));
433 return(n);
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)));
455 next = n->next;
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;
462 free(n);
464 else
466 next = 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. */
496 if (!n)
498 struct in_addr dns_ip;
499 unsigned long a;
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"));
505 return NULL;
508 /* look it up with DNS */
509 a = interpret_addr(qname);
511 putip((char *)&dns_ip,(char *)&a);
513 if (!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,
519 True, True);
520 return NULL;
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,
525 True,True);
527 /* failed to add it? yikes! */
528 if (!n) return NULL;
531 /* is our entry already dead? */
532 if (n->death_time)
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"));
541 return NULL;
544 DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));
546 return n;