/*
- Unix SMB/Netbios implementation.
- Version 1.9.
+ Unix SMB/CIFS implementation.
NBT netbios routines and daemon - version 2
Copyright (C) Andrew Tridgell 1994-1998
Copyright (C) Luke Kenneth Casson Leighton 1994-1998
extern int ClientDGRAM;
extern int global_nmb_port;
-extern int DEBUGLEVEL;
-
extern int num_response_packets;
extern struct in_addr loopback_ip;
uint16 nb_flags,
struct in_addr *register_ip)
{
- struct nmb_packet *nmb = &packet->packet.nmb;
-
- if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL)
- {
- DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
- return False;
- }
-
- memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
-
- nmb->additional->rr_name = nmb->question.question_name;
- nmb->additional->rr_type = RR_TYPE_NB;
- nmb->additional->rr_class = RR_CLASS_IN;
-
- /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
- if (nmb->header.nm_flags.bcast)
- nmb->additional->ttl = PERMANENT_TTL;
- else
- nmb->additional->ttl = lp_max_ttl();
-
- nmb->additional->rdlength = 6;
-
- set_nb_flags(nmb->additional->rdata,nb_flags);
-
- /* Set the address for the name we are registering. */
- putip(&nmb->additional->rdata[2], register_ip);
-
- /* Ensure that we send out the file descriptor to give us the
- the specific source address we are registering as our
- IP source address. */
-
- packet->fd = find_subnet_fd_for_address( *register_ip );
-
- return True;
+ struct nmb_packet *nmb = &packet->packet.nmb;
+
+ if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
+ DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
+ return False;
+ }
+
+ memset((char *)nmb->additional,'\0',sizeof(struct res_rec));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = RR_TYPE_NB;
+ nmb->additional->rr_class = RR_CLASS_IN;
+
+ /* See RFC 1002, sections 5.1.1.1, 5.1.1.2 and 5.1.1.3 */
+ if (nmb->header.nm_flags.bcast)
+ nmb->additional->ttl = PERMANENT_TTL;
+ else
+ nmb->additional->ttl = lp_max_ttl();
+
+ nmb->additional->rdlength = 6;
+
+ set_nb_flags(nmb->additional->rdata,nb_flags);
+
+ /* Set the address for the name we are registering. */
+ putip(&nmb->additional->rdata[2], register_ip);
+
+ /*
+ it turns out that Jeremys code was correct, we are supposed
+ to send registrations from the IP we are registering. The
+ trick is what to do on timeouts! When we send on a
+ non-routable IP then the reply will timeout, and we should
+ treat this as success, not failure. That means we go into
+ our standard refresh cycle for that name which copes nicely
+ with disconnected networks.
+ */
+ packet->fd = find_subnet_fd_for_address(*register_ip);
+
+ return True;
}
/***************************************************************************
Sends out a multihomed name register.
**************************************************************************/
-static BOOL initiate_multihomed_name_register_packet( struct packet_struct *packet,
- uint16 nb_flags, struct in_addr *register_ip)
+static BOOL initiate_multihomed_name_register_packet(struct packet_struct *packet,
+ uint16 nb_flags, struct in_addr *register_ip)
{
- struct nmb_packet *nmb = &packet->packet.nmb;
- fstring second_ip_buf;
-
- fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
-
- nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
- nmb->header.arcount = 1;
+ struct nmb_packet *nmb = &packet->packet.nmb;
+ fstring second_ip_buf;
- nmb->header.nm_flags.recursion_desired = True;
+ fstrcpy(second_ip_buf, inet_ntoa(packet->ip));
- if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
- return False;
+ nmb->header.opcode = NMB_NAME_MULTIHOMED_REG_OPCODE;
+ nmb->header.arcount = 1;
- DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
+ nmb->header.nm_flags.recursion_desired = True;
+
+ if(create_and_init_additional_record(packet, nb_flags, register_ip) == False)
+ return False;
+
+ DEBUG(4,("initiate_multihomed_name_register_packet: sending registration \
for name %s IP %s (bcast=%s) to IP %s\n",
- nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
- BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
+ nmb_namestr(&nmb->additional->rr_name), inet_ntoa(*register_ip),
+ BOOLSTR(nmb->header.nm_flags.bcast), second_ip_buf ));
- return send_netbios_packet( packet );
+ return send_netbios_packet( packet );
}
/***************************************************************************
return rrec;
}
+
+/****************************************************************************
+ Queue a refresh name packet to the broadcast address of a subnet.
+****************************************************************************/
+void queue_wins_refresh(struct nmb_name *nmbname,
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ uint16 nb_flags,
+ struct in_addr refresh_ip,
+ const char *tag)
+{
+ struct packet_struct *p;
+ struct response_record *rrec;
+ struct in_addr wins_ip;
+ struct userdata_struct *userdata;
+ fstring ip_str;
+
+ wins_ip = wins_srv_ip_tag(tag, refresh_ip);
+
+ if ((p = create_and_init_netbios_packet(nmbname, False, False, wins_ip)) == NULL) {
+ return;
+ }
+
+ if (!initiate_name_refresh_packet(p, nb_flags, &refresh_ip)) {
+ p->locked = False;
+ free_packet(p);
+ return;
+ }
+
+ fstrcpy(ip_str, inet_ntoa(refresh_ip));
+
+ DEBUG(6,("Refreshing name %s IP %s with WINS server %s using tag '%s'\n",
+ nmb_namestr(nmbname), ip_str, inet_ntoa(wins_ip), tag));
+
+ userdata = (struct userdata_struct *)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);
+
+ if ((rrec = make_response_record(unicast_subnet,
+ p,
+ resp_fn, timeout_fn,
+ NULL,
+ NULL,
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return;
+ }
+
+ free(userdata);
+
+ /* we don't want to repeat refresh packets */
+ rrec->repeat_count = 0;
+}
+
+
/****************************************************************************
- Queue a multihomed register name packet to the broadcast address of a subnet.
+ Queue a multihomed register name packet to a given WINS server IP
****************************************************************************/
struct response_record *queue_register_multihomed_name( struct subnet_record *subrec,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- register_name_success_function success_fn,
- register_name_fail_function fail_fn,
- struct userdata_struct *userdata,
- struct nmb_name *nmbname,
- uint16 nb_flags,
- struct in_addr register_ip)
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ register_name_success_function success_fn,
+ register_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr register_ip,
+ struct in_addr wins_ip)
{
- struct packet_struct *p;
- struct response_record *rrec;
- BOOL ret;
-
- /* Sanity check. */
- if(subrec != unicast_subnet)
- {
- DEBUG(0,("queue_register_multihomed_name: should only be done on \
+ struct packet_struct *p;
+ struct response_record *rrec;
+ BOOL ret;
+
+ /* Sanity check. */
+ if(subrec != unicast_subnet) {
+ DEBUG(0,("queue_register_multihomed_name: should only be done on \
unicast subnet. subnet is %s\n.", subrec->subnet_name ));
- return NULL;
- }
+ return NULL;
+ }
- if(assert_check_subnet(subrec))
- return NULL;
+ if(assert_check_subnet(subrec))
+ return NULL;
- if(( p = create_and_init_netbios_packet(nmbname, False, True,
- subrec->bcast_ip)) == NULL)
- return NULL;
-
- if (nb_flags & NB_GROUP)
- ret = initiate_name_register_packet( p, nb_flags, ®ister_ip);
- else
- ret = initiate_multihomed_name_register_packet( p, nb_flags, ®ister_ip);
-
- if(ret == False)
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
-
- if((rrec = make_response_record(subrec, /* subnet record. */
- p, /* packet we sent. */
- resp_fn, /* function to call on response. */
- timeout_fn, /* function to call on timeout. */
- (success_function)success_fn, /* function to call on operation success. */
- (fail_function)fail_fn, /* function to call on operation fail. */
- userdata)) == NULL)
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
+ if ((p = create_and_init_netbios_packet(nmbname, False, True, wins_ip)) == NULL)
+ return NULL;
+
+ if (nb_flags & NB_GROUP)
+ ret = initiate_name_register_packet( p, nb_flags, ®ister_ip);
+ else
+ ret = initiate_multihomed_name_register_packet(p, nb_flags, ®ister_ip);
+
+ if (ret == False) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
- return rrec;
+ if ((rrec = make_response_record(subrec, /* subnet record. */
+ p, /* packet we sent. */
+ resp_fn, /* function to call on response. */
+ timeout_fn, /* function to call on timeout. */
+ (success_function)success_fn, /* function to call on operation success. */
+ (fail_function)fail_fn, /* function to call on operation fail. */
+ userdata)) == NULL) {
+ p->locked = False;
+ free_packet(p);
+ return NULL;
+ }
+
+ return rrec;
}
/****************************************************************************
****************************************************************************/
struct response_record *queue_release_name( struct subnet_record *subrec,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- release_name_success_function success_fn,
- release_name_fail_function fail_fn,
- struct userdata_struct *userdata,
- struct nmb_name *nmbname,
- uint16 nb_flags,
- struct in_addr release_ip)
+ response_function resp_fn,
+ timeout_response_function timeout_fn,
+ release_name_success_function success_fn,
+ release_name_fail_function fail_fn,
+ struct userdata_struct *userdata,
+ struct nmb_name *nmbname,
+ uint16 nb_flags,
+ struct in_addr release_ip,
+ struct in_addr dest_ip)
{
struct packet_struct *p;
struct response_record *rrec;
return NULL;
if ((p = create_and_init_netbios_packet(nmbname, (subrec != unicast_subnet), False,
- subrec->bcast_ip)) == NULL)
+ dest_ip)) == NULL)
return NULL;
if(initiate_name_release_packet( p, nb_flags, &release_ip) == False)
return rrec;
}
-/****************************************************************************
- Queue a refresh name packet to the broadcast address of a subnet.
-****************************************************************************/
-
-struct response_record *queue_refresh_name( struct subnet_record *subrec,
- response_function resp_fn,
- timeout_response_function timeout_fn,
- refresh_name_success_function success_fn,
- refresh_name_fail_function fail_fn,
- struct userdata_struct *userdata,
- struct name_record *namerec,
- struct in_addr refresh_ip)
-{
- struct packet_struct *p;
- struct response_record *rrec;
-
- if(assert_check_subnet(subrec))
- return NULL;
-
- if(( p = create_and_init_netbios_packet(&namerec->name, (subrec != unicast_subnet), False,
- subrec->bcast_ip)) == NULL)
- return NULL;
-
- if( !initiate_name_refresh_packet( p, namerec->data.nb_flags, &refresh_ip ) )
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
-
- if((rrec = make_response_record(subrec, /* subnet record. */
- p, /* packet we sent. */
- resp_fn, /* function to call on response. */
- timeout_fn, /* function to call on timeout. */
- (success_function)success_fn, /* function to call on operation success. */
- (fail_function)fail_fn, /* function to call on operation fail. */
- userdata)) == NULL)
- {
- p->locked = False;
- free_packet(p);
- return NULL;
- }
-
- return rrec;
-}
-
/****************************************************************************
Queue a query name packet to the broadcast address of a subnet.
****************************************************************************/
{
struct packet_struct *p;
struct response_record *rrec;
+ struct in_addr to_ip;
if(assert_check_subnet(subrec))
return NULL;
+ to_ip = subrec->bcast_ip;
+
+ /* queries to the WINS server turn up here as queries to IP 0.0.0.0
+ These need to be handled a bit differently */
+ if (subrec->type == UNICAST_SUBNET && is_zero_ip(to_ip)) {
+ /* what we really need to do is loop over each of our wins
+ * servers and wins server tags here, but that just doesn't
+ * fit our architecture at the moment (userdata may already
+ * be used when we get here). For now we just query the first
+ * active wins server on the first tag. */
+ char **tags = wins_srv_tags();
+ if (!tags) {
+ return NULL;
+ }
+ to_ip = wins_srv_ip_tag(tags[0], to_ip);
+ wins_srv_tags_free(tags);
+ }
+
if(( p = create_and_init_netbios_packet(nmbname,
(subrec != unicast_subnet),
(subrec == unicast_subnet),
- subrec->bcast_ip)) == NULL)
+ to_ip)) == NULL)
return NULL;
if(lp_bind_interfaces_only()) {
struct res_rec answers;
struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
BOOL loopback_this_packet = False;
- char *packet_type = "unknown";
+ const char *packet_type = "unknown";
/* Check if we are sending to or from ourselves. */
if(ismyip(orig_packet->ip) && (orig_packet->port == global_nmb_port))
struct dgram_packet *dgram = &p->packet.dgram;
int command = CVAL(buf,0);
struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
- extern pstring global_scope;
/* Drop the packet if it's a different NetBIOS scope, or
the source is from one of our names. */
- if (!strequal(dgram->dest_name.scope, global_scope))
+ if (!strequal(dgram->dest_name.scope, global_scope()))
{
DEBUG(7,("process_browse_packet: Discarding datagram from IP %s. Scope (%s) \
-mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope));
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope()));
return;
}
struct dgram_packet *dgram = &p->packet.dgram;
int command = SVAL(buf,0);
struct subnet_record *subrec = find_subnet_for_dgram_browse_packet(p);
- extern pstring global_scope;
/* Drop the packet if it's a different NetBIOS scope, or
the source is from one of our names. */
- if (!strequal(dgram->dest_name.scope, global_scope))
+ if (!strequal(dgram->dest_name.scope, global_scope()))
{
DEBUG(7,("process_lanman_packet: Discarding datagram from IP %s. Scope (%s) \
-mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope));
+mismatch with our scope (%s).\n", inet_ntoa(p->ip), dgram->dest_name.scope, global_scope()));
return;
}
len = SVAL(buf,smb_vwv11);
buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+ if (len <= 0)
+ return;
+
+ if (buf2 + len > buf + sizeof(dgram->data)) {
+ DEBUG(2,("process_dgram: datagram from %s to %s IP %s for %s len=%d too long.\n",
+ nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip), smb_buf(buf),len));
+ len = (buf + sizeof(dgram->data)) - buf;
+ }
+
DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
inet_ntoa(p->ip), smb_buf(buf),CVAL(buf2,0),len));
- if (len <= 0)
- return;
-
/* Datagram packet received for the browser mailslot */
if (strequal(smb_buf(buf),BROWSE_MAILSLOT))
{
to IP %s on subnet %s\n", rrec->response_id, inet_ntoa(rrec->packet->ip),
subrec->subnet_name));
}
- rrec->repeat_time += rrec->repeat_interval;
+ rrec->repeat_time = t + rrec->repeat_interval;
rrec->repeat_count--;
}
else
*listen_number = (count*2) + 2;
- if (*ppset) free(*ppset);
- if (*psock_array) free(*psock_array);
+ SAFE_FREE(*ppset);
+ SAFE_FREE(*psock_array);
*ppset = pset;
*psock_array = sock_array;
BlockSignals(False, SIGTERM);
- selrtn = sys_select(FD_SETSIZE,&fds,&timeout);
+ selrtn = sys_select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
/* We can only take signals when we are in the select - block them again here. */
inet_ntoa(packet->ip),packet->port));
free_packet(packet);
} else if ((ip_equal(loopback_ip, packet->ip) ||
- ismyip(packet->ip)) && packet->port == global_nmb_port) {
- DEBUG(7,("discarding own packet from %s:%d\n",
+ ismyip(packet->ip)) && packet->port == global_nmb_port &&
+ packet->packet.nmb.header.nm_flags.bcast) {
+ DEBUG(7,("discarding own bcast packet from %s:%d\n",
inet_ntoa(packet->ip),packet->port));
free_packet(packet);
} else {
free_packet(packet);
} else if ((ip_equal(loopback_ip, packet->ip) ||
ismyip(packet->ip)) && packet->port == DGRAM_PORT) {
- DEBUG(7,("discarding own packet from %s:%d\n",
+ DEBUG(7,("discarding own dgram packet from %s:%d\n",
inet_ntoa(packet->ip),packet->port));
free_packet(packet);
} else {
/****************************************************************************
Construct and send a netbios DGRAM.
**************************************************************************/
-BOOL send_mailslot(BOOL unique, char *mailslot,char *buf,int len,
- char *srcname, int src_type,
- char *dstname, int dest_type,
+BOOL send_mailslot(BOOL unique, const char *mailslot,char *buf,int len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
struct in_addr dest_ip,struct in_addr src_ip,
int dest_port)
{
/* Setup the smb part. */
ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
memcpy(tmp,ptr,4);
- set_message(ptr,17,17 + len,True);
+ set_message(ptr,17,23 + len,True);
memcpy(ptr,tmp,4);
- CVAL(ptr,smb_com) = SMBtrans;
+ SCVAL(ptr,smb_com,SMBtrans);
SSVAL(ptr,smb_vwv1,len);
SSVAL(ptr,smb_vwv11,len);
SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));