Coverage Report

Created: 2025-11-29 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/agent/agent_index.c
Line
Count
Source
1
/*
2
 * agent_index.c
3
 *
4
 * Maintain a registry of index allocations
5
 *      (Primarily required for AgentX support,
6
 *       but it could be more widely usable).
7
 */
8
9
10
#include <net-snmp/net-snmp-config.h>
11
#include <net-snmp/net-snmp-features.h>
12
#include <signal.h>
13
#ifdef HAVE_STRING_H
14
#include <string.h>
15
#endif
16
#ifdef HAVE_STDLIB_H
17
#include <stdlib.h>
18
#endif
19
#include <sys/types.h>
20
#include <stdio.h>
21
#include <fcntl.h>
22
#ifdef TIME_WITH_SYS_TIME
23
# include <sys/time.h>
24
# include <time.h>
25
#else
26
# ifdef HAVE_SYS_TIME_H
27
#  include <sys/time.h>
28
# else
29
#  include <time.h>
30
# endif
31
#endif
32
#ifdef HAVE_NETINET_IN_H
33
#include <netinet/in.h>
34
#endif
35
36
#include <net-snmp/net-snmp-includes.h>
37
#include <net-snmp/agent/net-snmp-agent-includes.h>
38
#include <net-snmp/agent/agent_callbacks.h>
39
#include <net-snmp/agent/agent_index.h>
40
41
#include "snmpd.h"
42
#include "agent_global_vars.h"
43
#include "mibgroup/struct.h"
44
#include <net-snmp/agent/table.h>
45
#include <net-snmp/agent/table_iterator.h>
46
47
#ifdef USING_AGENTX_SUBAGENT_MODULE
48
#include "agentx/subagent.h"
49
#include "agentx/client.h"
50
#endif
51
52
netsnmp_feature_child_of(agent_index_all, libnetsnmpagent);
53
54
netsnmp_feature_child_of(remove_index, agent_index_all);
55
56
        /*
57
         * Initial support for index allocation
58
         */
59
60
struct snmp_index {
61
    netsnmp_variable_list *varbind;     /* or pointer to var_list ? */
62
    int             allocated;
63
    netsnmp_session *session;
64
    struct snmp_index *next_oid;
65
    struct snmp_index *prev_oid;
66
    struct snmp_index *next_idx;
67
}              *snmp_index_head = NULL;
68
69
/*
70
 * The caller is responsible for free()ing the memory returned by
71
 * this function.  
72
 */
73
74
char           *
75
register_string_index(oid * name, size_t name_len, char *cp)
76
0
{
77
0
    netsnmp_variable_list varbind, *res;
78
79
0
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
80
0
    varbind.type = ASN_OCTET_STR;
81
0
    snmp_set_var_objid(&varbind, name, name_len);
82
0
    if (cp != ANY_STRING_INDEX) {
83
0
        snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp));
84
0
        res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
85
0
    } else {
86
0
        res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
87
0
    }
88
89
0
    if (res == NULL) {
90
0
        return NULL;
91
0
    } else {
92
0
        char *rv = (char *)malloc(res->val_len + 1);
93
0
        if (rv) {
94
0
            memcpy(rv, res->val.string, res->val_len);
95
0
            rv[res->val_len] = 0;
96
0
        }
97
0
        free(res);
98
0
        return rv;
99
0
    }
100
0
}
101
102
int
103
register_int_index(oid * name, size_t name_len, int val)
104
0
{
105
0
    netsnmp_variable_list varbind, *res;
106
107
0
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
108
0
    varbind.type = ASN_INTEGER;
109
0
    snmp_set_var_objid(&varbind, name, name_len);
110
0
    varbind.val.string = varbind.buf;
111
0
    if (val != ANY_INTEGER_INDEX) {
112
0
        varbind.val_len = sizeof(long);
113
0
        *varbind.val.integer = val;
114
0
        res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
115
0
    } else {
116
0
        res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
117
0
    }
118
119
0
    if (res == NULL) {
120
0
        return -1;
121
0
    } else {
122
0
        int             rv = *(res->val.integer);
123
0
        free(res);
124
0
        return rv;
125
0
    }
126
0
}
127
128
/*
129
 * The caller is responsible for free()ing the memory returned by
130
 * this function.  
131
 */
132
133
netsnmp_variable_list *
134
register_oid_index(oid * name, size_t name_len,
135
                   oid * value, size_t value_len)
136
0
{
137
0
    netsnmp_variable_list varbind;
138
139
0
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
140
0
    varbind.type = ASN_OBJECT_ID;
141
0
    snmp_set_var_objid(&varbind, name, name_len);
142
0
    if (value != ANY_OID_INDEX) {
143
0
        snmp_set_var_value(&varbind, (u_char *) value,
144
0
                           value_len * sizeof(oid));
145
0
        return register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
146
0
    } else {
147
0
        return register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
148
0
    }
149
0
}
150
151
/*
152
 * The caller is responsible for free()ing the memory returned by
153
 * this function.  
154
 */
155
156
netsnmp_variable_list *
157
register_index(netsnmp_variable_list * varbind, int flags,
158
               netsnmp_session * ss)
159
0
{
160
0
    netsnmp_variable_list *rv = NULL;
161
0
    struct snmp_index *new_index, *idxptr, *idxptr2;
162
0
    struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
163
0
    int             res, res2, i;
164
165
0
    DEBUGMSGTL(("register_index", "register "));
166
0
    DEBUGMSGVAR(("register_index", varbind));
167
0
    DEBUGMSG(("register_index", "for session %8p\n", ss));
168
169
0
#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
170
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
171
0
             NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
172
0
        return (agentx_register_index(ss, varbind, flags));
173
0
    }
174
0
#endif
175
    /*
176
     * Look for the requested OID entry 
177
     */
178
0
    prev_oid_ptr = NULL;
179
0
    prev_idx_ptr = NULL;
180
0
    res = 1;
181
0
    res2 = 1;
182
0
    for (idxptr = snmp_index_head; idxptr != NULL;
183
0
         prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
184
0
        if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
185
0
                                    idxptr->varbind->name,
186
0
                                    idxptr->varbind->name_length)) <= 0)
187
0
            break;
188
0
    }
189
190
    /*
191
     * Found the OID - now look at the registered indices 
192
     */
193
0
    if (res == 0 && idxptr) {
194
0
        if (varbind->type != idxptr->varbind->type)
195
0
            return NULL;        /* wrong type */
196
197
        /*
198
         * If we've been asked for an arbitrary new value,
199
         *      then find the end of the list.
200
         * If we've been asked for any arbitrary value,
201
         *      then look for an unused entry, and use that.
202
         *      If there aren't any, continue as for new.
203
         * Otherwise, locate the given value in the (sorted)
204
         *      list of already allocated values
205
         */
206
0
        if (flags & ALLOCATE_ANY_INDEX) {
207
0
            for (idxptr2 = idxptr; idxptr2 != NULL;
208
0
                 prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
209
210
0
                if (flags == ALLOCATE_ANY_INDEX && !(idxptr2->allocated)) {
211
0
                    if ((rv =
212
0
                         snmp_clone_varbind(idxptr2->varbind)) != NULL) {
213
0
                        idxptr2->session = ss;
214
0
                        idxptr2->allocated = 1;
215
0
                    }
216
0
                    return rv;
217
0
                }
218
0
            }
219
0
        } else {
220
0
            for (idxptr2 = idxptr; idxptr2 != NULL;
221
0
                 prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
222
0
                switch (varbind->type) {
223
0
                case ASN_INTEGER:
224
0
                    res2 =
225
0
                        (*varbind->val.integer -
226
0
                         *idxptr2->varbind->val.integer);
227
0
                    break;
228
0
                case ASN_OCTET_STR:
229
0
                    i = SNMP_MIN(varbind->val_len,
230
0
                                 idxptr2->varbind->val_len);
231
0
                    res2 =
232
0
                        memcmp(varbind->val.string,
233
0
                               idxptr2->varbind->val.string, i);
234
0
                    break;
235
0
                case ASN_OBJECT_ID:
236
0
                    res2 =
237
0
                        snmp_oid_compare(varbind->val.objid,
238
0
                                         varbind->val_len / sizeof(oid),
239
0
                                         idxptr2->varbind->val.objid,
240
0
                                         idxptr2->varbind->val_len /
241
0
                                         sizeof(oid));
242
0
                    break;
243
0
                default:
244
0
                    return NULL;        /* wrong type */
245
0
                }
246
0
                if (res2 <= 0)
247
0
                    break;
248
0
            }
249
0
            if (res2 == 0) {
250
0
                if (idxptr2->allocated) {
251
                    /*
252
                     * No good: the index is in use.  
253
                     */
254
0
                    return NULL;
255
0
                } else {
256
                    /*
257
                     * Okay, it's unallocated, we can just claim ownership
258
                     * here.  
259
                     */
260
0
                    if ((rv =
261
0
                         snmp_clone_varbind(idxptr2->varbind)) != NULL) {
262
0
                        idxptr2->session = ss;
263
0
                        idxptr2->allocated = 1;
264
0
                    }
265
0
                    return rv;
266
0
                }
267
0
            }
268
0
        }
269
0
    }
270
271
    /*
272
     * OK - we've now located where the new entry needs to
273
     *      be fitted into the index registry tree          
274
     * To recap:
275
     *      'prev_oid_ptr' points to the head of the OID index
276
     *          list prior to this one.  If this is null, then
277
     *          it means that this is the first OID in the list.
278
     *      'idxptr' points either to the head of this OID list,
279
     *          or the next OID (if this is a new OID request)
280
     *          These can be distinguished by the value of 'res'.
281
     *
282
     *      'prev_idx_ptr' points to the index entry that sorts
283
     *          immediately prior to the requested value (if any).
284
     *          If an arbitrary value is required, then this will
285
     *          point to the last allocated index.
286
     *          If this pointer is null, then either this is a new
287
     *          OID request, or the requested value is the first
288
     *          in the list.
289
     *      'idxptr2' points to the next sorted index (if any)
290
     *          but is not actually needed any more.
291
     *
292
     *  Clear?  Good!
293
     *      I hope you've been paying attention.
294
     *          There'll be a test later :-)
295
     */
296
297
    /*
298
     *      We proceed by creating the new entry
299
     *         (by copying the entry provided)
300
     */
301
0
    new_index = calloc(1, sizeof(struct snmp_index));
302
0
    if (new_index == NULL)
303
0
        return NULL;
304
305
0
    if (NULL == snmp_varlist_add_variable(&new_index->varbind,
306
0
                                          varbind->name,
307
0
                                          varbind->name_length,
308
0
                                          varbind->type,
309
0
                                          varbind->val.string,
310
0
                                          varbind->val_len)) {
311
        /*
312
         * if (snmp_clone_var( varbind, new_index->varbind ) != 0 ) 
313
         */
314
0
        free(new_index);
315
0
        return NULL;
316
0
    }
317
0
    new_index->session = ss;
318
0
    new_index->allocated = 1;
319
320
0
    if (varbind->type == ASN_OCTET_STR && flags == ALLOCATE_THIS_INDEX)
321
0
        new_index->varbind->val.string[new_index->varbind->val_len] = 0;
322
323
    /*
324
     * If we've been given a value, then we can use that, but
325
     *    otherwise, we need to create a new value for this entry.
326
     * Note that ANY_INDEX and NEW_INDEX are both covered by this
327
     *   test (since NEW_INDEX & ANY_INDEX = ANY_INDEX, remember?)
328
     */
329
0
    if (flags & ALLOCATE_ANY_INDEX) {
330
0
        if (prev_idx_ptr) {
331
0
            if (snmp_clone_var(prev_idx_ptr->varbind, new_index->varbind)
332
0
                != 0) {
333
0
                free(new_index);
334
0
                return NULL;
335
0
            }
336
0
        } else
337
0
            new_index->varbind->val.string = new_index->varbind->buf;
338
339
0
        switch (varbind->type) {
340
0
        case ASN_INTEGER:
341
0
            if (prev_idx_ptr) {
342
0
                (*new_index->varbind->val.integer)++;
343
0
            } else
344
0
                *(new_index->varbind->val.integer) = 1;
345
0
            new_index->varbind->val_len = sizeof(long);
346
0
            break;
347
0
        case ASN_OCTET_STR:
348
0
            if (prev_idx_ptr) {
349
0
                size_t maxlen = sizeof(new_index->varbind->buf);
350
0
                i = new_index->varbind->val_len - 1;
351
352
0
                while (i >= 0 && new_index->varbind->buf[i] == 'z') {
353
0
                    new_index->varbind->buf[i] = 'a';
354
0
                    i--;
355
0
                }
356
357
0
                if (i >= 0) {
358
0
                    new_index->varbind->buf[i]++;
359
0
                } else {
360
                    /* All 'z's — need to grow */
361
0
                    if (new_index->varbind->val_len + 1 < maxlen) {
362
0
                        memmove(new_index->varbind->buf + 1, new_index->varbind->buf,
363
0
                                new_index->varbind->val_len);
364
0
                        new_index->varbind->buf[0] = 'a';
365
0
                        new_index->varbind->val_len++;
366
0
                    } else {
367
                        /* Buffer full — cannot grow */
368
0
                        free(new_index);
369
0
                        return NULL;
370
0
                    }
371
0
                }
372
0
            } else {
373
0
                strcpy((char *) new_index->varbind->buf, "aaaa");
374
0
                new_index->varbind->val_len = 4;
375
0
            }
376
0
            break;
377
0
        case ASN_OBJECT_ID:
378
0
            if (prev_idx_ptr) {
379
0
                i = prev_idx_ptr->varbind->val_len / sizeof(oid) - 1;
380
0
                while (new_index->varbind->val.objid[i] == 255) {
381
0
                    new_index->varbind->val.objid[i] = 1;
382
0
                    i--;
383
0
                    if (i == 0 && new_index->varbind->val.objid[0] == 2) {
384
0
                        new_index->varbind->val.objid[0] = 1;
385
0
                        i = new_index->varbind->val_len / sizeof(oid);
386
0
                        new_index->varbind->val.objid[i] = 0;
387
0
                        new_index->varbind->val_len += sizeof(oid);
388
0
                    }
389
0
                }
390
0
                new_index->varbind->val.objid[i]++;
391
0
            } else {
392
                /*
393
                 * If the requested OID name is small enough,
394
                 * *   append another OID (1) and use this as the
395
                 * *   default starting value for new indexes.
396
                 */
397
0
                if ((varbind->name_length + 1) * sizeof(oid) <= 40) {
398
0
                    for (i = 0; i < (int) varbind->name_length; i++)
399
0
                        new_index->varbind->val.objid[i] =
400
0
                            varbind->name[i];
401
0
                    new_index->varbind->val.objid[varbind->name_length] =
402
0
                        1;
403
0
                    new_index->varbind->val_len =
404
0
                        (varbind->name_length + 1) * sizeof(oid);
405
0
                } else {
406
                    /*
407
                     * Otherwise use '.1.1.1.1...' 
408
                     */
409
0
                    i = 40 / sizeof(oid);
410
0
                    if (i > 4)
411
0
                        i = 4;
412
0
                    new_index->varbind->val_len = i * (sizeof(oid));
413
0
                    for (i--; i >= 0; i--)
414
0
                        new_index->varbind->val.objid[i] = 1;
415
0
                }
416
0
            }
417
0
            break;
418
0
        default:
419
0
            snmp_free_var(new_index->varbind);
420
0
            free(new_index);
421
0
            return NULL;        /* Index type not supported */
422
0
        }
423
0
    }
424
425
    /*
426
     * Try to duplicate the new varbind for return.  
427
     */
428
429
0
    if ((rv = snmp_clone_varbind(new_index->varbind)) == NULL) {
430
0
        snmp_free_var(new_index->varbind);
431
0
        free(new_index);
432
0
        return NULL;
433
0
    }
434
435
    /*
436
     * Right - we've set up the new entry.
437
     * All that remains is to link it into the tree.
438
     * There are a number of possible cases here,
439
     *   so watch carefully.
440
     */
441
0
    if (prev_idx_ptr) {
442
0
        new_index->next_idx = prev_idx_ptr->next_idx;
443
0
        new_index->next_oid = prev_idx_ptr->next_oid;
444
0
        prev_idx_ptr->next_idx = new_index;
445
0
    } else {
446
0
        if (res == 0 && idxptr) {
447
0
            new_index->next_idx = idxptr;
448
0
            new_index->next_oid = idxptr->next_oid;
449
0
        } else {
450
0
            new_index->next_idx = NULL;
451
0
            new_index->next_oid = idxptr;
452
0
        }
453
454
0
        if (prev_oid_ptr) {
455
0
            while (prev_oid_ptr) {
456
0
                prev_oid_ptr->next_oid = new_index;
457
0
                prev_oid_ptr = prev_oid_ptr->next_idx;
458
0
            }
459
0
        } else
460
0
            snmp_index_head = new_index;
461
0
    }
462
0
    return rv;
463
0
}
464
465
        /*
466
         * Release an allocated index,
467
         *   to allow it to be used elsewhere
468
         */
469
netsnmp_feature_child_of(release_index,netsnmp_unused);
470
#ifndef NETSNMP_FEATURE_REMOVE_RELEASE_INDEX
471
int
472
release_index(netsnmp_variable_list * varbind)
473
0
{
474
0
    return (unregister_index(varbind, TRUE, NULL));
475
0
}
476
#endif /* NETSNMP_FEATURE_REMOVE_RELEASE_INDEX */
477
478
#ifndef NETSNMP_FEATURE_REMOVE_REMOVE_INDEX
479
        /*
480
         * Completely remove an allocated index,
481
         *   due to errors in the registration process.
482
         */
483
int
484
remove_index(netsnmp_variable_list * varbind, netsnmp_session * ss)
485
0
{
486
0
    return (unregister_index(varbind, FALSE, ss));
487
0
}
488
#endif /* NETSNMP_FEATURE_REMOVE_REMOVE_INDEX */
489
490
void
491
unregister_index_by_session(netsnmp_session * ss)
492
0
{
493
0
    struct snmp_index *idxptr, *idxptr2;
494
0
    for (idxptr = snmp_index_head; idxptr != NULL;
495
0
         idxptr = idxptr->next_oid)
496
0
        for (idxptr2 = idxptr; idxptr2 != NULL;
497
0
             idxptr2 = idxptr2->next_idx)
498
0
            if (idxptr2->session == ss) {
499
0
                idxptr2->allocated = 0;
500
0
                idxptr2->session = NULL;
501
0
            }
502
0
}
503
504
505
int
506
unregister_index(netsnmp_variable_list * varbind, int remember,
507
                 netsnmp_session * ss)
508
0
{
509
0
    struct snmp_index *idxptr, *idxptr2;
510
0
    struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
511
0
    int             res, res2, i;
512
513
0
#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
514
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
515
0
             NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
516
0
        return (agentx_unregister_index(ss, varbind));
517
0
    }
518
0
#endif
519
    /*
520
     * Look for the requested OID entry 
521
     */
522
0
    prev_oid_ptr = NULL;
523
0
    prev_idx_ptr = NULL;
524
0
    res = 1;
525
0
    res2 = 1;
526
0
    for (idxptr = snmp_index_head; idxptr != NULL;
527
0
         prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
528
0
        if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
529
0
                                    idxptr->varbind->name,
530
0
                                    idxptr->varbind->name_length)) <= 0)
531
0
            break;
532
0
    }
533
534
0
    if (res != 0)
535
0
        return INDEX_ERR_NOT_ALLOCATED;
536
0
    if (varbind->type != idxptr->varbind->type)
537
0
        return INDEX_ERR_WRONG_TYPE;
538
539
0
    for (idxptr2 = idxptr; idxptr2 != NULL;
540
0
         prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
541
0
        switch (varbind->type) {
542
0
        case ASN_INTEGER:
543
0
            res2 =
544
0
                (*varbind->val.integer -
545
0
                 *idxptr2->varbind->val.integer);
546
0
            break;
547
0
        case ASN_OCTET_STR:
548
0
            i = SNMP_MIN(varbind->val_len,
549
0
                         idxptr2->varbind->val_len);
550
0
            res2 =
551
0
                memcmp(varbind->val.string,
552
0
                       idxptr2->varbind->val.string, i);
553
0
            break;
554
0
        case ASN_OBJECT_ID:
555
0
            res2 =
556
0
                snmp_oid_compare(varbind->val.objid,
557
0
                                 varbind->val_len / sizeof(oid),
558
0
                                 idxptr2->varbind->val.objid,
559
0
                                 idxptr2->varbind->val_len /
560
0
                                 sizeof(oid));
561
0
            break;
562
0
        default:
563
0
            return INDEX_ERR_WRONG_TYPE;        /* wrong type */
564
0
        }
565
0
        if (res2 <= 0)
566
0
            break;
567
0
    }
568
0
    if (res2 != 0 || (res2 == 0 && !idxptr2->allocated)) {
569
0
        return INDEX_ERR_NOT_ALLOCATED;
570
0
    }
571
0
    if (ss != idxptr2->session)
572
0
        return INDEX_ERR_WRONG_SESSION;
573
574
    /*
575
     *  If this is a "normal" index unregistration,
576
     *      mark the index entry as unused, but leave
577
     *      it in situ.  This allows differentiation
578
     *      between ANY_INDEX and NEW_INDEX
579
     */
580
0
    if (remember) {
581
0
        idxptr2->allocated = 0; /* Unused index */
582
0
        idxptr2->session = NULL;
583
0
        return SNMP_ERR_NOERROR;
584
0
    }
585
    /*
586
     *  If this is a failed attempt to register a
587
     *      number of indexes, the successful ones
588
     *      must be removed completely.
589
     */
590
0
    if (prev_idx_ptr) {
591
0
        prev_idx_ptr->next_idx = idxptr2->next_idx;
592
0
    } else if (prev_oid_ptr) {
593
0
        if (idxptr2->next_idx)  /* Use p_idx_ptr as a temp variable */
594
0
            prev_idx_ptr = idxptr2->next_idx;
595
0
        else
596
0
            prev_idx_ptr = idxptr2->next_oid;
597
0
        while (prev_oid_ptr) {
598
0
            prev_oid_ptr->next_oid = prev_idx_ptr;
599
0
            prev_oid_ptr = prev_oid_ptr->next_idx;
600
0
        }
601
0
    } else {
602
0
        if (idxptr2->next_idx)
603
0
            snmp_index_head = idxptr2->next_idx;
604
0
        else
605
0
            snmp_index_head = idxptr2->next_oid;
606
0
    }
607
0
    snmp_free_var(idxptr2->varbind);
608
0
    free(idxptr2);
609
0
    return SNMP_ERR_NOERROR;
610
0
}
611
612
netsnmp_feature_child_of(unregister_indexes,netsnmp_unused);
613
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES
614
int
615
unregister_string_index(oid * name, size_t name_len, char *cp)
616
0
{
617
0
    netsnmp_variable_list varbind;
618
619
0
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
620
0
    varbind.type = ASN_OCTET_STR;
621
0
    snmp_set_var_objid(&varbind, name, name_len);
622
0
    snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp));
623
0
    return (unregister_index(&varbind, FALSE, main_session));
624
0
}
625
626
int
627
unregister_int_index(oid * name, size_t name_len, int val)
628
0
{
629
0
    netsnmp_variable_list varbind;
630
631
0
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
632
0
    varbind.type = ASN_INTEGER;
633
0
    snmp_set_var_objid(&varbind, name, name_len);
634
0
    varbind.val.string = varbind.buf;
635
0
    varbind.val_len = sizeof(long);
636
0
    *varbind.val.integer = val;
637
0
    return (unregister_index(&varbind, FALSE, main_session));
638
0
}
639
640
int
641
unregister_oid_index(oid * name, size_t name_len,
642
                     oid * value, size_t value_len)
643
0
{
644
0
    netsnmp_variable_list varbind;
645
646
0
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
647
0
    varbind.type = ASN_OBJECT_ID;
648
0
    snmp_set_var_objid(&varbind, name, name_len);
649
0
    snmp_set_var_value(&varbind, (u_char *) value,
650
0
                       value_len * sizeof(oid));
651
0
    return (unregister_index(&varbind, FALSE, main_session));
652
0
}
653
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES */
654
655
void
656
dump_idx_registry(void)
657
0
{
658
0
    struct snmp_index *idxptr, *idxptr2;
659
0
    u_char         *sbuf = NULL, *ebuf = NULL;
660
0
    size_t          sbuf_len = 0, sout_len = 0, ebuf_len = 0, eout_len = 0;
661
662
0
    if (snmp_index_head != NULL) {
663
0
        printf("\nIndex Allocations:\n");
664
0
    }
665
666
0
    for (idxptr = snmp_index_head; idxptr != NULL;
667
0
         idxptr = idxptr->next_oid) {
668
0
        sout_len = 0;
669
0
        if (sprint_realloc_objid(&sbuf, &sbuf_len, &sout_len, 1,
670
0
                                 idxptr->varbind->name,
671
0
                                 idxptr->varbind->name_length)) {
672
0
            printf("%s indexes:\n", sbuf);
673
0
        } else {
674
0
            printf("%s [TRUNCATED] indexes:\n", sbuf);
675
0
        }
676
677
0
        for (idxptr2 = idxptr; idxptr2 != NULL;
678
0
             idxptr2 = idxptr2->next_idx) {
679
0
            switch (idxptr2->varbind->type) {
680
0
            case ASN_INTEGER:
681
0
                printf("    %ld for session %8p, allocated %d\n",
682
0
                       *idxptr2->varbind->val.integer, idxptr2->session,
683
0
                       idxptr2->allocated);
684
0
                break;
685
0
            case ASN_OCTET_STR:
686
0
                printf("    \"%s\" for session %8p, allocated %d\n",
687
0
                       idxptr2->varbind->val.string, idxptr2->session,
688
0
                       idxptr2->allocated);
689
0
                break;
690
0
            case ASN_OBJECT_ID:
691
0
                eout_len = 0;
692
0
                if (sprint_realloc_objid(&ebuf, &ebuf_len, &eout_len, 1,
693
0
                                         idxptr2->varbind->val.objid,
694
0
                                         idxptr2->varbind->val_len /
695
0
                                         sizeof(oid))) {
696
0
                    printf("    %s for session %8p, allocated %d\n", ebuf,
697
0
                           idxptr2->session, idxptr2->allocated);
698
0
                } else {
699
0
                    printf
700
0
                        ("    %s [TRUNCATED] for sess %8p, allocated %d\n",
701
0
                         ebuf, idxptr2->session, idxptr2->allocated);
702
0
                }
703
0
                break;
704
0
            default:
705
0
                printf("unsupported type (%d/0x%02x)\n",
706
0
                       idxptr2->varbind->type, idxptr2->varbind->type);
707
0
            }
708
0
        }
709
0
    }
710
711
0
    if (sbuf != NULL) {
712
0
        free(sbuf);
713
0
    }
714
0
    if (ebuf != NULL) {
715
0
        free(ebuf);
716
0
    }
717
0
}
718
719
netsnmp_feature_child_of(count_indexes, netsnmp_unused);
720
#ifndef NETSNMP_FEATURE_REMOVE_UNUSED
721
unsigned long
722
count_indexes(oid * name, size_t namelen, int include_unallocated)
723
0
{
724
0
    struct snmp_index *i = NULL, *j = NULL;
725
0
    unsigned long   n = 0;
726
727
0
    for (i = snmp_index_head; i != NULL; i = i->next_oid) {
728
0
        if (netsnmp_oid_equals(name, namelen,
729
0
                             i->varbind->name,
730
0
                             i->varbind->name_length) == 0) {
731
0
            for (j = i; j != NULL; j = j->next_idx) {
732
0
                if (j->allocated || include_unallocated) {
733
0
                    n++;
734
0
                }
735
0
            }
736
0
        }
737
0
    }
738
0
    return n;
739
0
}
740
#endif /* NETSNMP_FEATURE_REMOVE_UNUSED */
741
742
#ifdef TESTING
743
netsnmp_variable_list varbind;
744
netsnmp_session main_sess, *main_session = &main_sess;
745
746
void
747
test_string_register(int n, char *cp)
748
{
749
    varbind->name[4] = n;
750
    if (register_string_index(varbind->name, varbind.name_length, cp) ==
751
        NULL)
752
        printf("allocating %s failed\n", cp);
753
}
754
755
void
756
test_int_register(int n, int val)
757
{
758
    varbind->name[4] = n;
759
    if (register_int_index(varbind->name, varbind.name_length, val) == -1)
760
        printf("allocating %d/%d failed\n", n, val);
761
}
762
763
void
764
test_oid_register(int n, int subid)
765
{
766
    netsnmp_variable_list *res;
767
768
    varbind->name[4] = n;
769
    if (subid != -1) {
770
        varbind->val.objid[5] = subid;
771
        res = register_oid_index(varbind->name, varbind.name_length,
772
                                 varbind->val.objid,
773
                                 varbind->val_len / sizeof(oid));
774
    } else
775
        res =
776
            register_oid_index(varbind->name, varbind.name_length, NULL,
777
                               0);
778
779
    if (res == NULL)
780
        printf("allocating %d/%d failed\n", n, subid);
781
}
782
783
void
784
main(int argc, char argv[])
785
{
786
    oid             name[] = { 1, 2, 3, 4, 0 };
787
    int             i;
788
789
    memset(&varbind, 0, sizeof(netsnmp_variable_list));
790
    snmp_set_var_objid(&varbind, name, 5);
791
    varbind->type = ASN_OCTET_STR;
792
    /*
793
     * Test index structure linking:
794
     *      a) sorted by OID
795
     */
796
    test_string_register(20, "empty OID");
797
    test_string_register(10, "first OID");
798
    test_string_register(40, "last OID");
799
    test_string_register(30, "middle OID");
800
801
    /*
802
     *      b) sorted by index value
803
     */
804
    test_string_register(25, "eee: empty IDX");
805
    test_string_register(25, "aaa: first IDX");
806
    test_string_register(25, "zzz: last IDX");
807
    test_string_register(25, "mmm: middle IDX");
808
    printf("This next one should fail....\n");
809
    test_string_register(25, "eee: empty IDX"); /* duplicate */
810
    printf("done\n");
811
812
    /*
813
     *      c) test initial index linking
814
     */
815
    test_string_register(5, "eee: empty initial IDX");
816
    test_string_register(5, "aaa: replace initial IDX");
817
818
    /*
819
     *      Did it all work?
820
     */
821
    dump_idx_registry();
822
    unregister_index_by_session(main_session);
823
    /*
824
     *  Now test index allocation
825
     *      a) integer values
826
     */
827
    test_int_register(110, -1); /* empty */
828
    test_int_register(110, -1); /* append */
829
    test_int_register(110, 10); /* append exact */
830
    printf("This next one should fail....\n");
831
    test_int_register(110, 10); /* exact duplicate */
832
    printf("done\n");
833
    test_int_register(110, -1); /* append */
834
    test_int_register(110, 5);  /* insert exact */
835
836
    /*
837
     *      b) string values
838
     */
839
    test_string_register(120, NULL);    /* empty */
840
    test_string_register(120, NULL);    /* append */
841
    test_string_register(120, "aaaz");
842
    test_string_register(120, NULL);    /* minor rollover */
843
    test_string_register(120, "zzzz");
844
    test_string_register(120, NULL);    /* major rollover */
845
846
    /*
847
     *      c) OID values
848
     */
849
850
    test_oid_register(130, -1); /* empty */
851
    test_oid_register(130, -1); /* append */
852
853
    varbind->val_len = varbind.name_length * sizeof(oid);
854
    memcpy(varbind->buf, varbind.name, varbind.val_len);
855
    varbind->val.objid = (oid *) varbind.buf;
856
    varbind->val_len += sizeof(oid);
857
858
    test_oid_register(130, 255);        /* append exact */
859
    test_oid_register(130, -1); /* minor rollover */
860
    test_oid_register(130, 100);        /* insert exact */
861
    printf("This next one should fail....\n");
862
    test_oid_register(130, 100);        /* exact duplicate */
863
    printf("done\n");
864
865
    varbind->val.objid = (oid *) varbind.buf;
866
    for (i = 0; i < 6; i++)
867
        varbind->val.objid[i] = 255;
868
    varbind->val.objid[0] = 1;
869
    test_oid_register(130, 255);        /* set up rollover  */
870
    test_oid_register(130, -1); /* medium rollover */
871
872
    for (i = 0; i < 6; i++)
873
        varbind->val.objid[i] = 255;
874
    varbind->val.objid[0] = 2;
875
    test_oid_register(130, 255);        /* set up rollover  */
876
    test_oid_register(130, -1); /* major rollover */
877
878
    /*
879
     *      Did it all work?
880
     */
881
    dump_idx_registry();
882
883
    /*
884
     *      Test the various "invalid" requests
885
     *      (unsupported types, mis-matched types, etc)
886
     */
887
    printf("The rest of these should fail....\n");
888
    test_oid_register(110, -1);
889
    test_oid_register(110, 100);
890
    test_oid_register(120, -1);
891
    test_oid_register(120, 100);
892
    test_string_register(110, NULL);
893
    test_string_register(110, "aaaa");
894
    test_string_register(130, NULL);
895
    test_string_register(130, "aaaa");
896
    test_int_register(120, -1);
897
    test_int_register(120, 1);
898
    test_int_register(130, -1);
899
    test_int_register(130, 1);
900
    printf("done - this dump should be the same as before\n");
901
    dump_idx_registry();
902
}
903
#endif