Coverage Report

Created: 2026-07-16 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/asn1.c
Line
Count
Source
1
/*
2
 * Abstract Syntax Notation One, ASN.1
3
 * As defined in ISO/IS 8824 and ISO/IS 8825
4
 * This implements a subset of the above International Standards that
5
 * is sufficient to implement SNMP.
6
 *
7
 * Encodes abstract data types into a machine independent stream of bytes.
8
 *
9
 * Portions of this file are subject to the following copyright(s).  See
10
 * the Net-SNMP's COPYING file for more details and other copyrights
11
 * that may apply:
12
 *
13
 * Portions of this file are copyrighted by:
14
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
15
 * Use is subject to license terms specified in the COPYING file
16
 * distributed with the Net-SNMP package.
17
 */
18
/**********************************************************************
19
  Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
20
21
                      All Rights Reserved
22
23
Permission to use, copy, modify, and distribute this software and its 
24
documentation for any purpose and without fee is hereby granted, 
25
provided that the above copyright notice appear in all copies and that
26
both that copyright notice and this permission notice appear in 
27
supporting documentation, and that the name of CMU not be
28
used in advertising or publicity pertaining to distribution of the
29
software without specific, written prior permission.  
30
31
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
32
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
33
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
34
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
35
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
36
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37
SOFTWARE.
38
******************************************************************/
39
/**
40
 * @defgroup asn1_packet_parse asn1 parsing and datatype manipulation routines.
41
 * @ingroup library
42
 *
43
 * @{
44
 * 
45
 * Note on 
46
 * 
47
 * Re-allocating reverse ASN.1 encoder functions.  Synopsis:
48
 *
49
 * \code
50
 *
51
 * u_char *buf = (u_char*)malloc(100);
52
 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
53
 * size_t buf_len = 100, offset = 0;
54
 * long data = 12345;
55
 * int allow_realloc = 1;
56
 * 
57
 * if (asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
58
 *                            type, &data, sizeof(long)) == 0) {
59
 *     error;
60
 * }
61
 * 
62
 * \endcode
63
 *
64
 * NOTE WELL: after calling one of these functions with allow_realloc
65
 * non-zero, buf might have moved, buf_len might have grown and
66
 * offset will have increased by the size of the encoded data.
67
 * You should **NEVER** do something like this:
68
 * 
69
 * \code
70
 *
71
 * u_char *buf = (u_char *)malloc(100), *ptr;
72
 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
73
 * size_t buf_len = 100, offset = 0;
74
 * long data1 = 1234, data2 = 5678;
75
 * int rc = 0, allow_realloc = 1;
76
 * 
77
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
78
 *                                type, &data1, sizeof(long));
79
 * ptr = buf[buf_len - offset];   / * points at encoding of data1 * /
80
 * if (rc == 0) {
81
 *      error;
82
 * }
83
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
84
 *                              type, &data2, sizeof(long));
85
 * make use of ptr here;
86
 * 
87
 * \endcode
88
 * 
89
 * ptr is **INVALID** at this point.  In general, you should store the
90
 * offset value and compute pointers when you need them:
91
 * 
92
 * 
93
 * \code
94
 *
95
 * u_char *buf = (u_char *)malloc(100), *ptr;
96
 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
97
 * size_t buf_len = 100, offset = 0, ptr_offset;
98
 * long data1 = 1234, data2 = 5678;
99
 * int rc = 0, allow_realloc = 1;
100
 * 
101
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
102
 *                              type, &data1, sizeof(long));
103
 * ptr_offset = offset;
104
 * if (rc == 0) {
105
 *      error;
106
 * }
107
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
108
 *                              type, &data2, sizeof(long));
109
 * ptr = buf + buf_len - ptr_offset
110
 * make use of ptr here;
111
 * 
112
 * \endcode
113
 * 
114
 * 
115
 * Here, you can see that ptr will be a valid pointer even if the block of
116
 * memory has been moved, as it may well have been.  Plenty of examples of
117
 * usage all over asn1.c, snmp_api.c, snmpusm.c.
118
 * 
119
 * The other thing you should **NEVER** do is to pass a pointer to a buffer
120
 * on the stack as the first argument when allow_realloc is non-zero, unless
121
 * you really know what you are doing and your machine/compiler allows you to
122
 * free non-heap memory.  There are rumours that such things exist, but many
123
 * consider them no more than the wild tales of a fool.
124
 * 
125
 * Of course, you can pass allow_realloc as zero, to indicate that you do not
126
 * wish the packet buffer to be reallocated for some reason; perhaps because
127
 * it is on the stack.  This may be useful to emulate the functionality of
128
 * the old API:
129
 *
130
 * \code 
131
 * 
132
 * u_char my_static_buffer[100], *cp = NULL;
133
 * size_t my_static_buffer_len = 100;
134
 * float my_pi = (float)22/(float)7;
135
 * 
136
 * cp = asn_rbuild_float(my_static_buffer, &my_static_buffer_len,
137
 *                       ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
138
 * if (cp == NULL) {
139
 * error;
140
 * }
141
 * 
142
 * \endcode
143
 * 
144
 * IS EQUIVALENT TO:
145
 * 
146
 * \code
147
 * 
148
 * u_char my_static_buffer[100];
149
 * size_t my_static_buffer_len = 100, my_offset = 0;
150
 * float my_pi = (float)22/(float)7;
151
 * int rc = 0;
152
 * 
153
 * rc = asn_realloc_rbuild_float(&my_static_buffer, &my_static_buffer_len,
154
 *                               &my_offset, 0,
155
 *                               ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
156
 * if (rc == 0) {
157
 *   error;
158
 * }
159
 * \endcode
160
 * 
161
 */
162
163
164
#include <net-snmp/net-snmp-config.h>
165
166
#ifdef KINETICS
167
#include "gw.h"
168
#endif
169
170
#ifdef HAVE_STRING_H
171
#include <string.h>
172
#else
173
#include <strings.h>
174
#endif
175
176
#include <sys/types.h>
177
#include <stdio.h>
178
#ifdef HAVE_STDINT_H
179
#include <stdint.h>
180
#endif
181
#ifdef HAVE_STDLIB_H
182
#include <stdlib.h>
183
#endif
184
#ifdef HAVE_NETINET_IN_H
185
#include <netinet/in.h>
186
#endif
187
188
#ifdef vms
189
#include <in.h>
190
#endif
191
192
#include <net-snmp/output_api.h>
193
#include <net-snmp/utilities.h>
194
195
#include <net-snmp/library/asn1.h>
196
#include <net-snmp/library/int64.h>
197
#include <net-snmp/library/mib.h>
198
199
#ifndef NULL
200
#define NULL  0
201
#endif
202
203
#include <net-snmp/library/snmp_api.h>
204
205
#ifndef INT32_MAX
206
#   define INT32_MAX 2147483647
207
#endif
208
209
#ifndef INT32_MIN
210
#   define INT32_MIN (0 - INT32_MAX - 1)
211
#endif
212
213
214
10.8k
#define CHECK_OVERFLOW_S(x,y) do {                                      \
215
10.8k
        if (x > INT32_MAX) {                                            \
216
416
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
217
416
            x &= 0xffffffff;                                            \
218
10.4k
        } else if (x < INT32_MIN) {                                     \
219
83
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
220
83
            x = 0 - (x & 0xffffffff);                                   \
221
83
        }                                                               \
222
10.8k
    } while(0)
223
224
698
#define CHECK_OVERFLOW_U(x,y) do {                                      \
225
698
        if (x > UINT32_MAX) {                                           \
226
45
            x &= 0xffffffff;                                            \
227
45
            DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
228
45
        }                                                               \
229
698
    } while(0)
230
231
/**
232
 * @internal
233
 * output an error for a wrong size
234
 * 
235
 * @param str        error string
236
 * @param wrongsize  wrong size
237
 * @param rightsize  expected size
238
 */
239
static
240
    void
241
_asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
242
15
{
243
15
    char            ebuf[128];
244
245
15
    snprintf(ebuf, sizeof(ebuf),
246
15
            "%s size %lu: s/b %lu", str,
247
15
      (unsigned long)wrongsize, (unsigned long)rightsize);
248
15
    ERROR_MSG(ebuf);
249
15
}
250
251
/**
252
 * @internal
253
 * output an error for a wrong type
254
 * 
255
 * @param str        error string
256
 * @param wrongtype  wrong type
257
 */
258
static
259
    void
260
_asn_type_err(const char *str, int wrongtype)
261
1.03k
{
262
1.03k
    char            ebuf[128];
263
264
1.03k
    snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
265
1.03k
    ebuf[ sizeof(ebuf)-1 ] = 0;
266
1.03k
    ERROR_MSG(ebuf);
267
1.03k
}
268
269
/**
270
 * @internal 
271
 * output an error for a wrong length
272
 * 
273
 * @param str        error string
274
 * @param wrongsize  wrong  length
275
 * @param rightsize  expected length
276
 */
277
static
278
    void
279
_asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
280
189
{
281
189
    char            ebuf[128];
282
283
189
    snprintf(ebuf, sizeof(ebuf),
284
189
            "%s length %lu too large: exceeds %lu", str,
285
189
      (unsigned long)wrongsize, (unsigned long)rightsize);
286
189
    ERROR_MSG(ebuf);
287
189
}
288
289
/**
290
 * @internal
291
 * output an error for a wrong length
292
 *
293
 * @param str        error string
294
 * @param wrongsize  wrong  length
295
 * @param rightsize  expected length
296
 */
297
static void
298
_asn_short_err(const char *str, size_t wrongsize, size_t rightsize)
299
4.99k
{
300
4.99k
    char            ebuf[128];
301
302
4.99k
    snprintf(ebuf, sizeof(ebuf), "%s length %lu too short: need %lu", str,
303
4.99k
      (unsigned long)wrongsize, (unsigned long)rightsize);
304
4.99k
    ERROR_MSG(ebuf);
305
4.99k
}
306
307
/**
308
 * @internal
309
 * checks a buffer with a length + data to see if it is big enough for
310
 *    the length encoding and the data of the parsed length.
311
 *
312
 * @param IN  pkt      The buffer
313
 * @param IN  pkt_len  The length of the bugger
314
 * @param OUT data_len Pointer to size of data
315
 *
316
 * @return Pointer to start of data or NULL if pkt isn't long enough
317
 *
318
 * pkt = get_buf(..., &pkt_len);
319
 * data = asn_parse_nlength(pkt, pkt_len, &data_len);
320
 * if (NULL == data) { handle_error(); }
321
 *
322
 */
323
u_char *
324
asn_parse_nlength(u_char *pkt, size_t pkt_len, u_long *data_len)
325
38.0k
{
326
38.0k
    int len_len;
327
328
38.0k
    if (pkt_len < 1)
329
0
        return NULL;               /* always too short */
330
331
38.0k
    if (NULL == pkt || NULL == data_len)
332
0
        return NULL;
333
334
38.0k
    *data_len = 0;
335
336
38.0k
    if (*pkt & 0x80) {
337
        /*
338
         * long length; first byte is length of length (after masking high bit)
339
         */
340
2.14k
        len_len = (int) ((*pkt & ~0x80) + 1);
341
2.14k
        if (pkt_len < len_len)
342
498
            return NULL;           /* still too short for length and data */
343
344
        /* now we know we have enough data to parse length */
345
1.65k
        if (NULL == asn_parse_length(pkt, data_len))
346
209
            return NULL;           /* propagate error from asn_parse_length */
347
35.9k
    } else {
348
        /*
349
         * short length; first byte is the length
350
         */
351
35.9k
        len_len = 1;
352
35.9k
        *data_len = *pkt;
353
35.9k
    }
354
355
37.3k
    if ((*data_len + len_len) > pkt_len)
356
2.40k
        return NULL;
357
358
34.9k
    return (pkt + len_len);
359
37.3k
}
360
361
#if 0
362
/**
363
 * @internal
364
 * call after asn_parse_length to verify result.
365
 * 
366
 * @param str  error string
367
 * @param bufp start of buffer
368
 * @param data start of data
369
 * @param plen  ? parsed length
370
 * @param dlen  ? data/buf length
371
 * 
372
 * @return 1 on error 0 on success
373
 */
374
static
375
    int
376
_asn_parse_length_check(const char *str,
377
                        const u_char * bufp, const u_char * data,
378
                        u_long plen, size_t dlen)
379
{
380
    char            ebuf[128];
381
    size_t          header_len;
382
383
    if (bufp == NULL) {
384
        /*
385
         * error message is set 
386
         */
387
        return 1;
388
    }
389
    header_len = bufp - data;
390
    if (plen > SNMP_MAX_PACKET_LEN || header_len > SNMP_MAX_PACKET_LEN ||
391
        ((size_t) plen + header_len) > dlen) {
392
        snprintf(ebuf, sizeof(ebuf),
393
                "%s: message overflow: %d len + %d delta > %d len",
394
                str, (int) plen, (int) header_len, (int) dlen);
395
        ERROR_MSG(ebuf);
396
        return 1;
397
    }
398
    return 0;
399
}
400
#endif
401
402
403
/**
404
 * @internal 
405
 * call after asn_build_header to verify result.
406
 * 
407
 * @param str     error string to output
408
 * @param data    data pointer to verify (NULL => error )
409
 * @param datalen  data len to check
410
 * @param typedlen  type length
411
 * 
412
 * @return 0 on success, 1 on error
413
 */
414
static
415
    int
416
_asn_build_header_check(const char *str, const u_char * data,
417
                        size_t datalen, size_t typedlen)
418
0
{
419
0
    char            ebuf[128];
420
421
0
    if (data == NULL) {
422
        /*
423
         * error message is set 
424
         */
425
0
        return 1;
426
0
    }
427
0
    if (datalen < typedlen) {
428
0
        snprintf(ebuf, sizeof(ebuf),
429
0
                "%s: bad header, length too short: %lu < %lu", str,
430
0
                (unsigned long)datalen, (unsigned long)typedlen);
431
0
        ERROR_MSG(ebuf);
432
0
        return 1;
433
0
    }
434
0
    return 0;
435
0
}
436
437
/**
438
 * @internal 
439
 * call after asn_build_header to verify result.
440
 * 
441
 * @param str       error string
442
 * @param pkt       packet to check
443
 * @param pkt_len  length of the packet
444
 * @param typedlen length of the type
445
 * 
446
 * @return 0 on success 1 on error 
447
 */
448
static
449
    int
450
_asn_realloc_build_header_check(const char *str,
451
                                u_char ** pkt,
452
                                const size_t * pkt_len, size_t typedlen)
453
0
{
454
0
    char            ebuf[128];
455
456
0
    if (pkt == NULL || *pkt == NULL) {
457
        /*
458
         * Error message is set.  
459
         */
460
0
        return 1;
461
0
    }
462
463
0
    if (*pkt_len < typedlen) {
464
0
        snprintf(ebuf, sizeof(ebuf),
465
0
                "%s: bad header, length too short: %lu < %lu", str,
466
0
                (unsigned long)*pkt_len, (unsigned long)typedlen);
467
0
        ERROR_MSG(ebuf);
468
0
        return 1;
469
0
    }
470
0
    return 0;
471
0
}
472
473
/**
474
 * @internal 
475
 * checks the incoming packet for validity and returns its size or 0 
476
 * 
477
 * @param pkt The packet 
478
 * @param len The length to check 
479
 * 
480
 * @return The size of the packet if valid; 0 otherwise
481
 */
482
int
483
asn_check_packet(u_char * pkt, size_t len)
484
8.80k
{
485
8.80k
    u_long          asn_length;
486
487
8.80k
    if (len < 2)
488
94
        return 0;               /* always too short */
489
490
8.71k
    if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
491
304
        return -1;              /* wrong type */
492
493
8.40k
    if (*(pkt + 1) & 0x80) {
494
        /*
495
         * long length 
496
         */
497
723
        if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
498
20
            return 0;           /* still to short, incomplete length */
499
703
        if (NULL == asn_parse_length(pkt + 1, &asn_length))
500
71
            return 0;           /* propagate error from asn_parse_length() */
501
632
        return (asn_length + 2 + (*(pkt + 1) & ~0x80));
502
7.68k
    } else {
503
        /*
504
         * short length 
505
         */
506
7.68k
        return (*(pkt + 1) + 2);
507
7.68k
    }
508
8.40k
}
509
510
static
511
    int
512
_asn_bitstring_check(const char *str, size_t asn_length, u_char datum)
513
31
{
514
31
    char            ebuf[128];
515
516
31
    if (asn_length < 1) {
517
13
        snprintf(ebuf, sizeof(ebuf),
518
13
                "%s: length %d too small", str, (int) asn_length);
519
13
        ERROR_MSG(ebuf);
520
13
        return 1;
521
13
    }
522
    /*
523
     * if (datum > 7){
524
     * sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
525
     * ERROR_MSG(ebuf);
526
     * return 1;
527
     * }
528
     */
529
18
    return 0;
530
31
}
531
532
/**
533
 * @internal 
534
 * asn_parse_int - pulls a long out of an int type.
535
 *
536
 *  On entry, datalength is input as the number of valid bytes following
537
 *   "data".  On exit, it is returned as the number of valid bytes
538
 *   following the end of this object.
539
 *
540
 *  Returns a pointer to the first byte past the end
541
 *   of this object (i.e. the start of the next object).
542
 *  Returns NULL on any error.
543
 *  
544
 * @param data       IN - pointer to start of object
545
 * @param datalength IN/OUT - number of valid bytes left in buffer
546
 * @param type       OUT - asn type of object
547
 * @param intp       IN/OUT - pointer to start of output buffer
548
 * @param intsize    IN - size of output buffer
549
 * 
550
 * @return pointer to the first byte past the end
551
 *   of this object (i.e. the start of the next object) Returns NULL on any error
552
 */
553
u_char         *
554
asn_parse_int(u_char * data,
555
              size_t * datalength,
556
              u_char * type, long *intp, size_t intsize)
557
12.8k
{
558
    /*
559
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
560
     */
561
12.8k
    static const char *errpre = "parse int";
562
12.8k
    register u_char *bufp = data;
563
12.8k
    u_long          asn_length;
564
12.8k
    int             i;
565
12.8k
    union {
566
12.8k
        long          l;
567
12.8k
        unsigned char b[sizeof(long)];
568
12.8k
    } value;
569
570
12.8k
    if (NULL == data || NULL == datalength || NULL == type || NULL == intp) {
571
0
        ERROR_MSG("parse int: NULL pointer");
572
0
        return NULL;
573
0
    }
574
575
12.8k
    if (intsize != sizeof(long)) {
576
0
        _asn_size_err(errpre, intsize, sizeof(long));
577
0
        return NULL;
578
0
    }
579
580
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
581
12.8k
    if (*datalength < 2) {
582
515
        _asn_short_err(errpre, *datalength, 2);
583
515
        return NULL;
584
515
    }
585
586
12.3k
    *type = *bufp++;
587
12.3k
    if (*type != ASN_INTEGER) {
588
742
        _asn_type_err(errpre, *type);
589
742
        return NULL;
590
742
    }
591
592
11.5k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
593
11.5k
    if (NULL == bufp) {
594
681
        _asn_short_err(errpre, *datalength - 1, asn_length);
595
681
        return NULL;
596
681
    }
597
598
10.8k
    if ((size_t) asn_length > intsize || (int) asn_length == 0) {
599
73
        _asn_length_err(errpre, (size_t) asn_length, intsize);
600
73
        return NULL;
601
73
    }
602
603
10.8k
    *datalength -= (int) asn_length + (bufp - data);
604
605
10.8k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
606
607
10.8k
    memset(&value.b, *bufp & 0x80 ? 0xff : 0, sizeof(value.b));
608
10.8k
    if (NETSNMP_BIGENDIAN) {
609
0
        for (i = sizeof(long) - asn_length; asn_length--; i++)
610
0
            value.b[i] = *bufp++;
611
10.8k
    } else {
612
28.3k
        for (i = asn_length - 1; asn_length--; i--)
613
17.5k
            value.b[i] = *bufp++;
614
10.8k
    }
615
616
10.8k
    CHECK_OVERFLOW_S(value.l, 1);
617
618
10.8k
    DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2lX)\n", value.l, value.l));
619
620
10.8k
    *intp = value.l;
621
10.8k
    return bufp;
622
10.8k
}
623
624
625
/**
626
 * @internal 
627
 * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
628
 *
629
 *  On entry, datalength is input as the number of valid bytes following
630
 *   "data".  On exit, it is returned as the number of valid bytes
631
 *   following the end of this object.
632
 *
633
 *  Returns a pointer to the first byte past the end
634
 *   of this object (i.e. the start of the next object).
635
 *  Returns NULL on any error.
636
 *  
637
 * @param data       IN - pointer to start of object
638
 * @param datalength IN/OUT - number of valid bytes left in buffer
639
 * @param type       OUT - asn type of object
640
 * @param intp       IN/OUT - pointer to start of output buffer
641
 * @param intsize    IN - size of output buffer
642
 * 
643
 * @return pointer to the first byte past the end
644
 *   of this object (i.e. the start of the next object) Returns NULL on any error
645
 */
646
u_char         *
647
asn_parse_unsigned_int(u_char * data,
648
                       size_t * datalength,
649
                       u_char * type, u_long * intp, size_t intsize)
650
342
{
651
    /*
652
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
653
     */
654
342
    static const char *errpre = "parse uint";
655
342
    register u_char *bufp = data;
656
342
    u_long          asn_length;
657
342
    register u_long value = 0;
658
659
342
    if (NULL == data || NULL == datalength || NULL == type || NULL == intp) {
660
0
        ERROR_MSG("parse uint: NULL pointer");
661
0
        return NULL;
662
0
    }
663
664
342
    if (intsize != sizeof(long)) {
665
0
        _asn_size_err(errpre, intsize, sizeof(long));
666
0
        return NULL;
667
0
    }
668
669
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
670
342
    if (*datalength < 2) {
671
1
        _asn_short_err(errpre, *datalength, 2);
672
1
        return NULL;
673
1
    }
674
675
341
    *type = *bufp++;
676
341
    if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
677
117
            && *type != ASN_UINTEGER) {
678
32
        _asn_type_err(errpre, *type);
679
32
        return NULL;
680
32
    }
681
682
309
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
683
309
    if (NULL == bufp) {
684
134
        _asn_short_err(errpre, *datalength - 1, asn_length);
685
134
        return NULL;
686
134
    }
687
688
175
    if ((asn_length > (intsize + 1)) || ((int) asn_length == 0) ||
689
166
        ((asn_length == intsize + 1) && *bufp != 0x00)) {
690
17
        _asn_length_err(errpre, (size_t) asn_length, intsize);
691
17
        return NULL;
692
17
    }
693
158
    *datalength -= (int) asn_length + (bufp - data);
694
695
158
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
696
697
835
    while (asn_length--)
698
677
        value = (value << 8) | *bufp++;
699
700
158
    CHECK_OVERFLOW_U(value,2);
701
702
158
    DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2lX)\n", value, value));
703
704
158
    *intp = value;
705
158
    return bufp;
706
175
}
707
708
709
/**
710
 * @internal 
711
 * asn_build_int - builds an ASN object containing an integer.
712
 *
713
 *  On entry, datalength is input as the number of valid bytes following
714
 *   "data".  On exit, it is returned as the number of valid bytes
715
 *   following the end of this object.
716
 *
717
 *  Returns a pointer to the first byte past the end
718
 *   of this object (i.e. the start of the next object).
719
 *  Returns NULL on any error.
720
 * 
721
 * 
722
 * @param data         IN - pointer to start of output buffer
723
 * @param datalength   IN/OUT - number of valid bytes left in buffer
724
 * @param type         IN  - asn type of objec
725
 * @param intp         IN - pointer to start of long integer
726
 * @param intsize      IN - size of input buffer
727
 * 
728
 * @return  Returns a pointer to the first byte past the end
729
 *          of this object (i.e. the start of the next object).
730
 *          Returns NULL on any error.
731
 */
732
u_char         *
733
asn_build_int(u_char * data,
734
           size_t * datalength, u_char type, const long *intp, size_t intsize)
735
0
{
736
    /*
737
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
738
     */
739
0
    static const char *errpre = "build int";
740
0
    register long   integer;
741
0
    register u_long mask;
742
0
    u_char         *initdatap = data;
743
744
0
    if (intsize != sizeof(long)) {
745
0
        _asn_size_err(errpre, intsize, sizeof(long));
746
0
        return NULL;
747
0
    }
748
0
    integer = *intp;
749
0
    CHECK_OVERFLOW_S(integer,3);
750
    /*
751
     * Truncate "unnecessary" bytes off of the most significant end of this
752
     * 2's complement integer.  There should be no sequence of 9
753
     * consecutive 1's or 0's at the most significant end of the
754
     * integer.
755
     */
756
0
    mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
757
    /*
758
     * mask is 0xFF800000 on a big-endian machine 
759
     */
760
0
    while ((((integer & mask) == 0) || ((integer & mask) == mask))
761
0
           && intsize > 1) {
762
0
        intsize--;
763
0
        integer = (u_long)integer << 8;
764
0
    }
765
0
    data = asn_build_header(data, datalength, type, intsize);
766
0
    if (_asn_build_header_check(errpre, data, *datalength, intsize))
767
0
        return NULL;
768
769
0
    *datalength -= intsize;
770
0
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
771
    /*
772
     * mask is 0xFF000000 if sizeof(long) == 4.
773
     */
774
0
    while (intsize--) {
775
0
        *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
776
0
        integer = (u_long)integer << 8;
777
0
    }
778
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
779
0
    DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp, *intp));
780
0
    return data;
781
0
}
782
783
784
785
/**
786
 * @internal 
787
 * asn_build_unsigned_int - builds an ASN object containing an integer.
788
 *
789
 *  On entry, datalength is input as the number of valid bytes following
790
 *   "data".  On exit, it is returned as the number of valid bytes
791
 *   following the end of this object.
792
 *
793
 *  Returns a pointer to the first byte past the end
794
 *   of this object (i.e. the start of the next object).
795
 *  Returns NULL on any error.
796
 * 
797
 * 
798
 * @param data         IN - pointer to start of output buffer
799
 * @param datalength   IN/OUT - number of valid bytes left in buffer
800
 * @param type         IN  - asn type of objec
801
 * @param intp         IN - pointer to start of long integer
802
 * @param intsize      IN - size of input buffer
803
 * 
804
 * @return  Returns a pointer to the first byte past the end
805
 *          of this object (i.e. the start of the next object).
806
 *          Returns NULL on any error.
807
 */
808
u_char         *
809
asn_build_unsigned_int(u_char * data,
810
                       size_t * datalength,
811
                       u_char type, const u_long * intp, size_t intsize)
812
0
{
813
    /*
814
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
815
     */
816
0
    static const char *errpre = "build uint";
817
0
    register u_long integer;
818
0
    register u_long mask;
819
0
    int             add_null_byte = 0;
820
0
    u_char         *initdatap = data;
821
822
0
    if (intsize != sizeof(long)) {
823
0
        _asn_size_err(errpre, intsize, sizeof(long));
824
0
        return NULL;
825
0
    }
826
0
    integer = *intp;
827
0
    CHECK_OVERFLOW_U(integer,4);
828
829
0
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
830
    /*
831
     * mask is 0xFF000000 on a big-endian machine 
832
     */
833
0
    if ((u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
834
        /*
835
         * if MSB is set 
836
         */
837
0
        add_null_byte = 1;
838
0
        intsize++;
839
0
    } else {
840
        /*
841
         * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
842
         * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
843
         * integer.
844
         */
845
0
        mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
846
        /*
847
         * mask is 0xFF800000 on a big-endian machine 
848
         */
849
0
        while ((((integer & mask) == 0) || ((integer & mask) == mask))
850
0
               && intsize > 1) {
851
0
            intsize--;
852
0
            integer <<= 8;
853
0
        }
854
0
    }
855
0
    data = asn_build_header(data, datalength, type, intsize);
856
0
    if (_asn_build_header_check(errpre, data, *datalength, intsize))
857
0
        return NULL;
858
859
0
    *datalength -= intsize;
860
0
    if (add_null_byte == 1) {
861
0
        *data++ = '\0';
862
0
        intsize--;
863
0
    }
864
0
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
865
    /*
866
     * mask is 0xFF000000 on a big-endian machine 
867
     */
868
0
    while (intsize--) {
869
0
        *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
870
0
        integer <<= 8;
871
0
    }
872
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
873
0
    DEBUGMSG(("dumpv_send", "  UInteger:\t%ld (0x%.2lX)\n", *intp, *intp));
874
0
    return data;
875
0
}
876
877
878
/**
879
 * @internal 
880
 * asn_parse_string - pulls an octet string out of an ASN octet string type.
881
 *
882
 *  On entry, datalength is input as the number of valid bytes following
883
 *   "data".  On exit, it is returned as the number of valid bytes
884
 *   following the beginning of the next object.
885
 *
886
 *  "string" is filled with the octet string.
887
 * ASN.1 octet string   ::=      primstring | cmpdstring
888
 * primstring           ::= 0x04 asnlength byte {byte}*
889
 * cmpdstring           ::= 0x24 asnlength string {string}*
890
 *
891
 *  Returns a pointer to the first byte past the end
892
 *   of this object (i.e. the start of the next object).
893
 *  Returns NULL on any error.
894
 * 
895
 * @param data        IN - pointer to start of object
896
 * @param datalength  IN/OUT - number of valid bytes left in buffer
897
 * @param type        OUT - asn type of object 
898
 * @param string      IN/OUT - pointer to start of output buffer
899
 * @param strlength   IN/OUT - size of output buffer
900
 * 
901
 * @return  Returns a pointer to the first byte past the end
902
 *          of this object (i.e. the start of the next object).
903
 *          Returns NULL on any error.
904
 */
905
906
u_char         *
907
asn_parse_string(u_char * data,
908
                 size_t * datalength,
909
                 u_char * type, u_char * str, size_t * strlength)
910
7.65k
{
911
7.65k
    static const char *errpre = "parse string";
912
7.65k
    u_char         *bufp = data;
913
7.65k
    u_long          asn_length;
914
915
7.65k
    if (NULL == data || NULL == datalength || NULL == type || NULL == str ||
916
7.65k
        NULL == strlength) {
917
0
        ERROR_MSG("parse string: NULL pointer");
918
0
        return NULL;
919
0
    }
920
921
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
922
7.65k
    if (*datalength < 2) {
923
690
        _asn_short_err(errpre, *datalength, 2);
924
690
        return NULL;
925
690
    }
926
927
6.96k
    *type = *bufp++;
928
6.96k
    if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
929
2.98k
            && *type != ASN_NSAP) {
930
145
        _asn_type_err(errpre, *type);
931
145
        return NULL;
932
145
    }
933
934
6.81k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
935
6.81k
    if (NULL == bufp) {
936
659
        _asn_short_err(errpre, *datalength - 1, asn_length);
937
659
        return NULL;
938
659
    }
939
940
6.15k
    if (asn_length > *strlength) {
941
26
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
942
26
        return NULL;
943
26
    }
944
945
6.13k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
946
947
6.13k
    memmove(str, bufp, asn_length);
948
6.13k
    if (*strlength > asn_length)
949
5.51k
        str[asn_length] = 0;
950
6.13k
    *strlength = asn_length;
951
6.13k
    *datalength -= asn_length + (bufp - data);
952
953
6.13k
    DEBUGIF("dumpv_recv") {
954
6.13k
        u_char         *buf = (u_char *) malloc(1 + asn_length);
955
6.13k
        size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
956
957
6.13k
        if (sprint_realloc_asciistring
958
6.13k
            (&buf, &l, &ol, 1, str, asn_length)) {
959
6.13k
            DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
960
6.13k
        } else {
961
0
            if (buf == NULL) {
962
0
                DEBUGMSG(("dumpv_recv", "  String:\t[TRUNCATED]\n"));
963
0
            } else {
964
0
                DEBUGMSG(("dumpv_recv", "  String:\t%s [TRUNCATED]\n",
965
0
                          buf));
966
0
            }
967
0
        }
968
6.13k
        if (buf != NULL) {
969
6.13k
            free(buf);
970
6.13k
        }
971
6.13k
    }
972
973
6.13k
    return bufp + asn_length;
974
6.15k
}
975
976
977
/**
978
 * @internal
979
 * asn_build_string - Builds an ASN octet string object containing the input string.
980
 *
981
 *  On entry, datalength is input as the number of valid bytes following
982
 *   "data".  On exit, it is returned as the number of valid bytes
983
 *   following the beginning of the next object.
984
 *
985
 *  Returns a pointer to the first byte past the end
986
 *   of this object (i.e. the start of the next object).
987
 *  Returns NULL on any error.
988
 *
989
 * @param data         IN - pointer to start of object
990
 * @param datalength   IN/OUT - number of valid bytes left in buffer
991
 * @param type         IN - asn type of object
992
 * @param string       IN - pointer to start of input buffer
993
 * @param strlength    IN - size of input buffer
994
 * @return  Returns a pointer to the first byte past the end
995
 *          of this object (i.e. the start of the next object).
996
 *          Returns NULL on any error.
997
 */
998
999
u_char         *
1000
asn_build_string(u_char * data,
1001
                 size_t * datalength,
1002
                 u_char type, const u_char * str, size_t strlength)
1003
0
{
1004
    /*
1005
     * ASN.1 octet string ::= primstring | cmpdstring
1006
     * primstring ::= 0x04 asnlength byte {byte}*
1007
     * cmpdstring ::= 0x24 asnlength string {string}*
1008
     * This code will never send a compound string.
1009
     */
1010
0
    u_char         *initdatap = data;
1011
0
    data = asn_build_header(data, datalength, type, strlength);
1012
0
    if (_asn_build_header_check
1013
0
        ("build string", data, *datalength, strlength))
1014
0
        return NULL;
1015
1016
0
    if (strlength) {
1017
0
        if (str == NULL) {
1018
0
            memset(data, 0, strlength);
1019
0
        } else {
1020
0
            memmove(data, str, strlength);
1021
0
        }
1022
0
    }
1023
0
    *datalength -= strlength;
1024
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
1025
0
    DEBUGIF("dumpv_send") {
1026
0
        u_char         *buf = (u_char *) malloc(1 + strlength);
1027
0
        size_t          l = (buf != NULL) ? (1 + strlength) : 0, ol = 0;
1028
1029
0
        if (sprint_realloc_asciistring(&buf, &l, &ol, 1,
1030
0
                                       str ? str : (const u_char *)"",
1031
0
                                       strlength)) {
1032
0
            DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
1033
0
        } else {
1034
0
            if (buf == NULL) {
1035
0
                DEBUGMSG(("dumpv_send", "  String:\t[TRUNCATED]\n"));
1036
0
            } else {
1037
0
                DEBUGMSG(("dumpv_send", "  String:\t%s [TRUNCATED]\n",
1038
0
                          buf));
1039
0
            }
1040
0
        }
1041
0
        if (buf != NULL) {
1042
0
            free(buf);
1043
0
        }
1044
0
    }
1045
0
    return data + strlength;
1046
0
}
1047
1048
1049
1050
/**
1051
 * @internal
1052
 * asn_parse_header - interprets the ID and length of the current object.
1053
 *
1054
 *  On entry, datalength is input as the number of valid bytes following
1055
 *   "data".  On exit, it is returned as the number of valid bytes
1056
 *   in this object following the id and length.
1057
 *
1058
 *  Returns a pointer to the first byte of the contents of this object.
1059
 *  Returns NULL on any error.
1060
 *
1061
 *
1062
 * @param data         IN - pointer to start of object
1063
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1064
 * @param type         OUT - asn type of object
1065
 * @return  Returns a pointer to the first byte of the contents of this object.
1066
 *          Returns NULL on any error.
1067
 *
1068
 */
1069
u_char         *
1070
asn_parse_header(u_char * data, size_t * datalength, u_char * type)
1071
16.1k
{
1072
16.1k
    register u_char *bufp;
1073
16.1k
    u_long          asn_length = 0;
1074
16.1k
    const char      *errpre = "parse header";
1075
1076
16.1k
    if (!data || !datalength || !type) {
1077
0
        ERROR_MSG("parse header: NULL pointer");
1078
0
        return NULL;
1079
0
    }
1080
1081
    /** need at least 2 bytes to work with: type, length (which might be 0) */
1082
16.1k
    if (*datalength < 2) {
1083
626
        _asn_short_err(errpre, *datalength, 2);
1084
626
        return NULL;
1085
626
    }
1086
1087
15.5k
    bufp = data;
1088
    /*
1089
     * this only works on data types < 30, i.e. no extension octets 
1090
     */
1091
15.5k
    if (IS_EXTENSION_ID(*bufp)) {
1092
76
        ERROR_MSG("can't process ID >= 30");
1093
76
        return NULL;
1094
76
    }
1095
15.4k
    *type = *bufp++;
1096
1097
15.4k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1098
15.4k
    if (NULL == bufp) {
1099
1.05k
        _asn_short_err(errpre, *datalength - 1, asn_length);
1100
1.05k
        return NULL;
1101
1.05k
    }
1102
1103
#ifdef DUMP_PRINT_HEADERS
1104
    DEBUGDUMPSETUP("recv", data, (bufp - data));
1105
    DEBUGMSG(("dumpv_recv", "  Header: 0x%.2X, len = %d (0x%X)\n", *data,
1106
              asn_length, asn_length));
1107
#else
1108
    /*
1109
     * DEBUGMSGHEXTLI(("recv",data,(bufp-data)));
1110
     * DEBUGMSG(("dumpH_recv","\n"));
1111
     */
1112
14.4k
#endif
1113
1114
14.4k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1115
1116
14.4k
    if ((asn_length > 2) && (*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
1117
1118
        /*
1119
         * check if 64-but counter 
1120
         */
1121
474
        switch (*(bufp + 1)) {
1122
56
        case ASN_OPAQUE_COUNTER64:
1123
92
        case ASN_OPAQUE_U64:
1124
216
        case ASN_OPAQUE_FLOAT:
1125
226
        case ASN_OPAQUE_DOUBLE:
1126
436
        case ASN_OPAQUE_I64:
1127
436
            *type = *(bufp + 1);
1128
436
            break;
1129
1130
38
        default:
1131
            /*
1132
             * just an Opaque 
1133
             */
1134
38
            *datalength = (int) asn_length;
1135
38
            return bufp;
1136
474
        }
1137
        /*
1138
         * value is encoded as special format 
1139
         */
1140
436
        *datalength = (int) asn_length;
1141
436
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
1142
436
        if (NULL == bufp) {
1143
118
            _asn_short_err("parse opaque header", *datalength - 2, asn_length);
1144
118
            return NULL;
1145
118
        }
1146
436
    }
1147
14.2k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1148
1149
14.2k
    *datalength = (int) asn_length;
1150
1151
14.2k
    return bufp;
1152
14.4k
}
1153
1154
/**
1155
 * @internal
1156
 * same as asn_parse_header with test for expected type
1157
 *
1158
 * @see asn_parse_header
1159
 *
1160
 * @param data          IN - pointer to start of object
1161
 * @param datalength    IN/OUT - number of valid bytes left in buffer
1162
 * @param type          OUT - asn type of object
1163
 * @param expected_type IN expected type
1164
 * @return  Returns a pointer to the first byte of the contents of this object.
1165
 *          Returns NULL on any error.
1166
 *
1167
 */
1168
u_char         *
1169
asn_parse_sequence(u_char * data, size_t * datalength, u_char * type, u_char expected_type,     /* must be this type */
1170
                   const char *estr)
1171
11.0k
{                               /* error message prefix */
1172
11.0k
    data = asn_parse_header(data, datalength, type);
1173
11.0k
    if (data && (*type != expected_type)) {
1174
314
        char            ebuf[128];
1175
314
        snprintf(ebuf, sizeof(ebuf),
1176
314
                 "%s header type %02X: s/b %02X", estr,
1177
314
                (u_char) * type, (u_char) expected_type);
1178
314
        ERROR_MSG(ebuf);
1179
314
        return NULL;
1180
314
    }
1181
10.7k
    return data;
1182
11.0k
}
1183
1184
1185
1186
/**
1187
 * @internal
1188
 * asn_build_header - builds an ASN header for an object with the ID and
1189
 * length specified.
1190
 *
1191
 *  On entry, datalength is input as the number of valid bytes following
1192
 *   "data".  On exit, it is returned as the number of valid bytes
1193
 *   in this object following the id and length.
1194
 *
1195
 *  This only works on data types < 30, i.e. no extension octets.
1196
 *  The maximum length is 0xFFFF;
1197
 *
1198
 *  Returns a pointer to the first byte of the contents of this object.
1199
 *  Returns NULL on any error.
1200
 *
1201
 * @param data         IN - pointer to start of object
1202
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1203
 * @param type         IN - asn type of object
1204
 * @param length       IN - length of object
1205
 * @return Returns a pointer to the first byte of the contents of this object.
1206
 *          Returns NULL on any error.
1207
 */
1208
u_char         *
1209
asn_build_header(u_char * data,
1210
                 size_t * datalength, u_char type, size_t length)
1211
0
{
1212
0
    char            ebuf[128];
1213
1214
0
    if (*datalength < 1) {
1215
0
        snprintf(ebuf, sizeof(ebuf),
1216
0
                "bad header length < 1 :%lu, %lu",
1217
0
    (unsigned long)*datalength, (unsigned long)length);
1218
0
        ERROR_MSG(ebuf);
1219
0
        return NULL;
1220
0
    }
1221
0
    *data++ = type;
1222
0
    (*datalength)--;
1223
0
    return asn_build_length(data, datalength, length);
1224
0
}
1225
1226
/**
1227
 * @internal
1228
 * asn_build_sequence - builds an ASN header for a sequence with the ID and
1229
 *
1230
 * length specified.
1231
 *  On entry, datalength is input as the number of valid bytes following
1232
 *   "data".  On exit, it is returned as the number of valid bytes
1233
 *   in this object following the id and length.
1234
 *
1235
 *  This only works on data types < 30, i.e. no extension octets.
1236
 *  The maximum length is 0xFFFF;
1237
 *
1238
 *  Returns a pointer to the first byte of the contents of this object.
1239
 *  Returns NULL on any error.
1240
 *
1241
 * @param data         IN - pointer to start of object
1242
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1243
 * @param type         IN - asn type of object
1244
 * @param length       IN - length of object
1245
 *
1246
 * @return Returns a pointer to the first byte of the contents of this object.
1247
 *         Returns NULL on any error.
1248
 */
1249
u_char         *
1250
asn_build_sequence(u_char * data,
1251
                   size_t * datalength, u_char type, size_t length)
1252
0
{
1253
0
    static const char *errpre = "build seq";
1254
0
    char            ebuf[128];
1255
1256
0
    if (*datalength < 4) {
1257
0
        snprintf(ebuf, sizeof(ebuf),
1258
0
                "%s: length %d < 4: PUNT", errpre,
1259
0
                (int) *datalength);
1260
0
        ERROR_MSG(ebuf);
1261
0
        return NULL;
1262
0
    }
1263
0
    *datalength -= 4;
1264
0
    *data++ = type;
1265
0
    *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1266
0
    *data++ = (u_char) ((length >> 8) & 0xFF);
1267
0
    *data++ = (u_char) (length & 0xFF);
1268
0
    return data;
1269
0
}
1270
1271
/**
1272
 * @internal
1273
 * asn_parse_length - interprets the length of the current object.
1274
 *
1275
 *  On exit, length contains the value of this length field.
1276
 *
1277
 *  Returns a pointer to the first byte after this length
1278
 *  field (aka: the start of the data field).
1279
 *  Returns NULL on any error.
1280
 *
1281
 * @param data         IN - pointer to start of length field
1282
 * @param length       OUT - value of length field
1283
 *
1284
 *  @return Returns a pointer to the first byte after this length
1285
 *          field (aka: the start of the data field).
1286
 *          Returns NULL on any error.
1287
 *
1288
 * WARNING: this function does not know the length of the data
1289
*           buffer, so it can go past the end of a short buffer.
1290
 */
1291
u_char         *
1292
asn_parse_length(u_char * data, u_long * length)
1293
2.35k
{
1294
2.35k
    static const char *errpre = "parse length";
1295
2.35k
    char            ebuf[128];
1296
2.35k
    register u_char lengthbyte;
1297
1298
2.35k
    if (!data || !length) {
1299
0
        ERROR_MSG("parse length: NULL pointer");
1300
0
        return NULL;
1301
0
    }
1302
2.35k
    lengthbyte = *data;
1303
1304
2.35k
    if (lengthbyte & ASN_LONG_LEN) {
1305
2.35k
        lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
1306
2.35k
        if (lengthbyte == 0) {
1307
39
            snprintf(ebuf, sizeof(ebuf),
1308
39
                     "%s: indefinite length not supported", errpre);
1309
39
            ERROR_MSG(ebuf);
1310
39
            return NULL;
1311
39
        }
1312
2.31k
        if (lengthbyte > sizeof(long)) {
1313
115
            snprintf(ebuf, sizeof(ebuf),
1314
115
                    "%s: data length %d > %lu not supported", errpre,
1315
115
                    lengthbyte, (unsigned long)sizeof(long));
1316
115
            ERROR_MSG(ebuf);
1317
115
            return NULL;
1318
115
        }
1319
2.20k
        data++;
1320
2.20k
        *length = 0;            /* protect against short lengths */
1321
15.3k
        while (lengthbyte--) {
1322
13.1k
            *length <<= 8;
1323
13.1k
            *length |= *data++;
1324
13.1k
        }
1325
2.20k
        if ((long) *length < 0) {
1326
126
            snprintf(ebuf, sizeof(ebuf),
1327
126
                     "%s: negative data length %ld\n", errpre,
1328
126
                     (long) *length);
1329
126
            ERROR_MSG(ebuf);
1330
126
            return NULL;
1331
126
        }
1332
2.07k
        return data;
1333
2.20k
    } else {                    /* short asnlength */
1334
0
        *length = (long) lengthbyte;
1335
0
        return data + 1;
1336
0
    }
1337
2.35k
}
1338
1339
/**
1340
 * @internal
1341
 * asn_build_length - builds an ASN header for a length with
1342
 * length specified.
1343
 *
1344
 *  On entry, datalength is input as the number of valid bytes following
1345
 *   "data".  On exit, it is returned as the number of valid bytes
1346
 *   in this object following the length.
1347
 *
1348
 *
1349
 *  Returns a pointer to the first byte of the contents of this object.
1350
 *  Returns NULL on any error.
1351
 *
1352
 * @param data         IN - pointer to start of object
1353
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1354
 * @param length       IN - length of object
1355
 *
1356
 * @return Returns a pointer to the first byte of the contents of this object.
1357
 *         Returns NULL on any error.
1358
 */
1359
u_char         *
1360
asn_build_length(u_char * data, size_t * datalength, size_t length)
1361
0
{
1362
0
    static const char *errpre = "build length";
1363
0
    char            ebuf[128];
1364
1365
0
    u_char         *start_data = data;
1366
1367
    /*
1368
     * no indefinite lengths sent 
1369
     */
1370
0
    if (length < 0x80) {
1371
0
        if (*datalength < 1) {
1372
0
            snprintf(ebuf, sizeof(ebuf),
1373
0
                    "%s: bad length < 1 :%lu, %lu", errpre,
1374
0
                    (unsigned long)*datalength, (unsigned long)length);
1375
0
            ERROR_MSG(ebuf);
1376
0
            return NULL;
1377
0
        }
1378
0
        *data++ = (u_char) length;
1379
0
    } else if (length <= 0xFF) {
1380
0
        if (*datalength < 2) {
1381
0
            snprintf(ebuf, sizeof(ebuf),
1382
0
                    "%s: bad length < 2 :%lu, %lu", errpre,
1383
0
                    (unsigned long)*datalength, (unsigned long)length);
1384
0
            ERROR_MSG(ebuf);
1385
0
            return NULL;
1386
0
        }
1387
0
        *data++ = (u_char) (0x01 | ASN_LONG_LEN);
1388
0
        *data++ = (u_char) length;
1389
0
    } else {                    /* 0xFF < length <= 0xFFFF */
1390
0
        if (*datalength < 3) {
1391
0
            snprintf(ebuf, sizeof(ebuf),
1392
0
                    "%s: bad length < 3 :%lu, %lu", errpre,
1393
0
                    (unsigned long)*datalength, (unsigned long)length);
1394
0
            ERROR_MSG(ebuf);
1395
0
            return NULL;
1396
0
        }
1397
0
        *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1398
0
        *data++ = (u_char) ((length >> 8) & 0xFF);
1399
0
        *data++ = (u_char) (length & 0xFF);
1400
0
    }
1401
0
    *datalength -= (data - start_data);
1402
0
    return data;
1403
1404
0
}
1405
1406
/**
1407
 * @internal
1408
 * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
1409
 *
1410
 *  On entry, datalength is input as the number of valid bytes following
1411
 *   "data".  On exit, it is returned as the number of valid bytes
1412
 *   following the beginning of the next object.
1413
 *
1414
 *  "objid" is filled with the object identifier.
1415
 *
1416
 *  Returns a pointer to the first byte past the end
1417
 *   of this object (i.e. the start of the next object).
1418
 *  Returns NULL on any error.
1419
 *
1420
 * @param data         IN - pointer to start of object
1421
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1422
 * @param type         OUT - asn type of object
1423
 * @param objid        IN/OUT - pointer to start of output buffer
1424
 * @param objidlength  IN/OUT - number of sub-id's in objid
1425
 *
1426
 *  @return Returns a pointer to the first byte past the end
1427
 *   of this object (i.e. the start of the next object).
1428
 *  Returns NULL on any error.
1429
 *
1430
 */
1431
u_char         *
1432
asn_parse_objid(u_char * data,
1433
                size_t * datalength,
1434
                u_char * type, oid * objid, size_t * objidlength)
1435
2.89k
{
1436
2.89k
    static const char *errpre = "parse objid";
1437
    /*
1438
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1439
     * subidentifier ::= {leadingbyte}* lastbyte
1440
     * leadingbyte ::= 1 7bitvalue
1441
     * lastbyte ::= 0 7bitvalue
1442
     */
1443
2.89k
    register u_char *bufp = data;
1444
2.89k
    register oid   *oidp = objid + 1;
1445
2.89k
    register u_long subidentifier;
1446
2.89k
    register long   length;
1447
2.89k
    u_long          asn_length;
1448
2.89k
    size_t          original_length = *objidlength;
1449
1450
2.89k
    if (NULL == data || NULL == datalength || NULL == type || NULL == objid) {
1451
0
        ERROR_MSG("parse objid: NULL pointer");
1452
0
        return NULL;
1453
0
    }
1454
1455
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1456
2.89k
    if (*datalength < 2) {
1457
41
        _asn_short_err(errpre, *datalength, 2);
1458
41
        return NULL;
1459
41
    }
1460
1461
2.85k
    *type = *bufp++;
1462
2.85k
    if (*type != ASN_OBJECT_ID) {
1463
86
        _asn_type_err(errpre, *type);
1464
86
        return NULL;
1465
86
    }
1466
2.76k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1467
2.76k
    if (NULL == bufp) {
1468
469
        _asn_short_err(errpre, *datalength - 1, asn_length);
1469
469
        return NULL;
1470
469
    }
1471
1472
2.29k
    *datalength -= (int) asn_length + (bufp - data);
1473
1474
2.29k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1475
1476
    /*
1477
     * Handle invalid object identifier encodings of the form 06 00 robustly 
1478
     */
1479
2.29k
    if (asn_length == 0)
1480
916
        objid[0] = objid[1] = 0;
1481
1482
2.29k
    length = asn_length;
1483
2.29k
    (*objidlength)--;           /* account for expansion of first byte */
1484
1485
9.03k
    while (length > 0 && (*objidlength)-- > 0) {
1486
6.80k
        subidentifier = 0;
1487
9.73k
        do {                    /* shift and add in low order 7 bits */
1488
9.73k
            if (subidentifier > (MAX_SUBID >> 7)) {
1489
20
                ERROR_MSG("subidentifier too large / overflow");
1490
20
                return NULL;
1491
20
            }
1492
9.71k
            subidentifier =
1493
9.71k
                (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1494
9.71k
            length--;
1495
9.71k
        } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0));        /* last byte has high bit clear */
1496
1497
6.78k
  if (length == 0) {
1498
1.36k
            u_char *last_byte = bufp - 1;
1499
1.36k
            if (*last_byte & ASN_BIT8) {
1500
                /* last byte has high bit set -> wrong BER encoded OID */
1501
39
                ERROR_MSG("subidentifier syntax error");
1502
39
                return NULL;
1503
39
            }
1504
1.36k
        }
1505
6.74k
        if (subidentifier > MAX_SUBID) {
1506
0
            ERROR_MSG("subidentifier too large");
1507
0
            return NULL;
1508
0
        }
1509
6.74k
        *oidp++ = (oid) subidentifier;
1510
6.74k
    }
1511
1512
2.23k
    if (length || oidp < objid + 1) {
1513
0
        ERROR_MSG("OID length exceeds buffer size");
1514
0
        *objidlength = original_length;
1515
0
        return NULL;
1516
0
    }
1517
1518
    /*
1519
     * The first two subidentifiers are encoded into the first component
1520
     * with the value (X * 40) + Y, where:
1521
     *  X is the value of the first subidentifier.
1522
     *  Y is the value of the second subidentifier.
1523
     */
1524
2.23k
    subidentifier = oidp - objid >= 2 ? objid[1] : 0;
1525
2.23k
    if (subidentifier == 0x2B) {
1526
59
        objid[0] = 1;
1527
59
        objid[1] = 3;
1528
2.17k
    } else {
1529
2.17k
        if (subidentifier < 40) {
1530
1.05k
            objid[0] = 0;
1531
1.05k
            objid[1] = subidentifier;
1532
1.12k
        } else if (subidentifier < 80) {
1533
142
            objid[0] = 1;
1534
142
            objid[1] = subidentifier - 40;
1535
983
        } else {
1536
983
            objid[0] = 2;
1537
983
            objid[1] = subidentifier - 80;
1538
983
        }
1539
2.17k
    }
1540
1541
2.23k
    *objidlength = (int) (oidp - objid);
1542
1543
2.23k
    DEBUGMSG(("dumpv_recv", "  ObjID: "));
1544
2.23k
    DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1545
2.23k
    DEBUGMSG(("dumpv_recv", "\n"));
1546
2.23k
    return bufp;
1547
2.23k
}
1548
1549
/* Number of bytes occupied by an ASN.1-encoded object identifier. */
1550
static unsigned int encoded_oid_len(uint32_t objid)
1551
0
{
1552
0
    unsigned int encoded_len = 0;
1553
1554
0
    if (objid == 0)
1555
0
        return 1;
1556
1557
0
    while (objid) {
1558
0
        encoded_len++;
1559
0
        objid >>= 7;
1560
0
    }
1561
1562
0
    return encoded_len;
1563
0
}
1564
1565
/**
1566
 * @internal
1567
 * asn_build_objid - Builds an ASN object identifier object containing the
1568
 * input string.
1569
 *
1570
 *  On entry, datalength is input as the number of valid bytes following
1571
 *   "data".  On exit, it is returned as the number of valid bytes
1572
 *   following the beginning of the next object.
1573
 *
1574
 *  Returns a pointer to the first byte past the end
1575
 *   of this object (i.e. the start of the next object).
1576
 *  Returns NULL on any error.
1577
 *
1578
 * @param data         IN - pointer to start of object
1579
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1580
 * @param type         IN - asn type of object
1581
 * @param objid        IN - pointer to start of input buffer
1582
 * @param objidlength  IN - number of sub-id's in objid
1583
 *
1584
 * @return   Returns a pointer to the first byte past the end
1585
 *           of this object (i.e. the start of the next object).
1586
 *           Returns NULL on any error.
1587
 */
1588
u_char         *
1589
asn_build_objid(u_char * data,
1590
                size_t * datalength,
1591
                u_char type, const oid * objid, size_t objidlength)
1592
0
{
1593
    /*
1594
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1595
     * subidentifier ::= {leadingbyte}* lastbyte
1596
     * leadingbyte ::= 1 7bitvalue
1597
     * lastbyte ::= 0 7bitvalue
1598
     */
1599
0
    size_t          asnlength;
1600
0
    register u_long objid_val;
1601
0
    u_long          first_objid_val;
1602
0
    register int    i;
1603
0
    u_char         *initdatap = data;
1604
1605
    /*
1606
     * check if there are at least 2 sub-identifiers 
1607
     */
1608
0
    if (objidlength == 0) {
1609
        /*
1610
         * there are not, so make the OID have two sub-identifiers with value
1611
         * zero. Both sub-identifiers are encoded as a single byte.
1612
         */
1613
0
        objid_val = 0;
1614
0
        objidlength = 1;
1615
0
    } else if (objid[0] > 2) {
1616
0
        ERROR_MSG("build objid: bad first subidentifier");
1617
0
        return NULL;
1618
0
    } else if (objidlength == 1) {
1619
        /*
1620
         * encode the first value 
1621
         */
1622
0
        objid_val = objid[0] * 40;
1623
0
        objidlength = 2;
1624
0
    } else {
1625
        /*
1626
         * combine the first two values 
1627
         */
1628
0
        if ((objid[1] >= 40 && objid[0] < 2) ||
1629
0
            objid[1] > UINT32_MAX - objid[0] * 40) {
1630
0
            ERROR_MSG("build objid: bad second subidentifier");
1631
0
            return NULL;
1632
0
        }
1633
0
        objid_val = objid[0] * 40 + objid[1];
1634
0
    }
1635
0
    first_objid_val = objid_val;
1636
0
    CHECK_OVERFLOW_U(first_objid_val, 14);
1637
1638
    /*
1639
     * ditch illegal calls now 
1640
     */
1641
0
    if (objidlength > MAX_OID_LEN)
1642
0
        return NULL;
1643
1644
    /*
1645
     * calculate the number of bytes needed to store the encoded value 
1646
     */
1647
0
    if (objidlength <= 1) {
1648
0
        asnlength = encoded_oid_len(first_objid_val);
1649
0
    } else {
1650
0
        asnlength = 0;
1651
0
        for (i = 1; i < objidlength; i++) {
1652
0
            objid_val = i == 1 ? first_objid_val : objid[i];
1653
0
            CHECK_OVERFLOW_U(objid_val, 5);
1654
0
            asnlength += encoded_oid_len(objid_val);
1655
0
        }
1656
0
    }
1657
1658
    /*
1659
     * store the ASN.1 tag and length 
1660
     */
1661
0
    data = asn_build_header(data, datalength, type, asnlength);
1662
0
    if (_asn_build_header_check("build objid", data, *datalength, asnlength))
1663
0
        return NULL;
1664
1665
    /*
1666
     * store the encoded OID value 
1667
     */
1668
0
    if (objidlength <= 1) {
1669
0
        *data++ = 0;
1670
0
    } else {
1671
0
        for (i = 1; i < objidlength; i++) {
1672
0
            unsigned int encoded_len;
1673
0
            int j;
1674
1675
0
            objid_val = (uint32_t)(i == 1 ? first_objid_val : objid[i]);
1676
0
            encoded_len = encoded_oid_len(objid_val);
1677
0
            for (j = encoded_len - 1; j >= 0; j--) {
1678
0
                data[j] = (objid_val & 0x7f) |
1679
0
                    (j == encoded_len - 1 ? 0 : 0x80);
1680
0
                objid_val >>= 7;
1681
0
            }
1682
0
            data += encoded_len;
1683
0
        }
1684
0
    }
1685
1686
    /*
1687
     * return the length and data ptr 
1688
     */
1689
0
    *datalength -= asnlength;
1690
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1691
0
    DEBUGMSG(("dumpv_send", "  ObjID: "));
1692
0
    DEBUGMSGOID(("dumpv_send", objid, objidlength));
1693
0
    DEBUGMSG(("dumpv_send", "\n"));
1694
0
    return data;
1695
0
}
1696
1697
/**
1698
 * @internal
1699
 * asn_parse_null - Interprets an ASN null type.
1700
 *
1701
 *  On entry, datalength is input as the number of valid bytes following
1702
 *   "data".  On exit, it is returned as the number of valid bytes
1703
 *   following the beginning of the next object.
1704
 *
1705
 *  Returns a pointer to the first byte past the end
1706
 *   of this object (i.e. the start of the next object).
1707
 *  Returns NULL on any error.
1708
 *
1709
 * @param data         IN - pointer to start of object
1710
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1711
 * @param type         OUT - asn type of object
1712
 *  @return Returns a pointer to the first byte past the end
1713
 *          of this object (i.e. the start of the next object).
1714
 *          Returns NULL on any error.
1715
 */
1716
u_char         *
1717
asn_parse_null(u_char * data, size_t * datalength, u_char * type)
1718
0
{
1719
    /*
1720
     * ASN.1 null ::= 0x05 0x00
1721
     */
1722
0
    register u_char *bufp = data;
1723
0
    u_long          asn_length;
1724
0
    static const char *errpre = "parse null";
1725
1726
0
    if (NULL == data || NULL == datalength || NULL == type) {
1727
0
        ERROR_MSG("parse null: NULL pointer");
1728
0
        return NULL;
1729
0
    }
1730
1731
    /** need at least 2 bytes to work with: type, length  (which should be 0) */
1732
0
    if (*datalength < 2) {
1733
0
        _asn_short_err(errpre, *datalength, 2);
1734
0
        return NULL;
1735
0
    }
1736
1737
0
    *type = *bufp++;
1738
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1739
0
    if (NULL == bufp) {
1740
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1741
0
        return NULL;
1742
0
    }
1743
0
    if (asn_length != 0) {
1744
0
        ERROR_MSG("parse null: malformed ASN.1 null");
1745
0
        return NULL;
1746
0
    }
1747
1748
0
    *datalength -= (bufp - data);
1749
1750
0
    DEBUGDUMPSETUP("recv", data, bufp - data);
1751
0
    DEBUGMSG(("dumpv_recv", "  NULL\n"));
1752
1753
0
    return bufp + asn_length;
1754
0
}
1755
1756
1757
/**
1758
 * @internal
1759
 * asn_build_null - Builds an ASN null object.
1760
 *
1761
 *  On entry, datalength is input as the number of valid bytes following
1762
 *   "data".  On exit, it is returned as the number of valid bytes
1763
 *   following the beginning of the next object.
1764
 *
1765
 *  Returns a pointer to the first byte past the end
1766
 *   of this object (i.e. the start of the next object).
1767
 *  Returns NULL on any error.
1768
 *
1769
 * @param data         IN - pointer to start of object
1770
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1771
 * @param type         IN - asn type of object
1772
 * @retun  Returns a pointer to the first byte past the end
1773
 *         of this object (i.e. the start of the next object).
1774
 *         Returns NULL on any error.
1775
 *
1776
 */
1777
u_char         *
1778
asn_build_null(u_char * data, size_t * datalength, u_char type)
1779
0
{
1780
    /*
1781
     * ASN.1 null ::= 0x05 0x00
1782
     */
1783
0
    u_char         *initdatap = data;
1784
0
    data = asn_build_header(data, datalength, type, 0);
1785
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1786
0
    DEBUGMSG(("dumpv_send", "  NULL\n"));
1787
0
    return data;
1788
0
}
1789
1790
/**
1791
 * @internal
1792
 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
1793
 *
1794
 *  On entry, datalength is input as the number of valid bytes following
1795
 *   "data".  On exit, it is returned as the number of valid bytes
1796
 *   following the beginning of the next object.
1797
 *
1798
 *  "string" is filled with the bit string.
1799
 *
1800
 *  Returns a pointer to the first byte past the end
1801
 *   of this object (i.e. the start of the next object).
1802
 *  Returns NULL on any error.
1803
 *
1804
 * @param data         IN - pointer to start of object
1805
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1806
 * @param type         OUT - asn type of object
1807
 * @param string       IN/OUT - pointer to start of output buffer
1808
 * @param strlength    IN/OUT - size of output buffer
1809
 * @return Returns a pointer to the first byte past the end
1810
 *         of this object (i.e. the start of the next object).
1811
 *         Returns NULL on any error.
1812
 */
1813
u_char         *
1814
asn_parse_bitstring(u_char * data,
1815
                    size_t * datalength,
1816
                    u_char * type, u_char * str, size_t * strlength)
1817
31
{
1818
    /*
1819
     * bitstring ::= 0x03 asnlength unused {byte}*
1820
     */
1821
31
    static const char *errpre = "parse bitstring";
1822
31
    register u_char *bufp = data;
1823
31
    u_long          asn_length;
1824
1825
31
    if (NULL == data || NULL == datalength || NULL == type ||
1826
31
        NULL == str || NULL == strlength) {
1827
0
        ERROR_MSG("parse bitstring: NULL pointer");
1828
0
        return NULL;
1829
0
    }
1830
1831
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1832
31
    if (*datalength < 2) {
1833
0
        _asn_short_err(errpre, *datalength, 2);
1834
0
        return NULL;
1835
0
    }
1836
1837
31
    *type = *bufp++;
1838
31
    if (*type != ASN_BIT_STR) {
1839
0
        _asn_type_err(errpre, *type);
1840
0
        return NULL;
1841
0
    }
1842
1843
31
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1844
31
    if (NULL == bufp) {
1845
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1846
0
        return NULL;
1847
0
    }
1848
1849
31
    if ((size_t) asn_length > *strlength) {
1850
0
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
1851
0
        return NULL;
1852
0
    }
1853
31
    if (_asn_bitstring_check(errpre, asn_length, *bufp))
1854
13
        return NULL;
1855
1856
18
    DEBUGDUMPSETUP("recv", data, bufp - data);
1857
18
    DEBUGMSG(("dumpv_recv", "  Bitstring: "));
1858
18
    DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1859
18
    DEBUGMSG(("dumpv_recv", "\n"));
1860
1861
18
    memmove(str, bufp, asn_length);
1862
18
    *strlength = (int) asn_length;
1863
18
    *datalength -= (int) asn_length + (bufp - data);
1864
18
    return bufp + asn_length;
1865
31
}
1866
1867
1868
/**
1869
 * @internal
1870
 * asn_build_bitstring - Builds an ASN bit string object containing the
1871
 * input string.
1872
 *
1873
 *  On entry, datalength is input as the number of valid bytes following
1874
 *   "data".  On exit, it is returned as the number of valid bytes
1875
 *   following the beginning of the next object.
1876
 *
1877
 *  Returns a pointer to the first byte past the end
1878
 *   of this object (i.e. the start of the next object).
1879
 *  Returns NULL on any error.
1880
 *
1881
 * @param data         IN - pointer to start of object
1882
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1883
 * @param type         IN - asn type of object
1884
 * @param string       IN - pointer to start of input buffer
1885
 * @param strlength    IN - size of input buffer
1886
 * @return Returns a pointer to the first byte past the end
1887
 *         of this object (i.e. the start of the next object).
1888
 *         Returns NULL on any error.
1889
 */
1890
u_char         *
1891
asn_build_bitstring(u_char * data,
1892
                    size_t * datalength,
1893
                    u_char type, const u_char * str, size_t strlength)
1894
0
{
1895
    /*
1896
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1897
     */
1898
0
    static const char *errpre = "build bitstring";
1899
0
    if (_asn_bitstring_check
1900
0
        (errpre, strlength, (u_char)((str) ? *str :  0)))
1901
0
        return NULL;
1902
1903
0
    data = asn_build_header(data, datalength, type, strlength);
1904
0
    if (_asn_build_header_check(errpre, data, *datalength, strlength))
1905
0
        return NULL;
1906
1907
0
    if (strlength > 0 && str)
1908
0
        memmove(data, str, strlength);
1909
0
    else if (strlength > 0 && !str) {
1910
0
        ERROR_MSG("no string passed into asn_build_bitstring\n");
1911
0
        return NULL;
1912
0
    }
1913
1914
0
    *datalength -= strlength;
1915
0
    DEBUGDUMPSETUP("send", data, strlength);
1916
0
    DEBUGMSG(("dumpv_send", "  Bitstring: "));
1917
0
    DEBUGMSGHEX(("dumpv_send", data, strlength));
1918
0
    DEBUGMSG(("dumpv_send", "\n"));
1919
0
    return data + strlength;
1920
0
}
1921
1922
/**
1923
 * @internal
1924
 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
1925
 * type.
1926
 *
1927
 *  On entry, datalength is input as the number of valid bytes following
1928
 *   "data".  On exit, it is returned as the number of valid bytes
1929
 *   following the end of this object.
1930
 *
1931
 *  Returns a pointer to the first byte past the end
1932
 *   of this object (i.e. the start of the next object).
1933
 *  Returns NULL on any error.
1934
 *
1935
 * @param data         IN - pointer to start of object
1936
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1937
 * @param type         OUT - asn type of object
1938
 * @param cp           IN/OUT - pointer to counter struct
1939
 * @param countersize  IN - size of output buffer
1940
 * @return  Returns a pointer to the first byte past the end
1941
 *          of this object (i.e. the start of the next object).
1942
 *          Returns NULL on any error.
1943
 */
1944
u_char         *
1945
asn_parse_unsigned_int64(u_char * data,
1946
                         size_t * datalength,
1947
                         u_char * type,
1948
                         struct counter64 *cp, size_t countersize)
1949
178
{
1950
    /*
1951
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1952
     */
1953
178
    static const char *errpre = "parse uint64";
1954
178
    const int       uint64sizelimit = (4 * 2) + 1;
1955
178
    register u_char *bufp = data;
1956
178
    u_long          asn_length;
1957
178
    register u_long low = 0, high = 0;
1958
1959
178
    if (countersize != sizeof(struct counter64)) {
1960
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
1961
0
        return NULL;
1962
0
    }
1963
1964
178
    if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
1965
0
        ERROR_MSG("parse uint64: NULL pointer");
1966
0
        return NULL;
1967
0
    }
1968
1969
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1970
178
    if (*datalength < 2) {
1971
0
        _asn_short_err(errpre, *datalength, 2);
1972
0
        return NULL;
1973
0
    }
1974
1975
178
    *type = *bufp++;
1976
178
    if (*type != ASN_COUNTER64
1977
91
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1978
91
            && *type != ASN_OPAQUE
1979
178
#endif
1980
178
            ) {
1981
4
        _asn_type_err(errpre, *type);
1982
4
        return NULL;
1983
4
    }
1984
174
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1985
174
    if (NULL == bufp) {
1986
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1987
0
        return NULL;
1988
0
    }
1989
1990
174
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1991
174
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1992
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_<type> */
1993
174
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
1994
0
        _asn_short_err(errpre, asn_length, 2);
1995
0
        return NULL;
1996
0
    }
1997
1998
    /*
1999
     * 64 bit counters as opaque 
2000
     */
2001
174
    if ((*type == ASN_OPAQUE) &&
2002
87
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2003
46
        (*bufp == ASN_OPAQUE_TAG1) &&
2004
46
        ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
2005
46
         (*(bufp + 1) == ASN_OPAQUE_U64))) {
2006
        /*
2007
         * change type to Counter64 or U64 
2008
         */
2009
46
        *type = *(bufp + 1);
2010
        /*
2011
         * value is encoded as special format 
2012
         */
2013
46
        *datalength = asn_length;
2014
46
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2015
46
        if (NULL == bufp) {
2016
0
            _asn_short_err("parse opaque uint64", *datalength - 2, asn_length);
2017
0
            return NULL;
2018
0
        }
2019
46
    }
2020
174
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2021
174
    if (((int) asn_length > uint64sizelimit) ||
2022
116
        (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
2023
65
        _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
2024
65
        return NULL;
2025
65
    }
2026
109
    *datalength -= (int) asn_length + (bufp - data);
2027
761
    while (asn_length--) {
2028
652
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2029
652
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2030
652
    }
2031
2032
109
    CHECK_OVERFLOW_U(high,6);
2033
109
    CHECK_OVERFLOW_U(low,6);
2034
2035
109
    cp->low = low;
2036
109
    cp->high = high;
2037
2038
109
    DEBUGIF("dumpv_recv") {
2039
109
        char            i64buf[I64CHARSZ + 1];
2040
109
        printU64(i64buf, cp);
2041
109
        DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
2042
109
    }
2043
2044
109
    return bufp;
2045
174
}
2046
2047
2048
/**
2049
 * @internal
2050
 * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
2051
 *
2052
 *  On entry, datalength is input as the number of valid bytes following
2053
 *   "data".  On exit, it is returned as the number of valid bytes
2054
 *   following the end of this object.
2055
 *
2056
 *  Returns a pointer to the first byte past the end
2057
 *   of this object (i.e. the start of the next object).
2058
 *  Returns NULL on any error.
2059
 *
2060
 * @param data         IN - pointer to start of output buffer
2061
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2062
 * @param type         IN  - asn type of object
2063
 * @param cp           IN - pointer to counter struct
2064
 * @param countersize  IN - size of input buffer
2065
 * @return  Returns a pointer to the first byte past the end
2066
 *          of this object (i.e. the start of the next object).
2067
 *          Returns NULL on any error.
2068
 */
2069
u_char         *
2070
asn_build_unsigned_int64(u_char * data,
2071
                         size_t * datalength,
2072
                         u_char type,
2073
                         const struct counter64 *cp, size_t countersize)
2074
0
{
2075
    /*
2076
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2077
     */
2078
2079
0
    uint64_t        value;
2080
0
    int             add_null_byte = 0;
2081
0
    size_t          intsize = 8;
2082
0
    u_char         *initdatap = data;
2083
2084
0
    if (countersize != sizeof(struct counter64)) {
2085
0
        _asn_size_err("build uint64", countersize, sizeof(struct counter64));
2086
0
        return NULL;
2087
0
    }
2088
2089
0
    {
2090
0
        u_long high = cp->high, low = cp->low;
2091
2092
0
        CHECK_OVERFLOW_U(high,7);
2093
0
        CHECK_OVERFLOW_U(low,7);
2094
2095
0
        value = ((uint64_t)cp->high << 32) | cp->low;
2096
0
    }
2097
2098
0
    if (value >> 63) {
2099
        /*
2100
         * if MSB is set 
2101
         */
2102
0
        add_null_byte = 1;
2103
0
        intsize++;
2104
0
    } else {
2105
        /*
2106
         * Truncate "unnecessary" bytes off of the most significant end of this
2107
         * 2's complement integer.
2108
         * There should be no sequence of 9 consecutive 1's or 0's at the most
2109
         * significant end of the integer.
2110
         */
2111
0
        static const uint64_t mask = 0xff8ull << 52;
2112
0
        while (((value & mask) == 0 || (value & mask) == mask) && intsize > 1) {
2113
0
            intsize--;
2114
0
            value <<= 8;
2115
0
        }
2116
0
    }
2117
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2118
    /*
2119
     * encode a Counter64 as an opaque (it also works in SNMPv1) 
2120
     */
2121
    /*
2122
     * turn into Opaque holding special tagged value 
2123
     */
2124
0
    if (type == ASN_OPAQUE_COUNTER64) {
2125
        /*
2126
         * put the tag and length for the Opaque wrapper 
2127
         */
2128
0
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2129
0
        if (_asn_build_header_check
2130
0
            ("build counter u64", data, *datalength, intsize + 3))
2131
0
            return NULL;
2132
2133
        /*
2134
         * put the special tag and length 
2135
         */
2136
0
        *data++ = ASN_OPAQUE_TAG1;
2137
0
        *data++ = ASN_OPAQUE_COUNTER64;
2138
0
        *data++ = (u_char) intsize;
2139
0
        *datalength = *datalength - 3;
2140
0
    } else
2141
        /*
2142
         * Encode the Unsigned int64 in an opaque 
2143
         */
2144
        /*
2145
         * turn into Opaque holding special tagged value 
2146
         */
2147
0
    if (type == ASN_OPAQUE_U64) {
2148
        /*
2149
         * put the tag and length for the Opaque wrapper 
2150
         */
2151
0
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2152
0
        if (_asn_build_header_check
2153
0
            ("build opaque u64", data, *datalength, intsize + 3))
2154
0
            return NULL;
2155
2156
        /*
2157
         * put the special tag and length 
2158
         */
2159
0
        *data++ = ASN_OPAQUE_TAG1;
2160
0
        *data++ = ASN_OPAQUE_U64;
2161
0
        *data++ = (u_char) intsize;
2162
0
        *datalength = *datalength - 3;
2163
0
    } else {
2164
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2165
0
        data = asn_build_header(data, datalength, type, intsize);
2166
0
        if (_asn_build_header_check
2167
0
            ("build uint64", data, *datalength, intsize))
2168
0
            return NULL;
2169
2170
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2171
0
    }
2172
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2173
0
    *datalength -= intsize;
2174
0
    if (add_null_byte == 1) {
2175
0
        *data++ = '\0';
2176
0
        intsize--;
2177
0
    }
2178
0
    while (intsize--) {
2179
0
        *data++ = value >> 56;
2180
0
        value <<= 8;
2181
0
    }
2182
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2183
0
    DEBUGIF("dumpv_send") {
2184
0
        char            i64buf[I64CHARSZ + 1];
2185
0
        printU64(i64buf, cp);
2186
0
        DEBUGMSG(("dumpv_send", "%s", i64buf));
2187
0
    }
2188
0
    return data;
2189
0
}
2190
2191
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2192
2193
2194
/**
2195
 * @internal
2196
 * asn_parse_signed_int64 - pulls a 64 bit signed long out of an ASN int
2197
 * type.
2198
 *
2199
 *  On entry, datalength is input as the number of valid bytes following
2200
 *   "data".  On exit, it is returned as the number of valid bytes
2201
 *   following the end of this object.
2202
 *
2203
 *  Returns a pointer to the first byte past the end
2204
 *   of this object (i.e. the start of the next object).
2205
 *  Returns NULL on any error.
2206
 
2207
 * @param data         IN - pointer to start of object
2208
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2209
 * @param type         OUT - asn type of object
2210
 * @param cp           IN/OUT - pointer to counter struct
2211
 * @param countersize  IN - size of output buffer
2212
 * @return  Returns a pointer to the first byte past the end
2213
 *          of this object (i.e. the start of the next object).
2214
 *          Returns NULL on any error.
2215
 */
2216
2217
u_char         *
2218
asn_parse_signed_int64(u_char * data,
2219
                       size_t * datalength,
2220
                       u_char * type,
2221
                       struct counter64 *cp, size_t countersize)
2222
221
{
2223
221
    static const char *errpre = "parse int64";
2224
221
    const int       int64sizelimit = (4 * 2) + 1;
2225
221
    char            ebuf[128];
2226
221
    register u_char *bufp = data;
2227
221
    u_long          asn_length;
2228
221
    register u_int  low = 0, high = 0;
2229
2230
221
    if (countersize != sizeof(struct counter64)) {
2231
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
2232
0
        return NULL;
2233
0
    }
2234
2235
221
    if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
2236
0
        ERROR_MSG("parse int64: NULL pointer");
2237
0
        return NULL;
2238
0
    }
2239
2240
    /** need at least 2 bytes to work with: type, length (which might be 0) */
2241
221
    if (*datalength < 2) {
2242
0
        _asn_short_err(errpre, *datalength, 2);
2243
0
        return NULL;
2244
0
    }
2245
2246
221
    *type = *bufp++;
2247
221
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2248
221
    if (NULL == bufp) {
2249
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2250
0
        return NULL;
2251
0
    }
2252
2253
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_I64 */
2254
221
    if (asn_length < 2) {
2255
6
        _asn_short_err(errpre, asn_length, 2);
2256
6
        return NULL;
2257
6
    }
2258
2259
215
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2260
215
    if ((*type == ASN_OPAQUE) &&
2261
204
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2262
169
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
2263
        /*
2264
         * change type to Int64 
2265
         */
2266
169
        *type = *(bufp + 1);
2267
        /*
2268
         * value is encoded as special format 
2269
         */
2270
169
        *datalength = asn_length;
2271
169
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2272
169
        if (NULL == bufp) {
2273
0
            _asn_short_err("parse opaque int64", *datalength - 2, asn_length);
2274
0
            return NULL;
2275
0
        }
2276
169
    }
2277
    /*
2278
     * this should always have been true until snmp gets int64 PDU types 
2279
     */
2280
46
    else {
2281
46
        snprintf(ebuf, sizeof(ebuf),
2282
46
                "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
2283
46
                errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
2284
46
        ERROR_MSG(ebuf);
2285
46
        return NULL;
2286
46
    }
2287
169
    if (((int) asn_length > int64sizelimit) ||
2288
169
        (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
2289
8
        _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
2290
8
        return NULL;
2291
8
    }
2292
161
    *datalength -= (int) asn_length + (bufp - data);
2293
161
    if ((asn_length > 0) && (*bufp & 0x80)) {
2294
49
        low = 0xFFFFFFFFU;   /* first byte bit 1 means start the data with 1s */
2295
49
        high = 0xFFFFFF;
2296
49
    }
2297
2298
1.06k
    for ( ; asn_length; asn_length--) {
2299
905
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2300
905
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2301
905
    }
2302
2303
161
    CHECK_OVERFLOW_U(high,8);
2304
161
    CHECK_OVERFLOW_U(low,8);
2305
2306
161
    cp->low = low;
2307
161
    cp->high = high;
2308
2309
161
    DEBUGIF("dumpv_recv") {
2310
161
        char            i64buf[I64CHARSZ + 1];
2311
161
        printI64(i64buf, cp);
2312
161
        DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
2313
161
    }
2314
2315
161
    return bufp;
2316
169
}
2317
2318
2319
2320
/**
2321
 * @internal
2322
 * asn_build_signed_int64 - builds an ASN object containing a 64 bit integer.
2323
 *
2324
 *  On entry, datalength is input as the number of valid bytes following
2325
 *   "data".  On exit, it is returned as the number of valid bytes
2326
 *   following the end of this object.
2327
 *
2328
 *  Returns a pointer to the first byte past the end
2329
 *   of this object (i.e. the start of the next object).
2330
 *  Returns NULL on any error.
2331
 *
2332
 * @param data         IN - pointer to start of output buffer
2333
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2334
 * @param type         IN  - asn type of object
2335
 * @param cp           IN - pointer to counter struct
2336
 * @param countersize  IN - size of input buffer
2337
 * @return  Returns a pointer to the first byte past the end
2338
 *          of this object (i.e. the start of the next object).
2339
 *          Returns NULL on any error.
2340
 */
2341
u_char         *
2342
asn_build_signed_int64(u_char * data,
2343
                       size_t * datalength,
2344
                       u_char type,
2345
                       const struct counter64 *cp, size_t countersize)
2346
0
{
2347
    /*
2348
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2349
     */
2350
2351
0
    register u_int  mask, mask2;
2352
0
    u_long          low;
2353
0
    long            high; /* MUST be signed because of CHECK_OVERFLOW_S(). */
2354
0
    size_t          intsize;
2355
0
    u_char         *initdatap = data;
2356
2357
0
    if (countersize != sizeof(struct counter64)) {
2358
0
        _asn_size_err("build int64", countersize,
2359
0
                      sizeof(struct counter64));
2360
0
        return NULL;
2361
0
    }
2362
0
    intsize = 8;
2363
0
    low = cp->low;
2364
0
    high = cp->high; /* unsigned to signed conversion */
2365
2366
0
    CHECK_OVERFLOW_S(high,9);
2367
0
    CHECK_OVERFLOW_U(low,9);
2368
2369
    /*
2370
     * Truncate "unnecessary" bytes off of the most significant end of this
2371
     * 2's complement integer.  There should be no sequence of 9
2372
     * consecutive 1's or 0's at the most significant end of the
2373
     * integer.
2374
     */
2375
0
    mask = 0xFF000000U;
2376
0
    mask2 = 0xFF800000U;
2377
0
    while ((((high & mask2) == 0) || ((high & mask2) == mask2))
2378
0
           && intsize > 1) {
2379
0
        intsize--;
2380
0
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2381
0
        low = (low & 0x00ffffff) << 8;
2382
0
    }
2383
    /*
2384
     * until a real int64 gets incorperated into SNMP, we are going to
2385
     * encode it as an opaque instead.  First, we build the opaque
2386
     * header and then the int64 tag type we use to mark it as an
2387
     * int64 in the opaque string. 
2388
     */
2389
0
    data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2390
0
    if (_asn_build_header_check
2391
0
        ("build int64", data, *datalength, intsize + 3))
2392
0
        return NULL;
2393
2394
0
    *data++ = ASN_OPAQUE_TAG1;
2395
0
    *data++ = ASN_OPAQUE_I64;
2396
0
    *data++ = (u_char) intsize;
2397
0
    *datalength -= (3 + intsize);
2398
2399
0
    while (intsize--) {
2400
0
        *data++ = (u_char) (high >> 24);
2401
0
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2402
0
        low = (low & 0x00ffffff) << 8;
2403
0
    }
2404
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2405
0
    DEBUGIF("dumpv_send") {
2406
0
        char            i64buf[I64CHARSZ + 1];
2407
0
        printU64(i64buf, cp);
2408
0
        DEBUGMSG(("dumpv_send", "%s\n", i64buf));
2409
0
    }
2410
0
    return data;
2411
0
}
2412
2413
2414
/**
2415
 * @internal
2416
 * asn_parse_float - pulls a single precision floating-point out of an opaque type.
2417
 *
2418
 *  On entry, datalength is input as the number of valid bytes following
2419
 *   "data".  On exit, it is returned as the number of valid bytes
2420
 *   following the end of this object.
2421
 *
2422
 *  Returns a pointer to the first byte past the end
2423
 *   of this object (i.e. the start of the next object).
2424
 *  Returns NULL on any error.
2425
 *
2426
 * @param data         IN - pointer to start of object
2427
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2428
 * @param type         OUT - asn type of object
2429
 * @param floatp       IN/OUT - pointer to float
2430
 * @param floatsize    IN - size of output buffer
2431
 * @return  Returns a pointer to the first byte past the end
2432
 *          of this object (i.e. the start of the next object).
2433
 *          Returns NULL on any error.
2434
 */
2435
u_char         *
2436
asn_parse_float(u_char * data,
2437
                size_t * datalength,
2438
                u_char * type, float *floatp, size_t floatsize)
2439
24
{
2440
24
    static const char *errpre = "parse float";
2441
24
    register u_char *bufp = data;
2442
24
    u_long          asn_length;
2443
24
    union {
2444
24
        float           floatVal;
2445
24
        long            longVal;
2446
24
        u_char          c[sizeof(float)];
2447
24
    } fu;
2448
2449
24
    if (floatsize != sizeof(float)) {
2450
0
        _asn_size_err("parse float", floatsize, sizeof(float));
2451
0
        return NULL;
2452
0
    }
2453
2454
24
    if (NULL == data || NULL == datalength || NULL == type || NULL == floatp) {
2455
0
        ERROR_MSG("parse float: NULL pointer");
2456
0
        return NULL;
2457
0
    }
2458
2459
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
2460
24
    if (*datalength < 2) {
2461
0
        _asn_short_err(errpre, *datalength, 2);
2462
0
        return NULL;
2463
0
    }
2464
2465
24
    *type = *bufp++;
2466
24
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2467
24
    if (NULL == bufp) {
2468
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2469
0
        return NULL;
2470
0
    }
2471
2472
24
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2473
    /*
2474
     * the float is encoded as an opaque 
2475
     */
2476
24
    if ((*type == ASN_OPAQUE) &&
2477
16
        (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
2478
1
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
2479
2480
        /*
2481
         * value is encoded as special format 
2482
         */
2483
1
        *datalength = asn_length;
2484
1
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2485
1
        if (NULL == bufp) {
2486
0
            _asn_short_err("parse opaque float", *datalength - 2, asn_length);
2487
0
            return NULL;
2488
0
        }
2489
        /*
2490
         * change type to Float 
2491
         */
2492
1
        *type = ASN_OPAQUE_FLOAT;
2493
1
    }
2494
2495
24
    if (*type != ASN_OPAQUE_FLOAT) {
2496
15
        _asn_type_err(errpre, *type);
2497
15
        return NULL;
2498
15
    }
2499
2500
9
    if (asn_length != sizeof(float)) {
2501
5
        _asn_size_err("parse seq float", asn_length, sizeof(float));
2502
5
        return NULL;
2503
5
    }
2504
2505
4
    *datalength -= (int) asn_length + (bufp - data);
2506
4
    memcpy(&fu.c[0], bufp, asn_length);
2507
2508
    /*
2509
     * correct for endian differences 
2510
     */
2511
4
    fu.longVal = ntohl(fu.longVal);
2512
2513
4
    *floatp = fu.floatVal;
2514
2515
4
    DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
2516
4
    return bufp;
2517
9
}
2518
2519
/**
2520
 * @internal
2521
 * asn_build_float - builds an ASN object containing a single precision floating-point
2522
 *                    number in an Opaque value.
2523
 *
2524
 *  On entry, datalength is input as the number of valid bytes following
2525
 *   "data".  On exit, it is returned as the number of valid bytes
2526
 *   following the end of this object.
2527
 *
2528
 *  Returns a pointer to the first byte past the end
2529
 *   of this object (i.e. the start of the next object).
2530
 *  Returns NULL on any error.
2531
 *
2532
 * @param data         IN - pointer to start of object
2533
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2534
 * @param type         IN - asn type of object
2535
 * @param floatp       IN - pointer to float
2536
 * @param floatsize    IN - size of input buffer
2537
 * @return  Returns a pointer to the first byte past the end
2538
 *          of this object (i.e. the start of the next object).
2539
 *          Returns NULL on any error.
2540
2541
 */
2542
u_char         *
2543
asn_build_float(u_char * data,
2544
                size_t * datalength,
2545
                u_char type, const float *floatp, size_t floatsize)
2546
0
{
2547
0
    union {
2548
0
        float           floatVal;
2549
0
        int             intVal;
2550
0
        u_char          c[sizeof(float)];
2551
0
    } fu;
2552
0
    u_char         *initdatap = data;
2553
2554
0
    if (floatsize != sizeof(float)) {
2555
0
        _asn_size_err("build float", floatsize, sizeof(float));
2556
0
        return NULL;
2557
0
    }
2558
    /*
2559
     * encode the float as an opaque 
2560
     */
2561
    /*
2562
     * turn into Opaque holding special tagged value 
2563
     */
2564
2565
    /*
2566
     * put the tag and length for the Opaque wrapper 
2567
     */
2568
0
    data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
2569
0
    if (_asn_build_header_check
2570
0
        ("build float", data, *datalength, (floatsize + 3)))
2571
0
        return NULL;
2572
2573
    /*
2574
     * put the special tag and length 
2575
     */
2576
0
    *data++ = ASN_OPAQUE_TAG1;
2577
0
    *data++ = ASN_OPAQUE_FLOAT;
2578
0
    *data++ = (u_char) floatsize;
2579
0
    *datalength = *datalength - 3;
2580
2581
0
    fu.floatVal = *floatp;
2582
    /*
2583
     * correct for endian differences 
2584
     */
2585
0
    fu.intVal = htonl(fu.intVal);
2586
2587
0
    *datalength -= floatsize;
2588
0
    memcpy(data, &fu.c[0], floatsize);
2589
2590
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2591
0
    DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
2592
0
    data += floatsize;
2593
0
    return data;
2594
0
}
2595
2596
2597
/**
2598
 * @internal
2599
 * asn_parse_double - pulls a double out of an opaque type.
2600
 *
2601
 *  On entry, datalength is input as the number of valid bytes following
2602
 *   "data".  On exit, it is returned as the number of valid bytes
2603
 *   following the end of this object.
2604
 *
2605
 *  Returns a pointer to the first byte past the end
2606
 *   of this object (i.e. the start of the next object).
2607
 *  Returns NULL on any error.
2608
 *
2609
 * @param data         IN - pointer to start of object
2610
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2611
 * @param type         OUT - asn type of object
2612
 * @param doublep       IN/OUT - pointer to double
2613
 * @param doublesize    IN - size of output buffer
2614
 * @return  Returns a pointer to the first byte past the end
2615
 *          of this object (i.e. the start of the next object).
2616
 *          Returns NULL on any error.
2617
 */
2618
u_char         *
2619
asn_parse_double(u_char * data,
2620
                 size_t * datalength,
2621
                 u_char * type, double *doublep, size_t doublesize)
2622
19
{
2623
19
    static const char *errpre = "parse double";
2624
19
    register u_char *bufp = data;
2625
19
    u_long          asn_length;
2626
19
    long            tmp;
2627
19
    union {
2628
19
        double          doubleVal;
2629
19
        int             intVal[2];
2630
19
        u_char          c[sizeof(double)];
2631
19
    } fu;
2632
2633
2634
19
    if (doublesize != sizeof(double)) {
2635
0
        _asn_size_err("parse double", doublesize, sizeof(double));
2636
0
        return NULL;
2637
0
    }
2638
2639
19
    if (NULL == data || NULL == datalength || NULL == type || NULL == doublep) {
2640
0
        ERROR_MSG("parse double: NULL pointer");
2641
0
        return NULL;
2642
0
    }
2643
2644
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
2645
19
    if (*datalength < 2) {
2646
0
        _asn_short_err(errpre, *datalength, 2);
2647
0
        return NULL;
2648
0
    }
2649
2650
19
    *type = *bufp++;
2651
19
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2652
19
    if (NULL == bufp) {
2653
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2654
0
        return NULL;
2655
0
    }
2656
2657
19
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2658
    /*
2659
     * the double is encoded as an opaque 
2660
     */
2661
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_DOUBLE */
2662
19
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2663
0
        _asn_short_err(errpre, asn_length, 2);
2664
0
        return NULL;
2665
0
    }
2666
19
    if ((*type == ASN_OPAQUE) &&
2667
10
        (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2668
2
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2669
2670
        /*
2671
         * value is encoded as special format 
2672
         */
2673
2
        *datalength = asn_length;
2674
2
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2675
2
        if (NULL == bufp) {
2676
0
            _asn_short_err("parse opaque double", *datalength - 2, asn_length);
2677
0
            return NULL;
2678
0
        }
2679
2680
        /*
2681
         * change type to Double 
2682
         */
2683
2
        *type = ASN_OPAQUE_DOUBLE;
2684
2
    }
2685
2686
19
    if (*type != ASN_OPAQUE_DOUBLE) {
2687
8
        _asn_type_err(errpre, *type);
2688
8
        return NULL;
2689
8
    }
2690
2691
11
    if (asn_length != sizeof(double)) {
2692
10
        _asn_size_err("parse seq double", asn_length, sizeof(double));
2693
10
        return NULL;
2694
10
    }
2695
1
    *datalength -= (int) asn_length + (bufp - data);
2696
1
    memcpy(&fu.c[0], bufp, asn_length);
2697
2698
    /*
2699
     * correct for endian differences 
2700
     */
2701
2702
1
    tmp = ntohl(fu.intVal[0]);
2703
1
    fu.intVal[0] = ntohl(fu.intVal[1]);
2704
1
    fu.intVal[1] = tmp;
2705
2706
1
    *doublep = fu.doubleVal;
2707
1
    DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
2708
2709
1
    return bufp;
2710
11
}
2711
2712
2713
/**
2714
 * @internal
2715
 * asn_build_double - builds an ASN object containing a double
2716
 *                    number in an Opaque value.
2717
 *
2718
 *  On entry, datalength is input as the number of valid bytes following
2719
 *   "data".  On exit, it is returned as the number of valid bytes
2720
 *   following the end of this object.
2721
 *
2722
 *  Returns a pointer to the first byte past the end
2723
 *   of this object (i.e. the start of the next object).
2724
 *  Returns NULL on any error.
2725
 *
2726
 * @param data         IN - pointer to start of object
2727
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2728
 * @param type         IN - asn type of object
2729
 * @param doublep      IN - pointer to double
2730
 * @param doublesize   IN - size of input buffer
2731
 * @return  Returns a pointer to the first byte past the end
2732
 *          of this object (i.e. the start of the next object).
2733
 *          Returns NULL on any error.
2734
 */
2735
u_char         *
2736
asn_build_double(u_char * data,
2737
                 size_t * datalength,
2738
                 u_char type, const double *doublep, size_t doublesize)
2739
0
{
2740
0
    long            tmp;
2741
0
    union {
2742
0
        double          doubleVal;
2743
0
        int             intVal[2];
2744
0
        u_char          c[sizeof(double)];
2745
0
    } fu;
2746
0
    u_char         *initdatap = data;
2747
2748
0
    if (doublesize != sizeof(double)) {
2749
0
        _asn_size_err("build double", doublesize, sizeof(double));
2750
0
        return NULL;
2751
0
    }
2752
2753
    /*
2754
     * encode the double as an opaque 
2755
     */
2756
    /*
2757
     * turn into Opaque holding special tagged value 
2758
     */
2759
2760
    /*
2761
     * put the tag and length for the Opaque wrapper 
2762
     */
2763
0
    data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
2764
0
    if (_asn_build_header_check
2765
0
        ("build double", data, *datalength, doublesize + 3))
2766
0
        return NULL;
2767
2768
    /*
2769
     * put the special tag and length 
2770
     */
2771
0
    *data++ = ASN_OPAQUE_TAG1;
2772
0
    *data++ = ASN_OPAQUE_DOUBLE;
2773
0
    *data++ = (u_char) doublesize;
2774
0
    *datalength = *datalength - 3;
2775
2776
0
    fu.doubleVal = *doublep;
2777
    /*
2778
     * correct for endian differences 
2779
     */
2780
0
    tmp = htonl(fu.intVal[0]);
2781
0
    fu.intVal[0] = htonl(fu.intVal[1]);
2782
0
    fu.intVal[1] = tmp;
2783
0
    *datalength -= doublesize;
2784
0
    memcpy(data, &fu.c[0], doublesize);
2785
2786
0
    data += doublesize;
2787
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2788
0
    DEBUGMSG(("dumpv_send", "  Opaque double: %f\n", *doublep));
2789
0
    return data;
2790
0
}
2791
2792
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2793
2794
2795
/**
2796
 * @internal
2797
 * This function increases the size of the buffer pointed to by *pkt, which
2798
 * is initially of size *pkt_len.  Contents are preserved **AT THE TOP END OF 
2799
 * THE BUFFER** (hence making this function useful for reverse encoding).
2800
 * You can change the reallocation scheme, but you **MUST** guarantee to
2801
 * allocate **AT LEAST** one extra byte.  If memory cannot be reallocated,
2802
 * then return 0; otherwise return 1.   
2803
 * 
2804
 * @param pkt     buffer to increase
2805
 * @param pkt_len initial buffer size
2806
 * 
2807
 * @return 1 on success 0 on error (memory cannot be reallocated)
2808
 */
2809
int
2810
asn_realloc(u_char ** pkt, size_t * pkt_len)
2811
0
{
2812
0
    if (pkt != NULL && pkt_len != NULL) {
2813
0
        size_t          old_pkt_len = *pkt_len;
2814
2815
0
        DEBUGMSGTL(("asn_realloc", " old_pkt %8p, old_pkt_len %" NETSNMP_PRIz
2816
0
                    "u\n", *pkt, old_pkt_len));
2817
2818
0
        if (snmp_realloc(pkt, pkt_len)) {
2819
0
            DEBUGMSGTL(("asn_realloc", " new_pkt %8p, new_pkt_len %"
2820
0
                        NETSNMP_PRIz "u\n", *pkt, *pkt_len));
2821
0
            DEBUGMSGTL(("asn_realloc", " memmove(%8p + %08" NETSNMP_PRIz
2822
0
                        "x, %8p, %08" NETSNMP_PRIz "x)\n", *pkt,
2823
0
                        *pkt_len - old_pkt_len, *pkt, old_pkt_len));
2824
0
            memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
2825
0
            memset(*pkt, ' ', *pkt_len - old_pkt_len);
2826
0
            return 1;
2827
0
        } else {
2828
0
            DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n"));
2829
0
        }
2830
0
    }
2831
0
    return 0;
2832
0
}
2833
2834
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2835
2836
/**
2837
 * @internal
2838
 * reverse  builds an ASN header for a length with
2839
 * length specified.
2840
 * 
2841
 * @param pkt     IN/OUT address of the begining of the buffer.
2842
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2843
 * @param offset  IN/OUT offset to the start of the buffer where to write
2844
 * @param r       IN if not zero reallocate the buffer to fit the 
2845
 *                needed size.
2846
 * @param length  IN - length of object
2847
 *
2848
 * @return 1 on success, 0 on error
2849
 */
2850
int
2851
asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
2852
                          size_t * offset, int r, size_t length)
2853
0
{
2854
0
    static const char *errpre = "build length";
2855
0
    char            ebuf[128];
2856
0
    int             tmp_int;
2857
0
    size_t          start_offset = *offset;
2858
2859
0
    if (length <= 0x7f) {
2860
0
        if (((*pkt_len - *offset) < 1)
2861
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2862
0
            snprintf(ebuf, sizeof(ebuf),
2863
0
                    "%s: bad length < 1 :%ld, %lu", errpre,
2864
0
                    (long)(*pkt_len - *offset), (unsigned long)length);
2865
0
            ERROR_MSG(ebuf);
2866
0
            return 0;
2867
0
        }
2868
0
        *(*pkt + *pkt_len - (++*offset)) = length;
2869
0
    } else {
2870
0
        while (length > 0xff) {
2871
0
            if (((*pkt_len - *offset) < 1)
2872
0
                && !(r && asn_realloc(pkt, pkt_len))) {
2873
0
                snprintf(ebuf, sizeof(ebuf),
2874
0
                        "%s: bad length < 1 :%ld, %lu", errpre,
2875
0
                        (long)(*pkt_len - *offset), (unsigned long)length);
2876
0
                ERROR_MSG(ebuf);
2877
0
                return 0;
2878
0
            }
2879
0
            *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2880
0
            length >>= 8;
2881
0
        }
2882
2883
0
        while ((*pkt_len - *offset) < 2) {
2884
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
2885
0
                snprintf(ebuf, sizeof(ebuf),
2886
0
                        "%s: bad length < 1 :%ld, %lu", errpre,
2887
0
                        (long)(*pkt_len - *offset), (unsigned long)length);
2888
0
                ERROR_MSG(ebuf);
2889
0
                return 0;
2890
0
            }
2891
0
        }
2892
2893
0
        *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2894
0
        tmp_int = *offset - start_offset;
2895
0
        *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
2896
0
    }
2897
2898
0
    return 1;
2899
0
}
2900
2901
/**
2902
 * @internal
2903
 * builds an ASN header for an object with the ID and
2904
 * length specified.
2905
 *
2906
 * @see asn_build_header
2907
 * 
2908
 * @param pkt     IN/OUT address of the begining of the buffer.
2909
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2910
 * @param offset  IN/OUT offset to the start of the buffer where to write
2911
 * @param r       IN if not zero reallocate the buffer to fit the 
2912
 *                needed size.
2913
 * @param type   IN - type of object
2914
 * @param length   IN - length of object
2915
 *
2916
 * @return 1 on success, 0 on error
2917
 */
2918
int
2919
asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
2920
                          size_t * offset, int r,
2921
                          u_char type, size_t length)
2922
0
{
2923
0
    char            ebuf[128];
2924
2925
0
    if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
2926
0
        if (((*pkt_len - *offset) < 1)
2927
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2928
0
            snprintf(ebuf, sizeof(ebuf),
2929
0
                    "bad header length < 1 :%ld, %lu",
2930
0
                    (long)(*pkt_len - *offset), (unsigned long)length);
2931
0
            ERROR_MSG(ebuf);
2932
0
            return 0;
2933
0
        }
2934
0
        *(*pkt + *pkt_len - (++*offset)) = type;
2935
0
        return 1;
2936
0
    }
2937
0
    return 0;
2938
0
}
2939
2940
/**
2941
 * @internal
2942
 * builds an ASN object containing an int.
2943
 *
2944
 * @see asn_build_int
2945
 * 
2946
 * @param pkt     IN/OUT address of the begining of the buffer.
2947
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2948
 * @param offset  IN/OUT offset to the start of the buffer where to write
2949
 * @param r       IN if not zero reallocate the buffer to fit the 
2950
 *                needed size.
2951
 * @param type    IN - type of object
2952
 * @param intp    IN - pointer to start of long integer
2953
 * @param intsize IN - size of input buffer
2954
 *
2955
 * @return 1 on success, 0 on error
2956
 */
2957
int
2958
asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
2959
                       size_t * offset, int r,
2960
                       u_char type, const long *intp, size_t intsize)
2961
0
{
2962
0
    static const char *errpre = "build int";
2963
0
    register long   integer = *intp;
2964
0
    int             testvalue;
2965
0
    size_t          start_offset = *offset;
2966
2967
0
    if (intsize != sizeof(long)) {
2968
0
        _asn_size_err(errpre, intsize, sizeof(long));
2969
0
        return 0;
2970
0
    }
2971
2972
0
    CHECK_OVERFLOW_S(integer,10);
2973
0
    testvalue = (integer < 0) ? -1 : 0;
2974
2975
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2976
0
        return 0;
2977
0
    }
2978
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2979
0
    integer >>= 8;
2980
2981
0
    while (integer != testvalue) {
2982
0
        if (((*pkt_len - *offset) < 1)
2983
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2984
0
            return 0;
2985
0
        }
2986
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2987
0
        integer >>= 8;
2988
0
    }
2989
2990
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
2991
        /*
2992
         * Make sure left most bit is representational of the rest of the bits
2993
         * that aren't encoded.  
2994
         */
2995
0
        if (((*pkt_len - *offset) < 1)
2996
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2997
0
            return 0;
2998
0
        }
2999
0
        *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
3000
0
    }
3001
3002
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3003
0
                                  (*offset - start_offset))) {
3004
0
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3005
0
                                            (*offset - start_offset))) {
3006
0
            return 0;
3007
0
        } else {
3008
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3009
0
                           (*offset - start_offset));
3010
0
            DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp,
3011
0
                      *intp));
3012
0
            return 1;
3013
0
        }
3014
0
    }
3015
3016
0
    return 0;
3017
0
}
3018
3019
/**
3020
 * @internal
3021
 * builds an ASN object containing an string.
3022
 *
3023
 * @see asn_build_string 
3024
 * 
3025
 * @param pkt     IN/OUT address of the begining of the buffer.
3026
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3027
 * @param offset  IN/OUT offset to the start of the buffer where to write
3028
 * @param r       IN if not zero reallocate the buffer to fit the 
3029
 *                needed size.
3030
 * @param type    IN - type of object
3031
 * @param string    IN - pointer to start of the string
3032
 * @param strlength IN - size of input buffer
3033
 *
3034
 * @return 1 on success, 0 on error
3035
 */
3036
3037
int
3038
asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
3039
                          size_t * offset, int r,
3040
                          u_char type,
3041
                          const u_char * str, size_t strlength)
3042
0
{
3043
0
    static const char *errpre = "build string";
3044
0
    size_t          start_offset = *offset;
3045
3046
0
    if (str == NULL && strlength > 0) {
3047
0
        ERROR_MSG("no string passed into asn_realloc_rbuild_string()\n");
3048
0
        return 0;
3049
0
    }
3050
3051
0
    while ((*pkt_len - *offset) < strlength) {
3052
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3053
0
            return 0;
3054
0
        }
3055
0
    }
3056
3057
0
    *offset += strlength;
3058
0
    if (str)
3059
0
        memcpy(*pkt + *pkt_len - *offset, str, strlength);
3060
3061
0
    if (asn_realloc_rbuild_header
3062
0
        (pkt, pkt_len, offset, r, type, strlength)) {
3063
0
        if (_asn_realloc_build_header_check
3064
0
            (errpre, pkt, pkt_len, strlength)) {
3065
0
            return 0;
3066
0
        } else {
3067
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3068
0
                           *offset - start_offset);
3069
0
            DEBUGIF("dumpv_send") {
3070
0
                if (strlength == 0) {
3071
0
                    DEBUGMSG(("dumpv_send", "  String: [NULL]\n"));
3072
0
                } else {
3073
0
                    u_char         *buf = (u_char *) malloc(2 * strlength);
3074
0
                    size_t          l =
3075
0
                        (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3076
3077
0
                    if (sprint_realloc_asciistring
3078
0
                        (&buf, &l, &ol, 1, str, strlength)) {
3079
0
                        DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
3080
0
                    } else {
3081
0
                        if (buf == NULL) {
3082
0
                            DEBUGMSG(("dumpv_send",
3083
0
                                      "  String:\t[TRUNCATED]\n"));
3084
0
                        } else {
3085
0
                            DEBUGMSG(("dumpv_send",
3086
0
                                      "  String:\t%s [TRUNCATED]\n", buf));
3087
0
                        }
3088
0
                    }
3089
0
                    if (buf != NULL) {
3090
0
                        free(buf);
3091
0
                    }
3092
0
                }
3093
0
            }
3094
0
        }
3095
0
        return 1;
3096
0
    }
3097
3098
0
    return 0;
3099
0
}
3100
3101
/**
3102
 * @internal
3103
 * builds an ASN object containing an unsigned int.
3104
 *
3105
 * @see asn_build_unsigned_int
3106
 * 
3107
 * @param pkt     IN/OUT address of the begining of the buffer.
3108
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3109
 * @param offset  IN/OUT offset to the start of the buffer where to write
3110
 * @param r       IN if not zero reallocate the buffer to fit the 
3111
 *                needed size.
3112
 * @param type    IN - type of object
3113
 * @param intp    IN - pointer to start of unsigned int
3114
 * @param intsize IN - size of input buffer
3115
 *
3116
 * @return 1 on success, 0 on error
3117
 */
3118
int
3119
asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
3120
                                size_t * offset, int r,
3121
                            u_char type, const u_long * intp, size_t intsize)
3122
0
{
3123
0
    static const char *errpre = "build uint";
3124
0
    register u_long integer = *intp;
3125
0
    size_t          start_offset = *offset;
3126
3127
0
    if (intsize != sizeof(unsigned long)) {
3128
0
        _asn_size_err(errpre, intsize, sizeof(unsigned long));
3129
0
        return 0;
3130
0
    }
3131
3132
0
    CHECK_OVERFLOW_U(integer,11);
3133
3134
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3135
0
        return 0;
3136
0
    }
3137
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3138
0
    integer >>= 8;
3139
3140
0
    while (integer != 0) {
3141
0
        if (((*pkt_len - *offset) < 1)
3142
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3143
0
            return 0;
3144
0
        }
3145
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3146
0
        integer >>= 8;
3147
0
    }
3148
3149
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3150
        /*
3151
         * Make sure left most bit is representational of the rest of the bits
3152
         * that aren't encoded.  
3153
         */
3154
0
        if (((*pkt_len - *offset) < 1)
3155
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3156
0
            return 0;
3157
0
        }
3158
0
        *(*pkt + *pkt_len - (++*offset)) = 0;
3159
0
    }
3160
3161
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3162
0
                                  (*offset - start_offset))) {
3163
0
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3164
0
                                            (*offset - start_offset))) {
3165
0
            return 0;
3166
0
        } else {
3167
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3168
0
                           (*offset - start_offset));
3169
0
            DEBUGMSG(("dumpv_send", "  UInteger:\t%lu (0x%.2lX)\n", *intp,
3170
0
                      *intp));
3171
0
            return 1;
3172
0
        }
3173
0
    }
3174
3175
0
    return 0;
3176
0
}
3177
3178
/**
3179
 * @internal
3180
 * builds an ASN object containing an sequence.
3181
 *
3182
 * @see asn_build_sequence
3183
 * 
3184
 * @param pkt     IN/OUT address of the begining of the buffer.
3185
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3186
 * @param offset  IN/OUT offset to the start of the buffer where to write
3187
 * @param r       IN if not zero reallocate the buffer to fit the 
3188
 *                needed size.
3189
 * @param type    IN - type of object
3190
 * @param length IN - length of object
3191
 *
3192
 * @return 1 on success, 0 on error
3193
 */
3194
3195
int
3196
asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
3197
                            size_t * offset, int r,
3198
                            u_char type, size_t length)
3199
0
{
3200
0
    return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3201
0
                                     length);
3202
0
}
3203
3204
/**
3205
 * @internal
3206
 * Store a single byte while reverse encoding.
3207
 * @param pkt[in|out]     Start of the buffer.
3208
 * @param pkt_len[in|out] Size of the buffer in bytes.
3209
 * @param offset[in|out]  Offset from the end of the buffer where to write.
3210
 * @param r[in]           If not zero, increase the buffer size if needed.
3211
 * @param byte[in]        Data to store.
3212
 *
3213
 * @return 1 on success, 0 on error.
3214
 */
3215
static int store_byte(uint8_t **pkt, size_t *pkt_len, size_t *offset, int r,
3216
                      uint8_t byte)
3217
0
{
3218
0
    netsnmp_assert(*offset <= *pkt_len);
3219
0
    if (*offset >= *pkt_len && (!r || !asn_realloc(pkt, pkt_len)))
3220
0
        return 0;
3221
0
    netsnmp_assert(*offset < *pkt_len);
3222
0
    *(*pkt + *pkt_len - (++*offset)) = byte;
3223
0
    return 1;
3224
0
}
3225
3226
/**
3227
 * @internal
3228
 * Store 32 bits while reverse encoding.
3229
 * @param pkt[in|out]     Start of the buffer.
3230
 * @param pkt_len[in|out] Size of the buffer in bytes.
3231
 * @param offset[in|out]  Offset from the end of the buffer where to write.
3232
 * @param r[in]           If not zero, increase the buffer size if needed.
3233
 * @param subid[in]       Data to store.
3234
 *
3235
 * @return 1 on success, 0 on error.
3236
 */
3237
static int store_uint32(uint8_t **pkt, size_t *pkt_len, size_t *offset, int r,
3238
                        uint32_t subid)
3239
0
{
3240
0
    if (!store_byte(pkt, pkt_len, offset, r, subid & 0x7f))
3241
0
        return 0;
3242
3243
0
    for (subid >>= 7; subid; subid >>= 7)
3244
0
        if (!store_byte(pkt, pkt_len, offset, r, subid | 0x80))
3245
0
            return 0;
3246
3247
0
    return 1;
3248
0
}
3249
3250
/**
3251
 * @internal
3252
 * builds an ASN object containing an objid.
3253
 *
3254
 * @see asn_build_objid
3255
 * 
3256
 * @param pkt     IN/OUT address of the begining of the buffer.
3257
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3258
 * @param offset  IN/OUT offset to the start of the buffer where to write
3259
 * @param r       IN if not zero reallocate the buffer to fit the 
3260
 *                needed size.
3261
 * @param type    IN - type of object
3262
 * @param objid   IN - pointer to the object id
3263
 * @param objidlength  IN - length of the input 
3264
 *
3265
 * @return 1 on success, 0 on error
3266
 */
3267
3268
int
3269
asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
3270
                         size_t * offset, int r,
3271
                         u_char type,
3272
                         const oid * objid, size_t objidlength)
3273
0
{
3274
    /*
3275
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
3276
     * subidentifier ::= {leadingbyte}* lastbyte
3277
     * leadingbyte ::= 1 7bitvalue
3278
     * lastbyte ::= 0 7bitvalue
3279
     */
3280
0
    register size_t i;
3281
0
    register oid    tmpint;
3282
0
    size_t          start_offset = *offset;
3283
0
    const char     *errpre = "build objid";
3284
3285
    /*
3286
     * Check if there are at least 2 sub-identifiers.  
3287
     */
3288
0
    if (objidlength == 0) {
3289
        /*
3290
         * There are not, so make the OID have two sub-identifiers with value
3291
         * zero. Encode both sub-identifiers as a single byte.
3292
         */
3293
0
        if (!store_byte(pkt, pkt_len, offset, r, 0))
3294
0
            return 0;
3295
0
    } else if (objid[0] > 2) {
3296
0
        ERROR_MSG("build objid: bad first subidentifier");
3297
0
        return 0;
3298
0
    } else if (objidlength == 1) {
3299
        /*
3300
         * Encode the first value.  
3301
         */
3302
0
        if (!store_byte(pkt, pkt_len, offset, r, 40 * objid[0]))
3303
0
            return 0;
3304
0
    } else {
3305
0
        for (i = objidlength - 1; i >= 2; i--) {
3306
0
            tmpint = objid[i];
3307
0
            CHECK_OVERFLOW_U(tmpint, 12);
3308
0
            if (!store_uint32(pkt, pkt_len, offset, r, tmpint))
3309
0
                return 0;
3310
0
        }
3311
3312
        /*
3313
         * Combine the first two values.  
3314
         */
3315
0
        if ((objid[1] >= 40 && objid[0] < 2) ||
3316
0
            objid[1] > UINT32_MAX - objid[0] * 40) {
3317
0
            return 0;
3318
0
        }
3319
0
        if (!store_uint32(pkt, pkt_len, offset, r, objid[0] * 40 + objid[1]))
3320
0
            return 0;
3321
0
    }
3322
3323
0
    tmpint = *offset - start_offset;
3324
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, tmpint)) {
3325
0
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, tmpint)) {
3326
0
            return 0;
3327
0
        } else {
3328
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), tmpint);
3329
0
            DEBUGMSG(("dumpv_send", "  ObjID: "));
3330
0
            DEBUGMSGOID(("dumpv_send", objid, objidlength));
3331
0
            DEBUGMSG(("dumpv_send", "\n"));
3332
0
            return 1;
3333
0
        }
3334
0
    }
3335
3336
0
    return 0;
3337
0
}
3338
3339
/**
3340
 * @internal
3341
 * builds an ASN object containing an null object.
3342
 *
3343
 * @see asn_build_null
3344
 * 
3345
 * @param pkt     IN/OUT address of the begining of the buffer.
3346
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3347
 * @param offset  IN/OUT offset to the start of the buffer where to write
3348
 * @param r       IN if not zero reallocate the buffer to fit the 
3349
 *                needed size.
3350
 * @param type    IN - type of object
3351
 *
3352
 * @return 1 on success, 0 on error
3353
 */
3354
3355
int
3356
asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
3357
                        size_t * offset, int r, u_char type)
3358
0
{
3359
    /*
3360
     * ASN.1 null ::= 0x05 0x00
3361
     */
3362
0
    size_t          start_offset = *offset;
3363
3364
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
3365
0
        DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3366
0
                       (*offset - start_offset));
3367
0
        DEBUGMSG(("dumpv_send", "  NULL\n"));
3368
0
        return 1;
3369
0
    } else {
3370
0
        return 0;
3371
0
    }
3372
0
}
3373
3374
/**
3375
 * @internal
3376
 * builds an ASN object containing an bitstring.
3377
 *
3378
 * @see asn_build_bitstring
3379
 * 
3380
 * @param pkt     IN/OUT address of the begining of the buffer.
3381
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3382
 * @param offset  IN/OUT offset to the start of the buffer where to write
3383
 * @param r       IN if not zero reallocate the buffer to fit the 
3384
 *                needed size.
3385
 * @param type    IN - type of object
3386
 * @param string   IN - pointer to the string
3387
 * @param strlength  IN - length of the input 
3388
 *
3389
 * @return 1 on success, 0 on error
3390
 */
3391
3392
int
3393
asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
3394
                             size_t * offset, int r,
3395
                             u_char type,
3396
                             const u_char * str, size_t strlength)
3397
0
{
3398
    /*
3399
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
3400
     */
3401
0
    static const char *errpre = "build bitstring";
3402
0
    size_t          start_offset = *offset;
3403
3404
0
    if (str == NULL && strlength > 0) {
3405
0
        ERROR_MSG("no string passed into asn_realloc_rbuild_bitstring\n");
3406
0
        return 0;
3407
0
    }
3408
3409
0
    while ((*pkt_len - *offset) < strlength) {
3410
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3411
0
            return 0;
3412
0
        }
3413
0
    }
3414
3415
0
    *offset += strlength;
3416
0
    memcpy(*pkt + *pkt_len - *offset, str, strlength);
3417
3418
0
    if (asn_realloc_rbuild_header
3419
0
        (pkt, pkt_len, offset, r, type, strlength)) {
3420
0
        if (_asn_realloc_build_header_check
3421
0
            (errpre, pkt, pkt_len, strlength)) {
3422
0
            return 0;
3423
0
        } else {
3424
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3425
0
                           *offset - start_offset);
3426
0
            DEBUGIF("dumpv_send") {
3427
0
                if (strlength == 0) {
3428
0
                    DEBUGMSG(("dumpv_send", "  Bitstring: [NULL]\n"));
3429
0
                } else {
3430
0
                    u_char         *buf = (u_char *) malloc(2 * strlength);
3431
0
                    size_t          l =
3432
0
                        (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3433
3434
0
                    if (sprint_realloc_asciistring
3435
0
                        (&buf, &l, &ol, 1, str, strlength)) {
3436
0
                        DEBUGMSG(("dumpv_send", "  Bitstring:\t%s\n",
3437
0
                                  buf));
3438
0
                    } else {
3439
0
                        if (buf == NULL) {
3440
0
                            DEBUGMSG(("dumpv_send",
3441
0
                                      "  Bitstring:\t[TRUNCATED]\n"));
3442
0
                        } else {
3443
0
                            DEBUGMSG(("dumpv_send",
3444
0
                                      "  Bitstring:\t%s [TRUNCATED]\n",
3445
0
                                      buf));
3446
0
                        }
3447
0
                    }
3448
0
                    if (buf != NULL) {
3449
0
                        free(buf);
3450
0
                    }
3451
0
                }
3452
0
            }
3453
0
        }
3454
0
        return 1;
3455
0
    }
3456
3457
0
    return 0;
3458
0
}
3459
3460
/**
3461
 * @internal
3462
 * builds an ASN object containing an unsigned int64.
3463
 *
3464
 * @see asn_build_unsigned_int64
3465
 * 
3466
 * @param pkt     IN/OUT address of the begining of the buffer.
3467
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3468
 * @param offset  IN/OUT offset to the start of the buffer where to write
3469
 * @param r       IN if not zero reallocate the buffer to fit the 
3470
 *                needed size.
3471
 * @param type    IN - type of object
3472
 * @param cp           IN - pointer to counter struct
3473
 * @param countersize  IN - size of input buffer
3474
 *
3475
 * @return 1 on success, 0 on error
3476
 */
3477
int
3478
asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
3479
                                  size_t * offset, int r,
3480
                                  u_char type,
3481
                               const struct counter64 *cp, size_t countersize)
3482
0
{
3483
    /*
3484
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3485
     */
3486
0
    register u_long low = cp->low, high = cp->high;
3487
0
    size_t          intsize, start_offset = *offset;
3488
0
    int             count;
3489
3490
0
    if (countersize != sizeof(struct counter64)) {
3491
0
        _asn_size_err("build uint64", countersize,
3492
0
                      sizeof(struct counter64));
3493
0
        return 0;
3494
0
    }
3495
3496
0
    CHECK_OVERFLOW_U(high,13);
3497
0
    CHECK_OVERFLOW_U(low,13);
3498
3499
    /*
3500
     * Encode the low 4 bytes first.  
3501
     */
3502
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3503
0
        return 0;
3504
0
    }
3505
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3506
0
    low >>= 8;
3507
0
    count = 1;
3508
3509
0
    while (low != 0) {
3510
0
        count++;
3511
0
        if (((*pkt_len - *offset) < 1)
3512
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3513
0
            return 0;
3514
0
        }
3515
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3516
0
        low >>= 8;
3517
0
    }
3518
3519
    /*
3520
     * Then the high byte if present.  
3521
     */
3522
0
    if (high) {
3523
        /*
3524
         * Do the rest of the low byte.  
3525
         */
3526
0
        for (; count < 4; count++) {
3527
0
            if (((*pkt_len - *offset) < 1)
3528
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3529
0
                return 0;
3530
0
            }
3531
0
            *(*pkt + *pkt_len - (++*offset)) = 0;
3532
0
        }
3533
3534
        /*
3535
         * Do high byte.  
3536
         */
3537
0
        if (((*pkt_len - *offset) < 1)
3538
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3539
0
            return 0;
3540
0
        }
3541
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3542
0
        high >>= 8;
3543
3544
0
        while (high != 0) {
3545
0
            if (((*pkt_len - *offset) < 1)
3546
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3547
0
                return 0;
3548
0
            }
3549
0
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3550
0
            high >>= 8;
3551
0
        }
3552
0
    }
3553
3554
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3555
        /*
3556
         * Make sure left most bit is representational of the rest of the bits
3557
         * that aren't encoded.  
3558
         */
3559
0
        if (((*pkt_len - *offset) < 1)
3560
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3561
0
            return 0;
3562
0
        }
3563
0
        *(*pkt + *pkt_len - (++*offset)) = 0;
3564
0
    }
3565
3566
0
    intsize = *offset - start_offset;
3567
3568
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3569
    /*
3570
     * Encode a Counter64 as an opaque (it also works in SNMPv1).  
3571
     */
3572
0
    if (type == ASN_OPAQUE_COUNTER64) {
3573
0
        while ((*pkt_len - *offset) < 5) {
3574
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3575
0
                return 0;
3576
0
            }
3577
0
        }
3578
3579
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3580
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
3581
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3582
3583
        /*
3584
         * Put the tag and length for the Opaque wrapper.  
3585
         */
3586
0
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3587
0
                                      ASN_OPAQUE, intsize + 3)) {
3588
0
            if (_asn_realloc_build_header_check
3589
0
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3590
0
                return 0;
3591
0
            }
3592
0
        } else {
3593
0
            return 0;
3594
0
        }
3595
0
    } else if (type == ASN_OPAQUE_U64) {
3596
        /*
3597
         * Encode the Unsigned int64 in an opaque.  
3598
         */
3599
0
        while ((*pkt_len - *offset) < 5) {
3600
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3601
0
                return 0;
3602
0
            }
3603
0
        }
3604
3605
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3606
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
3607
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3608
3609
        /*
3610
         * Put the tag and length for the Opaque wrapper.  
3611
         */
3612
0
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3613
0
                                      ASN_OPAQUE, intsize + 3)) {
3614
0
            if (_asn_realloc_build_header_check
3615
0
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3616
0
                return 0;
3617
0
            }
3618
0
        } else {
3619
0
            return 0;
3620
0
        }
3621
0
    } else {
3622
3623
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3624
0
        if (asn_realloc_rbuild_header
3625
0
            (pkt, pkt_len, offset, r, type, intsize)) {
3626
0
            if (_asn_realloc_build_header_check
3627
0
                ("build uint64", pkt, pkt_len, intsize)) {
3628
0
                return 0;
3629
0
            }
3630
0
        } else {
3631
0
            return 0;
3632
0
        }
3633
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3634
0
    }
3635
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3636
3637
0
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3638
0
    DEBUGMSG(("dumpv_send", "  U64:\t%lu %lu\n", cp->high, cp->low));
3639
0
    return 1;
3640
0
}
3641
3642
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3643
3644
3645
/**
3646
 * @internal
3647
 * builds an ASN object containing an signed int64.
3648
 *
3649
 * @see asn_build_signed_int64
3650
 * 
3651
 * @param pkt     IN/OUT address of the begining of the buffer.
3652
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3653
 * @param offset  IN/OUT offset to the start of the buffer where to write
3654
 * @param r       IN if not zero reallocate the buffer to fit the 
3655
 *                needed size.
3656
 * @param type    IN - type of object
3657
 * @param cp           IN - pointer to counter struct
3658
 * @param countersize  IN - size of input buffer
3659
 *
3660
 * @return 1 on success, 0 on error
3661
 */
3662
int
3663
asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
3664
                                size_t * offset, int r,
3665
                                u_char type,
3666
                                const struct counter64 *cp, size_t countersize)
3667
0
{
3668
    /*
3669
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3670
     */
3671
0
    register int32_t low = cp->low, high = cp->high;
3672
0
    size_t           intsize, start_offset = *offset;
3673
0
    int              count;
3674
0
    int32_t          testvalue = (high & 0x80000000) ? -1 : 0;
3675
3676
0
    if (countersize != sizeof(struct counter64)) {
3677
0
        _asn_size_err("build uint64", countersize,
3678
0
                      sizeof(struct counter64));
3679
0
        return 0;
3680
0
    }
3681
3682
    /*
3683
     * Encode the low 4 bytes first.  
3684
     */
3685
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3686
0
        return 0;
3687
0
    }
3688
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3689
0
    low >>= 8;
3690
0
    count = 1;
3691
3692
0
    while ((int) low != testvalue && count < 4) {
3693
0
        count++;
3694
0
        if (((*pkt_len - *offset) < 1)
3695
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3696
0
            return 0;
3697
0
        }
3698
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3699
0
        low >>= 8;
3700
0
    }
3701
3702
    /*
3703
     * Then the high byte if present.  
3704
     */
3705
0
    if (high != testvalue) {
3706
        /*
3707
         * Do the rest of the low byte.  
3708
         */
3709
0
        for (; count < 4; count++) {
3710
0
            if (((*pkt_len - *offset) < 1)
3711
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3712
0
                return 0;
3713
0
            }
3714
0
            *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3715
0
        }
3716
3717
        /*
3718
         * Do high byte.  
3719
         */
3720
0
        if (((*pkt_len - *offset) < 1)
3721
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3722
0
            return 0;
3723
0
        }
3724
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3725
0
        high >>= 8;
3726
3727
0
        while ((int) high != testvalue) {
3728
0
            if (((*pkt_len - *offset) < 1)
3729
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3730
0
                return 0;
3731
0
            }
3732
0
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3733
0
            high >>= 8;
3734
0
        }
3735
0
    }
3736
3737
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3738
        /*
3739
         * Make sure left most bit is representational of the rest of the bits
3740
         * that aren't encoded.  
3741
         */
3742
0
        if (((*pkt_len - *offset) < 1)
3743
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3744
0
            return 0;
3745
0
        }
3746
0
        *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3747
0
    }
3748
3749
0
    intsize = *offset - start_offset;
3750
3751
0
    while ((*pkt_len - *offset) < 5) {
3752
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3753
0
            return 0;
3754
0
        }
3755
0
    }
3756
3757
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3758
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
3759
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3760
3761
    /*
3762
     * Put the tag and length for the Opaque wrapper.  
3763
     */
3764
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3765
0
                                  ASN_OPAQUE, intsize + 3)) {
3766
0
        if (_asn_realloc_build_header_check
3767
0
            ("build counter u64", pkt, pkt_len, intsize + 3)) {
3768
0
            return 0;
3769
0
        }
3770
0
    } else {
3771
0
        return 0;
3772
0
    }
3773
3774
0
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3775
0
    DEBUGMSG(("dumpv_send", "  UInt64:\t%lu %lu\n", cp->high, cp->low));
3776
0
    return 1;
3777
0
}
3778
3779
/**
3780
 * @internal
3781
 * builds an ASN object containing an float.
3782
 *
3783
 * @see asn_build_float
3784
 * 
3785
 * @param pkt     IN/OUT address of the begining of the buffer.
3786
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3787
 * @param offset  IN/OUT offset to the start of the buffer where to write
3788
 * @param r       IN if not zero reallocate the buffer to fit the 
3789
 *                needed size.
3790
 * @param type       IN - type of object
3791
 * @param floatp     IN - pointer to the float
3792
 * @param floatsize  IN - size of input buffer
3793
 *
3794
 * @return 1 on success, 0 on error
3795
 */
3796
3797
int
3798
asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
3799
                         size_t * offset, int r,
3800
                         u_char type, const float *floatp, size_t floatsize)
3801
0
{
3802
0
    size_t          start_offset = *offset;
3803
0
    union {
3804
0
        float           floatVal;
3805
0
        int             intVal;
3806
0
        u_char          c[sizeof(float)];
3807
0
    } fu;
3808
3809
    /*
3810
     * Floatsize better not be larger than realistic.  
3811
     */
3812
0
    if (floatsize != sizeof(float) || floatsize > 122) {
3813
0
        return 0;
3814
0
    }
3815
3816
0
    while ((*pkt_len - *offset) < floatsize + 3) {
3817
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3818
0
            return 0;
3819
0
        }
3820
0
    }
3821
3822
    /*
3823
     * Correct for endian differences and copy value.  
3824
     */
3825
0
    fu.floatVal = *floatp;
3826
0
    fu.intVal = htonl(fu.intVal);
3827
0
    *offset += floatsize;
3828
0
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
3829
3830
    /*
3831
     * Put the special tag and length (3 bytes).  
3832
     */
3833
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
3834
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
3835
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3836
3837
    /*
3838
     * Put the tag and length for the Opaque wrapper.  
3839
     */
3840
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3841
0
                                  ASN_OPAQUE, floatsize + 3)) {
3842
0
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3843
0
                                            floatsize + 3)) {
3844
0
            return 0;
3845
0
        } else {
3846
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3847
0
                           *offset - start_offset);
3848
0
            DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
3849
0
            return 1;
3850
0
        }
3851
0
    }
3852
3853
0
    return 0;
3854
0
}
3855
3856
/**
3857
 * @internal
3858
 * builds an ASN object containing an double.
3859
 *
3860
 * @see asn_build_double
3861
 * 
3862
 * @param pkt     IN/OUT address of the begining of the buffer.
3863
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3864
 * @param offset  IN/OUT offset to the start of the buffer where to write
3865
 * @param r       IN if not zero reallocate the buffer to fit the 
3866
 *                needed size.
3867
 * @param type    IN - type of object
3868
 * @param doublep           IN - pointer to double
3869
 * @param doublesize  IN - size of input buffer
3870
 *
3871
 * @return 1 on success, 0 on error
3872
 */
3873
3874
int
3875
asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
3876
                          size_t * offset, int r,
3877
                          u_char type, const double *doublep, size_t doublesize)
3878
0
{
3879
0
    size_t          start_offset = *offset;
3880
0
    long            tmp;
3881
0
    union {
3882
0
        double          doubleVal;
3883
0
        int             intVal[2];
3884
0
        u_char          c[sizeof(double)];
3885
0
    } fu;
3886
3887
    /*
3888
     * Doublesize better not be larger than realistic.  
3889
     */
3890
0
    if (doublesize != sizeof(double) || doublesize > 122) {
3891
0
        return 0;
3892
0
    }
3893
3894
0
    while ((*pkt_len - *offset) < doublesize + 3) {
3895
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3896
0
            return 0;
3897
0
        }
3898
0
    }
3899
3900
    /*
3901
     * Correct for endian differences and copy value.  
3902
     */
3903
0
    fu.doubleVal = *doublep;
3904
0
    tmp = htonl(fu.intVal[0]);
3905
0
    fu.intVal[0] = htonl(fu.intVal[1]);
3906
0
    fu.intVal[1] = tmp;
3907
0
    *offset += doublesize;
3908
0
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
3909
3910
    /*
3911
     * Put the special tag and length (3 bytes).  
3912
     */
3913
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
3914
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
3915
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3916
3917
    /*
3918
     * Put the tag and length for the Opaque wrapper.  
3919
     */
3920
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3921
0
                                  ASN_OPAQUE, doublesize + 3)) {
3922
0
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3923
0
                                            doublesize + 3)) {
3924
0
            return 0;
3925
0
        } else {
3926
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3927
0
                           *offset - start_offset);
3928
0
            DEBUGMSG(("dumpv_send", "  Opaque Double:\t%f\n", *doublep));
3929
0
            return 1;
3930
0
        }
3931
0
    }
3932
3933
0
    return 0;
3934
0
}
3935
3936
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3937
#endif                          /*  NETSNMP_USE_REVERSE_ASNENCODING  */
3938
/**
3939
 * @}
3940
 */