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
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
struct nmb_packet *nmb = NULL;
/* Allocate the packet_struct we will return. */
- if((packet = (struct packet_struct *)malloc(sizeof(*packet))) == NULL) {
+ if((packet = SMB_MALLOC_P(struct packet_struct)) == NULL) {
DEBUG(0,("create_and_init_netbios_packet: malloc fail (1) for packet struct.\n"));
return NULL;
}
{
struct nmb_packet *nmb = &packet->packet.nmb;
- if((nmb->additional = (struct res_rec *)malloc(sizeof(struct res_rec))) == NULL) {
+ if((nmb->additional = SMB_MALLOC_P(struct res_rec)) == NULL) {
DEBUG(0,("initiate_name_register_packet: malloc fail for additional record.\n"));
return False;
}
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);
+ userdata = (struct userdata_struct *)SMB_MALLOC(sizeof(*userdata) + strlen(tag) + 1);
if (!userdata) {
+ p->locked = False;
+ free_packet(p);
DEBUG(0,("Failed to allocate userdata structure!\n"));
return;
}
/****************************************************************************
Queue a query name packet to a given address from the WINS subnet.
****************************************************************************/
-
+
struct response_record *queue_query_name_from_wins_server( struct in_addr to_ip,
response_function resp_fn,
timeout_response_function timeout_fn,
/****************************************************************************
Queue a node status packet to a given name and address.
****************************************************************************/
-
+
struct response_record *queue_node_status( struct subnet_record *subrec,
response_function resp_fn,
timeout_response_function timeout_fn,
p->locked = False;
free_packet(p);
return NULL;
- }
+ }
if((rrec = make_response_record(subrec, /* subnet record. */
p, /* packet we sent. */
struct res_rec answers;
struct nmb_packet *orig_nmb = &orig_packet->packet.nmb;
BOOL loopback_this_packet = False;
+ int rr_type = RR_TYPE_NB;
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))
loopback_this_packet = True;
-
+
nmb = &packet.packet.nmb;
/* Do a partial copy of the packet. We clear the locked flag and
packet_type = "nmb_status";
nmb->header.nm_flags.recursion_desired = False;
nmb->header.nm_flags.recursion_available = False;
+ rr_type = RR_TYPE_NBSTAT;
break;
case NMB_QUERY:
packet_type = "nmb_query";
nmb->header.nm_flags.recursion_desired = True;
nmb->header.nm_flags.recursion_available = True;
+ if (rcode) {
+ rr_type = RR_TYPE_NULL;
+ }
break;
case NMB_REG:
case NMB_REG_REFRESH:
packet_type = "nmb_wack";
nmb->header.nm_flags.recursion_desired = False;
nmb->header.nm_flags.recursion_available = False;
+ rr_type = RR_TYPE_NULL;
break;
case WINS_REG:
packet_type = "wins_reg";
packet_type = "wins_query";
nmb->header.nm_flags.recursion_desired = True;
nmb->header.nm_flags.recursion_available = True;
+ if (rcode) {
+ rr_type = RR_TYPE_NULL;
+ }
break;
default:
DEBUG(0,("reply_netbios_packet: Unknown packet type: %s %s to ip %s\n",
nmb->header.nm_flags.bcast = False;
nmb->header.nm_flags.trunc = False;
nmb->header.nm_flags.authoritative = True;
-
+
nmb->header.rcode = rcode;
nmb->header.qdcount = 0;
nmb->header.ancount = 1;
nmb->header.nscount = 0;
nmb->header.arcount = 0;
-
+
memset((char*)&nmb->question,'\0',sizeof(nmb->question));
-
+
nmb->answers = &answers;
memset((char*)nmb->answers,'\0',sizeof(*nmb->answers));
-
+
nmb->answers->rr_name = orig_nmb->question.question_name;
- nmb->answers->rr_type = orig_nmb->question.question_type;
- nmb->answers->rr_class = orig_nmb->question.question_class;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = RR_CLASS_IN;
nmb->answers->ttl = ttl;
-
+
if (data && len) {
nmb->answers->rdlength = len;
memcpy(nmb->answers->rdata, data, len);
}
-
+
packet.packet_type = NMB_PACKET;
/* Ensure we send out on the same fd that the original
packet came in on to give the correct source IP address. */
packet.timestamp = time(NULL);
debug_nmb_packet(&packet);
-
+
if(loopback_this_packet) {
struct packet_struct *lo_packet;
DEBUG(5,("reply_netbios_packet: sending packet to ourselves.\n"));
packet_queue = packet;
return;
}
-
+
/* find the bottom */
- for (p=packet_queue;p->next;p=p->next)
+ for (p=packet_queue;p->next;p=p->next)
;
p->next = packet;
process_master_browser_announce(subrec, p, buf+1);
break;
case ANN_BecomeBackup:
- /*
+ /*
* We don't currently implement this. Log it just in case.
*/
debug_browse_data(buf, len);
command code %d from %s IP %s to %s\n", subrec->subnet_name, command, nmb_namestr(&dgram->source_name),
inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
break;
- }
+ }
}
/****************************************************************************
switch (command) {
case ANN_HostAnnouncement:
debug_browse_data(buf, len);
- process_lm_host_announce(subrec, p, buf+1);
+ process_lm_host_announce(subrec, p, buf+1, len > 1 ? len-1 : 0);
break;
case ANN_AnnouncementRequest:
- process_lm_announce_request(subrec, p, buf+1);
+ process_lm_announce_request(subrec, p, buf+1, len > 1 ? len-1 : 0);
break;
default:
DEBUG(0,("process_lanman_packet: On subnet %s ignoring browse packet \
return;
}
+ /* Ensure we have a large enough packet before looking inside. */
+ if (dgram->datasize < (smb_vwv12 - 2)) {
+ /* That's the offset minus the 4 byte length + 2 bytes of offset. */
+ DEBUG(0,("process_dgram: ignoring too short dgram packet (%u) sent to name %s from IP %s\n",
+ (unsigned int)dgram->datasize,
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
buf = &dgram->data[0];
buf -= 4; /* XXXX for the pseudo tcp length - someday I need to get rid of this */
len = SVAL(buf,smb_vwv11);
buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
- if (len <= 0)
+ if (len <= 0 || len > dgram->datasize) {
+ DEBUG(0,("process_dgram: ignoring malformed1 (datasize = %d, len = %d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
+ }
+
+ if (buf2 < dgram->data || (buf2 >= dgram->data + dgram->datasize)) {
+ DEBUG(0,("process_dgram: ignoring malformed2 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ (int)PTR_DIFF(buf2, dgram->data),
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
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;
+ if ((buf2 + len < dgram->data) || (buf2 + len > dgram->data + dgram->datasize)) {
+ DEBUG(0,("process_dgram: ignoring malformed3 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+ dgram->datasize,
+ len,
+ (int)PTR_DIFF(buf2, dgram->data),
+ nmb_namestr(&dgram->dest_name),
+ inet_ntoa(p->ip) ));
+ return;
}
DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
return ignore;
}
-
+
/****************************************************************************
Validate a request nmb packet.
****************************************************************************/
break;
}
break;
-
+
case NMB_NAME_RELEASE_OPCODE:
if(subrec == wins_server_subnet)
wins_process_name_release_request(subrec, p);
rrec->num_msgs++;
/* Ensure we don't re-send the request. */
rrec->repeat_count = 0;
-
+
/* Call the response received function for this packet. */
(*rrec->resp_fn)(subrec, rrec, p);
}
}
free_packet(p);
}
-}
+}
/*******************************************************************
Retransmit or timeout elements from all the outgoing subnet response
for (rrec = subrec->responselist; rrec; rrec = nextrrec) {
nextrrec = rrec->next;
-
+
if (rrec->repeat_time <= t) {
if (rrec->repeat_count > 0) {
/* Resend while we have a non-zero repeat_count. */
plus the broadcast sockets.
***************************************************************************/
-static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number)
+static BOOL create_listen_fdset(fd_set **ppset, int **psock_array, int *listen_number, int *maxfd)
{
int *sock_array = NULL;
struct subnet_record *subrec = NULL;
int count = 0;
int num = 0;
- fd_set *pset = (fd_set *)malloc(sizeof(fd_set));
+ fd_set *pset = SMB_MALLOC_P(fd_set);
if(pset == NULL) {
DEBUG(0,("create_listen_fdset: malloc fail !\n"));
if((count*2) + 2 > FD_SETSIZE) {
DEBUG(0,("create_listen_fdset: Too many file descriptors needed (%d). We can \
only use %d.\n", (count*2) + 2, FD_SETSIZE));
+ SAFE_FREE(pset);
return True;
}
- if((sock_array = (int *)malloc(((count*2) + 2)*sizeof(int))) == NULL) {
+ if((sock_array = SMB_MALLOC_ARRAY(int, (count*2) + 2)) == NULL) {
DEBUG(0,("create_listen_fdset: malloc fail for socket array.\n"));
+ SAFE_FREE(pset);
return True;
}
/* Add in the broadcast socket on 137. */
FD_SET(ClientNMB,pset);
sock_array[num++] = ClientNMB;
+ *maxfd = MAX( *maxfd, ClientNMB);
/* Add in the 137 sockets on all the interfaces. */
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
FD_SET(subrec->nmb_sock,pset);
sock_array[num++] = subrec->nmb_sock;
+ *maxfd = MAX( *maxfd, subrec->nmb_sock);
}
/* Add in the broadcast socket on 138. */
FD_SET(ClientDGRAM,pset);
sock_array[num++] = ClientDGRAM;
+ *maxfd = MAX( *maxfd, ClientDGRAM);
/* Add in the 138 sockets on all the interfaces. */
for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
FD_SET(subrec->dgram_sock,pset);
sock_array[num++] = subrec->dgram_sock;
+ *maxfd = MAX( *maxfd, subrec->dgram_sock);
}
*listen_number = (count*2) + 2;
*ppset = pset;
*psock_array = sock_array;
-
+
return False;
}
static int listen_number = 0;
static int *sock_array = NULL;
int i;
+ static int maxfd = 0;
- fd_set fds;
+ fd_set r_fds;
+ fd_set w_fds;
int selrtn;
struct timeval timeout;
#ifndef SYNC_DNS
#endif
if(listen_set == NULL || rescan_listen_set) {
- if(create_listen_fdset(&listen_set, &sock_array, &listen_number)) {
+ if(create_listen_fdset(&listen_set, &sock_array, &listen_number, &maxfd)) {
DEBUG(0,("listen_for_packets: Fatal error. unable to create listen set. Exiting.\n"));
return True;
}
rescan_listen_set = False;
}
- memcpy((char *)&fds, (char *)listen_set, sizeof(fd_set));
+ memcpy((char *)&r_fds, (char *)listen_set, sizeof(fd_set));
+ FD_ZERO(&w_fds);
#ifndef SYNC_DNS
dns_fd = asyncdns_fd();
if (dns_fd != -1) {
- FD_SET(dns_fd, &fds);
+ FD_SET(dns_fd, &r_fds);
+ maxfd = MAX( maxfd, dns_fd);
}
#endif
- /*
+ /*
* During elections and when expecting a netbios response packet we
* need to send election packets at tighter intervals.
* Ideally it needs to be the interval (in ms) between time now and
timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
timeout.tv_usec = 0;
+ {
+ struct timeval now = timeval_current();
+ event_add_to_select_args(nmbd_event_context(), &now,
+ &r_fds, &w_fds, &timeout, &maxfd);
+ }
+
+ if (timeval_is_zero(&timeout)) {
+ /* Process a timed event now... */
+ if (run_events(nmbd_event_context(), 0, NULL, NULL)) {
+ return False;
+ }
+ }
+
/* Prepare for the select - allow certain signals. */
BlockSignals(False, SIGTERM);
- selrtn = sys_select(FD_SETSIZE,&fds,NULL,NULL,&timeout);
+ selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&timeout);
/* We can only take signals when we are in the select - block them again here. */
return False;
}
+ if (run_events(nmbd_event_context(), selrtn, &r_fds, &w_fds)) {
+ return False;
+ }
+
#ifndef SYNC_DNS
- if (dns_fd != -1 && FD_ISSET(dns_fd,&fds)) {
+ if (dns_fd != -1 && FD_ISSET(dns_fd,&r_fds)) {
run_dns_queue();
}
#endif
for(i = 0; i < listen_number; i++) {
if (i < (listen_number/2)) {
/* Processing a 137 socket. */
- if (FD_ISSET(sock_array[i],&fds)) {
+ if (FD_ISSET(sock_array[i],&r_fds)) {
struct packet_struct *packet = read_packet(sock_array[i], NMB_PACKET);
if (packet) {
/*
}
} else {
/* Processing a 138 socket. */
- if (FD_ISSET(sock_array[i],&fds)) {
+ if (FD_ISSET(sock_array[i],&r_fds)) {
struct packet_struct *packet = read_packet(sock_array[i], DGRAM_PACKET);
if (packet) {
/*
/* generate_name_trn_id(); */ /* Not used, so gone, RJS */
/* DIRECT GROUP or UNIQUE datagram. */
- dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
dgram->header.flags.node_type = M_NODE;
dgram->header.flags.first = True;
dgram->header.flags.more = False;
dgram->header.source_port = DGRAM_PORT;
dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
dgram->header.packet_offset = 0;
-
+
make_nmb_name(&dgram->source_name,srcname,src_type);
make_nmb_name(&dgram->dest_name,dstname,dest_type);
SSVAL(ptr,smb_vwv16,2);
p2 = smb_buf(ptr);
safe_strcpy_base(p2, mailslot, dgram->data, sizeof(dgram->data));
- p2 = skip_string(p2,1);
-
+ p2 = skip_string(ptr,MAX_DGRAM_SIZE,p2);
+
if (((p2+len) > dgram->data+sizeof(dgram->data)) || ((p2+len) < p2)) {
DEBUG(0, ("send_mailslot: Cannot write beyond end of packet\n"));
return False;