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