cd26be5a8b2cf9a31b69b7b99c87d7a181160527
[samba.git] / source / 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 reply to a name release
44 ****************************************************************************/
45 void reply_name_release(struct packet_struct *p)
46 {
47   struct nmb_packet *nmb = &p->packet.nmb;
48   struct in_addr ip;
49   int nb_flags = nmb->additional->rdata[0];
50   BOOL bcast = nmb->header.nm_flags.bcast;
51   struct name_record *n;
52   struct subnet_record *d = NULL;
53   int search = 0;
54   
55   putip((char *)&ip,&nmb->additional->rdata[2]);  
56   
57   DEBUG(3,("Name release on name %s\n",
58            namestr(&nmb->question.question_name)));
59   
60   if (!(d = find_req_subnet(p->ip, bcast)))
61   {
62     DEBUG(3,("response packet: bcast %s not known\n",
63                         inet_ntoa(p->ip)));
64     return;
65   }
66
67   if (bcast)
68         search &= FIND_LOCAL;
69   else
70         search &= FIND_WINS;
71
72   n = find_name_search(&d, &nmb->question.question_name, 
73                                         search, ip);
74   
75   /* XXXX under what conditions should we reject the removal?? */
76   if (n && n->nb_flags == nb_flags)
77     {
78       /* success = True; */
79       
80       remove_name(d,n);
81       n = NULL;
82     }
83   
84   if (bcast) return;
85   
86   /* Send a NAME RELEASE RESPONSE */
87   send_name_response(p->fd, nmb->header.name_trn_id, NMB_REL,
88                                                 True, False,
89                                                 &nmb->question.question_name, nb_flags, 0, ip);
90 }
91
92
93 /****************************************************************************
94 send a registration / release response: pos/neg
95 **************************************************************************/
96 void send_name_response(int fd,
97                                 int name_trn_id, int opcode, BOOL success, BOOL recurse,
98                                 struct nmb_name *reply_name, int nb_flags, int ttl,
99                                 struct in_addr ip)
100 {
101   char rdata[6];
102   struct packet_struct p;
103
104   int rcode = 0;  
105
106   if (success == False)
107   {
108     /* NEGATIVE RESPONSE */
109     rcode = 6;
110   }
111   else if (opcode == NMB_REG && recurse == False)
112   {
113     /* END-NODE CHALLENGE REGISTRATION RESPONSE */
114         rcode = 0;
115   }
116   
117   rdata[0] = nb_flags;
118   rdata[1] = 0;
119   putip(&rdata[2],(char *)&ip);
120   
121   p.ip = ip;
122   p.port = NMB_PORT;
123   p.fd = fd;
124   p.timestamp = time(NULL);
125   p.packet_type = NMB_PACKET;
126
127   reply_netbios_packet(&p,name_trn_id,
128                        rcode,opcode,recurse,
129                        reply_name, 0x20, 0x1,
130                        ttl, 
131                        rdata, 6);
132 }
133
134
135 /****************************************************************************
136 reply to a reg request
137 **************************************************************************/
138 void reply_name_reg(struct packet_struct *p)
139 {
140   struct nmb_packet *nmb = &p->packet.nmb;
141   struct nmb_name *question = &nmb->question.question_name;
142   
143   struct nmb_name *reply_name = question;
144
145   char *qname      = question->name;
146   int   qname_type = question->name_type;
147  
148   BOOL bcast = nmb->header.nm_flags.bcast;
149   
150   int ttl = GET_TTL(nmb->additional->ttl);
151   int nb_flags = nmb->additional->rdata[0];
152   BOOL group = NAME_GROUP(nb_flags);
153
154   struct subnet_record *d = NULL;
155   struct name_record *n = NULL;
156
157   BOOL success = True;
158   BOOL secured_redirect = False;
159   BOOL recurse = True; /* true if samba replies yes/no: false if caller
160                           must challenge the current owner of the unique
161                           name: applies to non-secured WINS server only
162                         */
163
164   struct in_addr ip, from_ip;
165   int search = 0;
166   
167   putip((char *)&from_ip,&nmb->additional->rdata[2]);
168   ip = from_ip;
169   
170   DEBUG(3,("Name registration for name %s at %s\n",
171                    namestr(question),inet_ntoa(ip)));
172   
173   if (group)
174     {
175       /* apparently we should return 255.255.255.255 for group queries
176          (email from MS) */
177       ip = ipgrp;
178     }
179   
180   if (!(d = find_req_subnet(p->ip, bcast)))
181   {
182     DEBUG(3,("response packet: bcast %s not known\n",
183                                 inet_ntoa(p->ip)));
184     return;
185   }
186
187   if (bcast)
188         search &= FIND_LOCAL;
189   else
190         search &= FIND_WINS;
191
192   /* see if the name already exists */
193   n = find_name_search(&d, question, search, from_ip);
194   
195   if (n)
196   {
197     if (!group) /* unique names */
198         {
199           if (n->source == SELF || NAME_GROUP(n->nb_flags))
200           {
201               /* no-one can register one of samba's names, nor can they
202                  register a name that's a group name as a unique name */
203               
204               success = False;
205           }
206           else if(!ip_equal(ip, n->ip))
207           {
208 #if 0
209               /* hm. this unique name doesn't belong to them. */
210               
211               /* XXXX rfc1001.txt says:
212                * if we are doing non-secured WINS (which is much simpler) then
213                * we send a message to the person wanting the name saying 'he
214                * owns this name: i don't want to hear from you ever again
215                * until you've checked with him if you can have it!'. we then
216                * abandon the registration. once the person wanting the name
217                * has checked with the current owner, they will repeat the
218                * registration packet if the current owner is dead or doesn't
219                * want the name.
220                */
221
222               /* non-secured WINS implementation: caller is responsible
223                  for checking with current owner of name, then getting back
224                  to us... IF current owner no longer owns the unique name */
225               
226            /* XXXX please note also that samba cannot cope with 
227               _receiving_ such redirecting, non-secured registration
228               packets. code to do this needs to be added.
229             */
230
231           secured_redirect = False;
232               success = False;
233               recurse = False;
234               
235               /* we inform on the current owner to the caller (which is
236                  why it's non-secure */
237               
238               reply_name = &n->name;
239 #else
240               /* XXXX rfc1001.txt says:
241                * if we are doing secured WINS, we must send a Wait-Acknowledge
242                * packet (WACK) to the person who wants the name, then do a
243                * name query on the person who currently owns the unique name.
244                * if the current owner still says they own it, the person who wants
245                    * the name can't have it. if they do not, or are not alive, they can.
246                */
247
248           secured_redirect = True;
249               recurse = False;
250
251               reply_name = &n->name;
252
253 #endif /* 0 */
254
255           }
256           else
257           {
258               n->ip = ip;
259               n->death_time = ttl?p->timestamp+ttl*3:0;
260               DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip)));
261           }
262         }
263     else
264         {
265           /* refresh the name */
266           if (n->source != SELF)
267           {
268               n->death_time = ttl?p->timestamp + ttl*3:0;
269           }
270         }
271
272     /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
273     /* names that people have checked for and not found get DNSFAILed. 
274        we need to update the name record if someone then registers */
275
276     if (n->source == DNSFAIL)
277       n->source = REGISTER;
278
279   }
280   else
281   {
282       /* add the name to our name/subnet, or WINS, database */
283       n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
284                                 True,!bcast);
285   }
286   
287   /* if samba owns a unique name on a subnet, then it must respond and
288      disallow the attempted registration. if the registration is
289      successful by broadcast, only then is there no need to respond
290      (implicit registration: see rfc1001.txt 15.2.1).
291    */
292
293   if (bcast && success) return;
294   
295   if (secured_redirect)
296   {
297     char rdata[2];
298
299     /* XXXX luke is confused. RSVAL or SSVAL? assume NMB byte ordering */
300     RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
301   
302     /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3 
303        type  = 0x0a; see rfc1002.txt 4.2.1.3 
304        class = 0x01; see rfc1002.txt 4.2.16
305      */
306
307     /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
308     reply_netbios_packet(p,nmb->header.name_trn_id,
309                        0,NMB_WAIT_ACK,False,
310                        reply_name, 0x0a, 0x01,
311                        15*1000, /* 15 seconds long enough to wait? */
312                        rdata, 2);
313
314     /* initiate some enquiries to the current owner. */
315         queue_netbios_packet(d,ClientNMB,NMB_QUERY,
316                                                  NAME_REGISTER_CHALLENGE,
317                                                  reply_name->name,reply_name->name_type,nb_flags,0,
318                                                  False, False, n->ip, p->ip);
319   }
320   else
321   {
322     /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.13-14
323        or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
324      */
325
326         send_name_response(p->fd, nmb->header.name_trn_id, NMB_REG,
327                                                 success, recurse,
328                                                 reply_name, nb_flags, ttl, ip);
329   }
330 }
331
332
333 /****************************************************************************
334 reply to a name status query
335 ****************************************************************************/
336 void reply_name_status(struct packet_struct *p)
337 {
338   struct nmb_packet *nmb = &p->packet.nmb;
339   char *qname   = nmb->question.question_name.name;
340   int ques_type = nmb->question.question_name.name_type;
341   char rdata[MAX_DGRAM_SIZE];
342   char *countptr, *buf, *bufend;
343   int names_added;
344   struct name_record *n;
345   struct subnet_record *d = NULL;
346
347   BOOL bcast = nmb->header.nm_flags.bcast;
348   
349   if (!(d = find_req_subnet(p->ip, bcast)))
350   {
351     DEBUG(3,("Name status req: bcast %s not known\n",
352                         inet_ntoa(p->ip)));
353     return;
354   }
355
356   DEBUG(3,("Name status for name %s %s\n",
357            namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
358   
359   n = find_name_search(&d, &nmb->question.question_name,
360                                 FIND_SELF|FIND_LOCAL,
361                                 p->ip);
362   
363   if (!n) return;
364   
365   /* XXXX hack, we should calculate exactly how many will fit */
366   bufend = &rdata[MAX_DGRAM_SIZE] - 18;
367   countptr = buf = rdata;
368   buf += 1;
369   
370   names_added = 0;
371   
372   for (n = d->namelist ; n && buf < bufend; n = n->next) 
373     {
374       int name_type = n->name.name_type;
375       
376       if (n->source != SELF) continue;
377       
378       /* start with first bit of putting info in buffer: the name */
379       
380       bzero(buf,18);
381           sprintf(buf,"%-15.15s",n->name.name);
382       strupper(buf);
383       
384       /* now check if we want to exclude other workgroup names
385          from the response. if we don't exclude them, windows clients
386          get confused and will respond with an error for NET VIEW */
387       
388       if (name_type >= 0x1b && name_type <= 0x20 && 
389           ques_type >= 0x1b && ques_type <= 0x20)
390         {
391           if (!strequal(qname, n->name.name)) continue;
392         }
393       
394       /* carry on putting name info in buffer */
395       
396       buf[15] = name_type;
397       buf[16]  = n->nb_flags;
398       
399       buf += 18;
400       
401       names_added++;
402     }
403   
404   SCVAL(countptr,0,names_added);
405   
406   /* XXXXXXX we should fill in more fields of the statistics structure */
407   bzero(buf,64);
408   {
409     extern int num_good_sends,num_good_receives;
410     SIVAL(buf,20,num_good_sends);
411     SIVAL(buf,24,num_good_receives);
412   }
413   
414   SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
415   
416   buf += 64;
417   
418   /* Send a POSITIVE NAME STATUS RESPONSE */
419   reply_netbios_packet(p,nmb->header.name_trn_id,
420                            0,0,True,
421                        &nmb->question.question_name,
422                        nmb->question.question_type,
423                        nmb->question.question_class,
424                        0,
425                        rdata,PTR_DIFF(buf,rdata));
426 }
427
428
429 /***************************************************************************
430 reply to a name query.
431
432 with broadcast name queries:
433
434         - only reply if the query is for one of YOUR names. all other machines on
435           the network will be doing the same thing (that is, only replying to a
436           broadcast query if they own it)
437           NOTE: broadcast name queries should only be sent out by a machine
438           if they HAVEN'T been configured to use WINS. this is generally bad news
439           in a wide area tcp/ip network and should be rectified by the systems
440           administrator. USE WINS! :-)
441         - the exception to this is if the query is for a Primary Domain Controller
442           type name (0x1b), in which case, a reply is sent.
443
444         - NEVER send a negative response to a broadcast query. no-one else will!
445
446 with directed name queries:
447
448         - if you are the WINS server, you are expected to respond with either
449       a negative response, a positive response, or a wait-for-acknowledgement
450       packet, and then later on a pos/neg response.
451
452 ****************************************************************************/
453 void reply_name_query(struct packet_struct *p)
454 {
455   struct nmb_packet *nmb = &p->packet.nmb;
456   struct nmb_name *question = &nmb->question.question_name;
457   int name_type = question->name_type;
458   BOOL bcast = nmb->header.nm_flags.bcast;
459   int ttl=0;
460   int rcode = 0;
461   int nb_flags = 0;
462   struct in_addr retip;
463   char rdata[6];
464   struct subnet_record *d = NULL;
465   BOOL success = True;
466   struct name_record *n;
467
468   /* directed queries are for WINS server: broadcasts are local SELF queries.
469      the exception is PDC names.  */
470
471   int search = bcast ? FIND_LOCAL | FIND_SELF : FIND_WINS;
472   
473   if (name_type == 0x1b)
474   {
475     /* even if it's a broadcast, we don't ignore queries for PDC names */
476     search |= FIND_WINS;
477     search &= ~FIND_SELF;
478   }
479
480   if (!(d = find_req_subnet(p->ip, bcast)))
481   {
482     DEBUG(3,("name query: bcast %s not known\n",
483                                   inet_ntoa(p->ip)));
484     success = False;
485   }
486
487   DEBUG(3,("Name query "));
488   
489   if (search == 0)
490   {
491     /* eh? no criterion for searching database. help! */
492     success = False;
493   }
494
495   if (success && (n = search_for_name(&d,question,p->ip,p->timestamp, search)))
496   {
497       /* don't respond to broadcast queries unless the query is for
498          a name we own or it is for a Primary Domain Controller name */
499
500       if (bcast && n->source != SELF && name_type != 0x1b) {
501             if (!lp_wins_proxy() || same_net(p->ip,n->ip,*iface_nmask(p->ip))) {
502               /* never reply with a negative response to broadcast queries */
503               return;
504             }
505           }
506       
507       /* name is directed query, or it's self, or it's a PDC type name, or
508              we're replying on behalf of a caller because they are on a different
509          subnet and cannot hear the broadcast. XXXX lp_wins_proxy should be
510                  switched off in environments where broadcasts are forwarded */
511
512       /* XXXX note: for proxy servers, we should forward the query on to
513          another WINS server if the name is not in our database, or we are
514          not a WINS server ourselves
515        */
516       ttl = n->death_time - p->timestamp;
517       retip = n->ip;
518       nb_flags = n->nb_flags;
519   }
520   else
521   {
522       if (bcast) return; /* never reply negative response to bcasts */
523       success = False;
524   }
525   
526   /* if the IP is 0 then substitute my IP */
527   if (zero_ip(retip)) retip = *iface_ip(p->ip);
528
529   if (success)
530   {
531       rcode = 0;
532       DEBUG(3,("OK %s\n",inet_ntoa(retip)));      
533   }
534   else
535   {
536       rcode = 3;
537       DEBUG(3,("UNKNOWN\n"));      
538   }
539   
540   if (success)
541   {
542       rdata[0] = nb_flags;
543       rdata[1] = 0;
544       putip(&rdata[2],(char *)&retip);
545   }
546   
547   reply_netbios_packet(p,nmb->header.name_trn_id,
548                            rcode,0,True,
549                        &nmb->question.question_name,
550                        nmb->question.question_type,
551                        nmb->question.question_class,
552                        ttl,
553                        rdata, success ? 6 : 0);
554 }
555
556