Coverage Report

Created: 2025-10-10 07:11

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
299k
{
100
299k
    unsigned int    ivalue = value;
101
299k
    size_t          ilen = *out_len;
102
299k
    unsigned int    i = 0;
103
104
299k
    while ((*out_len + 4) >= *buf_len) {
105
29
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
106
0
            return 0;
107
0
        }
108
29
    }
109
110
299k
    if (network_order) {
111
11.4k
        if (!NETSNMP_BIGENDIAN)
112
11.4k
            value = ntohl(value);
113
11.4k
        memmove((*buf + *out_len), &value, 4);
114
11.4k
        *out_len += 4;
115
287k
    } else {
116
287k
        if (!NETSNMP_BIGENDIAN) {
117
287k
            memmove((*buf + *out_len), &value, 4);
118
287k
            *out_len += 4;
119
287k
        } 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
287k
    }
127
299k
    DEBUGDUMPSETUP("send", (*buf + ilen), 4);
128
299k
    DEBUGMSG(("dumpv_send", "  Integer:\t%u (0x%.2X)\n", ivalue,
129
299k
              ivalue));
130
299k
    return 1;
131
299k
}
132
133
void
134
agentx_build_int(u_char * bufp, u_int value, int network_byte_order)
135
1.11k
{
136
1.11k
    u_char         *orig_bufp = bufp;
137
1.11k
    u_int           orig_val = value;
138
139
1.11k
    if (network_byte_order) {
140
192
        if (!NETSNMP_BIGENDIAN)
141
192
            value = ntohl(value);
142
192
        memmove(bufp, &value, 4);
143
927
    } else {
144
927
        if (!NETSNMP_BIGENDIAN) {
145
927
            memmove(bufp, &value, 4);
146
927
        } 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
927
    }
159
1.11k
    DEBUGDUMPSETUP("send", orig_bufp, 4);
160
1.11k
    DEBUGMSG(("dumpv_send", "  Integer:\t%u (0x%.2X)\n", orig_val,
161
1.11k
              orig_val));
162
1.11k
}
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
29.7k
{
169
29.7k
    unsigned short  ivalue = value;
170
29.7k
    size_t          ilen = *out_len;
171
29.7k
    unsigned short  i = 0;
172
173
29.7k
    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
29.7k
    if (network_order) {
180
1.47k
        if (!NETSNMP_BIGENDIAN)
181
1.47k
            value = ntohs(value);
182
1.47k
        memmove((*buf + *out_len), &value, 2);
183
1.47k
        *out_len += 2;
184
28.2k
    } else {
185
28.2k
        if (!NETSNMP_BIGENDIAN) {
186
28.2k
            memmove((*buf + *out_len), &value, 2);
187
28.2k
            *out_len += 2;
188
28.2k
        } 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
28.2k
    }
196
29.7k
    DEBUGDUMPSETUP("send", (*buf + ilen), 2);
197
29.7k
    DEBUGMSG(("dumpv_send", "  Short:\t%hu (0x%.2hX)\n", ivalue, ivalue));
198
29.7k
    return 1;
199
29.7k
}
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
108k
{
207
108k
    size_t          ilen = *out_len, i = 0;
208
108k
    int             prefix = 0;
209
210
108k
    DEBUGPRINTINDENT("dumpv_send");
211
108k
    DEBUGMSG(("dumpv_send", "OID: "));
212
108k
    DEBUGMSGOID(("dumpv_send", name, name_len));
213
108k
    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
108k
    if (name_len == 0)
223
0
        inclusive = 0;
224
225
    /*
226
     * 'Compact' internet OIDs 
227
     */
228
108k
    if (name_len >= 5 && (name[0] == 1 && name[1] == 3 &&
229
16.6k
                          name[2] == 6 && name[3] == 1 &&
230
15.6k
                          name[4] > 0 && name[4] < 256)) {
231
14.9k
        prefix = name[4];
232
14.9k
        name += 5;
233
14.9k
        name_len -= 5;
234
14.9k
    }
235
236
108k
    while ((*out_len + 4 + (4 * name_len)) >= *buf_len) {
237
237
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
238
0
            return 0;
239
0
        }
240
237
    }
241
242
108k
    *(*buf + *out_len) = (u_char) name_len;
243
108k
    (*out_len)++;
244
108k
    *(*buf + *out_len) = (u_char) prefix;
245
108k
    (*out_len)++;
246
108k
    *(*buf + *out_len) = (u_char) inclusive;
247
108k
    (*out_len)++;
248
108k
    *(*buf + *out_len) = (u_char) 0x00;
249
108k
    (*out_len)++;
250
251
108k
    DEBUGDUMPHEADER("send", "OID Header");
252
108k
    DEBUGDUMPSETUP("send", (*buf + ilen), 4);
253
108k
    DEBUGMSG(("dumpv_send", "  # subids:\t%d (0x%.2X)\n", (int)name_len,
254
108k
              (unsigned int)name_len));
255
108k
    DEBUGPRINTINDENT("dumpv_send");
256
108k
    DEBUGMSG(("dumpv_send", "  prefix:\t%d (0x%.2X)\n", prefix, prefix));
257
108k
    DEBUGPRINTINDENT("dumpv_send");
258
108k
    DEBUGMSG(("dumpv_send", "  inclusive:\t%d (0x%.2X)\n", inclusive,
259
108k
              inclusive));
260
108k
    DEBUGINDENTLESS();
261
108k
    DEBUGDUMPHEADER("send", "OID Segments");
262
263
387k
    for (i = 0; i < name_len; i++) {
264
279k
        if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
265
279k
                                      name[i], network_order)) {
266
0
            DEBUGINDENTLESS();
267
0
            return 0;
268
0
        }
269
279k
    }
270
108k
    DEBUGINDENTLESS();
271
272
108k
    return 1;
273
108k
}
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
6.19k
{
281
6.19k
    size_t          ilen = *out_len, i = 0;
282
283
6.34k
    while ((*out_len + 4 + (4 * ((string_len + 3) / 4))) >= *buf_len) {
284
144
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
285
0
            return 0;
286
0
        }
287
144
    }
288
289
6.19k
    DEBUGDUMPHEADER("send", "Build String");
290
6.19k
    DEBUGDUMPHEADER("send", "length");
291
6.19k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
292
6.19k
                                  string_len, network_order)) {
293
0
        DEBUGINDENTLESS();
294
0
        DEBUGINDENTLESS();
295
0
        return 0;
296
0
    }
297
298
6.19k
    if (string_len == 0) {
299
1.59k
        DEBUGMSG(("dumpv_send", "  String: <empty>\n"));
300
1.59k
        DEBUGINDENTLESS();
301
1.59k
        DEBUGINDENTLESS();
302
1.59k
        return 1;
303
1.59k
    }
304
305
4.60k
    memmove((*buf + *out_len), string, string_len);
306
4.60k
    *out_len += string_len;
307
308
    /*
309
     * Pad to a multiple of 4 bytes if necessary (per RFC 2741).  
310
     */
311
312
4.60k
    if (string_len % 4 != 0) {
313
9.18k
        for (i = 0; i < 4 - (string_len % 4); i++) {
314
5.56k
            *(*buf + *out_len) = 0;
315
5.56k
            (*out_len)++;
316
5.56k
        }
317
3.61k
    }
318
319
4.60k
    DEBUGDUMPSETUP("send", (*buf + ilen + 4), ((string_len + 3) / 4) * 4);
320
4.60k
    DEBUGMSG(("dumpv_send", "  String:\t%.*s\n", (int)string_len, string));
321
4.60k
    DEBUGINDENTLESS();
322
4.60k
    DEBUGINDENTLESS();
323
4.60k
    return 1;
324
6.19k
}
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
226
{
332
226
    union {
333
226
        double          doubleVal;
334
226
        int             intVal[2];
335
226
        char            c[sizeof(double)];
336
226
    } du;
337
226
    int             tmp;
338
226
    u_char          opaque_buffer[3 + sizeof(double)];
339
340
226
    opaque_buffer[0] = ASN_OPAQUE_TAG1;
341
226
    opaque_buffer[1] = ASN_OPAQUE_DOUBLE;
342
226
    opaque_buffer[2] = sizeof(double);
343
344
226
    du.doubleVal = double_val;
345
226
    tmp = htonl(du.intVal[0]);
346
226
    du.intVal[0] = htonl(du.intVal[1]);
347
226
    du.intVal[1] = tmp;
348
226
    memcpy(&opaque_buffer[3], &du.c[0], sizeof(double));
349
350
226
    return agentx_realloc_build_string(buf, buf_len, out_len,
351
226
                                       allow_realloc, opaque_buffer,
352
226
                                       3 + sizeof(double), network_order);
353
226
}
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
382
{
360
382
    union {
361
382
        float           floatVal;
362
382
        int             intVal;
363
382
        char            c[sizeof(float)];
364
382
    } fu;
365
382
    u_char          opaque_buffer[3 + sizeof(float)];
366
367
382
    opaque_buffer[0] = ASN_OPAQUE_TAG1;
368
382
    opaque_buffer[1] = ASN_OPAQUE_FLOAT;
369
382
    opaque_buffer[2] = sizeof(float);
370
371
382
    fu.floatVal = float_val;
372
382
    fu.intVal = htonl(fu.intVal);
373
382
    memcpy(&opaque_buffer[3], &fu.c[0], sizeof(float));
374
375
382
    return agentx_realloc_build_string(buf, buf_len, out_len,
376
382
                                       allow_realloc, opaque_buffer,
377
382
                                       3 + sizeof(float), network_order);
378
382
}
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
29.6k
{
386
29.6k
    DEBUGDUMPHEADER("send", "VarBind");
387
29.6k
    DEBUGDUMPHEADER("send", "type");
388
29.6k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
389
29.6k
    if ((vp->type == ASN_OPAQUE_FLOAT) || (vp->type == ASN_OPAQUE_DOUBLE)
390
29.0k
        || (vp->type == ASN_OPAQUE_I64) || (vp->type == ASN_OPAQUE_U64)
391
29.0k
        || (vp->type == ASN_OPAQUE_COUNTER64)) {
392
608
        if (!agentx_realloc_build_short
393
608
            (buf, buf_len, out_len, allow_realloc,
394
608
             (unsigned short) ASN_OPAQUE, network_order)) {
395
0
            DEBUGINDENTLESS();
396
0
            DEBUGINDENTLESS();
397
0
            return 0;
398
0
        }
399
608
    } else
400
29.0k
#endif
401
29.0k
    if (vp->type == ASN_PRIV_INCL_RANGE || vp->type == ASN_PRIV_EXCL_RANGE) {
402
12.9k
        if (!agentx_realloc_build_short
403
12.9k
            (buf, buf_len, out_len, allow_realloc,
404
12.9k
             (unsigned short) ASN_OBJECT_ID, network_order)) {
405
0
            DEBUGINDENTLESS();
406
0
            DEBUGINDENTLESS();
407
0
            return 0;
408
0
        }
409
16.0k
    } else {
410
16.0k
        if (!agentx_realloc_build_short
411
16.0k
            (buf, buf_len, out_len, allow_realloc,
412
16.0k
             (unsigned short) vp->type, network_order)) {
413
0
            DEBUGINDENTLESS();
414
0
            DEBUGINDENTLESS();
415
0
            return 0;
416
0
        }
417
16.0k
    }
418
419
29.6k
    while ((*out_len + 2) >= *buf_len) {
420
40
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
421
0
            DEBUGINDENTLESS();
422
0
            DEBUGINDENTLESS();
423
0
            return 0;
424
0
        }
425
40
    }
426
427
29.6k
    *(*buf + *out_len) = 0;
428
29.6k
    (*out_len)++;
429
29.6k
    *(*buf + *out_len) = 0;
430
29.6k
    (*out_len)++;
431
29.6k
    DEBUGINDENTLESS();
432
433
29.6k
    DEBUGDUMPHEADER("send", "name");
434
29.6k
    if (!agentx_realloc_build_oid(buf, buf_len, out_len, allow_realloc, 0,
435
29.6k
                                  vp->name, vp->name_length,
436
29.6k
                                  network_order)) {
437
0
        DEBUGINDENTLESS();
438
0
        DEBUGINDENTLESS();
439
0
        return 0;
440
0
    }
441
29.6k
    DEBUGINDENTLESS();
442
443
29.6k
    DEBUGDUMPHEADER("send", "value");
444
29.6k
    switch (vp->type) {
445
446
768
    case ASN_INTEGER:
447
1.61k
    case ASN_COUNTER:
448
2.41k
    case ASN_GAUGE:
449
4.14k
    case ASN_TIMETICKS:
450
5.60k
    case ASN_UINTEGER:
451
5.60k
        if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
452
5.60k
                                      *(vp->val.integer), network_order)) {
453
0
            DEBUGINDENTLESS();
454
0
            DEBUGINDENTLESS();
455
0
            return 0;
456
0
        }
457
5.60k
        break;
458
459
5.60k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
460
5.60k
    case ASN_OPAQUE_FLOAT:
461
382
        DEBUGDUMPHEADER("send", "Build Opaque Float");
462
382
        DEBUGPRINTINDENT("dumpv_send");
463
382
        DEBUGMSG(("dumpv_send", "  Float:\t%f\n", *(vp->val.floatVal)));
464
382
        if (!agentx_realloc_build_float
465
382
            (buf, buf_len, out_len, allow_realloc, *(vp->val.floatVal),
466
382
             network_order)) {
467
0
            DEBUGINDENTLESS();
468
0
            DEBUGINDENTLESS();
469
0
            DEBUGINDENTLESS();
470
0
            return 0;
471
0
        }
472
382
        DEBUGINDENTLESS();
473
382
        break;
474
475
226
    case ASN_OPAQUE_DOUBLE:
476
226
        DEBUGDUMPHEADER("send", "Build Opaque Double");
477
226
        DEBUGPRINTINDENT("dumpv_send");
478
226
        DEBUGMSG(("dumpv_send", "  Double:\t%f\n", *(vp->val.doubleVal)));
479
226
        if (!agentx_realloc_build_double
480
226
            (buf, buf_len, out_len, allow_realloc, *(vp->val.doubleVal),
481
226
             network_order)) {
482
0
            DEBUGINDENTLESS();
483
0
            DEBUGINDENTLESS();
484
0
            DEBUGINDENTLESS();
485
0
            return 0;
486
0
        }
487
226
        DEBUGINDENTLESS();
488
226
        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
826
    case ASN_OCTET_STR:
500
1.73k
    case ASN_IPADDRESS:
501
5.37k
    case ASN_OPAQUE:
502
5.37k
        if (!agentx_realloc_build_string
503
5.37k
            (buf, buf_len, out_len, allow_realloc, vp->val.string,
504
5.37k
             vp->val_len, network_order)) {
505
0
            DEBUGINDENTLESS();
506
0
            DEBUGINDENTLESS();
507
0
            return 0;
508
0
        }
509
5.37k
        break;
510
511
5.37k
    case ASN_OBJECT_ID:
512
10.4k
    case ASN_PRIV_EXCL_RANGE:
513
13.4k
    case ASN_PRIV_INCL_RANGE:
514
13.4k
        if (!agentx_realloc_build_oid
515
13.4k
            (buf, buf_len, out_len, allow_realloc, 1, vp->val.objid,
516
13.4k
             vp->val_len / sizeof(oid), network_order)) {
517
0
            DEBUGINDENTLESS();
518
0
            DEBUGINDENTLESS();
519
0
            return 0;
520
0
        }
521
13.4k
        break;
522
523
13.4k
    case ASN_COUNTER64:
524
1.55k
        if (network_order) {
525
74
            DEBUGDUMPHEADER("send", "Build Counter64 (high, low)");
526
74
            if (!agentx_realloc_build_int
527
74
                (buf, buf_len, out_len, allow_realloc,
528
74
                 vp->val.counter64->high, network_order)
529
74
                || !agentx_realloc_build_int(buf, buf_len, out_len,
530
74
                                             allow_realloc,
531
74
                                             vp->val.counter64->low,
532
74
                                             network_order)) {
533
0
                DEBUGINDENTLESS();
534
0
                DEBUGINDENTLESS();
535
0
                DEBUGINDENTLESS();
536
0
                return 0;
537
0
            }
538
74
            DEBUGINDENTLESS();
539
1.48k
        } else {
540
1.48k
            DEBUGDUMPHEADER("send", "Build Counter64 (low, high)");
541
1.48k
            if (!agentx_realloc_build_int
542
1.48k
                (buf, buf_len, out_len, allow_realloc,
543
1.48k
                 vp->val.counter64->low, network_order)
544
1.48k
                || !agentx_realloc_build_int(buf, buf_len, out_len,
545
1.48k
                                             allow_realloc,
546
1.48k
                                             vp->val.counter64->high,
547
1.48k
                                             network_order)) {
548
0
                DEBUGINDENTLESS();
549
0
                DEBUGINDENTLESS();
550
0
                DEBUGINDENTLESS();
551
0
                return 0;
552
0
            }
553
1.48k
            DEBUGINDENTLESS();
554
1.48k
        }
555
1.55k
        break;
556
557
1.69k
    case ASN_NULL:
558
2.25k
    case SNMP_NOSUCHOBJECT:
559
2.61k
    case SNMP_NOSUCHINSTANCE:
560
2.99k
    case SNMP_ENDOFMIBVIEW:
561
2.99k
        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
29.6k
    }
570
29.6k
    DEBUGINDENTLESS();
571
29.6k
    DEBUGINDENTLESS();
572
29.6k
    return 1;
573
29.6k
}
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
1.11k
{
580
1.11k
    size_t          ilen = *out_len;
581
1.11k
    const int       network_order =
582
1.11k
        pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER;
583
584
2.23k
    while ((*out_len + 4) >= *buf_len) {
585
1.11k
        if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
586
0
            return 0;
587
0
        }
588
1.11k
    }
589
590
    /*
591
     * First 4 bytes are version, pdu type, flags, and a 0 reserved byte.  
592
     */
593
594
1.11k
    *(*buf + *out_len) = 1;
595
1.11k
    (*out_len)++;
596
1.11k
    *(*buf + *out_len) = pdu->command;
597
1.11k
    (*out_len)++;
598
1.11k
    *(*buf + *out_len) = (u_char) (pdu->flags & AGENTX_MSG_FLAGS_MASK);
599
1.11k
    (*out_len)++;
600
1.11k
    *(*buf + *out_len) = 0;
601
1.11k
    (*out_len)++;
602
603
1.11k
    DEBUGDUMPHEADER("send", "AgentX Header");
604
1.11k
    DEBUGDUMPSETUP("send", (*buf + ilen), 4);
605
1.11k
    DEBUGMSG(("dumpv_send", "  Version:\t%d\n", (int) *(*buf + ilen)));
606
1.11k
    DEBUGPRINTINDENT("dumpv_send");
607
1.11k
    DEBUGMSG(("dumpv_send", "  Command:\t%d (%s)\n", pdu->command,
608
1.11k
              agentx_cmd((u_char)pdu->command)));
609
1.11k
    DEBUGPRINTINDENT("dumpv_send");
610
1.11k
    DEBUGMSG(("dumpv_send", "  Flags:\t%02x\n", (int) *(*buf + ilen + 2)));
611
612
1.11k
    DEBUGDUMPHEADER("send", "Session ID");
613
1.11k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
614
1.11k
                                  pdu->sessid, network_order)) {
615
0
        DEBUGINDENTLESS();
616
0
        DEBUGINDENTLESS();
617
0
        return 0;
618
0
    }
619
1.11k
    DEBUGINDENTLESS();
620
621
1.11k
    DEBUGDUMPHEADER("send", "Transaction ID");
622
1.11k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
623
1.11k
                                  pdu->transid, network_order)) {
624
0
        DEBUGINDENTLESS();
625
0
        DEBUGINDENTLESS();
626
0
        return 0;
627
0
    }
628
1.11k
    DEBUGINDENTLESS();
629
630
1.11k
    DEBUGDUMPHEADER("send", "Request ID");
631
1.11k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
632
1.11k
                                  pdu->reqid, network_order)) {
633
0
        DEBUGINDENTLESS();
634
0
        DEBUGINDENTLESS();
635
0
        return 0;
636
0
    }
637
1.11k
    DEBUGINDENTLESS();
638
639
1.11k
    DEBUGDUMPHEADER("send", "Dummy Length :-(");
640
1.11k
    if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
641
1.11k
                                  0, network_order)) {
642
0
        DEBUGINDENTLESS();
643
0
        DEBUGINDENTLESS();
644
0
        return 0;
645
0
    }
646
1.11k
    DEBUGINDENTLESS();
647
648
1.11k
    if (pdu->flags & AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT) {
649
125
        DEBUGDUMPHEADER("send", "Community");
650
125
        if (!agentx_realloc_build_string
651
125
            (buf, buf_len, out_len, allow_realloc, pdu->community,
652
125
             pdu->community_len, network_order)) {
653
0
            DEBUGINDENTLESS();
654
0
            DEBUGINDENTLESS();
655
0
            return 0;
656
0
        }
657
125
        DEBUGINDENTLESS();
658
125
    }
659
660
1.11k
    DEBUGINDENTLESS();
661
1.11k
    return 1;
662
1.11k
}
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
1.11k
{
669
1.11k
    size_t          ilen = *out_len;
670
1.11k
    netsnmp_variable_list *vp;
671
1.11k
    int             inc, i = 0;
672
1.11k
    const int       network_order =
673
1.11k
        pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER;
674
675
1.11k
    session->s_snmp_errno = 0;
676
1.11k
    session->s_errno = 0;
677
678
    /*
679
     * Various PDU types don't include context information (RFC 2741, p. 20). 
680
     */
681
1.11k
    switch (pdu->command) {
682
51
    case AGENTX_MSG_OPEN:
683
80
    case AGENTX_MSG_CLOSE:
684
103
    case AGENTX_MSG_RESPONSE:
685
105
    case AGENTX_MSG_COMMITSET:
686
107
    case AGENTX_MSG_UNDOSET:
687
108
    case AGENTX_MSG_CLEANUPSET:
688
108
        pdu->flags &= ~(AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT);
689
1.11k
    }
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
1.11k
    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
1.11k
    if (!agentx_realloc_build_header
706
1.11k
        (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
1.11k
    pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
716
717
1.11k
    DEBUGDUMPHEADER("send", "AgentX Payload");
718
1.11k
    switch (pdu->command) {
719
720
51
    case AGENTX_MSG_OPEN:
721
        /*
722
         * Timeout  
723
         */
724
51
        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
51
        *(*buf + *out_len) = (u_char) pdu->time;
731
51
        (*out_len)++;
732
204
        for (i = 0; i < 3; i++) {
733
153
            *(*buf + *out_len) = 0;
734
153
            (*out_len)++;
735
153
        }
736
51
        DEBUGDUMPHEADER("send", "Open Timeout");
737
51
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
738
51
        DEBUGMSG(("dumpv_send", "  Timeout:\t%d\n",
739
51
                  (int) *(*buf + *out_len - 4)));
740
51
        DEBUGINDENTLESS();
741
742
51
        DEBUGDUMPHEADER("send", "Open ID");
743
51
        if (!agentx_realloc_build_oid
744
51
            (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name,
745
51
             pdu->variables->name_length, network_order)) {
746
0
            DEBUGINDENTLESS();
747
0
            DEBUGINDENTLESS();
748
0
            return 0;
749
0
        }
750
51
        DEBUGINDENTLESS();
751
51
        DEBUGDUMPHEADER("send", "Open Description");
752
51
        if (!agentx_realloc_build_string
753
51
            (buf, buf_len, out_len, allow_realloc,
754
51
             pdu->variables->val.string, pdu->variables->val_len,
755
51
             network_order)) {
756
0
            DEBUGINDENTLESS();
757
0
            DEBUGINDENTLESS();
758
0
            return 0;
759
0
        }
760
51
        DEBUGINDENTLESS();
761
51
        break;
762
763
29
    case AGENTX_MSG_CLOSE:
764
        /*
765
         * Reason  
766
         */
767
29
        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
29
        *(*buf + *out_len) = (u_char) pdu->errstat;
774
29
        (*out_len)++;
775
116
        for (i = 0; i < 3; i++) {
776
87
            *(*buf + *out_len) = 0;
777
87
            (*out_len)++;
778
87
        }
779
29
        DEBUGDUMPHEADER("send", "Close Reason");
780
29
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
781
29
        DEBUGMSG(("dumpv_send", "  Reason:\t%d\n",
782
29
                  (int) *(*buf + *out_len - 4)));
783
29
        DEBUGINDENTLESS();
784
29
        break;
785
786
52
    case AGENTX_MSG_REGISTER:
787
77
    case AGENTX_MSG_UNREGISTER:
788
77
        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
77
        if (pdu->command == AGENTX_MSG_REGISTER) {
795
52
            *(*buf + *out_len) = (u_char) pdu->time;
796
52
        } else {
797
25
            *(*buf + *out_len) = 0;
798
25
        }
799
77
        (*out_len)++;
800
77
        *(*buf + *out_len) = (u_char) pdu->priority;
801
77
        (*out_len)++;
802
77
        *(*buf + *out_len) = (u_char) pdu->range_subid;
803
77
        (*out_len)++;
804
77
        *(*buf + *out_len) = (u_char) 0;
805
77
        (*out_len)++;
806
807
77
        DEBUGDUMPHEADER("send", "(Un)Register Header");
808
77
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
809
77
        if (pdu->command == AGENTX_MSG_REGISTER) {
810
52
            DEBUGMSG(("dumpv_send", "  Timeout:\t%d\n",
811
52
                      (int) *(*buf + *out_len - 4)));
812
52
            DEBUGPRINTINDENT("dumpv_send");
813
52
        }
814
77
        DEBUGMSG(("dumpv_send", "  Priority:\t%d\n",
815
77
                  (int) *(*buf + *out_len - 3)));
816
77
        DEBUGPRINTINDENT("dumpv_send");
817
77
        DEBUGMSG(("dumpv_send", "  Range SubID:\t%d\n",
818
77
                  (int) *(*buf + *out_len - 2)));
819
77
        DEBUGINDENTLESS();
820
821
77
        vp = pdu->variables;
822
77
        DEBUGDUMPHEADER("send", "(Un)Register Prefix");
823
77
        if (!agentx_realloc_build_oid
824
77
            (buf, buf_len, out_len, allow_realloc, 0, vp->name,
825
77
             vp->name_length, network_order)) {
826
827
0
            DEBUGINDENTLESS();
828
0
            DEBUGINDENTLESS();
829
0
            return 0;
830
0
        }
831
77
        DEBUGINDENTLESS();
832
833
77
        if (pdu->range_subid) {
834
65
            DEBUGDUMPHEADER("send", "(Un)Register Range");
835
65
            if (!agentx_realloc_build_int
836
65
                (buf, buf_len, out_len, allow_realloc,
837
65
                 vp->val.objid[pdu->range_subid - 1], network_order)) {
838
0
                DEBUGINDENTLESS();
839
0
                DEBUGINDENTLESS();
840
0
                return 0;
841
0
            }
842
65
            DEBUGINDENTLESS();
843
65
        }
844
77
        break;
845
846
77
    case AGENTX_MSG_GETBULK:
847
33
        DEBUGDUMPHEADER("send", "GetBulk Non-Repeaters");
848
33
        if (!agentx_realloc_build_short
849
33
            (buf, buf_len, out_len, allow_realloc, 
850
33
            (u_short)pdu->non_repeaters,
851
33
             network_order)) {
852
0
            DEBUGINDENTLESS();
853
0
            DEBUGINDENTLESS();
854
0
            return 0;
855
0
        }
856
33
        DEBUGINDENTLESS();
857
858
33
        DEBUGDUMPHEADER("send", "GetBulk Max-Repetitions");
859
33
        if (!agentx_realloc_build_short
860
33
            (buf, buf_len, out_len, allow_realloc, 
861
33
            (u_short)pdu->max_repetitions,
862
33
             network_order)) {
863
0
            DEBUGINDENTLESS();
864
0
            DEBUGINDENTLESS();
865
0
            return 0;
866
0
        }
867
33
        DEBUGINDENTLESS();
868
869
33
        NETSNMP_FALLTHROUGH;
870
871
85
    case AGENTX_MSG_GET:
872
154
    case AGENTX_MSG_GETNEXT:
873
154
        DEBUGDUMPHEADER("send", "Get* Variable List");
874
32.5k
        for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) {
875
32.3k
            inc = (vp->type == ASN_PRIV_INCL_RANGE);
876
32.3k
            if (!agentx_realloc_build_oid
877
32.3k
                (buf, buf_len, out_len, allow_realloc, inc, vp->name,
878
32.3k
                 vp->name_length, network_order)) {
879
0
                DEBUGINDENTLESS();
880
0
                DEBUGINDENTLESS();
881
0
                return 0;
882
0
            }
883
32.3k
            if (!agentx_realloc_build_oid
884
32.3k
                (buf, buf_len, out_len, allow_realloc, 0, vp->val.objid,
885
32.3k
                 vp->val_len / sizeof(oid), network_order)) {
886
0
                DEBUGINDENTLESS();
887
0
                DEBUGINDENTLESS();
888
0
                return 0;
889
0
            }
890
32.3k
        }
891
154
        DEBUGINDENTLESS();
892
154
        break;
893
894
23
    case AGENTX_MSG_RESPONSE:
895
23
        pdu->flags &= ~(UCD_MSG_FLAG_EXPECT_RESPONSE);
896
23
        if (!agentx_realloc_build_int(buf, buf_len, out_len, allow_realloc,
897
23
                                      pdu->time, network_order)) {
898
0
            DEBUGINDENTLESS();
899
0
            return 0;
900
0
        }
901
23
        DEBUGDUMPHEADER("send", "Response");
902
23
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
903
23
        DEBUGMSG(("dumpv_send", "  sysUpTime:\t%lu\n", pdu->time));
904
23
        DEBUGINDENTLESS();
905
906
23
        if (!agentx_realloc_build_short
907
23
            (buf, buf_len, out_len, allow_realloc, 
908
23
            (u_short)pdu->errstat,
909
23
             network_order)
910
23
            || !agentx_realloc_build_short(buf, buf_len, out_len,
911
23
                                           allow_realloc, 
912
23
                                           (u_short)pdu->errindex,
913
23
                                           network_order)) {
914
0
            DEBUGINDENTLESS();
915
0
            return 0;
916
0
        }
917
23
        DEBUGDUMPHEADER("send", "Response errors");
918
23
        DEBUGDUMPSETUP("send", (*buf + *out_len - 4), 4);
919
23
        DEBUGMSG(("dumpv_send", "  errstat:\t%ld\n", pdu->errstat));
920
23
        DEBUGPRINTINDENT("dumpv_send");
921
23
        DEBUGMSG(("dumpv_send", "  errindex:\t%ld\n", pdu->errindex));
922
23
        DEBUGINDENTLESS();
923
924
23
        NETSNMP_FALLTHROUGH;
925
926
89
    case AGENTX_MSG_INDEX_ALLOCATE:
927
166
    case AGENTX_MSG_INDEX_DEALLOCATE:
928
258
    case AGENTX_MSG_NOTIFY:
929
354
    case AGENTX_MSG_TESTSET:
930
354
        DEBUGDUMPHEADER("send", "Get* Variable List");
931
29.9k
        for (vp = pdu->variables; vp != NULL; vp = vp->next_variable) {
932
29.6k
            if (!agentx_realloc_build_varbind
933
29.6k
                (buf, buf_len, out_len, allow_realloc, vp,
934
29.6k
                 network_order)) {
935
0
                DEBUGINDENTLESS();
936
0
                DEBUGINDENTLESS();
937
0
                return 0;
938
0
            }
939
29.6k
        }
940
354
        DEBUGINDENTLESS();
941
354
        break;
942
943
2
    case AGENTX_MSG_COMMITSET:
944
4
    case AGENTX_MSG_UNDOSET:
945
6
    case AGENTX_MSG_PING:
946
        /*
947
         * "Empty" packet.  
948
         */
949
6
        break;
950
951
1
    case AGENTX_MSG_CLEANUPSET:
952
1
        pdu->flags &= ~(UCD_MSG_FLAG_EXPECT_RESPONSE);
953
1
        break;
954
955
45
    case AGENTX_MSG_ADD_AGENT_CAPS:
956
45
        DEBUGDUMPHEADER("send", "AgentCaps OID");
957
45
        if (!agentx_realloc_build_oid
958
45
            (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name,
959
45
             pdu->variables->name_length, network_order)) {
960
0
            DEBUGINDENTLESS();
961
0
            DEBUGINDENTLESS();
962
0
            return 0;
963
0
        }
964
45
        DEBUGINDENTLESS();
965
966
45
        DEBUGDUMPHEADER("send", "AgentCaps Description");
967
45
        if (!agentx_realloc_build_string
968
45
            (buf, buf_len, out_len, allow_realloc,
969
45
             pdu->variables->val.string, pdu->variables->val_len,
970
45
             network_order)) {
971
0
            DEBUGINDENTLESS();
972
0
            DEBUGINDENTLESS();
973
0
            return 0;
974
0
        }
975
45
        DEBUGINDENTLESS();
976
45
        break;
977
978
402
    case AGENTX_MSG_REMOVE_AGENT_CAPS:
979
402
        DEBUGDUMPHEADER("send", "AgentCaps OID");
980
402
        if (!agentx_realloc_build_oid
981
402
            (buf, buf_len, out_len, allow_realloc, 0, pdu->variables->name,
982
402
             pdu->variables->name_length, network_order)) {
983
0
            DEBUGINDENTLESS();
984
0
            DEBUGINDENTLESS();
985
0
            return 0;
986
0
        }
987
402
        DEBUGINDENTLESS();
988
402
        break;
989
990
0
    default:
991
0
        session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
992
0
        return 0;
993
1.11k
    }
994
1.11k
    DEBUGINDENTLESS();
995
996
    /*
997
     * Fix the payload length (ignoring the 20-byte header).  
998
     */
999
1000
1.11k
    agentx_build_int((*buf + 16), (*out_len - ilen) - 20, network_order);
1001
1002
1.11k
    DEBUGMSGTL(("agentx_build", "packet built okay\n"));
1003
1.11k
    return 1;
1004
1.11k
}
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
1.11k
{
1010
1.11k
    if (session == NULL || buf_len == NULL ||
1011
1.11k
        out_len == NULL || pdu == NULL || buf == NULL) {
1012
0
        return -1;
1013
0
    }
1014
1.11k
    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
1.11k
    return 0;
1022
1.11k
}
1023
1024
        /***********************
1025
  *
1026
  *  Utility functions for parsing an AgentX packet
1027
  *
1028
  ***********************/
1029
1030
static int
1031
agentx_parse_int(const u_char *data, u_int network_byte_order)
1032
336k
{
1033
336k
    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
336k
    DEBUGDUMPSETUP("recv", data, 4);
1040
336k
    if (network_byte_order) {
1041
23.3k
        memmove(&value, data, 4);
1042
23.3k
        if (!NETSNMP_BIGENDIAN)
1043
23.3k
            value = ntohl(value);
1044
313k
    } else {
1045
313k
        if (!NETSNMP_BIGENDIAN) {
1046
313k
            memmove(&value, data, 4);
1047
313k
        } 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
313k
    }
1061
336k
    DEBUGMSG(("dumpv_recv", "  Integer:\t%u (0x%.2X)\n", value, value));
1062
1063
336k
    return value;
1064
336k
}
1065
1066
1067
static int
1068
agentx_parse_short(const u_char *data, u_int network_byte_order)
1069
49.9k
{
1070
49.9k
    u_short         value = 0;
1071
1072
49.9k
    if (network_byte_order) {
1073
4.44k
        memmove(&value, data, 2);
1074
4.44k
        if (!NETSNMP_BIGENDIAN)
1075
4.44k
            value = ntohs(value);
1076
45.5k
    } else {
1077
45.5k
        if (!NETSNMP_BIGENDIAN) {
1078
45.5k
            memmove(&value, data, 2);
1079
45.5k
        } 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.5k
    }
1089
1090
49.9k
    DEBUGDUMPSETUP("recv", data, 2);
1091
49.9k
    DEBUGMSG(("dumpv_recv", "  Short:\t%hu (0x%.2X)\n", value, value));
1092
49.9k
    return value;
1093
49.9k
}
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
21.4k
{
1112
21.4k
    if (rb->size > 0)
1113
1.81k
        free(rb->buf);
1114
21.4k
}
1115
1116
/* Reallocate @rb->buf if it is smaller than @min_size. */
1117
static int increase_size(struct rszbuf *rb, int min_size)
1118
159k
{
1119
159k
    if (min_size <= abs(rb->size))
1120
157k
        return 1;
1121
1.81k
    cleanup_rszbuf(rb);
1122
1.81k
    rb->buf = malloc(min_size);
1123
1.81k
    rb->size = rb->buf ? min_size : 0;
1124
1.81k
    return rb->buf != NULL;
1125
159k
}
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
144k
{
1131
144k
    u_int           n_subid;
1132
144k
    u_int           prefix;
1133
144k
    u_int           tmp_oid_len;
1134
144k
    int             i;
1135
144k
    oid            *oid_ptr;
1136
144k
    const u_char   *buf_ptr = data;
1137
1138
144k
    if (*length < 4) {
1139
210
        DEBUGMSGTL(("agentx", "Incomplete Object ID\n"));
1140
210
        return NULL;
1141
210
    }
1142
1143
143k
    DEBUGDUMPHEADER("recv", "OID Header");
1144
143k
    DEBUGDUMPSETUP("recv", data, 4);
1145
143k
    DEBUGMSG(("dumpv_recv", "  # subids:\t%d (0x%.2X)\n", data[0],
1146
143k
              data[0]));
1147
143k
    DEBUGPRINTINDENT("dumpv_recv");
1148
143k
    DEBUGMSG(("dumpv_recv", "  prefix: \t%d (0x%.2X)\n", data[1],
1149
143k
              data[1]));
1150
143k
    DEBUGPRINTINDENT("dumpv_recv");
1151
143k
    DEBUGMSG(("dumpv_recv", "  inclusive:\t%d (0x%.2X)\n", data[2],
1152
143k
              data[2]));
1153
1154
143k
    DEBUGINDENTLESS();
1155
143k
    DEBUGDUMPHEADER("recv", "OID Segments");
1156
1157
143k
    n_subid = data[0];
1158
143k
    prefix = data[1];
1159
143k
    if (inc)
1160
39.2k
        *inc = data[2];
1161
1162
143k
    buf_ptr += 4;
1163
143k
    *length -= 4;
1164
1165
143k
    DEBUGMSG(("djp", "  parse_oid\n"));
1166
143k
    DEBUGMSG(("djp", "  sizeof(oid) = %d\n", (int)sizeof(oid)));
1167
143k
    if (n_subid == 0 && prefix == 0) {
1168
        /*
1169
         * Null OID 
1170
         */
1171
105k
        if (!increase_size(oid_buf, 2 * sizeof(oid)))
1172
0
            return NULL;
1173
105k
        memset(oid_buf->buf, 0, 2 * sizeof(oid));
1174
105k
        oid_buf->used = 2;
1175
105k
        DEBUGPRINTINDENT("dumpv_recv");
1176
105k
        DEBUGMSG(("dumpv_recv", "OID: NULL (0.0)\n"));
1177
105k
        DEBUGINDENTLESS();
1178
105k
        return buf_ptr;
1179
105k
    }
1180
1181
    /*
1182
     * Check that the expanded OID will fit in the buffer provided
1183
     */
1184
38.0k
    tmp_oid_len = n_subid + 5 * (prefix != 0);
1185
38.0k
    if (!increase_size(oid_buf, tmp_oid_len * sizeof(oid))) {
1186
0
        DEBUGMSGTL(("agentx", "Out of memory\n"));
1187
0
        DEBUGINDENTLESS();
1188
0
        return NULL;
1189
0
    }
1190
1191
38.0k
    if (*length < 4 * n_subid) {
1192
508
        DEBUGMSGTL(("agentx", "Incomplete Object ID\n"));
1193
508
        DEBUGINDENTLESS();
1194
508
        return NULL;
1195
508
    }
1196
1197
37.5k
    oid_ptr = oid_buf->buf;
1198
1199
37.5k
    if (prefix) {  
1200
29.4k
        *oid_ptr++ = 1;
1201
29.4k
        *oid_ptr++ = 3;
1202
29.4k
        *oid_ptr++ = 6;
1203
29.4k
        *oid_ptr++ = 1;
1204
29.4k
        *oid_ptr++ = prefix;
1205
29.4k
    }
1206
1207
319k
    for (i = 0; i < n_subid; i++) {
1208
281k
  int x;
1209
1210
281k
  x = agentx_parse_int(buf_ptr, network_byte_order);
1211
281k
        *oid_ptr++ = x;
1212
281k
        buf_ptr += 4;
1213
281k
        *length -= 4;
1214
281k
    }
1215
1216
37.5k
    oid_buf->used = tmp_oid_len;
1217
1218
37.5k
    DEBUGINDENTLESS();
1219
37.5k
    DEBUGPRINTINDENT("dumpv_recv");
1220
37.5k
    DEBUGMSG(("dumpv_recv", "OID: "));
1221
37.5k
    DEBUGMSGOID(("dumpv_recv", oid_buf->buf, oid_buf->used));
1222
37.5k
    DEBUGMSG(("dumpv_recv", "\n"));
1223
1224
37.5k
    return buf_ptr;
1225
38.0k
}
1226
1227
1228
1229
static const u_char *
1230
agentx_parse_string(const u_char *data, size_t *length, struct rszbuf *string,
1231
                    u_int network_byte_order)
1232
15.8k
{
1233
15.8k
    u_int           len;
1234
1235
15.8k
    if (*length < 4) {
1236
64
        DEBUGMSGTL(("agentx", "Incomplete string (too short: %d)\n",
1237
64
                    (int)*length));
1238
64
        return NULL;
1239
64
    }
1240
1241
15.8k
    len = agentx_parse_int(data, network_byte_order);
1242
15.8k
    if (len > UINT_MAX - 4) {
1243
6
        DEBUGMSGTL(("agentx", "Too long: %u\n", len));
1244
6
        return NULL;
1245
6
    }
1246
15.8k
    if (*length < len + 4) {
1247
176
        DEBUGMSGTL(("agentx", "Incomplete string (still too short: %d)\n",
1248
176
                    (int)*length));
1249
176
        return NULL;
1250
176
    }
1251
15.6k
    if (!increase_size(string, len + 1)) {
1252
0
        DEBUGMSGTL(("agentx", "Out of memory\n"));
1253
0
        return NULL;
1254
0
    }
1255
15.6k
    memmove(string->buf, data + 4, len);
1256
15.6k
    memset((char *)string->buf + len, '\0', 1);
1257
15.6k
    string->used = len;
1258
1259
15.6k
    len = (len + 3) & ~3UL; /* Include padding. */
1260
1261
15.6k
    if (*length < len + 4) {
1262
37
        DEBUGMSGTL(("agentx", "Packet too short for string padding (still too short: %d)\n",
1263
37
                    (int)*length));
1264
37
        return NULL;
1265
37
    }
1266
1267
15.6k
    *length -= (len + 4);
1268
15.6k
    DEBUGDUMPSETUP("recv", data, (len + 4));
1269
15.6k
    DEBUGIF("dumpv_recv") {
1270
0
        u_char         *buf = NULL;
1271
0
        size_t          buf_len = 0, out_len = 0;
1272
1273
0
        if (sprint_realloc_asciistring(&buf, &buf_len, &out_len, 1,
1274
0
                                       string->buf, string->used)) {
1275
0
            DEBUGMSG(("dumpv_recv", "String: %s\n", buf));
1276
0
        } else {
1277
0
            DEBUGMSG(("dumpv_recv", "String: %s [TRUNCATED]\n", buf));
1278
0
        }
1279
0
        if (buf != NULL) {
1280
0
            free(buf);
1281
0
        }
1282
0
    }
1283
15.6k
    return data + (len + 4);
1284
15.6k
}
1285
1286
static const u_char *
1287
agentx_parse_opaque(const u_char *data, size_t *length, int *type,
1288
                    struct rszbuf *opaque_buf, u_int network_byte_order)
1289
11.2k
{
1290
11.2k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1291
11.2k
    union {
1292
11.2k
        float           floatVal;
1293
11.2k
        double          doubleVal;
1294
11.2k
        int             intVal[2];
1295
11.2k
        char            c[sizeof(double)];
1296
11.2k
    } fu;
1297
11.2k
    int             tmp;
1298
11.2k
    u_char         *buf;
1299
11.2k
#endif
1300
11.2k
    const u_char   *const cp =
1301
11.2k
        agentx_parse_string(data, length, opaque_buf, network_byte_order);
1302
1303
11.2k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1304
11.2k
    if (cp == NULL)
1305
37
        return NULL;
1306
1307
11.1k
    buf = opaque_buf->buf;
1308
1309
11.1k
    if (opaque_buf->used <= 3 || buf[0] != ASN_OPAQUE_TAG1)
1310
4.34k
        return cp;              /* Unrecognised opaque type */
1311
1312
6.85k
    switch (buf[1]) {
1313
2.48k
    case ASN_OPAQUE_FLOAT:
1314
2.48k
        if (opaque_buf->used != 3 + sizeof(float) ||
1315
1.33k
            (buf[2] != sizeof(float)))
1316
1.74k
            return cp;          /* Encoding isn't right for FLOAT */
1317
1318
749
        memcpy(&fu.c[0], &buf[3], sizeof(float));
1319
749
        fu.intVal[0] = ntohl(fu.intVal[0]);
1320
749
        opaque_buf->used = sizeof(float);
1321
749
        memcpy(buf, &fu.c[0], sizeof(float));
1322
749
        *type = ASN_OPAQUE_FLOAT;
1323
749
        DEBUGMSG(("dumpv_recv", "Float: %f\n", fu.floatVal));
1324
749
        return cp;
1325
1326
2.58k
    case ASN_OPAQUE_DOUBLE:
1327
2.58k
        if (opaque_buf->used != 3 + sizeof(double) ||
1328
1.57k
            (buf[2] != sizeof(double)))
1329
1.91k
            return cp;          /* Encoding isn't right for DOUBLE */
1330
1331
665
        memcpy(&fu.c[0], &buf[3], sizeof(double));
1332
665
        tmp = ntohl(fu.intVal[1]);
1333
665
        fu.intVal[1] = ntohl(fu.intVal[0]);
1334
665
        fu.intVal[0] = tmp;
1335
665
        opaque_buf->used = sizeof(double);
1336
665
        memcpy(buf, &fu.c[0], sizeof(double));
1337
665
        *type = ASN_OPAQUE_DOUBLE;
1338
665
        DEBUGMSG(("dumpv_recv", "Double: %f\n", fu.doubleVal));
1339
665
        return cp;
1340
1341
16
    case ASN_OPAQUE_I64:
1342
17
    case ASN_OPAQUE_U64:
1343
17
    case ASN_OPAQUE_COUNTER64:
1344
1.77k
    default:
1345
1.77k
        return cp;              /* Unrecognised opaque sub-type */
1346
6.85k
    }
1347
#else
1348
    return cp;
1349
#endif
1350
6.85k
}
1351
1352
1353
static const u_char *
1354
agentx_parse_varbind(const u_char *data, size_t *length, int *type,
1355
                     struct rszbuf *oid_buf, struct rszbuf *data_buf,
1356
                     u_int network_byte_order)
1357
49.4k
{
1358
49.4k
    const u_char   *bufp = data;
1359
49.4k
    u_int           int_val;
1360
49.4k
    struct counter64 tmp64;
1361
1362
49.4k
    if (*length < 4)
1363
53
        return NULL;
1364
49.4k
    DEBUGDUMPHEADER("recv", "VarBind:");
1365
49.4k
    DEBUGDUMPHEADER("recv", "Type");
1366
49.4k
    *type = agentx_parse_short(bufp, network_byte_order);
1367
49.4k
    DEBUGINDENTLESS();
1368
49.4k
    bufp += 4;
1369
49.4k
    *length -= 4;
1370
1371
49.4k
    bufp = agentx_parse_oid(bufp, length, NULL, oid_buf, network_byte_order);
1372
49.4k
    if (bufp == NULL) {
1373
372
        DEBUGINDENTLESS();
1374
372
        return NULL;
1375
372
    }
1376
1377
49.0k
    switch (*type) {
1378
1.40k
    case ASN_INTEGER:
1379
2.79k
    case ASN_COUNTER:
1380
4.12k
    case ASN_GAUGE:
1381
6.28k
    case ASN_TIMETICKS:
1382
8.73k
    case ASN_UINTEGER:
1383
8.73k
        if (*length < 4) {
1384
68
            DEBUGINDENTLESS();
1385
68
            return NULL;
1386
68
        }
1387
8.66k
        int_val = agentx_parse_int(bufp, network_byte_order);
1388
8.66k
        memmove(data_buf->buf, &int_val, 4);
1389
8.66k
        data_buf->used = 4;
1390
8.66k
        bufp += 4;
1391
8.66k
        *length -= 4;
1392
8.66k
        break;
1393
1394
1.82k
    case ASN_OCTET_STR:
1395
3.90k
    case ASN_IPADDRESS:
1396
3.90k
        bufp = agentx_parse_string(bufp, length, data_buf, network_byte_order);
1397
3.90k
        break;
1398
1399
11.2k
    case ASN_OPAQUE:
1400
11.2k
        bufp = agentx_parse_opaque(bufp, length, type, data_buf,
1401
11.2k
                                   network_byte_order);
1402
11.2k
        break;
1403
1404
3.71k
    case ASN_PRIV_INCL_RANGE:
1405
14.3k
    case ASN_PRIV_EXCL_RANGE:
1406
15.3k
    case ASN_OBJECT_ID:
1407
15.3k
        bufp = agentx_parse_oid(bufp, length, NULL, data_buf,
1408
15.3k
                                network_byte_order);
1409
15.3k
        data_buf->used *= sizeof(oid);
1410
        /*
1411
         * 'agentx_parse_oid()' returns the number of sub_ids 
1412
         */
1413
15.3k
        break;
1414
1415
2.59k
    case ASN_COUNTER64:
1416
2.59k
        if (*length < 8) {
1417
12
            DEBUGINDENTLESS();
1418
12
            return NULL;
1419
12
        }
1420
2.58k
        memset(&tmp64, 0, sizeof(tmp64));
1421
2.58k
  if (network_byte_order) {
1422
453
      tmp64.high = agentx_parse_int(bufp,   network_byte_order);
1423
453
      tmp64.low  = agentx_parse_int(bufp+4, network_byte_order);
1424
2.12k
  } else {
1425
2.12k
      tmp64.high = agentx_parse_int(bufp+4, network_byte_order);
1426
2.12k
      tmp64.low  = agentx_parse_int(bufp,   network_byte_order);
1427
2.12k
  }
1428
1429
2.58k
        memcpy(data_buf->buf, &tmp64, sizeof(tmp64));
1430
2.58k
        data_buf->used = sizeof(tmp64);
1431
2.58k
  bufp    += 8;
1432
2.58k
  *length -= 8;
1433
2.58k
        break;
1434
1435
2.53k
    case ASN_NULL:
1436
4.35k
    case SNMP_NOSUCHOBJECT:
1437
5.56k
    case SNMP_NOSUCHINSTANCE:
1438
7.04k
    case SNMP_ENDOFMIBVIEW:
1439
        /*
1440
         * No data associated with these types. 
1441
         */
1442
7.04k
        data_buf->used = 0;
1443
7.04k
        break;
1444
1445
167
    default:
1446
167
        DEBUGMSG(("recv", "Can not parse type %x", *type));
1447
167
        DEBUGINDENTLESS();
1448
167
        return NULL;
1449
49.0k
    }
1450
48.8k
    DEBUGINDENTLESS();
1451
48.8k
    return bufp;
1452
49.0k
}
1453
1454
/*
1455
 *  AgentX header:
1456
 *
1457
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1458
 * |    h.version  |   h.type      |   h.flags     |  <reserved>   |
1459
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1460
 * |                       h.sessionID                             |
1461
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1462
 * |                     h.transactionID                           |
1463
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1464
 * |                       h.packetID                              |
1465
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1466
 * |                     h.payload_length                          |
1467
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1468
 *
1469
 *    Total length = 20 bytes
1470
 *
1471
 *  If we don't seem to have the full packet, return NULL
1472
 *    and let the driving code go back for the rest.
1473
 *  Don't report this as an error, as it's quite "normal"
1474
 *    with a connection-oriented service.
1475
 *
1476
 *  Note that once the header has been successfully processed
1477
 *    (and hence we should have the full packet), any subsequent
1478
 *    "running out of room" is indeed an error.
1479
 */
1480
static const u_char *
1481
agentx_parse_header(netsnmp_pdu *pdu, const u_char *data, size_t *length)
1482
6.46k
{
1483
6.46k
    const u_char   *bufp = data;
1484
6.46k
    size_t          payload;
1485
1486
6.46k
    if (*length < 20) {         /* Incomplete header */
1487
194
        return NULL;
1488
194
    }
1489
1490
6.27k
    DEBUGDUMPHEADER("recv", "AgentX Header");
1491
6.27k
    DEBUGDUMPHEADER("recv", "Version");
1492
6.27k
    DEBUGDUMPSETUP("recv", bufp, 1);
1493
6.27k
    pdu->version = AGENTX_VERSION_BASE | *bufp;
1494
6.27k
    DEBUGMSG(("dumpv_recv", "  Version:\t%d\n", *bufp));
1495
6.27k
    DEBUGINDENTLESS();
1496
6.27k
    bufp++;
1497
1498
6.27k
    DEBUGDUMPHEADER("recv", "Command");
1499
6.27k
    DEBUGDUMPSETUP("recv", bufp, 1);
1500
6.27k
    pdu->command = *bufp;
1501
6.27k
    DEBUGMSG(("dumpv_recv", "  Command:\t%d (%s)\n", *bufp,
1502
6.27k
              agentx_cmd(*bufp)));
1503
6.27k
    DEBUGINDENTLESS();
1504
6.27k
    bufp++;
1505
1506
6.27k
    DEBUGDUMPHEADER("recv", "Flags");
1507
6.27k
    DEBUGDUMPSETUP("recv", bufp, 1);
1508
6.27k
    pdu->flags |= *bufp;
1509
6.27k
    DEBUGMSG(("dumpv_recv", "  Flags:\t0x%x\n", *bufp));
1510
6.27k
    DEBUGINDENTLESS();
1511
6.27k
    bufp++;
1512
1513
6.27k
    DEBUGDUMPHEADER("recv", "Reserved Byte");
1514
6.27k
    DEBUGDUMPSETUP("recv", bufp, 1);
1515
6.27k
    DEBUGMSG(("dumpv_recv", "  Reserved:\t0x%x\n", *bufp));
1516
6.27k
    DEBUGINDENTLESS();
1517
6.27k
    bufp++;
1518
1519
6.27k
    DEBUGDUMPHEADER("recv", "Session ID");
1520
6.27k
    pdu->sessid = agentx_parse_int(bufp,
1521
6.27k
                                   pdu->
1522
6.27k
                                   flags &
1523
6.27k
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1524
6.27k
    DEBUGINDENTLESS();
1525
6.27k
    bufp += 4;
1526
1527
6.27k
    DEBUGDUMPHEADER("recv", "Transaction ID");
1528
6.27k
    pdu->transid = agentx_parse_int(bufp,
1529
6.27k
                                    pdu->
1530
6.27k
                                    flags &
1531
6.27k
                                    AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1532
6.27k
    DEBUGINDENTLESS();
1533
6.27k
    bufp += 4;
1534
1535
6.27k
    DEBUGDUMPHEADER("recv", "Packet ID");
1536
6.27k
    pdu->reqid = agentx_parse_int(bufp,
1537
6.27k
                                  pdu->
1538
6.27k
                                  flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1539
6.27k
    DEBUGINDENTLESS();
1540
6.27k
    bufp += 4;
1541
1542
6.27k
    DEBUGDUMPHEADER("recv", "Payload Length");
1543
6.27k
    payload = agentx_parse_int(bufp,
1544
6.27k
                               pdu->
1545
6.27k
                               flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1546
6.27k
    DEBUGINDENTLESS();
1547
6.27k
    bufp += 4;
1548
1549
6.27k
    DEBUGINDENTLESS();
1550
6.27k
    *length -= 20;
1551
6.27k
    if (*length != payload) {   /* Short payload */
1552
3.25k
        return NULL;
1553
3.25k
    }
1554
3.01k
    return bufp;
1555
6.27k
}
1556
1557
1558
int
1559
agentx_parse(netsnmp_session * session, netsnmp_pdu *pdu, u_char * data,
1560
             size_t len)
1561
6.53k
{
1562
6.53k
    const u_char   *bufp = data;
1563
6.53k
    char            data_buffer[64];
1564
6.53k
    struct rszbuf   data_buf = {
1565
6.53k
        data_buffer,
1566
6.53k
        -(int)sizeof(data_buffer)
1567
6.53k
    };
1568
6.53k
    oid             oid_buffer[32];
1569
6.53k
    struct rszbuf   oid_buf = {
1570
6.53k
        oid_buffer,
1571
6.53k
        -(int)sizeof(oid_buffer)
1572
6.53k
    };
1573
6.53k
    oid             end_oid_buffer[32];
1574
6.53k
    struct rszbuf   end_oid_buf = {
1575
6.53k
        end_oid_buffer,
1576
6.53k
        -(int)sizeof(end_oid_buffer)
1577
6.53k
    };
1578
6.53k
    int             range_bound;        /* OID-range upper bound */
1579
6.53k
    int             inc;        /* Inclusive SearchRange flag */
1580
6.53k
    int             type;       /* VarBind data type */
1581
6.53k
    size_t         *length = &len;
1582
6.53k
    const int       dbgindent = debug_indent_get();
1583
6.53k
    int             res = SNMP_ERR_NOERROR;
1584
1585
6.53k
    if (pdu == NULL)
1586
0
        return SNMP_ERR_NOERROR;
1587
 
1588
6.53k
    if (!IS_AGENTX_VERSION(session->version)) {
1589
0
        res = SNMPERR_BAD_VERSION;
1590
0
        goto out;
1591
0
    }
1592
1593
6.53k
#ifndef SNMPERR_INCOMPLETE_PACKET
1594
    /*
1595
     *  Ideally, "short" packets on stream connections should
1596
     *    be handled specially, and the driving code set up to
1597
     *    keep reading until the full packet is received.
1598
     *
1599
     *  For now, lets assume that all packets are read in one go.
1600
     *    I've probably inflicted enough damage on the UCD library
1601
     *    for one week!
1602
     *
1603
     *  I'll come back to this once Wes is speaking to me again.
1604
     */
1605
6.53k
#define SNMPERR_INCOMPLETE_PACKET SNMPERR_ASN_PARSE_ERR
1606
6.53k
#endif
1607
1608
6.53k
    if (len > 65536)
1609
66
        goto parse_err;
1610
1611
    /*
1612
     *  Handle (common) header ....
1613
     */
1614
6.46k
    bufp = agentx_parse_header(pdu, bufp, length);
1615
6.46k
    if (bufp == NULL) {
1616
3.44k
        res = SNMPERR_INCOMPLETE_PACKET;       /* i.e. wait for the rest */
1617
3.44k
        goto out;
1618
3.44k
    }
1619
1620
    /*
1621
     * Control PDU handling 
1622
     */
1623
3.01k
    pdu->flags |= UCD_MSG_FLAG_ALWAYS_IN_VIEW;
1624
3.01k
    pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
1625
3.01k
    pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
1626
1627
    /*
1628
     *  ... and (not-un-common) context
1629
     */
1630
3.01k
    if (pdu->flags & AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT) {
1631
585
        DEBUGDUMPHEADER("recv", "Context");
1632
585
        bufp = agentx_parse_string(bufp, length, &data_buf, pdu->flags &
1633
585
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1634
585
        DEBUGINDENTLESS();
1635
585
        if (bufp == NULL)
1636
142
            goto parse_err;
1637
1638
443
        pdu->community_len = data_buf.used;
1639
443
        snmp_clone_mem((void **)&pdu->community, data_buf.buf, data_buf.used);
1640
    
1641
        /* The NetSNMP API stuffs the context into the PDU's community string
1642
         * field, when using the AgentX Protocol.  The rest of the code however,
1643
         * expects to find the context in the PDU's context field.  Therefore we
1644
         * need to copy the context into the PDU's context fields.  */
1645
443
        if (pdu->community_len > 0 && pdu->contextName == NULL) {
1646
            /*
1647
             * strlen() is safe here because snmp_clone_mem() '\0'-terminates its output
1648
             */
1649
165
            if (strlen((const char *)pdu->community) != pdu->community_len)
1650
59
                goto parse_err;
1651
106
            pdu->contextName    = strdup((char *) pdu->community);
1652
106
            pdu->contextNameLen = pdu->community_len;
1653
106
        }
1654
443
    }
1655
1656
2.81k
#define AGENTX_NEEDLEN( len ) \
1657
2.81k
        if ( *length < len ) { \
1658
50
            goto parse_err; \
1659
50
        }
1660
2.81k
    DEBUGDUMPHEADER("recv", "PDU");
1661
2.81k
    switch (pdu->command) {
1662
115
    case AGENTX_MSG_OPEN:
1663
115
        AGENTX_NEEDLEN(4);
1664
110
        pdu->time = *bufp;      /* Timeout */
1665
110
        bufp += 4;
1666
110
        *length -= 4;
1667
1668
        /*
1669
         * Store subagent OID & description in a VarBind 
1670
         */
1671
110
        DEBUGDUMPHEADER("recv", "Subagent OID");
1672
110
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf, pdu->flags &
1673
110
                                AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1674
110
        DEBUGINDENTLESS();
1675
110
        if (bufp == NULL)
1676
10
            goto parse_err;
1677
100
        DEBUGDUMPHEADER("recv", "Subagent Description");
1678
100
        bufp = agentx_parse_string(bufp, length, &data_buf, pdu->flags &
1679
100
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1680
100
        DEBUGINDENTLESS();
1681
100
        if (bufp == NULL)
1682
34
            goto parse_err;
1683
66
        snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1684
66
                              ASN_OCTET_STR, data_buf.buf, data_buf.used);
1685
66
        break;
1686
1687
50
    case AGENTX_MSG_CLOSE:
1688
50
        AGENTX_NEEDLEN(4);
1689
43
        pdu->errstat = *bufp;   /* Reason */
1690
43
        bufp += 4;
1691
43
        *length -= 4;
1692
1693
43
        break;
1694
1695
69
    case AGENTX_MSG_UNREGISTER:
1696
264
    case AGENTX_MSG_REGISTER:
1697
264
        AGENTX_NEEDLEN(4);
1698
256
        DEBUGDUMPHEADER("recv", "Registration Header");
1699
256
        if (pdu->command == AGENTX_MSG_REGISTER) {
1700
192
            pdu->time = *bufp;  /* Timeout (Register only) */
1701
192
            DEBUGDUMPSETUP("recv", bufp, 1);
1702
192
            DEBUGMSG(("dumpv_recv", "  Timeout:     \t%d\n", *bufp));
1703
192
        }
1704
256
        bufp++;
1705
256
        pdu->priority = *bufp;
1706
256
        DEBUGDUMPSETUP("recv", bufp, 1);
1707
256
        DEBUGMSG(("dumpv_recv", "  Priority:    \t%d\n", *bufp));
1708
256
        bufp++;
1709
256
        pdu->range_subid = *bufp;
1710
256
        DEBUGDUMPSETUP("recv", bufp, 1);
1711
256
        DEBUGMSG(("dumpv_recv", "  Range Sub-Id:\t%d\n", *bufp));
1712
256
        bufp++;
1713
256
        bufp++;
1714
256
        *length -= 4;
1715
256
        DEBUGINDENTLESS();
1716
1717
256
        DEBUGDUMPHEADER("recv", "Registration OID");
1718
256
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf, pdu->flags &
1719
256
                                AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1720
256
        DEBUGINDENTLESS();
1721
256
        if (bufp == NULL)
1722
11
            goto parse_err;
1723
1724
245
        if (pdu->range_subid) {
1725
209
            if (pdu->range_subid > oid_buf.used)
1726
45
                goto parse_err;
1727
164
            AGENTX_NEEDLEN(4);
1728
153
            range_bound = agentx_parse_int(bufp, pdu->flags &
1729
153
                                           AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1730
153
            bufp += 4;
1731
153
            *length -= 4;
1732
1733
            /*
1734
             * Construct the end-OID.  
1735
             */
1736
153
            if (!increase_size(&end_oid_buf, oid_buf.used * sizeof(oid)))
1737
0
                goto parse_err;
1738
153
            memcpy(end_oid_buf.buf, oid_buf.buf, oid_buf.used * sizeof(oid));
1739
153
            ((oid *)end_oid_buf.buf)[pdu->range_subid - 1] = range_bound;
1740
1741
153
            snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1742
153
                                  ASN_PRIV_INCL_RANGE, end_oid_buf.buf,
1743
153
                                  oid_buf.used * sizeof(oid));
1744
153
        } else {
1745
36
            snmp_add_null_var(pdu, oid_buf.buf, oid_buf.used);
1746
36
        }
1747
189
        break;
1748
1749
189
    case AGENTX_MSG_GETBULK:
1750
88
        AGENTX_NEEDLEN(4);
1751
81
        DEBUGDUMPHEADER("recv", "Non-repeaters");
1752
81
        pdu->non_repeaters = agentx_parse_short(bufp, pdu->flags &
1753
81
                                                AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1754
81
        DEBUGINDENTLESS();
1755
81
        DEBUGDUMPHEADER("recv", "Max-repeaters");
1756
81
        pdu->max_repetitions = agentx_parse_short(bufp + 2, pdu->flags &
1757
81
                                                  AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1758
81
        DEBUGINDENTLESS();
1759
81
        bufp += 4;
1760
81
        *length -= 4;
1761
81
        NETSNMP_FALLTHROUGH;
1762
1763
260
    case AGENTX_MSG_GETNEXT:
1764
425
    case AGENTX_MSG_GET:
1765
1766
        /*
1767
         * *  SearchRange List
1768
         * *  Keep going while we have data left
1769
         */
1770
425
        DEBUGDUMPHEADER("recv", "Search Range");
1771
39.4k
        while (*length > 0) {
1772
39.2k
            bufp = agentx_parse_oid(bufp, length, &inc, &oid_buf, pdu->flags &
1773
39.2k
                                    AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1774
39.2k
            if (bufp == NULL)
1775
96
                goto parse_err;
1776
39.1k
            bufp = agentx_parse_oid(bufp, length, NULL, &end_oid_buf,
1777
39.1k
                                    pdu->flags &
1778
39.1k
                                    AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1779
39.1k
            if (bufp == NULL)
1780
121
                goto parse_err;
1781
            /*
1782
             * 'agentx_parse_oid()' returns the number of sub_ids 
1783
             */
1784
39.0k
            snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1785
39.0k
                                  inc ? ASN_PRIV_INCL_RANGE :
1786
39.0k
                                  ASN_PRIV_EXCL_RANGE,
1787
39.0k
                                  end_oid_buf.buf,
1788
39.0k
                                  end_oid_buf.used * sizeof(oid));
1789
39.0k
        }
1790
1791
208
        DEBUGINDENTLESS();
1792
208
        break;
1793
1794
1795
210
    case AGENTX_MSG_RESPONSE:
1796
1797
210
        pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
1798
1799
210
        AGENTX_NEEDLEN(8);
1800
1801
        /*
1802
         * sysUpTime 
1803
         */
1804
198
        pdu->time = agentx_parse_int(bufp, pdu->flags &
1805
198
                                     AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1806
198
        bufp += 4;
1807
198
        *length -= 4;
1808
1809
198
        pdu->errstat = agentx_parse_short(bufp, pdu->flags &
1810
198
                                          AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1811
198
        pdu->errindex =
1812
198
            agentx_parse_short(bufp + 2,
1813
198
                               pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1814
198
        bufp += 4;
1815
198
        *length -= 4;
1816
198
        NETSNMP_FALLTHROUGH;
1817
1818
380
    case AGENTX_MSG_INDEX_ALLOCATE:
1819
827
    case AGENTX_MSG_INDEX_DEALLOCATE:
1820
1.05k
    case AGENTX_MSG_NOTIFY:
1821
1.37k
    case AGENTX_MSG_TESTSET:
1822
1823
        /*
1824
         * *  VarBind List
1825
         * *  Keep going while we have data left
1826
         */
1827
1828
1.37k
        DEBUGDUMPHEADER("recv", "VarBindList");
1829
50.0k
        while (*length > 0) {
1830
49.4k
            bufp = agentx_parse_varbind(bufp, length, &type, &oid_buf,
1831
49.4k
                                        &data_buf, pdu->flags &
1832
49.4k
                                        AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1833
49.4k
            if (bufp == NULL)
1834
841
                goto parse_err;
1835
48.6k
            snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used, type,
1836
48.6k
                                  data_buf.buf, data_buf.used);
1837
48.6k
        }
1838
537
        DEBUGINDENTLESS();
1839
537
        break;
1840
1841
3
    case AGENTX_MSG_COMMITSET:
1842
6
    case AGENTX_MSG_UNDOSET:
1843
9
    case AGENTX_MSG_CLEANUPSET:
1844
12
    case AGENTX_MSG_PING:
1845
1846
        /*
1847
         * "Empty" packet 
1848
         */
1849
12
        break;
1850
1851
1852
86
    case AGENTX_MSG_ADD_AGENT_CAPS:
1853
        /*
1854
         * Store AgentCap OID & description in a VarBind 
1855
         */
1856
86
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf,
1857
86
                                pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1858
86
        if (bufp == NULL)
1859
12
            goto parse_err;
1860
74
        bufp = agentx_parse_string(bufp, length, &data_buf, pdu->flags &
1861
74
                                   AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1862
74
        if (bufp == NULL)
1863
19
            goto parse_err;
1864
55
        snmp_pdu_add_variable(pdu, oid_buf.buf, oid_buf.used,
1865
55
                              ASN_OCTET_STR, data_buf.buf, data_buf.used);
1866
55
        break;
1867
1868
430
    case AGENTX_MSG_REMOVE_AGENT_CAPS:
1869
        /*
1870
         * Store AgentCap OID & description in a VarBind 
1871
         */
1872
430
        bufp = agentx_parse_oid(bufp, length, NULL, &oid_buf,
1873
430
                                pdu->flags & AGENTX_FLAGS_NETWORK_BYTE_ORDER);
1874
430
        if (bufp == NULL)
1875
15
            goto parse_err;
1876
415
        snmp_add_null_var(pdu, oid_buf.buf, oid_buf.used);
1877
415
        break;
1878
1879
36
    default:
1880
36
        DEBUGMSGTL(("agentx", "Unrecognised PDU type: %d\n",
1881
36
                    pdu->command));
1882
36
        res = SNMPERR_UNKNOWN_PDU;
1883
2.81k
    }
1884
1885
6.53k
out:
1886
6.53k
    debug_indent_add(dbgindent - debug_indent_get());
1887
6.53k
    cleanup_rszbuf(&end_oid_buf);
1888
6.53k
    cleanup_rszbuf(&oid_buf);
1889
6.53k
    cleanup_rszbuf(&data_buf);
1890
6.53k
    return res;
1891
1892
1.52k
parse_err:
1893
1.52k
    res = SNMPERR_ASN_PARSE_ERR;
1894
1.52k
    goto out;
1895
2.81k
}
1896
#undef AGENTX_NEEDLEN
1897
1898
1899
1900
1901
#ifdef TESTING
1902
1903
void testit(netsnmp_pdu *pdu1)
1904
{
1905
    char            packet1[BUFSIZ];
1906
    char            packet2[BUFSIZ];
1907
    int             len1, len2;
1908
    netsnmp_pdu     pdu2;
1909
    netsnmp_session sess;
1910
1911
    memset(&pdu2, 0, sizeof(netsnmp_pdu));
1912
    memset(packet1, 0, BUFSIZ);
1913
    memset(packet2, 0, BUFSIZ);
1914
1915
    /*
1916
     * Encode this into a "packet" 
1917
     */
1918
    len1 = BUFSIZ;
1919
    if (agentx_build(&sess, pdu1, packet1, &len1) < 0) {
1920
        DEBUGMSGTL(("agentx", "First build failed\n"));
1921
        exit(1);
1922
    }
1923
1924
    DEBUGMSGTL(("agentx", "First build succeeded:\n"));
1925
    xdump(packet1, len1, "Ax1> ");
1926
1927
    /*
1928
     * Unpack this into a PDU 
1929
     */
1930
    len2 = len1;
1931
    if (agentx_parse(&pdu2, packet1, &len2, (u_char **) NULL) < 0) {
1932
        DEBUGMSGTL(("agentx", "First parse failed\n"));
1933
        exit(1);
1934
    }
1935
    DEBUGMSGTL(("agentx", "First parse succeeded:\n"));
1936
    if (len2 != 0)
1937
        DEBUGMSGTL(("agentx",
1938
                    "Warning - parsed packet has %d bytes left\n", len2));
1939
1940
    /*
1941
     * Encode this into another "packet" 
1942
     */
1943
    len2 = BUFSIZ;
1944
    if (agentx_build(&sess, &pdu2, packet2, &len2) < 0) {
1945
        DEBUGMSGTL(("agentx", "Second build failed\n"));
1946
        exit(1);
1947
    }
1948
1949
    DEBUGMSGTL(("agentx", "Second build succeeded:\n"));
1950
    xdump(packet2, len2, "Ax2> ");
1951
1952
    /*
1953
     * Compare the results 
1954
     */
1955
    if (len1 != len2) {
1956
        DEBUGMSGTL(("agentx",
1957
                    "Error: first build (%d) is different to second (%d)\n",
1958
                    len1, len2));
1959
        exit(1);
1960
    }
1961
    if (memcmp(packet1, packet2, len1) != 0) {
1962
        DEBUGMSGTL(("agentx",
1963
                    "Error: first build data is different to second\n"));
1964
        exit(1);
1965
    }
1966
1967
    DEBUGMSGTL(("agentx", "OK\n"));
1968
}
1969
1970
1971
1972
int main(void)
1973
{
1974
    netsnmp_pdu     pdu1;
1975
    oid             oid_buf[] = { 1, 3, 6, 1, 2, 1, 10 };
1976
    oid             oid_buf2[] = { 1, 3, 6, 1, 2, 1, 20 };
1977
    oid             null_oid[] = { 0, 0 };
1978
    char           *string = "Example string";
1979
    char           *context = "LUCS";
1980
1981
1982
    /*
1983
     * Create an example AgentX pdu structure 
1984
     */
1985
1986
    memset(&pdu1, 0, sizeof(netsnmp_pdu));
1987
    pdu1.command = AGENTX_MSG_TESTSET;
1988
    pdu1.flags = 0;
1989
    pdu1.sessid = 16;
1990
    pdu1.transid = 24;
1991
    pdu1.reqid = 132;
1992
1993
    pdu1.time = 10;
1994
    pdu1.non_repeaters = 3;
1995
    pdu1.max_repetitions = 32;
1996
    pdu1.priority = 5;
1997
    pdu1.range_subid = 0;
1998
1999
    snmp_pdu_add_variable(&pdu1, oid_buf, OID_LENGTH(oid_buf),
2000
                          ASN_OBJECT_ID, (char *) oid_buf2,
2001
                          sizeof(oid_buf2));
2002
    snmp_pdu_add_variable(&pdu1, oid_buf, OID_LENGTH(oid_buf),
2003
                          ASN_INTEGER, (char *) &pdu1.reqid,
2004
                          sizeof(pdu1.reqid));
2005
    snmp_pdu_add_variable(&pdu1, oid_buf, OID_LENGTH(oid_buf),
2006
                          ASN_OCTET_STR, (char *) string, strlen(string));
2007
2008
    printf("Test with non-network order.....\n");
2009
    testit(&pdu1);
2010
2011
    printf("\nTest with network order.....\n");
2012
    pdu1.flags |= AGENTX_FLAGS_NETWORK_BYTE_ORDER;
2013
    testit(&pdu1);
2014
2015
    pdu1.community = context;
2016
    pdu1.community_len = strlen(context);
2017
    pdu1.flags |= AGENTX_FLAGS_NON_DEFAULT_CONTEXT;
2018
    printf("Test with non-default context.....\n");
2019
    testit(&pdu1);
2020
2021
2022
}
2023
#endif
2024
2025
/*
2026
 * returns the proper length of an incoming agentx packet. 
2027
 */
2028
/*
2029
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2030
 *    |   h.version   |    h.type     |    h.flags    |  <reserved>   |
2031
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2032
 *    |                          h.sessionID                          |
2033
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2034
 *    |                        h.transactionID                        |
2035
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2036
 *    |                          h.packetID                           |
2037
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2038
 *    |                        h.payload_length                       |
2039
 *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2040
 *    20 bytes in header
2041
 */
2042
2043
int
2044
agentx_check_packet(u_char * packet, size_t packet_len)
2045
0
{
2046
2047
0
    if (packet_len < 20)
2048
0
        return 0;               /* minimum header length == 20 */
2049
2050
0
    return agentx_parse_int(packet + 16,
2051
0
                            *(packet +
2052
0
                              2) & AGENTX_FLAGS_NETWORK_BYTE_ORDER) + 20;
2053
0
}