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