add DEBUGLEVEL to replace.c
[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 #if 0
356       /* XXXX function needs work */
357       continue;
358
359     if ((d = find_subnet(back_ip)))
360         {
361           struct subnet_record *d1;
362           for (d1 = subnetlist; d1; d1 = d1->next)
363           {
364               struct work_record *work;
365               for (work = d1->workgrouplist; work; work = work->next)
366                 {
367                   if (work->token == 0 /* token */)
368                   {
369                       queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
370                                            work->work_group,0x1d,
371                        0,0,0,NULL,NULL,
372                                            False,False,back_ip,back_ip);
373                       return;
374                   }
375                 }
376           }
377         }
378 #endif
379   }
380 }
381
382
383 /****************************************************************************
384   send a backup list response.
385   **************************************************************************/
386 static void send_backup_list(char *work_name, struct nmb_name *src_name,
387                              int token, uint32 info,
388                              int name_type, struct in_addr ip)
389 {                     
390   char outbuf[1024];
391   char *p, *countptr, *nameptr;
392   int count = 0;
393   char *theirname = src_name->name;
394   
395   DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", 
396            work_name, inet_ntoa(ip),
397            myname,0x0,theirname,0x0));     
398   
399   if (name_type == 0x1d)
400     {
401       DEBUG(4,("master browsers: "));
402     }
403   else if (name_type == 0x1b)
404     {
405       DEBUG(4,("domain controllers: "));
406     }
407   else
408     {
409       DEBUG(0,("backup request for unknown type %0x\n", name_type));
410       return;
411     }
412   
413   bzero(outbuf,sizeof(outbuf));
414   p = outbuf;
415   
416   CVAL(p,0) = ANN_GetBackupListResp;    /* backup list response */
417   
418   p++;
419   countptr = p;
420
421   SIVAL(p,1,info); /* the sender's unique info */
422
423   p += 5;
424   
425   nameptr = p;
426
427 #if 0
428
429   for (d = subnetlist; d; d = d->next)
430   {
431       struct work_record *work;
432       
433       for (work = d->workgrouplist; work; work = work->next)
434         {
435           struct server_record *s;
436           
437           if (!strequal(work->work_group, work_name)) continue;
438           
439           for (s = work->serverlist; s; s = s->next)
440             { 
441               BOOL found = False;
442               char *n;
443               
444               if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
445               
446               for (n = nameptr; n < p; n = skip_string(n, 1))
447                 {
448                   if (strequal(n, s->serv.name)) found = True;
449                 }
450               
451               if (found) continue; /* exclude names already added */
452               
453               /* workgroup request: include all backup browsers in the list */
454               /* domain request: include all domain members in the list */
455
456               if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
457                       (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
458                 {                          
459                   DEBUG(4, ("%s ", s->serv.name));
460                   
461                   count++;
462                   strcpy(p,s->serv.name);
463                   strupper(p);
464                   p = skip_string(p,1);
465                 }
466          }
467         }
468   }
469
470 #endif
471
472         count++;
473         strcpy(p,myname);
474         strupper(p);
475         p = skip_string(p,1);
476
477   if (count == 0)
478     {
479       DEBUG(4, ("none\n"));
480     }
481   else
482     {
483       DEBUG(4, (" - count %d\n", count));
484     }
485   
486   CVAL(countptr, 0) = count;
487
488   {
489     int len = PTR_DIFF(p, outbuf);
490     debug_browse_data(outbuf, len);
491   }
492   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
493                       myname,theirname,0x0,0x0,ip,*iface_ip(ip));
494 }
495
496
497 /*******************************************************************
498   process a send backup list request
499
500   A client sends a backup list request to ask for a list of servers on
501   the net that maintain server lists for a domain. A server is then
502   chosen from this list to send NetServerEnum commands to to list
503   available servers.
504
505   Currently samba only sends back one name in the backup list, its
506   own. For larger nets we'll have to add backups and send "become
507   backup" requests occasionally.
508   ******************************************************************/
509 static void process_send_backup_list(struct packet_struct *p,char *buf)
510 {
511   struct dgram_packet *dgram = &p->packet.dgram;
512   struct in_addr ip = dgram->header.source_ip;
513   struct subnet_record *d;
514   struct work_record *work;
515
516   int    token = CVAL(buf,0); /* sender's key index for the workgroup */
517   uint32 info  = IVAL(buf,1); /* XXXX don't know: some sort of info */
518   int name_type = dgram->dest_name.name_type;
519
520   if (same_context(dgram)) return;
521   
522   if (name_type != 0x1b && name_type != 0x1d) {
523     DEBUG(0,("backup request to wrong type %d from %s\n",
524               name_type,inet_ntoa(ip)));
525     return;
526   }
527   
528   for (d = subnetlist; d; d = d->next)
529     {
530       for (work = d->workgrouplist; work; work = work->next)
531         {
532           if (strequal(work->work_group, dgram->dest_name.name))
533             {
534               DEBUG(2,("sending backup list to %s %s id=%x\n",
535                        namestr(&dgram->dest_name),inet_ntoa(ip),info));
536   
537               send_backup_list(work->work_group,&dgram->source_name,
538                                token,info,name_type,ip);
539               return;
540             }
541         } 
542     }
543 }
544
545
546 /*******************************************************************
547   process a reset browser state
548
549   diagnostic packet:
550   0x1 - stop being a master browser and become a backup browser.
551   0x2 - discard browse lists, stop being a master browser, try again.
552   0x4 - stop being a master browser forever. no way. ain't gonna.
553          
554   ******************************************************************/
555 static void process_reset_browser(struct packet_struct *p,char *buf)
556 {
557   struct dgram_packet *dgram = &p->packet.dgram;
558   int state = CVAL(buf,0);
559
560   DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
561            namestr(&dgram->dest_name), state));
562
563   /* stop being a master but still deal with being a backup browser */
564   if (state & 0x1)
565     {
566       struct subnet_record *d;
567       for (d = subnetlist; d; d = d->next)
568         {
569           struct work_record *work;
570           for (work = d->workgrouplist; work; work = work->next)
571             {
572               if (AM_MASTER(work))
573                 {
574                   become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
575                 }
576             }
577         }
578     }
579   
580   /* XXXX documentation inconsistency: the above description does not
581      exactly tally with what is implemented for state & 0x2
582    */
583
584   /* totally delete all servers and start afresh */
585   if (state & 0x2)
586     {
587       struct subnet_record *d;
588       for (d = subnetlist; d; d = d->next)
589         {
590           struct work_record *work;
591           for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
592         }
593       add_my_subnets(lp_workgroup());
594     }
595   
596   /* stop browsing altogether. i don't think this is a good idea! */
597   if (state & 0x4)
598     {
599       DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
600     }
601 }
602
603 /*******************************************************************
604   process a announcement request
605
606   clients send these when they want everyone to send an announcement
607   immediately. This can cause quite a storm of packets!
608   ******************************************************************/
609 static void process_announce_request(struct packet_struct *p,char *buf)
610 {
611   struct dgram_packet *dgram = &p->packet.dgram;
612   struct work_record *work;
613   struct in_addr ip = dgram->header.source_ip;
614   struct subnet_record *d = find_subnet(ip);
615   int token = CVAL(buf,0);
616   char *name = buf+1;
617   
618   name[15] = 0;
619   
620   DEBUG(3,("Announce request from %s to %s token=0x%X\n",
621            name,namestr(&dgram->dest_name), token));
622   
623   if (strequal(dgram->source_name.name,myname)) return;
624   
625   /* XXXX BUG or FEATURE?: need to ensure that we are a member of
626      this workgroup before announcing, particularly as we only
627      respond on local interfaces anyway.
628
629      if (strequal(dgram->dest_name, lp_workgroup()) return; ???
630    */
631
632   if (!d) return;
633   
634   for (work = d->workgrouplist; work; work = work->next)
635     {
636      /* XXXX BUG: the destination name type should also be checked,
637         not just the name. e.g if the name is WORKGROUP(0x1d) then
638         we should only respond if we own that name */
639     
640       if (strequal(dgram->dest_name.name,work->work_group)) 
641         {
642           work->needannounce = True;
643         }
644     }
645 }
646
647
648
649 /****************************************************************************
650 process a browse frame
651 ****************************************************************************/
652 void process_browse_packet(struct packet_struct *p,char *buf,int len)
653 {
654   int command = CVAL(buf,0);
655   switch (command) 
656     {
657     case ANN_HostAnnouncement:
658     case ANN_DomainAnnouncement:
659     case ANN_LocalMasterAnnouncement:
660       {
661         debug_browse_data(buf, len);
662         process_announce(p,command,buf+1);
663         break;
664       }
665       
666     case ANN_AnnouncementRequest:
667       {
668         process_announce_request(p,buf+1);
669         break;
670       }
671       
672     case ANN_Election:
673       {
674         process_election(p,buf+1);
675         break;
676       }
677       
678     case ANN_GetBackupListReq:
679       {
680         debug_browse_data(buf, len);
681         process_send_backup_list(p,buf+1);
682         break;
683       }
684       
685     case ANN_GetBackupListResp:
686     {
687         debug_browse_data(buf, len);
688         process_rcv_backup_list(p, buf+1);
689         break;
690     }
691       
692     case ANN_ResetBrowserState:
693       {
694         process_reset_browser(p, buf+1);
695         break;
696       }
697       
698     case ANN_MasterAnnouncement:
699       {
700         process_master_announce(p,buf+1);
701         break;
702       }
703       
704     default:
705       {
706         struct dgram_packet *dgram = &p->packet.dgram;
707         DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
708                  command, namestr(&dgram->source_name), 
709                  inet_ntoa(p->ip), namestr(&dgram->dest_name)));
710       }
711     }
712 }
713
714