This is it ! The mega-merge of the JRA_NMBD_REWRITE branch
[jerry/samba.git] / source / nmbd / nmbd_incomingdgrams.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    Copyright (C) Luke Kenneth Casson Leighton 1994-1997 
7    Copyright (C) Jeremy Allison 1994-1997
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23 */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
29 extern pstring myname;
30 extern fstring myworkgroup;
31
32 #if 0
33
34 /* XXXX note: This function is currently unsuitable for use, as it
35    does not properly check that a server is in a fit state to become
36    a backup browser before asking it to be one.
37    The code is left here to be worked on at a later date.
38 */
39
40 /****************************************************************************
41 Tell a server to become a backup browser
42 **************************************************************************/
43
44 void tell_become_backup(void)
45 {
46   struct subnet_record *subrec;
47   for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec))
48   {
49     struct work_record *work;
50     for (work = subrec->workgrouplist; work; work = work->next)
51     {
52       struct server_record *servrec;
53       int num_servers = 0;
54       int num_backups = 0;
55           
56       for (servrec = work->serverlist; servrec; servrec = servrec->next)
57       {
58         num_servers++;
59               
60         if (is_myname(servrec->serv.name))
61           continue;
62               
63         if (servrec->serv.type & SV_TYPE_BACKUP_BROWSER) 
64         {
65           num_backups++;
66           continue;
67         }
68               
69         if (servrec->serv.type & SV_TYPE_MASTER_BROWSER)
70           continue;
71               
72         if (!(servrec->serv.type & SV_TYPE_POTENTIAL_BROWSER))
73           continue;
74               
75         DEBUG(3,("num servers: %d num backups: %d\n", 
76               num_servers, num_backups));
77               
78         /* make first server a backup server. thereafter make every
79            tenth server a backup server */
80         if (num_backups != 0 && (num_servers+9) / num_backups > 10)
81           continue;
82               
83         DEBUG(2,("sending become backup to %s %s for %s\n",
84              servrec->serv.name, inet_ntoa(subrec->bcast_ip),
85              work->work_group));
86               
87         /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
88         do_announce_request(servrec->serv.name, work->work_group,
89               ANN_BecomeBackup, 0x20, 0x1e, subrec->bcast_ip);
90       }
91     }
92   }
93 }
94 #endif
95
96 /*******************************************************************
97   Process an incoming host announcement packet.
98 *******************************************************************/
99
100 void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
101 {
102   struct dgram_packet *dgram = &p->packet.dgram;
103   int ttl = IVAL(buf,1)/1000;
104   char *announce_name = buf+5;
105   uint32 servertype = IVAL(buf,23);
106   char *comment = buf+31;
107   struct work_record *work;
108   struct server_record *servrec;
109   char *work_name;
110   char *source_name = dgram->source_name.name;
111
112   comment[43] = 0;
113   
114   DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
115 %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
116               namestr(&dgram->dest_name),announce_name));
117
118   DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
119            ttl, servertype,comment));
120
121   /* Filter servertype to remove impossible bits. */
122   servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
123
124   /* A host announcement must be sent to the name WORKGROUP<1d>. */
125   if(dgram->dest_name.name_type != 0x1d)
126   {
127     DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
128 (was %02x) should be 0x1d. Allowing packet anyway.\n",
129               inet_ntoa(p->ip), dgram->dest_name.name_type));
130     /* Change it so it was. */
131     dgram->dest_name.name_type = 0x1d;
132   }
133
134   /* For a host announce the workgroup name is the destination name. */
135   work_name = dgram->dest_name.name;
136
137   /*
138    * We are being very agressive here in adding a workgroup
139    * name on the basis of a host announcing itself as being
140    * in that workgroup. Maybe we should wait for the workgroup
141    * announce instead ? JRA.
142    */
143
144   if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL)
145   {
146     /* We have no record of this workgroup. Add it. */
147     if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
148       return;
149   }
150   
151   if((servrec = find_server_in_workgroup( work, announce_name))==NULL)
152   {
153     /* If this server is not already in the workgroup, add it. */
154     create_server_on_workgroup(work, announce_name, 
155                                servertype|SV_TYPE_LOCAL_LIST_ONLY, 
156                                ttl, comment);
157   }
158   else
159   {
160     /* Update the record. */
161     servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
162     update_server_ttl( servrec, ttl);
163     StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
164   }
165
166   subrec->work_changed = True;
167 }
168
169 /*******************************************************************
170   Process an incoming WORKGROUP announcement packet.
171 *******************************************************************/
172
173 void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
174 {
175   struct dgram_packet *dgram = &p->packet.dgram;
176   int ttl = IVAL(buf,1)/1000;
177   char *workgroup_announce_name = buf+5;
178   uint32 servertype = IVAL(buf,23);
179   char *master_name = buf+31;
180   struct work_record *work;
181   char *source_name = dgram->source_name.name;
182
183   master_name[43] = 0;
184
185   DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
186 %s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
187               namestr(&dgram->dest_name),workgroup_announce_name));
188
189   DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
190            ttl, servertype, master_name));
191
192   /* Workgroup announcements must only go to the MSBROWSE name. */
193   if (!strequal(dgram->dest_name.name, MSBROWSE) || (dgram->dest_name.name_type != 0x1))
194   {
195     DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
196               inet_ntoa(p->ip), namestr(&dgram->dest_name)));
197     return;
198   }
199
200   if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL)
201   {
202     /* We have no record of this workgroup. Add it. */
203     if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
204       return;
205   }
206   else
207   {
208     /* Update the workgroup death_time. */
209     update_workgroup_ttl(work, ttl);
210   }
211
212   if(*work->local_master_browser_name == '\0')
213   {
214     /* Set the master browser name. */
215     StrnCpy(work->local_master_browser_name, master_name,
216             sizeof(work->local_master_browser_name)-1);
217
218   }
219
220   subrec->work_changed = True;
221 }
222
223 /*******************************************************************
224   Process an incoming local master browser announcement packet.
225 *******************************************************************/
226
227 void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
228 {
229   struct dgram_packet *dgram = &p->packet.dgram;
230   int ttl = IVAL(buf,1)/1000;
231   char *server_name = buf+5;
232   uint32 servertype = IVAL(buf,23);
233   char *comment = buf+31;
234   char *work_name;
235   struct work_record *work;
236   struct server_record *servrec;
237   char *source_name = dgram->source_name.name;
238
239   comment[43] = 0;
240
241   DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
242 %s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
243               namestr(&dgram->dest_name),server_name));
244
245   DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
246            ttl, servertype, comment));
247
248   /* A local master announcement must be sent to the name WORKGROUP<1e>. */
249   if(dgram->dest_name.name_type != 0x1e)
250   {
251     DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
252 (was %02x) should be 0x1e. Ignoring packet.\n",
253               inet_ntoa(p->ip), dgram->dest_name.name_type));
254     return;
255   }
256
257   /* Filter servertype to remove impossible bits. */
258   servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);
259
260   /* For a local master announce the workgroup name is the destination name. */
261   work_name = dgram->dest_name.name;
262
263   if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL)
264   {
265     /* We have no record of this workgroup. Add it. */
266     if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
267       return;
268   }
269
270   /* If we think we're the local master browser for this workgroup,
271      we should never have got this packet. We don't see our own
272      packets.
273    */
274   if(AM_LOCAL_MASTER_BROWSER(work))
275   {
276     DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
277 a local master browser for workgroup %s and we think we are master. Forcing election.\n",
278       server_name, inet_ntoa(p->ip), work_name));
279
280     /* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
281        they have become a local master browser once, they will never
282        stop sending local master announcements. To fix this we send
283        them a reset browser packet, with level 0x2 on the __SAMBA__
284        name that only they should be listening to. */
285    
286     send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);
287
288     /* We should demote ourself and force an election. */
289
290     unbecome_local_master_browser( subrec, work);
291
292     /* The actual election requests are handled in
293        nmbd_election.c */
294
295     work->needelection = True;
296     return;
297   }  
298
299   /* Find the server record on this workgroup. If it doesn't exist, add it. */
300
301   if((servrec = find_server_in_workgroup( work, server_name))==NULL)
302   {
303     /* If this server is not already in the workgroup, add it. */
304     create_server_on_workgroup(work, server_name, 
305                                servertype|SV_TYPE_LOCAL_LIST_ONLY, 
306                                ttl, comment);
307   }
308   else
309   {
310     /* Update the record. */
311     servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
312     update_server_ttl(servrec, ttl);
313     StrnCpy(servrec->serv.comment,comment,sizeof(servrec->serv.comment)-1);
314   }
315
316   /* Set the master browser name. */
317   StrnCpy(work->local_master_browser_name, server_name,
318             sizeof(work->local_master_browser_name)-1);
319
320   subrec->work_changed = True;
321 }
322
323 /*******************************************************************
324   Process a domain master announcement frame.
325   Domain master browsers receive these from local masters. The Domain
326   master should then issue a sync with the local master, asking for
327   that machines local server list.
328 ******************************************************************/
329
330 void process_master_browser_announce(struct subnet_record *subrec, 
331                                      struct packet_struct *p,char *buf)
332 {
333   char *local_master_name = buf;
334   struct work_record *work;
335   struct browse_cache_record *browrec;
336
337   local_master_name[15] = 0;
338   
339   DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
340            local_master_name, inet_ntoa(p->ip)));
341   
342   if (!lp_domain_master()) 
343   {
344     DEBUG(0,("process_master_browser_announce: Not configured as domain \
345 master - ignoring master announce.\n"));
346     return;
347   }
348   
349   if((work = find_workgroup_on_subnet(subrec, myworkgroup)) == NULL)
350   {
351     DEBUG(0,("process_master_browser_announce: Cannot find workgroup %s on subnet %s\n",
352            myworkgroup, subrec->subnet_name));
353     return;
354   }
355
356   if(!AM_DOMAIN_MASTER_BROWSER(work))
357   {
358     DEBUG(0,("process_master_browser_announce: Local master announce made to us from \
359 %s IP %s and we are not a domain master browser.\n", local_master_name, inet_ntoa(p->ip)));
360     return;
361   }
362
363   /* Add this host as a local master browser entry on the browse lists.
364      This causes a sync request to be made to it at a later date.
365    */
366
367   if((browrec = find_browser_in_lmb_cache( local_master_name )) == NULL)
368   {
369     /* Add it. */
370     create_browser_in_lmb_cache( work->work_group, local_master_name, p->ip);
371   }
372   else
373     update_browser_death_time(browrec);
374 }
375
376 /****************************************************************************
377   Send a backup list response.
378 *****************************************************************************/
379
380 static void send_backup_list_response(struct subnet_record *subrec, 
381                              struct work_record *work,
382                              struct nmb_name *send_to_name,
383                              unsigned char max_number_requested,
384                              uint32 token, struct in_addr sendto_ip)
385 {                     
386   char outbuf[1024];
387   char *p, *countptr, *nameptr;
388   int count = 0;
389   int len;
390   struct server_record *servrec;
391
392   bzero(outbuf,sizeof(outbuf));
393
394   DEBUG(3,("send_backup_list_response: sending backup list for workgroup %s to %s IP %s\n",
395            work->work_group, namestr(send_to_name), inet_ntoa(sendto_ip)));
396   
397   p = outbuf;
398   
399   SCVAL(p,0,ANN_GetBackupListResp); /* Backup list response opcode. */
400   p++;
401
402   countptr = p;
403   p++;
404
405   SIVAL(p,0,token); /* The sender's unique info. */
406   p += 4;
407   
408   nameptr = p;
409
410   /* We always return at least one name - our own. */
411   count = 1;
412   StrnCpy(p,myname,15);
413   strupper(p);
414   p = skip_string(p,1);
415
416   /* Look for backup browsers in this workgroup. */
417   for (servrec = work->serverlist; servrec; servrec = servrec->next)
418   { 
419     len = PTR_DIFF(p, outbuf);
420     if((sizeof(outbuf) - len) < 16)
421       break;
422
423     if(count >= max_number_requested)
424       break;
425
426     if(strnequal(servrec->serv.name, myname,15))
427       continue;
428
429     if(!(servrec->serv.type & SV_TYPE_BACKUP_BROWSER))
430       continue;
431
432     StrnCpy(p, servrec->serv.name, 15);
433     strupper(p);
434     count++;
435
436     DEBUG(5,("send_backup_list_response: Adding server %s number %d\n",
437               p, count));
438
439     p = skip_string(p,1);
440   }
441
442   SCVAL(countptr, 0, count);
443
444   len = PTR_DIFF(p, outbuf);
445
446   DEBUG(4,("send_backup_list_response: sending response to %s<00> IP %s with %d servers.\n",
447           send_to_name->name, inet_ntoa(sendto_ip), count));
448
449   send_mailslot(True, BROWSE_MAILSLOT,
450                 outbuf,PTR_DIFF(p,outbuf),
451                 myname, 0, 
452                 send_to_name->name,0,
453                 sendto_ip, subrec->myip);
454 }
455
456 /*******************************************************************
457   Process a send backup list request packet.
458
459   A client sends a backup list request to ask for a list of servers on
460   the net that maintain server lists for a domain. A server is then
461   chosen from this list to send NetServerEnum commands to to list
462   available servers.
463
464 ********************************************************************/
465
466 void process_get_backup_list_request(struct subnet_record *subrec,
467                                      struct packet_struct *p,char *buf)
468 {
469   struct dgram_packet *dgram = &p->packet.dgram;
470   struct work_record *work;
471   unsigned char max_number_requested = CVAL(buf,0);
472   uint32 token = IVAL(buf,1); /* Sender's key index for the workgroup. */
473   int name_type = dgram->dest_name.name_type;
474   char *workgroup_name = dgram->dest_name.name;
475
476   DEBUG(3,("process_get_backup_list_request: request from %s IP %s to %s.\n",
477            namestr(&dgram->source_name), inet_ntoa(p->ip),
478            namestr(&dgram->dest_name)));
479   
480   /* We have to be a master browser, or a domain master browser
481      for the requested workgroup. That means it must be our
482      workgroup. */
483
484   if(strequal(workgroup_name, myworkgroup) == False)
485   {
486     DEBUG(7,("process_get_backup_list_request: Ignoring announce request for workgroup %s.\n",
487            workgroup_name));
488     return;
489   }
490
491   if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
492   {
493     DEBUG(0,("process_get_backup_list_request: Cannot find workgroup %s on \
494 subnet %s.\n", workgroup_name, subrec->subnet_name));
495     return;
496   }
497
498   if(name_type == 0x1b)
499   {
500     /* We must be a domain master browser in order to
501        process this packet. */
502
503     if(!AM_DOMAIN_MASTER_BROWSER(work))
504     {
505       DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
506 and I am not a domain master browser.\n", workgroup_name));
507       return;
508     }
509   }
510   else if (name_type == 0x1d)
511   {
512     /* We must be a local master browser in order to
513        process this packet. */
514
515     if(!AM_LOCAL_MASTER_BROWSER(work))
516     {
517       DEBUG(0,("process_get_backup_list_request: domain list requested for workgroup %s \
518 and I am not a local master browser.\n", workgroup_name));
519       return;
520     }
521   }
522   else
523   {
524     DEBUG(0,("process_get_backup_list_request: Invalid name type %x - should be 0x1b or 0x1d.\n",
525             name_type));
526     return;
527   }
528
529   send_backup_list_response(subrec, work, &dgram->source_name, 
530                             max_number_requested, token, p->ip);
531 }
532
533 /*******************************************************************
534   Process a reset browser state packet.
535
536   Diagnostic packet:
537   0x1 - Stop being a master browser and become a backup browser.
538   0x2 - Discard browse lists, stop being a master browser, try again.
539   0x4 - Stop being a master browser forever.
540          
541 ******************************************************************/
542
543 void process_reset_browser(struct subnet_record *subrec,
544                                   struct packet_struct *p,char *buf)
545 {
546   struct dgram_packet *dgram = &p->packet.dgram;
547   int state = CVAL(buf,0);
548   struct subnet_record *sr;
549
550   DEBUG(1,("process_reset_browser: received diagnostic browser reset \
551 request from %s IP %s state=0x%X\n",
552              namestr(&dgram->source_name), inet_ntoa(p->ip), state));
553
554   /* Stop being a local master browser on all our broadcast subnets. */
555   if (state & 0x1)
556   {
557     for (sr = FIRST_SUBNET; sr; sr = NEXT_SUBNET_EXCLUDING_UNICAST(sr))
558     {
559       struct work_record *work;
560       for (work = sr->workgrouplist; work; work = work->next)
561       {
562         if (AM_LOCAL_MASTER_BROWSER(work))
563         {
564           unbecome_local_master_browser(sr, work);
565           work->needelection = True;
566         }
567       }
568     }
569   }
570   
571   /* Discard our browse lists. */
572   if (state & 0x2)
573   {
574     /*
575      * Calling expire_workgroups_and_servers with a -1
576      * time causes all servers not marked with a PERMANENT_TTL
577      * on the workgroup lists to be discarded, and all 
578      * workgroups with empty server lists to be discarded.
579      * This means we keep our own server names and workgroup
580      * as these have a PERMANENT_TTL.
581      */
582
583     expire_workgroups_and_servers(-1);
584   }
585   
586   /* Request to stop browsing altogether. */
587   if (state & 0x4)
588     DEBUG(1,("process_reset_browser: ignoring request to stop being a browser.\n"));
589 }
590
591 /*******************************************************************
592   Process a announcement request packet.
593   We don't respond immediately, we just check it's a request for
594   out workgroup and then set the flag telling the announce code
595   in nmbd_sendannounce.c:announce_my_server_names that an 
596   announcement is needed soon.
597   ******************************************************************/
598
599 void process_announce_request(struct subnet_record *subrec, struct packet_struct *p, char *buf)
600 {
601   struct dgram_packet *dgram = &p->packet.dgram;
602   struct work_record *work;
603   char *workgroup_name = dgram->dest_name.name;
604  
605   DEBUG(3,("process_announce_request: Announce request from %s IP %s to %s.\n",
606            namestr(&dgram->source_name), inet_ntoa(p->ip),
607            namestr(&dgram->dest_name)));
608   
609   /* We only send announcement requests on our workgroup. */
610   if(strequal(workgroup_name, myworkgroup) == False)
611   {
612     DEBUG(7,("process_announce_request: Ignoring announce request for workgroup %s.\n",
613            workgroup_name));
614     return;
615   }
616
617   if((work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL)
618   {
619     DEBUG(0,("process_announce_request: Unable to find workgroup %s on subnet !\n",
620             workgroup_name));
621     return;
622   }
623
624   work->needannounce = True;
625 }