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