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