- updated load_netbios_names() to cope with new wins.dat format
[Samba.git] / source / namedbname.c
blobb8edfa255413c5c95851715ecee0dcbc9a978246
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"
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 */
59 else
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;
99 if (!d) return;
101 if (!d->namelist)
103 d->namelist = n;
104 n->prev = NULL;
105 n->next = NULL;
106 return;
109 for (n2 = d->namelist; n2->next; n2 = n2->next) ;
111 n2->next = n;
112 n->next = NULL;
113 n->prev = n2;
117 /****************************************************************************
118 remove a name from the namelist. The pointer must be an element just
119 retrieved
120 **************************************************************************/
121 void remove_name(struct subnet_record *d, struct name_record *n)
123 struct name_record *nlist;
124 if (!d) return;
126 nlist = d->namelist;
128 while (nlist && nlist != n) nlist = nlist->next;
130 if (nlist)
132 if (nlist->next) nlist->next->prev = nlist->prev;
133 if (nlist->prev) nlist->prev->next = nlist->next;
134 free(nlist);
139 /****************************************************************************
140 find a name in a namelist.
141 **************************************************************************/
142 struct name_record *find_name(struct name_record *n,
143 struct nmb_name *name,
144 int search)
146 struct name_record *ret;
148 for (ret = n; ret; ret = ret->next)
150 if (name_equal(&ret->name,name))
152 /* self search: self names only */
153 if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
154 continue;
156 return ret;
159 return NULL;
163 /****************************************************************************
164 find a name in the domain database namelist
165 search can be any of:
166 FIND_SELF - look exclusively for names the samba server has added for itself
167 FIND_LOCAL - look for names in the local subnet record.
168 FIND_WINS - look for names in the WINS record
169 **************************************************************************/
170 struct name_record *find_name_search(struct subnet_record **d,
171 struct nmb_name *name,
172 int search, struct in_addr ip)
174 if (d == NULL) return NULL; /* bad error! */
176 if ((search & FIND_LOCAL) == FIND_LOCAL)
178 if (*d != NULL)
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));
183 if (n) return n;
187 if ((search & FIND_WINS) != FIND_WINS) return NULL;
189 /* find WINS subnet record. */
190 *d = find_subnet(ipgrp);
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);
210 FILE *f;
212 strcpy(fname,lp_lockdir());
213 trim_string(fname,NULL,"/");
214 strcat(fname,"/");
215 strcat(fname,WINS_LIST);
216 strcpy(fnamenew,fname);
217 strcat(fnamenew,".");
219 f = fopen(fnamenew,"w");
221 if (!f)
223 DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
226 DEBUG(3,("Dump of local name table:\n"));
228 for (d = subnetlist; d; d = d->next)
229 for (n = d->namelist; n; n = n->next)
231 int i;
233 DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
234 DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
235 DEBUG(3,("%-19s TTL=%ld ",
236 namestr(&n->name),
237 n->death_time?n->death_time-t:0));
239 for (i = 0; i < n->num_ips; i++)
241 DEBUG(3,("%15s NB=%2x ",
242 inet_ntoa(n->ip_flgs[i].ip),
243 n->ip_flgs[i].nb_flags));
246 DEBUG(3,("\n"));
248 if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
250 fstring data;
252 /* XXXX i have little imagination as to how to output nb_flags as
253 anything other than as a hexadecimal number :-) */
255 sprintf(data, "%s#%02x %ld",
256 n->name.name,n->name.name_type, /* XXXX ignore scope for now */
257 n->death_time);
258 fprintf(f, "%s", data);
259 for (i = 0; i < n->num_ips; i++)
261 DEBUG(3,("%15s NB=%2x ",
262 inet_ntoa(n->ip_flgs[i].ip),
263 n->ip_flgs[i].nb_flags));
265 sprintf(data, "%s %2x ",
266 inet_ntoa(n->ip_flgs[i].ip),
267 n->ip_flgs[i].nb_flags);
269 fprintf(f, "%s", data);
271 DEBUG(3,("\n"));
272 fprintf(f, "\n");
277 fclose(f);
278 unlink(fname);
279 chmod(fnamenew,0644);
280 rename(fnamenew,fname);
282 DEBUG(3,("Wrote wins database %s\n",fname));
286 /****************************************************************************
287 load a netbios name database file
289 XXXX we cannot cope with loading Internet Group names, yet
290 ****************************************************************************/
291 void load_netbios_names(void)
293 struct subnet_record *d = find_subnet(ipgrp);
294 fstring fname;
296 FILE *f;
297 pstring line;
299 if (!d) return;
301 strcpy(fname,lp_lockdir());
302 trim_string(fname,NULL,"/");
303 strcat(fname,"/");
304 strcat(fname,WINS_LIST);
306 f = fopen(fname,"r");
308 if (!f) {
309 DEBUG(2,("Can't open wins database file %s\n",fname));
310 return;
313 while (!feof(f))
315 pstring name_str, ip_str, ttd_str, nb_flags_str;
317 pstring name;
318 int type = 0;
319 int nb_flags;
320 time_t ttd;
321 struct in_addr ipaddr;
323 enum name_source source;
325 char *ptr;
326 int count = 0;
328 char *p;
330 if (!fgets_slash(line,sizeof(pstring),f)) continue;
332 if (*line == '#') continue;
334 ptr = line;
336 if (next_token(&ptr,name_str ,NULL)) ++count;
337 if (next_token(&ptr,ttd_str ,NULL)) ++count;
338 if (next_token(&ptr,ip_str ,NULL)) ++count;
339 if (next_token(&ptr,nb_flags_str,NULL)) ++count;
341 if (count <= 0) continue;
343 if (count != 4) {
344 DEBUG(0,("Ill formed wins line"));
345 DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line));
346 continue;
349 /* netbios name. # divides the name from the type (hex): netbios#xx */
350 strcpy(name,name_str);
352 p = strchr(name,'#');
354 if (p) {
355 *p = 0;
356 sscanf(p+1,"%x",&type);
359 /* decode the netbios flags (hex) and the time-to-die (seconds) */
360 sscanf(nb_flags_str,"%x",&nb_flags);
361 sscanf(ttd_str,"%ld",&ttd);
363 ipaddr = *interpret_addr2(ip_str);
365 if (ip_equal(ipaddr,ipzero)) {
366 source = SELF;
368 else
370 source = REGISTER;
373 DEBUG(4, ("add WINS line: %s#%02x %s %ld %2x\n",
374 name,type, inet_ntoa(ipaddr), ttd, nb_flags));
376 /* add all entries that have 60 seconds or more to live */
377 if (ttd - 60 < time(NULL) || ttd == 0)
379 time_t t = (ttd?ttd-time(NULL):0) / 3;
381 /* add netbios entry read from the wins.dat file. IF it's ok */
382 add_netbios_entry(d,name,type,nb_flags,t,source,ipaddr,True,True);
386 fclose(f);
390 /****************************************************************************
391 remove an entry from the name list
392 ****************************************************************************/
393 void remove_netbios_name(struct subnet_record *d,
394 char *name,int type, enum name_source source,
395 struct in_addr ip)
397 struct nmb_name nn;
398 struct name_record *n;
400 make_nmb_name(&nn, name, type, scope);
401 n = find_name_search(&d, &nn, FIND_LOCAL, ip);
403 if (n && n->source == source) remove_name(d,n);
407 /****************************************************************************
408 add an entry to the name list.
410 this is a multi-purpose function.
412 it adds samba's own names in to its records on each interface, keeping a
413 record of whether it is a master browser, domain master, or WINS server.
415 it also keeps a record of WINS entries.
417 ****************************************************************************/
418 struct name_record *add_netbios_entry(struct subnet_record *d,
419 char *name, int type, int nb_flags,
420 int ttl, enum name_source source, struct in_addr ip,
421 BOOL new_only,BOOL wins)
423 struct name_record *n;
424 struct name_record *n2=NULL;
425 int search = 0;
426 BOOL self = source == SELF;
428 /* add the name to the WINS list if the name comes from a directed query */
429 search |= wins ? FIND_WINS : FIND_LOCAL;
430 /* search for SELF names only */
431 search |= self ? FIND_SELF : 0;
433 if (!self)
435 if (!wins && type != 0x1b)
437 /* the only broadcast (non-WINS) names we are adding are ours
438 (SELF) and Domain Master type names */
439 return NULL;
443 n = (struct name_record *)malloc(sizeof(*n));
444 if (!n) return(NULL);
446 bzero((char *)n,sizeof(*n));
448 n->num_ips = 1; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
449 n->ip_flgs = (struct nmb_ip*)malloc(sizeof(*n->ip_flgs) * n->num_ips);
450 if (!n->ip_flgs)
452 free(n);
453 return NULL;
456 make_nmb_name(&n->name,name,type,scope);
458 if ((n2 = find_name_search(&d, &n->name, search, new_only?ipzero:ip)))
460 free(n->ip_flgs);
461 free(n);
462 if (new_only || (n2->source==SELF && source!=SELF)) return n2;
463 n = n2;
466 if (ttl)
467 n->death_time = time(NULL)+ttl*3;
468 n->refresh_time = time(NULL)+GET_TTL(ttl);
470 /* XXXX only one entry expected with this function */
471 n->ip_flgs[0].ip = ip;
472 n->ip_flgs[0].nb_flags = nb_flags;
474 n->source = source;
476 if (!n2) add_name(d,n);
478 DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
479 namestr(&n->name),inet_ntoa(ip),ttl,nb_flags));
481 return(n);
485 /*******************************************************************
486 expires old names in the namelist
487 ******************************************************************/
488 void expire_names(time_t t)
490 struct name_record *n;
491 struct name_record *next;
492 struct subnet_record *d;
494 /* expire old names */
495 for (d = subnetlist; d; d = d->next)
497 for (n = d->namelist; n; n = next)
499 if (n->death_time && n->death_time < t)
501 DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
503 next = n->next;
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 free(n->ip_flgs);
511 free(n);
513 else
515 next = n->next;
522 /***************************************************************************
523 reply to a name query
524 ****************************************************************************/
525 struct name_record *search_for_name(struct subnet_record **d,
526 struct nmb_name *question,
527 struct in_addr ip, int Time, int search)
529 int name_type = question->name_type;
530 char *qname = question->name;
531 BOOL dns_type = name_type == 0x20 || name_type == 0;
533 struct name_record *n;
535 DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
537 /* first look up name in cache */
538 n = find_name_search(d,question,search,ip);
540 if (*d == NULL) return NULL;
542 DEBUG(4,("subnet %s ", inet_ntoa((*d)->bcast_ip)));
544 /* now try DNS lookup. */
545 if (!n)
547 struct in_addr dns_ip;
548 unsigned long a;
550 /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
551 if (!dns_type && name_type != 0x1b)
553 DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
554 return NULL;
557 /* look it up with DNS */
558 a = interpret_addr(qname);
560 putip((char *)&dns_ip,(char *)&a);
562 if (!a)
564 /* no luck with DNS. We could possibly recurse here XXXX */
565 DEBUG(3,("no recursion.\n"));
566 /* add the fail to our WINS cache of names. give it 1 hour in the cache */
567 add_netbios_entry(*d,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
568 True, True);
569 return NULL;
572 /* add it to our WINS cache of names. give it 2 hours in the cache */
573 n = add_netbios_entry(*d,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
574 True,True);
576 /* failed to add it? yikes! */
577 if (!n) return NULL;
580 /* is our entry already dead? */
581 if (n->death_time)
583 if (n->death_time < Time) return False;
586 /* it may have been an earlier failure */
587 if (n->source == DNSFAIL)
589 DEBUG(3,("DNSFAIL\n"));
590 return NULL;
593 DEBUG(3,("OK %s\n",inet_ntoa(n->ip_flgs[0].ip)));
595 return n;