Coverage Report

Created: 2026-08-13 06:18

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
0
#define CHECK_OVERFLOW_S(x,y) do {                                      \
215
0
        if (x > INT32_MAX) {                                            \
216
0
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
217
0
            x &= 0xffffffff;                                            \
218
0
        } else if (x < INT32_MIN) {                                     \
219
0
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
220
0
            x = 0 - (x & 0xffffffff);                                   \
221
0
        }                                                               \
222
0
    } while(0)
223
224
0
#define CHECK_OVERFLOW_U(x,y) do {                                      \
225
0
        if (x > UINT32_MAX) {                                           \
226
0
            x &= 0xffffffff;                                            \
227
0
            DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
228
0
        }                                                               \
229
0
    } 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
0
{
243
0
    char            ebuf[128];
244
245
0
    snprintf(ebuf, sizeof(ebuf),
246
0
            "%s size %lu: s/b %lu", str,
247
0
      (unsigned long)wrongsize, (unsigned long)rightsize);
248
0
    ERROR_MSG(ebuf);
249
0
}
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
0
{
262
0
    char            ebuf[128];
263
264
0
    snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
265
0
    ebuf[ sizeof(ebuf)-1 ] = 0;
266
0
    ERROR_MSG(ebuf);
267
0
}
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
0
{
281
0
    char            ebuf[128];
282
283
0
    snprintf(ebuf, sizeof(ebuf),
284
0
            "%s length %lu too large: exceeds %lu", str,
285
0
      (unsigned long)wrongsize, (unsigned long)rightsize);
286
0
    ERROR_MSG(ebuf);
287
0
}
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
0
{
300
0
    char            ebuf[128];
301
302
0
    snprintf(ebuf, sizeof(ebuf), "%s length %lu too short: need %lu", str,
303
0
      (unsigned long)wrongsize, (unsigned long)rightsize);
304
0
    ERROR_MSG(ebuf);
305
0
}
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
0
{
326
0
    int len_len;
327
328
0
    if (pkt_len < 1)
329
0
        return NULL;               /* always too short */
330
331
0
    if (NULL == pkt || NULL == data_len)
332
0
        return NULL;
333
334
0
    *data_len = 0;
335
336
0
    if (*pkt & 0x80) {
337
        /*
338
         * long length; first byte is length of length (after masking high bit)
339
         */
340
0
        len_len = (int) ((*pkt & ~0x80) + 1);
341
0
        if (pkt_len < len_len)
342
0
            return NULL;           /* still too short for length and data */
343
344
        /* now we know we have enough data to parse length */
345
0
        if (NULL == asn_parse_length(pkt, data_len))
346
0
            return NULL;           /* propagate error from asn_parse_length */
347
0
    } else {
348
        /*
349
         * short length; first byte is the length
350
         */
351
0
        len_len = 1;
352
0
        *data_len = *pkt;
353
0
    }
354
355
0
    if ((*data_len + len_len) > pkt_len)
356
0
        return NULL;
357
358
0
    return (pkt + len_len);
359
0
}
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
0
{
485
0
    u_long          asn_length;
486
487
0
    if (len < 2)
488
0
        return 0;               /* always too short */
489
490
0
    if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
491
0
        return -1;              /* wrong type */
492
493
0
    if (*(pkt + 1) & 0x80) {
494
        /*
495
         * long length 
496
         */
497
0
        if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
498
0
            return 0;           /* still to short, incomplete length */
499
0
        if (NULL == asn_parse_length(pkt + 1, &asn_length))
500
0
            return 0;           /* propagate error from asn_parse_length() */
501
0
        return (asn_length + 2 + (*(pkt + 1) & ~0x80));
502
0
    } else {
503
        /*
504
         * short length 
505
         */
506
0
        return (*(pkt + 1) + 2);
507
0
    }
508
0
}
509
510
static
511
    int
512
_asn_bitstring_check(const char *str, size_t asn_length, u_char datum)
513
0
{
514
0
    char            ebuf[128];
515
516
0
    if (asn_length < 1) {
517
0
        snprintf(ebuf, sizeof(ebuf),
518
0
                "%s: length %d too small", str, (int) asn_length);
519
0
        ERROR_MSG(ebuf);
520
0
        return 1;
521
0
    }
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
0
    return 0;
530
0
}
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
0
{
558
    /*
559
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
560
     */
561
0
    static const char *errpre = "parse int";
562
0
    register u_char *bufp = data;
563
0
    u_long          asn_length;
564
0
    int             i;
565
0
    union {
566
0
        long          l;
567
0
        unsigned char b[sizeof(long)];
568
0
    } value;
569
570
0
    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
0
    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
0
    if (*datalength < 2) {
582
0
        _asn_short_err(errpre, *datalength, 2);
583
0
        return NULL;
584
0
    }
585
586
0
    *type = *bufp++;
587
0
    if (*type != ASN_INTEGER) {
588
0
        _asn_type_err(errpre, *type);
589
0
        return NULL;
590
0
    }
591
592
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
593
0
    if (NULL == bufp) {
594
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
595
0
        return NULL;
596
0
    }
597
598
0
    if ((size_t) asn_length > intsize || (int) asn_length == 0) {
599
0
        _asn_length_err(errpre, (size_t) asn_length, intsize);
600
0
        return NULL;
601
0
    }
602
603
0
    *datalength -= (int) asn_length + (bufp - data);
604
605
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
606
607
0
    memset(&value.b, *bufp & 0x80 ? 0xff : 0, sizeof(value.b));
608
0
    if (NETSNMP_BIGENDIAN) {
609
0
        for (i = sizeof(long) - asn_length; asn_length--; i++)
610
0
            value.b[i] = *bufp++;
611
0
    } else {
612
0
        for (i = asn_length - 1; asn_length--; i--)
613
0
            value.b[i] = *bufp++;
614
0
    }
615
616
0
    CHECK_OVERFLOW_S(value.l, 1);
617
618
0
    DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2lX)\n", value.l, value.l));
619
620
0
    *intp = value.l;
621
0
    return bufp;
622
0
}
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
0
{
651
    /*
652
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
653
     */
654
0
    static const char *errpre = "parse uint";
655
0
    register u_char *bufp = data;
656
0
    u_long          asn_length;
657
0
    register u_long value = 0;
658
659
0
    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
0
    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
0
    if (*datalength < 2) {
671
0
        _asn_short_err(errpre, *datalength, 2);
672
0
        return NULL;
673
0
    }
674
675
0
    *type = *bufp++;
676
0
    if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
677
0
            && *type != ASN_UINTEGER) {
678
0
        _asn_type_err(errpre, *type);
679
0
        return NULL;
680
0
    }
681
682
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
683
0
    if (NULL == bufp) {
684
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
685
0
        return NULL;
686
0
    }
687
688
0
    if ((asn_length > (intsize + 1)) || ((int) asn_length == 0) ||
689
0
        ((asn_length == intsize + 1) && *bufp != 0x00)) {
690
0
        _asn_length_err(errpre, (size_t) asn_length, intsize);
691
0
        return NULL;
692
0
    }
693
0
    *datalength -= (int) asn_length + (bufp - data);
694
695
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
696
697
0
    while (asn_length--)
698
0
        value = (value << 8) | *bufp++;
699
700
0
    CHECK_OVERFLOW_U(value,2);
701
702
0
    DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2lX)\n", value, value));
703
704
0
    *intp = value;
705
0
    return bufp;
706
0
}
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
0
{
911
0
    static const char *errpre = "parse string";
912
0
    u_char         *bufp = data;
913
0
    u_long          asn_length;
914
915
0
    if (NULL == data || NULL == datalength || NULL == type || NULL == str ||
916
0
        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
0
    if (*datalength < 2) {
923
0
        _asn_short_err(errpre, *datalength, 2);
924
0
        return NULL;
925
0
    }
926
927
0
    *type = *bufp++;
928
0
    if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
929
0
            && *type != ASN_NSAP) {
930
0
        _asn_type_err(errpre, *type);
931
0
        return NULL;
932
0
    }
933
934
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
935
0
    if (NULL == bufp) {
936
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
937
0
        return NULL;
938
0
    }
939
940
0
    if (asn_length > *strlength) {
941
0
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
942
0
        return NULL;
943
0
    }
944
945
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
946
947
0
    memmove(str, bufp, asn_length);
948
0
    if (*strlength > asn_length)
949
0
        str[asn_length] = 0;
950
0
    *strlength = asn_length;
951
0
    *datalength -= asn_length + (bufp - data);
952
953
0
    DEBUGIF("dumpv_recv") {
954
0
        u_char         *buf = (u_char *) malloc(1 + asn_length);
955
0
        size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
956
957
0
        if (sprint_realloc_asciistring
958
0
            (&buf, &l, &ol, 1, str, asn_length)) {
959
0
            DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
960
0
        } 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
0
        if (buf != NULL) {
969
0
            free(buf);
970
0
        }
971
0
    }
972
973
0
    return bufp + asn_length;
974
0
}
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
0
{
1072
0
    register u_char *bufp;
1073
0
    u_long          asn_length = 0;
1074
0
    const char      *errpre = "parse header";
1075
1076
0
    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
0
    if (*datalength < 2) {
1083
0
        _asn_short_err(errpre, *datalength, 2);
1084
0
        return NULL;
1085
0
    }
1086
1087
0
    bufp = data;
1088
    /*
1089
     * this only works on data types < 30, i.e. no extension octets 
1090
     */
1091
0
    if (IS_EXTENSION_ID(*bufp)) {
1092
0
        ERROR_MSG("can't process ID >= 30");
1093
0
        return NULL;
1094
0
    }
1095
0
    *type = *bufp++;
1096
1097
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1098
0
    if (NULL == bufp) {
1099
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1100
0
        return NULL;
1101
0
    }
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
0
#endif
1113
1114
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1115
1116
0
    if ((asn_length > 2) && (*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
1117
1118
        /*
1119
         * check if 64-but counter 
1120
         */
1121
0
        switch (*(bufp + 1)) {
1122
0
        case ASN_OPAQUE_COUNTER64:
1123
0
        case ASN_OPAQUE_U64:
1124
0
        case ASN_OPAQUE_FLOAT:
1125
0
        case ASN_OPAQUE_DOUBLE:
1126
0
        case ASN_OPAQUE_I64:
1127
0
            *type = *(bufp + 1);
1128
0
            break;
1129
1130
0
        default:
1131
            /*
1132
             * just an Opaque 
1133
             */
1134
0
            *datalength = (int) asn_length;
1135
0
            return bufp;
1136
0
        }
1137
        /*
1138
         * value is encoded as special format 
1139
         */
1140
0
        *datalength = (int) asn_length;
1141
0
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
1142
0
        if (NULL == bufp) {
1143
0
            _asn_short_err("parse opaque header", *datalength - 2, asn_length);
1144
0
            return NULL;
1145
0
        }
1146
0
    }
1147
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1148
1149
0
    *datalength = (int) asn_length;
1150
1151
0
    return bufp;
1152
0
}
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
0
{                               /* error message prefix */
1172
0
    data = asn_parse_header(data, datalength, type);
1173
0
    if (data && (*type != expected_type)) {
1174
0
        char            ebuf[128];
1175
0
        snprintf(ebuf, sizeof(ebuf),
1176
0
                 "%s header type %02X: s/b %02X", estr,
1177
0
                (u_char) * type, (u_char) expected_type);
1178
0
        ERROR_MSG(ebuf);
1179
0
        return NULL;
1180
0
    }
1181
0
    return data;
1182
0
}
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
0
{
1294
0
    static const char *errpre = "parse length";
1295
0
    char            ebuf[128];
1296
0
    register u_char lengthbyte;
1297
1298
0
    if (!data || !length) {
1299
0
        ERROR_MSG("parse length: NULL pointer");
1300
0
        return NULL;
1301
0
    }
1302
0
    lengthbyte = *data;
1303
1304
0
    if (lengthbyte & ASN_LONG_LEN) {
1305
0
        lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
1306
0
        if (lengthbyte == 0) {
1307
0
            snprintf(ebuf, sizeof(ebuf),
1308
0
                     "%s: indefinite length not supported", errpre);
1309
0
            ERROR_MSG(ebuf);
1310
0
            return NULL;
1311
0
        }
1312
0
        if (lengthbyte > sizeof(long)) {
1313
0
            snprintf(ebuf, sizeof(ebuf),
1314
0
                    "%s: data length %d > %lu not supported", errpre,
1315
0
                    lengthbyte, (unsigned long)sizeof(long));
1316
0
            ERROR_MSG(ebuf);
1317
0
            return NULL;
1318
0
        }
1319
0
        data++;
1320
0
        *length = 0;            /* protect against short lengths */
1321
0
        while (lengthbyte--) {
1322
0
            *length <<= 8;
1323
0
            *length |= *data++;
1324
0
        }
1325
0
        if ((long) *length < 0) {
1326
0
            snprintf(ebuf, sizeof(ebuf),
1327
0
                     "%s: negative data length %ld\n", errpre,
1328
0
                     (long) *length);
1329
0
            ERROR_MSG(ebuf);
1330
0
            return NULL;
1331
0
        }
1332
0
        return data;
1333
0
    } else {                    /* short asnlength */
1334
0
        *length = (long) lengthbyte;
1335
0
        return data + 1;
1336
0
    }
1337
0
}
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
0
{
1436
0
    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
0
    register u_char *bufp = data;
1444
0
    register oid   *oidp = objid + 1;
1445
0
    register u_long subidentifier;
1446
0
    register long   length;
1447
0
    u_long          asn_length;
1448
0
    size_t          original_length = *objidlength;
1449
1450
0
    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
0
    if (*datalength < 2) {
1457
0
        _asn_short_err(errpre, *datalength, 2);
1458
0
        return NULL;
1459
0
    }
1460
1461
0
    *type = *bufp++;
1462
0
    if (*type != ASN_OBJECT_ID) {
1463
0
        _asn_type_err(errpre, *type);
1464
0
        return NULL;
1465
0
    }
1466
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1467
0
    if (NULL == bufp) {
1468
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1469
0
        return NULL;
1470
0
    }
1471
1472
0
    *datalength -= (int) asn_length + (bufp - data);
1473
1474
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1475
1476
    /*
1477
     * Handle invalid object identifier encodings of the form 06 00 robustly 
1478
     */
1479
0
    if (asn_length == 0)
1480
0
        objid[0] = objid[1] = 0;
1481
1482
0
    length = asn_length;
1483
0
    (*objidlength)--;           /* account for expansion of first byte */
1484
1485
0
    while (length > 0 && (*objidlength)-- > 0) {
1486
0
        subidentifier = 0;
1487
0
        do {                    /* shift and add in low order 7 bits */
1488
0
            if (subidentifier > (MAX_SUBID >> 7)) {
1489
0
                ERROR_MSG("subidentifier too large / overflow");
1490
0
                return NULL;
1491
0
            }
1492
0
            subidentifier =
1493
0
                (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1494
0
            length--;
1495
0
        } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0));        /* last byte has high bit clear */
1496
1497
0
  if (length == 0) {
1498
0
            u_char *last_byte = bufp - 1;
1499
0
            if (*last_byte & ASN_BIT8) {
1500
                /* last byte has high bit set -> wrong BER encoded OID */
1501
0
                ERROR_MSG("subidentifier syntax error");
1502
0
                return NULL;
1503
0
            }
1504
0
        }
1505
0
        if (subidentifier > MAX_SUBID) {
1506
0
            ERROR_MSG("subidentifier too large");
1507
0
            return NULL;
1508
0
        }
1509
0
        *oidp++ = (oid) subidentifier;
1510
0
    }
1511
1512
0
    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
0
    subidentifier = oidp - objid >= 2 ? objid[1] : 0;
1525
0
    if (subidentifier == 0x2B) {
1526
0
        objid[0] = 1;
1527
0
        objid[1] = 3;
1528
0
    } else {
1529
0
        if (subidentifier < 40) {
1530
0
            objid[0] = 0;
1531
0
            objid[1] = subidentifier;
1532
0
        } else if (subidentifier < 80) {
1533
0
            objid[0] = 1;
1534
0
            objid[1] = subidentifier - 40;
1535
0
        } else {
1536
0
            objid[0] = 2;
1537
0
            objid[1] = subidentifier - 80;
1538
0
        }
1539
0
    }
1540
1541
0
    *objidlength = (int) (oidp - objid);
1542
1543
0
    DEBUGMSG(("dumpv_recv", "  ObjID: "));
1544
0
    DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1545
0
    DEBUGMSG(("dumpv_recv", "\n"));
1546
0
    return bufp;
1547
0
}
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
0
{
1818
    /*
1819
     * bitstring ::= 0x03 asnlength unused {byte}*
1820
     */
1821
0
    static const char *errpre = "parse bitstring";
1822
0
    register u_char *bufp = data;
1823
0
    u_long          asn_length;
1824
1825
0
    if (NULL == data || NULL == datalength || NULL == type ||
1826
0
        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
0
    if (*datalength < 2) {
1833
0
        _asn_short_err(errpre, *datalength, 2);
1834
0
        return NULL;
1835
0
    }
1836
1837
0
    *type = *bufp++;
1838
0
    if (*type != ASN_BIT_STR) {
1839
0
        _asn_type_err(errpre, *type);
1840
0
        return NULL;
1841
0
    }
1842
1843
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1844
0
    if (NULL == bufp) {
1845
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1846
0
        return NULL;
1847
0
    }
1848
1849
0
    if ((size_t) asn_length > *strlength) {
1850
0
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
1851
0
        return NULL;
1852
0
    }
1853
0
    if (_asn_bitstring_check(errpre, asn_length, *bufp))
1854
0
        return NULL;
1855
1856
0
    DEBUGDUMPSETUP("recv", data, bufp - data);
1857
0
    DEBUGMSG(("dumpv_recv", "  Bitstring: "));
1858
0
    DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1859
0
    DEBUGMSG(("dumpv_recv", "\n"));
1860
1861
0
    memmove(str, bufp, asn_length);
1862
0
    *strlength = (int) asn_length;
1863
0
    *datalength -= (int) asn_length + (bufp - data);
1864
0
    return bufp + asn_length;
1865
0
}
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
0
{
1950
    /*
1951
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1952
     */
1953
0
    static const char *errpre = "parse uint64";
1954
0
    const int       uint64sizelimit = (4 * 2) + 1;
1955
0
    register u_char *bufp = data;
1956
0
    u_long          asn_length;
1957
0
    register u_long low = 0, high = 0;
1958
1959
0
    if (countersize != sizeof(struct counter64)) {
1960
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
1961
0
        return NULL;
1962
0
    }
1963
1964
0
    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
0
    if (*datalength < 2) {
1971
0
        _asn_short_err(errpre, *datalength, 2);
1972
0
        return NULL;
1973
0
    }
1974
1975
0
    *type = *bufp++;
1976
0
    if (*type != ASN_COUNTER64
1977
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1978
0
            && *type != ASN_OPAQUE
1979
0
#endif
1980
0
            ) {
1981
0
        _asn_type_err(errpre, *type);
1982
0
        return NULL;
1983
0
    }
1984
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1985
0
    if (NULL == bufp) {
1986
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1987
0
        return NULL;
1988
0
    }
1989
1990
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1991
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1992
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_<type> */
1993
0
    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
0
    if ((*type == ASN_OPAQUE) &&
2002
0
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2003
0
        (*bufp == ASN_OPAQUE_TAG1) &&
2004
0
        ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
2005
0
         (*(bufp + 1) == ASN_OPAQUE_U64))) {
2006
        /*
2007
         * change type to Counter64 or U64 
2008
         */
2009
0
        *type = *(bufp + 1);
2010
        /*
2011
         * value is encoded as special format 
2012
         */
2013
0
        *datalength = asn_length;
2014
0
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2015
0
        if (NULL == bufp) {
2016
0
            _asn_short_err("parse opaque uint64", *datalength - 2, asn_length);
2017
0
            return NULL;
2018
0
        }
2019
0
    }
2020
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2021
0
    if (((int) asn_length > uint64sizelimit) ||
2022
0
        (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
2023
0
        _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
2024
0
        return NULL;
2025
0
    }
2026
0
    *datalength -= (int) asn_length + (bufp - data);
2027
0
    while (asn_length--) {
2028
0
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2029
0
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2030
0
    }
2031
2032
0
    CHECK_OVERFLOW_U(high,6);
2033
0
    CHECK_OVERFLOW_U(low,6);
2034
2035
0
    cp->low = low;
2036
0
    cp->high = high;
2037
2038
0
    DEBUGIF("dumpv_recv") {
2039
0
        char            i64buf[I64CHARSZ + 1];
2040
0
        printU64(i64buf, cp);
2041
0
        DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
2042
0
    }
2043
2044
0
    return bufp;
2045
0
}
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
0
{
2223
0
    static const char *errpre = "parse int64";
2224
0
    const int       int64sizelimit = (4 * 2) + 1;
2225
0
    char            ebuf[128];
2226
0
    register u_char *bufp = data;
2227
0
    u_long          asn_length;
2228
0
    register u_int  low = 0, high = 0;
2229
2230
0
    if (countersize != sizeof(struct counter64)) {
2231
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
2232
0
        return NULL;
2233
0
    }
2234
2235
0
    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
0
    if (*datalength < 2) {
2242
0
        _asn_short_err(errpre, *datalength, 2);
2243
0
        return NULL;
2244
0
    }
2245
2246
0
    *type = *bufp++;
2247
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2248
0
    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
0
    if (asn_length < 2) {
2255
0
        _asn_short_err(errpre, asn_length, 2);
2256
0
        return NULL;
2257
0
    }
2258
2259
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2260
0
    if ((*type == ASN_OPAQUE) &&
2261
0
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2262
0
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
2263
        /*
2264
         * change type to Int64 
2265
         */
2266
0
        *type = *(bufp + 1);
2267
        /*
2268
         * value is encoded as special format 
2269
         */
2270
0
        *datalength = asn_length;
2271
0
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2272
0
        if (NULL == bufp) {
2273
0
            _asn_short_err("parse opaque int64", *datalength - 2, asn_length);
2274
0
            return NULL;
2275
0
        }
2276
0
    }
2277
    /*
2278
     * this should always have been true until snmp gets int64 PDU types 
2279
     */
2280
0
    else {
2281
0
        snprintf(ebuf, sizeof(ebuf),
2282
0
                "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
2283
0
                errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
2284
0
        ERROR_MSG(ebuf);
2285
0
        return NULL;
2286
0
    }
2287
0
    if (((int) asn_length > int64sizelimit) ||
2288
0
        (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
2289
0
        _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
2290
0
        return NULL;
2291
0
    }
2292
0
    *datalength -= (int) asn_length + (bufp - data);
2293
0
    if ((asn_length > 0) && (*bufp & 0x80)) {
2294
0
        low = 0xFFFFFFFFU;   /* first byte bit 1 means start the data with 1s */
2295
0
        high = 0xFFFFFF;
2296
0
    }
2297
2298
0
    for ( ; asn_length; asn_length--) {
2299
0
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2300
0
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2301
0
    }
2302
2303
0
    CHECK_OVERFLOW_U(high,8);
2304
0
    CHECK_OVERFLOW_U(low,8);
2305
2306
0
    cp->low = low;
2307
0
    cp->high = high;
2308
2309
0
    DEBUGIF("dumpv_recv") {
2310
0
        char            i64buf[I64CHARSZ + 1];
2311
0
        printI64(i64buf, cp);
2312
0
        DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
2313
0
    }
2314
2315
0
    return bufp;
2316
0
}
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
0
{
2440
0
    static const char *errpre = "parse float";
2441
0
    register u_char *bufp = data;
2442
0
    u_long          asn_length;
2443
0
    union {
2444
0
        float           floatVal;
2445
0
        long            longVal;
2446
0
        u_char          c[sizeof(float)];
2447
0
    } fu;
2448
2449
0
    if (floatsize != sizeof(float)) {
2450
0
        _asn_size_err("parse float", floatsize, sizeof(float));
2451
0
        return NULL;
2452
0
    }
2453
2454
0
    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
0
    if (*datalength < 2) {
2461
0
        _asn_short_err(errpre, *datalength, 2);
2462
0
        return NULL;
2463
0
    }
2464
2465
0
    *type = *bufp++;
2466
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2467
0
    if (NULL == bufp) {
2468
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2469
0
        return NULL;
2470
0
    }
2471
2472
0
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2473
    /*
2474
     * the float is encoded as an opaque 
2475
     */
2476
0
    if ((*type == ASN_OPAQUE) &&
2477
0
        (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
2478
0
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
2479
2480
        /*
2481
         * value is encoded as special format 
2482
         */
2483
0
        *datalength = asn_length;
2484
0
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2485
0
        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
0
        *type = ASN_OPAQUE_FLOAT;
2493
0
    }
2494
2495
0
    if (*type != ASN_OPAQUE_FLOAT) {
2496
0
        _asn_type_err(errpre, *type);
2497
0
        return NULL;
2498
0
    }
2499
2500
0
    if (asn_length != sizeof(float)) {
2501
0
        _asn_size_err("parse seq float", asn_length, sizeof(float));
2502
0
        return NULL;
2503
0
    }
2504
2505
0
    *datalength -= (int) asn_length + (bufp - data);
2506
0
    memcpy(&fu.c[0], bufp, asn_length);
2507
2508
    /*
2509
     * correct for endian differences 
2510
     */
2511
0
    fu.longVal = ntohl(fu.longVal);
2512
2513
0
    *floatp = fu.floatVal;
2514
2515
0
    DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
2516
0
    return bufp;
2517
0
}
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
0
{
2623
0
    static const char *errpre = "parse double";
2624
0
    register u_char *bufp = data;
2625
0
    u_long          asn_length;
2626
0
    long            tmp;
2627
0
    union {
2628
0
        double          doubleVal;
2629
0
        int             intVal[2];
2630
0
        u_char          c[sizeof(double)];
2631
0
    } fu;
2632
2633
2634
0
    if (doublesize != sizeof(double)) {
2635
0
        _asn_size_err("parse double", doublesize, sizeof(double));
2636
0
        return NULL;
2637
0
    }
2638
2639
0
    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
0
    if (*datalength < 2) {
2646
0
        _asn_short_err(errpre, *datalength, 2);
2647
0
        return NULL;
2648
0
    }
2649
2650
0
    *type = *bufp++;
2651
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2652
0
    if (NULL == bufp) {
2653
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2654
0
        return NULL;
2655
0
    }
2656
2657
0
    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
0
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2663
0
        _asn_short_err(errpre, asn_length, 2);
2664
0
        return NULL;
2665
0
    }
2666
0
    if ((*type == ASN_OPAQUE) &&
2667
0
        (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2668
0
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2669
2670
        /*
2671
         * value is encoded as special format 
2672
         */
2673
0
        *datalength = asn_length;
2674
0
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2675
0
        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
0
        *type = ASN_OPAQUE_DOUBLE;
2684
0
    }
2685
2686
0
    if (*type != ASN_OPAQUE_DOUBLE) {
2687
0
        _asn_type_err(errpre, *type);
2688
0
        return NULL;
2689
0
    }
2690
2691
0
    if (asn_length != sizeof(double)) {
2692
0
        _asn_size_err("parse seq double", asn_length, sizeof(double));
2693
0
        return NULL;
2694
0
    }
2695
0
    *datalength -= (int) asn_length + (bufp - data);
2696
0
    memcpy(&fu.c[0], bufp, asn_length);
2697
2698
    /*
2699
     * correct for endian differences 
2700
     */
2701
2702
0
    tmp = ntohl(fu.intVal[0]);
2703
0
    fu.intVal[0] = ntohl(fu.intVal[1]);
2704
0
    fu.intVal[1] = tmp;
2705
2706
0
    *doublep = fu.doubleVal;
2707
0
    DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
2708
2709
0
    return bufp;
2710
0
}
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
 */