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