nmbd_incomingrequests.c [plain text]
#include "includes.h"
extern fstring global_myworkgroup;
static void send_name_release_response(int rcode, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
char rdata[6];
memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
reply_netbios_packet(p,
rcode,
NMB_REL,
NMB_NAME_RELEASE_OPCODE,
0,
rdata,
6);
}
void process_name_release_request(struct subnet_record *subrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct in_addr owner_ip;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
BOOL group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec;
int rcode = 0;
START_PROFILE(name_release);
putip((char *)&owner_ip,&nmb->additional->rdata[2]);
if(!bcast)
{
DEBUG(0,("process_name_release_request: unicast name release request \
received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name));
send_name_release_response(FMT_ERR, p);
goto done;
}
DEBUG(3,("process_name_release_request: Name release on name %s, \
subnet %s from owner IP %s\n",
nmb_namestr(&nmb->question.question_name),
subrec->subnet_name, inet_ntoa(owner_ip)));
if( group && !ismyip(owner_ip) )
goto done;
if( !group && !ismyip(owner_ip) && strequal(question->name, global_myworkgroup) &&
((question->name_type == 0x0) || (question->name_type == 0x1e)))
{
DEBUG(6,("process_name_release_request: FTP OnNet bug workaround. Ignoring \
group release name %s from IP %s on subnet %s with no group bit set.\n",
nmb_namestr(question), inet_ntoa(owner_ip), subrec->subnet_name ));
goto done;
}
namerec = find_name_on_subnet(subrec, &nmb->question.question_name, FIND_ANY_NAME);
if( namerec
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) ) )
{
rcode = ACT_ERR;
DEBUG(0, ("process_name_release_request: Attempt to release name %s from IP %s \
on subnet %s being rejected as it is one of our names.\n",
nmb_namestr(&nmb->question.question_name), inet_ntoa(owner_ip), subrec->subnet_name));
}
if(rcode == 0)
goto done;
send_name_release_response(rcode, p);
done:
END_PROFILE(name_release);
}
static void send_name_registration_response(int rcode, int ttl, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
char rdata[6];
memcpy(&rdata[0], &nmb->additional->rdata[0], 6);
reply_netbios_packet(p,
rcode,
NMB_REG,
NMB_NAME_REG_OPCODE,
ttl,
rdata,
6);
}
void process_name_refresh_request(struct subnet_record *subrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
struct in_addr from_ip;
START_PROFILE(name_refresh);
putip((char *)&from_ip,&nmb->additional->rdata[2]);
if(!bcast)
{
DEBUG(0,("process_name_refresh_request: unicast name registration request \
received for name %s from IP %s on subnet %s.\n",
nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
DEBUG(0,("Error - should be sent to WINS server\n"));
send_name_registration_response(FMT_ERR, 0, p);
goto done;
}
DEBUG(3,("process_name_refresh_request: Name refresh for name %s \
IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
done:
END_PROFILE(name_refresh);
}
void process_name_registration_request(struct subnet_record *subrec,
struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
struct nmb_name *question = &nmb->question.question_name;
BOOL bcast = nmb->header.nm_flags.bcast;
uint16 nb_flags = get_nb_flags(nmb->additional->rdata);
BOOL group = (nb_flags & NB_GROUP) ? True : False;
struct name_record *namerec = NULL;
int ttl = nmb->additional->ttl;
struct in_addr from_ip;
START_PROFILE(name_registration);
putip((char *)&from_ip,&nmb->additional->rdata[2]);
if(!bcast)
{
DEBUG(0,("process_name_registration_request: unicast name registration request \
received for name %s from IP %s on subnet %s. Error - should be sent to WINS server\n",
nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
send_name_registration_response(FMT_ERR, 0, p);
goto done;
}
DEBUG(3,("process_name_registration_request: Name registration for name %s \
IP %s on subnet %s\n", nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
if((namerec != NULL) && (namerec->data.source == WINS_PROXY_NAME))
{
remove_name_from_namelist( subrec, namerec );
namerec = NULL;
}
if (!group)
{
if( (namerec != NULL)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME)
|| NAME_GROUP(namerec) ) )
{
send_name_registration_response(ACT_ERR, 0, p);
goto done;
}
else if(namerec != NULL)
{
namerec->data.ip[0] = from_ip;
update_name_ttl(namerec, ttl);
DEBUG(3,("process_name_registration_request: Updated name record %s \
with IP %s on subnet %s\n",nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
goto done;
}
}
else
{
if( (namerec != NULL)
&& !NAME_GROUP(namerec)
&& ( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) ) )
{
send_name_registration_response(ACT_ERR, 0, p);
goto done;
}
}
done:
END_PROFILE(name_registration);
}
static int status_compare(char *n1,char *n2)
{
extern pstring global_myname;
int l1,l2,l3;
for (l1=0;l1<15 && n1[l1] && n1[l1] != ' ';l1++) ;
for (l2=0;l2<15 && n2[l2] && n2[l2] != ' ';l2++) ;
l3 = strlen(global_myname);
if ((l1==l3) && strncmp(n1,global_myname,l3) == 0 &&
(l2!=l3 || strncmp(n2,global_myname,l3) != 0))
return -1;
if ((l2==l3) && strncmp(n2,global_myname,l3) == 0 &&
(l1!=l3 || strncmp(n1,global_myname,l3) != 0))
return 1;
return memcmp(n1,n2,18);
}
void process_node_status_request(struct subnet_record *subrec, 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 *namerec;
START_PROFILE(node_status);
DEBUG(3,("process_node_status_request: status request for name %s from IP %s on \
subnet %s.\n", nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip),
subrec->subnet_name));
if((namerec = find_name_on_subnet(subrec, &nmb->question.question_name,
FIND_SELF_NAME)) == 0)
{
DEBUG(1,("process_node_status_request: status request for name %s from IP %s on \
subnet %s - name not found.\n", nmb_namestr(&nmb->question.question_name),
inet_ntoa(p->ip), subrec->subnet_name));
goto done;
}
bufend = &rdata[MAX_DGRAM_SIZE] - (18 + 46 + 60);
countptr = buf = rdata;
buf += 1;
buf0 = buf;
names_added = 0;
namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
while (buf < bufend)
{
if( (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME) )
{
int name_type = namerec->name.name_type;
if (!strequal(namerec->name.name,"*") &&
!strequal(namerec->name.name,"__SAMBA__") &&
(name_type < 0x1b || name_type >= 0x20 ||
ques_type < 0x1b || ques_type >= 0x20 ||
strequal(qname, namerec->name.name)))
{
memset(buf,'\0',18);
slprintf(buf, 17, "%-15.15s",namerec->name.name);
strupper(buf);
buf[15] = name_type;
set_nb_flags( &buf[16],namerec->data.nb_flags );
buf[16] |= NB_ACTIVE;
buf += 18;
names_added++;
}
}
if (names_added > 1) {
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;
namerec = (struct name_record *)ubi_trNext( namerec );
if (!namerec)
{
struct subnet_record *uni_subrec = unicast_subnet;
if (uni_subrec != subrec)
{
subrec = uni_subrec;
namerec = (struct name_record *)ubi_trFirst( subrec->namelist );
}
}
if (!namerec)
break;
}
SCVAL(countptr,0,names_added);
memset(buf,'\0',46);
buf += 46;
reply_netbios_packet(p,
0,
NMB_STATUS,
NMB_NAME_QUERY_OPCODE,
0,
rdata,
PTR_DIFF(buf,rdata));
done:
END_PROFILE(node_status);
}
void process_name_query_request(struct subnet_record *subrec, 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;
char *prdata = NULL;
char rdata[6];
BOOL success = False;
struct name_record *namerec = NULL;
int reply_data_len = 0;
int i;
START_PROFILE(name_query);
DEBUG(3,("process_name_query_request: Name query from %s on subnet %s for name %s\n",
inet_ntoa(p->ip), subrec->subnet_name, nmb_namestr(question)));
if(subrec == remote_broadcast_subnet)
namerec = find_name_for_remote_broadcast_subnet( question, FIND_ANY_NAME);
else
namerec = find_name_on_subnet(subrec, question, FIND_ANY_NAME);
if( namerec
&& ( (namerec->data.death_time != PERMANENT_TTL)
&& (namerec->data.death_time < p->timestamp) ) )
{
DEBUG(5,("process_name_query_request: expired name %s\n", nmb_namestr(&namerec->name)));
namerec = NULL;
}
if (namerec)
{
if( !bcast
|| ( bcast
&& ( (name_type == 0x1b)
|| (namerec->data.source == SELF_NAME)
|| (namerec->data.source == PERMANENT_NAME)
|| ( (namerec->data.source == WINS_PROXY_NAME)
&& ( (name_type == 0) || (name_type == 0x20) )
)
)
)
)
{
if( namerec->data.source == WINS_PROXY_NAME )
{
for( i = 0; i < namerec->data.num_ips; i++)
{
if(same_net( namerec->data.ip[i], subrec->myip, subrec->mask_ip ))
{
DEBUG(5,("process_name_query_request: name %s is a WINS proxy name and is also \
on the same subnet (%s) as the requestor. Not replying.\n",
nmb_namestr(&namerec->name), subrec->subnet_name ));
goto done;
}
}
}
ttl = (namerec->data.death_time != PERMANENT_TTL) ?
namerec->data.death_time - p->timestamp : lp_max_ttl();
if( namerec->data.num_ips == 1 )
prdata = rdata;
else
{
if((prdata = (char *)malloc( namerec->data.num_ips * 6 )) == NULL)
{
DEBUG(0,("process_name_query_request: malloc fail !\n"));
goto done;
}
}
for( i = 0; i < namerec->data.num_ips; i++ )
{
set_nb_flags(&prdata[i*6],namerec->data.nb_flags);
putip((char *)&prdata[2+(i*6)], &namerec->data.ip[i]);
}
sort_query_replies(prdata, i, p->ip);
reply_data_len = namerec->data.num_ips * 6;
success = True;
}
}
if(!success && (namerec == NULL) && we_are_a_wins_client() && lp_wins_proxy() &&
bcast && (subrec != remote_broadcast_subnet))
{
make_wins_proxy_name_query_request( subrec, p, question );
goto done;
}
if (!success && bcast)
{
if((prdata != rdata) && (prdata != NULL))
SAFE_FREE(prdata);
goto done;
}
if(!success && !bcast && nmb->header.nm_flags.recursion_desired)
{
if((prdata != rdata) && (prdata != NULL))
SAFE_FREE(prdata);
goto done;
}
if (success)
{
rcode = 0;
DEBUG(3,("OK\n"));
}
else
{
rcode = NAM_ERR;
DEBUG(3,("UNKNOWN\n"));
}
reply_netbios_packet(p,
rcode,
NMB_QUERY,
NMB_NAME_QUERY_OPCODE,
ttl,
prdata,
reply_data_len);
if((prdata != rdata) && (prdata != NULL))
SAFE_FREE(prdata);
done:
END_PROFILE(name_query);
}