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