]> git.samba.org - kamenim/samba-autobuild/.git/blobdiff - source3/libsmb/nmblib.c
Change all uses of uint32/16/8 in proto.h to uint32_t/16_t/8_t.
[kamenim/samba-autobuild/.git] / source3 / libsmb / nmblib.c
index 15a9a93ff29c37306e1ba9c0becfe929115ea085..4adc3da5fab2e3a7127b08e92dd578b34191d3be 100644 (file)
@@ -20,9 +20,7 @@
 */
 
 #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;
@@ -70,8 +68,9 @@ static void debug_nmb_res_rec(struct res_rec *res, const char *hdr)
                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));
@@ -290,7 +289,7 @@ void put_name(char *dest, const char *name, int pad, unsigned int name_type)
  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;
@@ -304,6 +303,9 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
        }
 
        if (buf) {
+               if (offset >= buflen) {
+                       return 0;
+               }
                buf[offset] = 0x20;
        }
 
@@ -311,6 +313,9 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
 
        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);
                }
@@ -318,20 +323,30 @@ static int put_nmb_name(char *buf,int offset,struct nmb_name *name)
        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]);
@@ -406,13 +421,13 @@ static bool parse_alloc_res_rec(char *inbuf,int *offset,int length,
  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) {
@@ -604,6 +619,8 @@ static struct packet_struct *copy_nmb_packet(struct packet_struct *packet)
 
        /* 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;
@@ -669,6 +686,8 @@ static struct packet_struct *copy_dgram_packet(struct packet_struct *packet)
 
        /* 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. */
@@ -724,6 +743,22 @@ void free_packet(struct packet_struct *packet)
        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.
 ******************************************************************/
@@ -794,9 +829,8 @@ struct packet_struct *read_packet(int fd,enum packet_type packet_type)
        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 ) );
@@ -838,9 +872,6 @@ static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
                DEBUG(0,("Packet send failed to %s(%d) ERRNO=%s\n",
                        inet_ntoa(ip),port,strerror(errno)));
 
-       if (ret)
-               num_good_sends++;
-
        return(ret);
 }
 
@@ -849,9 +880,8 @@ static bool send_udp(int fd,char *buf,int len,struct in_addr ip,int port)
  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;
 
@@ -874,8 +904,8 @@ static int build_dgram(char *buf, size_t len, struct packet_struct *p)
        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) {
@@ -904,10 +934,10 @@ void make_nmb_name( struct nmb_name *n, const char *name, int type)
        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);
 }
 
 /*******************************************************************
@@ -926,9 +956,8 @@ bool nmb_name_equal(struct nmb_name *n1, struct nmb_name *n2)
  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;
 
@@ -967,13 +996,13 @@ static int build_nmb(char *buf, size_t len, struct packet_struct *p)
                /* 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);
@@ -985,26 +1014,26 @@ static int build_nmb(char *buf, size_t len, struct packet_struct *p)
        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);
        }
 
@@ -1036,13 +1065,13 @@ static int build_nmb(char *buf, size_t len, struct packet_struct *p)
        } 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;
@@ -1058,11 +1087,11 @@ int build_packet(char *buf, size_t buflen, struct packet_struct *p)
 
        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;
        }
 
@@ -1085,62 +1114,7 @@ bool send_packet(struct packet_struct *p)
        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));
 }
 
 /****************************************************************************
@@ -1149,23 +1123,6 @@ struct packet_struct *receive_nmb_packet(int fd, int t, int trn_id)
  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.
 ***************************************************************************/
@@ -1191,7 +1148,7 @@ bool match_mailslot_name(struct packet_struct *p, const char *mailslot_name)
  Return the number of bits that match between two len character buffers
 ***************************************************************************/
 
-int matching_len_bits(unsigned char *p1, unsigned char *p2, size_t len)
+int matching_len_bits(const unsigned char *p1, const unsigned char *p2, size_t len)
 {
        size_t i, j;
        int ret = 0;
@@ -1237,26 +1194,42 @@ void sort_query_replies(char *data, int n, struct in_addr ip)
 
        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);
 }
 
 /****************************************************************************
  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);
@@ -1264,21 +1237,13 @@ static int name_interpret(char *in, fstring name)
                *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);
@@ -1289,12 +1254,19 @@ static int name_interpret(char *in, fstring name)
  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)
@@ -1306,7 +1278,9 @@ int name_mangle( char *In, char *Out, char name_type )
                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);
@@ -1325,37 +1299,50 @@ int name_mangle( char *In, char *Out, char 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 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 {
@@ -1365,37 +1352,48 @@ static char *name_ptr(char *buf,int ofs)
 
 /****************************************************************************
  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);