"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