Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/ldap/liblber/decode.c
4394 views
1
/* decode.c - ber input decoding routines */
2
/* $OpenLDAP$ */
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4
*
5
* Copyright 1998-2024 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 <stdio.h>
34
35
#include <ac/stdlib.h>
36
#include <ac/stdarg.h>
37
#include <ac/string.h>
38
#include <ac/socket.h>
39
40
#include "lber-int.h"
41
42
43
/* out->bv_len should be the buffer size on input */
44
int
45
ber_decode_oid( BerValue *in, BerValue *out )
46
{
47
const unsigned char *der;
48
unsigned long val;
49
unsigned val1;
50
ber_len_t i;
51
char *ptr;
52
53
assert( in != NULL );
54
assert( out != NULL );
55
56
/* need 4 chars/inbyte + \0 for input={7f 7f 7f...} */
57
if ( !out->bv_val || (out->bv_len+3)/4 <= in->bv_len )
58
return -1;
59
60
ptr = NULL;
61
der = (unsigned char *) in->bv_val;
62
val = 0;
63
for ( i=0; i < in->bv_len; i++ ) {
64
val |= der[i] & 0x7f;
65
if ( !( der[i] & 0x80 )) {
66
if ( ptr == NULL ) {
67
/* Initial "x.y": val=x*40+y, x<=2, y<40 if x<2 */
68
ptr = out->bv_val;
69
val1 = (val < 80 ? val/40 : 2);
70
val -= val1*40;
71
ptr += sprintf( ptr, "%u", val1 );
72
}
73
ptr += sprintf( ptr, ".%lu", val );
74
val = 0;
75
} else if ( val - 1UL < LBER_OID_COMPONENT_MAX >> 7 ) {
76
val <<= 7;
77
} else {
78
/* val would overflow, or is 0 from invalid initial 0x80 octet */
79
return -1;
80
}
81
}
82
if ( ptr == NULL || val != 0 )
83
return -1;
84
85
out->bv_len = ptr - out->bv_val;
86
return 0;
87
}
88
89
/* Return tag, with *bv = rest of element (starting at length octets) */
90
static ber_tag_t
91
ber_tag_and_rest( const BerElement *ber, struct berval *bv )
92
{
93
ber_tag_t tag;
94
ptrdiff_t rest;
95
unsigned char *ptr;
96
97
assert( ber != NULL );
98
assert( LBER_VALID( ber ) );
99
100
ptr = (unsigned char *) ber->ber_ptr;
101
rest = (unsigned char *) ber->ber_end - ptr;
102
if ( rest <= 0 ) {
103
goto fail;
104
}
105
106
tag = ber->ber_tag;
107
if ( (char *) ptr == ber->ber_buf ) {
108
tag = *ptr;
109
}
110
ptr++;
111
rest--;
112
if ( (tag & LBER_BIG_TAG_MASK) != LBER_BIG_TAG_MASK ) {
113
goto done;
114
}
115
116
do {
117
if ( rest <= 0 ) {
118
break;
119
}
120
tag <<= 8;
121
tag |= *ptr++ & 0xffU;
122
rest--;
123
124
if ( ! (tag & LBER_MORE_TAG_MASK) ) {
125
goto done;
126
}
127
} while ( tag <= (ber_tag_t)-1 / 256 );
128
129
fail:
130
/* Error or unsupported tag size */
131
tag = LBER_DEFAULT;
132
133
done:
134
bv->bv_len = rest;
135
bv->bv_val = (char *) ptr;
136
return tag;
137
}
138
139
/* Return the tag - LBER_DEFAULT returned means trouble */
140
ber_tag_t
141
ber_get_tag( BerElement *ber )
142
{
143
struct berval bv;
144
ber_tag_t tag = ber_tag_and_rest( ber, &bv );
145
146
ber->ber_ptr = bv.bv_val;
147
return tag;
148
}
149
150
/* Return next element's tag and point *bv at its contents in-place */
151
ber_tag_t
152
ber_peek_element( const BerElement *ber, struct berval *bv )
153
{
154
ber_tag_t tag;
155
ber_len_t len, rest;
156
unsigned i;
157
unsigned char *ptr;
158
159
assert( bv != NULL );
160
161
/*
162
* Any ber element looks like this: tag length contents.
163
* Assuming everything's ok, we return the tag, and point
164
* bv at the contents.
165
*
166
* Assumptions:
167
* 1) definite lengths
168
* 2) primitive encodings used whenever possible
169
*/
170
171
len = 0;
172
173
/*
174
* First, we read the tag.
175
*/
176
tag = ber_tag_and_rest( ber, bv );
177
178
rest = bv->bv_len;
179
ptr = (unsigned char *) bv->bv_val;
180
if ( tag == LBER_DEFAULT || rest == 0 ) {
181
goto fail;
182
}
183
184
/*
185
* Next, read the length. The first octet determines the length
186
* of the length. If bit 8 is 0, the length is the short form,
187
* otherwise if the octet != 0x80 it's the long form, otherwise
188
* the ber element has the unsupported indefinite-length format.
189
* Lengths that do not fit in a ber_len_t are not accepted.
190
*/
191
192
len = *ptr++;
193
rest--;
194
195
if ( len & 0x80U ) {
196
len &= 0x7fU;
197
if ( len - 1U > sizeof(ber_len_t) - 1U || rest < len ) {
198
/* Indefinite-length/too long length/not enough data */
199
goto fail;
200
}
201
202
rest -= len;
203
i = len;
204
for( len = *ptr++ & 0xffU; --i; len |= *ptr++ & 0xffU ) {
205
len <<= 8;
206
}
207
}
208
209
/* BER element should have enough data left */
210
if( len > rest ) {
211
fail:
212
tag = LBER_DEFAULT;
213
}
214
215
bv->bv_len = len;
216
bv->bv_val = (char *) ptr;
217
return tag;
218
}
219
220
/* Move past next element, point *bv at it in-place, and return its tag.
221
* The caller may \0-terminate *bv, as next octet is saved in ber->ber_tag.
222
* Similar to ber_get_stringbv(ber, bv, LBER_BV_NOTERM) except on error.
223
*/
224
ber_tag_t
225
ber_skip_element( BerElement *ber, struct berval *bv )
226
{
227
ber_tag_t tag = ber_peek_element( ber, bv );
228
229
if ( tag != LBER_DEFAULT ) {
230
ber->ber_ptr = bv->bv_val + bv->bv_len;
231
ber->ber_tag = *(unsigned char *) ber->ber_ptr;
232
}
233
234
return tag;
235
}
236
237
/* Move past next element, point *bv at the complete element in-place, and
238
* return its tag. The caller may \0-terminate *bv, as next octet is saved in
239
* ber->ber_tag. Similar to ber_skip_element(ber, bv) except the tag+length
240
* header is also included in *bv.
241
*/
242
ber_tag_t
243
ber_skip_raw( BerElement *ber, struct berval *bv )
244
{
245
char *val = ber->ber_ptr;
246
ber_tag_t tag = ber_skip_element( ber, bv );
247
248
if ( tag != LBER_DEFAULT ) {
249
bv->bv_len += bv->bv_val - val;
250
bv->bv_val = val;
251
}
252
253
return tag;
254
}
255
256
ber_tag_t
257
ber_peek_tag(
258
BerElement *ber,
259
ber_len_t *len )
260
{
261
struct berval bv;
262
ber_tag_t tag = ber_peek_element( ber, &bv );
263
264
*len = bv.bv_len;
265
return tag;
266
}
267
268
ber_tag_t
269
ber_skip_tag( BerElement *ber, ber_len_t *lenp )
270
{
271
struct berval bv;
272
ber_tag_t tag = ber_peek_element( ber, &bv );
273
274
ber->ber_ptr = bv.bv_val;
275
ber->ber_tag = *(unsigned char *) ber->ber_ptr;
276
277
*lenp = bv.bv_len;
278
return tag;
279
}
280
281
ber_tag_t
282
ber_get_int(
283
BerElement *ber,
284
ber_int_t *num )
285
{
286
struct berval bv;
287
ber_tag_t tag = ber_skip_element( ber, &bv );
288
289
if ( tag == LBER_DEFAULT ) {
290
return tag;
291
}
292
293
return ber_decode_int( &bv, num ) ? LBER_DEFAULT : tag;
294
}
295
296
int
297
ber_decode_int( const struct berval *bv, ber_int_t *num )
298
{
299
ber_len_t len = bv->bv_len;
300
if ( len > sizeof(ber_int_t) )
301
return -1;
302
303
assert( num != NULL );
304
305
/* parse two's complement integer */
306
if( len ) {
307
unsigned char *buf = (unsigned char *) bv->bv_val;
308
ber_len_t i;
309
ber_int_t netnum = buf[0] & 0xff;
310
311
/* sign extend */
312
netnum = (netnum ^ 0x80) - 0x80;
313
314
/* shift in the bytes */
315
for( i = 1; i < len; i++ ) {
316
netnum = (netnum << 8 ) | buf[i];
317
}
318
319
*num = netnum;
320
321
} else {
322
*num = 0;
323
}
324
325
return 0;
326
}
327
328
ber_tag_t
329
ber_get_enum(
330
BerElement *ber,
331
ber_int_t *num )
332
{
333
return ber_get_int( ber, num );
334
}
335
336
ber_tag_t
337
ber_get_stringb(
338
BerElement *ber,
339
char *buf,
340
ber_len_t *len )
341
{
342
struct berval bv;
343
ber_tag_t tag;
344
345
if ( (tag = ber_skip_element( ber, &bv )) == LBER_DEFAULT ) {
346
return LBER_DEFAULT;
347
}
348
349
/* must fit within allocated space with termination */
350
if ( bv.bv_len >= *len ) {
351
return LBER_DEFAULT;
352
}
353
354
memcpy( buf, bv.bv_val, bv.bv_len );
355
buf[bv.bv_len] = '\0';
356
357
*len = bv.bv_len;
358
return tag;
359
}
360
361
/* Definitions for get_string vector
362
*
363
* ChArray, BvArray, and BvVec are self-explanatory.
364
* BvOff is a struct berval embedded in an array of larger structures
365
* of siz bytes at off bytes from the beginning of the struct.
366
*/
367
enum bgbvc { ChArray, BvArray, BvVec, BvOff };
368
369
/* Use this single cookie for state, to keep actual
370
* stack use to the absolute minimum.
371
*/
372
typedef struct bgbvr {
373
const enum bgbvc choice;
374
const int option; /* (ALLOC unless BvOff) | (STRING if ChArray) */
375
ber_len_t siz; /* input array element size, output count */
376
ber_len_t off; /* BvOff offset to the struct berval */
377
void *result;
378
} bgbvr;
379
380
static ber_tag_t
381
ber_get_stringbvl( BerElement *ber, bgbvr *b )
382
{
383
int i = 0, n;
384
ber_tag_t tag;
385
ber_len_t tot_size = 0, siz = b->siz;
386
char *last, *orig;
387
struct berval bv, *bvp = NULL;
388
union stringbvl_u {
389
char **ca; /* ChArray */
390
BerVarray ba; /* BvArray */
391
struct berval **bv; /* BvVec */
392
char *bo; /* BvOff */
393
} res;
394
395
tag = ber_skip_tag( ber, &bv.bv_len );
396
397
if ( tag != LBER_DEFAULT ) {
398
tag = 0;
399
orig = ber->ber_ptr;
400
last = orig + bv.bv_len;
401
402
for ( ; ber->ber_ptr < last; i++, tot_size += siz ) {
403
if ( ber_skip_element( ber, &bv ) == LBER_DEFAULT )
404
break;
405
}
406
if ( ber->ber_ptr != last ) {
407
i = 0;
408
tag = LBER_DEFAULT;
409
}
410
411
ber->ber_ptr = orig;
412
ber->ber_tag = *(unsigned char *) orig;
413
}
414
415
b->siz = i;
416
if ( i == 0 ) {
417
return tag;
418
}
419
420
/* Allocate and NULL-terminate the result vector */
421
b->result = ber_memalloc_x( tot_size + siz, ber->ber_memctx );
422
if ( b->result == NULL ) {
423
return LBER_DEFAULT;
424
}
425
switch (b->choice) {
426
case ChArray:
427
res.ca = b->result;
428
res.ca[i] = NULL;
429
break;
430
case BvArray:
431
res.ba = b->result;
432
res.ba[i].bv_val = NULL;
433
break;
434
case BvVec:
435
res.bv = b->result;
436
res.bv[i] = NULL;
437
break;
438
case BvOff:
439
res.bo = (char *) b->result + b->off;
440
((struct berval *) (res.bo + tot_size))->bv_val = NULL;
441
tot_size = 0;
442
break;
443
}
444
445
n = 0;
446
do {
447
tag = ber_get_stringbv( ber, &bv, b->option );
448
if ( tag == LBER_DEFAULT ) {
449
goto failed;
450
}
451
452
/* store my result */
453
switch (b->choice) {
454
case ChArray:
455
res.ca[n] = bv.bv_val;
456
break;
457
case BvArray:
458
res.ba[n] = bv;
459
break;
460
case BvVec:
461
bvp = ber_memalloc_x( sizeof( struct berval ),
462
ber->ber_memctx );
463
if ( !bvp ) {
464
ber_memfree_x( bv.bv_val, ber->ber_memctx );
465
goto failed;
466
}
467
res.bv[n] = bvp;
468
*bvp = bv;
469
break;
470
case BvOff:
471
*(struct berval *)(res.bo + tot_size) = bv;
472
tot_size += siz;
473
break;
474
}
475
} while (++n < i);
476
return tag;
477
478
failed:
479
if (b->choice != BvOff) { /* BvOff does not have LBER_BV_ALLOC set */
480
while (--n >= 0) {
481
switch(b->choice) {
482
case ChArray:
483
ber_memfree_x(res.ca[n], ber->ber_memctx);
484
break;
485
case BvArray:
486
ber_memfree_x(res.ba[n].bv_val, ber->ber_memctx);
487
break;
488
case BvVec:
489
ber_memfree_x(res.bv[n]->bv_val, ber->ber_memctx);
490
ber_memfree_x(res.bv[n], ber->ber_memctx);
491
break;
492
default:
493
break;
494
}
495
}
496
}
497
ber_memfree_x(b->result, ber->ber_memctx);
498
b->result = NULL;
499
return LBER_DEFAULT;
500
}
501
502
ber_tag_t
503
ber_get_stringbv( BerElement *ber, struct berval *bv, int option )
504
{
505
ber_tag_t tag;
506
char *data;
507
508
tag = ber_skip_element( ber, bv );
509
if ( tag == LBER_DEFAULT ||
510
(( option & LBER_BV_STRING ) &&
511
bv->bv_len && memchr( bv->bv_val, 0, bv->bv_len - 1 )))
512
{
513
bv->bv_val = NULL;
514
return LBER_DEFAULT;
515
}
516
517
data = bv->bv_val;
518
if ( option & LBER_BV_ALLOC ) {
519
bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
520
ber->ber_memctx );
521
if ( bv->bv_val == NULL ) {
522
return LBER_DEFAULT;
523
}
524
525
if ( bv->bv_len != 0 ) {
526
memcpy( bv->bv_val, data, bv->bv_len );
527
}
528
data = bv->bv_val;
529
}
530
if ( !( option & LBER_BV_NOTERM ))
531
data[bv->bv_len] = '\0';
532
533
return tag;
534
}
535
536
ber_tag_t
537
ber_get_stringbv_null( BerElement *ber, struct berval *bv, int option )
538
{
539
ber_tag_t tag;
540
char *data;
541
542
tag = ber_skip_element( ber, bv );
543
if ( tag == LBER_DEFAULT || bv->bv_len == 0 ) {
544
bv->bv_val = NULL;
545
return tag;
546
}
547
548
if (( option & LBER_BV_STRING ) &&
549
memchr( bv->bv_val, 0, bv->bv_len - 1 ))
550
{
551
bv->bv_val = NULL;
552
return LBER_DEFAULT;
553
}
554
555
data = bv->bv_val;
556
if ( option & LBER_BV_ALLOC ) {
557
bv->bv_val = (char *) ber_memalloc_x( bv->bv_len + 1,
558
ber->ber_memctx );
559
if ( bv->bv_val == NULL ) {
560
return LBER_DEFAULT;
561
}
562
563
memcpy( bv->bv_val, data, bv->bv_len );
564
data = bv->bv_val;
565
}
566
if ( !( option & LBER_BV_NOTERM ))
567
data[bv->bv_len] = '\0';
568
569
return tag;
570
}
571
572
ber_tag_t
573
ber_get_stringa( BerElement *ber, char **buf )
574
{
575
BerValue bv;
576
ber_tag_t tag;
577
578
assert( buf != NULL );
579
580
tag = ber_get_stringbv( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING );
581
*buf = bv.bv_val;
582
583
return tag;
584
}
585
586
ber_tag_t
587
ber_get_stringa_null( BerElement *ber, char **buf )
588
{
589
BerValue bv;
590
ber_tag_t tag;
591
592
assert( buf != NULL );
593
594
tag = ber_get_stringbv_null( ber, &bv, LBER_BV_ALLOC | LBER_BV_STRING );
595
*buf = bv.bv_val;
596
597
return tag;
598
}
599
600
ber_tag_t
601
ber_get_stringal( BerElement *ber, struct berval **bv )
602
{
603
ber_tag_t tag;
604
605
assert( ber != NULL );
606
assert( bv != NULL );
607
608
*bv = (struct berval *) ber_memalloc_x( sizeof(struct berval),
609
ber->ber_memctx );
610
if ( *bv == NULL ) {
611
return LBER_DEFAULT;
612
}
613
614
tag = ber_get_stringbv( ber, *bv, LBER_BV_ALLOC );
615
if ( tag == LBER_DEFAULT ) {
616
ber_memfree_x( *bv, ber->ber_memctx );
617
*bv = NULL;
618
}
619
return tag;
620
}
621
622
ber_tag_t
623
ber_get_bitstringa(
624
BerElement *ber,
625
char **buf,
626
ber_len_t *blen )
627
{
628
ber_tag_t tag;
629
struct berval data;
630
unsigned char unusedbits;
631
632
assert( buf != NULL );
633
assert( blen != NULL );
634
635
if ( (tag = ber_skip_element( ber, &data )) == LBER_DEFAULT ) {
636
goto fail;
637
}
638
639
if ( --data.bv_len > (ber_len_t)-1 / 8 ) {
640
goto fail;
641
}
642
unusedbits = *(unsigned char *) data.bv_val++;
643
if ( unusedbits > 7 ) {
644
goto fail;
645
}
646
647
if ( memchr( data.bv_val, 0, data.bv_len )) {
648
goto fail;
649
}
650
651
*buf = (char *) ber_memalloc_x( data.bv_len, ber->ber_memctx );
652
if ( *buf == NULL ) {
653
return LBER_DEFAULT;
654
}
655
memcpy( *buf, data.bv_val, data.bv_len );
656
657
*blen = data.bv_len * 8 - unusedbits;
658
return tag;
659
660
fail:
661
*buf = NULL;
662
return LBER_DEFAULT;
663
}
664
665
ber_tag_t
666
ber_get_null( BerElement *ber )
667
{
668
ber_len_t len;
669
ber_tag_t tag = ber_skip_tag( ber, &len );
670
671
return( len == 0 ? tag : LBER_DEFAULT );
672
}
673
674
ber_tag_t
675
ber_get_boolean(
676
BerElement *ber,
677
ber_int_t *boolval )
678
{
679
return ber_get_int( ber, boolval );
680
}
681
682
ber_tag_t
683
ber_first_element(
684
BerElement *ber,
685
ber_len_t *len,
686
char **last )
687
{
688
assert( last != NULL );
689
690
/* skip the sequence header, use the len to mark where to stop */
691
if ( ber_skip_tag( ber, len ) == LBER_DEFAULT ) {
692
*last = NULL;
693
return LBER_DEFAULT;
694
}
695
696
*last = ber->ber_ptr + *len;
697
698
if ( *len == 0 ) {
699
return LBER_DEFAULT;
700
}
701
702
return ber_peek_tag( ber, len );
703
}
704
705
ber_tag_t
706
ber_next_element(
707
BerElement *ber,
708
ber_len_t *len,
709
LDAP_CONST char *last )
710
{
711
assert( ber != NULL );
712
assert( last != NULL );
713
assert( LBER_VALID( ber ) );
714
715
if ( ber->ber_ptr >= last ) {
716
return LBER_DEFAULT;
717
}
718
719
return ber_peek_tag( ber, len );
720
}
721
722
/* VARARGS */
723
ber_tag_t
724
ber_scanf ( BerElement *ber,
725
LDAP_CONST char *fmt,
726
... )
727
{
728
va_list ap;
729
LDAP_CONST char *fmt_reset;
730
char *s, **ss, ***sss;
731
struct berval data, *bval, **bvp, ***bvpp;
732
ber_int_t *i;
733
ber_len_t *l;
734
ber_tag_t *t;
735
ber_tag_t rc;
736
ber_len_t len;
737
738
va_start( ap, fmt );
739
740
assert( ber != NULL );
741
assert( fmt != NULL );
742
assert( LBER_VALID( ber ) );
743
744
fmt_reset = fmt;
745
746
if ( ber->ber_debug & (LDAP_DEBUG_TRACE|LDAP_DEBUG_BER)) {
747
ber_log_printf( LDAP_DEBUG_TRACE, ber->ber_debug,
748
"ber_scanf fmt (%s) ber:\n", fmt );
749
ber_log_dump( LDAP_DEBUG_BER, ber->ber_debug, ber, 1 );
750
}
751
752
for ( rc = 0; *fmt && rc != LBER_DEFAULT; fmt++ ) {
753
/* When this is modified, remember to update
754
* the error-cleanup code below accordingly. */
755
switch ( *fmt ) {
756
case '!': { /* Hook */
757
BERDecodeCallback *f;
758
void *p;
759
760
f = va_arg( ap, BERDecodeCallback * );
761
p = va_arg( ap, void * );
762
763
rc = (*f)( ber, p, 0 );
764
} break;
765
766
case 'a': /* octet string - allocate storage as needed */
767
ss = va_arg( ap, char ** );
768
rc = ber_get_stringa( ber, ss );
769
break;
770
771
case 'A': /* octet string - allocate storage as needed,
772
* but return NULL if len == 0 */
773
ss = va_arg( ap, char ** );
774
rc = ber_get_stringa_null( ber, ss );
775
break;
776
777
case 'b': /* boolean */
778
i = va_arg( ap, ber_int_t * );
779
rc = ber_get_boolean( ber, i );
780
break;
781
782
case 'B': /* bit string - allocate storage as needed */
783
ss = va_arg( ap, char ** );
784
l = va_arg( ap, ber_len_t * ); /* for length, in bits */
785
rc = ber_get_bitstringa( ber, ss, l );
786
break;
787
788
case 'e': /* enumerated */
789
case 'i': /* integer */
790
i = va_arg( ap, ber_int_t * );
791
rc = ber_get_int( ber, i );
792
break;
793
794
case 'l': /* length of next item */
795
l = va_arg( ap, ber_len_t * );
796
rc = ber_peek_tag( ber, l );
797
break;
798
799
case 'm': /* octet string in berval, in-place */
800
bval = va_arg( ap, struct berval * );
801
rc = ber_get_stringbv( ber, bval, 0 );
802
break;
803
804
case 'M': /* bvoffarray - must include address of
805
* a record len, and record offset.
806
* number of records will be returned thru
807
* len ptr on finish. parsed in-place.
808
*/
809
{
810
bgbvr cookie = { BvOff, 0 };
811
bvp = va_arg( ap, struct berval ** );
812
l = va_arg( ap, ber_len_t * );
813
cookie.siz = *l;
814
cookie.off = va_arg( ap, ber_len_t );
815
rc = ber_get_stringbvl( ber, &cookie );
816
*bvp = cookie.result;
817
*l = cookie.siz;
818
break;
819
}
820
821
case 'n': /* null */
822
rc = ber_get_null( ber );
823
break;
824
825
case 'o': /* octet string in a supplied berval */
826
bval = va_arg( ap, struct berval * );
827
rc = ber_get_stringbv( ber, bval, LBER_BV_ALLOC );
828
break;
829
830
case 'O': /* octet string - allocate & include length */
831
bvp = va_arg( ap, struct berval ** );
832
rc = ber_get_stringal( ber, bvp );
833
break;
834
835
case 's': /* octet string - in a buffer */
836
s = va_arg( ap, char * );
837
l = va_arg( ap, ber_len_t * );
838
rc = ber_get_stringb( ber, s, l );
839
break;
840
841
case 't': /* tag of next item */
842
t = va_arg( ap, ber_tag_t * );
843
*t = rc = ber_peek_tag( ber, &len );
844
break;
845
846
case 'T': /* skip tag of next item */
847
t = va_arg( ap, ber_tag_t * );
848
*t = rc = ber_skip_tag( ber, &len );
849
break;
850
851
case 'v': /* sequence of strings */
852
{
853
bgbvr cookie = {
854
ChArray, LBER_BV_ALLOC | LBER_BV_STRING, sizeof( char * )
855
};
856
rc = ber_get_stringbvl( ber, &cookie );
857
*(va_arg( ap, char *** )) = cookie.result;
858
break;
859
}
860
861
case 'V': /* sequence of strings + lengths */
862
{
863
bgbvr cookie = {
864
BvVec, LBER_BV_ALLOC, sizeof( struct berval * )
865
};
866
rc = ber_get_stringbvl( ber, &cookie );
867
*(va_arg( ap, struct berval *** )) = cookie.result;
868
break;
869
}
870
871
case 'W': /* bvarray */
872
{
873
bgbvr cookie = {
874
BvArray, LBER_BV_ALLOC, sizeof( struct berval )
875
};
876
rc = ber_get_stringbvl( ber, &cookie );
877
*(va_arg( ap, struct berval ** )) = cookie.result;
878
break;
879
}
880
881
case 'x': /* skip the next element - whatever it is */
882
rc = ber_skip_element( ber, &data );
883
break;
884
885
case '{': /* begin sequence */
886
case '[': /* begin set */
887
switch ( fmt[1] ) {
888
case 'v': case 'V': case 'W': case 'M':
889
break;
890
default:
891
rc = ber_skip_tag( ber, &len );
892
break;
893
}
894
break;
895
896
case '}': /* end sequence */
897
case ']': /* end set */
898
break;
899
900
default:
901
if( ber->ber_debug ) {
902
ber_log_printf( LDAP_DEBUG_ANY, ber->ber_debug,
903
"ber_scanf: unknown fmt %c\n", *fmt );
904
}
905
rc = LBER_DEFAULT;
906
break;
907
}
908
}
909
910
va_end( ap );
911
912
if ( rc == LBER_DEFAULT ) {
913
/*
914
* Error. Reclaim malloced memory that was given to the caller.
915
* Set allocated pointers to NULL, "data length" outvalues to 0.
916
*/
917
va_start( ap, fmt );
918
919
for ( ; fmt_reset < fmt; fmt_reset++ ) {
920
switch ( *fmt_reset ) {
921
case '!': { /* Hook */
922
BERDecodeCallback *f;
923
void *p;
924
925
f = va_arg( ap, BERDecodeCallback * );
926
p = va_arg( ap, void * );
927
928
(void) (*f)( ber, p, 1 );
929
} break;
930
931
case 'a': /* octet string - allocate storage as needed */
932
case 'A':
933
ss = va_arg( ap, char ** );
934
ber_memfree_x( *ss, ber->ber_memctx );
935
*ss = NULL;
936
break;
937
938
case 'b': /* boolean */
939
case 'e': /* enumerated */
940
case 'i': /* integer */
941
(void) va_arg( ap, ber_int_t * );
942
break;
943
944
case 'l': /* length of next item */
945
*(va_arg( ap, ber_len_t * )) = 0;
946
break;
947
948
case 'm': /* berval in-place */
949
bval = va_arg( ap, struct berval * );
950
BER_BVZERO( bval );
951
break;
952
953
case 'M': /* BVoff array in-place */
954
bvp = va_arg( ap, struct berval ** );
955
ber_memfree_x( *bvp, ber->ber_memctx );
956
*bvp = NULL;
957
*(va_arg( ap, ber_len_t * )) = 0;
958
(void) va_arg( ap, ber_len_t );
959
break;
960
961
case 'o': /* octet string in a supplied berval */
962
bval = va_arg( ap, struct berval * );
963
ber_memfree_x( bval->bv_val, ber->ber_memctx );
964
BER_BVZERO( bval );
965
break;
966
967
case 'O': /* octet string - allocate & include length */
968
bvp = va_arg( ap, struct berval ** );
969
ber_bvfree_x( *bvp, ber->ber_memctx );
970
*bvp = NULL;
971
break;
972
973
case 's': /* octet string - in a buffer */
974
(void) va_arg( ap, char * );
975
*(va_arg( ap, ber_len_t * )) = 0;
976
break;
977
978
case 't': /* tag of next item */
979
case 'T': /* skip tag of next item */
980
(void) va_arg( ap, ber_tag_t * );
981
break;
982
983
case 'B': /* bit string - allocate storage as needed */
984
ss = va_arg( ap, char ** );
985
ber_memfree_x( *ss, ber->ber_memctx );
986
*ss = NULL;
987
*(va_arg( ap, ber_len_t * )) = 0; /* for length, in bits */
988
break;
989
990
case 'v': /* sequence of strings */
991
sss = va_arg( ap, char *** );
992
ber_memvfree_x( (void **) *sss, ber->ber_memctx );
993
*sss = NULL;
994
break;
995
996
case 'V': /* sequence of strings + lengths */
997
bvpp = va_arg( ap, struct berval *** );
998
ber_bvecfree_x( *bvpp, ber->ber_memctx );
999
*bvpp = NULL;
1000
break;
1001
1002
case 'W': /* BerVarray */
1003
bvp = va_arg( ap, struct berval ** );
1004
ber_bvarray_free_x( *bvp, ber->ber_memctx );
1005
*bvp = NULL;
1006
break;
1007
1008
case 'n': /* null */
1009
case 'x': /* skip the next element - whatever it is */
1010
case '{': /* begin sequence */
1011
case '[': /* begin set */
1012
case '}': /* end sequence */
1013
case ']': /* end set */
1014
break;
1015
1016
default:
1017
/* format should be good */
1018
assert( 0 );
1019
}
1020
}
1021
1022
va_end( ap );
1023
}
1024
1025
return rc;
1026
}
1027
1028