a1442c0f03bed62f348a6f357dbe81f4d3fd2396
[kai/samba.git] / source3 / namedb.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-1995
6    
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.
11    
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.
16    
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.
20    
21    Revision History:
22
23    14 jan 96: lkcl@pires.co.uk
24    added multiple workgroup domain master support
25
26 */
27
28 #include "includes.h"
29 #include "smb.h"
30
31 extern int ClientNMB;
32 extern int ClientDGRAM;
33
34 extern int DEBUGLEVEL;
35
36 extern time_t StartupTime;
37 extern pstring myname;
38 extern pstring scope;
39
40 extern struct in_addr ipgrp;
41 extern struct in_addr ipzero;
42
43 /* this is our browse master/backup cache database */
44 struct browse_cache_record *browserlist = NULL;
45
46 /* local interfaces structure */
47 extern struct interface *local_interfaces;
48
49 /* remote interfaces structure */
50 extern struct interface *remote_interfaces;
51
52 /* this is our domain/workgroup/server database */
53 struct subnet_record *subnetlist = NULL;
54
55 static BOOL updatedlists = True;
56 int  updatecount=0;
57
58 int workgroup_count = 0; /* unique index key: one for each workgroup */
59
60 /* what server type are we currently */
61
62 #define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
63                         SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \
64                         SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
65
66
67 /****************************************************************************
68   add a workgroup into the domain list
69   **************************************************************************/
70 static void add_workgroup(struct work_record *work, struct subnet_record *d)
71 {
72   struct work_record *w2;
73
74   if (!work || !d) return;
75
76   if (!d->workgrouplist)
77     {
78       d->workgrouplist = work;
79       work->prev = NULL;
80       work->next = NULL;
81       return;
82     }
83   
84   for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
85   
86   w2->next = work;
87   work->next = NULL;
88   work->prev = w2;
89 }
90
91
92 /****************************************************************************
93   create a blank workgroup 
94   **************************************************************************/
95 static struct work_record *make_workgroup(char *name)
96 {
97   struct work_record *work;
98   struct subnet_record *d;
99   int t = -1;
100   
101   if (!name || !name[0]) return NULL;
102   
103   work = (struct work_record *)malloc(sizeof(*work));
104   if (!work) return(NULL);
105   
106   StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
107   work->serverlist = NULL;
108   
109   work->ServerType = DFLT_SERVER_TYPE;
110   work->RunningElection = False;
111   work->ElectionCount = 0;
112   work->needelection = False;
113   work->needannounce = True;
114   
115   /* make sure all token representations of workgroups are unique */
116   
117   for (d = subnetlist; d && t == -1; d = d->next)
118     {
119       struct work_record *w;
120       for (w = d->workgrouplist; w && t == -1; w = w->next)
121         {
122           if (strequal(w->work_group, work->work_group)) t = w->token;
123         }
124     }
125   
126   if (t == -1)
127     {
128       work->token = ++workgroup_count;
129     }
130   else
131     {
132       work->token = t;
133     }
134   
135   
136   /* WfWg  uses 01040b01 */
137   /* Win95 uses 01041501 */
138   /* NTAS  uses ???????? */
139   work->ElectionCriterion  = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8); 
140   work->ElectionCriterion |= (lp_os_level() << 24);
141   if (lp_domain_master()) {
142     work->ElectionCriterion |= 0x80;
143   }
144   
145   return work;
146 }
147
148
149 /*******************************************************************
150   expire old servers in the serverlist
151   time of -1 indicates everybody dies
152   ******************************************************************/
153 static void remove_old_servers(struct work_record *work, time_t t)
154 {
155   struct server_record *s;
156   struct server_record *nexts;
157   
158   /* expire old entries in the serverlist */
159   for (s = work->serverlist; s; s = nexts)
160     {
161       if (t == -1 || (s->death_time && s->death_time < t))
162         {
163           DEBUG(3,("Removing dead server %s\n",s->serv.name));
164           updatedlists = True;
165           nexts = s->next;
166           
167           if (s->prev) s->prev->next = s->next;
168           if (s->next) s->next->prev = s->prev;
169           
170           if (work->serverlist == s) 
171             work->serverlist = s->next; 
172
173           free(s);
174         }
175       else
176         {
177           nexts = s->next;
178         }
179     }
180 }
181
182
183 /*******************************************************************
184   remove workgroups
185   ******************************************************************/
186 struct work_record *remove_workgroup(struct subnet_record *d, 
187                                      struct work_record *work)
188 {
189   struct work_record *ret_work = NULL;
190   
191   if (!d || !work) return NULL;
192   
193   DEBUG(3,("Removing old workgroup %s\n", work->work_group));
194   
195   remove_old_servers(work, -1);
196   
197   ret_work = work->next;
198   
199   if (work->prev) work->prev->next = work->next;
200   if (work->next) work->next->prev = work->prev;
201   
202   if (d->workgrouplist == work) d->workgrouplist = work->next; 
203   
204   free(work);
205   
206   return ret_work;
207 }
208
209
210 /****************************************************************************
211   add a domain into the list
212   **************************************************************************/
213 static void add_subnet(struct subnet_record *d)
214 {
215   struct subnet_record *d2;
216
217   if (!subnetlist)
218   {
219     subnetlist = d;
220     d->prev = NULL;
221     d->next = NULL;
222     return;
223   }
224
225   for (d2 = subnetlist; d2->next; d2 = d2->next);
226
227   d2->next = d;
228   d->next = NULL;
229   d->prev = d2;
230 }
231
232 /***************************************************************************
233   add a browser into the list
234   **************************************************************************/
235 static void add_browse_cache(struct browse_cache_record *b)
236 {
237   struct browse_cache_record *b2;
238
239   if (!browserlist)
240     {
241       browserlist = b;
242       b->prev = NULL;
243       b->next = NULL;
244       return;
245     }
246   
247   for (b2 = browserlist; b2->next; b2 = b2->next) ;
248   
249   b2->next = b;
250   b->next = NULL;
251   b->prev = b2;
252 }
253
254
255 /***************************************************************************
256   add a server into the list
257   **************************************************************************/
258 static void add_server(struct work_record *work,struct server_record *s)
259 {
260   struct server_record *s2;
261
262   if (!work->serverlist) {
263     work->serverlist = s;
264     s->prev = NULL;
265     s->next = NULL;
266     return;
267   }
268
269   for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
270
271   s2->next = s;
272   s->next = NULL;
273   s->prev = s2;
274 }
275
276
277 /*******************************************************************
278   remove old browse entries
279   ******************************************************************/
280 void expire_browse_cache(time_t t)
281 {
282   struct browse_cache_record *b;
283   struct browse_cache_record *nextb;
284   
285   /* expire old entries in the serverlist */
286   for (b = browserlist; b; b = nextb)
287     {
288       if (b->synced && b->sync_time < t)
289         {
290           DEBUG(3,("Removing dead cached browser %s\n",b->name));
291           nextb = b->next;
292           
293           if (b->prev) b->prev->next = b->next;
294           if (b->next) b->next->prev = b->prev;
295           
296           if (browserlist == b) browserlist = b->next; 
297           
298           free(b);
299         }
300       else
301         {
302           nextb = b->next;
303         }
304     }
305 }
306
307
308 /****************************************************************************
309   find a workgroup in the workgrouplist 
310   only create it if the domain allows it, or the parameter 'add' insists
311   that it get created/added anyway. this allows us to force entries in
312   lmhosts file to be added.
313   **************************************************************************/
314 struct work_record *find_workgroupstruct(struct subnet_record *d, 
315                                          fstring name, BOOL add)
316 {
317   struct work_record *ret, *work;
318   
319   if (!d) return NULL;
320   
321   DEBUG(4, ("workgroup search for %s: ", name));
322   
323   if (strequal(name, "*"))
324     {
325       DEBUG(2,("add any workgroups: initiating browser search on %s\n",
326                inet_ntoa(d->bcast_ip)));
327       queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, NAME_QUERY_FIND_MST,
328                              MSBROWSE,0x1,0,0,
329                              True,False, d->bcast_ip);
330       return NULL;
331     }
332   
333   for (ret = d->workgrouplist; ret; ret = ret->next) {
334     if (!strcmp(ret->work_group,name)) {
335       DEBUG(4, ("found\n"));
336       return(ret);
337     }
338   }
339
340   if (!add) {
341     DEBUG(4, ("not found\n"));
342     return NULL;
343   }
344
345   DEBUG(4,("not found: creating\n"));
346   
347   if ((work = make_workgroup(name)))
348     {
349       if (lp_preferred_master() &&
350           strequal(lp_workgroup(), name) &&
351           d->my_interface)
352         {
353           DEBUG(3, ("preferred master startup for %s\n", work->work_group));
354           work->needelection = True;
355           work->ElectionCriterion |= (1<<3);
356         }
357       if (!d->my_interface)
358         {
359           work->needelection = False;
360         }
361       add_workgroup(work, d);
362       return(work);
363     }
364   return NULL;
365 }
366
367 /****************************************************************************
368   find a subnet in the subnetlist 
369   **************************************************************************/
370 struct subnet_record *find_subnet(struct in_addr bcast_ip)
371 {   
372   struct subnet_record *d;
373   struct in_addr wins_ip = ipgrp;
374   
375   /* search through subnet list for broadcast/netmask that matches
376      the source ip address. a subnet 255.255.255.255 represents the
377      WINS list. */
378   
379   for (d = subnetlist; d; d = d->next)
380     {
381         if (ip_equal(bcast_ip, wins_ip))
382             {
383            if (ip_equal(bcast_ip, d->bcast_ip))
384            {
385                return d;
386            }
387         }
388         else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip))
389             {
390         return(d);
391     }
392     }
393   
394   return (NULL);
395 }
396
397
398 /****************************************************************************
399   dump a copy of the workgroup/domain database
400   **************************************************************************/
401 void dump_workgroups(void)
402 {
403   struct subnet_record *d;
404   
405   for (d = subnetlist; d; d = d->next)
406     {
407       if (d->workgrouplist)
408         {
409           struct work_record *work;
410           
411           DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
412           DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
413           
414           for (work = d->workgrouplist; work; work = work->next)
415             {
416               DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
417               if (work->serverlist)
418                 {
419                   struct server_record *s;                
420                   for (s = work->serverlist; s; s = s->next)
421                     {
422                       DEBUG(4,("\t\t%s %8x (%s)\n",
423                                s->serv.name, s->serv.type, s->serv.comment));
424                     }
425                 }
426             }
427         }
428     }
429 }
430
431 /****************************************************************************
432   create a domain entry
433   ****************************************************************************/
434 static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr mask_ip)
435 {
436   struct subnet_record *d;
437   d = (struct subnet_record *)malloc(sizeof(*d));
438   
439   if (!d) return(NULL);
440   
441   bzero((char *)d,sizeof(*d));
442   
443   DEBUG(4, ("making domain %s ", inet_ntoa(bcast_ip)));
444   DEBUG(4, ("%s\n", inet_ntoa(mask_ip)));
445   
446   d->bcast_ip = bcast_ip;
447   d->mask_ip  = mask_ip;
448   d->workgrouplist = NULL;
449   d->my_interface = False; /* True iff the interface is on the samba host */
450
451   add_subnet(d);
452   
453   return d;
454 }
455
456
457 /****************************************************************************
458   add the remote interfaces from lp_remote_interfaces() and lp_interfaces()
459   to the netbios subnet database.
460   ****************************************************************************/
461 void add_subnet_interfaces(void)
462 {
463         struct interface *i;
464
465         /* loop on all local interfaces */
466         for (i = local_interfaces; i; i = i->next)
467         {
468                 /* add the interface into our subnet database */
469                 if (!find_subnet(i->bcast))
470                 {
471                     struct subnet_record *d = make_subnet(i->bcast,i->nmask);
472                         if (d)
473                         {
474                                 /* short-cut method to identifying local interfaces */
475                                 d->my_interface = True;
476                         }
477                 }
478         }
479
480         /* loop on all remote interfaces */
481         for (i = remote_interfaces; i; i = i->next)
482         {
483                 /* add the interface into our subnet database */
484                 if (!find_subnet(i->bcast))
485                 {
486                     make_subnet(i->bcast,i->nmask);
487                 }
488         }
489
490         /* add the pseudo-ip interface for WINS: 255.255.255.255 */
491         if (lp_wins_support())
492     {
493                 struct in_addr wins_bcast = ipgrp;
494                 struct in_addr wins_nmask = ipzero;
495                 make_subnet(wins_bcast, wins_nmask);
496     }
497 }
498
499
500 /****************************************************************************
501   add a domain entry. creates a workgroup, if necessary, and adds the domain
502   to the named a workgroup.
503   ****************************************************************************/
504 struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, 
505                                        struct in_addr mask_ip,
506                                        char *name, BOOL add, BOOL lmhosts)
507 {
508   struct subnet_record *d;
509   
510   /* XXXX andrew: struct in_addr ip appears not to be referenced at all except
511      in the DEBUG comment. i assume that the DEBUG comment below actually
512      intends to refer to bcast_ip? i don't know.
513
514   struct in_addr ip = ipgrp;
515
516   */
517   
518   if (zero_ip(bcast_ip)) 
519     bcast_ip = *iface_bcast(bcast_ip);
520   
521   /* add the domain into our domain database */
522   if ((d = find_subnet(bcast_ip)) ||
523       (d = make_subnet(bcast_ip, mask_ip)))
524     {
525       struct work_record *w = find_workgroupstruct(d, name, add);
526           extern pstring ServerComment;
527       
528       if (!w) return NULL;
529
530       /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
531          or register with WINS server, if it's our workgroup */
532       if (strequal(lp_workgroup(), name) && d->my_interface)
533         {
534           add_my_name_entry(d,name,0x1e,NB_ACTIVE|NB_GROUP);
535           add_my_name_entry(d,name,0x0 ,NB_ACTIVE|NB_GROUP);
536         }
537       /* add samba server name to workgroup list */
538       if ((strequal(lp_workgroup(), name) && d->my_interface) || lmhosts)
539         {
540           add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
541         }
542       
543       DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(bcast_ip)));
544       return d;
545     }
546   return NULL;
547 }
548
549 /****************************************************************************
550   add a browser entry
551   ****************************************************************************/
552 struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
553                                               time_t ttl, struct in_addr ip)
554 {
555   BOOL newentry=False;
556   
557   struct browse_cache_record *b;
558
559   /* search for the entry: if it's already in the cache, update that entry */
560   for (b = browserlist; b; b = b->next)
561     {
562       if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
563     }
564   
565   if (b && b->synced)
566     {
567       /* entries get left in the cache for a while. this stops sync'ing too
568          often if the network is large */
569       DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
570                 b->name, b->group, inet_ntoa(b->ip), b->sync_time));
571       return NULL;
572     }
573   
574   if (!b)
575     {
576       newentry = True;
577       b = (struct browse_cache_record *)malloc(sizeof(*b));
578       
579       if (!b) return(NULL);
580       
581       bzero((char *)b,sizeof(*b));
582     }
583   
584   /* update the entry */
585   ttl = time(NULL)+ttl;
586   
587   StrnCpy(b->name ,name,sizeof(b->name )-1);
588   StrnCpy(b->group,wg  ,sizeof(b->group)-1);
589   strupper(b->name);
590   strupper(b->group);
591   
592   b->ip     = ip;
593   b->type   = type;
594   
595   if (newentry || ttl < b->sync_time) 
596     b->sync_time = ttl;
597   
598   if (newentry)
599     {
600       b->synced = False;
601       add_browse_cache(b);
602       
603       DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
604                wg, name, type, inet_ntoa(ip),ttl));
605     }
606   else
607     {
608       DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
609                wg, name, type, inet_ntoa(ip),ttl));
610     }
611   
612   return(b);
613 }
614
615
616 /****************************************************************************
617   remove all samba's server entries
618   ****************************************************************************/
619 void remove_my_servers(void)
620 {
621         struct subnet_record *d; 
622         for (d = subnetlist; d; d = d->next)
623         {
624                 struct work_record *work;
625                 for (work = d->workgrouplist; work; work = work->next)
626                 {
627                         struct server_record *s;
628                         for (s = work->serverlist; s; s = s->next)
629                         {
630                                 if (!strequal(myname,s->serv.name)) continue;
631                                 announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
632                         }
633                 }
634         }
635 }
636
637
638 /****************************************************************************
639   add a server entry
640   ****************************************************************************/
641 struct server_record *add_server_entry(struct subnet_record *d, 
642                                        struct work_record *work,
643                                        char *name,int servertype, 
644                                        int ttl,char *comment,
645                                        BOOL replace)
646 {
647   BOOL newentry=False;
648   struct server_record *s;
649   
650   if (name[0] == '*')
651     {
652       return (NULL);
653     }
654   
655   for (s = work->serverlist; s; s = s->next)
656     {
657       if (strequal(name,s->serv.name)) break;
658     }
659   
660   if (s && !replace)
661     {
662       DEBUG(4,("Not replacing %s\n",name));
663       return(s);
664     }
665   
666   if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
667   updatedlists=True;
668   
669   if (!s)
670     {
671       newentry = True;
672       s = (struct server_record *)malloc(sizeof(*s));
673       
674       if (!s) return(NULL);
675       
676       bzero((char *)s,sizeof(*s));
677     }
678   
679   
680   if (d->my_interface && strequal(lp_workgroup(),work->work_group))
681     {
682       if (servertype)
683         servertype |= SV_TYPE_LOCAL_LIST_ONLY;
684     }
685   else
686     {
687       servertype &= ~SV_TYPE_LOCAL_LIST_ONLY;
688     }
689   
690   /* update the entry */
691   StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
692   StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
693   strupper(s->serv.name);
694   s->serv.type  = servertype;
695   s->death_time = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1);
696   
697   /* for a domain entry, the comment field refers to the server name */
698   
699   if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
700   
701   if (newentry)
702     {
703       add_server(work, s);
704       
705       DEBUG(3,("Added "));
706     }
707   else
708     {
709       DEBUG(3,("Updated "));
710     }
711   
712   DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
713            name,servertype,comment,
714            work->work_group,inet_ntoa(d->bcast_ip)));
715   
716   return(s);
717 }
718
719
720 /*******************************************************************
721   write out browse.dat
722   ******************************************************************/
723 void write_browse_list(void)
724 {
725   struct subnet_record *d;
726   
727   pstring fname,fnamenew;
728   FILE *f;
729   
730   if (!updatedlists) return;
731   
732   dump_names();
733   dump_workgroups();
734   
735   updatedlists = False;
736   updatecount++;
737   
738   strcpy(fname,lp_lockdir());
739   trim_string(fname,NULL,"/");
740   strcat(fname,"/");
741   strcat(fname,SERVER_LIST);
742   strcpy(fnamenew,fname);
743   strcat(fnamenew,".");
744   
745   f = fopen(fnamenew,"w");
746   
747   if (!f)
748     {
749       DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
750       return;
751     }
752   
753   for (d = subnetlist; d ; d = d->next)
754     {
755       struct work_record *work;
756       for (work = d->workgrouplist; work ; work = work->next)
757         {
758           struct server_record *s;
759           for (s = work->serverlist; s ; s = s->next)
760             {
761               fstring tmp;
762               
763               /* don't list domains I don't have a master for */
764               if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0])
765                 {
766                   continue;
767                 }
768               
769               /* output server details, plus what workgroup/domain
770                  they're in. without the domain information, the
771                  combined list of all servers in all workgroups gets
772                  sent to anyone asking about any workgroup! */
773               
774               sprintf(tmp, "\"%s\"", s->serv.name);
775               fprintf(f, "%-25s ", tmp);
776               fprintf(f, "%08x ", s->serv.type);
777               sprintf(tmp, "\"%s\" ", s->serv.comment);
778               fprintf(f, "%-30s", tmp);
779               fprintf(f, "\"%s\"\n", work->work_group);
780             }
781         }
782     }
783   
784   fclose(f);
785   unlink(fname);
786   chmod(fnamenew,0644);
787   rename(fnamenew,fname);   
788   DEBUG(3,("Wrote browse list %s\n",fname));
789 }
790
791
792 /*******************************************************************
793   expire old servers in the serverlist
794   ******************************************************************/
795 void expire_servers(time_t t)
796 {
797   struct subnet_record *d;
798   
799   for (d = subnetlist ; d ; d = d->next)
800     {
801       struct work_record *work;
802       
803       for (work = d->workgrouplist; work; work = work->next)
804         {
805           remove_old_servers(work, t);
806         }
807     }
808 }
809