*/
#include "includes.h"
-
-int num_good_sends = 0;
-int num_good_receives = 0;
+#include "libsmb/nmblib.h"
static const struct opcode_names {
const char *nmb_opcode_name;
res->rr_class,
res->ttl ) );
- if( res->rdlength == 0 || res->rdata == NULL )
+ if (res->rdlength == 0) {
return;
+ }
for (i = 0; i < res->rdlength; i+= MAX_NETBIOSNAME_LEN) {
DEBUGADD(4, (" %s %3x char ", hdr, i));
Handle "compressed" name pointers.
******************************************************************/
-static BOOL handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
- BOOL *got_pointer,int *ret)
+static bool handle_name_ptrs(unsigned char *ubuf,int *offset,int length,
+ bool *got_pointer,int *ret)
{
int loop_count=0;
int m,n=0;
unsigned char *ubuf = (unsigned char *)inbuf;
int ret = 0;
- BOOL got_pointer=False;
+ bool got_pointer=False;
int loop_count=0;
int offset = ofs;
If buf == NULL this is a length calculation.
******************************************************************/
-static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
+static int put_nmb_name(char *buf, size_t buflen, int offset,struct nmb_name *name)
{
int ret,m;
nstring buf1;
}
if (buf) {
+ if (offset >= buflen) {
+ return 0;
+ }
buf[offset] = 0x20;
}
for (m=0;m<MAX_NETBIOSNAME_LEN;m++) {
if (buf) {
+ if (offset+2+2*m >= buflen) {
+ return 0;
+ }
buf[offset+1+2*m] = 'A' + ((buf1[m]>>4)&0xF);
buf[offset+2+2*m] = 'A' + (buf1[m]&0xF);
}
offset += 33;
if (buf) {
+ if (offset >= buflen) {
+ return 0;
+ }
buf[offset] = 0;
}
if (name->scope[0]) {
/* XXXX this scope handling needs testing */
- ret += strlen(name->scope) + 1;
+ size_t scopenamelen = strlen(name->scope) + 1;
+ ret += scopenamelen;
if (buf) {
- safe_strcpy(&buf[offset+1],name->scope,
- sizeof(name->scope));
+ if (offset+1+scopenamelen >= buflen) {
+ return 0;
+ }
+ strlcpy(&buf[offset+1],name->scope,
+ buflen - (offset+1));
p = &buf[offset+1];
while ((p = strchr_m(p,'.'))) {
buf[offset] = PTR_DIFF(p,&buf[offset+1]);
offset += (buf[offset] + 1);
+ if (offset+1 >= buflen) {
+ return 0;
+ }
p = &buf[offset+1];
}
buf[offset] = strlen(&buf[offset+1]);
char *nmb_namestr(const struct nmb_name *n)
{
- static int i=0;
- static fstring ret[4];
fstring name;
- char *p = ret[i];
+ char *result;
pull_ascii_fstring(name, n->name);
if (!n->scope[0])
- slprintf(p,sizeof(fstring)-1, "%s<%02x>",name,n->name_type);
+ result = talloc_asprintf(talloc_tos(), "%s<%02x>", name,
+ n->name_type);
else
- slprintf(p,sizeof(fstring)-1, "%s<%02x>.%s",
- name,n->name_type,n->scope);
+ result = talloc_asprintf(talloc_tos(), "%s<%02x>.%s", name,
+ n->name_type, n->scope);
- i = (i+1)%4;
- return(p);
+ SMB_ASSERT(result != NULL);
+ return result;
}
/*******************************************************************
Allocate and parse some resource records.
******************************************************************/
-static BOOL parse_alloc_res_rec(char *inbuf,int *offset,int length,
+static bool parse_alloc_res_rec(char *inbuf,int *offset,int length,
struct res_rec **recs, int count)
{
int i;
If buf == NULL this is a length calculation.
******************************************************************/
-static int put_res_rec(char *buf,int offset,struct res_rec *recs,int count)
+static int put_res_rec(char *buf, size_t buflen, int offset,struct res_rec *recs,int count)
{
int ret=0;
int i;
for (i=0;i<count;i++) {
- int l = put_nmb_name(buf,offset,&recs[i].rr_name);
+ int l = put_nmb_name(buf,buflen,offset,&recs[i].rr_name);
offset += l;
ret += l;
if (buf) {
This is documented in section 4.4.1 of RFC1002.
******************************************************************/
-static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
+static bool parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
{
int offset;
int flags;
or is invalid for some reason, True otherwise.
******************************************************************/
-static BOOL parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
+static bool parse_nmb(char *inbuf,int length,struct nmb_packet *nmb)
{
int nm_flags,offset;
/* Ensure this copy is not locked. */
pkt_copy->locked = False;
+ pkt_copy->recv_fd = -1;
+ pkt_copy->send_fd = -1;
/* Ensure this copy has no resource records. */
nmb = &packet->packet.nmb;
/* Ensure this copy is not locked. */
pkt_copy->locked = False;
+ pkt_copy->recv_fd = -1;
+ pkt_copy->send_fd = -1;
/* There are no additional pointers in a dgram packet,
we are finished. */
SAFE_FREE(packet);
}
+int packet_trn_id(struct packet_struct *p)
+{
+ int result;
+ switch (p->packet_type) {
+ case NMB_PACKET:
+ result = p->packet.nmb.header.name_trn_id;
+ break;
+ case DGRAM_PACKET:
+ result = p->packet.dgram.header.dgm_id;
+ break;
+ default:
+ result = -1;
+ }
+ return result;
+}
+
/*******************************************************************
Parse a packet buffer into a packet structure.
******************************************************************/
int port)
{
struct packet_struct *p;
- BOOL ok=False;
+ bool ok=False;
p = SMB_MALLOC_P(struct packet_struct);
if (!p)
return(NULL);
+ ZERO_STRUCTP(p); /* initialize for possible padding */
+
p->next = NULL;
p->prev = NULL;
p->ip = ip;
if (!packet)
return NULL;
- packet->fd = fd;
-
- num_good_receives++;
+ packet->recv_fd = fd;
+ packet->send_fd = -1;
DEBUG(5,("Received a packet of len %d from (%s) port %d\n",
length, inet_ntoa(packet->ip), packet->port ) );
Send a udp packet on a already open socket.
******************************************************************/
-static BOOL send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
+static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
{
- BOOL ret = False;
+ bool ret = False;
int i;
struct sockaddr_in sock_out;
DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
inet_ntoa(ip),port,strerror(errno)));
- if (ret)
- num_good_sends++;
-
return(ret);
}
If buf == NULL this is a length calculation.
******************************************************************/
-static int build_dgram(char *buf, size_t len, struct packet_struct *p)
+static int build_dgram(char *buf, size_t len, struct dgram_packet *dgram)
{
- struct dgram_packet *dgram = &p->packet.dgram;
unsigned char *ubuf = (unsigned char *)buf;
int offset=0;
if (dgram->header.msg_type == 0x10 ||
dgram->header.msg_type == 0x11 ||
dgram->header.msg_type == 0x12) {
- offset += put_nmb_name((char *)ubuf,offset,&dgram->source_name);
- offset += put_nmb_name((char *)ubuf,offset,&dgram->dest_name);
+ offset += put_nmb_name((char *)ubuf,len,offset,&dgram->source_name);
+ offset += put_nmb_name((char *)ubuf,len,offset,&dgram->dest_name);
}
if (buf) {
fstring unix_name;
memset( (char *)n, '\0', sizeof(struct nmb_name) );
fstrcpy(unix_name, name);
- strupper_m(unix_name);
+ (void)strupper_m(unix_name);
push_ascii(n->name, unix_name, sizeof(n->name), STR_TERMINATE);
n->name_type = (unsigned int)type & 0xFF;
- push_ascii(n->scope, global_scope(), 64, STR_TERMINATE);
+ push_ascii(n->scope, lp_netbios_scope(), 64, STR_TERMINATE);
}
/*******************************************************************
Compare two nmb names
******************************************************************/
-BOOL nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
+bool nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
{
return ((n1->name_type == n2->name_type) &&
strequal(n1->name ,n2->name ) &&
If buf == NULL this is a length calculation.
******************************************************************/
-static int build_nmb(char *buf, size_t len, struct packet_struct *p)
+static int build_nmb(char *buf, size_t len, struct nmb_packet *nmb)
{
- struct nmb_packet *nmb = &p->packet.nmb;
unsigned char *ubuf = (unsigned char *)buf;
int offset=0;
/* XXXX this doesn't handle a qdcount of > 1 */
if (len) {
/* Length check. */
- int extra = put_nmb_name(NULL,offset,
+ int extra = put_nmb_name(NULL,0,offset,
&nmb->question.question_name);
if (offset + extra > len) {
return 0;
}
}
- offset += put_nmb_name((char *)ubuf,offset,
+ offset += put_nmb_name((char *)ubuf,len,offset,
&nmb->question.question_name);
if (buf) {
RSSVAL(ubuf,offset,nmb->question.question_type);
if (nmb->header.ancount) {
if (len) {
/* Length check. */
- int extra = put_res_rec(NULL,offset,nmb->answers,
+ int extra = put_res_rec(NULL,0,offset,nmb->answers,
nmb->header.ancount);
if (offset + extra > len) {
return 0;
}
}
- offset += put_res_rec((char *)ubuf,offset,nmb->answers,
+ offset += put_res_rec((char *)ubuf,len,offset,nmb->answers,
nmb->header.ancount);
}
if (nmb->header.nscount) {
if (len) {
/* Length check. */
- int extra = put_res_rec(NULL,offset,nmb->nsrecs,
+ int extra = put_res_rec(NULL,0,offset,nmb->nsrecs,
nmb->header.nscount);
if (offset + extra > len) {
return 0;
}
}
- offset += put_res_rec((char *)ubuf,offset,nmb->nsrecs,
+ offset += put_res_rec((char *)ubuf,len,offset,nmb->nsrecs,
nmb->header.nscount);
}
} else if (nmb->header.arcount) {
if (len) {
/* Length check. */
- int extra = put_res_rec(NULL,offset,nmb->additional,
+ int extra = put_res_rec(NULL,0,offset,nmb->additional,
nmb->header.arcount);
if (offset + extra > len) {
return 0;
}
}
- offset += put_res_rec((char *)ubuf,offset,nmb->additional,
+ offset += put_res_rec((char *)ubuf,len,offset,nmb->additional,
nmb->header.arcount);
}
return offset;
switch (p->packet_type) {
case NMB_PACKET:
- len = build_nmb(buf,buflen,p);
+ len = build_nmb(buf,buflen,&p->packet.nmb);
break;
case DGRAM_PACKET:
- len = build_dgram(buf,buflen,p);
+ len = build_dgram(buf,buflen,&p->packet.dgram);
break;
}
Send a packet_struct.
******************************************************************/
-BOOL send_packet(struct packet_struct *p)
+bool send_packet(struct packet_struct *p)
{
char buf[1024];
int len=0;
if (!len)
return(False);
- return(send_udp(p->fd,buf,len,p->ip,p->port));
-}
-
-/****************************************************************************
- Receive a packet with timeout on a open UDP filedescriptor.
- The timeout is in milliseconds
-***************************************************************************/
-
-struct packet_struct *receive_packet(int fd,enum packet_type type,int t)
-{
- fd_set fds;
- struct timeval timeout;
- int ret;
-
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
- timeout.tv_sec = t/1000;
- timeout.tv_usec = 1000*(t%1000);
-
- if ((ret = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout)) == -1) {
- /* errno should be EBADF or EINVAL. */
- DEBUG(0,("select returned -1, errno = %s (%d)\n",
- strerror(errno), errno));
- return NULL;
- }
-
- if (ret == 0) /* timeout */
- return NULL;
-
- if (FD_ISSET(fd,&fds))
- return(read_packet(fd,type));
-
- return(NULL);
-}
-
-/****************************************************************************
- Receive a UDP/137 packet either via UDP or from the unexpected packet
- queue. The packet must be a reply packet and have the specified trn_id.
- The timeout is in milliseconds.
-***************************************************************************/
-
-struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
-{
- struct packet_struct *p;
-
- p = receive_packet(fd, NMB_PACKET, t);
-
- if (p && p->packet.nmb.header.response &&
- p->packet.nmb.header.name_trn_id == trn_id) {
- return p;
- }
- if (p)
- free_packet(p);
-
- /* try the unexpected packet queue */
- return receive_unexpected(NMB_PACKET, trn_id, NULL);
+ return(send_udp(p->send_fd,buf,len,p->ip,p->port));
}
/****************************************************************************
The timeout is in milliseconds.
***************************************************************************/
-struct packet_struct *receive_dgram_packet(int fd, int t,
- const char *mailslot_name)
-{
- struct packet_struct *p;
-
- p = receive_packet(fd, DGRAM_PACKET, t);
-
- if (p && match_mailslot_name(p, mailslot_name)) {
- return p;
- }
- if (p)
- free_packet(p);
-
- /* try the unexpected packet queue */
- return receive_unexpected(DGRAM_PACKET, 0, mailslot_name);
-}
-
/****************************************************************************
See if a datagram has the right mailslot name.
***************************************************************************/
-BOOL match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
+bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
{
struct dgram_packet *dgram = &p->packet.dgram;
char *buf;
}
/****************************************************************************
- Return the number of bits that match between two 4 character buffers
+ Return the number of bits that match between two len character buffers
***************************************************************************/
-int matching_quad_bits(unsigned char *p1, unsigned char *p2)
+int matching_len_bits(const unsigned char *p1, const unsigned char *p2, size_t len)
{
- int i, j, ret = 0;
- for (i=0; i<4; i++) {
+ size_t i, j;
+ int ret = 0;
+ for (i=0; i<len; i++) {
if (p1[i] != p2[i])
break;
ret += 8;
}
- if (i==4)
+ if (i==len)
return ret;
for (j=0; j<8; j++) {
static int name_query_comp(unsigned char *p1, unsigned char *p2)
{
- return matching_quad_bits(p2+2, sort_ip) -
- matching_quad_bits(p1+2, sort_ip);
+ return matching_len_bits(p2+2, sort_ip, 4) -
+ matching_len_bits(p1+2, sort_ip, 4);
}
/****************************************************************************
putip(sort_ip, (char *)&ip);
+ /* TODO:
+ this can't use TYPESAFE_QSORT() as the types are wrong.
+ It should be fixed to use a real type instead of char*
+ */
qsort(data, n, 6, QSORT_CAST name_query_comp);
}
-/*******************************************************************
- Convert, possibly using a stupid microsoft-ism which has destroyed
- the transport independence of netbios (for CIFS vendors that usually
- use the Win95-type methods, not for NT to NT communication, which uses
- DCE/RPC and therefore full-length unicode strings...) a dns name into
- a netbios name.
-
- The netbios name (NOT necessarily null-terminated) is truncated to 15
- characters.
-
- ******************************************************************/
-
-char *dns_to_netbios_name(const char *dns_name)
-{
- static nstring netbios_name;
- int i;
- StrnCpy(netbios_name, dns_name, MAX_NETBIOSNAME_LEN-1);
- netbios_name[15] = 0;
-
- /* ok. this is because of a stupid microsoft-ism. if the called host
- name contains a '.', microsoft clients expect you to truncate the
- netbios name up to and including the '.' this even applies, by
- mistake, to workgroup (domain) names, which is _really_ daft.
- */
- for (i = 0; i < 15; i++) {
- if (netbios_name[i] == '.') {
- netbios_name[i] = 0;
- break;
- }
- }
-
- return netbios_name;
-}
-
/****************************************************************************
Interpret the weird netbios "name" into a unix fstring. Return the name type.
+ Returns -1 on error.
****************************************************************************/
-static int name_interpret(char *in, fstring name)
+static int name_interpret(unsigned char *buf, size_t buf_len,
+ unsigned char *in, fstring name)
{
+ unsigned char *end_ptr = buf + buf_len;
int ret;
- int len = (*in++) / 2;
+ unsigned int len;
fstring out_string;
- char *out = out_string;
+ unsigned char *out = (unsigned char *)out_string;
*out=0;
- if (len > 30 || len<1)
- return(0);
+ if (in >= end_ptr) {
+ return -1;
+ }
+ len = (*in++) / 2;
+
+ if (len<1) {
+ return -1;
+ }
while (len--) {
+ if (&in[1] >= end_ptr) {
+ return -1;
+ }
if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
*out = 0;
return(0);
*out = ((in[0]-'A')<<4) + (in[1]-'A');
in += 2;
out++;
+ if (PTR_DIFF(out,out_string) >= sizeof(fstring)) {
+ return -1;
+ }
}
ret = out[-1];
out[-1] = 0;
-#ifdef NETBIOS_SCOPE
- /* Handle any scope names */
- while(*in) {
- *out++ = '.'; /* Scope names are separated by periods */
- len = *(unsigned char *)in++;
- StrnCpy(out, in, len);
- out += len;
- *out=0;
- in += len;
- }
-#endif
pull_ascii_fstring(name, out_string);
return(ret);
Note: <Out> must be (33 + strlen(scope) + 2) bytes long, at minimum.
****************************************************************************/
-int name_mangle( char *In, char *Out, char name_type )
+char *name_mangle(TALLOC_CTX *mem_ctx, const char *In, char name_type)
{
int i;
int len;
nstring buf;
- char *p = Out;
+ char *result;
+ char *p;
+
+ result = talloc_array(mem_ctx, char, 33 + strlen(lp_netbios_scope()) + 2);
+ if (result == NULL) {
+ return NULL;
+ }
+ p = result;
/* Safely copy the input string, In, into buf[]. */
if (strcmp(In,"*") == 0)
nstring buf_dos;
pull_ascii_fstring(buf_unix, In);
- strupper_m(buf_unix);
+ if (!strupper_m(buf_unix)) {
+ return NULL;
+ }
push_ascii_nstring(buf_dos, buf_unix);
put_name(buf, buf_dos, ' ', name_type);
p[0] = '\0';
/* Add the scope string. */
- for( i = 0, len = 0; *(global_scope()) != '\0'; i++, len++ ) {
- switch( (global_scope())[i] ) {
+ for( i = 0, len = 0; *(lp_netbios_scope()) != '\0'; i++, len++ ) {
+ switch( (lp_netbios_scope())[i] ) {
case '\0':
p[0] = len;
if( len > 0 )
p[len+1] = 0;
- return( name_len(Out) );
+ return result;
case '.':
p[0] = len;
p += (len + 1);
len = -1;
break;
default:
- p[len+1] = (global_scope())[i];
+ p[len+1] = (lp_netbios_scope())[i];
break;
}
}
- return( name_len(Out) );
+ return result;
}
/****************************************************************************
Find a pointer to a netbios name.
****************************************************************************/
-static char *name_ptr(char *buf,int ofs)
+static unsigned char *name_ptr(unsigned char *buf, size_t buf_len, unsigned int ofs)
{
- unsigned char c = *(unsigned char *)(buf+ofs);
+ unsigned char c = 0;
+ if (ofs > buf_len || buf_len < 1) {
+ return NULL;
+ }
+
+ c = *(unsigned char *)(buf+ofs);
if ((c & 0xC0) == 0xC0) {
- uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+ uint16_t l = 0;
+
+ if (ofs > buf_len - 1) {
+ return NULL;
+ }
+ l = RSVAL(buf, ofs) & 0x3FFF;
+ if (l > buf_len) {
+ return NULL;
+ }
DEBUG(5,("name ptr to pos %d from %d is %s\n",l,ofs,buf+l));
return(buf + l);
} else {
/****************************************************************************
Extract a netbios name from a buf (into a unix string) return name type.
+ Returns -1 on error.
****************************************************************************/
-int name_extract(char *buf,int ofs, fstring name)
+int name_extract(unsigned char *buf, size_t buf_len, unsigned int ofs, fstring name)
{
- char *p = name_ptr(buf,ofs);
- int d = PTR_DIFF(p,buf+ofs);
+ unsigned char *p = name_ptr(buf,buf_len,ofs);
name[0] = '\0';
- if (d < -50 || d > 50)
- return(0);
- return(name_interpret(p,name));
+ if (p == NULL) {
+ return -1;
+ }
+ return(name_interpret(buf,buf_len,p,name));
}
/****************************************************************************
Return the total storage length of a mangled name.
+ Returns -1 on error.
****************************************************************************/
-int name_len(char *s1)
+int name_len(unsigned char *s1, size_t buf_len)
{
/* NOTE: this argument _must_ be unsigned */
unsigned char *s = (unsigned char *)s1;
- int len;
+ int len = 0;
+ if (buf_len < 1) {
+ return -1;
+ }
/* If the two high bits of the byte are set, return 2. */
- if (0xC0 == (*s & 0xC0))
+ if (0xC0 == (*s & 0xC0)) {
+ if (buf_len < 2) {
+ return -1;
+ }
return(2);
+ }
/* Add up the length bytes. */
for (len = 1; (*s); s += (*s) + 1) {
len += *s + 1;
- SMB_ASSERT(len < 80);
+ if (len > buf_len) {
+ return -1;
+ }
}
return(len);