This is the ubiqx binary tree and linked list library.
[Samba.git] / source / nameservreply.c
blob5b9c476549d487be8f16b8e894dfdc43e8139ba2
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
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.
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.
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.
21 Module name: nameservreply.c
23 Revision History:
25 14 jan 96: lkcl@pires.co.uk
26 added multiple workgroup domain master support
28 04 jul 96: lkcl@pires.co.uk
29 created module nameservreply containing NetBIOS reply functions
33 #include "includes.h"
35 extern int ClientNMB;
37 extern int DEBUGLEVEL;
39 extern struct in_addr wins_ip;
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,
46 BOOL recursion_available, BOOL recursion_desired,
47 struct nmb_name *reply_name, int nb_flags, int ttl,
48 struct in_addr ip)
50 char rdata[6];
51 struct packet_struct p;
53 int rcode = 0;
55 if (success == False)
57 /* NEGATIVE RESPONSE */
58 rcode = 6;
60 else if (opcode == NMB_REG && !recursion_available)
62 /* END-NODE CHALLENGE REGISTRATION RESPONSE */
63 rcode = 0;
66 rdata[0] = nb_flags;
67 rdata[1] = 0;
68 putip(&rdata[2],(char *)&ip);
70 p.ip = from_ip;
71 p.port = NMB_PORT;
72 p.fd = fd;
73 p.timestamp = time(NULL);
74 p.packet_type = NMB_PACKET;
76 reply_netbios_packet(&p,name_trn_id,
77 rcode,opcode,opcode,
78 recursion_available, recursion_desired,
79 reply_name, 0x20, 0x1,
80 ttl,
81 rdata, 6);
84 /****************************************************************************
85 add a netbios entry. respond to the (possibly new) owner.
86 **************************************************************************/
87 void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
88 uint16 response_id,
89 struct nmb_name *name,
90 int nb_flags, int ttl, struct in_addr register_ip,
91 BOOL new_owner, struct in_addr reply_to_ip)
93 /* register the old or the new owners' ip */
94 add_netbios_entry(d,name->name,name->name_type,
95 nb_flags,ttl,REGISTER,register_ip,False,True);
97 /* reply yes or no to the host that requested the name */
98 /* see rfc1002.txt - 4.2.10 and 4.2.11 */
99 send_name_response(fd,from_ip, response_id, NMB_REG,
100 new_owner,
101 True, True,
102 name, nb_flags, ttl, reply_to_ip);
106 /****************************************************************************
107 reply to a name release
108 ****************************************************************************/
109 void reply_name_release(struct packet_struct *p)
111 struct nmb_packet *nmb = &p->packet.nmb;
112 struct in_addr ip;
113 int nb_flags = nmb->additional->rdata[0];
114 BOOL bcast = nmb->header.nm_flags.bcast;
115 struct name_record *n;
116 struct subnet_record *d = NULL;
117 int search = 0;
118 BOOL success = False;
120 putip((char *)&ip,&nmb->additional->rdata[2]);
122 DEBUG(3,("Name release on name %s\n",
123 namestr(&nmb->question.question_name)));
125 if (!(d = find_req_subnet(p->ip, bcast)))
127 DEBUG(3,("response packet: bcast %s not known\n",
128 inet_ntoa(p->ip)));
129 return;
132 if (bcast)
133 search |= FIND_LOCAL;
134 else
135 search |= FIND_WINS;
137 n = find_name_search(&d, &nmb->question.question_name,
138 search, ip);
140 /* XXXX under what conditions should we reject the removal?? */
141 /* For now - remove if the names match and the group bit matches. */
142 if (n && (n->source != SELF) && (NAME_GROUP(n->ip_flgs[0].nb_flags) == NAME_GROUP(nb_flags)))
144 success = True;
146 /* If it's a group name not ending in 1c (not an internet name)
147 then just allow it to fade out of existance by timing out. */
148 if(NAME_GROUP(nb_flags) && (n->name.name_type != 0x1c))
150 DEBUG(5, ("reply_name_release: Allow group name %s(%d) to fade out on \
151 subnet %s\n", namestr(&nmb->question.question_name), n->name.name_type,
152 inet_ntoa(d->bcast_ip)));
154 else
156 DEBUG(5, ("reply_name_release: Removing name %s on subnet %s\n",
157 namestr(&nmb->question.question_name), inet_ntoa(d->bcast_ip)));
158 remove_name(d,n);
159 n = NULL;
163 if (bcast) return;
165 /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
166 send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
167 success, False, False,
168 &nmb->question.question_name, nb_flags, 0, ip);
172 /****************************************************************************
173 reply to a reg request
174 **************************************************************************/
175 void reply_name_reg(struct packet_struct *p)
177 struct nmb_packet *nmb = &p->packet.nmb;
178 struct nmb_name *question = &nmb->question.question_name;
180 struct nmb_name *reply_name = question;
182 char *qname = question->name;
183 int qname_type = question->name_type;
185 BOOL bcast = nmb->header.nm_flags.bcast;
187 int ttl = GET_TTL(nmb->additional->ttl);
188 int nb_flags = nmb->additional->rdata[0];
189 BOOL group = NAME_GROUP(nb_flags);
191 struct subnet_record *d = NULL;
192 struct name_record *n = NULL;
194 BOOL success = True;
195 BOOL secured_redirect = False;
197 struct in_addr ip, from_ip;
198 int search = 0;
200 putip((char *)&from_ip,&nmb->additional->rdata[2]);
201 ip = from_ip;
203 DEBUG(3,("Name registration for name %s at %s - ",
204 namestr(question),inet_ntoa(ip)));
206 if (group)
208 /* apparently we should return 255.255.255.255 for group queries
209 (email from MS) */
210 ip = *interpret_addr2("255.255.255.255");
213 if (!(d = find_req_subnet(p->ip, bcast)))
215 DEBUG(3,("reply_name_reg: subnet %s not known\n",
216 inet_ntoa(p->ip)));
217 return;
220 if (bcast)
221 search |= FIND_LOCAL;
222 else
223 search |= FIND_WINS;
225 /* see if the name already exists */
226 n = find_name_search(&d, question, search, from_ip);
228 if (n)
230 DEBUG(3,("found\n"));
231 if (!group) /* unique names */
233 if (n->source == SELF || NAME_GROUP(n->ip_flgs[0].nb_flags))
235 /* no-one can register one of samba's names, nor can they
236 register a name that's a group name as a unique name */
238 success = False;
240 else if(!ip_equal(ip, n->ip_flgs[0].ip))
242 /* XXXX rfc1001.txt says:
243 * if we are doing secured WINS, we must send a Wait-Acknowledge
244 * packet (WACK) to the person who wants the name, then do a
245 * name query on the person who currently owns the unique name.
246 * if the current owner still says they own it, the person who wants
247 * the name can't have it. if they do not, or are not alive, they can.
250 secured_redirect = True;
252 reply_name = &n->name;
254 else
256 n->ip_flgs[0].ip = ip;
257 n->death_time = ttl?p->timestamp+ttl*3:0;
258 DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip_flgs[0].ip)));
261 else
263 /* refresh the name */
264 if (n->source != SELF)
266 n->death_time = ttl?p->timestamp + ttl*3:0;
270 /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
271 /* names that people have checked for and not found get DNSFAILed.
272 we need to update the name record if someone then registers */
274 if (n->source == DNSFAIL)
275 n->source = REGISTER;
278 else
280 DEBUG(3,("not found\n"));
281 /* add the name to our name/subnet, or WINS, database */
282 n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
283 True,!bcast);
286 /* if samba owns a unique name on a subnet, then it must respond and
287 disallow the attempted registration. if the registration is
288 successful by broadcast, only then is there no need to respond
289 (implicit registration: see rfc1001.txt 15.2.1).
292 if (bcast && success) return;
294 if (secured_redirect)
296 char rdata[2];
298 /* XXXX i am confused. RSVAL or SSVAL? assume NMB byte ordering */
299 RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
301 /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
302 type = 0x0a; see rfc1002.txt 4.2.1.3
303 class = 0x01; see rfc1002.txt 4.2.16
306 /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
307 reply_netbios_packet(p,nmb->header.name_trn_id,
308 0,NMB_WAIT_ACK,NMB_WAIT_ACK,
309 False,False,
310 reply_name, 0x0a, 0x01,
311 15*1000, /* 15 seconds long enough to wait? */
312 rdata, 2);
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,
318 nb_flags,0,0,NULL,NULL,
319 False, False,
320 n->ip_flgs[0].ip, p->ip);
322 else
324 /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.5-6
325 or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
328 send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
329 success,
330 True, True,
331 reply_name, nb_flags, ttl, ip);
335 /* this is used to sort names for a name status into a sensible order
336 we put our own names first, then in alphabetical order */
337 static int status_compare(char *n1,char *n2)
339 extern pstring myname;
340 int l1,l2,l3;
342 /* its a bit tricky because the names are space padded */
343 for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
344 for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
345 l3 = strlen(myname);
347 if ((l1==l3) && strncmp(n1,myname,l3) == 0 &&
348 (l2!=l3 || strncmp(n2,myname,l3) != 0))
349 return -1;
351 if ((l2==l3) && strncmp(n2,myname,l3) == 0 &&
352 (l1!=l3 || strncmp(n1,myname,l3) != 0))
353 return 1;
355 return memcmp(n1,n2,18);
359 /****************************************************************************
360 reply to a name status query
362 combine the list of the local interface on which the query was made with
363 the names registered via wins.
364 ****************************************************************************/
365 void reply_name_status(struct packet_struct *p)
367 struct nmb_packet *nmb = &p->packet.nmb;
368 char *qname = nmb->question.question_name.name;
369 int ques_type = nmb->question.question_name.name_type;
370 char rdata[MAX_DGRAM_SIZE];
371 char *countptr, *buf, *bufend, *buf0;
372 int names_added,i;
373 struct name_record *n;
374 struct subnet_record *d = NULL;
375 int search = FIND_SELF | FIND_WINS | FIND_LOCAL;
377 /* NOTE: we always treat a name status lookup as a bcast */
378 if (!(d = find_req_subnet(p->ip, True)))
380 DEBUG(3,("Name status req: bcast %s not known\n",
381 inet_ntoa(p->ip)));
382 return;
385 DEBUG(3,("Name status for name %s %s\n",
386 namestr(&nmb->question.question_name),
387 inet_ntoa(p->ip)));
389 n = find_name_search(&d, &nmb->question.question_name,
390 search, p->ip);
392 if (!n) return;
394 /* XXXX hack, we should calculate exactly how many will fit */
395 bufend = &rdata[MAX_DGRAM_SIZE] - 18;
396 countptr = buf = rdata;
397 buf += 1;
398 buf0 = buf;
400 names_added = 0;
402 n = d->namelist;
404 while (buf < bufend)
406 if (n->source == SELF)
408 int name_type = n->name.name_type;
410 /* check if we want to exclude other workgroup names
411 from the response. if we don't exclude them, windows clients
412 get confused and will respond with an error for NET VIEW */
414 if (!strequal(n->name.name,"*") &&
415 !strequal(n->name.name,"__SAMBA__") &&
416 (name_type < 0x1b || name_type >= 0x20 ||
417 ques_type < 0x1b || ques_type >= 0x20 ||
418 strequal(qname, n->name.name)))
420 /* start with first bit of putting info in buffer: the name */
421 bzero(buf,18);
422 sprintf(buf,"%-15.15s",n->name.name);
423 strupper(buf);
425 /* put name type and netbios flags in buffer */
426 buf[15] = name_type;
427 buf[16] = n->ip_flgs[0].nb_flags;
429 buf += 18;
431 names_added++;
435 /* remove duplicate names */
436 qsort(buf0,names_added,18,QSORT_CAST status_compare);
438 for (i=1;i<names_added;i++) {
439 if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
440 names_added--;
441 if (names_added == i) break;
442 memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
443 i--;
447 buf = buf0 + 18*names_added;
449 n = n->next;
451 if (!n)
453 /* end of this name list: add wins names too? */
454 struct subnet_record *w_d;
456 if (!(w_d = wins_subnet)) break;
458 if (w_d != d)
460 d = w_d;
461 n = d->namelist; /* start on the wins name list */
464 if (!n) break;
467 SCVAL(countptr,0,names_added);
469 /* XXXXXXX we should fill in more fields of the statistics structure */
470 bzero(buf,64);
472 extern int num_good_sends,num_good_receives;
473 SIVAL(buf,20,num_good_sends);
474 SIVAL(buf,24,num_good_receives);
477 buf += 46;
479 /* Send a POSITIVE NAME STATUS RESPONSE */
480 reply_netbios_packet(p,nmb->header.name_trn_id,
481 0,NMB_STATUS,0,False, False,
482 &nmb->question.question_name,
483 0x21, 0x01,
484 0, rdata,PTR_DIFF(buf,rdata));
488 /***************************************************************************
489 reply to a name query.
491 with broadcast name queries:
493 - only reply if the query is for one of YOUR names. all other machines on
494 the network will be doing the same thing (that is, only replying to a
495 broadcast query if they own it)
496 NOTE: broadcast name queries should only be sent out by a machine
497 if they HAVEN'T been configured to use WINS. this is generally bad news
498 in a wide area tcp/ip network and should be rectified by the systems
499 administrator. USE WINS! :-)
500 - the exception to this is if the query is for a Primary Domain Controller
501 type name (0x1b), in which case, a reply is sent.
503 - NEVER send a negative response to a broadcast query. no-one else will!
505 with directed name queries:
507 - if you are the WINS server, you are expected to respond with either
508 a negative response, a positive response, or a wait-for-acknowledgement
509 packet, and then later on a pos/neg response.
511 ****************************************************************************/
512 void reply_name_query(struct packet_struct *p)
514 struct nmb_packet *nmb = &p->packet.nmb;
515 struct nmb_name *question = &nmb->question.question_name;
516 int name_type = question->name_type;
518 BOOL bcast = nmb->header.nm_flags.bcast;
519 BOOL query_is_to_wins_server = (!bcast &&
520 nmb->header.nm_flags.recursion_desired);
521 int ttl=0;
522 int rcode = 0;
523 int nb_flags = 0;
524 struct in_addr retip;
525 char rdata[6];
526 struct subnet_record *d = NULL;
527 BOOL success = True;
528 struct name_record *n = NULL;
529 BOOL acting_as_wins_server = lp_wins_support();
531 /* directed queries are for WINS server: broadcasts are local SELF queries.
532 the exception is Domain Master names. */
534 if (query_is_to_wins_server)
536 /* queries to the WINS server involve the WINS server subnet */
537 if (!(d = wins_subnet))
539 DEBUG(3,("name query: wins search %s not known\n",
540 inet_ntoa(p->ip)));
541 success = False;
544 else
546 /* queries to the WINS client involve, unfortunately, the WINS subnet
547 because it contains WINS client (SELF) entries, as _well_ as WINS
548 server entries. not good.
551 if (!(d = find_subnet(*iface_bcast(p->ip))))
553 DEBUG(3,("name query: interface for %s not known\n",
554 inet_ntoa(p->ip)));
555 success = False;
559 DEBUG(3,("Name query from %s for name %s<0x%x>\n",
560 inet_ntoa(p->ip), question->name, question->name_type));
562 if (!bcast && (name_type == 0x1d) && lp_wins_support())
564 /* see WINS manager HELP - 'How WINS Handles Special Names' */
565 /* a WINS query (unicasted) for a 0x1d name must always return False */
566 success = False;
569 if (success)
571 /* look up the name in the cache */
572 n = find_name_search(&d, question, FIND_LOCAL, p->ip);
574 /* it is a name that already failed DNS lookup or it's expired */
575 if (n && (n->source == DNSFAIL ||
576 (n->death_time && n->death_time < p->timestamp)))
578 success = False;
581 /* do we want to do dns lookups? */
582 /* XXXX this DELAYS nmbd while it does a search. lp_dns_proxy()
583 can be switched off, to ensure that the blocking doesn't occur.
584 a better solution would be to fork, but this will require a
585 mechanism to carry on processing after the query is resolved
586 (similar to the netbios queue).
588 if (success && !n && (lp_dns_proxy() || !bcast))
590 n = dns_name_search(question, p->timestamp);
594 if (!n) success = False;
596 if (success)
598 if (bcast && n->source != SELF && name_type != 0x1b)
600 /* don't respond to broadcast queries unless the query is for
601 a name we own or it is for a Primary Domain Controller name */
603 if (!lp_wins_proxy() ||
604 same_net(p->ip,n->ip_flgs[0].ip,*iface_nmask(p->ip)))
606 /* never reply with a negative response to broadcast queries */
607 return;
611 /* name is directed query, or it's self, or it's a Domain Master type
612 name, or we're replying on behalf of a caller because they are on a
613 different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
614 should be switched off in environments where broadcasts are forwarded
617 /* XXXX note: for proxy servers, we should forward the query on to
618 another WINS server if the name is not in our database, or we are
619 not a WINS server ourselves
621 ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
622 retip = n->ip_flgs[0].ip;
623 nb_flags = n->ip_flgs[0].nb_flags;
626 if (!success && bcast) return; /* never reply negative response to bcasts */
628 /* if the IP is 0 then substitute my IP */
629 if (zero_ip(retip)) retip = *iface_ip(p->ip);
631 /* SPECIAL CASE... If we are a WINS server and the request is explicitly
632 *to* the WINS server and the name type is WORKGROUP<0x1e> we should
633 respond with the local broadcast address 255.255.255.255.
635 if(!bcast && (name_type == 0x1e) && lp_wins_support())
636 retip = *interpret_addr2("255.255.255.255");
638 if (success)
640 rcode = 0;
641 DEBUG(3,("OK %s\n",inet_ntoa(retip)));
643 else
645 rcode = 3;
646 DEBUG(3,("UNKNOWN\n"));
649 if (success)
651 rdata[0] = nb_flags;
652 rdata[1] = 0;
653 putip(&rdata[2],(char *)&retip);
656 /* see rfc1002.txt 4.2.13 */
658 reply_netbios_packet(p,nmb->header.name_trn_id,
659 rcode,NMB_QUERY,0,
660 (query_is_to_wins_server && acting_as_wins_server ?
661 True : False), /* recursion_available flag */
662 True, /* recursion_desired_flag */
663 &nmb->question.question_name,
664 0x20, 0x01,
665 ttl,
666 rdata, success ? 6 : 0);