nmbd_nameregister.c [plain text]
#include "includes.h"
static void wins_next_registration(struct response_record *rrec);
static void register_name_response(struct subnet_record *subrec,
struct response_record *rrec, struct packet_struct *p)
{
struct nmb_packet *nmb = &p->packet.nmb;
BOOL bcast = nmb->header.nm_flags.bcast;
BOOL success = True;
struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
struct nmb_name *answer_name = &nmb->answers->rr_name;
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
int ttl = 0;
uint16 nb_flags = 0;
struct in_addr register_ip;
fstring reg_name;
putip(®ister_ip,&sent_nmb->additional->rdata[2]);
fstrcpy(reg_name, inet_ntoa(register_ip));
if (subrec == unicast_subnet) {
wins_srv_alive(rrec->packet->ip, register_ip);
}
if(!question_name || !answer_name) {
DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
question_name ? "question_name" : "answer_name" ));
return;
}
if(!nmb_name_equal(question_name, answer_name)) {
DEBUG(0,("register_name_response: Answer name %s differs from question name %s.\n",
nmb_namestr(answer_name), nmb_namestr(question_name)));
return;
}
if(bcast) {
#if 1
unstring ans_name;
pull_ascii_nstring(ans_name, sizeof(ans_name), answer_name->name);
if((nmb->header.rcode == ACT_ERR) && strequal(lp_workgroup(), ans_name) &&
(answer_name->name_type == 0x1b)) {
rrec->num_msgs--;
DEBUG(5,("register_name_response: Ignoring broadcast response to registration of name %s due to old Samba server bug.\n",
nmb_namestr(answer_name)));
return;
}
#endif
DEBUG(1,("register_name_response: Failed to register name %s IP %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n",
nmb_namestr(answer_name),
reg_name,
subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
success = False;
} else {
if (nmb->header.opcode == NMB_WACK_OPCODE) {
DEBUG(5,("register_name_response: WACK from WINS server %s in registering name %s IP %s\n",
inet_ntoa(p->ip), nmb_namestr(answer_name), reg_name));
rrec->repeat_count = 0;
rrec->repeat_time = p->timestamp + nmb->answers->ttl;
rrec->num_msgs--;
return;
} else if (nmb->header.rcode != 0) {
success = False;
DEBUG(0,("register_name_response: %sserver at IP %s rejected our name registration of %s IP %s with error code %d.\n",
subrec==unicast_subnet?"WINS ":"",
inet_ntoa(p->ip),
nmb_namestr(answer_name),
reg_name,
nmb->header.rcode));
} else {
success = True;
nb_flags = get_nb_flags(nmb->answers->rdata);
ttl = nmb->answers->ttl;
wins_next_registration(rrec);
}
}
DEBUG(5,("register_name_response: %s in registering %sname %s IP %s with %s.\n",
success ? "success" : "failure",
subrec==unicast_subnet?"WINS ":"",
nmb_namestr(answer_name),
reg_name,
inet_ntoa(rrec->packet->ip)));
if(success) {
standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
if( rrec->success_fn)
(*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
} else {
if( rrec->fail_fn)
(*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
standard_fail_register( subrec, rrec, question_name);
}
remove_response_record(subrec, rrec);
}
static void wins_registration_timeout(struct subnet_record *subrec,
struct response_record *rrec)
{
struct userdata_struct *userdata = rrec->userdata;
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
struct nmb_name *nmbname = &sent_nmb->question.question_name;
struct in_addr register_ip;
fstring src_addr;
putip(®ister_ip,&sent_nmb->additional->rdata[2]);
fstrcpy(src_addr, inet_ntoa(register_ip));
DEBUG(2,("wins_registration_timeout: WINS server %s timed out registering IP %s\n",
inet_ntoa(rrec->packet->ip), src_addr));
wins_srv_died(rrec->packet->ip, register_ip);
if (userdata) {
const char *tag = (const char *)userdata->data;
rrec->packet->ip = wins_srv_ip_tag(tag, register_ip);
}
if (wins_srv_is_dead(rrec->packet->ip, register_ip)) {
uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata);
int ttl = sent_nmb->additional->ttl;
standard_success_register(subrec, userdata, nmbname, nb_flags, ttl, register_ip);
if(rrec->success_fn) {
(*(register_name_success_function)rrec->success_fn)(subrec,
rrec->userdata,
nmbname,
nb_flags,
ttl,
register_ip);
}
wins_next_registration(rrec);
remove_response_record(subrec, rrec);
return;
}
rrec->repeat_count = 2;
rrec->repeat_time = time(NULL) + 1;
rrec->in_expiration_processing = False;
DEBUG(6,("Retrying register of name %s IP %s with WINS server %s\n",
nmb_namestr(nmbname), src_addr, inet_ntoa(rrec->packet->ip)));
}
static void register_name_timeout_response(struct subnet_record *subrec,
struct response_record *rrec)
{
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
BOOL bcast = sent_nmb->header.nm_flags.bcast;
BOOL success = False;
struct nmb_name *question_name = &sent_nmb->question.question_name;
uint16 nb_flags = 0;
int ttl = 0;
struct in_addr registered_ip;
if (bcast) {
if(rrec->num_msgs == 0) {
success = True;
nb_flags = get_nb_flags(sent_nmb->additional->rdata);
ttl = sent_nmb->additional->ttl;
putip(®istered_ip,&sent_nmb->additional->rdata[2]);
}
} else {
wins_registration_timeout(subrec, rrec);
return;
}
DEBUG(5,("register_name_timeout_response: %s in registering name %s on subnet %s.\n",
success ? "success" : "failure", nmb_namestr(question_name), subrec->subnet_name));
if(success) {
standard_success_register(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
if( rrec->success_fn)
(*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, nb_flags, ttl, registered_ip);
} else {
if( rrec->fail_fn)
(*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
standard_fail_register( subrec, rrec, question_name);
}
remove_response_record(subrec, rrec);
}
static void multihomed_register_one(struct nmb_name *nmbname,
uint16 nb_flags,
register_name_success_function success_fn,
register_name_fail_function fail_fn,
struct in_addr ip,
const char *tag)
{
struct userdata_struct *userdata;
struct in_addr wins_ip = wins_srv_ip_tag(tag, ip);
fstring ip_str;
userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
if (!userdata) {
DEBUG(0,("Failed to allocate userdata structure!\n"));
return;
}
ZERO_STRUCTP(userdata);
userdata->userdata_len = strlen(tag) + 1;
strlcpy(userdata->data, tag, userdata->userdata_len);
fstrcpy(ip_str, inet_ntoa(ip));
DEBUG(6,("Registering name %s IP %s with WINS server %s using tag '%s'\n",
nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
if (queue_register_multihomed_name(unicast_subnet,
register_name_response,
register_name_timeout_response,
success_fn,
fail_fn,
userdata,
nmbname,
nb_flags,
ip,
wins_ip) == NULL) {
DEBUG(0,("multihomed_register_one: Failed to send packet trying to register name %s IP %s\n",
nmb_namestr(nmbname), inet_ntoa(ip)));
}
free(userdata);
}
static void wins_next_registration(struct response_record *rrec)
{
struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
struct nmb_name *nmbname = &sent_nmb->question.question_name;
uint16 nb_flags = get_nb_flags(sent_nmb->additional->rdata);
struct userdata_struct *userdata = rrec->userdata;
const char *tag;
struct in_addr last_ip;
struct subnet_record *subrec;
putip(&last_ip,&sent_nmb->additional->rdata[2]);
if (!userdata) {
return;
}
tag = (const char *)userdata->data;
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
if (ip_equal(last_ip, subrec->myip)) {
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec);
break;
}
}
if (!subrec) {
return;
}
switch (sent_nmb->header.opcode) {
case NMB_NAME_MULTIHOMED_REG_OPCODE:
multihomed_register_one(nmbname, nb_flags, NULL, NULL, subrec->myip, tag);
break;
case NMB_NAME_REFRESH_OPCODE_8:
queue_wins_refresh(nmbname,
register_name_response,
register_name_timeout_response,
nb_flags, subrec->myip, tag);
break;
}
}
static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
register_name_success_function success_fn,
register_name_fail_function fail_fn)
{
int num_ips=0;
int i, t;
struct subnet_record *subrec;
char **wins_tags;
struct in_addr *ip_list;
unstring name;
for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
num_ips++;
if((ip_list = SMB_MALLOC_ARRAY(struct in_addr, num_ips))==NULL) {
DEBUG(0,("multihomed_register_name: malloc fail !\n"));
return;
}
for (subrec = FIRST_SUBNET, i = 0;
subrec;
subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) {
ip_list[i] = subrec->myip;
}
pull_ascii_nstring(name, sizeof(name), nmbname->name);
add_name_to_subnet(unicast_subnet, name, nmbname->name_type,
nb_flags, lp_max_ttl(), SELF_NAME,
num_ips, ip_list);
wins_tags = wins_srv_tags();
for (t=0; wins_tags && wins_tags[t]; t++) {
multihomed_register_one(nmbname, nb_flags,
success_fn, fail_fn,
ip_list[0],
wins_tags[t]);
}
wins_srv_tags_free(wins_tags);
SAFE_FREE(ip_list);
}
void register_name(struct subnet_record *subrec,
const char *name, int type, uint16 nb_flags,
register_name_success_function success_fn,
register_name_fail_function fail_fn,
struct userdata_struct *userdata)
{
struct nmb_name nmbname;
nstring nname;
errno = 0;
push_ascii_nstring(nname, name);
if (errno == E2BIG) {
unstring tname;
pull_ascii_nstring(tname, sizeof(tname), nname);
DEBUG(0,("register_name: NetBIOS name %s is too long. Truncating to %s\n",
name, tname));
make_nmb_name(&nmbname, tname, type);
} else {
make_nmb_name(&nmbname, name, type);
}
nb_flags |= NB_ACTIVE;
if (subrec == unicast_subnet) {
multihomed_register_name(&nmbname, nb_flags,
success_fn, fail_fn);
return;
}
if (queue_register_name(subrec,
register_name_response,
register_name_timeout_response,
success_fn,
fail_fn,
userdata,
&nmbname,
nb_flags) == NULL) {
DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
nmb_namestr(&nmbname)));
}
}
void wins_refresh_name(struct name_record *namerec)
{
int t;
char **wins_tags;
wins_tags = wins_srv_tags();
for (t=0; wins_tags && wins_tags[t]; t++) {
queue_wins_refresh(&namerec->name,
register_name_response,
register_name_timeout_response,
namerec->data.nb_flags,
namerec->data.ip[0], wins_tags[t]);
}
wins_srv_tags_free(wins_tags);
}