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