This is a first step toward moving long namelists into a database. I
[samba.git] / source / nmbd / nmbd_namelistdb.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios routines and daemon - version 2
5    Copyright (C) Andrew Tridgell 1994-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7    Copyright (C) Jeremy Allison 1994-1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23 */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
29 extern pstring scope;
30 extern char **my_netbios_names;
31
32 uint16 samba_nb_type = 0; /* samba's NetBIOS name type */
33
34
35 /****************************************************************************
36   Set Samba's NetBIOS name type.
37   ****************************************************************************/
38
39 void set_samba_nb_type(void)
40 {
41   if( lp_wins_support() || (*lp_wins_server()) )
42     samba_nb_type = NB_MFLAG; /* samba is a 'hybrid' node type */
43   else
44     samba_nb_type = NB_BFLAG; /* samba is broadcast-only node type */
45 }
46
47 /****************************************************************************
48   Returns True if the netbios name is ^1^2__MSBROWSE__^2^1.
49
50   Note: This name is registered if as a master browser or backup browser
51   you are responsible for a workgroup (when you announce a domain by
52   broadcasting on your local subnet, you announce it as coming from this
53   name: see announce_host()).
54
55   **************************************************************************/
56
57 BOOL ms_browser_name( char *name, int type )
58 {
59   return( strequal( name, MSBROWSE ) && (type == 0x01) );
60 }
61
62 /****************************************************************************
63   Add a netbios name into a namelist.
64   **************************************************************************/
65
66 static void add_name_to_namelist(struct subnet_record *subrec, 
67                                  struct name_record *namerec)
68 {
69   struct name_record *namerec2;
70
71   if (!subrec->namelist)
72   {
73     subrec->namelist = namerec;
74     namerec->prev = NULL;
75     namerec->next = NULL;
76     return;
77   }
78
79   for( namerec2 = subrec->namelist; namerec2->next; namerec2 = namerec2->next )
80     ;
81
82   namerec2->next = namerec;
83   namerec->next = NULL;
84   namerec->prev = namerec2;
85   namerec->subnet = subrec;
86
87   subrec->namelist_changed = True;
88 }
89
90 /****************************************************************************
91   Remove a name from the namelist.
92   **************************************************************************/
93
94 void remove_name_from_namelist( struct subnet_record *subrec, 
95                                 struct name_record *namerec )
96 {
97   if (namerec->next)
98     namerec->next->prev = namerec->prev;
99   if (namerec->prev)
100     namerec->prev->next = namerec->next;
101
102   if(namerec == subrec->namelist)
103     subrec->namelist = namerec->next;
104
105   if(namerec->data.ip != NULL)
106     free((char *)namerec->data.ip);
107   free((char *)namerec);
108
109   subrec->namelist_changed = True;
110 }
111
112
113 /****************************************************************************
114   Find a name in a subnet.
115   **************************************************************************/
116
117 struct name_record *find_name_on_subnet(struct subnet_record *subrec,
118                                       struct nmb_name *nmbname, BOOL self_only)
119 {
120   struct name_record *namerec = subrec->namelist;
121   struct name_record *name_ret;
122   
123   for (name_ret = namerec; name_ret; name_ret = name_ret->next)
124   {
125     if (nmb_name_equal(&name_ret->name, nmbname))
126     {
127       /* Self names only - these include permanent names. */
128       if (self_only && (name_ret->data.source != SELF_NAME) && 
129               (name_ret->data.source != PERMANENT_NAME) )
130       {
131         continue;
132       }
133       DEBUG(9,("find_name_on_subnet: on subnet %s - found name %s source=%d\n", 
134                 subrec->subnet_name, namestr(nmbname), name_ret->data.source));
135       return name_ret;
136     }
137   }
138   DEBUG(9,("find_name_on_subnet: on subnet %s - name %s NOT FOUND\n", 
139             subrec->subnet_name, namestr(nmbname)));
140   return NULL;
141 }
142
143 /****************************************************************************
144   Find a name over all known broadcast subnets.
145 **************************************************************************/
146
147 struct name_record 
148   *find_name_for_remote_broadcast_subnet( struct nmb_name *nmbname,
149                                           BOOL             self_only )
150 {
151   struct subnet_record *subrec;
152   struct name_record *namerec = NULL;
153
154   for( subrec = FIRST_SUBNET;
155        subrec;
156        subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
157   {
158     if( NULL != (namerec = find_name_on_subnet(subrec, nmbname, self_only)) )
159       break;
160   }
161
162   return namerec;
163 }    
164   
165 /****************************************************************************
166   Update the ttl of an entry in a subnet name list.
167   ****************************************************************************/
168
169 void update_name_ttl( struct name_record *namerec, int ttl )
170 {
171   time_t time_now = time(NULL);
172
173   if(namerec->data.death_time != PERMANENT_TTL)
174     namerec->data.death_time = time_now + ttl;
175
176   namerec->data.refresh_time = time_now + (ttl/2);
177
178   namerec->subnet->namelist_changed = True;
179
180
181 /****************************************************************************
182   Add an entry to a subnet name list.
183   ****************************************************************************/
184
185 struct name_record *add_name_to_subnet(struct subnet_record *subrec,
186                 char *name, int type, uint16 nb_flags, int ttl, 
187                 enum name_source source, int num_ips, struct in_addr *iplist)
188 {
189   struct name_record *namerec;
190   time_t time_now = time(NULL);
191
192   if((namerec = (struct name_record *)malloc(sizeof(*namerec))) == NULL)
193   {
194     DEBUG(0,("add_name_to_subnet: malloc fail.\n"));
195     return NULL;
196   }
197
198   bzero((char *)namerec,sizeof(*namerec));
199
200   namerec->subnet = subrec;
201
202   namerec->data.num_ips = num_ips;
203   namerec->data.ip = (struct in_addr *)malloc( sizeof(struct in_addr) 
204                                                * namerec->data.num_ips );
205   if (!namerec->data.ip)
206   {
207      DEBUG(0,("add_name_to_subnet: malloc fail when creating ip_flgs.\n"));
208      free((char *)namerec);
209      return NULL;
210   }
211
212   bzero( (char *)namerec->data.ip,
213          sizeof(struct in_addr) * namerec->data.num_ips );
214
215   memcpy( &namerec->data.ip[0], iplist, num_ips * sizeof(struct in_addr) );
216
217   make_nmb_name( &namerec->name, name, type, scope );
218
219   /* Setup the death_time and refresh_time. */
220   if(ttl == PERMANENT_TTL)
221     namerec->data.death_time = PERMANENT_TTL;
222   else
223     namerec->data.death_time = time_now + ttl;
224
225   namerec->data.refresh_time = time_now + (ttl/2);
226
227   /* Enter the name as active. */
228   namerec->data.nb_flags = nb_flags | NB_ACTIVE;
229
230   /* If it's our primary name, flag it as so. */
231   if(strequal(my_netbios_names[0],name))
232     namerec->data.nb_flags |= NB_PERM;
233
234   namerec->data.source = source;
235   
236   add_name_to_namelist(subrec,namerec);
237
238   DEBUG( 3, ( "add_name_to_subnet: Added netbios name %s with first IP %s \
239 ttl=%d nb_flags=%2x to subnet %s\n",
240             namestr(&namerec->name),
241             inet_ntoa(*iplist),
242             ttl,
243             (unsigned int)nb_flags,
244             subrec->subnet_name) );
245
246   subrec->namelist_changed = True;
247
248   return(namerec);
249 }
250
251 /*******************************************************************
252  Utility function automatically called when a name refresh or register 
253  succeeds. By definition this is a SELF_NAME (or we wouldn't be registering
254  it).
255  ******************************************************************/
256
257 void standard_success_register(struct subnet_record *subrec, 
258                              struct userdata_struct *userdata,
259                              struct nmb_name *nmbname, uint16 nb_flags, int ttl,
260                              struct in_addr registered_ip)
261 {
262   struct name_record *namerec;
263
264   namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
265   if( NULL == namerec )
266     add_name_to_subnet( subrec, nmbname->name, nmbname->name_type,
267                         nb_flags, ttl, SELF_NAME, 1, &registered_ip );
268   else
269     update_name_ttl( namerec, ttl );
270 }
271
272 /*******************************************************************
273  Utility function automatically called when a name refresh or register 
274  fails.
275  ******************************************************************/
276
277 void standard_fail_register( struct subnet_record   *subrec,
278                              struct response_record *rrec,
279                              struct nmb_name        *nmbname )
280 {
281   struct name_record *namerec;
282
283   namerec = find_name_on_subnet( subrec, nmbname, FIND_SELF_NAME );
284
285   DEBUG( 0, ( "standard_fail_register: Failed to register/refresh name %s \
286 on subnet %s\n",
287             namestr(nmbname), subrec->subnet_name) );
288
289   /* Remove the name from the subnet. */
290   if( namerec )
291     remove_name_from_namelist(subrec, namerec);
292 }
293
294 /*******************************************************************
295  Utility function to remove an IP address from a name record.
296  ******************************************************************/
297
298 static void remove_nth_ip_in_record( struct name_record *namerec, int ind)
299 {
300   if( ind != namerec->data.num_ips )
301     memmove( (char *)(&namerec->data.ip[ind]),
302              (char *)(&namerec->data.ip[ind+1]), 
303              ( namerec->data.num_ips - ind - 1) * sizeof(struct in_addr) );
304
305   namerec->data.num_ips--;
306   namerec->subnet->namelist_changed = True;
307 }
308
309 /*******************************************************************
310  Utility function to check if an IP address exists in a name record.
311  ******************************************************************/
312
313 BOOL find_ip_in_name_record( struct name_record *namerec, struct in_addr ip )
314 {
315   int i;
316
317   for(i = 0; i < namerec->data.num_ips; i++)
318     if(ip_equal( namerec->data.ip[i], ip))
319       return True;
320
321   return False;
322 }
323
324 /*******************************************************************
325  Utility function to add an IP address to a name record.
326  ******************************************************************/
327
328 void add_ip_to_name_record(struct name_record *namerec, struct in_addr new_ip)
329 {
330   struct in_addr *new_list;
331
332   /* Don't add one we already have. */
333   if(find_ip_in_name_record( namerec, new_ip))
334     return;
335   
336   new_list = (struct in_addr *)malloc( (namerec->data.num_ips + 1)
337                                        * sizeof(struct in_addr) );
338   if( NULL == new_list )
339   {
340     DEBUG(0,("add_ip_to_name_record: Malloc fail !\n"));
341     return;
342   }
343
344   memcpy( (char *)new_list,
345           (char *)namerec->data.ip,
346           namerec->data.num_ips * sizeof(struct in_addr) );
347   new_list[namerec->data.num_ips] = new_ip;
348
349   free((char *)namerec->data.ip);
350   namerec->data.ip = new_list;
351   namerec->data.num_ips += 1;
352
353   namerec->subnet->namelist_changed = True;
354 }
355
356 /*******************************************************************
357  Utility function to remove an IP address from a name record.
358  ******************************************************************/
359
360 void remove_ip_from_name_record( struct name_record *namerec,
361                                  struct in_addr      remove_ip )
362 {
363   /* Try and find the requested ip address - remove it. */
364   int i;
365   int orig_num = namerec->data.num_ips;
366
367   for(i = 0; i < orig_num; i++)
368     if( ip_equal( remove_ip, namerec->data.ip[i]) )
369     {
370       remove_nth_ip_in_record( namerec, i);
371       break;
372     }
373 }
374
375 /*******************************************************************
376  Utility function that release_name callers can plug into as the
377  success function when a name release is successful. Used to save
378  duplication of success_function code.
379  ******************************************************************/
380
381 void standard_success_release( struct subnet_record   *subrec,
382                                struct userdata_struct *userdata,
383                                struct nmb_name        *nmbname,
384                                struct in_addr          released_ip )
385 {
386   struct name_record *namerec;
387
388   namerec = find_name_on_subnet( subrec, nmbname, FIND_ANY_NAME );
389
390   if( namerec == NULL )
391   {
392     DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
393 on subnet %s. Name was not found on subnet.\n",
394                 namestr(nmbname),
395                 inet_ntoa(released_ip),
396                 subrec->subnet_name) );
397     return;
398   }
399   else
400   {
401     int orig_num = namerec->data.num_ips;
402
403     remove_ip_from_name_record( namerec, released_ip );
404
405     if( namerec->data.num_ips == orig_num )
406       DEBUG( 0, ( "standard_success_release: Name release for name %s IP %s \
407 on subnet %s. This ip is not known for this name.\n",
408                 namestr(nmbname),
409                 inet_ntoa(released_ip),
410                 subrec->subnet_name ) );
411   }
412
413   if( namerec->data.num_ips == 0 )
414     remove_name_from_namelist( subrec, namerec );
415 }
416
417 /*******************************************************************
418   Expires old names in a subnet namelist.
419   ******************************************************************/
420
421 void expire_names_on_subnet(struct subnet_record *subrec, time_t t)
422 {
423   struct name_record *namerec;
424   struct name_record *next_namerec;
425
426   for (namerec = subrec->namelist; namerec; namerec = next_namerec)
427   {
428     next_namerec = namerec->next;
429     if( (namerec->data.death_time != PERMANENT_TTL)
430      && (namerec->data.death_time < t) )
431     {
432       if (namerec->data.source == SELF_NAME)
433       {
434         DEBUG( 3, ( "expire_names_on_subnet: Subnet %s not expiring SELF \
435 name %s\n", 
436                     subrec->subnet_name, namestr(&namerec->name) ) );
437         namerec->data.death_time += 300;
438         namerec->subnet->namelist_changed = True;
439         continue;
440       }
441       DEBUG(3,("expire_names_on_subnet: Subnet %s - removing expired name %s\n",
442                  subrec->subnet_name, namestr(&namerec->name)));
443   
444       remove_name_from_namelist(subrec, namerec);
445     }
446   }
447 }
448
449 /*******************************************************************
450   Expires old names in all subnet namelists.
451   ******************************************************************/
452
453 void expire_names(time_t t)
454 {
455   struct subnet_record *subrec;
456
457   for( subrec = FIRST_SUBNET;
458        subrec;
459        subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
460   {
461     expire_names_on_subnet( subrec, t );
462   }
463 }
464
465 /****************************************************************************
466   Add the magic samba names, useful for finding samba servers.
467   These go directly into the name list for a particular subnet,
468   without going through the normal registration process.
469   When adding them to the unicast subnet, add them as a list of
470   all broadcast subnet IP addresses.
471 **************************************************************************/
472
473 void add_samba_names_to_subnet( struct subnet_record *subrec )
474 {
475   struct in_addr *iplist = &subrec->myip;
476   int num_ips = 1;
477
478   /* These names are added permanently (ttl of zero) and will NOT be
479      refreshed.  */
480
481   if((subrec == unicast_subnet) || (subrec == wins_server_subnet) ||
482      (subrec == remote_broadcast_subnet) )
483   {
484     struct subnet_record *bcast_subrecs;
485     int i;
486     /* Create an IP list containing all our known subnets. */
487
488     num_ips = iface_count();
489     iplist = (struct in_addr *)malloc( num_ips * sizeof(struct in_addr) );
490     if( NULL == iplist )
491     {
492       DEBUG(0,("add_samba_names_to_subnet: Malloc fail !\n"));
493       return;
494     }
495
496     for( bcast_subrecs = FIRST_SUBNET, i = 0;
497          bcast_subrecs; 
498          bcast_subrecs = NEXT_SUBNET_EXCLUDING_UNICAST(bcast_subrecs), i++ )
499       iplist[i] = bcast_subrecs->myip;
500
501   }
502
503   add_name_to_subnet(subrec,"*",0x0,samba_nb_type, PERMANENT_TTL,
504                      PERMANENT_NAME, num_ips, iplist);
505   add_name_to_subnet(subrec,"*",0x20,samba_nb_type,PERMANENT_TTL,
506                      PERMANENT_NAME, num_ips, iplist);
507   add_name_to_subnet(subrec,"__SAMBA__",0x20,samba_nb_type,PERMANENT_TTL,
508                    PERMANENT_NAME, num_ips, iplist);
509   add_name_to_subnet(subrec,"__SAMBA__",0x00,samba_nb_type,PERMANENT_TTL,
510                    PERMANENT_NAME, num_ips, iplist);
511
512   if(iplist != &subrec->myip)
513     free((char *)iplist);
514 }
515
516 /****************************************************************************
517  Dump the contents of the namelists on all the subnets (including unicast)
518  into a file. Initiated by SIGHUP - used to debug the state of the namelists.
519 **************************************************************************/
520
521 static void dump_subnet_namelist( struct subnet_record *subrec, FILE *fp)
522 {
523   struct name_record *namerec;
524   char *src_type;
525   struct tm *tm;
526   int i;
527
528   fprintf(fp, "Subnet %s\n----------------------\n", subrec->subnet_name);
529   for (namerec = subrec->namelist; namerec; namerec = namerec->next)
530   {
531     fprintf(fp,"\tName = %s\t", namestr(&namerec->name));
532     switch(namerec->data.source)
533     {
534       case LMHOSTS_NAME:
535         src_type = "LMHOSTS_NAME";
536         break;
537       case WINS_PROXY_NAME:
538         src_type = "WINS_PROXY_NAME";
539         break;
540       case REGISTER_NAME:
541         src_type = "REGISTER_NAME";
542         break;
543       case SELF_NAME:
544         src_type = "SELF_NAME";
545         break;
546       case DNS_NAME:
547         src_type = "DNS_NAME";
548         break;
549       case DNSFAIL_NAME:
550         src_type = "DNSFAIL_NAME";
551         break;
552       case PERMANENT_NAME:
553         src_type = "PERMANENT_NAME";
554         break;
555       default:
556         src_type = "unknown!";
557         break;
558     }
559     fprintf(fp,"Source = %s\nb_flags = %x\t", src_type, namerec->data.nb_flags);
560
561     if(namerec->data.death_time != PERMANENT_TTL)
562     {
563       tm = LocalTime(&namerec->data.death_time);
564       fprintf(fp, "death_time = %s\t", asctime(tm));
565     }
566     else
567       fprintf(fp, "death_time = PERMANENT\t");
568
569     if(namerec->data.refresh_time != PERMANENT_TTL)
570     {
571       tm = LocalTime(&namerec->data.refresh_time);
572       fprintf(fp, "refresh_time = %s\n", asctime(tm));
573     }
574     else
575       fprintf(fp, "refresh_time = PERMANENT\n");
576
577     fprintf(fp, "\t\tnumber of IPS = %d", namerec->data.num_ips);
578     for(i = 0; i < namerec->data.num_ips; i++)
579       fprintf(fp, "\t%s", inet_ntoa(namerec->data.ip[i]));
580
581     fprintf(fp, "\n\n");
582   }
583 }
584
585 /****************************************************************************
586  Dump the contents of the namelists on all the subnets (including unicast)
587  into a file. Initiated by SIGHUP - used to debug the state of the namelists.
588 **************************************************************************/
589
590 void dump_all_namelists(void)
591 {
592   pstring fname;
593   FILE *fp; 
594   struct subnet_record *subrec;
595
596   pstrcpy(fname,lp_lockdir());
597   trim_string(fname,NULL,"/");
598   pstrcat(fname,"/"); 
599   pstrcat(fname,"namelist.debug");
600
601   fp = fopen(fname,"w");
602      
603   if (!fp)
604   { 
605     DEBUG(0,("dump_all_namelists: Can't open file %s. Error was %s\n",
606               fname,strerror(errno)));
607     return;
608   }
609       
610   for( subrec = FIRST_SUBNET;
611        subrec;
612        subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec) )
613     dump_subnet_namelist( subrec, fp);
614
615   if(!we_are_a_wins_client())
616     dump_subnet_namelist(unicast_subnet, fp);
617
618   if(remote_broadcast_subnet->namelist != NULL)
619     dump_subnet_namelist(remote_broadcast_subnet, fp);
620
621   if(wins_server_subnet != NULL)
622     dump_subnet_namelist( wins_server_subnet, fp);
623   fclose(fp);
624 }