Coverage Report

Created: 2026-10-19 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/agent/mibgroup/agentx/protocol.c
Line
Count
Source
1
/* Portions of this file are subject to the following copyright(s).  See
2
 * the Net-SNMP's COPYING file for more details and other copyrights
3
 * that may apply:
4
 */
5
/*
6
 * Portions of this file are copyrighted by:
7
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
8
 * Use is subject to license terms specified in the COPYING file
9
 * distributed with the Net-SNMP package.
10
 */
11
12
#include <net-snmp/net-snmp-config.h>
13
14
#include <limits.h>
15
#include <stdio.h>
16
#include <errno.h>
17
#ifdef HAVE_STDLIB_H
18
#include <stdlib.h>
19
#endif
20
#ifdef HAVE_STRING_H
21
#include <string.h>
22
#else
23
#include <strings.h>
24
#endif
25
#ifdef HAVE_UNISTD_H
26
#include <unistd.h>
27
#endif
28
#include <sys/types.h>
29
#ifdef TIME_WITH_SYS_TIME
30
# include <sys/time.h>
31
# include <time.h>
32
#else
33
# ifdef HAVE_SYS_TIME_H
34
#  include <sys/time.h>
35
# else
36
#  include <time.h>
37
# endif
38
#endif
39
#ifdef HAVE_NETINET_IN_H
40
#include <netinet/in.h>
41
#endif
42
#ifdef HAVE_ARPA_INET_H
43
#include <arpa/inet.h>
44
#endif
45
46
#include <net-snmp/net-snmp-includes.h>
47
48
#include "agentx/protocol.h"
49
50
const char     *
51
agentx_cmd(u_char code)
52
0
{
53
0
    switch (code) {
54
0
    case AGENTX_MSG_OPEN:
55
0
        return "Open";
56
0
    case AGENTX_MSG_CLOSE:
57
0
        return "Close";
58
0
    case AGENTX_MSG_REGISTER:
59
0
        return "Register";
60
0
    case AGENTX_MSG_UNREGISTER:
61
0
        return "Unregister";
62
0
    case AGENTX_MSG_GET:
63
0
        return "Get";
64
0
    case AGENTX_MSG_GETNEXT:
65
0
        return "Get Next";
66
0
    case AGENTX_MSG_GETBULK:
67
0
        return "Get Bulk";
68
0
    case AGENTX_MSG_TESTSET:
69
0
        return "Test Set";
70
0
    case AGENTX_MSG_COMMITSET:
71
0
        return "Commit Set";
72
0
    case AGENTX_MSG_UNDOSET:
73
0
        return "Undo Set";
74
0
    case AGENTX_MSG_CLEANUPSET:
75
0
        return "Cleanup Set";
76
0
    case AGENTX_MSG_NOTIFY:
77
0
        return "Notify";
78
0
    case AGENTX_MSG_PING:
79
0
        return "Ping";
80
0
    case AGENTX_MSG_INDEX_ALLOCATE:
81
0
        return "Index Allocate";
82
0
    case AGENTX_MSG_INDEX_DEALLOCATE:
83
0
        return "Index Deallocate";
84
0
    case AGENTX_MSG_ADD_AGENT_CAPS:
85
0
        return "Add Agent Caps";
86
0
    case AGENTX_MSG_REMOVE_AGENT_CAPS:
87
0
        return "Remove Agent Caps";
88
0
    case AGENTX_MSG_RESPONSE:
89
0
        return "Response";
90
0
    default:
91
0
        return "Unknown";
92
0
    }
93
0
}
94
95
int
96
agentx_realloc_build_int(u_char ** buf, size_t * buf_len, size_t * out_len,
97
                         int allow_realloc,
98
                         unsigned int value, int network_order)
99
699k
{
100
699k
    unsigned int    ivalue = value;
101
699k
    size_t          ilen = *out_len;
102
699k
    unsigned int    i = 0;
103
104
699k
    while ((*out_len + 4) >= *buf_len) {
105
26
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
106
0
            return 0;
107
0
        }
108
26
    }
109
110
699k
    if (network_order) {
111
151k
        if (!NETSNMP_BIGENDIAN)
112
151k
            value = ntohl(value);
113
151k
        memmove((*buf + *out_len), &value, 4);
114
151k
        *out_len += 4;
115
547k
    } else {
116
547k
        if (!NETSNMP_BIGENDIAN) {
117
547k
            memmove((*buf + *out_len), &value, 4);
118
547k
            *out_len += 4;
119
547k
        } else {
120
0
            for (i = 0; i < 4; i++) {
121
0
                *(*buf + *out_len) = (u_char) value & 0xff;
122
0
                (*out_len)++;
123
0
                value >>= 8;
124
0
            }
125
0
        }
126
547k
    }
127
699k
    DEBUGDUMPSETUP("send", (*buf + ilen), 4);
128
699k
    DEBUGMSG(("dumpv_send", "  Integer:\t%u (0x%.2X)\n", ivalue,
129
699k
              ivalue));
130
699k
    return 1;
131
699k
}
132
133
void
134
agentx_build_int(u_char * bufp, u_int value, int network_byte_order)
135
18.4k
{
136
18.4k
    u_char         *orig_bufp = bufp;
137
18.4k
    u_int           orig_val = value;
138
139
18.4k
    if (network_byte_order) {
140
6.48k
        if (!NETSNMP_BIGENDIAN)
141
6.48k
            value = ntohl(value);
142
6.48k
        memmove(bufp, &value, 4);
143
11.9k
    } else {
144
11.9k
        if (!NETSNMP_BIGENDIAN) {
145
11.9k
            memmove(bufp, &value, 4);
146
11.9k
        } else {
147
0
            *bufp = (u_char) value & 0xff;
148
0
            value >>= 8;
149
0
            bufp++;
150
0
            *bufp = (u_char) value & 0xff;
151
0
            value >>= 8;
152
0
            bufp++;
153
0
            *bufp = (u_char) value & 0xff;
154
0
            value >>= 8;
155
0
            bufp++;
156
0
            *bufp = (u_char) value & 0xff;
157
0
        }
158
11.9k
    }
159
18.4k
    DEBUGDUMPSETUP("send", orig_bufp, 4);
160
18.4k
    DEBUGMSG(("dumpv_send", "  Integer:\t%u (0x%.2X)\n", orig_val,
161
18.4k
              orig_val));
162
18.4k
}
163
164
int
165
agentx_realloc_build_short(u_char ** buf, size_t * buf_len,
166
                           size_t * out_len, int allow_realloc,
167
                           unsigned short value, int network_order)
168
166k
{
169
166k
    unsigned short  ivalue = value;
170
166k
    size_t          ilen = *out_len;
171
166k
    unsigned short  i = 0;
172
173
166k
    while ((*out_len + 2) >= *buf_len) {
174
1
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
175
0
            return 0;
176
0
        }
177
1
    }
178
179
166k
    if (network_order) {
180
40.9k
        if (!NETSNMP_BIGENDIAN)
181
40.9k
            value = ntohs(value);
182
40.9k
        memmove((*buf + *out_len), &value, 2);
183
40.9k
        *out_len += 2;
184
125k
    } else {
185
125k
        if (!NETSNMP_BIGENDIAN) {
186
125k
            memmove((*buf + *out_len), &value, 2);
187
125k
            *out_len += 2;
188
125k
        } else {
189
0
            for (i = 0; i < 2; i++) {
190
0
                *(*buf + *out_len) = (u_char) value & 0xff;
191
0
                (*out_len)++;
192
0
                value >>= 8;
193
0
            }
194
0
        }
195
125k
    }
196
166k
    DEBUGDUMPSETUP("send", (*buf + ilen), 2);
197
166k
    DEBUGMSG(("dumpv_send", "  Short:\t%hu (0x%.2hX)\n", ivalue, ivalue));
198
166k
    return 1;
199
166k
}
200
201
int
202
agentx_realloc_build_oid(u_char ** buf, size_t * buf_len, size_t * out_len,
203
                         int allow_realloc,
204
                         int inclusive, oid * name, size_t name_len,
205
                         int network_order)
206
268k
{
207
268k
    size_t          ilen = *out_len, i = 0;
208
268k
    int             prefix = 0;
209
210
268k
    DEBUGPRINTINDENT("dumpv_send");
211
268k
    DEBUGMSG(("dumpv_send", "OID: "));
212
268k
    DEBUGMSGOID(("dumpv_send", name, name_len));
213
268k
    DEBUGMSG(("dumpv_send", "\n"));
214
215
    /*
216
     * Updated clarification from the AgentX mailing list.
217
     * The "null Object Identifier" mentioned in RFC 2471,
218
     * section 5.1 is a special placeholder value, and
219
     * should only be used when explicitly mentioned in
220
     * this RFC.  In particular, it does *not* mean {0, 0}
221
     */
222
268k
    if (name_len == 0)
223
0
        inclusive = 0;
224
225
    /*
226
     * 'Compact' internet OIDs 
227
     */
228
268k
    if (name_len >= 5 && (name[0] == 1 && name[1] == 3 &&
229
32.9k
                          name[2] == 6 && name[3] == 1 &&
230
31.7k
                          name[4] > 0 && name[4] < 256)) {
231
30.2k
        prefix = name[4];
232
30.2k
        name += 5;
233
30.2k
        name_len -= 5;
234
30.2k
    }
235
236
269k
    while ((*out_len + 4 + (4 * name_len)) >= *buf_len) {
237
1.26k
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
238
0
            return 0;
239
0
        }
240
1.26k
    }
241
242
268k
    *(*buf + *out_len) = (u_char) name_len;
243
268k
    (*out_len)++;
244
268k
    *(*buf + *out_len) = (u_char) prefix;
245
268k
    (*out_len)++;
246
268k
    *(*buf + *out_len) = (u_char) inclusive;
247
268k
    (*out_len)++;
248
268k
    *(*buf + *out_len) = (u_char) 0x00;
249
268k
    (*out_len)++;
250
251
268k
    DEBUGDUMPHEADER("send", "OID Header");
252
268k
    DEBUGDUMPSETUP("send", (*buf + ilen), 4);
253
268k
    DEBUGMSG(("dumpv_send", "  # subids:\t%d (0x%.2X)\n", (int)name_len,
254
268k
              (unsigned int)name_len));
255
268k
    DEBUGPRINTINDENT("dumpv_send");
256
268k
    DEBUGMSG(("dumpv_send", "  prefix:\t%d (0x%.2X)\n", prefix, prefix));
257
268k
    DEBUGPRINTINDENT("dumpv_send");
258
268k
    DEBUGMSG(("dumpv_send", "  inclusive:\t%d (0x%.2X)\n", inclusive,
259
268k
              inclusive));
260
268k
    DEBUGINDENTLESS();
261
268k
    DEBUGDUMPHEADER("send", "OID Segments");
262
263
857k
    for (i = 0; i < name_len; i++) {
264
589k
        if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
265
589k
                                      name[i], network_order)) {
266
0
            DEBUGINDENTLESS();
267
0
            return 0;
268
0
        }
269
589k
    }
270
268k
    DEBUGINDENTLESS();
271
272
268k
    return 1;
273
268k
}
274
275
int
276
agentx_realloc_build_string(u_char ** buf, size_t * buf_len,
277
                            size_t * out_len, int allow_realloc,
278
                            u_char * string, size_t string_len,
279
                            int network_order)
280
11.5k
{
281
11.5k
    size_t          ilen = *out_len, i = 0;
282
283
11.8k
    while ((*out_len + 4 + (4 * ((string_len + 3) / 4))) >= *buf_len) {
284
306
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
285
0
            return 0;
286
0
        }
287
306
    }
288
289
11.5k
    DEBUGDUMPHEADER("send", "Build String");
290
11.5k
    DEBUGDUMPHEADER("send", "length");
291
11.5k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
292
11.5k
                                  string_len, network_order)) {
293
0
        DEBUGINDENTLESS();
294
0
        DEBUGINDENTLESS();
295
0
        return 0;
296
0
    }
297
298
11.5k
    if (string_len == 0) {
299
3.55k
        DEBUGMSG(("dumpv_send", "  String: <empty>\n"));
300
3.55k
        DEBUGINDENTLESS();
301
3.55k
        DEBUGINDENTLESS();
302
3.55k
        return 1;
303
3.55k
    }
304
305
7.94k
    memmove((*buf + *out_len), string, string_len);
306
7.94k
    *out_len += string_len;
307
308
    /*
309
     * Pad to a multiple of 4 bytes if necessary (per RFC 2741).  
310
     */
311
312
7.94k
    if (string_len % 4 != 0) {
313
13.1k
        for (i = 0; i < 4 - (string_len % 4); i++) {
314
8.86k
            *(*buf + *out_len) = 0;
315
8.86k
            (*out_len)++;
316
8.86k
        }
317
4.24k
    }
318
319
7.94k
    DEBUGDUMPSETUP("send", (*buf + ilen + 4), ((string_len + 3) / 4) * 4);
320
7.94k
    DEBUGMSG(("dumpv_send", "  String:\t%.*s\n", (int)string_len, string));
321
7.94k
    DEBUGINDENTLESS();
322
7.94k
    DEBUGINDENTLESS();
323
7.94k
    return 1;
324
11.5k
}
325
326
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
327
int
328
agentx_realloc_build_double(u_char ** buf, size_t * buf_len,
329
                            size_t * out_len, int allow_realloc,
330
                            double double_val, int network_order)
331
438
{
332
438
    union {
333
438
        double          doubleVal;
334
438
        int             intVal[2];
335
438
        char            c[sizeof(double)];
336
438
    } du;
337
438
    int             tmp;
338
438
    u_char          opaque_buffer[3 + sizeof(double)];
339
340
438
    opaque_buffer[0] = ASN_OPAQUE_TAG1;
341
438
    opaque_buffer[1] = ASN_OPAQUE_DOUBLE;
342
438
    opaque_buffer[2] = sizeof(double);
343
344
438
    du.doubleVal = double_val;
345
438
    tmp = htonl(du.intVal[0]);
346
438
    du.intVal[0] = htonl(du.intVal[1]);
347
438
    du.intVal[1] = tmp;
348
438
    memcpy(&opaque_buffer[3], &du.c[0], sizeof(double));
349
350
438
    return agentx_realloc_build_string(buf, buf_len, out_len,
351
438
                                       allow_realloc, opaque_buffer,
352
438
                                       3 + sizeof(double), network_order);
353
438
}
354
355
int
356
agentx_realloc_build_float(u_char ** buf, size_t * buf_len,
357
                           size_t * out_len, int allow_realloc,
358
                           float float_val, int network_order)
359
396
{
360
396
    union {
361
396
        float           floatVal;
362
396
        int             intVal;
363
396
        char            c[sizeof(float)];
364
396
    } fu;
365
396
    u_char          opaque_buffer[3 + sizeof(float)];
366
367
396
    opaque_buffer[0] = ASN_OPAQUE_TAG1;
368
396
    opaque_buffer[1] = ASN_OPAQUE_FLOAT;
369
396
    opaque_buffer[2] = sizeof(float);
370
371
396
    fu.floatVal = float_val;
372
396
    fu.intVal = htonl(fu.intVal);
373
396
    memcpy(&opaque_buffer[3], &fu.c[0], sizeof(float));
374
375
396
    return agentx_realloc_build_string(buf, buf_len, out_len,
376
396
                                       allow_realloc, opaque_buffer,
377
396
                                       3 + sizeof(float), network_order);
378
396
}
379
#endif
380
381
int
382
agentx_realloc_build_varbind(u_char ** buf, size_t * buf_len,
383
                             size_t * out_len, int allow_realloc,
384
                             netsnmp_variable_list * vp, int network_order)
385
131k
{
386
131k
    DEBUGDUMPHEADER("send", "VarBind");
387
131k
    DEBUGDUMPHEADER("send", "type");
388
131k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
389
131k
    if ((vp->type == ASN_OPAQUE_FLOAT) || (vp->type == ASN_OPAQUE_DOUBLE)
390
130k
        || (vp->type == ASN_OPAQUE_I64) || (vp->type == ASN_OPAQUE_U64)
391
130k
        || (vp->type == ASN_OPAQUE_COUNTER64)) {
392
834
        if (!agentx_realloc_build_short
393
834
            (buf, buf_len, out_len, allow_realloc,
394
834
             (unsigned short) ASN_OPAQUE, network_order)) {
395
0
            DEBUGINDENTLESS();
396
0
            DEBUGINDENTLESS();
397
0
            return 0;
398
0
        }
399
834
    } else
400
130k
#endif
401
130k
    if (vp->type == ASN_PRIV_INCL_RANGE || vp->type == ASN_PRIV_EXCL_RANGE) {
402
107k
        if (!agentx_realloc_build_short
403
107k
            (buf, buf_len, out_len, allow_realloc,
404
107k
             (unsigned short) ASN_OBJECT_ID, network_order)) {
405
0
            DEBUGINDENTLESS();
406
0
            DEBUGINDENTLESS();
407
0
            return 0;
408
0
        }
409
107k
    } else {
410
22.8k
        if (!agentx_realloc_build_short
411
22.8k
            (buf, buf_len, out_len, allow_realloc,
412
22.8k
             (unsigned short) vp->type, network_order)) {
413
0
            DEBUGINDENTLESS();
414
0
            DEBUGINDENTLESS();
415
0
            return 0;
416
0
        }
417
22.8k
    }
418
419
131k
    while ((*out_len + 2) >= *buf_len) {
420
399
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
421
0
            DEBUGINDENTLESS();
422
0
            DEBUGINDENTLESS();
423
0
            return 0;
424
0
        }
425
399
    }
426
427
131k
    *(*buf + *out_len) = 0;
428
131k
    (*out_len)++;
429
131k
    *(*buf + *out_len) = 0;
430
131k
    (*out_len)++;
431
131k
    DEBUGINDENTLESS();
432
433
131k
    DEBUGDUMPHEADER("send", "name");
434
131k
    if (!agentx_realloc_build_oid(buf, buf_len, out_len, allow_realloc, 0,
435
131k
                                  vp->name, vp->name_length,
436
131k
                                  network_order)) {
437
0
        DEBUGINDENTLESS();
438
0
        DEBUGINDENTLESS();
439
0
        return 0;
440
0
    }
441
131k
    DEBUGINDENTLESS();
442
443
131k
    DEBUGDUMPHEADER("send", "value");
444
131k
    switch (vp->type) {
445
446
647
    case ASN_INTEGER:
447
1.28k
    case ASN_COUNTER:
448
2.53k
    case ASN_GAUGE:
449
3.87k
    case ASN_TIMETICKS:
450
4.90k
    case ASN_UINTEGER:
451
4.90k
        if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
452
4.90k
                                      *(vp->val.integer), network_order)) {
453
0
            DEBUGINDENTLESS();
454
0
            DEBUGINDENTLESS();
455
0
            return 0;
456
0
        }
457
4.90k
        break;
458
459
4.90k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
460
4.90k
    case ASN_OPAQUE_FLOAT:
461
396
        DEBUGDUMPHEADER("send", "Build Opaque Float");
462
396
        DEBUGPRINTINDENT("dumpv_send");
463
396
        DEBUGMSG(("dumpv_send", "  Float:\t%f\n", *(vp->val.floatVal)));
464
396
        if (!agentx_realloc_build_float
465
396
            (buf, buf_len, out_len, allow_realloc, *(vp->val.floatVal),
466
396
             network_order)) {
467
0
            DEBUGINDENTLESS();
468
0
            DEBUGINDENTLESS();
469
0
            DEBUGINDENTLESS();
470
0
            return 0;
471
0
        }
472
396
        DEBUGINDENTLESS();
473
396
        break;
474
475
438
    case ASN_OPAQUE_DOUBLE:
476
438
        DEBUGDUMPHEADER("send", "Build Opaque Double");
477
438
        DEBUGPRINTINDENT("dumpv_send");
478
438
        DEBUGMSG(("dumpv_send", "  Double:\t%f\n", *(vp->val.doubleVal)));
479
438
        if (!agentx_realloc_build_double
480
438
            (buf, buf_len, out_len, allow_realloc, *(vp->val.doubleVal),
481
438
             network_order)) {
482
0
            DEBUGINDENTLESS();
483
0
            DEBUGINDENTLESS();
484
0
            DEBUGINDENTLESS();
485
0
            return 0;
486
0
        }
487
438
        DEBUGINDENTLESS();
488
438
        break;
489
490
0
    case ASN_OPAQUE_I64:
491
0
    case ASN_OPAQUE_U64:
492
0
    case ASN_OPAQUE_COUNTER64:
493
        /*
494
         * XXX - TODO - encode as raw OPAQUE for now (so fall through
495
         * here).  
496
         */
497
0
#endif
498
499
5.05k
    case ASN_OCTET_STR:
500
6.60k
    case ASN_IPADDRESS:
501
10.4k
    case ASN_OPAQUE:
502
10.4k
        if (!agentx_realloc_build_string
503
10.4k
            (buf, buf_len, out_len, allow_realloc, vp->val.string,
504
10.4k
             vp->val_len, network_order)) {
505
0
            DEBUGINDENTLESS();
506
0
            DEBUGINDENTLESS();
507
0
            return 0;
508
0
        }
509
10.4k
        break;
510
511
10.4k
    case ASN_OBJECT_ID:
512
99.1k
    case ASN_PRIV_EXCL_RANGE:
513
108k
    case ASN_PRIV_INCL_RANGE:
514
108k
        if (!agentx_realloc_build_oid
515
108k
            (buf, buf_len, out_len, allow_realloc, 1, vp->val.objid,
516
108k
             vp->val_len / sizeof(oid), network_order)) {
517
0
            DEBUGINDENTLESS();
518
0
            DEBUGINDENTLESS();
519
0
            return 0;
520
0
        }
521
108k
        break;
522
523
108k
    case ASN_COUNTER64:
524
1.01k
        if (network_order) {
525
318
            DEBUGDUMPHEADER("send", "Build Counter64 (high, low)");
526
318
            if (!agentx_realloc_build_int
527
318
                (buf, buf_len, out_len, allow_realloc,
528
318
                 vp->val.counter64->high, network_order)
529
318
                || !agentx_realloc_build_int(buf, buf_len, out_len,
530
318
                                             allow_realloc,
531
318
                                             vp->val.counter64->low,
532
318
                                             network_order)) {
533
0
                DEBUGINDENTLESS();
534
0
                DEBUGINDENTLESS();
535
0
                DEBUGINDENTLESS();
536
0
                return 0;
537
0
            }
538
318
            DEBUGINDENTLESS();
539
701
        } else {
540
701
            DEBUGDUMPHEADER("send", "Build Counter64 (low, high)");
541
701
            if (!agentx_realloc_build_int
542
701
                (buf, buf_len, out_len, allow_realloc,
543
701
                 vp->val.counter64->low, network_order)
544
701
                || !agentx_realloc_build_int(buf, buf_len, out_len,
545
701
                                             allow_realloc,
546
701
                                             vp->val.counter64->high,
547
701
                                             network_order)) {
548
0
                DEBUGINDENTLESS();
549
0
                DEBUGINDENTLESS();
550
0
                DEBUGINDENTLESS();
551
0
                return 0;
552
0
            }
553
701
            DEBUGINDENTLESS();
554
701
        }
555
1.01k
        break;
556
557
2.32k
    case ASN_NULL:
558
3.35k
    case SNMP_NOSUCHOBJECT:
559
3.99k
    case SNMP_NOSUCHINSTANCE:
560
5.42k
    case SNMP_ENDOFMIBVIEW:
561
5.42k
        break;
562
563
0
    default:
564
0
        DEBUGMSGTL(("agentx_build_varbind", "unknown type %d (0x%02x)\n",
565
0
                    vp->type, vp->type));
566
0
        DEBUGINDENTLESS();
567
0
        DEBUGINDENTLESS();
568
0
        return 0;
569
131k
    }
570
131k
    DEBUGINDENTLESS();
571
131k
    DEBUGINDENTLESS();
572
131k
    return 1;
573
131k
}
574
575
int
576
agentx_realloc_build_header(u_char ** buf, size_t * buf_len,
577
                            size_t * out_len, int allow_realloc,
578
                            netsnmp_pdu *pdu)
579
18.4k
{
580
18.4k
    size_t          ilen = *out_len;
581
18.4k
    const int       network_order =
582
18.4k
        pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER;
583
584
19.2k
    while ((*out_len + 4) >= *buf_len) {
585
857
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
586
0
            return 0;
587
0
        }
588
857
    }
589
590
    /*
591
     * First 4 bytes are version, pdu type, flags, and a 0 reserved byte.  
592
     */
593
594
18.4k
    *(*buf + *out_len) = 1;
595
18.4k
    (*out_len)++;
596
18.4k
    *(*buf + *out_len) = pdu->command;
597
18.4k
    (*out_len)++;
598
18.4k
    *(*buf + *out_len) = (u_char) (pdu->flags & AGENTX_MSG_FLAGS_MASK);
599
18.4k
    (*out_len)++;
600
18.4k
    *(*buf + *out_len) = 0;
601
18.4k
    (*out_len)++;
602
603
18.4k
    DEBUGDUMPHEADER("send", "AgentX Header");
604
18.4k
    DEBUGDUMPSETUP("send", (*buf + ilen), 4);
605
18.4k
    DEBUGMSG(("dumpv_send", "  Version:\t%d\n", (int) *(*buf + ilen)));
606
18.4k
    DEBUGPRINTINDENT("dumpv_send");
607
18.4k
    DEBUGMSG(("dumpv_send", "  Command:\t%d (%s)\n", pdu->command,
608
18.4k
              agentx_cmd((u_char)pdu->command)));
609
18.4k
    DEBUGPRINTINDENT("dumpv_send");
610
18.4k
    DEBUGMSG(("dumpv_send", "  Flags:\t%02x\n", (int) *(*buf + ilen + 2)));
611
612
18.4k
    DEBUGDUMPHEADER("send", "Session ID");
613
18.4k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
614
18.4k
                                  pdu->sessid, network_order)) {
615
0
        DEBUGINDENTLESS();
616
0
        DEBUGINDENTLESS();
617
0
        return 0;
618
0
    }
619
18.4k
    DEBUGINDENTLESS();
620
621
18.4k
    DEBUGDUMPHEADER("send", "Transaction ID");
622
18.4k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
623
18.4k
                                  pdu->transid, network_order)) {
624
0
        DEBUGINDENTLESS();
625
0
        DEBUGINDENTLESS();
626
0
        return 0;
627
0
    }
628
18.4k
    DEBUGINDENTLESS();
629
630
18.4k
    DEBUGDUMPHEADER("send", "Request ID");
631
18.4k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
632
18.4k
                                  pdu->reqid, network_order)) {
633
0
        DEBUGINDENTLESS();
634
0
        DEBUGINDENTLESS();
635
0
        return 0;
636
0
    }
637
18.4k
    DEBUGINDENTLESS();
638
639
18.4k
    DEBUGDUMPHEADER("send", "Dummy Length :-(");
640
18.4k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
641
18.4k
                                  0, network_order)) {
642
0
        DEBUGINDENTLESS();
643
0
        DEBUGINDENTLESS();
644
0
        return 0;
645
0
    }
646
18.4k
    DEBUGINDENTLESS();
647
648
18.4k
    if (pdu->flags & AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT) {
649
105
        DEBUGDUMPHEADER("send", "Community");
650
105
        if (!agentx_realloc_build_string
651
105
            (buf, buf_len, out_len, allow_realloc, pdu->community,
652
105
             pdu->community_len, network_order)) {
653
0
            DEBUGINDENTLESS();
654
0
            DEBUGINDENTLESS();
655
0
            return 0;
656
0
        }
657
105
        DEBUGINDENTLESS();
658
105
    }
659
660
18.4k
    DEBUGINDENTLESS();
661
18.4k
    return 1;
662
18.4k
}
663
664
static int
665
_agentx_realloc_build(u_char ** buf, size_t * buf_len, size_t * out_len,
666
                      int allow_realloc,
667
                      netsnmp_session * session, netsnmp_pdu *pdu)
668
18.4k
{
669
18.4k
    size_t          ilen = *out_len;
670
18.4k
    netsnmp_variable_list *vp;
671
18.4k
    int             inc, i = 0;
672
18.4k
    const int       network_order =
673
18.4k
        pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER;
674
675
18.4k
    session->s_snmp_errno = 0;
676
18.4k
    session->s_errno = 0;
677
678
    /*
679
     * Various PDU types don't include context information (RFC 2741, p. 20). 
680
     */
681
18.4k
    switch (pdu->command) {
682
42
    case AGENTX_MSG_OPEN:
683
73
    case AGENTX_MSG_CLOSE:
684
17.6k
    case AGENTX_MSG_RESPONSE:
685
17.6k
    case AGENTX_MSG_COMMITSET:
686
17.6k
    case AGENTX_MSG_UNDOSET:
687
17.6k
    case AGENTX_MSG_CLEANUPSET:
688
17.6k
        pdu->flags &= ~(AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT);
689
18.4k
    }
690
691
    /* We've received a PDU that has specified a context.  NetSNMP however, uses
692
     * the pdu->community field to specify context when using the AgentX
693
     * protocol.  Therefore we need to copy the context name and length into the
694
     * pdu->community and pdu->community_len fields, respectively. */
695
18.4k
    if (pdu->contextName != NULL && pdu->community == NULL)
696
0
    { 
697
0
        pdu->community     = (u_char *) strdup(pdu->contextName);
698
0
        pdu->community_len = pdu->contextNameLen;
699
0
        pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT;
700
0
    }
701
702
    /*
703
     * Build the header (and context if appropriate).  
704
     */
705
18.4k
    if (!agentx_realloc_build_header
706
18.4k
        (buf, buf_len, out_len, allow_realloc, pdu)) {
707
0
        return 0;
708
0
    }
709
710
    /*
711
     * Everything causes a response, except for agentx-Response-PDU and
712
     * agentx-CleanupSet-PDU.  
713
     */
714
715
18.4k
    pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
716
717
18.4k
    DEBUGDUMPHEADER("send", "AgentX Payload");
718
18.4k
    switch (pdu->command) {
719
720
42
    case AGENTX_MSG_OPEN:
721
        /*
722
         * Timeout  
723
         */
724
42
        while ((*out_len + 4) >= *buf_len) {
725
0
            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
726
0
                DEBUGINDENTLESS();
727
0
                return 0;
728
0
            }
729
0
        }
730
42
        *(*buf + *out_len) = (u_char) pdu->time;
731
42
        (*out_len)++;
732
168
        for (i = 0; i < 3; i++) {
733
126
            *(*buf + *out_len) = 0;
734
126
            (*out_len)++;
735
126
        }
736
42
        DEBUGDUMPHEADER("send", "Open Timeout");
737
42
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
738
42
        DEBUGMSG(("dumpv_send", "  Timeout:\t%d\n",
739
42
                  (int) *(*buf + *out_len - 4)));
740
42
        DEBUGINDENTLESS();
741
742
42
        DEBUGDUMPHEADER("send", "Open ID");
743
42
        if (!agentx_realloc_build_oid
744
42
            (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name,
745
42
             pdu->variables->name_length, network_order)) {
746
0
            DEBUGINDENTLESS();
747
0
            DEBUGINDENTLESS();
748
0
            return 0;
749
0
        }
750
42
        DEBUGINDENTLESS();
751
42
        DEBUGDUMPHEADER("send", "Open Description");
752
42
        if (!agentx_realloc_build_string
753
42
            (buf, buf_len, out_len, allow_realloc,
754
42
             pdu->variables->val.string, pdu->variables->val_len,
755
42
             network_order)) {
756
0
            DEBUGINDENTLESS();
757
0
            DEBUGINDENTLESS();
758
0
            return 0;
759
0
        }
760
42
        DEBUGINDENTLESS();
761
42
        break;
762
763
31
    case AGENTX_MSG_CLOSE:
764
        /*
765
         * Reason  
766
         */
767
31
        while ((*out_len + 4) >= *buf_len) {
768
0
            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
769
0
                DEBUGINDENTLESS();
770
0
                return 0;
771
0
            }
772
0
        }
773
31
        *(*buf + *out_len) = (u_char) pdu->errstat;
774
31
        (*out_len)++;
775
124
        for (i = 0; i < 3; i++) {
776
93
            *(*buf + *out_len) = 0;
777
93
            (*out_len)++;
778
93
        }
779
31
        DEBUGDUMPHEADER("send", "Close Reason");
780
31
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
781
31
        DEBUGMSG(("dumpv_send", "  Reason:\t%d\n",
782
31
                  (int) *(*buf + *out_len - 4)));
783
31
        DEBUGINDENTLESS();
784
31
        break;
785
786
42
    case AGENTX_MSG_REGISTER:
787
64
    case AGENTX_MSG_UNREGISTER:
788
64
        while ((*out_len + 4) >= *buf_len) {
789
0
            if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
790
0
                DEBUGINDENTLESS();
791
0
                return 0;
792
0
            }
793
0
        }
794
64
        if (pdu->command == AGENTX_MSG_REGISTER) {
795
42
            *(*buf + *out_len) = (u_char) pdu->time;
796
42
        } else {
797
22
            *(*buf + *out_len) = 0;
798
22
        }
799
64
        (*out_len)++;
800
64
        *(*buf + *out_len) = (u_char) pdu->priority;
801
64
        (*out_len)++;
802
64
        *(*buf + *out_len) = (u_char) pdu->range_subid;
803
64
        (*out_len)++;
804
64
        *(*buf + *out_len) = (u_char) 0;
805
64
        (*out_len)++;
806
807
64
        DEBUGDUMPHEADER("send", "(Un)Register Header");
808
64
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
809
64
        if (pdu->command == AGENTX_MSG_REGISTER) {
810
42
            DEBUGMSG(("dumpv_send", "  Timeout:\t%d\n",
811
42
                      (int) *(*buf + *out_len - 4)));
812
42
            DEBUGPRINTINDENT("dumpv_send");
813
42
        }
814
64
        DEBUGMSG(("dumpv_send", "  Priority:\t%d\n",
815
64
                  (int) *(*buf + *out_len - 3)));
816
64
        DEBUGPRINTINDENT("dumpv_send");
817
64
        DEBUGMSG(("dumpv_send", "  Range SubID:\t%d\n",
818
64
                  (int) *(*buf + *out_len - 2)));
819
64
        DEBUGINDENTLESS();
820
821
64
        vp = pdu->variables;
822
64
        DEBUGDUMPHEADER("send", "(Un)Register Prefix");
823
64
        if (!agentx_realloc_build_oid
824
64
            (buf, buf_len, out_len, allow_realloc, 0, vp->name,
825
64
             vp->name_length, network_order)) {
826
827
0
            DEBUGINDENTLESS();
828
0
            DEBUGINDENTLESS();
829
0
            return 0;
830
0
        }
831
64
        DEBUGINDENTLESS();
832
833
64
        if (pdu->range_subid) {
834
47
            DEBUGDUMPHEADER("send", "(Un)Register Range");
835
47
            if (!agentx_realloc_build_int
836
47
                (buf, buf_len, out_len, allow_realloc,
837
47
                 vp->val.objid[pdu->range_subid - 1], network_order)) {
838
0
                DEBUGINDENTLESS();
839
0
                DEBUGINDENTLESS();
840
0
                return 0;
841
0
            }
842
47
            DEBUGINDENTLESS();
843
47
        }
844
64
        break;
845
846
64
    case AGENTX_MSG_GETBULK:
847
25
        DEBUGDUMPHEADER("send", "GetBulk Non-Repeaters");
848
25
        if (!agentx_realloc_build_short
849
25
            (buf, buf_len, out_len, allow_realloc, 
850
25
            (u_short)pdu->non_repeaters,
851
25
             network_order)) {
852
0
            DEBUGINDENTLESS();
853
0
            DEBUGINDENTLESS();
854
0
            return 0;
855
0
        }
856
25
        DEBUGINDENTLESS();
857
858
25
        DEBUGDUMPHEADER("send", "GetBulk Max-Repetitions");
859
25
        if (!agentx_realloc_build_short
860
25
            (buf, buf_len, out_len, allow_realloc, 
861
25
            (u_short)pdu->max_repetitions,
862
25
             network_order)) {
863
0
            DEBUGINDENTLESS();
864
0
            DEBUGINDENTLESS();
865
0
            return 0;
866
0
        }
867
25
        DEBUGINDENTLESS();
868
869
25
        NETSNMP_FALLTHROUGH;
870
871
73
    case AGENTX_MSG_GET:
872
129
    case AGENTX_MSG_GETNEXT:
873
129
        DEBUGDUMPHEADER("send", "Get* Variable List");
874
13.8k
        for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) {
875
13.7k
            inc = (vp->type == ASN_PRIV_INCL_RANGE);
876
13.7k
            if (!agentx_realloc_build_oid
877
13.7k
                (buf, buf_len, out_len, allow_realloc, inc, vp->name,
878
13.7k
                 vp->name_length, network_order)) {
879
0
                DEBUGINDENTLESS();
880
0
                DEBUGINDENTLESS();
881
0
                return 0;
882
0
            }
883
13.7k
            if (!agentx_realloc_build_oid
884
13.7k
                (buf, buf_len, out_len, allow_realloc, 0, vp->val.objid,
885
13.7k
                 vp->val_len / sizeof(oid), network_order)) {
886
0
                DEBUGINDENTLESS();
887
0
                DEBUGINDENTLESS();
888
0
                return 0;
889
0
            }
890
13.7k
        }
891
129
        DEBUGINDENTLESS();
892
129
        break;
893
894
17.5k
    case AGENTX_MSG_RESPONSE:
895
17.5k
        pdu->flags &= ~(UCD_MSG_FLAG_EXPECT_RESPONSE);
896
17.5k
        if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
897
17.5k
                                      pdu->time, network_order)) {
898
0
            DEBUGINDENTLESS();
899
0
            return 0;
900
0
        }
901
17.5k
        DEBUGDUMPHEADER("send", "Response");
902
17.5k
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
903
17.5k
        DEBUGMSG(("dumpv_send", "  sysUpTime:\t%lu\n", pdu->time));
904
17.5k
        DEBUGINDENTLESS();
905
906
17.5k
        if (!agentx_realloc_build_short
907
17.5k
            (buf, buf_len, out_len, allow_realloc, 
908
17.5k
            (u_short)pdu->errstat,
909
17.5k
             network_order)
910
17.5k
            || !agentx_realloc_build_short(buf, buf_len, out_len,
911
17.5k
                                           allow_realloc, 
912
17.5k
                                           (u_short)pdu->errindex,
913
17.5k
                                           network_order)) {
914
0
            DEBUGINDENTLESS();
915
0
            return 0;
916
0
        }
917
17.5k
        DEBUGDUMPHEADER("send", "Response errors");
918
17.5k
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
919
17.5k
        DEBUGMSG(("dumpv_send", "  errstat:\t%ld\n", pdu->errstat));
920
17.5k
        DEBUGPRINTINDENT("dumpv_send");
921
17.5k
        DEBUGMSG(("dumpv_send", "  errindex:\t%ld\n", pdu->errindex));
922
17.5k
        DEBUGINDENTLESS();
923
924
17.5k
        NETSNMP_FALLTHROUGH;
925
926
17.6k
    case AGENTX_MSG_INDEX_ALLOCATE:
927
17.7k
    case AGENTX_MSG_INDEX_DEALLOCATE:
928
17.8k
    case AGENTX_MSG_NOTIFY:
929
17.9k
    case AGENTX_MSG_TESTSET:
930
17.9k
        DEBUGDUMPHEADER("send", "Get* Variable List");
931
149k
        for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) {
932
131k
            if (!agentx_realloc_build_varbind
933
131k
                (buf, buf_len, out_len, allow_realloc, vp,
934
131k
                 network_order)) {
935
0
                DEBUGINDENTLESS();
936
0
                DEBUGINDENTLESS();
937
0
                return 0;
938
0
            }
939
131k
        }
940
17.9k
        DEBUGINDENTLESS();
941
17.9k
        break;
942
943
6
    case AGENTX_MSG_COMMITSET:
944
8
    case AGENTX_MSG_UNDOSET:
945
9
    case AGENTX_MSG_PING:
946
        /*
947
         * "Empty" packet.  
948
         */
949
9
        break;
950
951
1
    case AGENTX_MSG_CLEANUPSET:
952
1
        pdu->flags &= ~(UCD_MSG_FLAG_EXPECT_RESPONSE);
953
1
        break;
954
955
36
    case AGENTX_MSG_ADD_AGENT_CAPS:
956
36
        DEBUGDUMPHEADER("send", "AgentCaps OID");
957
36
        if (!agentx_realloc_build_oid
958
36
            (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name,
959
36
             pdu->variables->name_length, network_order)) {
960
0
            DEBUGINDENTLESS();
961
0
            DEBUGINDENTLESS();
962
0
            return 0;
963
0
        }
964
36
        DEBUGINDENTLESS();
965
966
36
        DEBUGDUMPHEADER("send", "AgentCaps Description");
967
36
        if (!agentx_realloc_build_string
968
36
            (buf, buf_len, out_len, allow_realloc,
969
36
             pdu->variables->val.string, pdu->variables->val_len,
970
36
             network_order)) {
971
0
            DEBUGINDENTLESS();
972
0
            DEBUGINDENTLESS();
973
0
            return 0;
974
0
        }
975
36
        DEBUGINDENTLESS();
976
36
        break;
977
978
183
    case AGENTX_MSG_REMOVE_AGENT_CAPS:
979
183
        DEBUGDUMPHEADER("send", "AgentCaps OID");
980
183
        if (!agentx_realloc_build_oid
981
183
            (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name,
982
183
             pdu->variables->name_length, network_order)) {
983
0
            DEBUGINDENTLESS();
984
0
            DEBUGINDENTLESS();
985
0
            return 0;
986
0
        }
987
183
        DEBUGINDENTLESS();
988
183
        break;
989
990
0
    default:
991
0
        session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
992
0
        return 0;
993
18.4k
    }
994
18.4k
    DEBUGINDENTLESS();
995
996
    /*
997
     * Fix the payload length (ignoring the 20-byte header).  
998
     */
999
1000
18.4k
    agentx_build_int((*buf + 16), (*out_len - ilen) - 20, network_order);
1001
1002
18.4k
    DEBUGMSGTL(("agentx_build", "packet built okay\n"));
1003
18.4k
    return 1;
1004
18.4k
}
1005
1006
int
1007
agentx_realloc_build(netsnmp_session * session, netsnmp_pdu *pdu,
1008
                     u_char ** buf, size_t * buf_len, size_t * out_len)
1009
18.4k
{
1010
18.4k
    if (session == NULL || buf_len == NULL ||
1011
18.4k
        out_len == NULL || pdu == NULL || buf == NULL) {
1012
0
        return -1;
1013
0
    }
1014
18.4k
    if (!_agentx_realloc_build(buf, buf_len, out_len, 1, session, pdu)) {
1015
0
        if (session->s_snmp_errno == 0) {
1016
0
            session->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
1017
0
        }
1018
0
        return -1;
1019
0
    }
1020
1021
18.4k
    return 0;
1022
18.4k
}
1023
1024
        /***********************
1025
  *
1026
  *  Utility functions for parsing an AgentX packet
1027
  *
1028
  ***********************/
1029
1030
static u_int
1031
agentx_parse_int(const u_char *data, u_int network_byte_order)
1032
1.18M
{
1033
1.18M
    u_int           value = 0;
1034
1035
    /*
1036
     *  Note - this doesn't handle 'PDP_ENDIAN' systems
1037
     *      If anyone needs this added, contact the coders list
1038
     */
1039
1.18M
    DEBUGDUMPSETUP("recv", data, 4);
1040
1.18M
    if (network_byte_order) {
1041
108k
        memmove(&value, data, 4);
1042
108k
        if (!NETSNMP_BIGENDIAN)
1043
108k
            value = ntohl(value);
1044
1.08M
    } else {
1045
1.08M
        if (!NETSNMP_BIGENDIAN) {
1046
1.08M
            memmove(&value, data, 4);
1047
1.08M
        } else {
1048
            /*
1049
             * The equivalent of the 'ntohl()' macro,
1050
             * except this macro is null on big-endian systems
1051
             */
1052
0
            value += data[3];
1053
0
            value <<= 8;
1054
0
            value += data[2];
1055
0
            value <<= 8;
1056
0
            value += data[1];
1057
0
            value <<= 8;
1058
0
            value += data[0];
1059
0
        }
1060
1.08M
    }
1061
1.18M
    DEBUGMSG(("dumpv_recv", "  Integer:\t%u (0x%.2X)\n", value, value));
1062
1063
1.18M
    return value;
1064
1.18M
}
1065
1066
1067
static int
1068
agentx_parse_short(const u_char *data, u_int network_byte_order)
1069
53.7k
{
1070
53.7k
    u_short         value = 0;
1071
1072
53.7k
    if (network_byte_order) {
1073
8.14k
        memmove(&value, data, 2);
1074
8.14k
        if (!NETSNMP_BIGENDIAN)
1075
8.14k
            value = ntohs(value);
1076
45.6k
    } else {
1077
45.6k
        if (!NETSNMP_BIGENDIAN) {
1078
45.6k
            memmove(&value, data, 2);
1079
45.6k
        } else {
1080
            /*
1081
             * The equivalent of the 'ntohs()' macro,
1082
             * except this macro is null on big-endian systems
1083
             */
1084
0
            value += data[1];
1085
0
            value <<= 8;
1086
0
            value += data[0];
1087
0
        }
1088
45.6k
    }
1089
1090
53.7k
    DEBUGDUMPSETUP("recv", data, 2);
1091
53.7k
    DEBUGMSG(("dumpv_recv", "  Short:\t%hu (0x%.2X)\n", value, value));
1092
53.7k
    return value;
1093
53.7k
}
1094
1095
/**
1096
 * struct rszbuf - a resizeable buffer
1097
 * @buf:  Buffer pointer.
1098
 * @size: Size in bytes of the memory region @buf points at. Negative if @buf
1099
 *        has not been allocated dynamically.
1100
 * @used: Number of bytes in buf with useful data. If @buf points at an OID,
1101
 *        @used must be multiplied with sizeof(oid).
1102
 */
1103
struct rszbuf {
1104
    void    *buf;
1105
    int      size;
1106
    unsigned used;
1107
};
1108
1109
/* Free @rb->buf if it has been allocated dynamically. */
1110
static void cleanup_rszbuf(struct rszbuf *rb)
1111
595k
{
1112
595k
    if (rb->size > 0)
1113
3.96k
        free(rb->buf);
1114
595k
}
1115
1116
/* Reallocate @rb->buf if it is smaller than @min_size. */
1117
static int increase_size(struct rszbuf *rb, int min_size)
1118
354k
{
1119
354k
    if (min_size <= abs(rb->size))
1120
350k
        return 1;
1121
3.96k
    cleanup_rszbuf(rb);
1122
3.96k
    rb->buf = malloc(min_size);
1123
3.96k
    rb->size = rb->buf ? min_size : 0;
1124
3.96k
    return rb->buf != NULL;
1125
354k
}
1126
1127
const u_char *
1128
agentx_parse_oid(const u_char *data, size_t *length, int *inc,
1129
                 struct rszbuf *oid_buf, u_int network_byte_order)
1130
327k
{
1131
327k
    u_int           n_subid;
1132
327k
    u_int           prefix;
1133
327k
    u_int           tmp_oid_len;
1134
327k
    int             i;
1135
327k
    oid            *oid_ptr;
1136
327k
    const u_char   *buf_ptr = data;
1137
1138
327k
    if (*length < 4) {
1139
1.85k
        DEBUGMSGTL(("agentx", "Incomplete Object ID\n"));
1140
1.85k
        return NULL;
1141
1.85k
    }
1142
1143
326k
    DEBUGDUMPHEADER("recv", "OID Header");
1144
326k
    DEBUGDUMPSETUP("recv", data, 4);
1145
326k
    DEBUGMSG(("dumpv_recv", "  # subids:\t%d (0x%.2X)\n", data[0],
1146
326k
              data[0]));
1147
326k
    DEBUGPRINTINDENT("dumpv_recv");
1148
326k
    DEBUGMSG(("dumpv_recv", "  prefix: \t%d (0x%.2X)\n", data[1],
1149
326k
              data[1]));
1150
326k
    DEBUGPRINTINDENT("dumpv_recv");
1151
326k
    DEBUGMSG(("dumpv_recv", "  inclusive:\t%d (0x%.2X)\n", data[2],
1152
326k
              data[2]));
1153
1154
326k
    DEBUGINDENTLESS();
1155
326k
    DEBUGDUMPHEADER("recv", "OID Segments");
1156
1157
326k
    n_subid = data[0];
1158
326k
    prefix = data[1];
1159
326k
    if (inc)
1160
124k
        *inc = data[2];
1161
1162
326k
    buf_ptr += 4;
1163
326k
    *length -= 4;
1164
1165
326k
    DEBUGMSG(("djp", "  parse_oid\n"));
1166
326k
    DEBUGMSG(("djp", "  sizeof(oid) = %d\n", (int)sizeof(oid)));
1167
326k
    if (n_subid == 0 && prefix == 0) {
1168
        /*
1169
         * Null OID 
1170
         */
1171
262k
        if (!increase_size(oid_buf, 2 * sizeof(oid)))
1172
0
            return NULL;
1173
262k
        memset(oid_buf->buf, 0, 2 * sizeof(oid));
1174
262k
        oid_buf->used = 2;
1175
262k
        DEBUGPRINTINDENT("dumpv_recv");
1176
262k
        DEBUGMSG(("dumpv_recv", "OID: NULL (0.0)\n"));
1177
262k
        DEBUGINDENTLESS();
1178
262k
        return buf_ptr;
1179
262k
    }
1180
1181
    /*
1182
     * Check that the expanded OID will fit in the buffer provided
1183
     */
1184
63.8k
    tmp_oid_len = n_subid + 5 * (prefix != 0);
1185
63.8k
    if (tmp_oid_len > MAX_OID_LEN) {
1186
1.99k
        DEBUGMSGTL(("agentx", "OID length %d exceeds MAX_OID_LEN\n",
1187
1.99k
                    tmp_oid_len));
1188
1.99k
        DEBUGINDENTLESS();
1189
1.99k
        return NULL;
1190
1.99k
    }
1191
61.8k
    if (!increase_size(oid_buf, tmp_oid_len * sizeof(oid))) {
1192
0
        DEBUGMSGTL(("agentx", "Out of memory\n"));
1193
0
        DEBUGINDENTLESS();
1194
0
        return NULL;
1195
0
    }
1196
1197
61.8k
    if (*length < 4 * n_subid) {
1198
2.24k
        DEBUGMSGTL(("agentx", "Incomplete Object ID\n"));
1199
2.24k
        DEBUGINDENTLESS();
1200
2.24k
        return NULL;
1201
2.24k
    }
1202
1203
59.5k
    oid_ptr = oid_buf->buf;
1204
1205
59.5k
    if (prefix) {  
1206
50.3k
        *oid_ptr++ = 1;
1207
50.3k
        *oid_ptr++ = 3;
1208
50.3k
        *oid_ptr++ = 6;
1209
50.3k
        *oid_ptr++ = 1;
1210
50.3k
        *oid_ptr++ = prefix;
1211
50.3k
    }
1212
1213
225k
    for (i = 0; i < n_subid; i++) {
1214
165k
  u_int x;
1215
1216
165k
  x = agentx_parse_int(buf_ptr, network_byte_order);
1217
#ifdef EIGHTBIT_SUBIDS
1218
        if (x > MAX_SUBID) {
1219
            DEBUGMSGTL(("agentx", "Object ID sub-identifier too large\n"));
1220
            DEBUGINDENTLESS();
1221
            return NULL;
1222
        }
1223
#endif
1224
165k
        *oid_ptr++ = x;
1225
165k
        buf_ptr += 4;
1226
165k
        *length -= 4;
1227
165k
    }
1228
1229
59.5k
    oid_buf->used = tmp_oid_len;
1230
1231
59.5k
    DEBUGINDENTLESS();
1232
59.5k
    DEBUGPRINTINDENT("dumpv_recv");
1233
59.5k
    DEBUGMSG(("dumpv_recv", "OID: "));
1234
59.5k
    DEBUGMSGOID(("dumpv_recv", oid_buf->buf, oid_buf->used));
1235
59.5k
    DEBUGMSG(("dumpv_recv", "\n"));
1236
1237
59.5k
    return buf_ptr;
1238
61.8k
}
1239
1240
1241
1242
static const u_char *
1243
agentx_parse_string(const u_char *data, size_t *length, struct rszbuf *string,
1244
                    u_int network_byte_order)
1245
30.7k
{
1246
30.7k
    u_int           len;
1247
1248
30.7k
    if (*length < 4) {
1249
1.79k
        DEBUGMSGTL(("agentx", "Incomplete string (too short: %d)\n",
1250
1.79k
                    (int)*length));
1251
1.79k
        return NULL;
1252
1.79k
    }
1253
1254
28.9k
    len = agentx_parse_int(data, network_byte_order);
1255
28.9k
    if (len > UINT_MAX - 4) {
1256
115
        DEBUGMSGTL(("agentx", "Too long: %u\n", len));
1257
115
        return NULL;
1258
115
    }
1259
28.8k
    if (*length < len + 4) {
1260
1.55k
        DEBUGMSGTL(("agentx", "Incomplete string (still too short: %d)\n",
1261
1.55k
                    (int)*length));
1262
1.55k
        return NULL;
1263
1.55k
    }
1264
27.2k
    if (!increase_size(string, len + 1)) {
1265
0
        DEBUGMSGTL(("agentx", "Out of memory\n"));
1266
0
        return NULL;
1267
0
    }
1268
27.2k
    memmove(string->buf, data + 4, len);
1269
27.2k
    memset((char *)string->buf + len, '\0', 1);
1270
27.2k
    string->used = len;
1271
1272
27.2k
    len = (len + 3) & ~3UL; /* Include padding. */
1273
1274
27.2k
    if (*length < len + 4) {
1275
383
        DEBUGMSGTL(("agentx", "Packet too short for string padding (still too short: %d)\n",
1276
383
                    (int)*length));
1277
383
        return NULL;
1278
383
    }
1279
1280
26.8k
    *length -= (len + 4);
1281
26.8k
    DEBUGDUMPSETUP("recv", data, (len + 4));
1282
26.8k
    DEBUGIF("dumpv_recv") {
1283
0
        u_char         *buf = NULL;
1284
0
        size_t          buf_len = 0, out_len = 0;
1285
1286
0
        if (sprint_realloc_asciistring(&buf, &buf_len, &out_len, 1,
1287
0
                                       string->buf, string->used)) {
1288
0
            DEBUGMSG(("dumpv_recv", "String: %s\n", buf));
1289
0
        } else {
1290
0
            DEBUGMSG(("dumpv_recv", "String: %s [TRUNCATED]\n", buf));
1291
0
        }
1292
0
        if (buf != NULL) {
1293
0
            free(buf);
1294
0
        }
1295
0
    }
1296
26.8k
    return data + (len + 4);
1297
27.2k
}
1298
1299
static const u_char *
1300
agentx_parse_opaque(const u_char *data, size_t *length, int *type,
1301
                    struct rszbuf *opaque_buf, u_int network_byte_order)
1302
9.82k
{
1303
9.82k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1304
9.82k
    union {
1305
9.82k
        float           floatVal;
1306
9.82k
        double          doubleVal;
1307
9.82k
        int             intVal[2];
1308
9.82k
        char            c[sizeof(double)];
1309
9.82k
    } fu;
1310
9.82k
    int             tmp;
1311
9.82k
    u_char         *buf;
1312
9.82k
#endif
1313
9.82k
    const u_char   *const cp =
1314
9.82k
        agentx_parse_string(data, length, opaque_buf, network_byte_order);
1315
1316
9.82k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1317
9.82k
    if (cp == NULL)
1318
295
        return NULL;
1319
1320
9.53k
    buf = opaque_buf->buf;
1321
1322
9.53k
    if (opaque_buf->used <= 3 || buf[0] != ASN_OPAQUE_TAG1)
1323
4.14k
        return cp;              /* Unrecognised opaque type */
1324
1325
5.38k
    switch (buf[1]) {
1326
2.18k
    case ASN_OPAQUE_FLOAT:
1327
2.18k
        if (opaque_buf->used != 3 + sizeof(float) ||
1328
1.41k
            (buf[2] != sizeof(float)))
1329
1.51k
            return cp;          /* Encoding isn't right for FLOAT */
1330
1331
669
        memcpy(&fu.c[0], &buf[3], sizeof(float));
1332
669
        fu.intVal[0] = ntohl(fu.intVal[0]);
1333
669
        opaque_buf->used = sizeof(float);
1334
669
        memcpy(buf, &fu.c[0], sizeof(float));
1335
669
        *type = ASN_OPAQUE_FLOAT;
1336
669
        DEBUGMSG(("dumpv_recv", "Float: %f\n", fu.floatVal));
1337
669
        return cp;
1338
1339
2.17k
    case ASN_OPAQUE_DOUBLE:
1340
2.17k
        if (opaque_buf->used != 3 + sizeof(double) ||
1341
1.27k
            (buf[2] != sizeof(double)))
1342
1.54k
            return cp;          /* Encoding isn't right for DOUBLE */
1343
1344
634
        memcpy(&fu.c[0], &buf[3], sizeof(double));
1345
634
        tmp = ntohl(fu.intVal[1]);
1346
634
        fu.intVal[1] = ntohl(fu.intVal[0]);
1347
634
        fu.intVal[0] = tmp;
1348
634
        opaque_buf->used = sizeof(double);
1349
634
        memcpy(buf, &fu.c[0], sizeof(double));
1350
634
        *type = ASN_OPAQUE_DOUBLE;
1351
634
        DEBUGMSG(("dumpv_recv", "Double: %f\n", fu.doubleVal));
1352
634
        return cp;
1353
1354
10
    case ASN_OPAQUE_I64:
1355
11
    case ASN_OPAQUE_U64:
1356
11
    case ASN_OPAQUE_COUNTER64:
1357
1.02k
    default:
1358
1.02k
        return cp;              /* Unrecognised opaque sub-type */
1359
5.38k
    }
1360
#else
1361
    return cp;
1362
#endif
1363
5.38k
}
1364
1365
1366
static const u_char *
1367
agentx_parse_varbind(const u_char *data, size_t *length, int *type,
1368
                     struct rszbuf *oid_buf, struct rszbuf *data_buf,
1369
                     u_int network_byte_order)
1370
50.2k
{
1371
50.2k
    const u_char   *bufp = data;
1372
50.2k
    u_int           int_val;
1373
50.2k
    struct counter64 tmp64;
1374
1375
50.2k
    if (*length < 4)
1376
753
        return NULL;
1377
49.4k
    DEBUGDUMPHEADER("recv", "VarBind:");
1378
49.4k
    DEBUGDUMPHEADER("recv", "Type");
1379
49.4k
    *type = agentx_parse_short(bufp, network_byte_order);
1380
49.4k
    DEBUGINDENTLESS();
1381
49.4k
    bufp += 4;
1382
49.4k
    *length -= 4;
1383
1384
49.4k
    bufp = agentx_parse_oid(bufp, length, NULL, oid_buf, network_byte_order);
1385
49.4k
    if (bufp == NULL) {
1386
1.50k
        DEBUGINDENTLESS();
1387
1.50k
        return NULL;
1388
1.50k
    }
1389
1390
47.9k
    switch (*type) {
1391
1.97k
    case ASN_INTEGER:
1392
3.85k
    case ASN_COUNTER:
1393
6.05k
    case ASN_GAUGE:
1394
8.20k
    case ASN_TIMETICKS:
1395
10.0k
    case ASN_UINTEGER:
1396
10.0k
        if (*length < 4) {
1397
569
            DEBUGINDENTLESS();
1398
569
            return NULL;
1399
569
        }
1400
9.46k
        int_val = agentx_parse_int(bufp, network_byte_order);
1401
9.46k
        memmove(data_buf->buf, &int_val, 4);
1402
9.46k
        data_buf->used = 4;
1403
9.46k
        bufp += 4;
1404
9.46k
        *length -= 4;
1405
9.46k
        break;
1406
1407
2.44k
    case ASN_OCTET_STR:
1408
4.89k
    case ASN_IPADDRESS:
1409
4.89k
        bufp = agentx_parse_string(bufp, length, data_buf, network_byte_order);
1410
4.89k
        break;
1411
1412
9.82k
    case ASN_OPAQUE:
1413
9.82k
        bufp = agentx_parse_opaque(bufp, length, type, data_buf,
1414
9.82k
                                   network_byte_order);
1415
9.82k
        break;
1416
1417
3.02k
    case ASN_PRIV_INCL_RANGE:
1418
9.16k
    case ASN_PRIV_EXCL_RANGE:
1419
11.1k
    case ASN_OBJECT_ID:
1420
11.1k
        bufp = agentx_parse_oid(bufp, length, NULL, data_buf,
1421
11.1k
                                network_byte_order);
1422
11.1k
        data_buf->used *= sizeof(oid);
1423
        /*
1424
         * 'agentx_parse_oid()' returns the number of sub_ids 
1425
         */
1426
11.1k
        break;
1427
1428
2.85k
    case ASN_COUNTER64:
1429
2.85k
        if (*length < 8) {
1430
229
            DEBUGINDENTLESS();
1431
229
            return NULL;
1432
229
        }
1433
2.63k
        memset(&tmp64, 0, sizeof(tmp64));
1434
2.63k
  if (network_byte_order) {
1435
1.05k
      tmp64.high = agentx_parse_int(bufp,   network_byte_order);
1436
1.05k
      tmp64.low  = agentx_parse_int(bufp+4, network_byte_order);
1437
1.58k
  } else {
1438
1.58k
      tmp64.high = agentx_parse_int(bufp+4, network_byte_order);
1439
1.58k
      tmp64.low  = agentx_parse_int(bufp,   network_byte_order);
1440
1.58k
  }
1441
1442
2.63k
        memcpy(data_buf->buf, &tmp64, sizeof(tmp64));
1443
2.63k
        data_buf->used = sizeof(tmp64);
1444
2.63k
  bufp    += 8;
1445
2.63k
  *length -= 8;
1446
2.63k
        break;
1447
1448
1.80k
    case ASN_NULL:
1449
4.01k
    case SNMP_NOSUCHOBJECT:
1450
5.81k
    case SNMP_NOSUCHINSTANCE:
1451
8.24k
    case SNMP_ENDOFMIBVIEW:
1452
        /*
1453
         * No data associated with these types. 
1454
         */
1455
8.24k
        data_buf->used = 0;
1456
8.24k
        break;
1457
1458
961
    default:
1459
961
        DEBUGMSG(("recv", "Can not parse type %x", *type));
1460
961
        DEBUGINDENTLESS();
1461
961
        return NULL;
1462
47.9k
    }
1463
46.2k
    DEBUGINDENTLESS();
1464
46.2k
    return bufp;
1465
47.9k
}
1466
1467
/*
1468
 *  AgentX header:
1469
 *
1470
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1471
 * |    h.version  |   h.type      |   h.flags     |  <reserved>   |
1472
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1473
 * |                       h.sessionID                             |
1474
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1475
 * |                     h.transactionID                           |
1476
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1477
 * |                       h.packetID                              |
1478
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1479
 * |                     h.payload_length                          |
1480
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1481
 *
1482
 *    Total length = 20 bytes
1483
 *
1484
 *  If we don't seem to have the full packet, return NULL
1485
 *    and let the driving code go back for the rest.
1486
 *  Don't report this as an error, as it's quite "normal"
1487
 *    with a connection-oriented service.
1488
 *
1489
 *  Note that once the header has been successfully processed
1490
 *    (and hence we should have the full packet), any subsequent
1491
 *    "running out of room" is indeed an error.
1492
 */
1493
static const u_char *
1494
agentx_parse_header(netsnmp_pdu *pdu, const u_char *data, size_t *length)
1495
196k
{
1496
196k
    const u_char   *bufp = data;
1497
196k
    size_t          payload;
1498
1499
196k
    if (*length < 20) {         /* Incomplete header */
1500
510
        return NULL;
1501
510
    }
1502
1503
196k
    DEBUGDUMPHEADER("recv", "AgentX Header");
1504
196k
    DEBUGDUMPHEADER("recv", "Version");
1505
196k
    DEBUGDUMPSETUP("recv", bufp, 1);
1506
196k
    pdu->version = AGENTX_VERSION_BASE | *bufp;
1507
196k
    DEBUGMSG(("dumpv_recv", "  Version:\t%d\n", *bufp));
1508
196k
    DEBUGINDENTLESS();
1509
196k
    bufp++;
1510
1511
196k
    DEBUGDUMPHEADER("recv", "Command");
1512
196k
    DEBUGDUMPSETUP("recv", bufp, 1);
1513
196k
    pdu->command = *bufp;
1514
196k
    DEBUGMSG(("dumpv_recv", "  Command:\t%d (%s)\n", *bufp,
1515
196k
              agentx_cmd(*bufp)));
1516
196k
    DEBUGINDENTLESS();
1517
196k
    bufp++;
1518
1519
196k
    DEBUGDUMPHEADER("recv", "Flags");
1520
196k
    DEBUGDUMPSETUP("recv", bufp, 1);
1521
196k
    pdu->flags |= *bufp;
1522
196k
    DEBUGMSG(("dumpv_recv", "  Flags:\t0x%x\n", *bufp));
1523
196k
    DEBUGINDENTLESS();
1524
196k
    bufp++;
1525
1526
196k
    DEBUGDUMPHEADER("recv", "Reserved Byte");
1527
196k
    DEBUGDUMPSETUP("recv", bufp, 1);
1528
196k
    DEBUGMSG(("dumpv_recv", "  Reserved:\t0x%x\n", *bufp));
1529
196k
    DEBUGINDENTLESS();
1530
196k
    bufp++;
1531
1532
196k
    DEBUGDUMPHEADER("recv", "Session ID");
1533
196k
    pdu->sessid = agentx_parse_int(bufp,
1534
196k
                                   pdu->
1535
196k
                                   flags &
1536
196k
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1537
196k
    DEBUGINDENTLESS();
1538
196k
    bufp += 4;
1539
1540
196k
    DEBUGDUMPHEADER("recv", "Transaction ID");
1541
196k
    pdu->transid = agentx_parse_int(bufp,
1542
196k
                                    pdu->
1543
196k
                                    flags &
1544
196k
                                    AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1545
196k
    DEBUGINDENTLESS();
1546
196k
    bufp += 4;
1547
1548
196k
    DEBUGDUMPHEADER("recv", "Packet ID");
1549
196k
    pdu->reqid = agentx_parse_int(bufp,
1550
196k
                                  pdu->
1551
196k
                                  flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1552
196k
    DEBUGINDENTLESS();
1553
196k
    bufp += 4;
1554
1555
196k
    DEBUGDUMPHEADER("recv", "Payload Length");
1556
196k
    payload = agentx_parse_int(bufp,
1557
196k
                               pdu->
1558
196k
                               flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1559
196k
    DEBUGINDENTLESS();
1560
196k
    bufp += 4;
1561
1562
196k
    DEBUGINDENTLESS();
1563
196k
    *length -= 20;
1564
196k
    if (*length != payload) {   /* Short payload */
1565
4.06k
        return NULL;
1566
4.06k
    }
1567
192k
    return bufp;
1568
196k
}
1569
1570
1571
int
1572
agentx_parse(netsnmp_session * session, netsnmp_pdu *pdu, u_char * data,
1573
             size_t len)
1574
197k
{
1575
197k
    const u_char   *bufp = data;
1576
197k
    char            data_buffer[64];
1577
197k
    struct rszbuf   data_buf = {
1578
197k
        data_buffer,
1579
197k
        -(int)sizeof(data_buffer)
1580
197k
    };
1581
197k
    oid             oid_buffer[32];
1582
197k
    struct rszbuf   oid_buf = {
1583
197k
        oid_buffer,
1584
197k
        -(int)sizeof(oid_buffer)
1585
197k
    };
1586
197k
    oid             end_oid_buffer[32];
1587
197k
    struct rszbuf   end_oid_buf = {
1588
197k
        end_oid_buffer,
1589
197k
        -(int)sizeof(end_oid_buffer)
1590
197k
    };
1591
197k
    oid             range_bound;        /* OID-range upper bound */
1592
197k
    u_int           parsed_range_bound;
1593
197k
    int             inc;        /* Inclusive SearchRange flag */
1594
197k
    int             type;       /* VarBind data type */
1595
197k
    size_t         *length = &len;
1596
197k
    const int       dbgindent = debug_indent_get();
1597
197k
    int             res = SNMP_ERR_NOERROR;
1598
1599
197k
    if (pdu == NULL)
1600
0
        return SNMP_ERR_NOERROR;
1601
 
1602
197k
    if (!IS_AGENTX_VERSION(session->version)) {
1603
0
        res = SNMPERR_BAD_VERSION;
1604
0
        goto out;
1605
0
    }
1606
1607
197k
#ifndef SNMPERR_INCOMPLETE_PACKET
1608
    /*
1609
     *  Ideally, "short" packets on stream connections should
1610
     *    be handled specially, and the driving code set up to
1611
     *    keep reading until the full packet is received.
1612
     *
1613
     *  For now, lets assume that all packets are read in one go.
1614
     *    I've probably inflicted enough damage on the UCD library
1615
     *    for one week!
1616
     *
1617
     *  I'll come back to this once Wes is speaking to me again.
1618
     */
1619
197k
#define SNMPERR_INCOMPLETE_PACKET SNMPERR_ASN_PARSE_ERR
1620
197k
#endif
1621
1622
197k
    if (len > 65536)
1623
120
        goto parse_err;
1624
1625
    /*
1626
     *  Handle (common) header ....
1627
     */
1628
196k
    bufp = agentx_parse_header(pdu, bufp, length);
1629
196k
    if (bufp == NULL) {
1630
4.57k
        res = SNMPERR_INCOMPLETE_PACKET;       /* i.e. wait for the rest */
1631
4.57k
        goto out;
1632
4.57k
    }
1633
1634
    /*
1635
     * Control PDU handling 
1636
     */
1637
192k
    pdu->flags |= UCD_MSG_FLAG_ALWAYS_IN_VIEW;
1638
192k
    pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
1639
192k
    pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
1640
1641
    /*
1642
     *  ... and (not-un-common) context
1643
     */
1644
192k
    if (pdu->flags & AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT) {
1645
6.45k
        DEBUGDUMPHEADER("recv", "Context");
1646
6.45k
        bufp = agentx_parse_string(bufp, length, &data_buf, pdu->flags &
1647
6.45k
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1648
6.45k
        DEBUGINDENTLESS();
1649
6.45k
        if (bufp == NULL)
1650
2.00k
            goto parse_err;
1651
1652
4.44k
        pdu->community_len = data_buf.used;
1653
4.44k
        snmp_clone_mem((void **)&pdu->community, data_buf.buf, data_buf.used);
1654
    
1655
        /* The NetSNMP API stuffs the context into the PDU's community string
1656
         * field, when using the AgentX Protocol.  The rest of the code however,
1657
         * expects to find the context in the PDU's context field.  Therefore we
1658
         * need to copy the context into the PDU's context fields.  */
1659
4.44k
        if (pdu->community_len > 0 && pdu->contextName == NULL) {
1660
            /*
1661
             * strlen() is safe here because snmp_clone_mem() '\0'-terminates its output
1662
             */
1663
3.78k
            if (strlen((const char *)pdu->community) != pdu->community_len)
1664
612
                goto parse_err;
1665
3.17k
            pdu->contextName    = strdup((char *) pdu->community);
1666
3.17k
            pdu->contextNameLen = pdu->community_len;
1667
3.17k
        }
1668
4.44k
    }
1669
1670
189k
#define AGENTX_NEEDLEN( len ) \
1671
189k
        if ( *length < len ) { \
1672
2.74k
            goto parse_err; \
1673
2.74k
        }
1674
189k
    DEBUGDUMPHEADER("recv", "PDU");
1675
189k
    switch (pdu->command) {
1676
9.94k
    case AGENTX_MSG_OPEN:
1677
9.94k
        AGENTX_NEEDLEN(4);
1678
9.06k
        pdu->time = *bufp;      /* Timeout */
1679
9.06k
        bufp += 4;
1680
9.06k
        *length -= 4;
1681
1682
        /*
1683
         * Store subagent OID & description in a VarBind 
1684
         */
1685
9.06k
        DEBUGDUMPHEADER("recv", "Subagent OID");
1686
9.06k
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf, pdu->flags &
1687
9.06k
                                AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1688
9.06k
        DEBUGINDENTLESS();
1689
9.06k
        if (bufp == NULL)
1690
873
            goto parse_err;
1691
8.19k
        DEBUGDUMPHEADER("recv", "Subagent Description");
1692
8.19k
        bufp = agentx_parse_string(bufp, length, &data_buf, pdu->flags &
1693
8.19k
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1694
8.19k
        DEBUGINDENTLESS();
1695
8.19k
        if (bufp == NULL)
1696
1.09k
            goto parse_err;
1697
7.10k
        snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1698
7.10k
                              ASN_OCTET_STR, data_buf.buf, data_buf.used);
1699
7.10k
        break;
1700
1701
2.07k
    case AGENTX_MSG_CLOSE:
1702
2.07k
        AGENTX_NEEDLEN(4);
1703
1.83k
        pdu->errstat = *bufp;   /* Reason */
1704
1.83k
        bufp += 4;
1705
1.83k
        *length -= 4;
1706
1707
1.83k
        break;
1708
1709
2.45k
    case AGENTX_MSG_UNREGISTER:
1710
7.94k
    case AGENTX_MSG_REGISTER:
1711
7.94k
        AGENTX_NEEDLEN(4);
1712
7.28k
        DEBUGDUMPHEADER("recv", "Registration Header");
1713
7.28k
        if (pdu->command == AGENTX_MSG_REGISTER) {
1714
5.24k
            pdu->time = *bufp;  /* Timeout (Register only) */
1715
5.24k
            DEBUGDUMPSETUP("recv", bufp, 1);
1716
5.24k
            DEBUGMSG(("dumpv_recv", "  Timeout:     \t%d\n", *bufp));
1717
5.24k
        }
1718
7.28k
        bufp++;
1719
7.28k
        pdu->priority = *bufp;
1720
7.28k
        DEBUGDUMPSETUP("recv", bufp, 1);
1721
7.28k
        DEBUGMSG(("dumpv_recv", "  Priority:    \t%d\n", *bufp));
1722
7.28k
        bufp++;
1723
7.28k
        pdu->range_subid = *bufp;
1724
7.28k
        DEBUGDUMPSETUP("recv", bufp, 1);
1725
7.28k
        DEBUGMSG(("dumpv_recv", "  Range Sub-Id:\t%d\n", *bufp));
1726
7.28k
        bufp++;
1727
7.28k
        bufp++;
1728
7.28k
        *length -= 4;
1729
7.28k
        DEBUGINDENTLESS();
1730
1731
7.28k
        DEBUGDUMPHEADER("recv", "Registration OID");
1732
7.28k
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf, pdu->flags &
1733
7.28k
                                AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1734
7.28k
        DEBUGINDENTLESS();
1735
7.28k
        if (bufp == NULL)
1736
1.66k
            goto parse_err;
1737
1738
5.62k
        if (pdu->range_subid) {
1739
3.57k
            if (pdu->range_subid > oid_buf.used)
1740
554
                goto parse_err;
1741
3.02k
            AGENTX_NEEDLEN(4);
1742
2.75k
            parsed_range_bound = agentx_parse_int(bufp, pdu->flags &
1743
2.75k
                                                  AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1744
#ifdef EIGHTBIT_SUBIDS
1745
            if (parsed_range_bound > MAX_SUBID)
1746
                goto parse_err;
1747
#endif
1748
2.75k
            range_bound = parsed_range_bound;
1749
2.75k
            bufp += 4;
1750
2.75k
            *length -= 4;
1751
1752
            /*
1753
             * Construct the end-OID.  
1754
             */
1755
2.75k
            if (!increase_size(&end_oid_buf, oid_buf.used * sizeof(oid)))
1756
0
                goto parse_err;
1757
2.75k
            memcpy(end_oid_buf.buf, oid_buf.buf, oid_buf.used * sizeof(oid));
1758
2.75k
            ((oid *)end_oid_buf.buf)[pdu->range_subid - 1] = range_bound;
1759
1760
2.75k
            snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1761
2.75k
                                  ASN_PRIV_INCL_RANGE, end_oid_buf.buf,
1762
2.75k
                                  oid_buf.used * sizeof(oid));
1763
2.75k
        } else {
1764
2.04k
            snmp_add_null_var(pdu, oid_buf.buf, oid_buf.used);
1765
2.04k
        }
1766
4.80k
        break;
1767
1768
4.80k
    case AGENTX_MSG_GETBULK:
1769
761
        AGENTX_NEEDLEN(4);
1770
353
        DEBUGDUMPHEADER("recv", "Non-repeaters");
1771
353
        pdu->non_repeaters = agentx_parse_short(bufp, pdu->flags &
1772
353
                                                AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1773
353
        DEBUGINDENTLESS();
1774
353
        DEBUGDUMPHEADER("recv", "Max-repeaters");
1775
353
        pdu->max_repetitions = agentx_parse_short(bufp + 2, pdu->flags &
1776
353
                                                  AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1777
353
        DEBUGINDENTLESS();
1778
353
        bufp += 4;
1779
353
        *length -= 4;
1780
353
        NETSNMP_FALLTHROUGH;
1781
1782
2.04k
    case AGENTX_MSG_GETNEXT:
1783
2.99k
    case AGENTX_MSG_GET:
1784
1785
        /*
1786
         * *  SearchRange List
1787
         * *  Keep going while we have data left
1788
         */
1789
2.99k
        DEBUGDUMPHEADER("recv", "Search Range");
1790
126k
        while (*length > 0) {
1791
124k
            bufp = agentx_parse_oid(bufp, length, &inc, &oid_buf, pdu->flags &
1792
124k
                                    AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1793
124k
            if (bufp == NULL)
1794
457
                goto parse_err;
1795
123k
            bufp = agentx_parse_oid(bufp, length, NULL, &end_oid_buf,
1796
123k
                                    pdu->flags &
1797
123k
                                    AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1798
123k
            if (bufp == NULL)
1799
501
                goto parse_err;
1800
            /*
1801
             * 'agentx_parse_oid()' returns the number of sub_ids 
1802
             */
1803
123k
            snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1804
123k
                                  inc ? ASN_PRIV_INCL_RANGE :
1805
123k
                                  ASN_PRIV_EXCL_RANGE,
1806
123k
                                  end_oid_buf.buf,
1807
123k
                                  end_oid_buf.used * sizeof(oid));
1808
123k
        }
1809
1810
2.04k
        DEBUGINDENTLESS();
1811
2.04k
        break;
1812
1813
1814
2.09k
    case AGENTX_MSG_RESPONSE:
1815
1816
2.09k
        pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
1817
1818
2.09k
        AGENTX_NEEDLEN(8);
1819
1820
        /*
1821
         * sysUpTime 
1822
         */
1823
1.80k
        pdu->time = agentx_parse_int(bufp, pdu->flags &
1824
1.80k
                                     AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1825
1.80k
        bufp += 4;
1826
1.80k
        *length -= 4;
1827
1828
1.80k
        pdu->errstat = agentx_parse_short(bufp, pdu->flags &
1829
1.80k
                                          AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1830
1.80k
        pdu->errindex =
1831
1.80k
            agentx_parse_short(bufp + 2,
1832
1.80k
                               pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1833
1.80k
        bufp += 4;
1834
1.80k
        *length -= 4;
1835
1.80k
        NETSNMP_FALLTHROUGH;
1836
1837
9.16k
    case AGENTX_MSG_INDEX_ALLOCATE:
1838
11.7k
    case AGENTX_MSG_INDEX_DEALLOCATE:
1839
13.7k
    case AGENTX_MSG_NOTIFY:
1840
16.4k
    case AGENTX_MSG_TESTSET:
1841
1842
        /*
1843
         * *  VarBind List
1844
         * *  Keep going while we have data left
1845
         */
1846
1847
16.4k
        DEBUGDUMPHEADER("recv", "VarBindList");
1848
61.6k
        while (*length > 0) {
1849
50.2k
            bufp = agentx_parse_varbind(bufp, length, &type, &oid_buf,
1850
50.2k
                                        &data_buf, pdu->flags &
1851
50.2k
                                        AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1852
50.2k
            if (bufp == NULL)
1853
4.98k
                goto parse_err;
1854
45.2k
            snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used, type,
1855
45.2k
                                  data_buf.buf, data_buf.used);
1856
45.2k
        }
1857
11.4k
        DEBUGINDENTLESS();
1858
11.4k
        break;
1859
1860
299
    case AGENTX_MSG_COMMITSET:
1861
632
    case AGENTX_MSG_UNDOSET:
1862
965
    case AGENTX_MSG_CLEANUPSET:
1863
1.55k
    case AGENTX_MSG_PING:
1864
1865
        /*
1866
         * "Empty" packet 
1867
         */
1868
1.55k
        break;
1869
1870
1871
1.71k
    case AGENTX_MSG_ADD_AGENT_CAPS:
1872
        /*
1873
         * Store AgentCap OID & description in a VarBind 
1874
         */
1875
1.71k
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf,
1876
1.71k
                                pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1877
1.71k
        if (bufp == NULL)
1878
339
            goto parse_err;
1879
1.37k
        bufp = agentx_parse_string(bufp, length, &data_buf, pdu->flags &
1880
1.37k
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1881
1.37k
        if (bufp == NULL)
1882
295
            goto parse_err;
1883
1.07k
        snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1884
1.07k
                              ASN_OCTET_STR, data_buf.buf, data_buf.used);
1885
1.07k
        break;
1886
1887
1.13k
    case AGENTX_MSG_REMOVE_AGENT_CAPS:
1888
        /*
1889
         * Store AgentCap OID & description in a VarBind 
1890
         */
1891
1.13k
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf,
1892
1.13k
                                pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1893
1.13k
        if (bufp == NULL)
1894
237
            goto parse_err;
1895
895
        snmp_add_null_var(pdu, oid_buf.buf, oid_buf.used);
1896
895
        break;
1897
1898
145k
    default:
1899
145k
        DEBUGMSGTL(("agentx", "Unrecognised PDU type: %d\n",
1900
145k
                    pdu->command));
1901
145k
        res = SNMPERR_UNKNOWN_PDU;
1902
189k
    }
1903
1904
197k
out:
1905
197k
    debug_indent_add(dbgindent - debug_indent_get());
1906
197k
    cleanup_rszbuf(&end_oid_buf);
1907
197k
    cleanup_rszbuf(&oid_buf);
1908
197k
    cleanup_rszbuf(&data_buf);
1909
197k
    return res;
1910
1911
16.4k
parse_err:
1912
16.4k
    res = SNMPERR_ASN_PARSE_ERR;
1913
16.4k
    goto out;
1914
189k
}
1915
#undef AGENTX_NEEDLEN
1916
1917
1918
1919
1920
#ifdef TESTING
1921
1922
void testit(netsnmp_pdu *pdu1)
1923
{
1924
    char            packet1[BUFSIZ];
1925
    char            packet2[BUFSIZ];
1926
    int             len1, len2;
1927
    netsnmp_pdu     pdu2;
1928
    netsnmp_session sess;
1929
1930
    memset(&pdu2, 0, sizeof(netsnmp_pdu));
1931
    memset(packet1, 0, BUFSIZ);
1932
    memset(packet2, 0, BUFSIZ);
1933
1934
    /*
1935
     * Encode this into a "packet" 
1936
     */
1937
    len1 = BUFSIZ;
1938
    if (agentx_build(&sess, pdu1, packet1, &len1) < 0) {
1939
        DEBUGMSGTL(("agentx", "First build failed\n"));
1940
        exit(1);
1941
    }
1942
1943
    DEBUGMSGTL(("agentx", "First build succeeded:\n"));
1944
    xdump(packet1, len1, "Ax1> ");
1945
1946
    /*
1947
     * Unpack this into a PDU 
1948
     */
1949
    len2 = len1;
1950
    if (agentx_parse(&pdu2, packet1, &len2, (u_char **) NULL) < 0) {
1951
        DEBUGMSGTL(("agentx", "First parse failed\n"));
1952
        exit(1);
1953
    }
1954
    DEBUGMSGTL(("agentx", "First parse succeeded:\n"));
1955
    if (len2 != 0)
1956
        DEBUGMSGTL(("agentx",
1957
                    "Warning - parsed packet has %d bytes left\n", len2));
1958
1959
    /*
1960
     * Encode this into another "packet" 
1961
     */
1962
    len2 = BUFSIZ;
1963
    if (agentx_build(&sess, &pdu2, packet2, &len2) < 0) {
1964
        DEBUGMSGTL(("agentx", "Second build failed\n"));
1965
        exit(1);
1966
    }
1967
1968
    DEBUGMSGTL(("agentx", "Second build succeeded:\n"));
1969
    xdump(packet2, len2, "Ax2> ");
1970
1971
    /*
1972
     * Compare the results 
1973
     */
1974
    if (len1 != len2) {
1975
        DEBUGMSGTL(("agentx",
1976
                    "Error: first build (%d) is different to second (%d)\n",
1977
                    len1, len2));
1978
        exit(1);
1979
    }
1980
    if (memcmp(packet1, packet2, len1) != 0) {
1981
        DEBUGMSGTL(("agentx",
1982
                    "Error: first build data is different to second\n"));
1983
        exit(1);
1984
    }
1985
1986
    DEBUGMSGTL(("agentx", "OK\n"));
1987
}
1988
1989
1990
1991
int main(void)
1992
{
1993
    netsnmp_pdu     pdu1;
1994
    oid             oid_buf[] = { 1, 3, 6, 1, 2, 1, 10 };
1995
    oid             oid_buf2[] = { 1, 3, 6, 1, 2, 1, 20 };
1996
    oid             null_oid[] = { 0, 0 };
1997
    char           *string = "Example string";
1998
    char           *context = "LUCS";
1999
2000
2001
    /*
2002
     * Create an example AgentX pdu structure 
2003
     */
2004
2005
    memset(&pdu1, 0, sizeof(netsnmp_pdu));
2006
    pdu1.command = AGENTX_MSG_TESTSET;
2007
    pdu1.flags = 0;
2008
    pdu1.sessid = 16;
2009
    pdu1.transid = 24;
2010
    pdu1.reqid = 132;
2011
2012
    pdu1.time = 10;
2013
    pdu1.non_repeaters = 3;
2014
    pdu1.max_repetitions = 32;
2015
    pdu1.priority = 5;
2016
    pdu1.range_subid = 0;
2017
2018
    snmp_pdu_add_variable(&pdu1, oid_buf, OID_LENGTH(oid_buf),
2019
                          ASN_OBJECT_ID, (char *) oid_buf2,
2020
                          sizeof(oid_buf2));
2021
    snmp_pdu_add_variable(&pdu1, oid_buf, OID_LENGTH(oid_buf),
2022
                          ASN_INTEGER, (char *) &pdu1.reqid,
2023
                          sizeof(pdu1.reqid));
2024
    snmp_pdu_add_variable(&pdu1, oid_buf, OID_LENGTH(oid_buf),
2025
                          ASN_OCTET_STR, (char *) string, strlen(string));
2026
2027
    printf("Test with non-network order.....\n");
2028
    testit(&pdu1);
2029
2030
    printf("\nTest with network order.....\n");
2031
    pdu1.flags |= AGENTX_FLAGS_NETWORK_BYTE_ORDER;
2032
    testit(&pdu1);
2033
2034
    pdu1.community = context;
2035
    pdu1.community_len = strlen(context);
2036
    pdu1.flags |= AGENTX_FLAGS_NON_DEFAULT_CONTEXT;
2037
    printf("Test with non-default context.....\n");
2038
    testit(&pdu1);
2039
2040
2041
}
2042
#endif
2043
2044
/*
2045
 * returns the proper length of an incoming agentx packet. 
2046
 */
2047
/*
2048
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2049
 *    |   h.version   |    h.type     |    h.flags    |  <reserved>   |
2050
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2051
 *    |                          h.sessionID                          |
2052
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2053
 *    |                        h.transactionID                        |
2054
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2055
 *    |                          h.packetID                           |
2056
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2057
 *    |                        h.payload_length                       |
2058
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2059
 *    20 bytes in header
2060
 */
2061
2062
int
2063
agentx_check_packet(u_char * packet, size_t packet_len)
2064
190k
{
2065
190k
    u_int           payload_len;
2066
2067
190k
    if (packet_len < 20)
2068
316
        return 0;               /* minimum header length == 20 */
2069
2070
190k
    payload_len = agentx_parse_int(packet + 16,
2071
190k
                                   *(packet + 2) &
2072
190k
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
2073
190k
    if (payload_len > INT_MAX - 20)
2074
53
        return -1;
2075
2076
190k
    return (int)payload_len + 20;
2077
190k
}