added some debug lines to the rename code
[Samba.git] / source / namedbname.c
blob6ff20f4d45c8356dc2eb3d2379d380ee80f3c11a
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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
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 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 */
60 else
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;
100 if (!d) return;
102 if (!d->namelist)
104 d->namelist = n;
105 n->prev = NULL;
106 n->next = NULL;
107 return;
110 for (n2 = d->namelist; n2->next; n2 = n2->next) ;
112 n2->next = n;
113 n->next = NULL;
114 n->prev = n2;
116 if((d == wins_client_subnet) && lp_wins_support())
117 updatedlists = True;
121 /****************************************************************************
122 remove a name from the namelist. The pointer must be an element just
123 retrieved
124 **************************************************************************/
125 void remove_name(struct subnet_record *d, struct name_record *n)
127 struct name_record *nlist;
128 if (!d) return;
130 nlist = d->namelist;
132 while (nlist && nlist != n) nlist = nlist->next;
134 if (nlist)
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);
144 free(nlist);
147 if((d == wins_client_subnet) && lp_wins_support())
148 updatedlists = True;
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))
168 continue;
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));
172 return ret;
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));
177 return NULL;
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);
189 FILE *f;
191 if(lp_wins_support() == False || wins_client_subnet == NULL)
192 return;
194 fstrcpy(fname,lp_lockdir());
195 trim_string(fname,NULL,"/");
196 strcat(fname,"/");
197 strcat(fname,WINS_LIST);
198 fstrcpy(fnamenew,fname);
199 strcat(fnamenew,".");
201 f = fopen(fnamenew,"w");
203 if (!f)
205 DEBUG(3,("Can't open %s - %s\n",fnamenew,strerror(errno)));
206 return;
209 DEBUG(4,("Dump of WINS name table:\n"));
211 for (n = wins_client_subnet->namelist; n; n = n->next)
213 int i;
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 ",
218 namestr(&n->name),
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));
228 DEBUG(4,("\n"));
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 */
237 n->death_time);
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'));
245 fprintf(f, "\n");
250 fclose(f);
251 unlink(fname);
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;
267 fstring fname;
269 FILE *f;
270 pstring line;
272 if (!d) return;
274 fstrcpy(fname,lp_lockdir());
275 trim_string(fname,NULL,"/");
276 strcat(fname,"/");
277 strcat(fname,WINS_LIST);
279 f = fopen(fname,"r");
281 if (!f) {
282 DEBUG(2,("Can't open wins database file %s\n",fname));
283 return;
286 while (!feof(f))
288 pstring name_str, ip_str, ttd_str, nb_flags_str;
290 pstring name;
291 int type = 0;
292 unsigned int nb_flags;
293 time_t ttd;
294 struct in_addr ipaddr;
296 enum name_source source;
298 char *ptr;
299 int count = 0;
301 char *p;
303 if (!fgets_slash(line,sizeof(pstring),f)) continue;
305 if (*line == '#') continue;
307 ptr = line;
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;
316 if (count != 4) {
317 DEBUG(0,("Ill formed wins line"));
318 DEBUG(0,("[%s]: name#type abs_time ip nb_flags\n",line));
319 continue;
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));
327 continue;
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,'#');
338 if (p) {
339 *p = 0;
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)) {
350 source = SELF;
352 else
354 source = REGISTER;
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);
370 fclose(f);
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)
380 struct nmb_name nn;
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));
411 if(d == NULL)
413 DEBUG(0,("add_netbios_entry: called with NULL subnet record. This is a bug - \
414 please report this.!\n"));
415 return NULL;
418 if (!self)
420 if (!wins && (type != 0x1b))
422 /* the only broadcast (non-WINS) names we are adding are ours
423 (SELF) and Domain Master type names */
424 return NULL;
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.
431 return NULL;
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);
442 if (!n->ip_flgs)
444 free(n);
445 return NULL;
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)))
454 free(n->ip_flgs);
455 free(n);
456 if (new_only || (n2->source==SELF && source!=SELF)) return n2;
457 n = n2;
460 if (ttl)
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;
468 n->source = source;
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)));
476 return(n);
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)
494 next = 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;
501 continue;
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)
511 free(n->ip_flgs);
512 free(n);