1 /*
2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 /*
6 * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
7 *
8 * The contents of this file are subject to the Netscape Public License
9 * Version 1.0 (the "NPL"); you may not use this file except in
10 * compliance with the NPL. You may obtain a copy of the NPL at
11 * http://www.mozilla.org/NPL/
12 *
13 * Software distributed under the NPL is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
15 * for the specific language governing rights and limitations under the
16 * NPL.
17 *
18 * The Initial Developer of this code under the NPL is Netscape
19 * Communications Corporation. Portions created by Netscape are
20 * Copyright (C) 1998 Netscape Communications Corporation. All Rights
21 * Reserved.
22 */
23
24 /*
25 * Copyright (c) 1990 Regents of the University of Michigan.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms are permitted
29 * provided that this notice is preserved and that due credit is given
30 * to the University of Michigan at Ann Arbor. The name of the University
31 * may not be used to endorse or promote products derived from this
32 * software without specific prior written permission. This software
33 * is provided ``as is'' without express or implied warranty.
34 */
35
36 /* decode.c - ber input decoding routines */
37
38 #include <strings.h>
39 #include <sys/types.h>
40 #include <netinet/in.h>
41 #include <inttypes.h>
42
43 #include <ber_der.h>
44 #include "kmfber_int.h"
45
46 static void
ber_svecfree(char ** vals)47 ber_svecfree(char **vals)
48 {
49 int i;
50
51 if (vals == NULL)
52 return;
53 for (i = 0; vals[i] != NULL; i++)
54 free(vals[i]);
55 free((char *)vals);
56 }
57
58 /*
59 * Note: kmfber_get_tag() only uses the ber_end and ber_ptr elements of ber.
60 * If that changes, the kmfber_peek_tag() and/or
61 * kmfkmfber_skip_tag() implementations will need to be changed.
62 */
63 /* return the tag - KMFBER_DEFAULT returned means trouble */
64 static ber_tag_t
kmfber_get_tag(BerElement * ber)65 kmfber_get_tag(BerElement *ber)
66 {
67 unsigned char xbyte;
68 ber_tag_t tag;
69 char *tagp;
70 int i;
71
72 if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
73 return (KMFBER_DEFAULT);
74
75 if ((xbyte & KMFBER_BIG_TAG_MASK) != KMFBER_BIG_TAG_MASK)
76 return ((ber_uint_t)xbyte);
77
78 tagp = (char *)&tag;
79 tagp[0] = xbyte;
80 for (i = 1; i < sizeof (ber_int_t); i++) {
81 if (kmfber_read(ber, (char *)&xbyte, 1) != 1)
82 return (KMFBER_DEFAULT);
83
84 tagp[i] = xbyte;
85
86 if (! (xbyte & KMFBER_MORE_TAG_MASK))
87 break;
88 }
89
90 /* tag too big! */
91 if (i == sizeof (ber_int_t))
92 return (KMFBER_DEFAULT);
93
94 /* want leading, not trailing 0's */
95 return (tag >> (sizeof (ber_int_t)- i - 1));
96 }
97
98 /*
99 * Note: kmfber_skip_tag() only uses the ber_end and ber_ptr elements of ber.
100 * If that changes, the implementation of kmfber_peek_tag() will need to
101 * be changed.
102 */
103 ber_tag_t
kmfber_skip_tag(BerElement * ber,ber_len_t * len)104 kmfber_skip_tag(BerElement *ber, ber_len_t *len)
105 {
106 ber_tag_t tag;
107 unsigned char lc;
108 int noctets, diff;
109 uint32_t netlen;
110
111 /*
112 * Any ber element looks like this: tag length contents.
113 * Assuming everything's ok, we return the tag byte (we
114 * can assume a single byte), and return the length in len.
115 *
116 * Assumptions:
117 * 1) definite lengths
118 * 2) primitive encodings used whenever possible
119 */
120
121 /*
122 * First, we read the tag.
123 */
124
125 if ((tag = kmfber_get_tag(ber)) == KMFBER_DEFAULT)
126 return (KMFBER_DEFAULT);
127
128 /*
129 * Next, read the length. The first byte contains the length of
130 * the length. If bit 8 is set, the length is the long form,
131 * otherwise it's the short form. We don't allow a length that's
132 * greater than what we can hold in an unsigned long.
133 */
134
135 *len = 0;
136 netlen = 0;
137 if (kmfber_read(ber, (char *)&lc, 1) != 1)
138 return (KMFBER_DEFAULT);
139 if (lc & 0x80) {
140 noctets = (lc & 0x7f);
141 if (noctets > sizeof (ber_uint_t))
142 return (KMFBER_DEFAULT);
143 diff = sizeof (ber_int_t) - noctets;
144 if (kmfber_read(ber, (char *)&netlen + diff, noctets)
145 != noctets)
146 return (KMFBER_DEFAULT);
147 *len = ntohl(netlen);
148 } else {
149 *len = lc;
150 }
151
152 return (tag);
153 }
154
155
156 /*
157 * Note: Previously, we passed the "ber" parameter directly to
158 * kmfber_skip_tag(), saving and restoring the ber_ptr element only.
159 * We now take advantage of the fact that the only ber structure
160 * elements touched by kmfber_skip_tag() are ber_end and ber_ptr.
161 * If that changes, this code must change too.
162 */
163 static ber_tag_t
kmfber_peek_tag(BerElement * ber,ber_len_t * len)164 kmfber_peek_tag(BerElement *ber, ber_len_t *len)
165 {
166 BerElement bercopy;
167
168 bercopy.ber_end = ber->ber_end;
169 bercopy.ber_ptr = ber->ber_ptr;
170 return (kmfber_skip_tag(&bercopy, len));
171 }
172
173 static int
ber_getnint(BerElement * ber,ber_int_t * num,ber_slen_t len)174 ber_getnint(BerElement *ber, ber_int_t *num, ber_slen_t len)
175 {
176 int i;
177 ber_int_t value;
178 unsigned char buffer[sizeof (ber_int_t)];
179 /*
180 * The tag and length have already been stripped off. We should
181 * be sitting right before len bytes of 2's complement integer,
182 * ready to be read straight into an int. We may have to sign
183 * extend after we read it in.
184 */
185
186 if (len > sizeof (buffer))
187 return (-1);
188
189 /* read into the low-order bytes of netnum */
190 if (kmfber_read(ber, (char *)buffer, len) != len)
191 return (-1);
192
193 /* This sets the required sign extension */
194 if (len != 0) {
195 value = 0x80 & buffer[0] ? (-1) : 0;
196 } else {
197 value = 0;
198 }
199
200 for (i = 0; i < len; i++)
201 value = (value << 8) | buffer[i];
202
203 *num = value;
204
205 return (len);
206 }
207
208 static ber_tag_t
kmfber_get_int(BerElement * ber,ber_int_t * num)209 kmfber_get_int(BerElement *ber, ber_int_t *num)
210 {
211 ber_tag_t tag;
212 ber_len_t len;
213
214 if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
215 return (KMFBER_DEFAULT);
216
217 /*
218 * len is being demoted to a long here -- possible conversion error
219 */
220
221 if (ber_getnint(ber, num, (int)len) != (ber_slen_t)len)
222 return (KMFBER_DEFAULT);
223 else
224 return (tag);
225 }
226
227 static ber_tag_t
kmfber_get_stringb(BerElement * ber,char * buf,ber_len_t * len)228 kmfber_get_stringb(BerElement *ber, char *buf, ber_len_t *len)
229 {
230 ber_len_t datalen;
231 ber_tag_t tag;
232 #ifdef STR_TRANSLATION
233 char *transbuf;
234 #endif /* STR_TRANSLATION */
235
236 if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
237 return (KMFBER_DEFAULT);
238 if (datalen > (*len - 1))
239 return (KMFBER_DEFAULT);
240
241 /*
242 * datalen is being demoted to a long here -- possible conversion error
243 */
244
245 if (kmfber_read(ber, buf, datalen) != (ber_slen_t)datalen)
246 return (KMFBER_DEFAULT);
247
248 buf[datalen] = '\0';
249
250 #ifdef STR_TRANSLATION
251 if (datalen > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS)
252 != 0 && ber->ber_decode_translate_proc != NULL) {
253
254 transbuf = buf;
255 ++datalen;
256 if ((*(ber->ber_decode_translate_proc))(&transbuf, &datalen,
257 0) != 0) {
258 return (KMFBER_DEFAULT);
259 }
260 if (datalen > *len) {
261 free(transbuf);
262 return (KMFBER_DEFAULT);
263 }
264 (void) memmove(buf, transbuf, datalen);
265 free(transbuf);
266 --datalen;
267 }
268 #endif /* STR_TRANSLATION */
269
270 *len = datalen;
271 return (tag);
272 }
273
274 static ber_tag_t
kmfber_get_stringa(BerElement * ber,char ** buf)275 kmfber_get_stringa(BerElement *ber, char **buf)
276 {
277 ber_len_t datalen;
278 ber_tag_t tag;
279
280 if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
281 return (KMFBER_DEFAULT);
282
283 if ((*buf = (char *)malloc((size_t)datalen + 1)) == NULL)
284 return (KMFBER_DEFAULT);
285
286 /*
287 * datalen is being demoted to a long here -- possible conversion error
288 */
289 if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
290 return (KMFBER_DEFAULT);
291 (*buf)[datalen] = '\0';
292
293 return (tag);
294 }
295
296 ber_tag_t
ber_get_oid(BerElement * ber,struct berval * oid)297 ber_get_oid(BerElement *ber, struct berval *oid)
298 {
299 ber_len_t len;
300 ber_tag_t tag;
301
302 if ((tag = kmfber_skip_tag(ber, &len)) != 0x06) {
303 return (KMFBER_DEFAULT);
304 }
305
306 if ((oid->bv_val = (char *)malloc((size_t)len + 1)) == NULL) {
307 return (KMFBER_DEFAULT);
308 }
309 oid->bv_len = len;
310
311 if (kmfber_read(ber, oid->bv_val, oid->bv_len) !=
312 (ber_slen_t)oid->bv_len)
313 return (KMFBER_DEFAULT);
314
315 return (tag);
316 }
317
318 ber_tag_t
ber_get_bigint(BerElement * ber,struct berval ** bv)319 ber_get_bigint(BerElement *ber, struct berval **bv)
320 {
321 ber_len_t len;
322 ber_tag_t tag;
323
324 if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
325 == NULL) {
326 return (KMFBER_DEFAULT);
327 }
328 (*bv)->bv_len = 0;
329 (*bv)->bv_val = NULL;
330
331 if ((tag = kmfber_skip_tag(ber, &len)) != BER_INTEGER) {
332 return (KMFBER_DEFAULT);
333 }
334
335 if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
336 == NULL) {
337 return (KMFBER_DEFAULT);
338 }
339
340 /*
341 * len is being demoted to a long here -- possible conversion error
342 */
343 if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
344 return (KMFBER_DEFAULT);
345
346 (*bv)->bv_len = len;
347
348 /* If DER encoding, strip leading 0's if high-order bit is set */
349 if (ber->ber_options & KMFBER_OPT_USE_DER) {
350 char *p = (*bv)->bv_val;
351 while ((*p == 0x00) && ((*bv)->bv_len > 0) && (p[1] & 0x80)) {
352 p++;
353 (*bv)->bv_len--;
354 }
355 /*
356 * Shift the buffer to the beginning of the allocated space
357 * so it can be properly freed later.
358 */
359 if ((p > (*bv)->bv_val) && ((*bv)->bv_len > 0))
360 (void) bcopy(p, (*bv)->bv_val, (*bv)->bv_len);
361 }
362
363 return (tag);
364 }
365
366 static ber_tag_t
kmfber_get_stringal(BerElement * ber,struct berval ** bv)367 kmfber_get_stringal(BerElement *ber, struct berval **bv)
368 {
369 ber_len_t len;
370 ber_tag_t tag;
371
372 if ((*bv = (struct berval *)malloc(sizeof (struct berval)))
373 == NULL) {
374 return (KMFBER_DEFAULT);
375 }
376
377 if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT) {
378 return (KMFBER_DEFAULT);
379 }
380
381 if (((*bv)->bv_val = (char *)malloc((size_t)len + 1))
382 == NULL) {
383 return (KMFBER_DEFAULT);
384 }
385
386 /*
387 * len is being demoted to a long here -- possible conversion error
388 */
389 if (kmfber_read(ber, (*bv)->bv_val, len) != (ber_slen_t)len)
390 return (KMFBER_DEFAULT);
391 ((*bv)->bv_val)[len] = '\0';
392 (*bv)->bv_len = len;
393
394 return (tag);
395 }
396
397 static ber_tag_t
kmfber_get_bitstringa(BerElement * ber,char ** buf,ber_len_t * blen)398 kmfber_get_bitstringa(BerElement *ber, char **buf, ber_len_t *blen)
399 {
400 ber_len_t datalen;
401 ber_tag_t tag;
402 unsigned char unusedbits;
403
404 if ((tag = kmfber_skip_tag(ber, &datalen)) == KMFBER_DEFAULT)
405 return (KMFBER_DEFAULT);
406
407 if ((*buf = (char *)malloc((size_t)datalen - 1)) == NULL)
408 return (KMFBER_DEFAULT);
409
410 if (kmfber_read(ber, (char *)&unusedbits, 1) != 1)
411 return (KMFBER_DEFAULT);
412
413 /* Subtract 1 for the unused bits */
414 datalen--;
415
416 /*
417 * datalen is being demoted to a long here -- possible conversion error
418 */
419 if (kmfber_read(ber, *buf, datalen) != (ber_slen_t)datalen)
420 return (KMFBER_DEFAULT);
421
422 *blen = datalen * 8 - unusedbits;
423 return (tag);
424 }
425
426 static ber_tag_t
kmfber_get_null(BerElement * ber)427 kmfber_get_null(BerElement *ber)
428 {
429 ber_len_t len;
430 ber_tag_t tag;
431
432 if ((tag = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
433 return (KMFBER_DEFAULT);
434
435 if (len != 0)
436 return (KMFBER_DEFAULT);
437
438 return (tag);
439 }
440
441 static ber_tag_t
kmfber_get_boolean(BerElement * ber,int * boolval)442 kmfber_get_boolean(BerElement *ber, int *boolval)
443 {
444 ber_int_t longbool;
445 int rc;
446
447 rc = kmfber_get_int(ber, &longbool);
448 *boolval = longbool;
449
450 return (rc);
451 }
452
453 ber_tag_t
kmfber_first_element(BerElement * ber,ber_len_t * len,char ** last)454 kmfber_first_element(BerElement *ber, ber_len_t *len, char **last)
455 {
456 /* skip the sequence header, use the len to mark where to stop */
457 if (kmfber_skip_tag(ber, len) == KMFBER_DEFAULT) {
458 return (KMFBER_ERROR);
459 }
460
461 *last = ber->ber_ptr + *len;
462
463 if (*last == ber->ber_ptr) {
464 return (KMFBER_END_OF_SEQORSET);
465 }
466
467 return (kmfber_peek_tag(ber, len));
468 }
469
470 ber_tag_t
kmfber_next_element(BerElement * ber,ber_len_t * len,char * last)471 kmfber_next_element(BerElement *ber, ber_len_t *len, char *last)
472 {
473 if (ber->ber_ptr == last) {
474 return (KMFBER_END_OF_SEQORSET);
475 }
476
477 return (kmfber_peek_tag(ber, len));
478 }
479
480 void
kmfber_bvfree(struct berval * bv)481 kmfber_bvfree(struct berval *bv)
482 {
483 if (bv != NULL) {
484 if (bv->bv_val != NULL) {
485 free(bv->bv_val);
486 }
487 free((char *)bv);
488 }
489 }
490
491 void
kmfber_bvecfree(struct berval ** bv)492 kmfber_bvecfree(struct berval **bv)
493 {
494 int i;
495
496 if (bv != NULL) {
497 for (i = 0; bv[i] != NULL; i++) {
498 kmfber_bvfree(bv[i]);
499 }
500 free((char *)bv);
501 }
502 }
503
504 /* VARARGS */
505 ber_tag_t
kmfber_scanf(BerElement * ber,const char * fmt,...)506 kmfber_scanf(BerElement *ber, const char *fmt, ...)
507 {
508 va_list ap;
509 char *last, *p;
510 char *s, **ss, ***sss;
511 struct berval ***bv, **bvp, *bval;
512 int *i, j;
513 ber_slen_t *l;
514 ber_int_t rc, tag, *b_int;
515 ber_tag_t *t;
516 ber_len_t len;
517 size_t array_size;
518
519 va_start(ap, fmt);
520
521 for (rc = 0, p = (char *)fmt; *p && rc != KMFBER_DEFAULT; p++) {
522 switch (*p) {
523 case 'a': /* octet string - allocate storage as needed */
524 ss = va_arg(ap, char **);
525 rc = kmfber_get_stringa(ber, ss);
526 break;
527
528 case 'b': /* boolean */
529 i = va_arg(ap, int *);
530 rc = kmfber_get_boolean(ber, i);
531 break;
532
533 case 'D': /* Object ID */
534 bval = va_arg(ap, struct berval *);
535 rc = ber_get_oid(ber, bval);
536 break;
537 case 'e': /* enumerated */
538 case 'i': /* int */
539 b_int = va_arg(ap, ber_int_t *);
540 rc = kmfber_get_int(ber, b_int);
541 break;
542
543 case 'l': /* length of next item */
544 l = va_arg(ap, ber_slen_t *);
545 rc = kmfber_peek_tag(ber, (ber_len_t *)l);
546 break;
547
548 case 'n': /* null */
549 rc = kmfber_get_null(ber);
550 break;
551
552 case 's': /* octet string - in a buffer */
553 s = va_arg(ap, char *);
554 l = va_arg(ap, ber_slen_t *);
555 rc = kmfber_get_stringb(ber, s, (ber_len_t *)l);
556 break;
557
558 case 'o': /* octet string in a supplied berval */
559 bval = va_arg(ap, struct berval *);
560 (void) kmfber_peek_tag(ber, &bval->bv_len);
561 rc = kmfber_get_stringa(ber, &bval->bv_val);
562 break;
563
564 case 'I': /* variable length Integer */
565 /* Treat INTEGER same as an OCTET string, but ignore the tag */
566 bvp = va_arg(ap, struct berval **);
567 rc = ber_get_bigint(ber, bvp);
568 break;
569 case 'O': /* octet string - allocate & include length */
570 bvp = va_arg(ap, struct berval **);
571 rc = kmfber_get_stringal(ber, bvp);
572 break;
573
574 case 'B': /* bit string - allocate storage as needed */
575 ss = va_arg(ap, char **);
576 l = va_arg(ap, ber_slen_t *); /* for length, in bits */
577 rc = kmfber_get_bitstringa(ber, ss, (ber_len_t *)l);
578 break;
579
580 case 't': /* tag of next item */
581 t = va_arg(ap, ber_tag_t *);
582 *t = kmfber_peek_tag(ber, &len);
583 rc = (ber_int_t)(*t);
584 break;
585
586 case 'T': /* skip tag of next item */
587 t = va_arg(ap, ber_tag_t *);
588 *t = kmfber_skip_tag(ber, &len);
589 rc = (ber_int_t)(*t);
590 break;
591
592 case 'v': /* sequence of strings */
593 sss = va_arg(ap, char ***);
594 if (sss == NULL)
595 break;
596 *sss = NULL;
597 j = 0;
598 array_size = 0;
599 for (tag = kmfber_first_element(ber, &len, &last);
600 (tag != KMFBER_DEFAULT &&
601 tag != KMFBER_END_OF_SEQORSET &&
602 rc != KMFBER_DEFAULT);
603 tag = kmfber_next_element(ber, &len, last)) {
604 if (*sss == NULL) {
605 /* Make room for at least 15 strings */
606 *sss = (char **)malloc(16 * sizeof (char *));
607 array_size = 16;
608 } else {
609 if ((size_t)(j+2) > array_size) {
610 /* We'v overflowed our buffer */
611 *sss = (char **)realloc(*sss,
612 (array_size * 2) * sizeof (char *));
613 array_size = array_size * 2;
614 }
615 }
616 rc = kmfber_get_stringa(ber, &((*sss)[j]));
617 j++;
618 }
619 if (rc != KMFBER_DEFAULT && tag != KMFBER_END_OF_SEQORSET) {
620 rc = KMFBER_DEFAULT;
621 }
622 if (j > 0)
623 (*sss)[j] = NULL;
624 break;
625
626 case 'V': /* sequence of strings + lengths */
627 bv = va_arg(ap, struct berval ***);
628 *bv = NULL;
629 j = 0;
630 for (tag = kmfber_first_element(ber, &len, &last);
631 (tag != KMFBER_DEFAULT &&
632 tag != KMFBER_END_OF_SEQORSET &&
633 rc != KMFBER_DEFAULT);
634 tag = kmfber_next_element(ber, &len, last)) {
635 if (*bv == NULL) {
636 *bv = (struct berval **)malloc(
637 2 * sizeof (struct berval *));
638 } else {
639 *bv = (struct berval **)realloc(*bv,
640 (j + 2) * sizeof (struct berval *));
641 }
642 rc = kmfber_get_stringal(ber, &((*bv)[j]));
643 j++;
644 }
645 if (rc != KMFBER_DEFAULT &&
646 tag != KMFBER_END_OF_SEQORSET) {
647 rc = KMFBER_DEFAULT;
648 }
649 if (j > 0)
650 (*bv)[j] = NULL;
651 break;
652
653 case 'x': /* skip the next element - whatever it is */
654 if ((rc = kmfber_skip_tag(ber, &len)) == KMFBER_DEFAULT)
655 break;
656 ber->ber_ptr += len;
657 break;
658
659 case '{': /* begin sequence */
660 case '[': /* begin set */
661 if (*(p + 1) != 'v' && *(p + 1) != 'V')
662 rc = kmfber_skip_tag(ber, &len);
663 break;
664
665 case '}': /* end sequence */
666 case ']': /* end set */
667 break;
668
669 default:
670 rc = KMFBER_DEFAULT;
671 break;
672 }
673 }
674
675
676 va_end(ap);
677 if (rc == KMFBER_DEFAULT) {
678 va_start(ap, fmt);
679 for (p--; fmt < p && *fmt; fmt++) {
680 switch (*fmt) {
681 case 'a': /* octet string - allocate storage as needed */
682 ss = va_arg(ap, char **);
683 if (ss != NULL && *ss != NULL) {
684 free(*ss);
685 *ss = NULL;
686 }
687 break;
688
689 case 'b': /* boolean */
690 i = va_arg(ap, int *);
691 break;
692
693 case 'e': /* enumerated */
694 case 'i': /* int */
695 l = va_arg(ap, ber_slen_t *);
696 break;
697
698 case 'l': /* length of next item */
699 l = va_arg(ap, ber_slen_t *);
700 break;
701
702 case 'n': /* null */
703 break;
704
705 case 's': /* octet string - in a buffer */
706 s = va_arg(ap, char *);
707 l = va_arg(ap, ber_slen_t *);
708 break;
709
710 case 'o': /* octet string in a supplied berval */
711 bval = va_arg(ap, struct berval *);
712 if (bval->bv_val) free(bval->bv_val);
713 (void) memset(bval, 0, sizeof (struct berval));
714 break;
715
716 case 'O': /* octet string - allocate & include length */
717 bvp = va_arg(ap, struct berval **);
718 kmfber_bvfree(*bvp);
719 bvp = NULL;
720 break;
721
722 case 'B': /* bit string - allocate storage as needed */
723 ss = va_arg(ap, char **);
724 l = va_arg(ap, ber_slen_t *); /* for length, in bits */
725 if (ss != NULL && *ss != NULL) {
726 free(*ss);
727 *ss = NULL;
728 }
729 break;
730
731 case 't': /* tag of next item */
732 t = va_arg(ap, ber_tag_t *);
733 break;
734 case 'T': /* skip tag of next item */
735 t = va_arg(ap, ber_tag_t *);
736 break;
737
738 case 'v': /* sequence of strings */
739 sss = va_arg(ap, char ***);
740 if (sss != NULL && *sss != NULL) {
741 ber_svecfree(*sss);
742 *sss = NULL;
743 }
744 break;
745
746 case 'V': /* sequence of strings + lengths */
747 bv = va_arg(ap, struct berval ***);
748 kmfber_bvecfree(*bv);
749 *bv = NULL;
750 break;
751
752 case 'x': /* skip the next element - whatever it is */
753 break;
754
755 case '{': /* begin sequence */
756 case '[': /* begin set */
757 break;
758
759 case '}': /* end sequence */
760 case ']': /* end set */
761 break;
762
763 default:
764 break;
765 }
766 } /* for */
767 va_end(ap);
768 } /* if */
769
770 return (rc);
771 }
772
773 struct berval *
kmfber_bvdup(const struct berval * bv)774 kmfber_bvdup(const struct berval *bv)
775 {
776 struct berval *new;
777
778 if ((new = (struct berval *)malloc(sizeof (struct berval)))
779 == NULL) {
780 return (NULL);
781 }
782 if (bv->bv_val == NULL) {
783 new->bv_val = NULL;
784 new->bv_len = 0;
785 } else {
786 if ((new->bv_val = (char *)malloc(bv->bv_len + 1))
787 == NULL) {
788 return (NULL);
789 }
790 (void) memmove(new->bv_val, bv->bv_val, (size_t)bv->bv_len);
791 new->bv_val[bv->bv_len] = '\0';
792 new->bv_len = bv->bv_len;
793 }
794
795 return (new);
796 }
797