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