includes.h: Added USE_SETSID for SGI.
[Samba/gbeck.git] / source / nameservreply.c
blob9e46b80303922a8efde1aa9f0a48e96e0b8fc2a2
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, BOOL recurse,
46 struct nmb_name *reply_name, int nb_flags, int ttl,
47 struct in_addr ip)
49 char rdata[6];
50 struct packet_struct p;
52 int rcode = 0;
54 if (success == False)
56 /* NEGATIVE RESPONSE */
57 rcode = 6;
59 else if (opcode == NMB_REG && recurse == False)
61 /* END-NODE CHALLENGE REGISTRATION RESPONSE */
62 rcode = 0;
65 rdata[0] = nb_flags;
66 rdata[1] = 0;
67 putip(&rdata[2],(char *)&ip);
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;
75 reply_netbios_packet(&p,name_trn_id,
76 rcode,opcode,opcode,recurse,
77 reply_name, 0x20, 0x1,
78 ttl,
79 rdata, 6);
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)
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);
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);
102 /****************************************************************************
103 reply to a name release
104 ****************************************************************************/
105 void reply_name_release(struct packet_struct *p)
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;
116 putip((char *)&ip,&nmb->additional->rdata[2]);
118 DEBUG(3,("Name release on name %s\n",
119 namestr(&nmb->question.question_name)));
121 if (!(d = find_req_subnet(p->ip, bcast)))
123 DEBUG(3,("response packet: bcast %s not known\n",
124 inet_ntoa(p->ip)));
125 return;
128 if (bcast)
129 search |= FIND_LOCAL;
130 else
131 search |= FIND_WINS;
133 n = find_name_search(&d, &nmb->question.question_name,
134 search, ip);
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)))
140 success = True;
142 DEBUG(5, ("reply_name_release: Removing name %s on subnet %s\n",
143 namestr(&nmb->question.question_name), inet_ntoa(d->bcast_ip)));
144 remove_name(d,n);
145 n = NULL;
148 if (bcast) return;
150 /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
151 send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
152 success, nmb->header.nm_flags.recursion_desired,
153 &nmb->question.question_name, nb_flags, 0, ip);
157 /****************************************************************************
158 reply to a reg request
159 **************************************************************************/
160 void reply_name_reg(struct packet_struct *p)
162 struct nmb_packet *nmb = &p->packet.nmb;
163 struct nmb_name *question = &nmb->question.question_name;
165 struct nmb_name *reply_name = question;
167 char *qname = question->name;
168 int qname_type = question->name_type;
170 BOOL bcast = nmb->header.nm_flags.bcast;
172 int ttl = GET_TTL(nmb->additional->ttl);
173 int nb_flags = nmb->additional->rdata[0];
174 BOOL group = NAME_GROUP(nb_flags);
176 struct subnet_record *d = NULL;
177 struct name_record *n = NULL;
179 BOOL success = True;
180 BOOL secured_redirect = False;
182 struct in_addr ip, from_ip;
183 int search = 0;
185 putip((char *)&from_ip,&nmb->additional->rdata[2]);
186 ip = from_ip;
188 DEBUG(3,("Name registration for name %s at %s - ",
189 namestr(question),inet_ntoa(ip)));
191 if (group)
193 /* apparently we should return 255.255.255.255 for group queries
194 (email from MS) */
195 ip = *interpret_addr2("255.255.255.255");
198 if (!(d = find_req_subnet(p->ip, bcast)))
200 DEBUG(3,("reply_name_reg: subnet %s not known\n",
201 inet_ntoa(p->ip)));
202 return;
205 if (bcast)
206 search |= FIND_LOCAL;
207 else
208 search |= FIND_WINS;
210 /* see if the name already exists */
211 n = find_name_search(&d, question, search, from_ip);
213 if (n)
215 DEBUG(3,("found\n"));
216 if (!group) /* unique names */
218 if (n->source == SELF || NAME_GROUP(n->ip_flgs[0].nb_flags))
220 /* no-one can register one of samba's names, nor can they
221 register a name that's a group name as a unique name */
223 success = False;
225 else if(!ip_equal(ip, n->ip_flgs[0].ip))
227 /* XXXX rfc1001.txt says:
228 * if we are doing secured WINS, we must send a Wait-Acknowledge
229 * packet (WACK) to the person who wants the name, then do a
230 * name query on the person who currently owns the unique name.
231 * if the current owner still says they own it, the person who wants
232 * the name can't have it. if they do not, or are not alive, they can.
235 secured_redirect = True;
237 reply_name = &n->name;
239 else
241 n->ip_flgs[0].ip = ip;
242 n->death_time = ttl?p->timestamp+ttl*3:0;
243 DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip_flgs[0].ip)));
246 else
248 /* refresh the name */
249 if (n->source != SELF)
251 n->death_time = ttl?p->timestamp + ttl*3:0;
255 /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
256 /* names that people have checked for and not found get DNSFAILed.
257 we need to update the name record if someone then registers */
259 if (n->source == DNSFAIL)
260 n->source = REGISTER;
263 else
265 DEBUG(3,("not found\n"));
266 /* add the name to our name/subnet, or WINS, database */
267 n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
268 True,!bcast);
271 /* if samba owns a unique name on a subnet, then it must respond and
272 disallow the attempted registration. if the registration is
273 successful by broadcast, only then is there no need to respond
274 (implicit registration: see rfc1001.txt 15.2.1).
277 if (bcast && success) return;
279 if (secured_redirect)
281 char rdata[2];
283 /* XXXX i am confused. RSVAL or SSVAL? assume NMB byte ordering */
284 RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
286 /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
287 type = 0x0a; see rfc1002.txt 4.2.1.3
288 class = 0x01; see rfc1002.txt 4.2.16
291 /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
292 reply_netbios_packet(p,nmb->header.name_trn_id,
293 0,NMB_WAIT_ACK,NMB_WAIT_ACK,False,
294 reply_name, 0x0a, 0x01,
295 15*1000, /* 15 seconds long enough to wait? */
296 rdata, 2);
298 /* initiate some enquiries to the current owner. */
299 queue_netbios_packet(d,ClientNMB,NMB_QUERY,
300 NAME_REGISTER_CHALLENGE,
301 reply_name->name,reply_name->name_type,
302 nb_flags,0,0,NULL,NULL,
303 False, False, n->ip_flgs[0].ip, p->ip);
305 else
307 /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.13-14
308 or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
311 send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
312 success, nmb->header.nm_flags.recursion_desired,
313 reply_name, nb_flags, ttl, ip);
317 /* this is used to sort names for a name status into a sensible order
318 we put our own names first, then in alphabetical order */
319 static int status_compare(char *n1,char *n2)
321 extern pstring myname;
322 int l1,l2,l3;
324 /* its a bit tricky because the names are space padded */
325 for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
326 for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
327 l3 = strlen(myname);
329 if ((l1==l3) && strncmp(n1,myname,l3) == 0 &&
330 (l2!=l3 || strncmp(n2,myname,l3) != 0))
331 return -1;
333 if ((l2==l3) && strncmp(n2,myname,l3) == 0 &&
334 (l1!=l3 || strncmp(n1,myname,l3) != 0))
335 return 1;
337 return memcmp(n1,n2,18);
341 /****************************************************************************
342 reply to a name status query
344 combine the list of the local interface on which the query was made with
345 the names registered via wins.
346 ****************************************************************************/
347 void reply_name_status(struct packet_struct *p)
349 struct nmb_packet *nmb = &p->packet.nmb;
350 char *qname = nmb->question.question_name.name;
351 int ques_type = nmb->question.question_name.name_type;
352 char rdata[MAX_DGRAM_SIZE];
353 char *countptr, *buf, *bufend, *buf0;
354 int names_added,i;
355 struct name_record *n;
356 struct subnet_record *d = NULL;
357 int search = FIND_SELF | FIND_WINS | FIND_LOCAL;
359 /* NOTE: we always treat a name status lookup as a bcast */
360 if (!(d = find_req_subnet(p->ip, True)))
362 DEBUG(3,("Name status req: bcast %s not known\n",
363 inet_ntoa(p->ip)));
364 return;
367 DEBUG(3,("Name status for name %s %s\n",
368 namestr(&nmb->question.question_name),
369 inet_ntoa(p->ip)));
371 n = find_name_search(&d, &nmb->question.question_name,
372 search, p->ip);
374 if (!n) return;
376 /* XXXX hack, we should calculate exactly how many will fit */
377 bufend = &rdata[MAX_DGRAM_SIZE] - 18;
378 countptr = buf = rdata;
379 buf += 1;
380 buf0 = buf;
382 names_added = 0;
384 n = d->namelist;
386 while (buf < bufend)
388 if (n->source == SELF)
390 int name_type = n->name.name_type;
392 /* check if we want to exclude other workgroup names
393 from the response. if we don't exclude them, windows clients
394 get confused and will respond with an error for NET VIEW */
396 if (!strequal(n->name.name,"*") &&
397 !strequal(n->name.name,"__SAMBA__") &&
398 (name_type < 0x1b || name_type >= 0x20 ||
399 ques_type < 0x1b || ques_type >= 0x20 ||
400 strequal(qname, n->name.name)))
402 /* start with first bit of putting info in buffer: the name */
403 bzero(buf,18);
404 sprintf(buf,"%-15.15s",n->name.name);
405 strupper(buf);
407 /* put name type and netbios flags in buffer */
408 buf[15] = name_type;
409 buf[16] = n->ip_flgs[0].nb_flags;
411 buf += 18;
413 names_added++;
417 /* remove duplicate names */
418 qsort(buf0,names_added,18,QSORT_CAST status_compare);
420 for (i=1;i<names_added;i++) {
421 if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
422 names_added--;
423 if (names_added == i) break;
424 memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
425 i--;
429 buf = buf0 + 18*names_added;
431 n = n->next;
433 if (!n)
435 /* end of this name list: add wins names too? */
436 struct subnet_record *w_d;
438 if (!(w_d = wins_subnet)) break;
440 if (w_d != d)
442 d = w_d;
443 n = d->namelist; /* start on the wins name list */
446 if (!n) break;
449 SCVAL(countptr,0,names_added);
451 /* XXXXXXX we should fill in more fields of the statistics structure */
452 bzero(buf,64);
454 extern int num_good_sends,num_good_receives;
455 SIVAL(buf,20,num_good_sends);
456 SIVAL(buf,24,num_good_receives);
459 buf += 46;
461 /* Send a POSITIVE NAME STATUS RESPONSE */
462 reply_netbios_packet(p,nmb->header.name_trn_id,
463 0,NMB_STATUS,0,True,
464 &nmb->question.question_name,
465 0x21, 0x01,
466 0, rdata,PTR_DIFF(buf,rdata));
470 /***************************************************************************
471 reply to a name query.
473 with broadcast name queries:
475 - only reply if the query is for one of YOUR names. all other machines on
476 the network will be doing the same thing (that is, only replying to a
477 broadcast query if they own it)
478 NOTE: broadcast name queries should only be sent out by a machine
479 if they HAVEN'T been configured to use WINS. this is generally bad news
480 in a wide area tcp/ip network and should be rectified by the systems
481 administrator. USE WINS! :-)
482 - the exception to this is if the query is for a Primary Domain Controller
483 type name (0x1b), in which case, a reply is sent.
485 - NEVER send a negative response to a broadcast query. no-one else will!
487 with directed name queries:
489 - if you are the WINS server, you are expected to respond with either
490 a negative response, a positive response, or a wait-for-acknowledgement
491 packet, and then later on a pos/neg response.
493 ****************************************************************************/
494 void reply_name_query(struct packet_struct *p)
496 struct nmb_packet *nmb = &p->packet.nmb;
497 struct nmb_name *question = &nmb->question.question_name;
498 int name_type = question->name_type;
499 BOOL bcast = nmb->header.nm_flags.bcast;
500 int ttl=0;
501 int rcode = 0;
502 int nb_flags = 0;
503 struct in_addr retip;
504 char rdata[6];
505 struct subnet_record *d = NULL;
506 BOOL success = True;
507 struct name_record *n = NULL;
509 /* directed queries are for WINS server: broadcasts are local SELF queries.
510 the exception is Domain Master names. */
512 int search = bcast ? FIND_LOCAL | FIND_WINS: FIND_WINS;
514 if (search & FIND_LOCAL)
516 if (!(d = find_req_subnet(p->ip, bcast)))
518 DEBUG(3,("name query: bcast %s not known\n",
519 inet_ntoa(p->ip)));
520 success = False;
523 else
525 if (!(d = wins_subnet))
527 DEBUG(3,("name query: wins search %s not known\n",
528 inet_ntoa(p->ip)));
529 success = False;
533 DEBUG(3,("Name query from %s for name %s<0x%x>\n",
534 inet_ntoa(p->ip), question->name, question->name_type));
536 if (search == 0)
538 /* eh? no criterion for searching database. help! */
539 success = False;
542 if (!bcast && (name_type == 0x1d) && lp_wins_support())
544 /* see WINS manager HELP - 'How WINS Handles Special Names' */
545 /* a WINS query (unicasted) for a 0x1d name must always return False */
546 success = False;
549 if (success)
551 /* look up the name in the cache */
552 n = find_name_search(&d, question, search, p->ip);
554 /* it is a name that already failed DNS lookup or it's expired */
555 if (n && (n->source == DNSFAIL ||
556 (n->death_time && n->death_time < p->timestamp)))
558 success = False;
561 /* do we want to do dns lookups? */
562 /* XXXX this DELAYS nmbd while it does a search. not a good idea
563 but there's no pleasant alternative. phil@hands.com suggested
564 making the name a full DNS name, which would succeed / fail
565 much quicker.
567 if (success && !n && (lp_wins_proxy() || !bcast))
569 n = dns_name_search(question, p->timestamp);
573 if (!n) success = False;
575 if (success)
577 if (bcast && n->source != SELF && name_type != 0x1b)
579 /* don't respond to broadcast queries unless the query is for
580 a name we own or it is for a Primary Domain Controller name */
582 if (!lp_wins_proxy() ||
583 same_net(p->ip,n->ip_flgs[0].ip,*iface_nmask(p->ip)))
585 /* never reply with a negative response to broadcast queries */
586 return;
590 /* name is directed query, or it's self, or it's a Domain Master type
591 name, or we're replying on behalf of a caller because they are on a
592 different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
593 should be switched off in environments where broadcasts are forwarded
596 /* XXXX note: for proxy servers, we should forward the query on to
597 another WINS server if the name is not in our database, or we are
598 not a WINS server ourselves
600 ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
601 retip = n->ip_flgs[0].ip;
602 nb_flags = n->ip_flgs[0].nb_flags;
605 if (!success && bcast) return; /* never reply negative response to bcasts */
607 /* if the IP is 0 then substitute my IP */
608 if (zero_ip(retip)) retip = *iface_ip(p->ip);
610 /* SPECIAL CASE... If we are a WINS server and the request is explicitly
611 *to* the WINS server and the name type is WORKGROUP<0x1e> we should
612 respond with the local broadcast address 255.255.255.255.
614 if(!bcast && (name_type == 0x1e) && lp_wins_support())
615 retip = *interpret_addr2("255.255.255.255");
617 if (success)
619 rcode = 0;
620 DEBUG(3,("OK %s\n",inet_ntoa(retip)));
622 else
624 rcode = 3;
625 DEBUG(3,("UNKNOWN\n"));
628 if (success)
630 rdata[0] = nb_flags;
631 rdata[1] = 0;
632 putip(&rdata[2],(char *)&retip);
635 reply_netbios_packet(p,nmb->header.name_trn_id,
636 rcode,NMB_QUERY,0,True,
637 &nmb->question.question_name,
638 0x20, 0x01,
639 ttl,
640 rdata, success ? 6 : 0);