extern int DEBUGLEVEL;
extern pstring scope;
+extern fstring myworkgroup;
extern struct in_addr ipzero;
+extern struct in_addr wins_ip;
+extern struct in_addr ipzero;
+
#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
DEBUG(4,("response name release received\n"));
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
{
/* IMPORTANT: see expire_netbios_response_entries() */
DEBUG(4,("response name registration received!\n"));
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
+#if 1
+ /* This code is neccesitated due to bugs in earlier versions of
+ Samba (up to 1.9.16p11). They respond to a broadcast
+ name registration of WORKGROUP<1b> when they should
+ not. Hence, until these versions are gone, we should
+ treat such errors as success for this particular
+ case only. jallison@whistle.com.
+ */
+ if ( ((d != wins_client_subnet) && (nmb->header.rcode == 6) && strequal(myworkgroup, name) &&
+ (type == 0x1b)) ||
+ (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata))
+#else
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+#endif
{
/* IMPORTANT: see expire_netbios_response_entries() */
}
else
{
- DEBUG(2,("name registration for %s rejected!\n", namestr(ans_name)));
+ DEBUG(2,("name registration for %s rejected by ip %s!\n",
+ namestr(ans_name), inet_ntoa(p->ip)));
/* oh dear. we have problems. possibly unbecome a master browser. */
name_unregister_work(d,name,type);
}
}
-
-/****************************************************************************
- response from a name query announce host
- NAME_QUERY_ANNOUNCE_HOST is dealt with here
- ****************************************************************************/
-static void response_announce_host(struct nmb_name *ans_name,
- struct nmb_packet *nmb,
- struct response_record *n, struct subnet_record *d)
-{
- DEBUG(4, ("Name query at %s ip %s - ",
- namestr(&n->name), inet_ntoa(n->send_ip)));
-
- if (!name_equal(&n->name, ans_name))
- {
- /* someone gave us the wrong name as a reply. oops. */
- /* XXXX should say to them 'oi! release that name!' */
-
- DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
- return;
- }
-
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
- {
- /* we had sent out a name query to the current owner
- of a name because someone else wanted it. now they
- have responded saying that they still want the name,
- so the other host can't have it.
- */
-
- /* first check all the details are correct */
-
- int nb_flags = nmb->answers->rdata[0];
- struct in_addr found_ip;
-
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- if (nb_flags != n->nb_flags)
- {
- /* someone gave us the wrong nb_flags as a reply. oops. */
- /* XXXX should say to them 'oi! release that name!' */
-
- DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
- DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
- return;
- }
-
- /* do an announce host */
- do_announce_host(ANN_HostAnnouncement,
- n->my_name , 0x00, d->myip,
- n->name.name, 0x1d, found_ip,
- n->ttl,
- n->my_name, n->server_type, n->my_comment);
- }
- else
- {
- /* XXXX negative name query response. no master exists. oops */
- }
-}
-
-
/****************************************************************************
response from a name query server check. states of type NAME_QUERY_DOM_SRV_CHK,
NAME_QUERY_SRV_CHK, and NAME_QUERY_FIND_MST dealt with here.
****************************************************************************/
static void response_server_check(struct nmb_name *ans_name,
- struct response_record *n, struct subnet_record *d)
+ struct response_record *n, struct subnet_record *d, struct packet_struct *p)
{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr send_ip;
+ enum state_type cmd;
+
+ /* This next fix was from Bernhard Laeser <nlaesb@ascom.ch>
+ who noticed we were replying directly back to the server
+ we sent to - rather than reading the response.
+ */
+
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
+ putip((char*)&send_ip,&nmb->answers->rdata[2]);
+ else
+ {
+
+ DEBUG(2,("response_server_check: name query for %s failed\n",
+ namestr(ans_name)));
+ return;
+ }
+
/* issue another state: this time to do a name status check */
- enum state_type cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
+ cmd = (n->state == NAME_QUERY_DOM_SRV_CHK) ?
NAME_STATUS_DOM_SRV_CHK : NAME_STATUS_SRV_CHK;
- /* initiate a name status check on the server that replied
- in addition, the workgroup being checked has been stored
+ /* initiate a name status check on address given in the reply
+ record. In addition, the workgroup being checked has been stored
in the response_record->my_name (see announce_master) we
also propagate this into the same field. */
queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
ans_name->name, ans_name->name_type,
0,0,0,n->my_name,NULL,
- False,False,n->send_ip,n->reply_to_ip);
+ False,False,send_ip,n->reply_to_ip, 0);
}
if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
-/* I don't think we should be messing with our namelist here... JRA */
-#if 0
- /* might as well update our namelist while we're at it */
- if (add)
- {
- struct in_addr nameip;
- enum name_source src;
-
- if (ismyip(ip)) {
- nameip = ipzero;
- src = SELF;
- } else {
- nameip = ip;
- src = STATUS_QUERY;
- }
- add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
- }
-#endif /* JRA */
-
/* we want the server name */
if (serv_name && !*serv_name && !group && type == 0x20)
{
struct nmb_name name;
fstring serv_name;
- if (interpret_node_status(d,nmb->answers->rdata,
+ if (nmb->answers &&
+ interpret_node_status(d,nmb->answers->rdata,
&name,0x20,serv_name,ip,bcast))
{
if (*serv_name)
return;
}
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
{
/* we had sent out a name query to the current owner
of a name because someone else wanted it. now they
}
/* register the old or the new owners' ip */
- add_name_respond(d, n->fd, d->myip, n->response_id,&n->name,n->nb_flags,
+ add_name_respond(d, n->fd, d->myip, n->reply_id,&n->name,n->nb_flags,
GET_TTL(0), register_ip,
new_owner, n->reply_to_ip);
+
+ remove_response_record(d,n); /* remove the response record */
}
return;
}
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
{
int nb_flags = nmb->answers->rdata[0];
struct in_addr found_ip;
}
else
{
+ struct subnet_record *add_rec = (!bcast) ? wins_client_subnet : d;
+
/* update our netbios name list (re-register it if necessary) */
- add_netbios_entry(d, ans_name->name, ans_name->name_type,
+ add_netbios_entry(add_rec, ans_name->name, ans_name->name_type,
nb_flags,GET_TTL(0),REGISTER,
- found_ip,False,!bcast);
+ found_ip,False);
}
}
else
then we're in a mess: our name database doesn't match
reality. sort it out
*/
- remove_netbios_name(d,n->name.name, n->name.name_type,
- REGISTER,n->send_ip);
+ remove_netbios_name(d,n->name.name, n->name.name_type, REGISTER);
}
}
}
+/****************************************************************************
+ response from a name query for DOMAIN<1b>
+ NAME_QUERY_DOMAIN is dealt with here - we are trying to become a domain
+ master browser and WINS replied - check it's our address.
+ ****************************************************************************/
+static void response_name_query_domain(struct nmb_name *ans_name,
+ struct nmb_packet *nmb,
+ struct response_record *n, struct subnet_record *d)
+{
+ DEBUG(4, ("response_name_query_domain: Got %s response from %s for query \
+for %s\n", nmb->header.rcode == 0 ? "success" : "failure",
+ inet_ntoa(n->send_ip), namestr(ans_name)));
+
+ /* Check the name is correct and ip address returned is our own. If it is then we
+ just remove the response record.
+ */
+ if (name_equal(&n->name, ans_name) && (nmb->header.rcode == 0) && nmb->answers && (nmb->answers->rdata))
+ {
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+ /* Samba 1.9.16p11 servers seem to return the broadcast address for this
+ query. */
+ if (ismyip(found_ip) || ip_equal(wins_ip, found_ip) || ip_equal(ipzero, found_ip))
+ {
+ DEBUG(4, ("response_name_query_domain: WINS server returned our ip \
+address. Pretending we never received response.\n"));
+ n->num_msgs = 0;
+ n->repeat_count = 0;
+ n->repeat_time = 0;
+ }
+ else
+ {
+ DEBUG(0,("response_name_query_domain: WINS server already has a \
+domain master browser registered %s at address %s\n",
+ namestr(ans_name), inet_ntoa(found_ip)));
+ }
+ }
+ else
+ {
+ /* Negative/incorrect response. No domain master
+ browser was registered - pretend we didn't get this response.
+ */
+ n->num_msgs = 0;
+ n->repeat_count = 0;
+ n->repeat_time = 0;
+ }
+
+}
/****************************************************************************
report the response record type
case NAME_QUERY_CONFIRM : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
case NAME_QUERY_SYNC_LOCAL : DEBUG(4,("NAME_QUERY_SYNC_LOCAL\n")); break;
case NAME_QUERY_SYNC_REMOTE : DEBUG(4,("NAME_QUERY_SYNC_REMOTE\n")); break;
- case NAME_QUERY_ANNOUNCE_HOST: DEBUG(4,("NAME_QUERY_ANNCE_HOST\n"));break;
+ case NAME_QUERY_DOMAIN : DEBUG(4,("NAME_QUERY_DOMAIN\n")); break;
case NAME_REGISTER : DEBUG(4,("NAME_REGISTER\n")); break;
case NAME_REGISTER_CHALLENGE : DEBUG(4,("NAME_REGISTER_CHALLENGE\n"));break;
{
if (n->num_msgs > 1)
{
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ if (nmb->header.rcode == 0 && nmb->answers && nmb->answers->rdata)
{
int nb_flags = nmb->answers->rdata[0];
{
case NAME_QUERY_FIND_MST:
{
- /* query for ^1^2__MSBROWSE__^2^1 expect
+ /* query for ^1^2__MSBROWSE__^2^1 expect
lots of responses */
return False;
}
- case NAME_QUERY_ANNOUNCE_HOST:
case NAME_QUERY_DOM_SRV_CHK:
case NAME_QUERY_SRV_CHK:
case NAME_QUERY_MST_CHK:
case NAME_REGISTER_CHALLENGE: /* this is a query: we then do a register */
case NAME_QUERY_CONFIRM:
- case NAME_QUERY_ANNOUNCE_HOST:
case NAME_QUERY_SYNC_LOCAL:
case NAME_QUERY_SYNC_REMOTE:
case NAME_QUERY_DOM_SRV_CHK:
case NAME_QUERY_SRV_CHK:
case NAME_QUERY_FIND_MST:
{
- response_server_check(ans_name, n, d);
+ response_server_check(ans_name, n, d, p);
break;
}
break;
}
- case NAME_QUERY_ANNOUNCE_HOST:
- {
- response_announce_host(ans_name, nmb, n, d);
- break;
- }
-
case NAME_QUERY_CONFIRM:
case NAME_QUERY_SYNC_LOCAL:
case NAME_QUERY_SYNC_REMOTE:
namestr(&n->name), inet_ntoa(n->send_ip)));
break;
}
-
+
+ case NAME_QUERY_DOMAIN:
+ {
+ /* We were asking to be a domain master browser, and someone
+ replied. If it was the WINS server and the IP it is
+ returning is our own - then remove the record and pretend
+ we didn't get a response. Else we do nothing and let
+ dead_netbios_entry deal with it.
+ We can only become domain master browser
+ when no broadcast responses are received and WINS
+ either contains no entry for the DOMAIN<1b> name or
+ contains our IP address.
+ */
+ response_name_query_domain(ans_name, nmb, n, d);
+ break;
+ }
default:
{
DEBUG(1,("unknown state type received in response_netbios_packet\n"));
struct subnet_record *d = NULL;
if (!(n = find_response_record(&d,nmb->header.name_trn_id))) {
- DEBUG(2,("unknown netbios response (received late or from nmblookup?)\n"));
+ DEBUG(2,("unknown netbios response id %d (received late or from nmblookup?)\n",
+ nmb->header.name_trn_id));
return;
}
DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
}
- if (nmb->answers == NULL)
- {
- /* hm. the packet received was a response, but with no answer. wierd! */
- DEBUG(2,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
- inet_ntoa(p->ip), BOOLSTR(bcast)));
- return;
- }
+ if (nmb->answers == NULL) {
+ /* if there is no name is the response then the name is the one
+ we queried on */
+ ans_name = &n->name;
+ } else {
+ ans_name = &nmb->answers->rr_name;
+ debug_rr_type(nmb->answers->rr_type);
+ }
- ans_name = &nmb->answers->rr_name;
- DEBUG(3,("response for %s from %s (bcast=%s)\n",
- namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast)));
-
- debug_rr_type(nmb->answers->rr_type);
+ DEBUG(3,("response for %s from %s(%d) (bcast=%s)\n",
+ namestr(ans_name), inet_ntoa(p->ip), p->port, BOOLSTR(bcast)));
n->num_msgs++; /* count number of responses received */
n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
debug_state_type(n->state);
/* problem checking: multiple responses etc */
- if (response_problem_check(n, nmb, ans_name->name))
+ if (nmb->answers && response_problem_check(n, nmb, ans_name->name))
return;
/* now deal with the current state */