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