f0fca0071e3bc2d7f1b31ace9a60d15ce45b2976
[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-1995
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 browse cache database */
49 extern struct browse_cache_record *browserlist;
50
51 /* this is our domain/workgroup/server database */
52 extern struct interface *local_interfaces;
53
54 /* this is our domain/workgroup/server database */
55 extern struct subnet_record *subnetlist;
56
57 /* machine comment for host announcements */
58 extern  pstring ServerComment;
59
60 extern int  updatecount;
61
62 /* what server type are we currently */
63 #define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
64                 SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX |\
65                 SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
66
67 /* backup request types: which servers are to be included */
68 #define MASTER_TYPE (SV_TYPE_MASTER_BROWSER)
69 #define DOMCTL_TYPE (SV_TYPE_DOMAIN_CTRL   )
70
71 extern time_t StartupTime;
72
73 #define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
74
75 #define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
76
77
78 /****************************************************************************
79 tell a server to become a backup browser
80 state - 0x01 become backup instead of master
81       - 0x02 remove all entries in browse list and become non-master
82       - 0x04 stop master browser service altogether. NT ignores this 
83 **************************************************************************/
84 void reset_server(char *name, int state, struct in_addr ip)
85 {
86   char outbuf[20];
87   char *p;
88
89   bzero(outbuf,sizeof(outbuf));
90   p = outbuf;
91
92   CVAL(p,0) = ANN_ResetBrowserState;
93   CVAL(p,2) = state; 
94   p += 2;
95
96   DEBUG(2,("sending reset to %s %s of state %d\n",
97            name,inet_ntoa(ip),state));
98
99   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
100                       myname,name,0x20,0x1d,ip,*iface_ip(ip));
101 }
102
103
104 /****************************************************************************
105 tell a server to become a backup browser
106 **************************************************************************/
107 void tell_become_backup(void)
108 {
109   struct subnet_record *d;
110   for (d = subnetlist; d; d = d->next)
111     {
112       struct work_record *work;
113       for (work = d->workgrouplist; work; work = work->next)
114         {
115           struct server_record *s;
116           int num_servers = 0;
117           int num_backups = 0;
118           
119           for (s = work->serverlist; s; s = s->next)
120             {
121               if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
122               
123               num_servers++;
124               
125               if (strequal(myname, s->serv.name)) continue;
126               
127               if (s->serv.type & SV_TYPE_BACKUP_BROWSER) {
128                 num_backups++;
129                 continue;
130               }
131               
132               if (s->serv.type & SV_TYPE_MASTER_BROWSER) continue;
133               
134               if (!(s->serv.type & SV_TYPE_POTENTIAL_BROWSER)) continue;
135               
136               DEBUG(3,("num servers: %d num backups: %d\n", 
137                        num_servers, num_backups));
138               
139               /* make first server a backup server. thereafter make every
140                  tenth server a backup server */
141               if (num_backups != 0 && (num_servers+9) / num_backups > 10)
142                 {
143                   continue;
144                 }
145               
146               DEBUG(2,("sending become backup to %s %s for %s\n",
147                        s->serv.name, inet_ntoa(d->bcast_ip),
148                        work->work_group));
149               
150               /* type 11 request from MYNAME(20) to WG(1e) for SERVER */
151               do_announce_request(s->serv.name, work->work_group,
152                                   ANN_BecomeBackup, 0x20, 0x1e, d->bcast_ip);
153             }
154         }
155     }
156 }
157
158 /****************************************************************************
159 find a server responsible for a workgroup, and sync browse lists
160 **************************************************************************/
161 static void start_sync_browse_entry(struct browse_cache_record *b)
162 {                     
163   struct subnet_record *d;
164   struct work_record *work;
165   
166   if (!(d = find_subnet(b->ip))) return;
167
168   /* only sync if we are the master */
169   if (AM_MASTER(work)) {
170
171       /* first check whether the group we intend to sync with exists. if it
172          doesn't, the server must have died. o dear. */
173
174       /* see response_netbios_packet() or expire_netbios_response_entries() */
175       queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SYNC,
176                                            b->group,0x20,0,0,
177                                            False,False,b->ip);
178   }
179   
180   b->synced = True;
181 }
182
183
184 /****************************************************************************
185 search through browser list for an entry to sync with
186 **************************************************************************/
187 void do_browser_lists(void)
188 {
189   struct browse_cache_record *b;
190   static time_t last = 0;
191   time_t t = time(NULL);
192   
193   if (t-last < 20) return; /* don't do too many of these at once! */
194                            /* XXXX equally this period should not be too long
195                               the server may die in the intervening gap */
196   
197   last = t;
198   
199   /* pick any entry in the list, preferably one whose time is up */
200   for (b = browserlist; b && b->next; b = b->next)
201     {
202       if (b->sync_time < t && b->synced == False) break;
203     }
204   
205   if (b && !b->synced)
206     {
207     /* sync with the selected entry then remove some dead entries */
208     start_sync_browse_entry(b);
209       expire_browse_cache(t - 60);
210     }
211
212 }
213
214
215 /****************************************************************************
216 find a server responsible for a workgroup, and sync browse lists
217 control ends up back here via response_name_query.
218 **************************************************************************/
219 void sync_server(enum cmd_type cmd, char *serv_name, char *work_name, 
220                  int name_type,
221                  struct in_addr ip)
222 {                     
223   add_browser_entry(serv_name, name_type, work_name, 0, ip);
224
225   if (cmd == NAME_QUERY_MST_SRV_CHK)
226     {
227       /* announce ourselves as a master browser to serv_name */
228       do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
229                           0x20, 0, ip);
230     }
231 }
232
233
234 /****************************************************************************
235   add the default workgroup into my domain
236   **************************************************************************/
237 void add_my_subnets(char *group)
238 {
239   struct interface *i;
240
241   /* add or find domain on our local subnet, in the default workgroup */
242
243   if (*group == '*') return;
244
245         /* the coding choice is up to you, andrew: i can see why you don't want
246        global access to the local_interfaces structure: so it can't get
247        messed up! */
248     for (i = local_interfaces; i; i = i->next)
249     {
250       add_subnet_entry(i->bcast,i->nmask,group, True, False);
251   }
252 }
253
254
255 /****************************************************************************
256   send a backup list response.
257   **************************************************************************/
258 static void send_backup_list(char *work_name, struct nmb_name *src_name,
259                              int info_count, int token, int info,
260                              int name_type, struct in_addr ip)
261 {                     
262   struct subnet_record *d;
263   char outbuf[1024];
264   char *p, *countptr, *nameptr;
265   int count = 0;
266   int i, j;
267   char *theirname = src_name->name;
268   
269   DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n", 
270            work_name, inet_ntoa(ip),
271            myname,0x20,theirname,0x0));    
272   
273   if (name_type == 0x1d)
274     {
275       DEBUG(4,("master browsers: "));
276     }
277   else if (name_type == 0x1b)
278     {
279       DEBUG(4,("domain controllers: "));
280     }
281   else
282     {
283       DEBUG(0,("backup request for unknown type %0x\n", name_type));
284       return;
285     }
286   
287   bzero(outbuf,sizeof(outbuf));
288   p = outbuf;
289   
290   CVAL(p,0) = 10;    /* backup list response */
291   p++;
292   
293   countptr = p; /* count pointer */
294   
295   SSVAL(p,1,token); /* sender's workgroup index representation */
296   SSVAL(p,3,info); /* XXXX clueless: info, usually zero */
297   p += 5;
298   
299   nameptr = p;
300   
301   for (d = subnetlist; d; d = d->next)
302     {
303       struct work_record *work;
304       
305       for (work = d->workgrouplist; work; work = work->next)
306         {
307           struct server_record *s;
308           
309           if (!strequal(work->work_group, work_name)) continue;
310           
311           for (s = work->serverlist; s; s = s->next)
312             { 
313               BOOL found = False;
314               char *n;
315               
316               if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
317               
318               for (n = nameptr; n < p; n = skip_string(n, 1))
319                 {
320                   if (strequal(n, s->serv.name)) found = True;
321                 }
322               
323               if (found) continue; /* exclude names already added */
324               
325               /* workgroup request: include all backup browsers in the list */
326               /* domain request: include all domain members in the list */
327               
328               if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
329                   (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
330                 {                          
331                   DEBUG(4, ("%s ", s->serv.name));
332                   
333                   count++;
334                   strcpy(p,s->serv.name);
335                   strupper(p);
336                   p = skip_string(p,1);
337                 }
338             }
339         }
340     }
341   
342   if (count == 0)
343     {
344       DEBUG(4, ("none\n"));
345       return;
346     }
347   else
348     {
349       DEBUG(4, (" - count %d\n", count));
350     }
351   
352   CVAL(countptr,0) = count; /* total number of backup browsers found */
353   
354   {
355     int len = PTR_DIFF(p, outbuf);
356     
357     for (i = 0; i < len; i+= 16)
358       {
359         DEBUG(4, ("%3x char ", i));
360         
361         for (j = 0; j < 16; j++)
362           {
363             unsigned char x = outbuf[i+j];
364             if (x < 32 || x > 127) x = '.';
365             
366             if (i+j >= len) break;
367             DEBUG(4, ("%c", x));
368           }
369         
370         DEBUG(4, (" hex ", i));
371         
372         for (j = 0; j < 16; j++)
373           {
374             if (i+j >= len) break;
375             DEBUG(4, (" %02x", outbuf[i+j]));
376           }
377         
378         DEBUG(4, ("\n"));
379       }
380     
381   }
382   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
383                       myname,theirname,0x20,0,ip,*iface_ip(ip));
384 }
385
386
387 /*******************************************************************
388   same context: scope. should check name_type as well, and makes sure
389   we don't process messages from ourselves
390   ******************************************************************/
391 BOOL same_context(struct dgram_packet *dgram)
392 {
393   if (!strequal(dgram->dest_name  .scope,scope )) return(True);
394   if ( strequal(dgram->source_name.name ,myname)) return(True);
395   
396   return(False);
397 }
398
399
400 /*******************************************************************
401   am I listening on a name. XXXX check the type of name as well.
402   ******************************************************************/
403 BOOL listening_name(struct work_record *work, struct nmb_name *n)
404 {
405   if (strequal(n->name,myname) ||
406       strequal(n->name,work->work_group) ||
407       strequal(n->name,MSBROWSE))
408     {
409       return(True);
410     }
411   
412   return(False);
413 }
414
415
416 /*******************************************************************
417   process a domain announcement frame
418
419   Announce frames come in 3 types. Servers send host announcements
420   (command=1) to let the master browswer know they are
421   available. Master browsers send local master announcements
422   (command=15) to let other masters and backups that they are the
423   master. They also send domain announcements (command=12) to register
424   the domain
425
426   The comment field of domain announcements contains the master
427   browser name. The servertype is used by NetServerEnum to select
428   resources. We just have to pass it to smbd (via browser.dat) and let
429   the client choose using bit masks.
430   ******************************************************************/
431 static void process_announce(struct packet_struct *p,int command,char *buf)
432 {
433   struct dgram_packet *dgram = &p->packet.dgram;
434   struct in_addr ip = dgram->header.source_ip;
435   struct subnet_record *d = find_subnet(ip); 
436   int update_count = CVAL(buf,0);
437   int ttl = IVAL(buf,1)/1000;
438   char *name = buf+5;
439   int osmajor=CVAL(buf,21);
440   int osminor=CVAL(buf,22);
441   uint32 servertype = IVAL(buf,23);
442   char *comment = buf+31;
443   struct work_record *work;
444   char *work_name;
445   char *serv_name = dgram->source_name.name;
446   BOOL add = False;
447
448   comment[43] = 0;
449   
450   DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
451   DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
452            namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
453            servertype,comment));
454   
455   name[15] = 0;  
456   
457   if (dgram->dest_name.name_type == 0 && command == ANN_HostAnnouncement)
458     {
459       DEBUG(2,("Announce to nametype(0) not supported yet\n"));
460       return;
461     }
462
463   if (command == ANN_DomainAnnouncement && 
464       ((!strequal(dgram->dest_name.name, MSBROWSE)) ||
465        dgram->dest_name.name_type != 0x1))
466     {
467       DEBUG(0,("Announce(%d) from %s should be __MSBROWSE__(1) not %s\n",
468                 command, inet_ntoa(ip), namestr(&dgram->dest_name)));
469       return;
470     }
471   
472   if (same_context(dgram)) return;
473   
474   if (command == ANN_DomainAnnouncement) {
475     work_name = name;
476   } else {
477     work_name = dgram->dest_name.name;
478   }
479
480   /* we need some way of finding out about new workgroups
481      that appear to be sending packets to us. The name_type checks make
482      sure we don't add host names as workgroups */
483   if (command == ANN_HostAnnouncement &&
484       (dgram->dest_name.name_type == 0x1d ||
485        dgram->dest_name.name_type == 0x1e))
486     add = True;
487   
488   if (!(work = find_workgroupstruct(d, work_name,add)))
489     return;
490   
491   DEBUG(4, ("workgroup %s on %s\n", work->work_group, serv_name));
492   
493   ttl = GET_TTL(ttl);
494   
495   /* add them to our browse list */
496   add_server_entry(d,work,name,servertype,ttl,comment,True);
497   
498 #if 0
499   /* the tell become backup code is broken, no great harm is done by
500      disabling it */
501   tell_become_backup();
502 #endif
503
504   /* get their browse list from them and add it to ours. */
505   add_browser_entry(serv_name,dgram->dest_name.name_type,
506                     work->work_group,30,ip);
507 }
508
509 /*******************************************************************
510   process a master announcement frame
511   ******************************************************************/
512 static void process_master_announce(struct packet_struct *p,char *buf)
513 {
514   struct dgram_packet *dgram = &p->packet.dgram;
515   struct in_addr ip = dgram->header.source_ip;
516   struct subnet_record *d = find_subnet(ip);
517   struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
518   char *name = buf;
519   struct work_record *work;
520   name[15] = 0;
521   
522   DEBUG(3,("Master Announce from %s (%s)\n",name,inet_ntoa(ip)));
523   
524   if (same_context(dgram)) return;
525   
526   if (!d || !mydomain) return;
527   
528   if (!lp_domain_master()) return;
529   
530   for (work = mydomain->workgrouplist; work; work = work->next)
531     {
532       if (AM_MASTER(work))
533         {
534           /* merge browse lists with them */
535           add_browser_entry(name,0x1b, work->work_group,30,ip);
536         }
537     }
538 }
539
540 /*******************************************************************
541   process a receive backup list request
542   
543   we receive a list of servers, and we attempt to locate them all on
544   our local subnet, and sync browse lists with them on the workgroup
545   they are said to be in.
546   ******************************************************************/
547 static void process_rcv_backup_list(struct packet_struct *p,char *buf)
548 {
549   struct dgram_packet *dgram = &p->packet.dgram;
550   struct in_addr ip = dgram->header.source_ip;
551   int count = CVAL(buf,0);
552   int Index = IVAL(buf,1); /* caller's index representing workgroup */
553   char *buf1;
554   
555   DEBUG(3,("Receive Backup ack for %s from %s total=%d index=%d\n",
556            namestr(&dgram->dest_name), inet_ntoa(ip),
557            count, Index));
558   
559   if (same_context(dgram)) return;
560   
561   if (count <= 0) return;
562   
563   /* go through the list of servers attempting to sync browse lists */
564   for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
565     {
566       struct in_addr back_ip;
567       struct subnet_record *d;
568       
569       DEBUG(4,("Searching for backup browser %s at %s...\n",
570                buf1, inet_ntoa(ip)));
571       
572       /* XXXX assume name is a DNS name NOT a netbios name. a more complete
573          approach is to use reply_name_query functionality to find the name */
574       back_ip = *interpret_addr2(buf1);
575       
576       if (zero_ip(back_ip))
577         {
578           DEBUG(4,("Failed to find backup browser server using DNS\n"));
579           continue;
580         }
581       
582       DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
583       
584       if ((d = find_subnet(back_ip)))
585         {
586           struct subnet_record *d1;
587           for (d1 = subnetlist; d1; d1 = d1->next)
588             {
589               struct work_record *work;
590               for (work = d1->workgrouplist; work; work = work->next)
591                 {
592                   if (work->token == Index)
593                     {
594                       queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
595                                            work->work_group,0x1d,0,0,
596                                            False,False,back_ip);
597                       return;
598                     }
599                 }
600             }
601         }
602     }
603 }
604
605 /*******************************************************************
606   process a send backup list request
607
608   A client send a backup list request to ask for a list of servers on
609   the net that maintain server lists for a domain. A server is then
610   chosen from this list to send NetServerEnum commands to to list
611   available servers.
612
613   Currently samba only sends back one name in the backup list, its
614   own. For larger nets we'll have to add backups and send "become
615   backup" requests occasionally.
616   ******************************************************************/
617 static void process_send_backup_list(struct packet_struct *p,char *buf)
618 {
619   struct dgram_packet *dgram = &p->packet.dgram;
620   struct in_addr ip = dgram->header.source_ip;
621   struct subnet_record *d; 
622   struct work_record *work;
623
624   int count = CVAL(buf,0);
625   int token = SVAL(buf,1); /* sender's key index for the workgroup? */
626   int info  = SVAL(buf,3); /* XXXX don't know: some sort of info */
627   int name_type = dgram->dest_name.name_type;
628
629   if (same_context(dgram)) return;
630   
631   if (count <= 0) return;
632   
633   if (name_type != 0x1b && name_type != 0x1d) {
634     DEBUG(0,("backup request to wrong type %d from %s\n",
635               name_type,inet_ntoa(ip)));
636     return;
637   }
638   
639   for (d = subnetlist; d; d = d->next)
640     {
641       for (work = d->workgrouplist; work; work = work->next)
642         {
643           if (strequal(work->work_group, dgram->dest_name.name))
644             {
645               DEBUG(2,("sending backup list to %s %s count=%d\n",
646                        namestr(&dgram->dest_name),inet_ntoa(ip),count));
647   
648               send_backup_list(work->work_group,&dgram->source_name,
649                                count,token,info,name_type,ip);
650               return;
651             }
652         } 
653     }
654 }
655
656
657 /*******************************************************************
658   process a reset browser state
659
660   diagnostic packet:
661   0x1 - stop being a master browser
662   0x2 - discard browse lists, stop being a master browser, try again.
663   0x4 - stop being a master browser forever. no way. ain't gonna.
664          
665   ******************************************************************/
666 static void process_reset_browser(struct packet_struct *p,char *buf)
667 {
668   struct dgram_packet *dgram = &p->packet.dgram;
669   int state = CVAL(buf,0);
670
671   DEBUG(1,("received diagnostic browser reset request to %s state=0x%X\n",
672            namestr(&dgram->dest_name), state));
673
674   /* stop being a master but still deal with being a backup browser */
675   if (state & 0x1)
676     {
677       struct subnet_record *d;
678       for (d = subnetlist; d; d = d->next)
679         {
680           struct work_record *work;
681           for (work = d->workgrouplist; work; work = work->next)
682             {
683               if (AM_MASTER(work))
684                 {
685                   become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
686                 }
687             }
688         }
689     }
690   
691   /* totally delete all servers and start afresh */
692   if (state & 0x2)
693     {
694       struct subnet_record *d;
695       for (d = subnetlist; d; d = d->next)
696         {
697           struct work_record *work;
698           for (work=d->workgrouplist;work;work=remove_workgroup(d,work));
699         }
700       add_my_subnets(lp_workgroup());
701     }
702   
703   /* stop browsing altogether. i don't think this is a good idea! */
704   if (state & 0x4)
705     {
706       DEBUG(1,("ignoring request to stop being a browser. sorry!\n"));
707     }
708 }
709
710
711 /*******************************************************************
712   process a announcement request
713
714   clients send these when they want everyone to send an announcement
715   immediately. This can cause quite a storm of packets!
716   ******************************************************************/
717 static void process_announce_request(struct packet_struct *p,char *buf)
718 {
719   struct dgram_packet *dgram = &p->packet.dgram;
720   struct work_record *work;
721   struct in_addr ip = dgram->header.source_ip;
722   struct subnet_record *d = find_subnet(ip);
723   int token = CVAL(buf,0);
724   char *name = buf+1;
725   
726   name[15] = 0;
727   
728   DEBUG(3,("Announce request from %s to %s token=0x%X\n",
729            name,namestr(&dgram->dest_name), token));
730   
731   if (strequal(dgram->source_name.name,myname)) return;
732   
733   if (!d) return;
734   
735   if (!d->my_interface) return;
736   
737   for (work = d->workgrouplist; work; work = work->next)
738     {
739       if (strequal(dgram->dest_name.name,work->work_group)) 
740         {
741           work->needannounce = True;
742         }
743     }
744 }
745
746
747 /****************************************************************************
748    process a domain logon packet
749    **************************************************************************/
750 void process_logon_packet(struct packet_struct *p,char *buf,int len)
751 {
752   struct dgram_packet *dgram = &p->packet.dgram;
753   struct in_addr ip = dgram->header.source_ip;
754   struct subnet_record *d = find_subnet(ip);
755   char *logname,*q;
756   char *reply_name;
757   BOOL add_slashes = False;
758   pstring outbuf;
759   int code,reply_code;
760   struct work_record *work;
761   
762   if (!d) return;
763   
764   if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False))) 
765     return;
766   
767   if (!lp_domain_logons()) {
768     DEBUG(3,("No domain logons\n"));
769     return;
770   }
771   if (!listening_name(work, &dgram->dest_name))
772     {
773       DEBUG(4,("Not listening to that domain\n"));
774       return;
775     }
776   
777   code = SVAL(buf,0);
778   switch (code) {
779   case 0:    
780     {
781       char *machine = buf+2;
782       char *user = skip_string(machine,1);
783       logname = skip_string(user,1);
784       reply_code = 6;
785       reply_name = myname;
786       add_slashes = True;
787       DEBUG(3,("Domain login request from %s(%s) user=%s\n",
788                machine,inet_ntoa(p->ip),user));
789     }
790     break;
791   case 7:    
792     {
793       char *machine = buf+2;
794       logname = skip_string(machine,1);
795       reply_code = 7;
796       reply_name = lp_domain_controller();
797       if (!*reply_name) {
798         DEBUG(3,("No domain controller configured\n"));
799         return;
800       }
801       DEBUG(3,("GETDC request from %s(%s)\n",
802                machine,inet_ntoa(p->ip)));
803     }
804     break;
805   default:
806     DEBUG(3,("Unknown domain request %d\n",code));
807     return;
808   }
809   
810   bzero(outbuf,sizeof(outbuf));
811   q = outbuf;
812   SSVAL(q,0,reply_code);
813   q += 2;
814   if (add_slashes) {
815     strcpy(q,"\\\\");
816     q += 2;
817   }
818   StrnCpy(q,reply_name,16);
819   strupper(q);
820   q = skip_string(q,1);
821   SSVAL(q,0,0xFFFF);
822   q += 2;
823   
824   send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
825                       myname,&dgram->source_name.name[0],0x20,0,p->ip,
826                       *iface_ip(p->ip));  
827 }
828  
829
830 /****************************************************************************
831 depending on what announce has been made, we are only going to
832 accept certain types of name announce. XXXX untested code
833
834 check listening name type
835 ****************************************************************************/
836 BOOL listening_type(struct packet_struct *p, int command)
837 {
838   struct dgram_packet *dgram = &p->packet.dgram;
839   int type = dgram->dest_name.name_type;
840
841   switch (command)
842     {
843     case ANN_HostAnnouncement:
844       {
845         if (type != 0x0 || type != 0x20) return (False);
846         break;
847       }
848       
849     case ANN_AnnouncementRequest:
850       {
851         return (True);
852         break;
853       }
854       
855     case ANN_Election:
856       {
857         return (True);
858         break;
859       }
860       
861     case ANN_GetBackupListReq:
862       {
863         return (True);
864         break;
865       }
866       
867     case ANN_GetBackupListResp:
868       {
869         return (True);
870         break;
871       }
872       
873     case ANN_DomainAnnouncement:
874       {
875         if (type != 0x1b || type != 0x1c) return (False);
876         break;
877       }
878       
879     case ANN_MasterAnnouncement:
880       {
881         if (type != 0x1d) return (False);
882         break;
883       }
884       
885     case ANN_LocalMasterAnnouncement:
886       {
887         if (type != 0x1c || type != 0x1d) return (False);
888         break;
889       }
890     }
891   return (True); /* we're not dealing with unknown packet types */
892 }
893
894
895 /****************************************************************************
896 process a browse frame
897 ****************************************************************************/
898 void process_browse_packet(struct packet_struct *p,char *buf,int len)
899 {
900   int command = CVAL(buf,0);
901   switch (command) 
902     {
903     case ANN_HostAnnouncement:
904     case ANN_DomainAnnouncement:
905     case ANN_LocalMasterAnnouncement:
906       {
907         process_announce(p,command,buf+1);
908         break;
909       }
910       
911     case ANN_AnnouncementRequest:
912       {
913         process_announce_request(p,buf+1);
914         break;
915       }
916       
917     case ANN_Election:
918       {
919         process_election(p,buf+1);
920         break;
921       }
922       
923     case ANN_GetBackupListReq:
924       {
925         process_send_backup_list(p,buf+1);
926         break;
927       }
928       
929     case ANN_GetBackupListResp:
930       {
931         process_rcv_backup_list(p, buf+1);
932         break;
933       }
934       
935     case ANN_ResetBrowserState:
936       {
937         process_reset_browser(p, buf+1);
938         break;
939       }
940       
941     case ANN_MasterAnnouncement:
942       {
943         process_master_announce(p,buf+1);
944         break;
945       }
946       
947     default:
948       {
949         struct dgram_packet *dgram = &p->packet.dgram;
950         DEBUG(4,("ignoring browse packet %d from %s %s to %s\n",
951                  command, namestr(&dgram->source_name), 
952                  inet_ntoa(p->ip), namestr(&dgram->dest_name)));
953       }
954     }
955 }
956
957
958 /****************************************************************************
959 process udp 138 datagrams
960 ****************************************************************************/
961 void process_dgram(struct packet_struct *p)
962 {
963   char *buf;
964   char *buf2;
965   int len;
966   struct dgram_packet *dgram = &p->packet.dgram;
967
968   if (dgram->header.msg_type != 0x10 &&
969       dgram->header.msg_type != 0x11 &&
970       dgram->header.msg_type != 0x12) {
971     /* don't process error packets etc yet */
972     return;
973   }
974
975   buf = &dgram->data[0];
976   buf -= 4; /* XXXX for the pseudo tcp length - 
977                someday I need to get rid of this */
978
979   if (CVAL(buf,smb_com) != SMBtrans) return;
980
981   len = SVAL(buf,smb_vwv11);
982   buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
983
984   DEBUG(4,("datagram from %s to %s for %s of type %d len=%d\n",
985            namestr(&dgram->source_name),namestr(&dgram->dest_name),
986            smb_buf(buf),CVAL(buf2,0),len));
987
988  
989   if (len <= 0) return;
990
991    if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE"))
992    {
993      process_browse_packet(p,buf2,len);
994    } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) {
995      process_logon_packet(p,buf2,len);
996    }
997 }
998