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