~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to libraries/liblber/encode.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* encode.c - ber output encoding routines */
 
2
/* $OpenLDAP: pkg/ldap/libraries/liblber/encode.c,v 1.64.2.3 2008/02/11 23:26:41 kurt Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 1998-2008 The OpenLDAP Foundation.
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted only as authorized by the OpenLDAP
 
10
 * Public License.
 
11
 *
 
12
 * A copy of this license is available in the file LICENSE in the
 
13
 * top-level directory of the distribution or, alternatively, at
 
14
 * <http://www.OpenLDAP.org/license.html>.
 
15
 */
 
16
/* Portions Copyright (c) 1990 Regents of the University of Michigan.
 
17
 * All rights reserved.
 
18
 *
 
19
 * Redistribution and use in source and binary forms are permitted
 
20
 * provided that this notice is preserved and that due credit is given
 
21
 * to the University of Michigan at Ann Arbor. The name of the University
 
22
 * may not be used to endorse or promote products derived from this
 
23
 * software without specific prior written permission. This software
 
24
 * is provided ``as is'' without express or implied warranty.
 
25
 */
 
26
/* ACKNOWLEDGEMENTS:
 
27
 * This work was originally developed by the University of Michigan
 
28
 * (as part of U-MICH LDAP).
 
29
 */
 
30
 
 
31
#include "portable.h"
 
32
 
 
33
#include <ctype.h>
 
34
#include <stdio.h>
 
35
 
 
36
#include <ac/stdlib.h>
 
37
 
 
38
#include <ac/stdarg.h>
 
39
#include <ac/socket.h>
 
40
#include <ac/string.h>
 
41
 
 
42
#include "lber-int.h"
 
43
 
 
44
static int ber_put_len LDAP_P((
 
45
        BerElement *ber,
 
46
        ber_len_t len,
 
47
        int nosos ));
 
48
 
 
49
static int ber_start_seqorset LDAP_P((
 
50
        BerElement *ber,
 
51
        ber_tag_t tag ));
 
52
 
 
53
static int ber_put_seqorset LDAP_P(( BerElement *ber ));
 
54
 
 
55
static int ber_put_int_or_enum LDAP_P((
 
56
        BerElement *ber,
 
57
        ber_int_t num,
 
58
        ber_tag_t tag ));
 
59
 
 
60
#define BER_TOP_BYTE(type)      (sizeof(type)-1)
 
61
#define BER_TOP_MASK(type)      ((type)0xffU << (BER_TOP_BYTE(type)*8))
 
62
 
 
63
static int
 
64
ber_calc_taglen( ber_tag_t tag )
 
65
{
 
66
        int     i = BER_TOP_BYTE(ber_tag_t);
 
67
        ber_tag_t       mask = BER_TOP_MASK(ber_tag_t);
 
68
 
 
69
        /* find the first non-all-zero byte in the tag */
 
70
        for ( ; i > 0; i-- ) {
 
71
                /* not all zero */
 
72
                if ( tag & mask ) break;
 
73
                mask >>= 8;
 
74
        }
 
75
 
 
76
        return i + 1;
 
77
}
 
78
 
 
79
static int
 
80
ber_put_tag(
 
81
        BerElement      *ber,
 
82
        ber_tag_t tag,
 
83
        int nosos )
 
84
{
 
85
        int rc;
 
86
        int taglen;
 
87
        int     i;
 
88
        unsigned char nettag[sizeof(ber_tag_t)];
 
89
 
 
90
        assert( ber != NULL );
 
91
        assert( LBER_VALID( ber ) );
 
92
 
 
93
        taglen = ber_calc_taglen( tag );
 
94
 
 
95
        for( i=taglen-1; i>=0; i-- ) {
 
96
                nettag[i] = (unsigned char)(tag & 0xffU);
 
97
                tag >>= 8;
 
98
        }
 
99
 
 
100
        rc = ber_write( ber, (char *) nettag, taglen, nosos );
 
101
 
 
102
        return rc;
 
103
}
 
104
 
 
105
static ber_len_t
 
106
ber_calc_lenlen( ber_len_t len )
 
107
{
 
108
        /*
 
109
         * short len if it's less than 128 - one byte giving the len,
 
110
         * with bit 8 0.
 
111
         */
 
112
 
 
113
        if ( len <= (ber_len_t) 0x7FU ) return 1;
 
114
 
 
115
        /*
 
116
         * long len otherwise - one byte with bit 8 set, giving the
 
117
         * length of the length, followed by the length itself.
 
118
         */
 
119
 
 
120
        if ( len <= (ber_len_t) 0xffU ) return 2;
 
121
        if ( len <= (ber_len_t) 0xffffU ) return 3;
 
122
        if ( len <= (ber_len_t) 0xffffffU ) return 4;
 
123
 
 
124
        return 5;
 
125
}
 
126
 
 
127
static int
 
128
ber_put_len( BerElement *ber, ber_len_t len, int nosos )
 
129
{
 
130
        int rc;
 
131
        int             i,j;
 
132
        char            lenlen;
 
133
        ber_len_t       mask;
 
134
        unsigned char netlen[sizeof(ber_len_t)];
 
135
 
 
136
        assert( ber != NULL );
 
137
        assert( LBER_VALID( ber ) );
 
138
 
 
139
        /*
 
140
         * short len if it's less than 128 - one byte giving the len,
 
141
         * with bit 8 0.
 
142
         */
 
143
 
 
144
        if ( len <= 127 ) {
 
145
                char length_byte = (char) len;
 
146
                return ber_write( ber, &length_byte, 1, nosos );
 
147
        }
 
148
 
 
149
        /*
 
150
         * long len otherwise - one byte with bit 8 set, giving the
 
151
         * length of the length, followed by the length itself.
 
152
         */
 
153
 
 
154
        /* find the first non-all-zero byte */
 
155
        i = BER_TOP_BYTE(ber_len_t);
 
156
        mask = BER_TOP_MASK(ber_len_t);
 
157
        for ( ; i > 0; i-- ) {
 
158
                /* not all zero */
 
159
                if ( len & mask ) break;
 
160
                mask >>= 8;
 
161
        }
 
162
        lenlen = (unsigned char) ++i;
 
163
        if ( lenlen > 4 ) return -1;
 
164
 
 
165
        lenlen |= 0x80UL;
 
166
 
 
167
        /* write the length of the length */
 
168
        if ( ber_write( ber, &lenlen, 1, nosos ) != 1 ) return -1;
 
169
 
 
170
        for( j=i-1; j>=0; j-- ) {
 
171
                netlen[j] = (unsigned char)(len & 0xffU);
 
172
                len >>= 8;
 
173
        }
 
174
 
 
175
        /* write the length itself */
 
176
        rc = ber_write( ber, (char *) netlen, i, nosos );
 
177
 
 
178
        return rc == i ?  i+1 : -1;
 
179
}
 
180
 
 
181
/* out->bv_len should be the buffer size on input */
 
182
int
 
183
ber_encode_oid( BerValue *in, BerValue *out )
 
184
{
 
185
        unsigned char *der;
 
186
        unsigned long val1, val;
 
187
        int i, j, len;
 
188
        char *ptr, *end, *inend;
 
189
 
 
190
        assert( in != NULL );
 
191
        assert( out != NULL );
 
192
 
 
193
        if ( !out->bv_val || out->bv_len < in->bv_len/2 )
 
194
                return -1;
 
195
 
 
196
        der = (unsigned char *) out->bv_val;
 
197
        ptr = in->bv_val;
 
198
        inend = ptr + in->bv_len;
 
199
 
 
200
        /* OIDs start with <0-1>.<0-39> or 2.<any>, DER-encoded 40*val1+val2 */
 
201
        if ( !isdigit( (unsigned char) *ptr )) return -1;
 
202
        val1 = strtoul( ptr, &end, 10 );
 
203
        if ( end == ptr || val1 > 2 ) return -1;
 
204
        if ( *end++ != '.' || !isdigit( (unsigned char) *end )) return -1;
 
205
        val = strtoul( end, &ptr, 10 );
 
206
        if ( ptr == end ) return -1;
 
207
        if ( val > (val1 < 2 ? 39 : LBER_OID_COMPONENT_MAX - 80) ) return -1;
 
208
        val += val1 * 40;
 
209
 
 
210
        for (;;) {
 
211
                if ( ptr > inend ) return -1;
 
212
 
 
213
                len = 0;
 
214
                do {
 
215
                        der[len++] = (val & 0xff) | 0x80;
 
216
                } while ( (val >>= 7) != 0 );
 
217
                der[0] &= 0x7f;
 
218
                for ( i = 0, j = len; i < --j; i++ ) {
 
219
                        unsigned char tmp = der[i];
 
220
                        der[i] = der[j];
 
221
                        der[j] = tmp;
 
222
                }
 
223
                der += len;
 
224
                if ( ptr == inend )
 
225
                        break;
 
226
 
 
227
                if ( *ptr++ != '.' ) return -1;
 
228
                if ( !isdigit( (unsigned char) *ptr )) return -1;
 
229
                val = strtoul( ptr, &end, 10 );
 
230
                if ( end == ptr || val > LBER_OID_COMPONENT_MAX ) return -1;
 
231
                ptr = end;
 
232
        }
 
233
 
 
234
        out->bv_len = (char *)der - out->bv_val;
 
235
        return 0;
 
236
}
 
237
 
 
238
static int
 
239
ber_put_int_or_enum(
 
240
        BerElement *ber,
 
241
        ber_int_t num,
 
242
        ber_tag_t tag )
 
243
{
 
244
        int rc;
 
245
        int     i, j, sign, taglen, lenlen;
 
246
        ber_len_t       len;
 
247
        ber_uint_t      unum, mask;
 
248
        unsigned char netnum[sizeof(ber_uint_t)];
 
249
 
 
250
        assert( ber != NULL );
 
251
        assert( LBER_VALID( ber ) );
 
252
 
 
253
        sign = (num < 0);
 
254
        unum = num;     /* Bit fiddling should be done with unsigned values */
 
255
 
 
256
        /*
 
257
         * high bit is set - look for first non-all-one byte
 
258
         * high bit is clear - look for first non-all-zero byte
 
259
         */
 
260
        i = BER_TOP_BYTE(ber_int_t);
 
261
        mask = BER_TOP_MASK(ber_uint_t);
 
262
        for ( ; i > 0; i-- ) {
 
263
                if ( sign ) {
 
264
                        /* not all ones */
 
265
                        if ( (unum & mask) != mask ) break;
 
266
                } else {
 
267
                        /* not all zero */
 
268
                        if ( unum & mask ) break;
 
269
                }
 
270
                mask >>= 8;
 
271
        }
 
272
 
 
273
        /*
 
274
         * we now have the "leading byte".  if the high bit on this
 
275
         * byte matches the sign bit, we need to "back up" a byte.
 
276
         */
 
277
        mask = (unum & ((ber_uint_t)0x80U << (i * 8)));
 
278
        if ( (mask && !sign) || (sign && !mask) ) {
 
279
                i++;
 
280
        }
 
281
 
 
282
        len = i + 1;
 
283
 
 
284
        if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
 
285
                return -1;
 
286
        }
 
287
 
 
288
        if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ) {
 
289
                return -1;
 
290
        }
 
291
        i++;
 
292
 
 
293
        for( j=i-1; j>=0; j-- ) {
 
294
                netnum[j] = (unsigned char)(unum & 0xffU);
 
295
                unum >>= 8;
 
296
        }
 
297
 
 
298
        rc = ber_write( ber, (char *) netnum, i, 0 );
 
299
 
 
300
        /* length of tag + length + contents */
 
301
        return rc == i ? taglen + lenlen + i : -1;
 
302
}
 
303
 
 
304
int
 
305
ber_put_enum(
 
306
        BerElement *ber,
 
307
        ber_int_t num,
 
308
        ber_tag_t tag )
 
309
{
 
310
        assert( ber != NULL );
 
311
        assert( LBER_VALID( ber ) );
 
312
 
 
313
        if ( tag == LBER_DEFAULT ) {
 
314
                tag = LBER_ENUMERATED;
 
315
        }
 
316
 
 
317
        return ber_put_int_or_enum( ber, num, tag );
 
318
}
 
319
 
 
320
int
 
321
ber_put_int(
 
322
        BerElement *ber,
 
323
        ber_int_t num,
 
324
        ber_tag_t tag )
 
325
{
 
326
        assert( ber != NULL );
 
327
        assert( LBER_VALID( ber ) );
 
328
 
 
329
        if ( tag == LBER_DEFAULT ) {
 
330
                tag = LBER_INTEGER;
 
331
        }
 
332
 
 
333
        return ber_put_int_or_enum( ber, num, tag );
 
334
}
 
335
 
 
336
int
 
337
ber_put_ostring(
 
338
        BerElement *ber,
 
339
        LDAP_CONST char *str,
 
340
        ber_len_t len,
 
341
        ber_tag_t tag )
 
342
{
 
343
        int taglen, lenlen, rc;
 
344
 
 
345
        assert( ber != NULL );
 
346
        assert( str != NULL );
 
347
 
 
348
        assert( LBER_VALID( ber ) );
 
349
 
 
350
        if ( tag == LBER_DEFAULT ) {
 
351
                tag = LBER_OCTETSTRING;
 
352
        }
 
353
 
 
354
        if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 )
 
355
                return -1;
 
356
 
 
357
        if ( (lenlen = ber_put_len( ber, len, 0 )) == -1 ||
 
358
                (ber_len_t) ber_write( ber, str, len, 0 ) != len )
 
359
        {
 
360
                rc = -1;
 
361
        } else {
 
362
                /* return length of tag + length + contents */
 
363
                rc = taglen + lenlen + len;
 
364
        }
 
365
 
 
366
        return rc;
 
367
}
 
368
 
 
369
int
 
370
ber_put_berval(
 
371
        BerElement *ber,
 
372
        struct berval *bv,
 
373
        ber_tag_t tag )
 
374
{
 
375
        assert( ber != NULL );
 
376
        assert( LBER_VALID( ber ) );
 
377
 
 
378
        if( bv == NULL || bv->bv_len == 0 ) {
 
379
                return ber_put_ostring( ber, "", (ber_len_t) 0, tag );
 
380
        }
 
381
 
 
382
        return ber_put_ostring( ber, bv->bv_val, bv->bv_len, tag );
 
383
}
 
384
 
 
385
int
 
386
ber_put_string(
 
387
        BerElement *ber,
 
388
        LDAP_CONST char *str,
 
389
        ber_tag_t tag )
 
390
{
 
391
        assert( ber != NULL );
 
392
        assert( str != NULL );
 
393
 
 
394
        assert( LBER_VALID( ber ) );
 
395
 
 
396
        return ber_put_ostring( ber, str, strlen( str ), tag );
 
397
}
 
398
 
 
399
int
 
400
ber_put_bitstring(
 
401
        BerElement *ber,
 
402
        LDAP_CONST char *str,
 
403
        ber_len_t blen /* in bits */,
 
404
        ber_tag_t tag )
 
405
{
 
406
        int                             taglen, lenlen;
 
407
        ber_len_t               len;
 
408
        unsigned char   unusedbits;
 
409
 
 
410
        assert( ber != NULL );
 
411
        assert( str != NULL );
 
412
 
 
413
        assert( LBER_VALID( ber ) );
 
414
 
 
415
        if ( tag == LBER_DEFAULT ) {
 
416
                tag = LBER_BITSTRING;
 
417
        }
 
418
 
 
419
        if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
 
420
                return -1;
 
421
        }
 
422
 
 
423
        len = ( blen + 7 ) / 8;
 
424
        unusedbits = (unsigned char) ((len * 8) - blen);
 
425
        if ( (lenlen = ber_put_len( ber, len + 1, 0 )) == -1 ) {
 
426
                return -1;
 
427
        }
 
428
 
 
429
        if ( ber_write( ber, (char *)&unusedbits, 1, 0 ) != 1 ) {
 
430
                return -1;
 
431
        }
 
432
 
 
433
        if ( (ber_len_t) ber_write( ber, str, len, 0 ) != len ) {
 
434
                return -1;
 
435
        }
 
436
 
 
437
        /* return length of tag + length + unused bit count + contents */
 
438
        return taglen + 1 + lenlen + len;
 
439
}
 
440
 
 
441
int
 
442
ber_put_null( BerElement *ber, ber_tag_t tag )
 
443
{
 
444
        int     taglen;
 
445
 
 
446
        assert( ber != NULL );
 
447
        assert( LBER_VALID( ber ) );
 
448
 
 
449
        if ( tag == LBER_DEFAULT ) {
 
450
                tag = LBER_NULL;
 
451
        }
 
452
 
 
453
        if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
 
454
                return -1;
 
455
        }
 
456
 
 
457
        if ( ber_put_len( ber, 0, 0 ) != 1 ) {
 
458
                return -1;
 
459
        }
 
460
 
 
461
        return taglen + 1;
 
462
}
 
463
 
 
464
int
 
465
ber_put_boolean(
 
466
        BerElement *ber,
 
467
        ber_int_t boolval,
 
468
        ber_tag_t tag )
 
469
{
 
470
        int                             taglen;
 
471
        unsigned char   c;
 
472
 
 
473
        assert( ber != NULL );
 
474
        assert( LBER_VALID( ber ) );
 
475
 
 
476
        if ( tag == LBER_DEFAULT )
 
477
                tag = LBER_BOOLEAN;
 
478
 
 
479
        if ( (taglen = ber_put_tag( ber, tag, 0 )) == -1 ) {
 
480
                return -1;
 
481
        }
 
482
 
 
483
        if ( ber_put_len( ber, 1, 0 ) != 1 ) {
 
484
                return -1;
 
485
        }
 
486
 
 
487
        c = boolval ? (unsigned char) ~0U : (unsigned char) 0U;
 
488
 
 
489
        if ( ber_write( ber, (char *) &c, 1, 0 ) != 1 ) {
 
490
                return -1;
 
491
        }
 
492
 
 
493
        return taglen + 2;
 
494
}
 
495
 
 
496
#define FOUR_BYTE_LEN   5
 
497
 
 
498
static int
 
499
ber_start_seqorset(
 
500
        BerElement *ber,
 
501
        ber_tag_t tag )
 
502
{
 
503
        Seqorset        *new;
 
504
 
 
505
        assert( ber != NULL );
 
506
        assert( LBER_VALID( ber ) );
 
507
 
 
508
        new = (Seqorset *) ber_memcalloc_x( 1, sizeof(Seqorset), ber->ber_memctx );
 
509
 
 
510
        if ( new == NULL ) {
 
511
                return -1;
 
512
        }
 
513
 
 
514
        new->sos_ber = ber;
 
515
        if ( ber->ber_sos == NULL ) {
 
516
                new->sos_first = ber->ber_ptr;
 
517
        } else {
 
518
                new->sos_first = ber->ber_sos->sos_ptr;
 
519
        }
 
520
 
 
521
        /* Set aside room for a 4 byte length field */
 
522
        new->sos_ptr = new->sos_first + ber_calc_taglen( tag ) + FOUR_BYTE_LEN;
 
523
        new->sos_tag = tag;
 
524
 
 
525
        new->sos_next = ber->ber_sos;
 
526
        ber->ber_sos = new;
 
527
 
 
528
        return 0;
 
529
}
 
530
 
 
531
int
 
532
ber_start_seq( BerElement *ber, ber_tag_t tag )
 
533
{
 
534
        assert( ber != NULL );
 
535
        assert( LBER_VALID( ber ) );
 
536
 
 
537
        if ( tag == LBER_DEFAULT ) {
 
538
                tag = LBER_SEQUENCE;
 
539
        }
 
540
 
 
541
        return ber_start_seqorset( ber, tag );
 
542
}
 
543
 
 
544
int
 
545
ber_start_set( BerElement *ber, ber_tag_t tag )
 
546
{
 
547
        assert( ber != NULL );
 
548
        assert( LBER_VALID( ber ) );
 
549
 
 
550
        if ( tag == LBER_DEFAULT ) {
 
551
                tag = LBER_SET;
 
552
        }
 
553
 
 
554
        return ber_start_seqorset( ber, tag );
 
555
}
 
556
 
 
557
static int
 
558
ber_put_seqorset( BerElement *ber )
 
559
{
 
560
        int rc;
 
561
        ber_len_t       len;
 
562
        unsigned char netlen[sizeof(ber_len_t)];
 
563
        int                     taglen;
 
564
        ber_len_t       lenlen;
 
565
        unsigned char   ltag = 0x80U + FOUR_BYTE_LEN - 1;
 
566
        Seqorset        *next;
 
567
        Seqorset        **sos = &ber->ber_sos;
 
568
 
 
569
        assert( ber != NULL );
 
570
        assert( LBER_VALID( ber ) );
 
571
 
 
572
        if( *sos == NULL ) return -1;
 
573
 
 
574
        /*
 
575
         * If this is the toplevel sequence or set, we need to actually
 
576
         * write the stuff out.  Otherwise, it's already been put in
 
577
         * the appropriate buffer and will be written when the toplevel
 
578
         * one is written.  In this case all we need to do is update the
 
579
         * length and tag.
 
580
         */
 
581
 
 
582
        len = (*sos)->sos_clen;
 
583
 
 
584
        if ( sizeof(ber_len_t) > 4 && len > 0xffffffffUL ) {
 
585
                return -1;
 
586
        }
 
587
 
 
588
        if ( ber->ber_options & LBER_USE_DER ) {
 
589
                lenlen = ber_calc_lenlen( len );
 
590
 
 
591
        } else {
 
592
                lenlen = FOUR_BYTE_LEN;
 
593
        }
 
594
 
 
595
        if( lenlen > 1 ) {
 
596
                int i;
 
597
                ber_len_t j = len;
 
598
                for( i=lenlen-2; i >= 0; i-- ) {
 
599
                        netlen[i] = j & 0xffU;
 
600
                        j >>= 8;
 
601
                }
 
602
        } else {
 
603
                netlen[0] = (unsigned char)(len & 0x7fU);
 
604
        }
 
605
 
 
606
        if ( (next = (*sos)->sos_next) == NULL ) {
 
607
                /* write the tag */
 
608
                if ( (taglen = ber_put_tag( ber, (*sos)->sos_tag, 1 )) == -1 ) {
 
609
                        return( -1 );
 
610
                }
 
611
 
 
612
                if ( ber->ber_options & LBER_USE_DER ) {
 
613
                        /* Write the length in the minimum # of octets */
 
614
                        if ( ber_put_len( ber, len, 1 ) == -1 ) {
 
615
                                return -1;
 
616
                        }
 
617
 
 
618
                        if (lenlen != FOUR_BYTE_LEN) {
 
619
                                /*
 
620
                                 * We set aside FOUR_BYTE_LEN bytes for
 
621
                                 * the length field.  Move the data if
 
622
                                 * we don't actually need that much
 
623
                                 */
 
624
                                AC_MEMCPY( (*sos)->sos_first + taglen +
 
625
                                    lenlen, (*sos)->sos_first + taglen +
 
626
                                    FOUR_BYTE_LEN, len );
 
627
                        }
 
628
                } else {
 
629
                        /* Fill FOUR_BYTE_LEN bytes for length field */
 
630
                        /* one byte of length length */
 
631
                        if ( ber_write( ber, (char *)&ltag, 1, 1 ) != 1 ) {
 
632
                                return -1;
 
633
                        }
 
634
 
 
635
                        /* the length itself */
 
636
                        rc  = ber_write( ber, (char *) netlen, FOUR_BYTE_LEN-1, 1 );
 
637
 
 
638
                        if( rc != FOUR_BYTE_LEN - 1 ) {
 
639
                                return -1;
 
640
                        }
 
641
                }
 
642
                /* The ber_ptr is at the set/seq start - move it to the end */
 
643
                (*sos)->sos_ber->ber_ptr += len;
 
644
 
 
645
        } else {
 
646
                int i;
 
647
                unsigned char nettag[sizeof(ber_tag_t)];
 
648
                ber_tag_t tmptag = (*sos)->sos_tag;
 
649
 
 
650
                if( ber->ber_sos->sos_ptr > ber->ber_end ) {
 
651
                        /* The sos_ptr exceeds the end of the BerElement
 
652
                         * this can happen, for example, when the sos_ptr
 
653
                         * is near the end and no data was written for the
 
654
                         * 'V'.  We must realloc the BerElement to ensure
 
655
                         * we don't overwrite the buffer when writing
 
656
                         * the tag and length fields.
 
657
                         */
 
658
                        ber_len_t ext = ber->ber_sos->sos_ptr - ber->ber_end;
 
659
 
 
660
                        if( ber_realloc( ber,  ext ) != 0 ) {
 
661
                                return -1;
 
662
                        }
 
663
                }
 
664
 
 
665
                /* the tag */
 
666
                taglen = ber_calc_taglen( tmptag );
 
667
 
 
668
                for( i = taglen-1; i >= 0; i-- ) {
 
669
                        nettag[i] = (unsigned char)(tmptag & 0xffU);
 
670
                        tmptag >>= 8;
 
671
                }
 
672
 
 
673
                AC_FMEMCPY( (*sos)->sos_first, nettag, taglen );
 
674
 
 
675
                if ( ber->ber_options & LBER_USE_DER ) {
 
676
                        ltag = (lenlen == 1)
 
677
                                ? (unsigned char) len
 
678
                                : (unsigned char) (0x80U + (lenlen - 1));
 
679
                }
 
680
 
 
681
                /* one byte of length length */
 
682
                (*sos)->sos_first[1] = ltag;
 
683
 
 
684
                if ( ber->ber_options & LBER_USE_DER ) {
 
685
                        if (lenlen > 1) {
 
686
                                /* Write the length itself */
 
687
                                AC_FMEMCPY( (*sos)->sos_first + 2, netlen, lenlen - 1 );
 
688
                        }
 
689
                        if (lenlen != FOUR_BYTE_LEN) {
 
690
                                /*
 
691
                                 * We set aside FOUR_BYTE_LEN bytes for
 
692
                                 * the length field.  Move the data if
 
693
                                 * we don't actually need that much
 
694
                                 */
 
695
                                AC_FMEMCPY( (*sos)->sos_first + taglen +
 
696
                                    lenlen, (*sos)->sos_first + taglen +
 
697
                                    FOUR_BYTE_LEN, len );
 
698
                        }
 
699
                } else {
 
700
                        /* the length itself */
 
701
                        AC_FMEMCPY( (*sos)->sos_first + taglen + 1,
 
702
                            netlen, FOUR_BYTE_LEN - 1 );
 
703
                }
 
704
 
 
705
                next->sos_clen += (taglen + lenlen + len);
 
706
                next->sos_ptr += (taglen + lenlen + len);
 
707
        }
 
708
 
 
709
        /* we're done with this seqorset, so free it up */
 
710
        ber_memfree_x( (char *) (*sos), ber->ber_memctx );
 
711
        *sos = next;
 
712
 
 
713
        return taglen + lenlen + len;
 
714
}
 
715
 
 
716
int
 
717
ber_put_seq( BerElement *ber )
 
718
{
 
719
        assert( ber != NULL );
 
720
        assert( LBER_VALID( ber ) );
 
721
 
 
722
        return ber_put_seqorset( ber );
 
723
}
 
724
 
 
725
int
 
726
ber_put_set( BerElement *ber )
 
727
{
 
728
        assert( ber != NULL );
 
729
        assert( LBER_VALID( ber ) );
 
730
 
 
731
        return ber_put_seqorset( ber );
 
732
}
 
733
 
 
734
/* N tag */
 
735
static ber_tag_t lber_int_null = 0;
 
736
 
 
737
/* VARARGS */
 
738
int
 
739
ber_printf( BerElement *ber, LDAP_CONST char *fmt, ... )
 
740
{
 
741
        va_list         ap;
 
742
        char            *s, **ss;
 
743
        struct berval   *bv, **bvp;
 
744
        int             rc;
 
745
        ber_int_t       i;
 
746
        ber_len_t       len;
 
747
 
 
748
        assert( ber != NULL );
 
749
        assert( fmt != NULL );
 
750
 
 
751
        assert( LBER_VALID( ber ) );
 
752
 
 
753
        va_start( ap, fmt );
 
754
 
 
755
        for ( rc = 0; *fmt && rc != -1; fmt++ ) {
 
756
                switch ( *fmt ) {
 
757
                case '!': { /* hook */
 
758
                                BEREncodeCallback *f;
 
759
                                void *p;
 
760
 
 
761
                                f = va_arg( ap, BEREncodeCallback * );
 
762
                                p = va_arg( ap, void * );
 
763
 
 
764
                                rc = (*f)( ber, p );
 
765
                        } break;
 
766
 
 
767
                case 'b':       /* boolean */
 
768
                        i = va_arg( ap, ber_int_t );
 
769
                        rc = ber_put_boolean( ber, i, ber->ber_tag );
 
770
                        break;
 
771
 
 
772
                case 'i':       /* int */
 
773
                        i = va_arg( ap, ber_int_t );
 
774
                        rc = ber_put_int( ber, i, ber->ber_tag );
 
775
                        break;
 
776
 
 
777
                case 'e':       /* enumeration */
 
778
                        i = va_arg( ap, ber_int_t );
 
779
                        rc = ber_put_enum( ber, i, ber->ber_tag );
 
780
                        break;
 
781
 
 
782
                case 'n':       /* null */
 
783
                        rc = ber_put_null( ber, ber->ber_tag );
 
784
                        break;
 
785
 
 
786
                case 'N':       /* Debug NULL */
 
787
                        if( lber_int_null != 0 ) {
 
788
                                /* Insert NULL to ensure peer ignores unknown tags */
 
789
                                rc = ber_put_null( ber, lber_int_null );
 
790
                        } else {
 
791
                                rc = 0;
 
792
                        }
 
793
                        break;
 
794
 
 
795
                case 'o':       /* octet string (non-null terminated) */
 
796
                        s = va_arg( ap, char * );
 
797
                        len = va_arg( ap, ber_len_t );
 
798
                        rc = ber_put_ostring( ber, s, len, ber->ber_tag );
 
799
                        break;
 
800
 
 
801
                case 'O':       /* berval octet string */
 
802
                        bv = va_arg( ap, struct berval * );
 
803
                        if( bv == NULL ) break;
 
804
                        rc = ber_put_berval( ber, bv, ber->ber_tag );
 
805
                        break;
 
806
 
 
807
                case 's':       /* string */
 
808
                        s = va_arg( ap, char * );
 
809
                        rc = ber_put_string( ber, s, ber->ber_tag );
 
810
                        break;
 
811
 
 
812
                case 'B':       /* bit string */
 
813
                case 'X':       /* bit string (deprecated) */
 
814
                        s = va_arg( ap, char * );
 
815
                        len = va_arg( ap, int );        /* in bits */
 
816
                        rc = ber_put_bitstring( ber, s, len, ber->ber_tag );
 
817
                        break;
 
818
 
 
819
                case 't':       /* tag for the next element */
 
820
                        ber->ber_tag = va_arg( ap, ber_tag_t );
 
821
                        ber->ber_usertag = 1;
 
822
                        break;
 
823
 
 
824
                case 'v':       /* vector of strings */
 
825
                        if ( (ss = va_arg( ap, char ** )) == NULL )
 
826
                                break;
 
827
                        for ( i = 0; ss[i] != NULL; i++ ) {
 
828
                                if ( (rc = ber_put_string( ber, ss[i],
 
829
                                    ber->ber_tag )) == -1 )
 
830
                                        break;
 
831
                        }
 
832
                        break;
 
833
 
 
834
                case 'V':       /* sequences of strings + lengths */
 
835
                        if ( (bvp = va_arg( ap, struct berval ** )) == NULL )
 
836
                                break;
 
837
                        for ( i = 0; bvp[i] != NULL; i++ ) {
 
838
                                if ( (rc = ber_put_berval( ber, bvp[i],
 
839
                                    ber->ber_tag )) == -1 )
 
840
                                        break;
 
841
                        }
 
842
                        break;
 
843
 
 
844
                case 'W':       /* BerVarray */
 
845
                        if ( (bv = va_arg( ap, BerVarray )) == NULL )
 
846
                                break;
 
847
                        for ( i = 0; bv[i].bv_val != NULL; i++ ) {
 
848
                                if ( (rc = ber_put_berval( ber, &bv[i],
 
849
                                    ber->ber_tag )) == -1 )
 
850
                                        break;
 
851
                        }
 
852
                        break;
 
853
 
 
854
                case '{':       /* begin sequence */
 
855
                        rc = ber_start_seq( ber, ber->ber_tag );
 
856
                        break;
 
857
 
 
858
                case '}':       /* end sequence */
 
859
                        rc = ber_put_seqorset( ber );
 
860
                        break;
 
861
 
 
862
                case '[':       /* begin set */
 
863
                        rc = ber_start_set( ber, ber->ber_tag );
 
864
                        break;
 
865
 
 
866
                case ']':       /* end set */
 
867
                        rc = ber_put_seqorset( ber );
 
868
                        break;
 
869
 
 
870
                default:
 
871
                        if( ber->ber_debug ) {
 
872
                                ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
 
873
                                        "ber_printf: unknown fmt %c\n", *fmt );
 
874
                        }
 
875
                        rc = -1;
 
876
                        break;
 
877
                }
 
878
 
 
879
                if ( ber->ber_usertag == 0 ) {
 
880
                        ber->ber_tag = LBER_DEFAULT;
 
881
                } else {
 
882
                        ber->ber_usertag = 0;
 
883
                }
 
884
        }
 
885
 
 
886
        va_end( ap );
 
887
 
 
888
        return rc;
 
889
}