summaryrefslogtreecommitdiffstats
path: root/source/nameservreply.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/nameservreply.c')
-rw-r--r--source/nameservreply.c641
1 files changed, 0 insertions, 641 deletions
diff --git a/source/nameservreply.c b/source/nameservreply.c
deleted file mode 100644
index 9e46b803039..00000000000
--- a/source/nameservreply.c
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Module name: nameservreply.c
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
- 04 jul 96: lkcl@pires.co.uk
- created module nameservreply containing NetBIOS reply functions
-
-*/
-
-#include "includes.h"
-
-extern int ClientNMB;
-
-extern int DEBUGLEVEL;
-
-extern struct in_addr wins_ip;
-
-/****************************************************************************
-send a registration / release response: pos/neg
-**************************************************************************/
-static void send_name_response(int fd, struct in_addr from_ip,
- int name_trn_id, int opcode, BOOL success, BOOL recurse,
- struct nmb_name *reply_name, int nb_flags, int ttl,
- struct in_addr ip)
-{
- char rdata[6];
- struct packet_struct p;
-
- int rcode = 0;
-
- if (success == False)
- {
- /* NEGATIVE RESPONSE */
- rcode = 6;
- }
- else if (opcode == NMB_REG && recurse == False)
- {
- /* END-NODE CHALLENGE REGISTRATION RESPONSE */
- rcode = 0;
- }
-
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&ip);
-
- p.ip = from_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- reply_netbios_packet(&p,name_trn_id,
- rcode,opcode,opcode,recurse,
- reply_name, 0x20, 0x1,
- ttl,
- rdata, 6);
-}
-
-/****************************************************************************
- add a netbios entry. respond to the (possibly new) owner.
- **************************************************************************/
-void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
- uint16 response_id,
- struct nmb_name *name,
- int nb_flags, int ttl, struct in_addr register_ip,
- BOOL new_owner, struct in_addr reply_to_ip)
-{
- /* register the old or the new owners' ip */
- add_netbios_entry(d,name->name,name->name_type,
- nb_flags,ttl,REGISTER,register_ip,False,True);
-
- /* reply yes or no to the host that requested the name */
- send_name_response(fd,from_ip, response_id, NMB_REG,
- new_owner, False,
- name, nb_flags, ttl, reply_to_ip);
-}
-
-
-/****************************************************************************
-reply to a name release
-****************************************************************************/
-void reply_name_release(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct in_addr ip;
- int nb_flags = nmb->additional->rdata[0];
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct name_record *n;
- struct subnet_record *d = NULL;
- int search = 0;
- BOOL success = False;
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- DEBUG(3,("Name release on name %s\n",
- namestr(&nmb->question.question_name)));
-
- if (!(d = find_req_subnet(p->ip, bcast)))
- {
- DEBUG(3,("response packet: bcast %s not known\n",
- inet_ntoa(p->ip)));
- return;
- }
-
- if (bcast)
- search |= FIND_LOCAL;
- else
- search |= FIND_WINS;
-
- n = find_name_search(&d, &nmb->question.question_name,
- search, ip);
-
- /* XXXX under what conditions should we reject the removal?? */
- /* For now - remove if the names match and the group bit matches. */
- if (n && (n->source != SELF) && (NAME_GROUP(n->ip_flgs[0].nb_flags) == NAME_GROUP(nb_flags)))
- {
- success = True;
-
- DEBUG(5, ("reply_name_release: Removing name %s on subnet %s\n",
- namestr(&nmb->question.question_name), inet_ntoa(d->bcast_ip)));
- remove_name(d,n);
- n = NULL;
- }
-
- if (bcast) return;
-
- /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
- send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
- success, nmb->header.nm_flags.recursion_desired,
- &nmb->question.question_name, nb_flags, 0, ip);
-}
-
-
-/****************************************************************************
-reply to a reg request
-**************************************************************************/
-void reply_name_reg(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
-
- struct nmb_name *reply_name = question;
-
- char *qname = question->name;
- int qname_type = question->name_type;
-
- BOOL bcast = nmb->header.nm_flags.bcast;
-
- int ttl = GET_TTL(nmb->additional->ttl);
- int nb_flags = nmb->additional->rdata[0];
- BOOL group = NAME_GROUP(nb_flags);
-
- struct subnet_record *d = NULL;
- struct name_record *n = NULL;
-
- BOOL success = True;
- BOOL secured_redirect = False;
-
- struct in_addr ip, from_ip;
- int search = 0;
-
- putip((char *)&from_ip,&nmb->additional->rdata[2]);
- ip = from_ip;
-
- DEBUG(3,("Name registration for name %s at %s - ",
- namestr(question),inet_ntoa(ip)));
-
- if (group)
- {
- /* apparently we should return 255.255.255.255 for group queries
- (email from MS) */
- ip = *interpret_addr2("255.255.255.255");
- }
-
- if (!(d = find_req_subnet(p->ip, bcast)))
- {
- DEBUG(3,("reply_name_reg: subnet %s not known\n",
- inet_ntoa(p->ip)));
- return;
- }
-
- if (bcast)
- search |= FIND_LOCAL;
- else
- search |= FIND_WINS;
-
- /* see if the name already exists */
- n = find_name_search(&d, question, search, from_ip);
-
- if (n)
- {
- DEBUG(3,("found\n"));
- if (!group) /* unique names */
- {
- if (n->source == SELF || NAME_GROUP(n->ip_flgs[0].nb_flags))
- {
- /* no-one can register one of samba's names, nor can they
- register a name that's a group name as a unique name */
-
- success = False;
- }
- else if(!ip_equal(ip, n->ip_flgs[0].ip))
- {
- /* XXXX rfc1001.txt says:
- * if we are doing secured WINS, we must send a Wait-Acknowledge
- * packet (WACK) to the person who wants the name, then do a
- * name query on the person who currently owns the unique name.
- * if the current owner still says they own it, the person who wants
- * the name can't have it. if they do not, or are not alive, they can.
- */
-
- secured_redirect = True;
-
- reply_name = &n->name;
- }
- else
- {
- n->ip_flgs[0].ip = ip;
- n->death_time = ttl?p->timestamp+ttl*3:0;
- DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip_flgs[0].ip)));
- }
- }
- else
- {
- /* refresh the name */
- if (n->source != SELF)
- {
- n->death_time = ttl?p->timestamp + ttl*3:0;
- }
- }
-
- /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
- /* names that people have checked for and not found get DNSFAILed.
- we need to update the name record if someone then registers */
-
- if (n->source == DNSFAIL)
- n->source = REGISTER;
-
- }
- else
- {
- DEBUG(3,("not found\n"));
- /* add the name to our name/subnet, or WINS, database */
- n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
- True,!bcast);
- }
-
- /* if samba owns a unique name on a subnet, then it must respond and
- disallow the attempted registration. if the registration is
- successful by broadcast, only then is there no need to respond
- (implicit registration: see rfc1001.txt 15.2.1).
- */
-
- if (bcast && success) return;
-
- if (secured_redirect)
- {
- char rdata[2];
-
- /* XXXX i am confused. RSVAL or SSVAL? assume NMB byte ordering */
- RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
-
- /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
- type = 0x0a; see rfc1002.txt 4.2.1.3
- class = 0x01; see rfc1002.txt 4.2.16
- */
-
- /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- 0,NMB_WAIT_ACK,NMB_WAIT_ACK,False,
- reply_name, 0x0a, 0x01,
- 15*1000, /* 15 seconds long enough to wait? */
- rdata, 2);
-
- /* initiate some enquiries to the current owner. */
- queue_netbios_packet(d,ClientNMB,NMB_QUERY,
- NAME_REGISTER_CHALLENGE,
- reply_name->name,reply_name->name_type,
- nb_flags,0,0,NULL,NULL,
- False, False, n->ip_flgs[0].ip, p->ip);
- }
- else
- {
- /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.13-14
- or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
- */
-
- send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
- success, nmb->header.nm_flags.recursion_desired,
- reply_name, nb_flags, ttl, ip);
- }
-}
-
-/* this is used to sort names for a name status into a sensible order
- we put our own names first, then in alphabetical order */
-static int status_compare(char *n1,char *n2)
-{
- extern pstring myname;
- int l1,l2,l3;
-
- /* its a bit tricky because the names are space padded */
- for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
- for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
- l3 = strlen(myname);
-
- if ((l1==l3) && strncmp(n1,myname,l3) == 0 &&
- (l2!=l3 || strncmp(n2,myname,l3) != 0))
- return -1;
-
- if ((l2==l3) && strncmp(n2,myname,l3) == 0 &&
- (l1!=l3 || strncmp(n1,myname,l3) != 0))
- return 1;
-
- return memcmp(n1,n2,18);
-}
-
-
-/****************************************************************************
- reply to a name status query
-
- combine the list of the local interface on which the query was made with
- the names registered via wins.
- ****************************************************************************/
-void reply_name_status(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- int ques_type = nmb->question.question_name.name_type;
- char rdata[MAX_DGRAM_SIZE];
- char *countptr, *buf, *bufend, *buf0;
- int names_added,i;
- struct name_record *n;
- struct subnet_record *d = NULL;
- int search = FIND_SELF | FIND_WINS | FIND_LOCAL;
-
- /* NOTE: we always treat a name status lookup as a bcast */
- if (!(d = find_req_subnet(p->ip, True)))
- {
- DEBUG(3,("Name status req: bcast %s not known\n",
- inet_ntoa(p->ip)));
- return;
- }
-
- DEBUG(3,("Name status for name %s %s\n",
- namestr(&nmb->question.question_name),
- inet_ntoa(p->ip)));
-
- n = find_name_search(&d, &nmb->question.question_name,
- search, p->ip);
-
- if (!n) return;
-
- /* XXXX hack, we should calculate exactly how many will fit */
- bufend = &rdata[MAX_DGRAM_SIZE] - 18;
- countptr = buf = rdata;
- buf += 1;
- buf0 = buf;
-
- names_added = 0;
-
- n = d->namelist;
-
- while (buf < bufend)
- {
- if (n->source == SELF)
- {
- int name_type = n->name.name_type;
-
- /* check if we want to exclude other workgroup names
- from the response. if we don't exclude them, windows clients
- get confused and will respond with an error for NET VIEW */
-
- if (!strequal(n->name.name,"*") &&
- !strequal(n->name.name,"__SAMBA__") &&
- (name_type < 0x1b || name_type >= 0x20 ||
- ques_type < 0x1b || ques_type >= 0x20 ||
- strequal(qname, n->name.name)))
- {
- /* start with first bit of putting info in buffer: the name */
- bzero(buf,18);
- sprintf(buf,"%-15.15s",n->name.name);
- strupper(buf);
-
- /* put name type and netbios flags in buffer */
- buf[15] = name_type;
- buf[16] = n->ip_flgs[0].nb_flags;
-
- buf += 18;
-
- names_added++;
- }
- }
-
- /* remove duplicate names */
- qsort(buf0,names_added,18,QSORT_CAST status_compare);
-
- for (i=1;i<names_added;i++) {
- if (memcmp(buf0 + 18*i,buf0 + 18*(i-1),16) == 0) {
- names_added--;
- if (names_added == i) break;
- memmove(buf0 + 18*i,buf0 + 18*(i+1),18*(names_added-i));
- i--;
- }
- }
-
- buf = buf0 + 18*names_added;
-
- n = n->next;
-
- if (!n)
- {
- /* end of this name list: add wins names too? */
- struct subnet_record *w_d;
-
- if (!(w_d = wins_subnet)) break;
-
- if (w_d != d)
- {
- d = w_d;
- n = d->namelist; /* start on the wins name list */
- }
- }
- if (!n) break;
- }
-
- SCVAL(countptr,0,names_added);
-
- /* XXXXXXX we should fill in more fields of the statistics structure */
- bzero(buf,64);
- {
- extern int num_good_sends,num_good_receives;
- SIVAL(buf,20,num_good_sends);
- SIVAL(buf,24,num_good_receives);
- }
-
- buf += 46;
-
- /* Send a POSITIVE NAME STATUS RESPONSE */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- 0,NMB_STATUS,0,True,
- &nmb->question.question_name,
- 0x21, 0x01,
- 0, rdata,PTR_DIFF(buf,rdata));
-}
-
-
-/***************************************************************************
-reply to a name query.
-
-with broadcast name queries:
-
- - only reply if the query is for one of YOUR names. all other machines on
- the network will be doing the same thing (that is, only replying to a
- broadcast query if they own it)
- NOTE: broadcast name queries should only be sent out by a machine
- if they HAVEN'T been configured to use WINS. this is generally bad news
- in a wide area tcp/ip network and should be rectified by the systems
- administrator. USE WINS! :-)
- - the exception to this is if the query is for a Primary Domain Controller
- type name (0x1b), in which case, a reply is sent.
-
- - NEVER send a negative response to a broadcast query. no-one else will!
-
-with directed name queries:
-
- - if you are the WINS server, you are expected to respond with either
- a negative response, a positive response, or a wait-for-acknowledgement
- packet, and then later on a pos/neg response.
-
-****************************************************************************/
-void reply_name_query(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
- int name_type = question->name_type;
- BOOL bcast = nmb->header.nm_flags.bcast;
- int ttl=0;
- int rcode = 0;
- int nb_flags = 0;
- struct in_addr retip;
- char rdata[6];
- struct subnet_record *d = NULL;
- BOOL success = True;
- struct name_record *n = NULL;
-
- /* directed queries are for WINS server: broadcasts are local SELF queries.
- the exception is Domain Master names. */
-
- int search = bcast ? FIND_LOCAL | FIND_WINS: FIND_WINS;
-
- if (search & FIND_LOCAL)
- {
- if (!(d = find_req_subnet(p->ip, bcast)))
- {
- DEBUG(3,("name query: bcast %s not known\n",
- inet_ntoa(p->ip)));
- success = False;
- }
- }
- else
- {
- if (!(d = wins_subnet))
- {
- DEBUG(3,("name query: wins search %s not known\n",
- inet_ntoa(p->ip)));
- success = False;
- }
- }
-
- DEBUG(3,("Name query from %s for name %s<0x%x>\n",
- inet_ntoa(p->ip), question->name, question->name_type));
-
- if (search == 0)
- {
- /* eh? no criterion for searching database. help! */
- success = False;
- }
-
- if (!bcast && (name_type == 0x1d) && lp_wins_support())
- {
- /* see WINS manager HELP - 'How WINS Handles Special Names' */
- /* a WINS query (unicasted) for a 0x1d name must always return False */
- success = False;
- }
-
- if (success)
- {
- /* look up the name in the cache */
- n = find_name_search(&d, question, search, p->ip);
-
- /* it is a name that already failed DNS lookup or it's expired */
- if (n && (n->source == DNSFAIL ||
- (n->death_time && n->death_time < p->timestamp)))
- {
- success = False;
- }
-
- /* do we want to do dns lookups? */
- /* XXXX this DELAYS nmbd while it does a search. not a good idea
- but there's no pleasant alternative. phil@hands.com suggested
- making the name a full DNS name, which would succeed / fail
- much quicker.
- */
- if (success && !n && (lp_wins_proxy() || !bcast))
- {
- n = dns_name_search(question, p->timestamp);
- }
- }
-
- if (!n) success = False;
-
- if (success)
- {
- if (bcast && n->source != SELF && name_type != 0x1b)
- {
- /* don't respond to broadcast queries unless the query is for
- a name we own or it is for a Primary Domain Controller name */
-
- if (!lp_wins_proxy() ||
- same_net(p->ip,n->ip_flgs[0].ip,*iface_nmask(p->ip)))
- {
- /* never reply with a negative response to broadcast queries */
- return;
- }
- }
-
- /* name is directed query, or it's self, or it's a Domain Master type
- name, or we're replying on behalf of a caller because they are on a
- different subnet and cannot hear the broadcast. XXXX lp_wins_proxy
- should be switched off in environments where broadcasts are forwarded
- */
-
- /* XXXX note: for proxy servers, we should forward the query on to
- another WINS server if the name is not in our database, or we are
- not a WINS server ourselves
- */
- ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
- retip = n->ip_flgs[0].ip;
- nb_flags = n->ip_flgs[0].nb_flags;
- }
-
- if (!success && bcast) return; /* never reply negative response to bcasts */
-
- /* if the IP is 0 then substitute my IP */
- if (zero_ip(retip)) retip = *iface_ip(p->ip);
-
- /* SPECIAL CASE... If we are a WINS server and the request is explicitly
- *to* the WINS server and the name type is WORKGROUP<0x1e> we should
- respond with the local broadcast address 255.255.255.255.
- */
- if(!bcast && (name_type == 0x1e) && lp_wins_support())
- retip = *interpret_addr2("255.255.255.255");
-
- if (success)
- {
- rcode = 0;
- DEBUG(3,("OK %s\n",inet_ntoa(retip)));
- }
- else
- {
- rcode = 3;
- DEBUG(3,("UNKNOWN\n"));
- }
-
- if (success)
- {
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&retip);
- }
-
- reply_netbios_packet(p,nmb->header.name_trn_id,
- rcode,NMB_QUERY,0,True,
- &nmb->question.question_name,
- 0x20, 0x01,
- ttl,
- rdata, success ? 6 : 0);
-}