fixed error check which caused domain logons to fail
[Samba.git] / source / nmbd / nmbd_browsesync.c
blob6a8edd0eaf0e0323d0d7e685f4823a78a514025d
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
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.
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.
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.
25 #include "includes.h"
26 #include "smb.h"
28 extern struct in_addr ipzero;
29 extern pstring global_myname;
30 extern fstring global_myworkgroup;
32 /* This is our local master browser list database. */
33 extern ubi_dlList lmb_browserlist[];
35 /****************************************************************************
36 As a domain master browser, do a sync with a local master browser.
37 **************************************************************************/
38 static void sync_with_lmb(struct browse_cache_record *browc)
40 struct work_record *work;
42 if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
44 if( DEBUGLVL( 0 ) )
46 dbgtext( "sync_with_lmb:\n" );
47 dbgtext( "Failed to get a workgroup for a local master browser " );
48 dbgtext( "cache entry workgroup " );
49 dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
51 return;
54 /* We should only be doing this if we are a domain master browser for
55 the given workgroup. Ensure this is so. */
57 if(!AM_DOMAIN_MASTER_BROWSER(work))
59 if( DEBUGLVL( 0 ) )
61 dbgtext( "sync_with_lmb:\n" );
62 dbgtext( "We are trying to sync with a local master browser " );
63 dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
64 dbgtext( "and we are not a domain master browser on this workgroup.\n" );
65 dbgtext( "Error!\n" );
67 return;
70 if( DEBUGLVL( 2 ) )
72 dbgtext( "sync_with_lmb:\n" );
73 dbgtext( "Initiating sync with local master browser " );
74 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
75 dbgtext( "for workgroup %s\n", browc->work_group );
78 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
80 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
83 /****************************************************************************
84 Sync or expire any local master browsers.
85 **************************************************************************/
86 void dmb_expire_and_sync_browser_lists(time_t t)
88 static time_t last_run = 0;
89 struct browse_cache_record *browc;
91 /* Only do this every 20 seconds. */
92 if (t - last_run < 20)
93 return;
95 last_run = t;
97 expire_lmb_browsers(t);
99 for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
100 browc;
101 browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
103 if (browc->sync_time < t)
104 sync_with_lmb(browc);
108 /****************************************************************************
109 As a local master browser, send an announce packet to the domain master browser.
110 **************************************************************************/
112 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
114 pstring outbuf;
115 char *p;
117 if(ismyip(work->dmb_addr))
119 if( DEBUGLVL( 2 ) )
121 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
122 dbgtext( "We are both a domain and a local master browser for " );
123 dbgtext( "workgroup %s. ", work->work_group );
124 dbgtext( "Do not announce to ourselves.\n" );
126 return;
129 memset(outbuf,'\0',sizeof(outbuf));
130 p = outbuf;
131 CVAL(p,0) = ANN_MasterAnnouncement;
132 p++;
134 StrnCpy(p,global_myname,15);
135 strupper(p);
136 p = skip_string(p,1);
138 if( DEBUGLVL( 4 ) )
140 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
141 dbgtext( "Sending local master announce to " );
142 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
143 work->work_group );
146 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
147 global_myname, 0x0, work->dmb_name.name, 0x0,
148 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
152 /****************************************************************************
153 As a local master browser, do a sync with a domain master browser.
154 **************************************************************************/
156 static void sync_with_dmb(struct work_record *work)
158 if( DEBUGLVL( 2 ) )
160 dbgtext( "sync_with_dmb:\n" );
161 dbgtext( "Initiating sync with domain master browser " );
162 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
163 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
164 dbgtext( "for workgroup %s\n", work->work_group );
167 sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
168 work->dmb_addr, False, True);
171 /****************************************************************************
172 Function called when a node status query to a domain master browser IP succeeds.
173 ****************************************************************************/
175 static void domain_master_node_status_success(struct subnet_record *subrec,
176 struct userdata_struct *userdata,
177 struct res_rec *answers,
178 struct in_addr from_ip)
180 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
182 if( work == NULL )
184 if( DEBUGLVL( 0 ) )
186 dbgtext( "domain_master_node_status_success:\n" );
187 dbgtext( "Unable to find workgroup " );
188 dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
190 return;
193 if( DEBUGLVL( 3 ) )
195 dbgtext( "domain_master_node_status_success:\n" );
196 dbgtext( "Success in node status for workgroup " );
197 dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
200 /* Go through the list of names found at answers->rdata and look for
201 the first SERVER<0x20> name. */
203 if(answers->rdata != NULL)
205 char *p = answers->rdata;
206 int numnames = CVAL(p, 0);
208 p += 1;
210 while (numnames--)
212 char qname[17];
213 uint16 nb_flags;
214 int name_type;
216 StrnCpy(qname,p,15);
217 name_type = CVAL(p,15);
218 nb_flags = get_nb_flags(&p[16]);
219 trim_string(qname,NULL," ");
221 p += 18;
223 if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
225 struct nmb_name nmbname;
227 make_nmb_name(&nmbname, qname, name_type);
229 /* Copy the dmb name and IP address
230 into the workgroup struct. */
232 work->dmb_name = nmbname;
233 putip((char *)&work->dmb_addr, &from_ip);
235 /* Do the local master browser announcement to the domain
236 master browser name and IP. */
237 announce_local_master_browser_to_domain_master_browser( work );
239 /* Now synchronise lists with the domain master browser. */
240 sync_with_dmb(work);
241 break;
245 else
246 if( DEBUGLVL( 0 ) )
248 dbgtext( "domain_master_node_status_success:\n" );
249 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
250 dbgtext( "%s.\n", inet_ntoa(from_ip) );
254 /****************************************************************************
255 Function called when a node status query to a domain master browser IP fails.
256 ****************************************************************************/
258 static void domain_master_node_status_fail(struct subnet_record *subrec,
259 struct response_record *rrec)
261 struct userdata_struct *userdata = rrec->userdata;
263 if( DEBUGLVL( 0 ) )
265 dbgtext( "domain_master_node_status_fail:\n" );
266 dbgtext( "Doing a node status request to the domain master browser\n" );
267 dbgtext( "for workgroup %s ", userdata->data );
268 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
269 dbgtext( "Cannot sync browser lists.\n" );
273 /****************************************************************************
274 Function called when a query for a WORKGROUP<1b> name succeeds.
275 ****************************************************************************/
277 static void find_domain_master_name_query_success(struct subnet_record *subrec,
278 struct userdata_struct *userdata_in,
279 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
282 * Unfortunately, finding the IP address of the Domain Master Browser,
283 * as we have here, is not enough. We need to now do a sync to the
284 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
285 * respond to the SMBSERVER name. To get this name from IP
286 * address we do a Node status request, and look for the first
287 * NAME<0x20> in the response, and take that as the server name.
288 * We also keep a cache of the Domain Master Browser name for this
289 * workgroup in the Workgroup struct, so that if the same IP addess
290 * is returned every time, we don't need to do the node status
291 * request.
294 struct work_record *work;
295 struct nmb_name nmbname;
296 struct userdata_struct *userdata;
297 int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
299 if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
301 if( DEBUGLVL( 0 ) )
303 dbgtext( "find_domain_master_name_query_success:\n" );
304 dbgtext( "Failed to find workgroup %s\n", q_name->name );
306 return;
309 /* First check if we already have a dmb for this workgroup. */
311 if(!ip_equal(work->dmb_addr, ipzero) && ip_equal(work->dmb_addr, answer_ip))
313 /* Do the local master browser announcement to the domain
314 master browser name and IP. */
315 announce_local_master_browser_to_domain_master_browser( work );
317 /* Now synchronise lists with the domain master browser. */
318 sync_with_dmb(work);
319 return;
321 else
322 putip((char *)&work->dmb_addr, &ipzero);
324 /* Now initiate the node status request. */
325 make_nmb_name(&nmbname,"*",0x0);
327 /* Put the workgroup name into the userdata so we know
328 what workgroup we're talking to when the reply comes
329 back. */
331 /* Setup the userdata_struct - this is copied so we can use
332 a stack variable for this. */
333 if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
335 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
336 return;
339 userdata->copy_fn = NULL;
340 userdata->free_fn = NULL;
341 userdata->userdata_len = strlen(work->work_group)+1;
342 pstrcpy(userdata->data, work->work_group);
344 node_status( subrec, &nmbname, answer_ip,
345 domain_master_node_status_success,
346 domain_master_node_status_fail,
347 userdata);
349 zero_free(userdata, size);
352 /****************************************************************************
353 Function called when a query for a WORKGROUP<1b> name fails.
354 ****************************************************************************/
355 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
356 struct response_record *rrec,
357 struct nmb_name *question_name, int fail_code)
359 if( DEBUGLVL( 0 ) )
361 dbgtext( "find_domain_master_name_query_fail:\n" );
362 dbgtext( "Unable to find the Domain Master Browser name " );
363 dbgtext( "%s for the workgroup %s.\n",
364 nmb_namestr(question_name), question_name->name );
365 dbgtext( "Unable to sync browse lists in this workgroup.\n" );
369 /****************************************************************************
370 As a local master browser for a workgroup find the domain master browser
371 name, announce ourselves as local master browser to it and then pull the
372 full domain browse lists from it onto the given subnet.
373 **************************************************************************/
375 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
376 struct work_record *work)
378 struct nmb_name nmbname;
380 /* Only do this if we are using a WINS server. */
381 if(we_are_a_wins_client() == False)
383 if( DEBUGLVL( 10 ) )
385 dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
386 dbgtext( "Ignoring, as we are not a WINS client.\n" );
388 return;
391 make_nmb_name(&nmbname,work->work_group,0x1b);
393 /* First, query for the WORKGROUP<1b> name from the WINS server. */
394 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
395 find_domain_master_name_query_success,
396 find_domain_master_name_query_fail,
397 NULL);
401 /****************************************************************************
402 Function called when a node status query to a domain master browser IP succeeds.
403 This function is only called on query to a Samba 1.9.18 or above WINS server.
405 Note that adding the workgroup name is enough for this workgroup to be
406 browsable by clients, as clients query the WINS server or broadcast
407 nets for the WORKGROUP<1b> name when they want to browse a workgroup
408 they are not in. We do not need to do a sync with this Domain Master
409 Browser in order for our browse clients to see machines in this workgroup.
410 JRA.
411 ****************************************************************************/
413 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
414 struct userdata_struct *userdata,
415 struct res_rec *answers,
416 struct in_addr from_ip)
418 struct work_record *work;
419 fstring server_name;
421 server_name[0] = 0;
423 if( DEBUGLVL( 3 ) )
425 dbgtext( "get_domain_master_name_node_status_success:\n" );
426 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
430 * Go through the list of names found at answers->rdata and look for
431 * the first WORKGROUP<0x1b> name.
434 if(answers->rdata != NULL)
436 char *p = answers->rdata;
437 int numnames = CVAL(p, 0);
439 p += 1;
441 while (numnames--)
443 char qname[17];
444 uint16 nb_flags;
445 int name_type;
447 StrnCpy(qname,p,15);
448 name_type = CVAL(p,15);
449 nb_flags = get_nb_flags(&p[16]);
450 trim_string(qname,NULL," ");
452 p += 18;
454 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
455 server_name[0] == 0) {
456 /* this is almost certainly the server netbios name */
457 fstrcpy(server_name, qname);
458 continue;
461 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
463 if( DEBUGLVL( 5 ) )
465 dbgtext( "get_domain_master_name_node_status_success:\n" );
466 dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
467 dbgtext( "is a domain master browser for workgroup " );
468 dbgtext( "%s. Adding this name.\n", qname );
472 * If we don't already know about this workgroup, add it
473 * to the workgroup list on the unicast_subnet.
475 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
477 struct nmb_name nmbname;
479 * Add it - with an hour in the cache.
481 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
482 return;
484 /* remember who the master is */
485 fstrcpy(work->local_master_browser_name, server_name);
486 make_nmb_name(&nmbname, server_name, 0x20);
487 work->dmb_name = nmbname;
488 work->dmb_addr = from_ip;
490 break;
494 else
495 if( DEBUGLVL( 0 ) )
497 dbgtext( "get_domain_master_name_node_status_success:\n" );
498 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
499 dbgtext( "%s.\n", inet_ntoa(from_ip) );
503 /****************************************************************************
504 Function called when a node status query to a domain master browser IP fails.
505 ****************************************************************************/
507 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
508 struct response_record *rrec)
510 if( DEBUGLVL( 0 ) )
512 dbgtext( "get_domain_master_name_node_status_fail:\n" );
513 dbgtext( "Doing a node status request to the domain master browser " );
514 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
515 dbgtext( "Cannot get workgroup name.\n" );
519 /****************************************************************************
520 Function called when a query for *<1b> name succeeds.
521 ****************************************************************************/
523 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
524 struct userdata_struct *userdata_in,
525 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
528 * We now have a list of all the domain master browsers for all workgroups
529 * that have registered with the WINS server. Now do a node status request
530 * to each one and look for the first 1b name in the reply. This will be
531 * the workgroup name that we will add to the unicast subnet as a 'non-local'
532 * workgroup.
535 struct nmb_name nmbname;
536 struct in_addr send_ip;
537 int i;
539 if( DEBUGLVL( 5 ) )
541 dbgtext( "find_all_domain_master_names_query_succes:\n" );
542 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
543 dbgtext( "IP addresses for Domain Master Browsers.\n" );
546 for(i = 0; i < rrec->rdlength / 6; i++)
548 /* Initiate the node status requests. */
549 make_nmb_name(&nmbname, "*", 0);
551 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
554 * Don't send node status requests to ourself.
557 if(ismyip( send_ip ))
559 if( DEBUGLVL( 5 ) )
561 dbgtext( "find_all_domain_master_names_query_succes:\n" );
562 dbgtext( "Not sending node status to our own IP " );
563 dbgtext( "%s.\n", inet_ntoa(send_ip) );
565 continue;
568 if( DEBUGLVL( 5 ) )
570 dbgtext( "find_all_domain_master_names_query_success:\n" );
571 dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
574 node_status( subrec, &nmbname, send_ip,
575 get_domain_master_name_node_status_success,
576 get_domain_master_name_node_status_fail,
577 NULL);
581 /****************************************************************************
582 Function called when a query for *<1b> name fails.
583 ****************************************************************************/
584 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
585 struct response_record *rrec,
586 struct nmb_name *question_name, int fail_code)
588 if( DEBUGLVL( 10 ) )
590 dbgtext( "find_domain_master_name_query_fail:\n" );
591 dbgtext( "WINS server did not reply to a query for name " );
592 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
593 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
597 /****************************************************************************
598 If we are a domain master browser on the unicast subnet, do a query to the
599 WINS server for the *<1b> name. This will only work to a Samba WINS server,
600 so ignore it if we fail. If we succeed, contact each of the IP addresses in
601 turn and do a node status request to them. If this succeeds then look for a
602 <1b> name in the reply - this is the workgroup name. Add this to the unicast
603 subnet. This is expensive, so we only do this every 15 minutes.
604 **************************************************************************/
605 void collect_all_workgroup_names_from_wins_server(time_t t)
607 static time_t lastrun = 0;
608 struct work_record *work;
609 struct nmb_name nmbname;
611 /* Only do this if we are using a WINS server. */
612 if(we_are_a_wins_client() == False)
613 return;
615 /* Check to see if we are a domain master browser on the unicast subnet. */
616 if((work = find_workgroup_on_subnet( unicast_subnet, global_myworkgroup)) == NULL)
618 if( DEBUGLVL( 0 ) )
620 dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
621 dbgtext( "Cannot find my workgroup %s ", global_myworkgroup );
622 dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
624 return;
627 if(!AM_DOMAIN_MASTER_BROWSER(work))
628 return;
630 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
631 return;
633 lastrun = t;
635 make_nmb_name(&nmbname,"*",0x1b);
637 /* First, query for the *<1b> name from the WINS server. */
638 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
639 find_all_domain_master_names_query_success,
640 find_all_domain_master_names_query_fail,
641 NULL);
645 /****************************************************************************
646 If we are a domain master browser on the unicast subnet, do a regular sync
647 with all other DMBs that we know of on that subnet.
649 To prevent exponential network traffic with large numbers of workgroups
650 we use a randomised system where sync probability is inversely proportional
651 to the number of known workgroups
652 **************************************************************************/
653 void sync_all_dmbs(time_t t)
655 static time_t lastrun = 0;
656 struct work_record *work;
657 int count=0;
659 /* Only do this if we are using a WINS server. */
660 if(we_are_a_wins_client() == False)
661 return;
663 /* Check to see if we are a domain master browser on the
664 unicast subnet. */
665 work = find_workgroup_on_subnet(unicast_subnet, global_myworkgroup);
666 if (!work) return;
668 if (!AM_DOMAIN_MASTER_BROWSER(work))
669 return;
671 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
672 return;
674 /* count how many syncs we might need to do */
675 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
676 if (strcmp(global_myworkgroup, work->work_group)) {
677 count++;
681 /* sync with a probability of 1/count */
682 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
683 if (strcmp(global_myworkgroup, work->work_group)) {
684 if (((unsigned)sys_random()) % count != 0) continue;
686 lastrun = t;
688 if (!work->dmb_name.name[0]) {
689 /* we don't know the DMB - assume it is
690 the same as the unicast local master */
691 make_nmb_name(&work->dmb_name,
692 work->local_master_browser_name,
693 0x20);
696 DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
697 work->dmb_name.name,
698 inet_ntoa(work->dmb_addr)));
699 sync_browse_lists(work,
700 work->dmb_name.name,
701 work->dmb_name.name_type,
702 work->dmb_addr, False, False);