This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[samba.git] / source3 / nmbd / nmbd_browsesync.c
1 /* 
2    Unix SMB/CIFS implementation.
3    NBT netbios routines and daemon - version 2
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
6    Copyright (C) Jeremy Allison 1994-1998
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21    
22 */
23
24 #include "includes.h"
25
26 /* This is our local master browser list database. */
27 extern ubi_dlList lmb_browserlist[];
28
29 /****************************************************************************
30 As a domain master browser, do a sync with a local master browser.
31 **************************************************************************/
32 static void sync_with_lmb(struct browse_cache_record *browc)
33 {                     
34   struct work_record *work;
35
36   if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
37   {
38     if( DEBUGLVL( 0 ) )
39     {
40       dbgtext( "sync_with_lmb:\n" );
41       dbgtext( "Failed to get a workgroup for a local master browser " );
42       dbgtext( "cache entry workgroup " );
43       dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
44     }
45     return;
46   }
47
48   /* We should only be doing this if we are a domain master browser for
49      the given workgroup. Ensure this is so. */
50
51   if(!AM_DOMAIN_MASTER_BROWSER(work))
52   {
53     if( DEBUGLVL( 0 ) )
54     {
55       dbgtext( "sync_with_lmb:\n" );
56       dbgtext( "We are trying to sync with a local master browser " );
57       dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
58       dbgtext( "and we are not a domain master browser on this workgroup.\n" );
59       dbgtext( "Error!\n" );
60     }
61     return;
62   }
63
64   if( DEBUGLVL( 2 ) )
65   {
66     dbgtext( "sync_with_lmb:\n" );
67     dbgtext( "Initiating sync with local master browser " );
68     dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
69     dbgtext( "for workgroup %s\n", browc->work_group );
70   }
71
72   sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
73
74   browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
75 }
76
77 /****************************************************************************
78 Sync or expire any local master browsers.
79 **************************************************************************/
80 void dmb_expire_and_sync_browser_lists(time_t t)
81 {
82   static time_t last_run = 0;
83   struct browse_cache_record *browc;
84
85   /* Only do this every 20 seconds. */  
86   if (t - last_run < 20) 
87    return;
88
89   last_run = t;
90
91   expire_lmb_browsers(t);
92
93   for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
94        browc;
95        browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
96   {
97     if (browc->sync_time < t)
98       sync_with_lmb(browc);
99   }
100 }
101
102 /****************************************************************************
103 As a local master browser, send an announce packet to the domain master browser.
104 **************************************************************************/
105
106 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
107 {
108   pstring outbuf;
109   char *p;
110
111   if(ismyip(work->dmb_addr))
112   {
113     if( DEBUGLVL( 2 ) )
114     {
115       dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
116       dbgtext( "We are both a domain and a local master browser for " );
117       dbgtext( "workgroup %s.  ", work->work_group );
118       dbgtext( "Do not announce to ourselves.\n" );
119     }
120     return;
121   }
122
123   memset(outbuf,'\0',sizeof(outbuf));
124   p = outbuf;
125   SCVAL(p,0,ANN_MasterAnnouncement);
126   p++;
127
128   StrnCpy(p,global_myname(),15);
129   strupper(p);
130   p = skip_string(p,1);
131
132   if( DEBUGLVL( 4 ) )
133   {
134     dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
135     dbgtext( "Sending local master announce to " );
136     dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
137                                        work->work_group );
138   }
139
140   send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
141                 global_myname(), 0x0, work->dmb_name.name, 0x0, 
142                 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
143
144 }
145
146 /****************************************************************************
147 As a local master browser, do a sync with a domain master browser.
148 **************************************************************************/
149
150 static void sync_with_dmb(struct work_record *work)
151 {
152   if( DEBUGLVL( 2 ) )
153   {
154     dbgtext( "sync_with_dmb:\n" );
155     dbgtext( "Initiating sync with domain master browser " );
156     dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
157     dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
158     dbgtext( "for workgroup %s\n", work->work_group );
159   }
160
161   sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type, 
162                     work->dmb_addr, False, True);
163 }
164
165 /****************************************************************************
166   Function called when a node status query to a domain master browser IP succeeds.
167 ****************************************************************************/
168
169 static void domain_master_node_status_success(struct subnet_record *subrec,
170                                               struct userdata_struct *userdata,
171                                               struct res_rec *answers,
172                                               struct in_addr from_ip)
173 {
174   struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
175
176   if( work == NULL )
177   {
178     if( DEBUGLVL( 0 ) )
179     {
180       dbgtext( "domain_master_node_status_success:\n" );
181       dbgtext( "Unable to find workgroup " );
182       dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
183     }
184     return;
185   }
186
187   if( DEBUGLVL( 3 ) )
188   {
189     dbgtext( "domain_master_node_status_success:\n" );
190     dbgtext( "Success in node status for workgroup " );
191     dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
192   }
193
194   /* Go through the list of names found at answers->rdata and look for
195      the first SERVER<0x20> name. */
196
197   if(answers->rdata != NULL)
198   {
199     char *p = answers->rdata;
200     int numnames = CVAL(p, 0);
201
202     p += 1;
203
204     while (numnames--)
205     {
206       char qname[17];
207       uint16 nb_flags;
208       int name_type;
209
210       StrnCpy(qname,p,15);
211       name_type = CVAL(p,15);
212       nb_flags = get_nb_flags(&p[16]);
213       trim_string(qname,NULL," ");
214
215       p += 18;
216
217       if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
218       {
219         struct nmb_name nmbname;
220
221         make_nmb_name(&nmbname, qname, name_type);
222
223         /* Copy the dmb name and IP address
224            into the workgroup struct. */
225
226         work->dmb_name = nmbname;
227         putip((char *)&work->dmb_addr, &from_ip);
228
229         /* Do the local master browser announcement to the domain
230            master browser name and IP. */
231         announce_local_master_browser_to_domain_master_browser( work );
232
233         /* Now synchronise lists with the domain master browser. */
234         sync_with_dmb(work);
235         break;
236       }
237     }
238   }
239   else
240     if( DEBUGLVL( 0 ) )
241     {
242       dbgtext( "domain_master_node_status_success:\n" );
243       dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
244       dbgtext( "%s.\n", inet_ntoa(from_ip) );
245     }
246 }
247
248 /****************************************************************************
249   Function called when a node status query to a domain master browser IP fails.
250 ****************************************************************************/
251
252 static void domain_master_node_status_fail(struct subnet_record *subrec,
253                        struct response_record *rrec)
254 {
255   struct userdata_struct *userdata = rrec->userdata;
256
257   if( DEBUGLVL( 0 ) )
258   {
259     dbgtext( "domain_master_node_status_fail:\n" );
260     dbgtext( "Doing a node status request to the domain master browser\n" );
261     dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
262     dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
263     dbgtext( "Cannot sync browser lists.\n" );
264   }
265 }
266
267 /****************************************************************************
268   Function called when a query for a WORKGROUP<1b> name succeeds.
269 ****************************************************************************/
270
271 static void find_domain_master_name_query_success(struct subnet_record *subrec,
272                         struct userdata_struct *userdata_in,
273                         struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
274 {
275   /* 
276    * Unfortunately, finding the IP address of the Domain Master Browser,
277    * as we have here, is not enough. We need to now do a sync to the
278    * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
279    * respond to the SMBSERVER name. To get this name from IP
280    * address we do a Node status request, and look for the first
281    * NAME<0x20> in the response, and take that as the server name.
282    * We also keep a cache of the Domain Master Browser name for this
283    * workgroup in the Workgroup struct, so that if the same IP addess
284    * is returned every time, we don't need to do the node status
285    * request.
286    */
287
288   struct work_record *work;
289   struct nmb_name nmbname;
290   struct userdata_struct *userdata;
291   int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
292
293   if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
294   {
295     if( DEBUGLVL( 0 ) )
296       {
297       dbgtext( "find_domain_master_name_query_success:\n" );
298       dbgtext( "Failed to find workgroup %s\n", q_name->name );
299       }
300     return;
301   }
302
303   /* First check if we already have a dmb for this workgroup. */
304
305   if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip))
306   {
307     /* Do the local master browser announcement to the domain
308        master browser name and IP. */
309     announce_local_master_browser_to_domain_master_browser( work );
310
311     /* Now synchronise lists with the domain master browser. */
312     sync_with_dmb(work);
313     return;
314   }
315   else
316     zero_ip(&work->dmb_addr);
317
318   /* Now initiate the node status request. */
319   make_nmb_name(&nmbname,"*",0x0);
320
321   /* Put the workgroup name into the userdata so we know
322      what workgroup we're talking to when the reply comes
323      back. */
324
325   /* Setup the userdata_struct - this is copied so we can use
326      a stack variable for this. */
327   if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
328   {
329     DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
330     return;
331   }
332
333   userdata->copy_fn = NULL;
334   userdata->free_fn = NULL;
335   userdata->userdata_len = strlen(work->work_group)+1;
336   fstrcpy(userdata->data, work->work_group);
337
338   node_status( subrec, &nmbname, answer_ip, 
339                domain_master_node_status_success,
340                domain_master_node_status_fail,
341                userdata);
342
343   zero_free(userdata, size);
344 }
345
346 /****************************************************************************
347   Function called when a query for a WORKGROUP<1b> name fails.
348   ****************************************************************************/
349 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
350                                     struct response_record *rrec,
351                                     struct nmb_name *question_name, int fail_code)
352 {
353   if( DEBUGLVL( 0 ) )
354   {
355     dbgtext( "find_domain_master_name_query_fail:\n" );
356     dbgtext( "Unable to find the Domain Master Browser name " );
357     dbgtext( "%s for the workgroup %s.\n",
358              nmb_namestr(question_name), question_name->name );
359     dbgtext( "Unable to sync browse lists in this workgroup.\n" );
360   }
361 }
362
363 /****************************************************************************
364 As a local master browser for a workgroup find the domain master browser
365 name, announce ourselves as local master browser to it and then pull the
366 full domain browse lists from it onto the given subnet.
367 **************************************************************************/
368
369 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
370                                                    struct work_record *work)
371 {
372   struct nmb_name nmbname;
373
374   /* Only do this if we are using a WINS server. */
375   if(we_are_a_wins_client() == False)
376   {
377     if( DEBUGLVL( 10 ) )
378     {
379       dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
380       dbgtext( "Ignoring, as we are not a WINS client.\n" );
381     }
382     return;
383   }
384
385   make_nmb_name(&nmbname,work->work_group,0x1b);
386
387   /* First, query for the WORKGROUP<1b> name from the WINS server. */
388   query_name(unicast_subnet, nmbname.name, nmbname.name_type,
389              find_domain_master_name_query_success,
390              find_domain_master_name_query_fail,
391              NULL);
392
393 }
394
395 /****************************************************************************
396   Function called when a node status query to a domain master browser IP succeeds.
397   This function is only called on query to a Samba 1.9.18 or above WINS server.
398
399   Note that adding the workgroup name is enough for this workgroup to be
400   browsable by clients, as clients query the WINS server or broadcast 
401   nets for the WORKGROUP<1b> name when they want to browse a workgroup
402   they are not in. We do not need to do a sync with this Domain Master
403   Browser in order for our browse clients to see machines in this workgroup.
404   JRA.
405 ****************************************************************************/
406
407 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
408                                               struct userdata_struct *userdata,
409                                               struct res_rec *answers,
410                                               struct in_addr from_ip)
411 {
412   struct work_record *work;
413   fstring server_name;
414
415   server_name[0] = 0;
416
417   if( DEBUGLVL( 3 ) )
418   {
419     dbgtext( "get_domain_master_name_node_status_success:\n" );
420     dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
421   }
422
423   /* 
424    * Go through the list of names found at answers->rdata and look for
425    * the first WORKGROUP<0x1b> name.
426    */
427
428   if(answers->rdata != NULL)
429   {
430     char *p = answers->rdata;
431     int numnames = CVAL(p, 0);
432
433     p += 1;
434
435     while (numnames--)
436     {
437       char qname[17];
438       uint16 nb_flags;
439       int name_type;
440
441       StrnCpy(qname,p,15);
442       name_type = CVAL(p,15);
443       nb_flags = get_nb_flags(&p[16]);
444       trim_string(qname,NULL," ");
445
446       p += 18;
447
448       if(!(nb_flags & NB_GROUP) && (name_type == 0x00) && 
449          server_name[0] == 0) {
450               /* this is almost certainly the server netbios name */
451               fstrcpy(server_name, qname);
452               continue;
453       }
454
455       if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
456       {
457         if( DEBUGLVL( 5 ) )
458         {
459           dbgtext( "get_domain_master_name_node_status_success:\n" );
460           dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
461           dbgtext( "is a domain master browser for workgroup " );
462           dbgtext( "%s. Adding this name.\n", qname );
463         }
464
465         /* 
466          * If we don't already know about this workgroup, add it
467          * to the workgroup list on the unicast_subnet.
468          */
469         if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
470         {
471                 struct nmb_name nmbname;
472                 /* 
473                  * Add it - with an hour in the cache.
474                  */
475                 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
476                         return;
477
478                 /* remember who the master is */
479                 fstrcpy(work->local_master_browser_name, server_name);
480                 make_nmb_name(&nmbname, server_name, 0x20);
481                 work->dmb_name = nmbname;
482                 work->dmb_addr = from_ip;
483         }
484         break;
485       }
486     }
487   }
488   else
489     if( DEBUGLVL( 0 ) )
490     {
491       dbgtext( "get_domain_master_name_node_status_success:\n" );
492       dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
493       dbgtext( "%s.\n", inet_ntoa(from_ip) );
494     }
495 }
496
497 /****************************************************************************
498   Function called when a node status query to a domain master browser IP fails.
499 ****************************************************************************/
500
501 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
502                        struct response_record *rrec)
503 {
504   if( DEBUGLVL( 0 ) )
505   {
506     dbgtext( "get_domain_master_name_node_status_fail:\n" );
507     dbgtext( "Doing a node status request to the domain master browser " );
508     dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
509     dbgtext( "Cannot get workgroup name.\n" );
510   }
511 }
512
513 /****************************************************************************
514   Function called when a query for *<1b> name succeeds.
515 ****************************************************************************/
516
517 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
518                         struct userdata_struct *userdata_in,
519                         struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
520 {
521   /* 
522    * We now have a list of all the domain master browsers for all workgroups
523    * that have registered with the WINS server. Now do a node status request
524    * to each one and look for the first 1b name in the reply. This will be
525    * the workgroup name that we will add to the unicast subnet as a 'non-local'
526    * workgroup.
527    */
528
529   struct nmb_name nmbname;
530   struct in_addr send_ip;
531   int i;
532
533   if( DEBUGLVL( 5 ) )
534   {
535     dbgtext( "find_all_domain_master_names_query_succes:\n" );
536     dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
537     dbgtext( "IP addresses for Domain Master Browsers.\n" );
538   }
539
540   for(i = 0; i < rrec->rdlength / 6; i++)
541   {
542     /* Initiate the node status requests. */
543     make_nmb_name(&nmbname, "*", 0);
544
545     putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
546
547     /* 
548      * Don't send node status requests to ourself.
549      */
550
551     if(ismyip( send_ip ))
552     {
553       if( DEBUGLVL( 5 ) )
554       {
555         dbgtext( "find_all_domain_master_names_query_succes:\n" );
556         dbgtext( "Not sending node status to our own IP " );
557         dbgtext( "%s.\n", inet_ntoa(send_ip) );
558       }
559       continue;
560     }
561
562     if( DEBUGLVL( 5 ) )
563     {
564       dbgtext( "find_all_domain_master_names_query_success:\n" );
565       dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
566     }
567
568     node_status( subrec, &nmbname, send_ip, 
569                  get_domain_master_name_node_status_success,
570                  get_domain_master_name_node_status_fail,
571                  NULL);
572   }
573 }
574
575 /****************************************************************************
576   Function called when a query for *<1b> name fails.
577   ****************************************************************************/
578 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
579                                     struct response_record *rrec,
580                                     struct nmb_name *question_name, int fail_code)
581 {
582   if( DEBUGLVL( 10 ) )
583   {
584     dbgtext( "find_domain_master_name_query_fail:\n" );
585     dbgtext( "WINS server did not reply to a query for name " );
586     dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
587     dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
588   }
589 }
590
591 /****************************************************************************
592  If we are a domain master browser on the unicast subnet, do a query to the
593  WINS server for the *<1b> name. This will only work to a Samba WINS server,
594  so ignore it if we fail. If we succeed, contact each of the IP addresses in
595  turn and do a node status request to them. If this succeeds then look for a
596  <1b> name in the reply - this is the workgroup name. Add this to the unicast
597  subnet. This is expensive, so we only do this every 15 minutes.
598 **************************************************************************/
599 void collect_all_workgroup_names_from_wins_server(time_t t)
600 {
601   static time_t lastrun = 0;
602   struct work_record *work;
603   struct nmb_name nmbname;
604
605   /* Only do this if we are using a WINS server. */
606   if(we_are_a_wins_client() == False)
607     return;
608
609   /* Check to see if we are a domain master browser on the unicast subnet. */
610   if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL)
611   {
612     if( DEBUGLVL( 0 ) )
613     {
614       dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
615       dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
616       dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
617     }
618     return;
619   }
620
621   if(!AM_DOMAIN_MASTER_BROWSER(work))
622     return;
623
624   if ((lastrun != 0) && (t < lastrun + (15 * 60)))
625     return;
626      
627   lastrun = t;
628
629   make_nmb_name(&nmbname,"*",0x1b);
630
631   /* First, query for the *<1b> name from the WINS server. */
632   query_name(unicast_subnet, nmbname.name, nmbname.name_type,
633              find_all_domain_master_names_query_success,
634              find_all_domain_master_names_query_fail,
635              NULL);
636
637
638
639 /****************************************************************************
640  If we are a domain master browser on the unicast subnet, do a regular sync
641  with all other DMBs that we know of on that subnet.
642
643 To prevent exponential network traffic with large numbers of workgroups
644 we use a randomised system where sync probability is inversely proportional
645 to the number of known workgroups
646 **************************************************************************/
647 void sync_all_dmbs(time_t t)
648 {
649         static time_t lastrun = 0;
650         struct work_record *work;
651         int count=0;
652
653         /* Only do this if we are using a WINS server. */
654         if(we_are_a_wins_client() == False)
655                 return;
656
657         /* Check to see if we are a domain master browser on the
658            unicast subnet. */
659         work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
660         if (!work) return;
661
662         if (!AM_DOMAIN_MASTER_BROWSER(work))
663                 return;
664
665         if ((lastrun != 0) && (t < lastrun + (5 * 60)))
666                 return;
667      
668         /* count how many syncs we might need to do */
669         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
670                 if (strcmp(lp_workgroup(), work->work_group)) {
671                         count++;
672                 }
673         }
674
675         /* sync with a probability of 1/count */
676         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
677                 if (strcmp(lp_workgroup(), work->work_group)) {
678                         if (((unsigned)sys_random()) % count != 0) continue;
679
680                         lastrun = t;
681
682                         if (!work->dmb_name.name[0]) {
683                                 /* we don't know the DMB - assume it is
684                                    the same as the unicast local master */
685                                 make_nmb_name(&work->dmb_name, 
686                                               work->local_master_browser_name,
687                                               0x20);
688                         }
689
690                         DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
691                                  work->dmb_name.name, 
692                                  inet_ntoa(work->dmb_addr)));
693                         sync_browse_lists(work, 
694                                           work->dmb_name.name,
695                                           work->dmb_name.name_type, 
696                                           work->dmb_addr, False, False);
697                 }
698         }
699