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