Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1996
+ 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
extern int DEBUGLEVEL;
-extern struct in_addr ipgrp;
-
-
-/****************************************************************************
- 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, True,
- name, nb_flags, ttl, reply_to_ip);
-}
+extern struct in_addr wins_ip;
/****************************************************************************
send a registration / release response: pos/neg
**************************************************************************/
-void send_name_response(int fd, struct in_addr from_ip,
+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)
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
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;
- }
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
if (bcast)
- search &= FIND_LOCAL;
+ search |= FIND_LOCAL;
else
- search &= FIND_WINS;
+ search |= FIND_WINS;
n = find_name_search(&d, &nmb->question.question_name,
- search, ip);
+ search, ip);
/* XXXX under what conditions should we reject the removal?? */
- if (n && n->ip_flgs[0].nb_flags == nb_flags)
- {
+ /* For now - remove if the names match and the group bit matches. */
+ if (n && (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, False,
- &nmb->question.question_name, nb_flags, 0, ip);
+ success, nmb->header.nm_flags.recursion_desired,
+ &nmb->question.question_name, nb_flags, 0, ip);
}
putip((char *)&from_ip,&nmb->additional->rdata[2]);
ip = from_ip;
- DEBUG(3,("Name registration for name %s at %s\n",
+ 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 = ipgrp;
+ ip = *interpret_addr2("255.255.255.255");
}
if (!(d = find_req_subnet(p->ip, bcast)))
{
- DEBUG(3,("response packet: bcast %s not known\n",
+ DEBUG(3,("reply_name_reg: subnet %s not known\n",
inet_ntoa(p->ip)));
return;
}
if (bcast)
- search &= FIND_LOCAL;
+ search |= FIND_LOCAL;
else
- search &= FIND_WINS;
+ 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))
}
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);
/* 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);
+ 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_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
- success, True,
- reply_name, nb_flags, ttl, ip);
+ success, nmb->header.nm_flags.recursion_desired,
+ reply_name, nb_flags, ttl, ip);
}
}
if (!strequal(n->name.name,"*") &&
!strequal(n->name.name,"__SAMBA__") &&
- (name_type < 0x1b || name_type > 0x20 ||
- ques_type < 0x1b || ques_type > 0x20 ||
+ (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 */
/* end of this name list: add wins names too? */
struct subnet_record *w_d;
- if (!(w_d = find_subnet(ipgrp))) break;
+ if (!(w_d = wins_subnet)) break;
if (w_d != d)
{
reply_netbios_packet(p,nmb->header.name_trn_id,
0,NMB_STATUS,0,True,
&nmb->question.question_name,
- nmb->question.question_type,
- nmb->question.question_class,
- 0,
- rdata,PTR_DIFF(buf,rdata));
+ 0x21, 0x01,
+ 0, rdata,PTR_DIFF(buf,rdata));
}
char rdata[6];
struct subnet_record *d = NULL;
BOOL success = True;
- struct name_record *n;
+ 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_SELF : FIND_WINS;
-
- if (name_type == 0x1b)
- {
- search |= FIND_WINS;
- }
+ int search = bcast ? FIND_LOCAL | FIND_WINS: FIND_WINS;
- if (search | FIND_LOCAL)
+ if (search & FIND_LOCAL)
{
if (!(d = find_req_subnet(p->ip, bcast)))
{
}
else
{
- if (!(d = find_subnet(ipgrp)))
+ if (!(d = wins_subnet))
{
DEBUG(3,("name query: wins search %s not known\n",
inet_ntoa(p->ip)));
}
}
- DEBUG(3,("Name query "));
+ DEBUG(3,("Name query from %s for name %s<0x%x>\n",
+ inet_ntoa(p->ip), question->name, question->name_type));
if (search == 0)
{
success = False;
}
- if (!bcast && name_type == 0x1d)
+ 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 && (n = search_for_name(&d,question,p->ip,p->timestamp, search)))
+ 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)
{
- /* 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 (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 (bcast && n->source != SELF && name_type != 0x1b) {
- if (!lp_wins_proxy() || same_net(p->ip,n->ip_flgs[0].ip,*iface_nmask(p->ip))) {
+ 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
retip = n->ip_flgs[0].ip;
nb_flags = n->ip_flgs[0].nb_flags;
}
- else
- {
- if (bcast) return; /* never reply negative response to bcasts */
- success = False;
- }
-
+
+ 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;
reply_netbios_packet(p,nmb->header.name_trn_id,
rcode,NMB_QUERY,0,True,
&nmb->question.question_name,
- nmb->question.question_type,
- nmb->question.question_class,
+ 0x20, 0x01,
ttl,
rdata, success ? 6 : 0);
}
-
-