documented the new syntax of lmhosts
[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-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->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->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))
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 = 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)));
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 luke is 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, 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
314 /****************************************************************************
315   reply to a name status query
316
317   combine the list of the local interface on which the query was made with
318   the names registered via wins.
319   ****************************************************************************/
320 void reply_name_status(struct packet_struct *p)
321 {
322   struct nmb_packet *nmb = &p->packet.nmb;
323   char *qname   = nmb->question.question_name.name;
324   int ques_type = nmb->question.question_name.name_type;
325   char rdata[MAX_DGRAM_SIZE];
326   char *countptr, *buf, *bufend;
327   int names_added;
328   struct name_record *n;
329   struct subnet_record *d = NULL;
330   int search = FIND_SELF | FIND_WINS;
331
332   BOOL bcast = nmb->header.nm_flags.bcast;
333   
334   if (!(d = find_req_subnet(p->ip, bcast)))
335   {
336     DEBUG(3,("Name status req: bcast %s not known\n",
337                         inet_ntoa(p->ip)));
338     return;
339   }
340
341   DEBUG(3,("Name status for name %s %s\n",
342            namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
343   
344   if (bcast)
345     search |= FIND_LOCAL;
346
347   n = find_name_search(&d, &nmb->question.question_name,
348                                 search, p->ip);
349   
350   if (!n) return;
351   
352   /* XXXX hack, we should calculate exactly how many will fit */
353   bufend = &rdata[MAX_DGRAM_SIZE] - 18;
354   countptr = buf = rdata;
355   buf += 1;
356   
357   names_added = 0;
358
359   n = d->namelist;
360
361   while (buf < bufend) 
362   {
363     if (n->source == SELF)
364     {
365       int name_type = n->name.name_type;
366       
367       /* check if we want to exclude other workgroup names
368              from the response. if we don't exclude them, windows clients
369              get confused and will respond with an error for NET VIEW */
370       
371       if (name_type < 0x1b || name_type > 0x20 || 
372           ques_type < 0x1b || ques_type > 0x20 ||
373           strequal(qname, n->name.name))
374       {
375         /* start with first bit of putting info in buffer: the name */
376         bzero(buf,18);
377             sprintf(buf,"%-15.15s",n->name.name);
378         strupper(buf);
379         
380         /* put name type and netbios flags in buffer */
381         buf[15] = name_type;
382         buf[16]  = n->nb_flags;
383         
384         buf += 18;
385       
386         names_added++;
387       }
388     }
389
390     n = n->next;
391
392     if (!n)
393     {
394       /* end of this name list: add wins names too? */
395       struct subnet_record *w_d;
396
397       if (!(w_d = find_subnet(ipgrp))) break;
398
399       if (w_d != d)
400       {
401         d = w_d;
402         n = d->namelist; /* start on the wins name list */
403       }
404         }
405         if (!n) break;
406   }
407   
408   SCVAL(countptr,0,names_added);
409   
410   /* XXXXXXX we should fill in more fields of the statistics structure */
411   bzero(buf,64);
412   {
413     extern int num_good_sends,num_good_receives;
414     SIVAL(buf,20,num_good_sends);
415     SIVAL(buf,24,num_good_receives);
416   }
417   
418   buf += 46;
419   
420   /* Send a POSITIVE NAME STATUS RESPONSE */
421   reply_netbios_packet(p,nmb->header.name_trn_id,
422                            0,NMB_STATUS,0,True,
423                        &nmb->question.question_name,
424                        nmb->question.question_type,
425                        nmb->question.question_class,
426                        0,
427                        rdata,PTR_DIFF(buf,rdata));
428 }
429
430
431 /***************************************************************************
432 reply to a name query.
433
434 with broadcast name queries:
435
436         - only reply if the query is for one of YOUR names. all other machines on
437           the network will be doing the same thing (that is, only replying to a
438           broadcast query if they own it)
439           NOTE: broadcast name queries should only be sent out by a machine
440           if they HAVEN'T been configured to use WINS. this is generally bad news
441           in a wide area tcp/ip network and should be rectified by the systems
442           administrator. USE WINS! :-)
443         - the exception to this is if the query is for a Primary Domain Controller
444           type name (0x1b), in which case, a reply is sent.
445
446         - NEVER send a negative response to a broadcast query. no-one else will!
447
448 with directed name queries:
449
450         - if you are the WINS server, you are expected to respond with either
451       a negative response, a positive response, or a wait-for-acknowledgement
452       packet, and then later on a pos/neg response.
453
454 ****************************************************************************/
455 void reply_name_query(struct packet_struct *p)
456 {
457   struct nmb_packet *nmb = &p->packet.nmb;
458   struct nmb_name *question = &nmb->question.question_name;
459   int name_type = question->name_type;
460   BOOL bcast = nmb->header.nm_flags.bcast;
461   int ttl=0;
462   int rcode = 0;
463   int nb_flags = 0;
464   struct in_addr retip;
465   char rdata[6];
466   struct subnet_record *d = NULL;
467   BOOL success = True;
468   struct name_record *n;
469
470   /* directed queries are for WINS server: broadcasts are local SELF queries.
471      the exception is Domain Master names.  */
472
473   int search = bcast ? FIND_LOCAL | FIND_SELF : FIND_WINS;
474   
475   if (name_type == 0x1b || name_type == 0x0 || name_type == 0x20)
476   {
477     search |= FIND_WINS;
478   }
479
480   if (search | FIND_LOCAL)
481   {
482     if (!(d = find_req_subnet(p->ip, bcast)))
483     {
484       DEBUG(3,("name query: bcast %s not known\n",
485                                     inet_ntoa(p->ip)));
486       success = False;
487     }
488   }
489   else
490   {
491     if (!(d = find_subnet(ipgrp)))
492     {
493       DEBUG(3,("name query: wins search %s not known\n",
494                                     inet_ntoa(p->ip)));
495       success = False;
496     }
497   }
498
499   DEBUG(3,("Name query "));
500   
501   if (search == 0)
502   {
503     /* eh? no criterion for searching database. help! */
504     success = False;
505   }
506
507   if (success && (n = search_for_name(&d,question,p->ip,p->timestamp, search)))
508   {
509       /* don't respond to broadcast queries unless the query is for
510          a name we own or it is for a Primary Domain Controller name */
511
512       if (bcast && n->source != SELF && name_type != 0x1b) {
513             if (!lp_wins_proxy() || same_net(p->ip,n->ip,*iface_nmask(p->ip))) {
514               /* never reply with a negative response to broadcast queries */
515               return;
516             }
517           }
518       
519       /* name is directed query, or it's self, or it's a Domain Master type
520          name, or we're replying on behalf of a caller because they are on a
521          different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
522          should be switched off in environments where broadcasts are forwarded
523        */
524
525       /* XXXX note: for proxy servers, we should forward the query on to
526          another WINS server if the name is not in our database, or we are
527          not a WINS server ourselves
528        */
529       ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
530       retip = n->ip;
531       nb_flags = n->nb_flags;
532   }
533   else
534   {
535       if (bcast) return; /* never reply negative response to bcasts */
536       success = False;
537   }
538   
539   /* if the IP is 0 then substitute my IP */
540   if (zero_ip(retip)) retip = *iface_ip(p->ip);
541
542   if (success)
543   {
544       rcode = 0;
545       DEBUG(3,("OK %s\n",inet_ntoa(retip)));      
546   }
547   else
548   {
549       rcode = 3;
550       DEBUG(3,("UNKNOWN\n"));      
551   }
552   
553   if (success)
554   {
555       rdata[0] = nb_flags;
556       rdata[1] = 0;
557       putip(&rdata[2],(char *)&retip);
558   }
559   
560   reply_netbios_packet(p,nmb->header.name_trn_id,
561                            rcode,NMB_QUERY,0,True,
562                        &nmb->question.question_name,
563                        nmb->question.question_type,
564                        nmb->question.question_class,
565                        ttl,
566                        rdata, success ? 6 : 0);
567 }
568
569