- a huge pile of changes from Luke which implement the browse.conf
[ira/wip.git] / source / namework.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-1996
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21    Revision History:
22
23    14 jan 96: lkcl@pires.co.uk
24    added multiple workgroup domain master support
25
26    30 July 96: David.Chappell@mail.trincoll.edu
27    Expanded multiple workgroup domain master browser support.
28
29 */
30
31 #include "includes.h"
32
33 extern int ClientNMB;
34 extern int ClientDGRAM;
35
36 extern int DEBUGLEVEL;
37 extern pstring scope;
38 extern BOOL CanRecurse;
39
40 extern int ClientNMB;
41 extern int ClientDGRAM;
42
43 extern struct in_addr ipzero;
44
45 /* this is our domain/workgroup/server database */
46 extern struct subnet_record *subnetlist;
47
48 extern int  updatecount;
49
50 extern time_t StartupTime;
51
52 extern BOOL updatedlists;
53
54 extern pstring myname;
55
56
57 /****************************************************************************
58 tell a server to become a backup browser
59 state - 0x01 become backup instead of master
60       - 0x02 remove all entries in browse list and become non-master
61       - 0x04 stop master browser service altogether. NT ignores this 
62 **************************************************************************/
63 void reset_server(struct work_record *work, char *name, int state, struct in_addr ip)
64 {
65   char outbuf[20];
66   char *p;
67
68   bzero(outbuf,sizeof(outbuf));
69   p = outbuf;
70
71   CVAL(p,0) = ANN_ResetBrowserState;
72   CVAL(p,2) = state; 
73   p += 2;
74
75   DEBUG(2,("sending reset to %s %s of state %d\n",
76        name,inet_ntoa(ip),state));
77
78   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
79               conf_browsing_alias(work->token),name,0x20,0x1d,ip,*iface_ip(ip));
80 }
81
82
83 /****************************************************************************
84 tell a server to become a backup browser
85 **************************************************************************/
86 void tell_become_backup(void)
87 {
88   /* XXXX note: this function is currently unsuitable for use, as it
89      does not properly check that a server is in a fit state to become
90      a backup browser before asking it to be one.
91    */
92
93   struct subnet_record *d;
94   for (d = subnetlist; d; d = d->next)
95     {
96       struct work_record *work;
97       for (work = d->workgrouplist; work; work = work->next)
98     {
99       struct server_record *s;
100       int num_servers = 0;
101       int num_backups = 0;
102       
103       for (s = work->serverlist; s; s = s->next)
104         {
105           if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
106           
107           num_servers++;
108           
109           if (strequal(conf_browsing_alias(work->token), s->serv.name)) continue;
110           
111           if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
112         num_backups++;
113         continue;
114           }
115           
116           if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
117           
118           if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
119           
120           DEBUG(3,("num servers: %d num backups: %d\n", 
121                num_servers, num_backups));
122           
123           /* make first server a backup server. thereafter make every
124          tenth server a backup server */
125           if (num_backups != 0 && (num_servers+9) / num_backups > 10)
126         {
127           continue;
128         }
129           
130           DEBUG(2,("sending become backup to %s %s for %s\n",
131                s->serv.name, inet_ntoa(d->bcast_ip),
132                work->work_group));
133           
134           /* type 11 request from conf_browsing_alias(work->token)(20) to WG(1e) for SERVER */
135           do_announce_request(s->serv.name, s->serv.name, work->work_group,
136                   ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
137         }
138     }
139     }
140 }
141
142
143 /*******************************************************************
144   same context: scope. should check name_type as well, and makes sure
145   we don't process messages from ourselves
146   ******************************************************************/
147 BOOL same_context(struct dgram_packet *dgram)
148 {
149   if (!strequal(dgram->dest_name  .scope,scope )) return True;
150   
151   return False;
152 }
153
154
155 /*******************************************************************
156   am I listening on a name. XXXX check the type of name as well.
157   ******************************************************************/
158 BOOL listening_name(struct work_record *work, struct nmb_name *n)
159 {
160   if (strequal(n->name,conf_browsing_alias(work->token)) ||
161       strequal(n->name,work->work_group) ||
162       strequal(n->name,MSBROWSE))
163     {
164       return(True);
165     }
166   
167   return(False);
168 }
169
170
171 /*******************************************************************
172   process a domain announcement frame
173
174   Announce frames come in 3 types. Servers send host announcements
175   (command=1) to let the master browswer know they are
176   available. Master browsers send local master announcements
177   (command=15) to let other masters and backups that they are the
178   master. They also send domain announcements (command=12) to register
179   the domain
180
181   The comment field of domain announcements contains the master
182   browser name. The servertype is used by NetServerEnum to select
183   resources. We just have to pass it to smbd (via browser.dat) and let
184   the client choose using bit masks.
185   ******************************************************************/
186 static void process_announce(struct packet_struct *p,uint16 command,char *buf)
187 {
188   struct dgram_packet *dgram = &p->packet.dgram;
189   struct in_addr ip = dgram->header.source_ip;
190   struct subnet_record *d = find_subnet(ip); 
191   int update_count = CVAL(buf,0);
192
193   int ttl = IVAL(buf,1)/1000;
194   char *name = buf+5;
195   int osmajor=CVAL(buf,21);
196   int osminor=CVAL(buf,22);
197   uint32 servertype = IVAL(buf,23);
198   uint32 browse_type= CVAL(buf,27);
199   uint32 browse_sig = CVAL(buf,29);
200   char *comment = buf+31;
201
202   struct work_record *work;
203   char *work_name;
204   char *serv_name = dgram->source_name.name;
205   BOOL add = False;
206
207   comment[43] = 0;
208   
209   DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
210   DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
211        namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
212        servertype,browse_type,browse_sig,comment));
213   
214   name[15] = 0;  
215   
216   if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
217     {
218       DEBUG(2,("Announce to nametype(0) not supported yet\n"));
219       return;
220     }
221
222   if (command == ANN_DomainAnnouncement && 
223       ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
224        dgram->dest_name.name_type != 0x1))
225     {
226       DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
227         command, inet_ntoa(ip), namestr(&dgram->dest_name)));
228       return;
229     }
230   
231   if (!strequal(dgram->dest_name.scope,scope )) return;
232   
233   if (command == ANN_DomainAnnouncement) { 
234     /* XXXX if we are a master browser for the workgroup work_name,
235        then there is a local subnet configuration problem. only
236        we should be sending out such domain announcements, because
237        as the master browser, that is our job.
238
239        stop being a master browser, and force an election. this will
240        sort out the network problem. hopefully.
241      */
242
243     work_name = name;
244     add = True;
245   } else {
246     work_name = dgram->dest_name.name;
247   }
248
249   /* we need some way of finding out about new workgroups
250      that appear to be sending packets to us. The name_type checks make
251      sure we don't add host names as workgroups */
252   if (command == ANN_HostAnnouncement &&
253       (dgram->dest_name.name_type == 0x1d ||
254        dgram->dest_name.name_type == 0x1e))
255     add = True;
256   
257   if (!(work = find_workgroupstruct(d, work_name,add)))
258     return;
259   
260   DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
261   
262   ttl = GET_TTL(ttl);
263   
264   /* add them to our browse list, and update the browse.dat file */
265   add_server_entry(d,work,name,servertype,ttl,comment,True);
266   updatedlists = True;
267
268 #if 0
269   /* the tell become backup code is broken, no great harm is done by
270      disabling it */
271   tell_become_backup();
272 #endif
273
274   /* get the local_only browse list from the local master and add it 
275      to ours. */
276   if (command == ANN_LocalMasterAnnouncement)
277   {
278     add_browser_entry(serv_name,dgram->dest_name.name_type,
279               work->work_group,30,ip,True);
280   }
281 }
282
283 /*******************************************************************
284   process a master announcement frame
285   ******************************************************************/
286 static void process_master_announce(struct packet_struct *p,char *buf)
287 {
288   struct dgram_packet *dgram = &p->packet.dgram;
289   struct in_addr ip = dgram->header.source_ip;
290   struct subnet_record *d = find_subnet(ip);
291   struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
292   char *to_name = dgram->dest_name.name; /* our primary name or an alias */
293
294   char *name = buf;
295   char *work_name; 
296   int token;
297   name[15] = 0;
298   
299   DEBUG(3,("Master Announce from %s (%s)\n", name, inet_ntoa(ip)));
300   
301   if (same_context(dgram)) return;
302   
303   if (!d || !mydomain) return;
304   
305   token = conf_alias_to_token(to_name);
306
307   if (token == -1)
308   {
309     DEBUG(4, ("alias %s not known\n", to_name));
310     return;
311   }
312
313   /* carry on only if we are a domain master under the server alias */
314   if (!conf_should_domain_master(token)) return;
315
316   /* Convert the server name by which the master browser
317      called this server to the workgroup name. */
318   if ((work_name = conf_workgroup_name(token)) == (char*)NULL)
319   {
320       DEBUG(4, ("process_master_announce(): no alias for \"%s\"\n", to_name));
321       return;
322   }          
323   
324   /* merge browse lists with them */
325   add_browser_entry(name, 0x1b, work_name,30,ip,True);
326 }
327
328 /*******************************************************************
329   process a receive backup list request
330   
331   we receive a list of servers, and we attempt to locate them all on
332   our local subnet, and sync browse lists with them on the workgroup
333   they are said to be in.
334
335   XXXX NOTE: this function is in overdrive. it should not really do
336   half of what it actually does (it should pick _one_ name from the
337   list received and sync with it at regular intervals, rather than
338   sync with them all only once!)
339
340   ******************************************************************/
341 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
342 {
343   struct dgram_packet *dgram = &p->packet.dgram;
344   struct in_addr ip = dgram->header.source_ip;
345   int count = CVAL(buf,0);
346   unsigned int pick;
347   uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
348   char *buf1;
349   
350   DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
351        namestr(&dgram->dest_name), inet_ntoa(ip),
352        count, info));
353   
354   if (same_context(dgram)) return;
355   
356   if (count <= 0) return;
357   
358   pick = sys_random(count);
359
360   /* go through the list of servers attempting to sync browse lists */
361   for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
362   {
363     struct subnet_record *d;
364       
365     if (count != pick) continue;
366
367     DEBUG(4,("Searching for backup browser %s...\n", buf1));
368       
369     if ((d = find_subnet(ip)) != NULL)
370     {
371       struct work_record *work;
372       for (work = d->workgrouplist; work; work = work->next)
373       {
374         if (work->token == 0 /* token */)
375         {
376           queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
377                        work->token,work->work_group,0x1d,
378                        0,0,0,0,NULL,NULL,
379                        False,False,ipzero,ipzero);
380           return;
381         }
382       }
383     }
384   }
385 }
386
387
388 /****************************************************************************
389   send a backup list response.
390   **************************************************************************/
391 static void send_backup_list(struct work_record *work, struct nmb_name *src_name,
392                  int token, uint32 info,
393                  int name_type, struct in_addr ip)
394 {                     
395   char outbuf[1024];
396   char *p, *countptr, *nameptr;
397   int count = 0;
398   char *theirname = src_name->name;
399   
400   DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", 
401        work->work_group, inet_ntoa(ip),
402        conf_browsing_alias(work->token),0x0,theirname,0x0));     
403   
404   if (name_type == 0x1d)
405     {
406       DEBUG(4,("master browsers: "));
407     }
408   else if (name_type == 0x1b)
409     {
410       DEBUG(4,("domain controllers: "));
411     }
412   else
413     {
414       DEBUG(0,("backup request for unknown type %0x\n", name_type));
415       return;
416     }
417   
418   bzero(outbuf,sizeof(outbuf));
419   p = outbuf;
420   
421   CVAL(p,0) = ANN_GetBackupListResp;    /* backup list response */
422   
423   p++;
424   countptr = p;
425
426   SIVAL(p,1,info); /* the sender's unique info */
427
428   p += 5;
429   
430   nameptr = p;
431
432 #if 0
433
434   struct server_record *s;
435       
436   for (s = work->serverlist; s; s = s->next)
437   { 
438       BOOL found = False;
439       char *n;
440           
441       if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
442           
443     for (n = nameptr; n < p; n = skip_string(n, 1))
444     {
445       if (strequal(n, s->serv.name)) found = True;
446     }
447           
448     if (found) continue; /* exclude names already added */
449           
450       /* workgroup request: include all backup browsers in the list */
451       /* domain request: include all domain members in the list */
452
453     if ((name_type == 0x1d && (s->serv.type & SV_TYPE_MASTER_BROWSER)) ||
454         (name_type == 0x1b && (s->serv.type & SV_TYPE_DOMAIN_BROWSER)))
455     {                          
456       DEBUG(4, ("%s ", s->serv.name));
457           
458       count++;
459       strcpy(p,s->serv.name);
460       strupper(p);
461       p = skip_string(p,1);
462     }
463   }
464 #endif
465
466     count++;
467     strcpy(p,conf_browsing_alias(work->token));
468     strupper(p);
469     p = skip_string(p,1);
470
471   if (count == 0)
472   {
473       DEBUG(4, ("none\n"));
474   }
475   else
476   {
477       DEBUG(4, (" - count %d\n", count));
478   }
479   
480   CVAL(countptr, 0) = count;
481
482   {
483     int len = PTR_DIFF(p, outbuf);
484     debug_browse_data(outbuf, len);
485   }
486   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
487               conf_browsing_alias(work->token),theirname,0x0,0x0,ip,*iface_ip(ip));
488 }
489
490
491 /*******************************************************************
492   process a send backup list request
493
494   A client sends a backup list request to ask for a list of servers on
495   the net that maintain server lists for a domain. A server is then
496   chosen from this list to send NetServerEnum commands to to list
497   available servers.
498
499   Currently samba only sends back one name in the backup list, its
500   own. For larger nets we'll have to add backups and send "become
501   backup" requests occasionally.
502   ******************************************************************/
503 static void process_send_backup_list(struct packet_struct *p,char *buf)
504 {
505   struct dgram_packet *dgram = &p->packet.dgram;
506   struct in_addr ip = dgram->header.source_ip;
507   struct subnet_record *d;
508   struct work_record *work;
509
510   int    token = CVAL(buf,0); /* sender's key index for the workgroup */
511   uint32 info  = IVAL(buf,1); /* XXXX don't know: some sort of info */
512   int name_type = dgram->dest_name.name_type;
513
514   if (same_context(dgram)) return;
515   
516   if (name_type != 0x1b && name_type != 0x1d) {
517     DEBUG(0,("backup request to wrong type %d from %s\n",
518           name_type,inet_ntoa(ip)));
519     return;
520   }
521   
522   for (d = subnetlist; d; d = d->next)
523     {
524       for (work = d->workgrouplist; work; work = work->next)
525     {
526       if (strequal(work->work_group, dgram->dest_name.name))
527         {
528           DEBUG(2,("sending backup list to %s %s id=%x\n",
529                namestr(&dgram->dest_name),inet_ntoa(ip),info));
530   
531           send_backup_list(work,&dgram->source_name,
532                    token,info,name_type,ip);
533           return;
534         }
535     } 
536     }
537 }
538
539
540 /*******************************************************************
541   process a reset browser state
542
543   diagnostic packet:
544   0x1 - stop being a master browser and become a backup browser.
545   0x2 - discard browse lists, stop being a master browser, try again.
546   0x4 - stop being a master browser forever. no way. ain't gonna.
547          
548   ******************************************************************/
549 static void process_reset_browser(struct packet_struct *p,char *buf)
550 {
551   struct dgram_packet *dgram = &p->packet.dgram;
552   int state = CVAL(buf,0);
553
554   DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
555        namestr(&dgram->dest_name), state));
556
557   /* stop being a master but still deal with being a backup browser */
558   if (state & 0x1)
559     {
560       struct subnet_record *d;
561       for (d = subnetlist; d; d = d->next)
562     {
563       struct work_record *work;
564       for (work = d->workgrouplist; work; work = work->next)
565         {
566           if (AM_MASTER(work))
567         {
568           become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
569         }
570         }
571     }
572     }
573   
574   /* XXXX documentation inconsistency: the above description does not
575      exactly tally with what is implemented for state & 0x2
576    */
577
578   /* totally delete all servers and start afresh */
579   if (state & 0x2)
580   {
581     /* remove all workgroups (and their servers) from database */
582     struct subnet_record *d;
583     for (d = subnetlist; d; d = d->next)
584     {
585       struct work_record *work;
586       for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
587     }
588
589     /* add all known workgroups back into database */
590     add_workgroups_to_subnets();
591   }
592   
593   /* stop browsing altogether. i don't think this is a good idea! */
594   if (state & 0x4)
595   {
596       DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
597   }
598 }
599
600 /*******************************************************************
601   process a announcement request
602
603   clients send these when they want everyone to send an announcement
604   immediately. This can cause quite a storm of packets!
605   ******************************************************************/
606 static void process_announce_request(struct packet_struct *p,char *buf)
607 {
608   struct dgram_packet *dgram = &p->packet.dgram;
609   struct work_record *work;
610   struct in_addr ip = dgram->header.source_ip;
611   struct subnet_record *d = find_subnet(ip);
612   int token = CVAL(buf,0);
613   int wg_token = 0;
614   char *name = buf+1;
615   char *samba_alias;
616
617   name[15] = 0;
618   
619   DEBUG(3,("Announce request from %s to %s token=0x%X\n",
620        name,namestr(&dgram->dest_name), token));
621   
622   /* look up the index for this workgroup */
623   wg_token = conf_workgroup_name_to_token(dgram->dest_name.name,myname);
624   if (wg_token == -1) return;
625
626   /* check that samba is participating in this workgroup */
627   if (!conf_should_workgroup_member(wg_token)) return;
628
629   /* find samba's NetBIOS alias it operates under in this workgroup */
630   if ((samba_alias = conf_browsing_alias(wg_token)) == (char*)NULL) return;
631
632   /* ignore announce requests from samba under its own alias.
633      this should no longer happen because code has been added to
634      discard packets from ourself. */
635   if (strequal(dgram->source_name.name,samba_alias)) return;
636   
637   if (!d) return;
638   
639   /* XXXX BUG: the destination name type should also be checked,
640      not just the name. e.g if the name is WORKGROUP(0x1d) then
641      we should only respond if we own that name */
642     
643   for (work = d->workgrouplist; work; work = work->next)
644   {
645     if (wg_token == work->token) work->needannounce = True;
646   }
647 }
648
649
650 /****************************************************************************
651 process a browse frame
652 ****************************************************************************/
653 void process_browse_packet(struct packet_struct *p,char *buf,int len)
654 {
655   int command = CVAL(buf,0);
656   switch (command) 
657     {
658     case ANN_HostAnnouncement:
659     case ANN_DomainAnnouncement:
660     case ANN_LocalMasterAnnouncement:
661       {
662         debug_browse_data(buf, len);
663     process_announce(p,command,buf+1);
664     break;
665       }
666       
667     case ANN_AnnouncementRequest:
668       {
669     process_announce_request(p,buf+1);
670     break;
671       }
672       
673     case ANN_Election:
674       {
675     process_election(p,buf+1);
676     break;
677       }
678       
679     case ANN_GetBackupListReq:
680       {
681         debug_browse_data(buf, len);
682     process_send_backup_list(p,buf+1);
683     break;
684       }
685       
686     case ANN_GetBackupListResp:
687     {
688         debug_browse_data(buf, len);
689         process_rcv_backup_list(p, buf+1);
690         break;
691     }
692       
693     case ANN_ResetBrowserState:
694       {
695     process_reset_browser(p, buf+1);
696     break;
697       }
698       
699     case ANN_MasterAnnouncement:
700       {
701     process_master_announce(p,buf+1);
702     break;
703       }
704       
705     default:
706       {
707     struct dgram_packet *dgram = &p->packet.dgram;
708     DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
709          command, namestr(&dgram->source_name), 
710          inet_ntoa(p->ip), namestr(&dgram->dest_name)));
711       }
712     }
713 }
714
715