"Fossies" - the Fresh Open Source Software Archive

Member "npadmin-0.14/ber.C" (22 Nov 2002, 10361 Bytes) of package /linux/misc/old/npadmin-0.14.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* Copyright (c) 2000 Ben Woodard
    2  * All rights reserved.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public Licence
    6  * as published by the Free Software Foundation; either version 2
    7  * of the Licence, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRENTY; without even the implied warrenty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   12  * GNU General Public Licence in the COPYING file for more
   13  * details.
   14  *
   15  * You should have received a copy of the GNU Library General 
   16  * Public License along with the GNU C Library; see the file 
   17  * COPYING.LIB.  If not, write to the Free Software Foundation, 
   18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
   19  */
   20 
   21 #include <stdlib.h>
   22 #include <stdio.h>
   23 #include <string.h>
   24 #include <stdarg.h>
   25 #include <limits.h>
   26 #include <errno.h>
   27 #include <assert.h>
   28 #include <ctype.h>
   29 #include <sys/types.h>
   30 #include <netinet/in.h>
   31 
   32 #include "ber.h"
   33 #include "compat.h"
   34 
   35 BerEncodedData::BerEncodedData(unsigned char *dat, unsigned long len): 
   36   data(dat),length(len),next(NULL){
   37   assert(data);
   38 }
   39 
   40 unsigned char *start_data(Tags type,unsigned int len, unsigned char &headlen){
   41   unsigned char *retstr;
   42   if(len<128){
   43     retstr=new unsigned char[len+2];
   44     retstr[1]=len;
   45     headlen=2;
   46   } else {
   47     unsigned char buf[sizeof(unsigned long)];
   48     unsigned long nlen=htonl(len);
   49     memcpy(buf,&nlen,sizeof(unsigned long));
   50 
   51     //counts the number of leading 0's
   52     for(headlen=0;buf[headlen]==0 && headlen<3;headlen++);
   53     //magic function to to turn this into header length
   54     headlen=sizeof(unsigned long)-headlen+2;
   55 
   56     retstr=new unsigned char[len+headlen];
   57     retstr[1]=0x80-2+headlen; 
   58 
   59     char k=2;
   60     for(char j=sizeof(unsigned long)+2-headlen;j<=3;j++)
   61       retstr[k++]=buf[j];
   62   }
   63   retstr[0]=type;
   64   return retstr;
   65 }
   66 
   67 unsigned long unpack_len(unsigned char *start,
   68              unsigned char &headerlen){
   69   if(start[1]<128){
   70     headerlen=2;    
   71     return start[1];
   72   }
   73   unsigned long sizeofsize=start[1]&0x7f;
   74   assert(sizeofsize<=sizeof(long));
   75   long size=0;
   76   memcpy(((unsigned char*)(&size))+sizeof(long)-sizeofsize,start+2,sizeofsize);
   77   headerlen=2+sizeofsize;
   78   return htonl(size);
   79 }
   80 
   81 /* ber class is the basic encoding rules for ASN.1 class. All the classes that
   82  *     have encoding are derived from this class.
   83  * len - is the length of the encoded sequence.
   84  * mbufcache - is the the head of the mbuf chain that this class will hand out 
   85  *     when getmbuf is called. It is set to NULL initially and getmbuf fills 
   86  *     it in and subsequent calls just return it.
   87  * getmbuf - most classes just use the default getmbuf but sequences need to 
   88  *     do some special processing and so it must be used be virtual.
   89  * encode - does whatever is necessary to come up with a string to pass out
   90  *     the calling function. The string is probably not NULL terminated and 
   91  *     probably has NULLs in it.
   92  * Len - is used to find out the length of the encoded sequence. The value is
   93  *     undefined before an encode is called.
   94  */
   95 
   96 BerEncodedData *BerBase::encode(){
   97   assert(0);
   98   return NULL;
   99 }
  100 
  101 BerEncodedData *BerBase::getdata(){
  102   if(edatacache==NULL)
  103     edatacache=encode();
  104   assert(edatacache);
  105   return edatacache;
  106 }
  107 
  108 unsigned long BerBase::fulllen(){
  109   BerEncodedData *bed=getdata();
  110   unsigned long retval=bed->Length();
  111   while(bed->next){
  112     bed=bed->next;
  113     retval+=bed->Length();
  114   }
  115   return retval;
  116 }
  117 
  118 BerBase::BerBase(unsigned char* str):next(NULL){
  119   unsigned char *retstr;
  120   unsigned char headerlen;
  121   unsigned long size=unpack_len(str,headerlen);
  122   unsigned long fullen=size+headerlen;
  123   retstr=new unsigned char[fullen];
  124   memcpy(retstr,str,fullen);
  125   edatacache=new BerEncodedData(retstr,fullen);
  126 }
  127 
  128 /* 
  129  *
  130  * berNull - is the string 0x05 0x00 there is really not much too it.
  131  *
  132  */
  133 
  134 int BerNull::print(char *buf, unsigned int len){
  135   if(len<4) return -1;
  136   strncpy(buf,"NULL",4);
  137   return 4;
  138 }
  139 
  140 BerNull::BerNull(unsigned char *str): BerBase(str){
  141   assert(str[0]==NULL_TAG);
  142   assert(str[1]==0);
  143 }
  144 
  145 BerEncodedData *BerNull::encode(){
  146   unsigned char headlen=0;
  147   unsigned char *tmp=start_data(NULL_TAG,0,headlen);
  148   return new BerEncodedData(tmp,headlen);
  149 }
  150 
  151 /* berInt is the encoding of an int in ASN.1
  152  * The encoding is a 0x02 followed by the size of the data then the bytes of
  153  * of the data. The data is stored in the big endian 2's complement using the
  154  * fewest bytes possible. However a 0 still uses one byte. i.e. 0x20 0x01 0x00
  155  */
  156 
  157 int BerInt::print(char *buf, unsigned int len){
  158   return snprintf(buf,len,"%ld",val);
  159 }
  160 
  161 BerInt::BerInt(unsigned char *str): BerBase(str),val(0){
  162   /* this might cause some problems with the counters that exceede 31 bits in 
  163      length but for now it seems ok */
  164   assert(str[0]==INT_TAG||str[0]==COUNTER_TAG);
  165   assert(str[1]<=sizeof(long));
  166   memcpy(((unsigned char*)&val)+sizeof(long)-str[1],str+2,str[1]);
  167   //extend out the sign if necessary
  168   if(str[0]==INT_TAG && str[1]!=sizeof(long) && str[2]&0x80)
  169     memset(&val,0xff,sizeof(long)-str[1]);
  170   // being lazy again some high bit counters may cause a problem.
  171   assert(!(str[0]==COUNTER_TAG && str[1]==sizeof(long) && str[2]&0x80));
  172   val=ntohl(val);
  173 }
  174 
  175 BerEncodedData *BerInt::encode(){
  176   unsigned char buf[sizeof(long)];
  177   unsigned char *retval;
  178   unsigned char i,headerlen;
  179   long the_value=htonl(val);
  180   memcpy(buf,&the_value,sizeof(long));
  181   //  printf("0=%d 1=%d 2=%d 3=%d ",(int)buf[0],(int)buf[1],(int)buf[2],
  182   // (int)buf[3]);
  183 
  184   //count the number of bytes that are actually used
  185   for(i=sizeof(long);!buf[sizeof(long)-i] && i>1;i--);
  186   /* zero pad the case when the most significant byte has a 1 in the most 
  187      significant bit -- otherwise the other end will interpret it as a negative
  188      number */
  189   if(i!=sizeof(long) && buf[sizeof(long)-i]&0x7f)
  190     i++;
  191 
  192   //  printf("val=%ld len=%u buf[0]=%u buf[1]=%u buf[2]=%u buf[3]=%u\n",val,
  193   //     (unsigned) i,(unsigned) buf[0],(unsigned) buf[1],(unsigned) buf[2],
  194   //     (unsigned) buf[3]);
  195 
  196   retval=start_data(INT_TAG,i,headerlen);
  197   memcpy(retval+headerlen,buf+sizeof(long)-i,i);
  198   //  printf("i=%d ",(int) i);
  199   
  200   //  printf("va// lue=%d ",val);
  201 //   for(int j=0;j<i;j++){
  202 //     printf("i=%d val=%d ",j,(int) *(retval+headerlen+j));
  203 //   }
  204 //   printf("\n");
  205 
  206   return new BerEncodedData(retval,headerlen+i);
  207 }
  208 
  209 /*
  210  * Number of timeticks since some epoch. In 1/100 seconds
  211  */
  212 
  213 BerTimeTick::BerTimeTick(unsigned char *str): BerBase(str),val(0){
  214   assert(str[0]==TIME_TICK_TAG);
  215   assert(str[1]<=sizeof(unsigned long));
  216   memcpy(((unsigned char*)&val)+sizeof(unsigned long)-str[1],str+2,str[1]);
  217   val=ntohl(val);
  218 }
  219 
  220 BerEncodedData *BerTimeTick::encode(){
  221   unsigned char buf[sizeof(unsigned long)];
  222   unsigned char *retval;
  223   unsigned char i,headerlen;
  224   long the_value=htonl(val);
  225   memcpy(buf,&the_value,sizeof(unsigned long));
  226 
  227   //count the number of bytes that are actually used
  228   for(i=sizeof(long);!buf[sizeof(unsigned long)-i] && i>1;i--);
  229 
  230   retval=start_data(TIME_TICK_TAG,i,headerlen);
  231   memcpy(retval+headerlen,buf,i);
  232   return new BerEncodedData(retval,headerlen+i);
  233 }
  234 
  235 int BerTimeTick::print(char *buf, unsigned int len){
  236   // hopefully this works by just assming the bits are right 
  237   // rather than coercing the value into a different format.
  238   unsigned long t1=val%8640000;
  239   unsigned long t2=t1%360000;
  240   unsigned long t3=t2%6000;
  241   return snprintf(buf,len,"Time: %lud %luh %lum %lu.%lusec (%lu)",
  242           val/8640000,t1/360000,t2/6000,t3/100,t3%100,val);
  243 }
  244 
  245 
  246 /* berString is used to encode a string. It is simply the length 
  247    and the data. the only complication is the encoding of the 
  248    length. Also terminates string. */
  249 int BerString::copy(char *buf, unsigned int len){
  250   assert(len>stringlen+1);
  251   memcpy(buf,str,stringlen);
  252   buf[stringlen]='\0';
  253   return stringlen;
  254 }
  255 
  256 int BerString::print(char *buf, unsigned int len){
  257   int totlenused=0;
  258   /* strings are used for binary data as well as text. We need to handle 8 bit
  259      data as well as normal printable strings */
  260   for(char *cur=str;cur<str+stringlen;cur++){
  261     int lenused=snprintf(buf,len,isprint(*cur)?"%c":"\\0x%02x",
  262              *(unsigned char*)cur);
  263     assert(lenused!=-1);
  264     totlenused+=lenused;
  265     len-=lenused;
  266     buf+=lenused;
  267   }
  268   return totlenused;
  269 }
  270 
  271 BerString::BerString(CONST char *strng,unsigned int length): 
  272   stringlen(length){ 
  273   assert(strng);
  274   str=new char[length];
  275   memcpy(str,strng,length);
  276 }
  277 
  278 BerString::BerString(unsigned char *strn): BerBase(strn){ // Wire protocol only
  279   assert(strn[0]==STRING_TAG);
  280   unsigned char headerlen;
  281   unpack_len(strn,headerlen);
  282   // I can use edatacache->len here because BerBase(strn) fills in edatacache.
  283   str=new char[edatacache->Length()-headerlen];
  284   stringlen=edatacache->Length()-headerlen;
  285   memcpy(str,strn+headerlen,stringlen);
  286 }
  287 
  288 BerEncodedData *BerString::encode(){
  289   unsigned char headerlen;
  290   unsigned char *retval=start_data(STRING_TAG,stringlen,headerlen);
  291   memcpy(retval+headerlen,str,stringlen);
  292   return new BerEncodedData(retval,headerlen+stringlen);
  293 }
  294 
  295 /* 
  296  * BerIPAddr is used to encode an ipaddress. 
  297  */
  298 
  299 int BerIPAddr::print(char *buf, unsigned int length){
  300   assert(len==4); // don't know how to deal with v6 yet
  301   // might be a problem with endian but I borrowed this code out of nslookup
  302   return snprintf(buf,length,"%u.%u.%u.%u;",
  303           ((unsigned)ipaddr[0] & 0xff),
  304           ((unsigned)ipaddr[1] & 0xff),
  305           ((unsigned)ipaddr[2] & 0xff),
  306           ((unsigned)ipaddr[3] & 0xff));
  307 }
  308 
  309 BerIPAddr::BerIPAddr(const char *addr,int length): 
  310   len(length){ 
  311   assert(addr);
  312   assert(len==4); //don't know how to deal with anything but v4
  313   ipaddr=new unsigned char[4];
  314   memcpy(ipaddr,addr,4);
  315 }
  316 
  317 // Wire protocol only
  318 BerIPAddr::BerIPAddr(unsigned char *strn): BerBase(strn),len(4){ 
  319   strn[0]=IPADDR_TAG;
  320   unsigned char headerlen;
  321   unpack_len(strn,headerlen);
  322   // I can use edatacache->len here because BerBase(strn) fills 
  323   // in edatacache.
  324   assert(edatacache->Length()==6);
  325   ipaddr=new unsigned char[4];
  326   memcpy(ipaddr,strn+headerlen,4);
  327 }
  328 
  329 BerEncodedData *BerIPAddr::encode(){
  330   unsigned char headerlen;
  331   unsigned char *retval=start_data(IPADDR_TAG,4,headerlen);
  332   memcpy(retval+headerlen,ipaddr,4);
  333   return new BerEncodedData(retval,headerlen+len);
  334 }
  335