Diff for /libraries/liblber/encode.c between versions 1.64 and 1.64.2.8

version 1.64, 2006/01/03 22:12:07 version 1.64.2.8, 2009/10/31 00:01:23
Line 1 Line 1
 /* encode.c - ber output encoding routines */  /* encode.c - ber output encoding routines */
 /* $OpenLDAP: pkg/ldap/libraries/liblber/encode.c,v 1.63 2005/09/13 05:51:51 hyc Exp $ */  /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.  /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *   *
  * Copyright 1998-2006 The OpenLDAP Foundation.   * Copyright 1998-2009 The OpenLDAP Foundation.
  * All rights reserved.   * All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
Line 30 Line 30
   
 #include "portable.h"  #include "portable.h"
   
   #include <ctype.h>
   #include <limits.h>
 #include <stdio.h>  #include <stdio.h>
   
 #include <ac/stdlib.h>  #include <ac/stdlib.h>
Line 40 Line 42
   
 #include "lber-int.h"  #include "lber-int.h"
   
 static int ber_put_len LDAP_P((  
         BerElement *ber,  
         ber_len_t len,  
         int nosos ));  
   
 static int ber_start_seqorset LDAP_P((  
         BerElement *ber,  
         ber_tag_t tag ));  
   
 static int ber_put_seqorset LDAP_P(( BerElement *ber ));  #define OCTET_SIZE(type) ((ber_len_t) (sizeof(type)*CHAR_BIT + 7) / 8)
   #define TAGBUF_SIZE OCTET_SIZE(ber_tag_t)
   #define LENBUF_SIZE (1 + OCTET_SIZE(ber_len_t))
   #define HEADER_SIZE (TAGBUF_SIZE + LENBUF_SIZE)
   
 static int ber_put_int_or_enum LDAP_P((  /*
         BerElement *ber,   * BER element size constrains:
         ber_int_t num,   *
         ber_tag_t tag ));   * - We traditionally support a length of max 0xffffffff.  However
    *   some functions return an int length so that is their max.
    *   MAXINT_BERSIZE is the max for those functions.
    *
    * - MAXINT_BERSIZE must fit in MAXINT_BERSIZE_OCTETS octets.
    *
    * - sizeof(ber_elem_size_t) is normally MAXINT_BERSIZE_OCTETS:
    *   Big enough for MAXINT_BERSIZE, but not more.  (Larger wastes
    *   space in the working encoding and DER encoding of a sequence
    *   or set.  Smaller further limits sizes near a sequence/set.)
    *
    * ber_len_t is mostly unrelated to this.  Which may be for the best,
    * since it is also used for lengths of data that are never encoded.
    */
   #define MAXINT_BERSIZE \
           (INT_MAX>0xffffffffUL ? (ber_len_t) 0xffffffffUL : INT_MAX-HEADER_SIZE)
   #define MAXINT_BERSIZE_OCTETS 4
   typedef ber_uint_t ber_elem_size_t; /* normally 32 bits */
   
 #define BER_TOP_BYTE(type)      (sizeof(type)-1)  
 #define BER_TOP_MASK(type)      ((type)0xffU << (BER_TOP_BYTE(type)*8))  
   
 static int  /* Prepend tag to ptr, which points to the end of a tag buffer */
 ber_calc_taglen( ber_tag_t tag )  static unsigned char *
   ber_prepend_tag( unsigned char *ptr, ber_tag_t tag )
 {  {
         int     i = BER_TOP_BYTE(ber_tag_t);          do {
         ber_tag_t       mask = BER_TOP_MASK(ber_tag_t);                  *--ptr = (unsigned char) tag & 0xffU;
           } while ( (tag >>= 8) != 0 );
         /* find the first non-all-zero byte in the tag */  
         for ( ; i > 0; i-- ) {  
                 /* not all zero */  
                 if ( tag & mask ) break;  
                 mask >>= 8;  
         }  
   
         return i + 1;          return ptr;
 }  }
   
 static int  /* Prepend ber length to ptr, which points to the end of a length buffer */
 ber_put_tag(  static unsigned char *
         BerElement      *ber,  ber_prepend_len( unsigned char *ptr, ber_len_t len )
         ber_tag_t tag,  
         int nosos )  
 {  
         int rc;  
         int taglen;  
         int     i;  
         unsigned char nettag[sizeof(ber_tag_t)];  
   
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         taglen = ber_calc_taglen( tag );  
   
         for( i=taglen-1; i>=0; i-- ) {  
                 nettag[i] = (unsigned char)(tag & 0xffU);  
                 tag >>= 8;  
         }  
   
         rc = ber_write( ber, (char *) nettag, taglen, nosos );  
   
         return rc;  
 }  
   
 static ber_len_t  
 ber_calc_lenlen( ber_len_t len )  
 {  {
         /*          /*
          * short len if it's less than 128 - one byte giving the len,           * short len if it's less than 128 - one byte giving the len,
          * with bit 8 0.           * with bit 8 0.
          */  
   
         if ( len <= (ber_len_t) 0x7FU ) return 1;  
   
         /*  
          * long len otherwise - one byte with bit 8 set, giving the           * long len otherwise - one byte with bit 8 set, giving the
          * length of the length, followed by the length itself.           * length of the length, followed by the length itself.
          */           */
   
         if ( len <= (ber_len_t) 0xffU ) return 2;          *--ptr = (unsigned char) len & 0xffU;
         if ( len <= (ber_len_t) 0xffffU ) return 3;  
         if ( len <= (ber_len_t) 0xffffffU ) return 4;          if ( len >= 0x80 ) {
                   unsigned char *endptr = ptr--;
   
         return 5;                  while ( (len >>= 8) != 0 ) {
                           *ptr-- = (unsigned char) len & 0xffU;
                   }
                   *ptr = (unsigned char) (endptr - ptr) + 0x80U;
           }
   
           return ptr;
 }  }
   
 static int  /* out->bv_len should be the buffer size on input */
 ber_put_len( BerElement *ber, ber_len_t len, int nosos )  int
   ber_encode_oid( BerValue *in, BerValue *out )
 {  {
         int rc;          unsigned char *der;
         int             i,j;          unsigned long val1, val;
         char            lenlen;          int i, j, len;
         ber_len_t       mask;          char *ptr, *end, *inend;
         unsigned char netlen[sizeof(ber_len_t)];  
   
         assert( ber != NULL );          assert( in != NULL );
         assert( LBER_VALID( ber ) );          assert( out != NULL );
   
         /*          if ( !out->bv_val || out->bv_len < in->bv_len/2 )
          * short len if it's less than 128 - one byte giving the len,                  return -1;
          * with bit 8 0.  
          */  
   
         if ( len <= 127 ) {          der = (unsigned char *) out->bv_val;
                 char length_byte = (char) len;          ptr = in->bv_val;
                 return ber_write( ber, &length_byte, 1, nosos );          inend = ptr + in->bv_len;
         }  
   
         /*          /* OIDs start with <0-1>.<0-39> or 2.<any>, DER-encoded 40*val1+val2 */
          * long len otherwise - one byte with bit 8 set, giving the          if ( !isdigit( (unsigned char) *ptr )) return -1;
          * length of the length, followed by the length itself.          val1 = strtoul( ptr, &end, 10 );
          */          if ( end == ptr || val1 > 2 ) return -1;
           if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1;
           val = strtoul( end, &ptr, 10 );
           if ( ptr == end ) return -1;
           if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1;
           val += val1 * 40;
   
         /* find the first non-all-zero byte */          for (;;) {
         i = BER_TOP_BYTE(ber_len_t);                  if ( ptr > inend ) return -1;
         mask = BER_TOP_MASK(ber_len_t);  
         for ( ; i > 0; i-- ) {  
                 /* not all zero */  
                 if ( len & mask ) break;  
                 mask >>= 8;  
         }  
         lenlen = (unsigned char) ++i;  
         if ( lenlen > 4 ) return -1;  
   
         lenlen |= 0x80UL;                  /* Write the OID component little-endian, then reverse it */
                   len = 0;
                   do {
                           der[len++] = (val & 0xff) | 0x80;
                   } while ( (val >>= 7) != 0 );
                   der[0] &= 0x7f;
                   for ( i = 0, j = len; i < --j; i++ ) {
                           unsigned char tmp = der[i];
                           der[i] = der[j];
                           der[j] = tmp;
                   }
                   der += len;
   
         /* write the length of the length */                  if ( ptr == inend )
         if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) return -1;                          break;
   
         for( j=i-1; j>=0; j-- ) {                  if ( *ptr++ != '.' ) return -1;
                 netlen[j] = (unsigned char)(len & 0xffU);                  if ( !isdigit( (unsigned char) *ptr )) return -1;
                 len >>= 8;                  val = strtoul( ptr, &end, 10 );
                   if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1;
                   ptr = end;
         }          }
   
         /* write the length itself */          out->bv_len = (char *)der - out->bv_val;
         rc = ber_write( ber, (char *) netlen, i, nosos );          return 0;
   
         return rc == i ?  i+1 : -1;  
 }  }
   
 static int  static int
Line 183  ber_put_int_or_enum( Line 172  ber_put_int_or_enum(
         ber_int_t num,          ber_int_t num,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         int rc;          ber_uint_t unum;
         int     i, j, sign, taglen, lenlen;          unsigned char sign, data[TAGBUF_SIZE+1 + OCTET_SIZE(ber_int_t)], *ptr;
         ber_len_t       len;  
         ber_uint_t      unum, mask;  
         unsigned char netnum[sizeof(ber_uint_t)];  
   
         assert( ber != NULL );          sign = 0;
         assert( LBER_VALID( ber ) );  
   
         sign = (num < 0);  
         unum = num;     /* Bit fiddling should be done with unsigned values */          unum = num;     /* Bit fiddling should be done with unsigned values */
           if ( num < 0 ) {
         /*                  sign = 0xffU;
          * high bit is set - look for first non-all-one byte                  unum = ~unum;
          * high bit is clear - look for first non-all-zero byte  
          */  
         i = BER_TOP_BYTE(ber_int_t);  
         mask = BER_TOP_MASK(ber_uint_t);  
         for ( ; i > 0; i-- ) {  
                 if ( sign ) {  
                         /* not all ones */  
                         if ( (unum & mask) != mask ) break;  
                 } else {  
                         /* not all zero */  
                         if ( unum & mask ) break;  
                 }  
                 mask >>= 8;  
         }          }
           for ( ptr = &data[sizeof(data) - 1] ;; unum >>= 8 ) {
         /*                  *ptr-- = (sign ^ (unsigned char) unum) & 0xffU;
          * we now have the "leading byte".  if the high bit on this                  if ( unum < 0x80 )      /* top bit at *ptr is sign bit */
          * byte matches the sign bit, we need to "back up" a byte.                          break;
          */  
         mask = (unum & ((ber_uint_t)0x80U << (i * 8)));  
         if ( (mask && !sign) || (sign && !mask) ) {  
                 i++;  
         }  
   
         len = i + 1;  
   
         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {  
                 return -1;  
         }  
   
         if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) {  
                 return -1;  
         }  
         i++;  
   
         for( j=i-1; j>=0; j-- ) {  
                 netnum[j] = (unsigned char)(unum & 0xffU);  
                 unum >>= 8;  
         }          }
   
         rc = ber_write( ber, (char *) netnum, i, 0 );          *ptr = (unsigned char) (&data[sizeof(data) - 1] - ptr); /* length */
           ptr = ber_prepend_tag( ptr, tag );
   
         /* length of tag + length + contents */          return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
         return rc == i ? taglen + lenlen + i : -1;  
 }  }
   
 int  int
Line 249  ber_put_enum( Line 199  ber_put_enum(
         ber_int_t num,          ber_int_t num,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_ENUMERATED;                  tag = LBER_ENUMERATED;
         }          }
Line 265  ber_put_int( Line 212  ber_put_int(
         ber_int_t num,          ber_int_t num,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_INTEGER;                  tag = LBER_INTEGER;
         }          }
Line 282  ber_put_ostring( Line 226  ber_put_ostring(
         ber_len_t len,          ber_len_t len,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         int taglen, lenlen, rc;          int rc;
           unsigned char header[HEADER_SIZE], *ptr;
         assert( ber != NULL );  
         assert( str != NULL );  
   
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_OCTETSTRING;                  tag = LBER_OCTETSTRING;
         }          }
   
         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )          if ( len > MAXINT_BERSIZE ) {
                 return -1;                  return -1;
           }
   
         if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||          ptr = ber_prepend_len( &header[sizeof(header)], len );
                 (ber_len_t) ber_write( ber, str, len, 0 ) != len )          ptr = ber_prepend_tag( ptr, tag );
         {  
                 rc = -1;          rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 );
         } else {          if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) {
                 /* return length of tag + length + contents */                  /* length(tag + length + contents) */
                 rc = taglen + lenlen + len;                  return rc + (int) len;
         }          }
   
         return rc;          return -1;
 }  }
   
 int  int
Line 314  ber_put_berval( Line 255  ber_put_berval(
         struct berval *bv,          struct berval *bv,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if( bv == NULL || bv->bv_len == 0 ) {          if( bv == NULL || bv->bv_len == 0 ) {
                 return ber_put_ostring( ber, "", (ber_len_t) 0, tag );                  return ber_put_ostring( ber, "", (ber_len_t) 0, tag );
         }          }
Line 330  ber_put_string( Line 268  ber_put_string(
         LDAP_CONST char *str,          LDAP_CONST char *str,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         assert( ber != NULL );  
         assert( str != NULL );          assert( str != NULL );
   
         assert( LBER_VALID( ber ) );  
   
         return ber_put_ostring( ber, str, strlen( str ), tag );          return ber_put_ostring( ber, str, strlen( str ), tag );
 }  }
   
Line 345  ber_put_bitstring( Line 280  ber_put_bitstring(
         ber_len_t blen /* in bits */,          ber_len_t blen /* in bits */,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         int                             taglen, lenlen;          int rc;
         ber_len_t               len;          ber_len_t               len;
         unsigned char   unusedbits;          unsigned char   unusedbits, header[HEADER_SIZE + 1], *ptr;
   
         assert( ber != NULL );  
         assert( str != NULL );  
   
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_BITSTRING;                  tag = LBER_BITSTRING;
         }          }
   
         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {          unusedbits = (unsigned char) -blen & 7;
           len = blen / 8 + (unusedbits != 0); /* (blen+7)/8 without overflow */
           if ( len >= MAXINT_BERSIZE ) {
                 return -1;                  return -1;
         }          }
   
         len = ( blen + 7 ) / 8;          header[sizeof(header) - 1] = unusedbits;
         unusedbits = (unsigned char) ((len * 8) - blen);          ptr = ber_prepend_len( &header[sizeof(header) - 1], len + 1 );
         if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) {          ptr = ber_prepend_tag( ptr, tag );
                 return -1;  
         }  
   
         if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) {          rc = ber_write( ber, (char *) ptr, &header[sizeof(header)] - ptr, 0 );
                 return -1;          if ( rc >= 0 && ber_write( ber, str, len, 0 ) >= 0 ) {
                   /* length(tag + length + unused bit count + bitstring) */
                   return rc + (int) len;
         }          }
   
         if ( (ber_len_t) ber_write( ber, str, len, 0 ) != len ) {          return -1;
                 return -1;  
         }  
   
         /* return length of tag + length + unused bit count + contents */  
         return taglen + 1 + lenlen + len;  
 }  }
   
 int  int
 ber_put_null( BerElement *ber, ber_tag_t tag )  ber_put_null( BerElement *ber, ber_tag_t tag )
 {  {
         int     taglen;          unsigned char data[TAGBUF_SIZE + 1], *ptr;
   
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_NULL;                  tag = LBER_NULL;
         }          }
   
         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {          data[sizeof(data) - 1] = 0;                     /* length */
                 return -1;          ptr = ber_prepend_tag( &data[sizeof(data) - 1], tag );
         }  
   
         if ( ber_put_len( ber, 0, 0 ) != 1 ) {  
                 return -1;  
         }  
   
         return taglen + 1;          return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
 }  }
   
 int  int
Line 409  ber_put_boolean( Line 328  ber_put_boolean(
         ber_int_t boolval,          ber_int_t boolval,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         int                             taglen;          unsigned char data[TAGBUF_SIZE + 2], *ptr;
         unsigned char   c;  
   
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT )          if ( tag == LBER_DEFAULT )
                 tag = LBER_BOOLEAN;                  tag = LBER_BOOLEAN;
   
         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {          data[sizeof(data) - 1] = boolval ? 0xff : 0;
                 return -1;          data[sizeof(data) - 2] = 1;                     /* length */
         }          ptr = ber_prepend_tag( &data[sizeof(data) - 2], tag );
   
         if ( ber_put_len( ber, 1, 0 ) != 1 ) {          return ber_write( ber, (char *) ptr, &data[sizeof(data)] - ptr, 0 );
                 return -1;  }
         }  
   
         c = boolval ? (unsigned char) ~0U : (unsigned char) 0U;  
   
         if ( ber_write( ber, (char *) &c, 1, 0 ) != 1 ) {  /* Max number of length octets in a sequence or set, normally 5 */
                 return -1;  #define SOS_LENLEN (1 + (sizeof(ber_elem_size_t) > MAXINT_BERSIZE_OCTETS ? \
         }                  (ber_len_t) sizeof(ber_elem_size_t) : MAXINT_BERSIZE_OCTETS))
   
         return taglen + 2;  /* Header of incomplete sequence or set */
 }  typedef struct seqorset_header {
           char xtagbuf[TAGBUF_SIZE + 1];  /* room for tag + len(tag or len) */
 #define FOUR_BYTE_LEN   5          union {
                   ber_elem_size_t offset;         /* enclosing seqence/set */
                   char padding[SOS_LENLEN-1];     /* for final length encoding */
           } next_sos;
   #       define SOS_TAG_END(header) ((unsigned char *) &(header).next_sos - 1)
   } Seqorset_header;
   
   /* Start a sequence or set */
 static int  static int
 ber_start_seqorset(  ber_start_seqorset(
         BerElement *ber,          BerElement *ber,
         ber_tag_t tag )          ber_tag_t tag )
 {  {
         Seqorset        *new;          /*
            * Write the tag and SOS_LENLEN octets reserved for length, to ber.
            * For now, length octets = (tag length, previous ber_sos_inner).
            *
            * Update ber_sos_inner and the write-cursor ber_sos_ptr.  ber_ptr
            * will not move until the outermost sequence or set is complete.
            */
   
           Seqorset_header header;
           unsigned char   *headptr;
           ber_len_t               taglen, headlen;
           char                    *dest, **p;
   
         assert( ber != NULL );          assert( ber != NULL );
         assert( LBER_VALID( ber ) );          assert( LBER_VALID( ber ) );
   
         new = (Seqorset *) ber_memcalloc_x( 1, sizeof(Seqorset), ber->ber_memctx );          if ( ber->ber_sos_ptr == NULL ) {       /* outermost sequence/set? */
                   header.next_sos.offset = 0;
         if ( new == NULL ) {                  p = &ber->ber_ptr;
                 return -1;  
         }  
   
         new->sos_ber = ber;  
         if ( ber->ber_sos == NULL ) {  
                 new->sos_first = ber->ber_ptr;  
         } else {          } else {
                 new->sos_first = ber->ber_sos->sos_ptr;                  if ( (ber_len_t) -1 > (ber_elem_size_t) -1 ) {
                           if ( ber->ber_sos_inner > (ber_elem_size_t) -1 )
                                   return -1;
                   }
                   header.next_sos.offset = ber->ber_sos_inner;
                   p = &ber->ber_sos_ptr;
         }          }
           headptr = ber_prepend_tag( SOS_TAG_END(header), tag );
           *SOS_TAG_END(header) = taglen = SOS_TAG_END(header) - headptr;
           headlen = taglen + SOS_LENLEN;
   
           /* As ber_write(,headptr,headlen,) except update ber_sos_ptr, not *p */
           if ( headlen > (ber_len_t) (ber->ber_end - *p) ) {
                   if ( ber_realloc( ber, headlen ) != 0 )
                           return -1;
           }
           dest = *p;
           AC_MEMCPY( dest, headptr, headlen );
           ber->ber_sos_ptr = dest + headlen;
   
         /* Set aside room for a 4 byte length field */          ber->ber_sos_inner = dest + taglen - ber->ber_buf;
         new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;  
         new->sos_tag = tag;  
   
         new->sos_next = ber->ber_sos;  
         ber->ber_sos = new;  
   
           /*
            * Do not return taglen + SOS_LENLEN here - then ber_put_seqorset()
            * should return lenlen - SOS_LENLEN + len, which can be < 0.
            */
         return 0;          return 0;
 }  }
   
 int  int
 ber_start_seq( BerElement *ber, ber_tag_t tag )  ber_start_seq( BerElement *ber, ber_tag_t tag )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_SEQUENCE;                  tag = LBER_SEQUENCE;
         }          }
Line 486  ber_start_seq( BerElement *ber, ber_tag_ Line 423  ber_start_seq( BerElement *ber, ber_tag_
 int  int
 ber_start_set( BerElement *ber, ber_tag_t tag )  ber_start_set( BerElement *ber, ber_tag_t tag )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         if ( tag == LBER_DEFAULT ) {          if ( tag == LBER_DEFAULT ) {
                 tag = LBER_SET;                  tag = LBER_SET;
         }          }
Line 496  ber_start_set( BerElement *ber, ber_tag_ Line 430  ber_start_set( BerElement *ber, ber_tag_
         return ber_start_seqorset( ber, tag );          return ber_start_seqorset( ber, tag );
 }  }
   
   /* End a sequence or set */
 static int  static int
 ber_put_seqorset( BerElement *ber )  ber_put_seqorset( BerElement *ber )
 {  {
         int rc;          Seqorset_header header;
         ber_len_t       len;          unsigned char   *lenptr;        /* length octets in the sequence/set */
         unsigned char netlen[sizeof(ber_len_t)];          ber_len_t               len;            /* length(contents) */
         int                     taglen;          ber_len_t               xlen;           /* len + length(length) */
         ber_len_t       lenlen;  
         unsigned char   ltag = 0x80U + FOUR_BYTE_LEN - 1;  
         Seqorset        *next;  
         Seqorset        **sos = &ber->ber_sos;  
   
         assert( ber != NULL );          assert( ber != NULL );
         assert( LBER_VALID( ber ) );          assert( LBER_VALID( ber ) );
   
         if( *sos == NULL ) return -1;          if ( ber->ber_sos_ptr == NULL ) return -1;
   
         /*  
          * If this is the toplevel sequence or set, we need to actually  
          * write the stuff out.  Otherwise, it's already been put in  
          * the appropriate buffer and will be written when the toplevel  
          * one is written.  In this case all we need to do is update the  
          * length and tag.  
          */  
   
         len = (*sos)->sos_clen;  
   
         if ( sizeof(ber_len_t) > 4 && len > 0xffffffffUL ) {          lenptr = (unsigned char *) ber->ber_buf + ber->ber_sos_inner;
           xlen = ber->ber_sos_ptr - (char *) lenptr;
           if ( xlen > MAXINT_BERSIZE + SOS_LENLEN ) {
                 return -1;                  return -1;
         }          }
   
         if ( ber->ber_options & LBER_USE_DER ) {          /* Extract sequence/set information from length octets */
                 lenlen = ber_calc_lenlen( len );          memcpy( SOS_TAG_END(header), lenptr, SOS_LENLEN );
   
         } else {  
                 lenlen = FOUR_BYTE_LEN;  
         }  
   
         if( lenlen > 1 ) {          /* Store length, and close gap of leftover reserved length octets */
           len = xlen - SOS_LENLEN;
           if ( !(ber->ber_options & LBER_USE_DER) ) {
                 int i;                  int i;
                 ber_len_t j = len;                  lenptr[0] = SOS_LENLEN - 1 + 0x80; /* length(length)-1 */
                 for( i=lenlen-2; i >= 0; i-- ) {                  for( i = SOS_LENLEN; --i > 0; len >>= 8 ) {
                         netlen[i] = j & 0xffU;                          lenptr[i] = len & 0xffU;
                         j >>= 8;  
                 }                  }
         } else {          } else {
                 netlen[0] = (unsigned char)(len & 0x7fU);                  unsigned char *p = ber_prepend_len( lenptr + SOS_LENLEN, len );
         }                  ber_len_t unused = p - lenptr;
                   if ( unused != 0 ) {
         if ( (next = (*sos)->sos_next) == NULL ) {                          /* length(length) < the reserved SOS_LENLEN bytes */
                 /* write the tag */                          xlen -= unused;
                 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) {                          AC_MEMCPY( lenptr, p, xlen );
                         return( -1 );                          ber->ber_sos_ptr = (char *) lenptr + xlen;
                 }                  }
           }
   
                 if ( ber->ber_options & LBER_USE_DER ) {          ber->ber_sos_inner = header.next_sos.offset;
                         /* Write the length in the minimum # of octets */          if ( header.next_sos.offset == 0 ) { /* outermost sequence/set? */
                         if ( ber_put_len( ber, len, 1 ) == -1 ) {  
                                 return -1;  
                         }  
   
                         if (lenlen != FOUR_BYTE_LEN) {  
                                 /*  
                                  * We set aside FOUR_BYTE_LEN bytes for  
                                  * the length field.  Move the data if  
                                  * we don't actually need that much  
                                  */  
                                 AC_MEMCPY( (*sos)->sos_first + taglen +  
                                     lenlen, (*sos)->sos_first + taglen +  
                                     FOUR_BYTE_LEN, len );  
                         }  
                 } else {  
                         /* Fill FOUR_BYTE_LEN bytes for length field */  
                         /* one byte of length length */  
                         if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 ) {  
                                 return -1;  
                         }  
   
                         /* the length itself */  
                         rc  = ber_write( ber, (char *) netlen, FOUR_BYTE_LEN-1, 1 );  
   
                         if( rc != FOUR_BYTE_LEN - 1 ) {  
                                 return -1;  
                         }  
                 }  
                 /* The ber_ptr is at the set/seq start - move it to the end */                  /* The ber_ptr is at the set/seq start - move it to the end */
                 (*sos)->sos_ber->ber_ptr += len;                  ber->ber_ptr = ber->ber_sos_ptr;
                   ber->ber_sos_ptr = NULL;
         } else {  
                 int i;  
                 unsigned char nettag[sizeof(ber_tag_t)];  
                 ber_tag_t tmptag = (*sos)->sos_tag;  
   
                 if( ber->ber_sos->sos_ptr > ber->ber_end ) {  
                         /* The sos_ptr exceeds the end of the BerElement  
                          * this can happen, for example, when the sos_ptr  
                          * is near the end and no data was written for the  
                          * 'V'.  We must realloc the BerElement to ensure  
                          * we don't overwrite the buffer when writing  
                          * the tag and length fields.  
                          */  
                         ber_len_t ext = ber->ber_sos->sos_ptr - ber->ber_end;  
   
                         if( ber_realloc( ber,  ext ) != 0 ) {  
                                 return -1;  
                         }  
                 }  
   
                 /* the tag */  
                 taglen = ber_calc_taglen( tmptag );  
   
                 for( i = taglen-1; i >= 0; i-- ) {  
                         nettag[i] = (unsigned char)(tmptag & 0xffU);  
                         tmptag >>= 8;  
                 }  
   
                 AC_FMEMCPY( (*sos)->sos_first, nettag, taglen );  
   
                 if ( ber->ber_options & LBER_USE_DER ) {  
                         ltag = (lenlen == 1)  
                                 ? (unsigned char) len  
                                 : (unsigned char) (0x80U + (lenlen - 1));  
                 }  
   
                 /* one byte of length length */  
                 (*sos)->sos_first[1] = ltag;  
   
                 if ( ber->ber_options & LBER_USE_DER ) {  
                         if (lenlen > 1) {  
                                 /* Write the length itself */  
                                 AC_FMEMCPY( (*sos)->sos_first + 2, netlen, lenlen - 1 );  
                         }  
                         if (lenlen != FOUR_BYTE_LEN) {  
                                 /*  
                                  * We set aside FOUR_BYTE_LEN bytes for  
                                  * the length field.  Move the data if  
                                  * we don't actually need that much  
                                  */  
                                 AC_FMEMCPY( (*sos)->sos_first + taglen +  
                                     lenlen, (*sos)->sos_first + taglen +  
                                     FOUR_BYTE_LEN, len );  
                         }  
                 } else {  
                         /* the length itself */  
                         AC_FMEMCPY( (*sos)->sos_first + taglen + 1,  
                             netlen, FOUR_BYTE_LEN - 1 );  
                 }  
   
                 next->sos_clen += (taglen + lenlen + len);  
                 next->sos_ptr += (taglen + lenlen + len);  
         }          }
   
         /* we're done with this seqorset, so free it up */          return xlen + *SOS_TAG_END(header); /* lenlen + len + taglen */
         ber_memfree_x( (char *) (*sos), ber->ber_memctx );  
         *sos = next;  
   
         return taglen + lenlen + len;  
 }  }
   
 int  int
 ber_put_seq( BerElement *ber )  ber_put_seq( BerElement *ber )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         return ber_put_seqorset( ber );          return ber_put_seqorset( ber );
 }  }
   
 int  int
 ber_put_set( BerElement *ber )  ber_put_set( BerElement *ber )
 {  {
         assert( ber != NULL );  
         assert( LBER_VALID( ber ) );  
   
         return ber_put_seqorset( ber );          return ber_put_seqorset( ber );
 }  }
   
Line 689  ber_printf( BerElement *ber, LDAP_CONST Line 510  ber_printf( BerElement *ber, LDAP_CONST
   
         assert( ber != NULL );          assert( ber != NULL );
         assert( fmt != NULL );          assert( fmt != NULL );
   
         assert( LBER_VALID( ber ) );          assert( LBER_VALID( ber ) );
   
         va_start( ap, fmt );          va_start( ap, fmt );
Line 700  ber_printf( BerElement *ber, LDAP_CONST Line 520  ber_printf( BerElement *ber, LDAP_CONST
                                 BEREncodeCallback *f;                                  BEREncodeCallback *f;
                                 void *p;                                  void *p;
   
                                   ber->ber_usertag = 0;
   
                                 f = va_arg( ap, BEREncodeCallback * );                                  f = va_arg( ap, BEREncodeCallback * );
                                 p = va_arg( ap, void * );                                  p = va_arg( ap, void * );
   
                                 rc = (*f)( ber, p );                                  rc = (*f)( ber, p );
   
                                   if ( ber->ber_usertag ) {
                                           goto next;
                                   }
                         } break;                          } break;
   
                 case 'b':       /* boolean */                  case 'b':       /* boolean */
Line 726  ber_printf( BerElement *ber, LDAP_CONST Line 551  ber_printf( BerElement *ber, LDAP_CONST
                         break;                          break;
   
                 case 'N':       /* Debug NULL */                  case 'N':       /* Debug NULL */
                           rc = 0;
                         if( lber_int_null != 0 ) {                          if( lber_int_null != 0 ) {
                                 /* Insert NULL to ensure peer ignores unknown tags */                                  /* Insert NULL to ensure peer ignores unknown tags */
                                 rc = ber_put_null( ber, lber_int_null );                                  rc = ber_put_null( ber, lber_int_null );
                         } else {  
                                 rc = 0;  
                         }                          }
                         break;                          break;
   
Line 754  ber_printf( BerElement *ber, LDAP_CONST Line 578  ber_printf( BerElement *ber, LDAP_CONST
                 case 'B':       /* bit string */                  case 'B':       /* bit string */
                 case 'X':       /* bit string (deprecated) */                  case 'X':       /* bit string (deprecated) */
                         s = va_arg( ap, char * );                          s = va_arg( ap, char * );
                         len = va_arg( ap, int );        /* in bits */                          len = va_arg( ap, ber_len_t );  /* in bits */
                         rc = ber_put_bitstring( ber, s, len, ber->ber_tag );                          rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
                         break;                          break;
   
                 case 't':       /* tag for the next element */                  case 't':       /* tag for the next element */
                         ber->ber_tag = va_arg( ap, ber_tag_t );                          ber->ber_tag = va_arg( ap, ber_tag_t );
                         ber->ber_usertag = 1;                          goto next;
                         break;  
   
                 case 'v':       /* vector of strings */                  case 'v':       /* vector of strings */
                         if ( (ss = va_arg( ap, char ** )) == NULL )                          if ( (ss = va_arg( ap, char ** )) == NULL )
Line 818  ber_printf( BerElement *ber, LDAP_CONST Line 641  ber_printf( BerElement *ber, LDAP_CONST
                         break;                          break;
                 }                  }
   
                 if ( ber->ber_usertag == 0 ) {                  ber->ber_tag = LBER_DEFAULT;
                         ber->ber_tag = LBER_DEFAULT;          next:;
                 } else {  
                         ber->ber_usertag = 0;  
                 }  
         }          }
   
         va_end( ap );          va_end( ap );

Removed from v.1.64  
changed lines
  Added in v.1.64.2.8


______________
© Copyright 1998-2020, OpenLDAP Foundation, info@OpenLDAP.org