]> git.sur5r.net Git - openldap/blob - libraries/liblber/encode.c
d6b1304d2590ba5461157ef7546ad188a2034e6c
[openldap] / libraries / liblber / encode.c
1 /* encode.c - ber output encoding routines */
2 /*
3  * Copyright (c) 1990 Regents of the University of Michigan.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms are permitted
7  * provided that this notice is preserved and that due credit is given
8  * to the University of Michigan at Ann Arbor. The name of the University
9  * may not be used to endorse or promote products derived from this
10  * software without specific prior written permission. This software
11  * is provided ``as is'' without express or implied warranty.
12  */
13
14 #include <stdio.h>
15 #ifdef MACOS
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include "macos.h"
19 #else /* MACOS */
20 #if defined(NeXT) || defined(VMS)
21 #include <stdlib.h>
22 #else /* next || vms */
23 #ifndef __FreeBSD__
24 #include <malloc.h>
25 #endif
26 #endif /* next || vms */
27 #if defined( BC31 ) || defined( _WIN32 )
28 #include <stdarg.h>
29 #else /* BC31 || _WIN32 */
30 #include <varargs.h>
31 #endif /* BC31 || _WIN32 */
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #ifdef PCNFS
36 #include <tklib.h>
37 #endif /* PCNFS */
38 #endif /* MACOS */
39 #ifndef VMS
40 #include <memory.h>
41 #endif
42 #include <string.h>
43 #include "lber.h"
44
45 #if defined( DOS ) || defined( _WIN32 )
46 #include "msdos.h"
47 #endif /* DOS */
48
49 #ifdef NEEDPROTOS
50 static int ber_put_len( BerElement *ber, unsigned long len, int nosos );
51 static int ber_start_seqorset( BerElement *ber, unsigned long tag );
52 static int ber_put_seqorset( BerElement *ber );
53 static int ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag );
54 #endif /* NEEDPROTOS */
55
56
57 static int
58 ber_calc_taglen( unsigned long tag )
59 {
60         int     i;
61         long    mask;
62
63         /* find the first non-all-zero byte in the tag */
64         for ( i = sizeof(long) - 1; i > 0; i-- ) {
65                 mask = (0xffL << (i * 8));
66                 /* not all zero */
67                 if ( tag & mask )
68                         break;
69         }
70
71         return( i + 1 );
72 }
73
74 static int
75 ber_put_tag( BerElement *ber, unsigned long tag, int nosos )
76 {
77         int             taglen;
78         unsigned long   ntag;
79
80         taglen = ber_calc_taglen( tag );
81
82         ntag = LBER_HTONL( tag );
83
84         return( ber_write( ber, ((char *) &ntag) + sizeof(long) - taglen,
85             taglen, nosos ) );
86 }
87
88 static int
89 ber_calc_lenlen( unsigned long len )
90 {
91         /*
92          * short len if it's less than 128 - one byte giving the len,
93          * with bit 8 0.
94          */
95
96         if ( len <= 0x7F )
97                 return( 1 );
98
99         /*
100          * long len otherwise - one byte with bit 8 set, giving the
101          * length of the length, followed by the length itself.
102          */
103
104         if ( len <= 0xFF )
105                 return( 2 );
106         if ( len <= 0xFFFFL )
107                 return( 3 );
108         if ( len <= 0xFFFFFFL )
109                 return( 4 );
110
111         return( 5 );
112 }
113
114 static int
115 ber_put_len( BerElement *ber, unsigned long len, int nosos )
116 {
117         int             i;
118         char            lenlen;
119         long            mask;
120         unsigned long   netlen;
121
122         /*
123          * short len if it's less than 128 - one byte giving the len,
124          * with bit 8 0.
125          */
126
127         if ( len <= 127 ) {
128                 netlen = LBER_HTONL( len );
129                 return( ber_write( ber, (char *) &netlen + sizeof(long) - 1,
130                     1, nosos ) );
131         }
132
133         /*
134          * long len otherwise - one byte with bit 8 set, giving the
135          * length of the length, followed by the length itself.
136          */
137
138         /* find the first non-all-zero byte */
139         for ( i = sizeof(long) - 1; i > 0; i-- ) {
140                 mask = (0xffL << (i * 8));
141                 /* not all zero */
142                 if ( len & mask )
143                         break;
144         }
145         lenlen = ++i;
146         if ( lenlen > 4 )
147                 return( -1 );
148         lenlen |= 0x80;
149
150         /* write the length of the length */
151         if ( ber_write( ber, &lenlen, 1, nosos ) != 1 )
152                 return( -1 );
153
154         /* write the length itself */
155         netlen = LBER_HTONL( len );
156         if ( ber_write( ber, (char *) &netlen + (sizeof(long) - i), i, nosos )
157             != i )
158                 return( -1 );
159
160         return( i + 1 );
161 }
162
163 static int
164 ber_put_int_or_enum( BerElement *ber, long num, unsigned long tag )
165 {
166         int     i, sign, taglen;
167         int     len, lenlen;
168         long    netnum, mask;
169
170         sign = (num < 0);
171
172         /*
173          * high bit is set - look for first non-all-one byte
174          * high bit is clear - look for first non-all-zero byte
175          */
176         for ( i = sizeof(long) - 1; i > 0; i-- ) {
177                 mask = (0xffL << (i * 8));
178
179                 if ( sign ) {
180                         /* not all ones */
181                         if ( (num & mask) != mask )
182                                 break;
183                 } else {
184                         /* not all zero */
185                         if ( num & mask )
186                                 break;
187                 }
188         }
189
190         /*
191          * we now have the "leading byte".  if the high bit on this
192          * byte matches the sign bit, we need to "back up" a byte.
193          */
194         mask = (num & (0x80L << (i * 8)));
195         if ( (mask && !sign) || (sign && !mask) )
196                 i++;
197
198         len = i + 1;
199
200         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
201                 return( -1 );
202
203         if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 )
204                 return( -1 );
205         i++;
206         netnum = LBER_HTONL( num );
207         if ( ber_write( ber, (char *) &netnum + (sizeof(long) - i), i, 0 )
208            != i )
209                 return( -1 );
210
211         /* length of tag + length + contents */
212         return( taglen + lenlen + i );
213 }
214
215 int
216 ber_put_enum( BerElement *ber, long num, unsigned long tag )
217 {
218         if ( tag == LBER_DEFAULT )
219                 tag = LBER_ENUMERATED;
220
221         return( ber_put_int_or_enum( ber, num, tag ) );
222 }
223
224 int
225 ber_put_int( BerElement *ber, long num, unsigned long tag )
226 {
227         if ( tag == LBER_DEFAULT )
228                 tag = LBER_INTEGER;
229
230         return( ber_put_int_or_enum( ber, num, tag ) );
231 }
232
233 int
234 ber_put_ostring( BerElement *ber, char *str, unsigned long len,
235         unsigned long tag )
236 {
237         int     taglen, lenlen, rc;
238 #ifdef STR_TRANSLATION
239         int     free_str;
240 #endif /* STR_TRANSLATION */
241
242         if ( tag == LBER_DEFAULT )
243                 tag = LBER_OCTETSTRING;
244
245         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
246                 return( -1 );
247
248 #ifdef STR_TRANSLATION
249         if ( len > 0 && ( ber->ber_options & LBER_TRANSLATE_STRINGS ) != 0 &&
250             ber->ber_encode_translate_proc != NULL ) {
251                 if ( (*(ber->ber_encode_translate_proc))( &str, &len, 0 )
252                     != 0 ) {
253                         return( -1 );
254                 }
255                 free_str = 1;
256         } else {
257                 free_str = 0;
258         }
259 #endif /* STR_TRANSLATION */
260
261         if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
262                 ber_write( ber, str, len, 0 ) != len ) {
263                 rc = -1;
264         } else {
265                 /* return length of tag + length + contents */
266                 rc = taglen + lenlen + len;
267         }
268
269 #ifdef STR_TRANSLATION
270         if ( free_str ) {
271                 free( str );
272         }
273 #endif /* STR_TRANSLATION */
274
275         return( rc );
276 }
277
278 int
279 ber_put_string( BerElement *ber, char *str, unsigned long tag )
280 {
281         return( ber_put_ostring( ber, str, strlen( str ), tag ));
282 }
283
284 int
285 ber_put_bitstring( BerElement *ber, char *str,
286         unsigned long blen /* in bits */, unsigned long tag )
287 {
288         int             taglen, lenlen, len;
289         unsigned char   unusedbits;
290
291         if ( tag == LBER_DEFAULT )
292                 tag = LBER_BITSTRING;
293
294         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
295                 return( -1 );
296
297         len = ( blen + 7 ) / 8;
298         unusedbits = len * 8 - blen;
299         if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 )
300                 return( -1 );
301
302         if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 )
303                 return( -1 );
304
305         if ( ber_write( ber, str, len, 0 ) != len )
306                 return( -1 );
307
308         /* return length of tag + length + unused bit count + contents */
309         return( taglen + 1 + lenlen + len );
310 }
311
312 int
313 ber_put_null( BerElement *ber, unsigned long tag )
314 {
315         int     taglen;
316
317         if ( tag == LBER_DEFAULT )
318                 tag = LBER_NULL;
319
320         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
321                 return( -1 );
322
323         if ( ber_put_len( ber, 0, 0 ) != 1 )
324                 return( -1 );
325
326         return( taglen + 1 );
327 }
328
329 int
330 ber_put_boolean( BerElement *ber, int boolval, unsigned long tag )
331 {
332         int             taglen;
333         unsigned char   trueval = 0xff;
334         unsigned char   falseval = 0x00;
335
336         if ( tag == LBER_DEFAULT )
337                 tag = LBER_BOOLEAN;
338
339         if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
340                 return( -1 );
341
342         if ( ber_put_len( ber, 1, 0 ) != 1 )
343                 return( -1 );
344
345         if ( ber_write( ber, (char *)(boolval ? &trueval : &falseval), 1, 0 )
346             != 1 )
347                 return( -1 );
348
349         return( taglen + 2 );
350 }
351
352 #define FOUR_BYTE_LEN   5
353
354 static int
355 ber_start_seqorset( BerElement *ber, unsigned long tag )
356 {
357         Seqorset        *new;
358
359         if ( (new = (Seqorset *) calloc( sizeof(Seqorset), 1 ))
360             == NULLSEQORSET )
361                 return( -1 );
362         new->sos_ber = ber;
363         if ( ber->ber_sos == NULLSEQORSET )
364                 new->sos_first = ber->ber_ptr;
365         else
366                 new->sos_first = ber->ber_sos->sos_ptr;
367
368         /* Set aside room for a 4 byte length field */
369         new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
370         new->sos_tag = tag;
371
372         new->sos_next = ber->ber_sos;
373         ber->ber_sos = new;
374
375         return( 0 );
376 }
377
378 int
379 ber_start_seq( BerElement *ber, unsigned long tag )
380 {
381         if ( tag == LBER_DEFAULT )
382                 tag = LBER_SEQUENCE;
383
384         return( ber_start_seqorset( ber, tag ) );
385 }
386
387 int
388 ber_start_set( BerElement *ber, unsigned long tag )
389 {
390         if ( tag == LBER_DEFAULT )
391                 tag = LBER_SET;
392
393         return( ber_start_seqorset( ber, tag ) );
394 }
395
396 static int
397 ber_put_seqorset( BerElement *ber )
398 {
399         unsigned long   len, netlen;
400         int             taglen, lenlen;
401         unsigned char   ltag = 0x80 + FOUR_BYTE_LEN - 1;
402         Seqorset        *next;
403         Seqorset        **sos = &ber->ber_sos;
404
405         /*
406          * If this is the toplevel sequence or set, we need to actually
407          * write the stuff out.  Otherwise, it's already been put in
408          * the appropriate buffer and will be written when the toplevel
409          * one is written.  In this case all we need to do is update the
410          * length and tag.
411          */
412
413         len = (*sos)->sos_clen;
414         netlen = LBER_HTONL( len );
415         if ( sizeof(long) > 4 && len > 0xFFFFFFFFL )
416                 return( -1 );
417
418         if ( ber->ber_options & LBER_USE_DER ) {
419                 lenlen = ber_calc_lenlen( len );
420         } else {
421                 lenlen = FOUR_BYTE_LEN;
422         }
423
424         if ( (next = (*sos)->sos_next) == NULLSEQORSET ) {
425                 /* write the tag */
426                 if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 )
427                         return( -1 );
428
429                 if ( ber->ber_options & LBER_USE_DER ) {
430                         /* Write the length in the minimum # of octets */
431                         if ( ber_put_len( ber, len, 1 ) == -1 )
432                                 return( -1 );
433
434                         if (lenlen != FOUR_BYTE_LEN) {
435                                 /*
436                                  * We set aside FOUR_BYTE_LEN bytes for
437                                  * the length field.  Move the data if
438                                  * we don't actually need that much
439                                  */
440                                 SAFEMEMCPY( (*sos)->sos_first + taglen +
441                                     lenlen, (*sos)->sos_first + taglen +
442                                     FOUR_BYTE_LEN, len );
443                         }
444                 } else {
445                         /* Fill FOUR_BYTE_LEN bytes for length field */
446                         /* one byte of length length */
447                         if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 )
448                                 return( -1 );
449
450                         /* the length itself */
451                         if ( ber_write( ber, (char *) &netlen + sizeof(long)
452                             - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1 )
453                             != FOUR_BYTE_LEN - 1 )
454                                 return( -1 );
455                 }
456                 /* The ber_ptr is at the set/seq start - move it to the end */
457                 (*sos)->sos_ber->ber_ptr += len;
458         } else {
459                 unsigned long   ntag;
460
461                 /* the tag */
462                 taglen = ber_calc_taglen( (*sos)->sos_tag );
463                 ntag = LBER_HTONL( (*sos)->sos_tag );
464                 SAFEMEMCPY( (*sos)->sos_first, (char *) &ntag +
465                     sizeof(long) - taglen, taglen );
466
467                 if ( ber->ber_options & LBER_USE_DER ) {
468                         ltag = (lenlen == 1) ? len : 0x80 + (lenlen - 1);
469                 }
470
471                 /* one byte of length length */
472                 SAFEMEMCPY( (*sos)->sos_first + 1, &ltag, 1 );
473
474                 if ( ber->ber_options & LBER_USE_DER ) {
475                         if (lenlen > 1) {
476                                 /* Write the length itself */
477                                 SAFEMEMCPY( (*sos)->sos_first + 2,
478                                     (char *)&netlen + sizeof(unsigned long) -
479                                     (lenlen - 1),
480                                     lenlen - 1 );
481                         }
482                         if (lenlen != FOUR_BYTE_LEN) {
483                                 /*
484                                  * We set aside FOUR_BYTE_LEN bytes for
485                                  * the length field.  Move the data if
486                                  * we don't actually need that much
487                                  */
488                                 SAFEMEMCPY( (*sos)->sos_first + taglen +
489                                     lenlen, (*sos)->sos_first + taglen +
490                                     FOUR_BYTE_LEN, len );
491                         }
492                 } else {
493                         /* the length itself */
494                         SAFEMEMCPY( (*sos)->sos_first + taglen + 1,
495                             (char *) &netlen + sizeof(long) -
496                             (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1 );
497                 }
498
499                 next->sos_clen += (taglen + lenlen + len);
500                 next->sos_ptr += (taglen + lenlen + len);
501         }
502
503         /* we're done with this seqorset, so free it up */
504         free( (char *) (*sos) );
505         *sos = next;
506
507         return( taglen + lenlen + len );
508 }
509
510 int
511 ber_put_seq( BerElement *ber )
512 {
513         return( ber_put_seqorset( ber ) );
514 }
515
516 int
517 ber_put_set( BerElement *ber )
518 {
519         return( ber_put_seqorset( ber ) );
520 }
521
522 /* VARARGS */
523 int
524 ber_printf(
525 #if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
526         BerElement *ber, char *fmt, ... )
527 #else /* MACOS || _WIN32 || BC31 */
528         va_alist )
529 va_dcl
530 #endif /* MACOS || _WIN32 || BC31 */
531 {
532         va_list         ap;
533 #if !defined( MACOS ) && !defined( _WIN32 ) && !defined( BC31 )
534         BerElement      *ber;
535         char            *fmt;
536 #endif /* !MACOS && !_WIN32 && !BC31 */
537         char            *s, **ss;
538         struct berval   **bv;
539         int             rc, i;
540         unsigned long   len;
541
542 #if defined( MACOS ) || defined( _WIN32 ) || defined( BC31 )
543         va_start( ap, fmt );
544 #else /* MACOS || _WIN32 || BC31 */
545         va_start( ap );
546         ber = va_arg( ap, BerElement * );
547         fmt = va_arg( ap, char * );
548 #endif /* MACOS || _WIN32 || BC31 */
549
550         for ( rc = 0; *fmt && rc != -1; fmt++ ) {
551                 switch ( *fmt ) {
552                 case 'b':       /* boolean */
553                         i = va_arg( ap, int );
554                         rc = ber_put_boolean( ber, i, ber->ber_tag );
555                         break;
556
557                 case 'i':       /* int */
558                         i = va_arg( ap, int );
559                         rc = ber_put_int( ber, i, ber->ber_tag );
560                         break;
561
562                 case 'e':       /* enumeration */
563                         i = va_arg( ap, int );
564                         rc = ber_put_enum( ber, i, ber->ber_tag );
565                         break;
566
567                 case 'n':       /* null */
568                         rc = ber_put_null( ber, ber->ber_tag );
569                         break;
570
571                 case 'o':       /* octet string (non-null terminated) */
572                         s = va_arg( ap, char * );
573                         len = va_arg( ap, int );
574                         rc = ber_put_ostring( ber, s, len, ber->ber_tag );
575                         break;
576
577                 case 's':       /* string */
578                         s = va_arg( ap, char * );
579                         rc = ber_put_string( ber, s, ber->ber_tag );
580                         break;
581
582                 case 'B':       /* bit string */
583                         s = va_arg( ap, char * );
584                         len = va_arg( ap, int );        /* in bits */
585                         rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
586                         break;
587
588                 case 't':       /* tag for the next element */
589                         ber->ber_tag = va_arg( ap, unsigned long );
590                         ber->ber_usertag = 1;
591                         break;
592
593                 case 'v':       /* vector of strings */
594                         if ( (ss = va_arg( ap, char ** )) == NULL )
595                                 break;
596                         for ( i = 0; ss[i] != NULL; i++ ) {
597                                 if ( (rc = ber_put_string( ber, ss[i],
598                                     ber->ber_tag )) == -1 )
599                                         break;
600                         }
601                         break;
602
603                 case 'V':       /* sequences of strings + lengths */
604                         if ( (bv = va_arg( ap, struct berval ** )) == NULL )
605                                 break;
606                         for ( i = 0; bv[i] != NULL; i++ ) {
607                                 if ( (rc = ber_put_ostring( ber, bv[i]->bv_val,
608                                     bv[i]->bv_len, ber->ber_tag )) == -1 )
609                                         break;
610                         }
611                         break;
612
613                 case '{':       /* begin sequence */
614                         rc = ber_start_seq( ber, ber->ber_tag );
615                         break;
616
617                 case '}':       /* end sequence */
618                         rc = ber_put_seqorset( ber );
619                         break;
620
621                 case '[':       /* begin set */
622                         rc = ber_start_set( ber, ber->ber_tag );
623                         break;
624
625                 case ']':       /* end set */
626                         rc = ber_put_seqorset( ber );
627                         break;
628
629                 default:
630 #ifndef NO_USERINTERFACE
631                         fprintf( stderr, "unknown fmt %c\n", *fmt );
632 #endif /* NO_USERINTERFACE */
633                         rc = -1;
634                         break;
635                 }
636
637                 if ( ber->ber_usertag == 0 )
638                         ber->ber_tag = LBER_DEFAULT;
639                 else
640                         ber->ber_usertag = 0;
641         }
642
643         va_end( ap );
644
645         return( rc );
646 }