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