db517dff82590cfd0bf99d3a79ad0cb16430ef98
[kai/samba.git] / source3 / nameservreply.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    Module name: nameservreply.c
22
23    Revision History:
24
25    14 jan 96: lkcl@pires.co.uk
26    added multiple workgroup domain master support
27
28    04 jul 96: lkcl@pires.co.uk
29    created module nameservreply containing NetBIOS reply functions
30
31 */
32
33 #include "includes.h"
34
35 extern int ClientNMB;
36
37 extern int DEBUGLEVEL;
38
39 extern struct in_addr wins_ip;
40
41 /****************************************************************************
42 send a registration / release response: pos/neg
43 **************************************************************************/
44 static void send_name_response(int fd, struct in_addr from_ip,
45                                 int name_trn_id, int opcode, BOOL success, BOOL recurse,
46                                 struct nmb_name *reply_name, int nb_flags, int ttl,
47                                 struct in_addr ip)
48 {
49   char rdata[6];
50   struct packet_struct p;
51
52   int rcode = 0;  
53
54   if (success == False)
55   {
56     /* NEGATIVE RESPONSE */
57     rcode = 6;
58   }
59   else if (opcode == NMB_REG && recurse == False)
60   {
61     /* END-NODE CHALLENGE REGISTRATION RESPONSE */
62         rcode = 0;
63   }
64   
65   rdata[0] = nb_flags;
66   rdata[1] = 0;
67   putip(&rdata[2],(char *)&ip);
68   
69   p.ip = from_ip;
70   p.port = NMB_PORT;
71   p.fd = fd;
72   p.timestamp = time(NULL);
73   p.packet_type = NMB_PACKET;
74
75   reply_netbios_packet(&p,name_trn_id,
76                        rcode,opcode,opcode,recurse,
77                        reply_name, 0x20, 0x1,
78                        ttl, 
79                        rdata, 6);
80 }
81
82 /****************************************************************************
83   add a netbios entry. respond to the (possibly new) owner.
84   **************************************************************************/
85 void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
86                                 uint16 response_id,
87                                 struct nmb_name *name,
88                                 int nb_flags, int ttl, struct in_addr register_ip,
89                                 BOOL new_owner, struct in_addr reply_to_ip)
90 {
91   /* register the old or the new owners' ip */
92   add_netbios_entry(d,name->name,name->name_type,
93                     nb_flags,ttl,REGISTER,register_ip,False,True);
94
95   /* reply yes or no to the host that requested the name */
96   send_name_response(fd,from_ip, response_id, NMB_REG,
97                      new_owner, False,
98                      name, nb_flags, ttl, reply_to_ip);
99 }
100
101
102 /****************************************************************************
103 reply to a name release
104 ****************************************************************************/
105 void reply_name_release(struct packet_struct *p)
106 {
107   struct nmb_packet *nmb = &p->packet.nmb;
108   struct in_addr ip;
109   int nb_flags = nmb->additional->rdata[0];
110   BOOL bcast = nmb->header.nm_flags.bcast;
111   struct name_record *n;
112   struct subnet_record *d = NULL;
113   int search = 0;
114   BOOL success = False;
115   
116   putip((char *)&ip,&nmb->additional->rdata[2]);  
117   
118   DEBUG(3,("Name release on name %s\n",
119            namestr(&nmb->question.question_name)));
120   
121   if (!(d = find_req_subnet(p->ip, bcast)))
122     {
123       DEBUG(3,("response packet: bcast %s not known\n",
124                inet_ntoa(p->ip)));
125       return;
126     }
127
128   if (bcast)
129     search |= FIND_LOCAL;
130   else
131     search |= FIND_WINS;
132
133   n = find_name_search(&d, &nmb->question.question_name, 
134                        search, ip);
135   
136   /* XXXX under what conditions should we reject the removal?? */
137   /* For now - remove if the names match and the group bit matches. */
138   if (n && (NAME_GROUP(n->ip_flgs[0].nb_flags) == NAME_GROUP(nb_flags)))
139     {
140       success = True;
141       
142       DEBUG(5, ("reply_name_release: Removing name %s on subnet %s\n",
143                 namestr(&nmb->question.question_name), inet_ntoa(d->bcast_ip)));
144       remove_name(d,n);
145       n = NULL;
146     }
147   
148   if (bcast) return;
149   
150   /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
151   send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
152                      success, nmb->header.nm_flags.recursion_desired,
153                      &nmb->question.question_name, nb_flags, 0, ip);
154 }
155
156
157 /****************************************************************************
158 reply to a reg request
159 **************************************************************************/
160 void reply_name_reg(struct packet_struct *p)
161 {
162   struct nmb_packet *nmb = &p->packet.nmb;
163   struct nmb_name *question = &nmb->question.question_name;
164   
165   struct nmb_name *reply_name = question;
166
167   char *qname      = question->name;
168   int   qname_type = question->name_type;
169  
170   BOOL bcast = nmb->header.nm_flags.bcast;
171   
172   int ttl = GET_TTL(nmb->additional->ttl);
173   int nb_flags = nmb->additional->rdata[0];
174   BOOL group = NAME_GROUP(nb_flags);
175
176   struct subnet_record *d = NULL;
177   struct name_record *n = NULL;
178
179   BOOL success = True;
180   BOOL secured_redirect = False;
181
182   struct in_addr ip, from_ip;
183   int search = 0;
184   
185   putip((char *)&from_ip,&nmb->additional->rdata[2]);
186   ip = from_ip;
187   
188   DEBUG(3,("Name registration for name %s at %s - ",
189                    namestr(question),inet_ntoa(ip)));
190   
191   if (group)
192     {
193       /* apparently we should return 255.255.255.255 for group queries
194          (email from MS) */
195       ip = *interpret_addr2("255.255.255.255");
196     }
197   
198   if (!(d = find_req_subnet(p->ip, bcast)))
199   {
200     DEBUG(3,("reply_name_reg: subnet %s not known\n",
201                                 inet_ntoa(p->ip)));
202     return;
203   }
204
205   if (bcast)
206         search |= FIND_LOCAL;
207   else
208         search |= FIND_WINS;
209
210   /* see if the name already exists */
211   n = find_name_search(&d, question, search, from_ip);
212   
213   if (n)
214   {
215     DEBUG(3,("found\n"));
216     if (!group) /* unique names */
217         {
218           if (n->source == SELF || NAME_GROUP(n->ip_flgs[0].nb_flags))
219           {
220               /* no-one can register one of samba's names, nor can they
221                  register a name that's a group name as a unique name */
222               
223               success = False;
224           }
225           else if(!ip_equal(ip, n->ip_flgs[0].ip))
226           {
227               /* XXXX rfc1001.txt says:
228                * if we are doing secured WINS, we must send a Wait-Acknowledge
229                * packet (WACK) to the person who wants the name, then do a
230                * name query on the person who currently owns the unique name.
231                * if the current owner still says they own it, the person who wants
232                    * the name can't have it. if they do not, or are not alive, they can.
233                */
234
235           secured_redirect = True;
236
237               reply_name = &n->name;
238           }
239           else
240           {
241               n->ip_flgs[0].ip = ip;
242               n->death_time = ttl?p->timestamp+ttl*3:0;
243               DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip_flgs[0].ip)));
244           }
245         }
246     else
247         {
248           /* refresh the name */
249           if (n->source != SELF)
250           {
251               n->death_time = ttl?p->timestamp + ttl*3:0;
252           }
253         }
254
255     /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
256     /* names that people have checked for and not found get DNSFAILed. 
257        we need to update the name record if someone then registers */
258
259     if (n->source == DNSFAIL)
260       n->source = REGISTER;
261
262   }
263   else
264   {
265       DEBUG(3,("not found\n"));
266       /* add the name to our name/subnet, or WINS, database */
267       n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
268                                 True,!bcast);
269   }
270   
271   /* if samba owns a unique name on a subnet, then it must respond and
272      disallow the attempted registration. if the registration is
273      successful by broadcast, only then is there no need to respond
274      (implicit registration: see rfc1001.txt 15.2.1).
275    */
276
277   if (bcast && success) return;
278   
279   if (secured_redirect)
280   {
281     char rdata[2];
282
283     /* XXXX i am confused. RSVAL or SSVAL? assume NMB byte ordering */
284     RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
285   
286     /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3 
287        type  = 0x0a; see rfc1002.txt 4.2.1.3 
288        class = 0x01; see rfc1002.txt 4.2.16
289      */
290
291     /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
292     reply_netbios_packet(p,nmb->header.name_trn_id,
293                        0,NMB_WAIT_ACK,NMB_WAIT_ACK,False,
294                        reply_name, 0x0a, 0x01,
295                        15*1000, /* 15 seconds long enough to wait? */
296                        rdata, 2);
297
298     /* initiate some enquiries to the current owner. */
299         queue_netbios_packet(d,ClientNMB,NMB_QUERY,
300                          NAME_REGISTER_CHALLENGE,
301                          reply_name->name,reply_name->name_type,
302                          nb_flags,0,0,NULL,NULL,
303                          False, False, n->ip_flgs[0].ip, p->ip);
304   }
305   else
306   {
307     /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.13-14
308        or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
309      */
310
311         send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
312                         success, nmb->header.nm_flags.recursion_desired,
313                         reply_name, nb_flags, ttl, ip);
314   }
315 }
316
317 /* this is used to sort names for a name status into a sensible order
318    we put our own names first, then in alphabetical order */
319 static int status_compare(char *n1,char *n2)
320 {
321   extern pstring myname;
322   int l1,l2,l3;
323
324   /* its a bit tricky because the names are space padded */
325   for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
326   for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
327   l3 = strlen(myname);
328
329   if ((l1==l3) && strncmp(n1,myname,l3) == 0 && 
330       (l2!=l3 || strncmp(n2,myname,l3) != 0))
331     return -1;
332
333   if ((l2==l3) && strncmp(n2,myname,l3) == 0 && 
334       (l1!=l3 || strncmp(n1,myname,l3) != 0))
335     return 1;
336
337   return memcmp(n1,n2,18);
338 }
339
340
341 /****************************************************************************
342   reply to a name status query
343
344   combine the list of the local interface on which the query was made with
345   the names registered via wins.
346   ****************************************************************************/
347 void reply_name_status(struct packet_struct *p)
348 {
349   struct nmb_packet *nmb = &p->packet.nmb;
350   char *qname   = nmb->question.question_name.name;
351   int ques_type = nmb->question.question_name.name_type;
352   char rdata[MAX_DGRAM_SIZE];
353   char *countptr, *buf, *bufend, *buf0;
354   int names_added,i;
355   struct name_record *n;
356   struct subnet_record *d = NULL;
357   int search = FIND_SELF | FIND_WINS | FIND_LOCAL;
358
359   /* NOTE: we always treat a name status lookup as a bcast */ 
360   if (!(d = find_req_subnet(p->ip, True)))
361   {
362     DEBUG(3,("Name status req: bcast %s not known\n",
363                         inet_ntoa(p->ip)));
364     return;
365   }
366
367   DEBUG(3,("Name status for name %s %s\n",
368            namestr(&nmb->question.question_name), 
369            inet_ntoa(p->ip)));
370
371   n = find_name_search(&d, &nmb->question.question_name,
372                                 search, p->ip);
373   
374   if (!n) return;
375   
376   /* XXXX hack, we should calculate exactly how many will fit */
377   bufend = &rdata[MAX_DGRAM_SIZE] - 18;
378   countptr = buf = rdata;
379   buf += 1;
380   buf0 = buf;
381
382   names_added = 0;
383
384   n = d->namelist;
385
386   while (buf < bufend) 
387   {
388     if (n->source == SELF)
389     {
390       int name_type = n->name.name_type;
391       
392       /* check if we want to exclude other workgroup names
393              from the response. if we don't exclude them, windows clients
394              get confused and will respond with an error for NET VIEW */
395       
396       if (!strequal(n->name.name,"*") &&
397           !strequal(n->name.name,"__SAMBA__") &&
398           (name_type < 0x1b || name_type >= 0x20 || 
399            ques_type < 0x1b || ques_type >= 0x20 ||
400            strequal(qname, n->name.name)))
401       {
402         /* start with first bit of putting info in buffer: the name */
403         bzero(buf,18);
404             sprintf(buf,"%-15.15s",n->name.name);
405         strupper(buf);
406         
407         /* put name type and netbios flags in buffer */
408         buf[15] = name_type;
409         buf[16]  = n->ip_flgs[0].nb_flags;
410         
411         buf += 18;
412       
413         names_added++;
414       }
415     }
416
417     /* remove duplicate names */
418     qsort(buf0,names_added,18,QSORT_CAST status_compare);
419
420     for (i=1;i<names_added;i++) {
421       if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
422         names_added--;
423         if (names_added == i) break;
424         memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
425         i--;
426       }
427     }
428
429     buf = buf0 + 18*names_added;
430
431     n = n->next;
432
433     if (!n)
434     {
435       /* end of this name list: add wins names too? */
436       struct subnet_record *w_d;
437
438       if (!(w_d = wins_subnet)) break;
439
440       if (w_d != d)
441       {
442         d = w_d;
443         n = d->namelist; /* start on the wins name list */
444       }
445         }
446         if (!n) break;
447   }
448   
449   SCVAL(countptr,0,names_added);
450   
451   /* XXXXXXX we should fill in more fields of the statistics structure */
452   bzero(buf,64);
453   {
454     extern int num_good_sends,num_good_receives;
455     SIVAL(buf,20,num_good_sends);
456     SIVAL(buf,24,num_good_receives);
457   }
458   
459   buf += 46;
460   
461   /* Send a POSITIVE NAME STATUS RESPONSE */
462   reply_netbios_packet(p,nmb->header.name_trn_id,
463                            0,NMB_STATUS,0,True,
464                        &nmb->question.question_name,
465                        0x21, 0x01,
466                        0, rdata,PTR_DIFF(buf,rdata));
467 }
468
469
470 /***************************************************************************
471 reply to a name query.
472
473 with broadcast name queries:
474
475         - only reply if the query is for one of YOUR names. all other machines on
476           the network will be doing the same thing (that is, only replying to a
477           broadcast query if they own it)
478           NOTE: broadcast name queries should only be sent out by a machine
479           if they HAVEN'T been configured to use WINS. this is generally bad news
480           in a wide area tcp/ip network and should be rectified by the systems
481           administrator. USE WINS! :-)
482         - the exception to this is if the query is for a Primary Domain Controller
483           type name (0x1b), in which case, a reply is sent.
484
485         - NEVER send a negative response to a broadcast query. no-one else will!
486
487 with directed name queries:
488
489         - if you are the WINS server, you are expected to respond with either
490       a negative response, a positive response, or a wait-for-acknowledgement
491       packet, and then later on a pos/neg response.
492
493 ****************************************************************************/
494 void reply_name_query(struct packet_struct *p)
495 {
496   struct nmb_packet *nmb = &p->packet.nmb;
497   struct nmb_name *question = &nmb->question.question_name;
498   int name_type = question->name_type;
499   BOOL bcast = nmb->header.nm_flags.bcast;
500   int ttl=0;
501   int rcode = 0;
502   int nb_flags = 0;
503   struct in_addr retip;
504   char rdata[6];
505   struct subnet_record *d = NULL;
506   BOOL success = True;
507   struct name_record *n = NULL;
508
509   /* directed queries are for WINS server: broadcasts are local SELF queries.
510      the exception is Domain Master names.  */
511
512   int search = bcast ? FIND_LOCAL | FIND_WINS: FIND_WINS;
513
514   if (search & FIND_LOCAL)
515   {
516     if (!(d = find_req_subnet(p->ip, bcast)))
517     {
518       DEBUG(3,("name query: bcast %s not known\n",
519                                     inet_ntoa(p->ip)));
520       success = False;
521     }
522   }
523   else
524   {
525     if (!(d = wins_subnet))
526     {
527       DEBUG(3,("name query: wins search %s not known\n",
528                                     inet_ntoa(p->ip)));
529       success = False;
530     }
531   }
532
533   DEBUG(3,("Name query from %s for name %s<0x%x>\n", 
534                   inet_ntoa(p->ip), question->name, question->name_type));
535   
536   if (search == 0)
537   {
538     /* eh? no criterion for searching database. help! */
539     success = False;
540   }
541
542   if (!bcast && (name_type == 0x1d) && lp_wins_support())
543   {
544     /* see WINS manager HELP - 'How WINS Handles Special Names' */
545     /* a WINS query (unicasted) for a 0x1d name must always return False */
546     success = False;
547   }
548
549   if (success)
550   {
551     /* look up the name in the cache */
552     n = find_name_search(&d, question, search, p->ip);
553
554     /* it is a name that already failed DNS lookup or it's expired */
555     if (n && (n->source == DNSFAIL ||
556               (n->death_time && n->death_time < p->timestamp)))
557     {
558       success = False;
559     }
560    
561     /* do we want to do dns lookups? */
562     /* XXXX this DELAYS nmbd while it does a search. not a good idea
563        but there's no pleasant alternative. phil@hands.com suggested
564        making the name a full DNS name, which would succeed / fail
565        much quicker.
566      */
567     if (success && !n && (lp_wins_proxy() || !bcast))
568     {
569       n = dns_name_search(question, p->timestamp);
570     }
571   }
572
573   if (!n) success = False;
574   
575   if (success)
576   {
577       if (bcast && n->source != SELF && name_type != 0x1b)
578       {
579         /* don't respond to broadcast queries unless the query is for
580            a name we own or it is for a Primary Domain Controller name */
581
582             if (!lp_wins_proxy() || 
583             same_net(p->ip,n->ip_flgs[0].ip,*iface_nmask(p->ip)))
584         {
585               /* never reply with a negative response to broadcast queries */
586               return;
587         }
588       }
589       
590       /* name is directed query, or it's self, or it's a Domain Master type
591          name, or we're replying on behalf of a caller because they are on a
592          different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
593          should be switched off in environments where broadcasts are forwarded
594        */
595
596       /* XXXX note: for proxy servers, we should forward the query on to
597          another WINS server if the name is not in our database, or we are
598          not a WINS server ourselves
599        */
600       ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
601       retip = n->ip_flgs[0].ip;
602       nb_flags = n->ip_flgs[0].nb_flags;
603   }
604
605   if (!success && bcast) return; /* never reply negative response to bcasts */
606
607   /* if the IP is 0 then substitute my IP */
608   if (zero_ip(retip)) retip = *iface_ip(p->ip);
609
610   /* SPECIAL CASE... If we are a WINS server and the request is explicitly
611      *to* the WINS server and the name type is WORKGROUP<0x1e> we should 
612      respond with the local broadcast address 255.255.255.255.
613    */
614   if(!bcast && (name_type == 0x1e) && lp_wins_support())
615     retip = *interpret_addr2("255.255.255.255");
616
617   if (success)
618   {
619       rcode = 0;
620       DEBUG(3,("OK %s\n",inet_ntoa(retip)));      
621   }
622   else
623   {
624       rcode = 3;
625       DEBUG(3,("UNKNOWN\n"));      
626   }
627   
628   if (success)
629   {
630       rdata[0] = nb_flags;
631       rdata[1] = 0;
632       putip(&rdata[2],(char *)&retip);
633   }
634   
635   reply_netbios_packet(p,nmb->header.name_trn_id,
636                            rcode,NMB_QUERY,0,True,
637                        &nmb->question.question_name,
638                0x20, 0x01,
639                        ttl,
640                        rdata, success ? 6 : 0);
641 }