/src/net-snmp/agent/agent_index.c
Line | Count | Source (jump to first uncovered line) |
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 | i = new_index->varbind->val_len - 1; |
350 | 0 | while (new_index->varbind->buf[i] == 'z') { |
351 | 0 | new_index->varbind->buf[i] = 'a'; |
352 | 0 | i--; |
353 | 0 | if (i < 0) { |
354 | 0 | i = new_index->varbind->val_len; |
355 | 0 | new_index->varbind->buf[i] = 'a'; |
356 | 0 | new_index->varbind->buf[i + 1] = 0; |
357 | 0 | } |
358 | 0 | } |
359 | 0 | new_index->varbind->buf[i]++; |
360 | 0 | } else |
361 | 0 | strcpy((char *) new_index->varbind->buf, "aaaa"); |
362 | 0 | new_index->varbind->val_len = |
363 | 0 | strlen((char *) new_index->varbind->buf); |
364 | 0 | break; |
365 | 0 | case ASN_OBJECT_ID: |
366 | 0 | if (prev_idx_ptr) { |
367 | 0 | i = prev_idx_ptr->varbind->val_len / sizeof(oid) - 1; |
368 | 0 | while (new_index->varbind->val.objid[i] == 255) { |
369 | 0 | new_index->varbind->val.objid[i] = 1; |
370 | 0 | i--; |
371 | 0 | if (i == 0 && new_index->varbind->val.objid[0] == 2) { |
372 | 0 | new_index->varbind->val.objid[0] = 1; |
373 | 0 | i = new_index->varbind->val_len / sizeof(oid); |
374 | 0 | new_index->varbind->val.objid[i] = 0; |
375 | 0 | new_index->varbind->val_len += sizeof(oid); |
376 | 0 | } |
377 | 0 | } |
378 | 0 | new_index->varbind->val.objid[i]++; |
379 | 0 | } 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 | 0 | if ((varbind->name_length + 1) * sizeof(oid) <= 40) { |
386 | 0 | for (i = 0; i < (int) varbind->name_length; i++) |
387 | 0 | new_index->varbind->val.objid[i] = |
388 | 0 | varbind->name[i]; |
389 | 0 | new_index->varbind->val.objid[varbind->name_length] = |
390 | 0 | 1; |
391 | 0 | new_index->varbind->val_len = |
392 | 0 | (varbind->name_length + 1) * sizeof(oid); |
393 | 0 | } else { |
394 | | /* |
395 | | * Otherwise use '.1.1.1.1...' |
396 | | */ |
397 | 0 | i = 40 / sizeof(oid); |
398 | 0 | if (i > 4) |
399 | 0 | i = 4; |
400 | 0 | new_index->varbind->val_len = i * (sizeof(oid)); |
401 | 0 | for (i--; i >= 0; i--) |
402 | 0 | new_index->varbind->val.objid[i] = 1; |
403 | 0 | } |
404 | 0 | } |
405 | 0 | break; |
406 | 0 | default: |
407 | 0 | snmp_free_var(new_index->varbind); |
408 | 0 | free(new_index); |
409 | 0 | return NULL; /* Index type not supported */ |
410 | 0 | } |
411 | 0 | } |
412 | | |
413 | | /* |
414 | | * Try to duplicate the new varbind for return. |
415 | | */ |
416 | | |
417 | 0 | if ((rv = snmp_clone_varbind(new_index->varbind)) == NULL) { |
418 | 0 | snmp_free_var(new_index->varbind); |
419 | 0 | free(new_index); |
420 | 0 | return NULL; |
421 | 0 | } |
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 | 0 | if (prev_idx_ptr) { |
430 | 0 | new_index->next_idx = prev_idx_ptr->next_idx; |
431 | 0 | new_index->next_oid = prev_idx_ptr->next_oid; |
432 | 0 | prev_idx_ptr->next_idx = new_index; |
433 | 0 | } else { |
434 | 0 | if (res == 0 && idxptr) { |
435 | 0 | new_index->next_idx = idxptr; |
436 | 0 | new_index->next_oid = idxptr->next_oid; |
437 | 0 | } else { |
438 | 0 | new_index->next_idx = NULL; |
439 | 0 | new_index->next_oid = idxptr; |
440 | 0 | } |
441 | |
|
442 | 0 | if (prev_oid_ptr) { |
443 | 0 | while (prev_oid_ptr) { |
444 | 0 | prev_oid_ptr->next_oid = new_index; |
445 | 0 | prev_oid_ptr = prev_oid_ptr->next_idx; |
446 | 0 | } |
447 | 0 | } else |
448 | 0 | snmp_index_head = new_index; |
449 | 0 | } |
450 | 0 | return rv; |
451 | 0 | } |
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 |
460 | | release_index(netsnmp_variable_list * varbind) |
461 | 0 | { |
462 | 0 | return (unregister_index(varbind, TRUE, NULL)); |
463 | 0 | } |
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 |
472 | | remove_index(netsnmp_variable_list * varbind, netsnmp_session * ss) |
473 | 0 | { |
474 | 0 | return (unregister_index(varbind, FALSE, ss)); |
475 | 0 | } |
476 | | #endif /* NETSNMP_FEATURE_REMOVE_REMOVE_INDEX */ |
477 | | |
478 | | void |
479 | | unregister_index_by_session(netsnmp_session * ss) |
480 | 0 | { |
481 | 0 | struct snmp_index *idxptr, *idxptr2; |
482 | 0 | for (idxptr = snmp_index_head; idxptr != NULL; |
483 | 0 | idxptr = idxptr->next_oid) |
484 | 0 | for (idxptr2 = idxptr; idxptr2 != NULL; |
485 | 0 | idxptr2 = idxptr2->next_idx) |
486 | 0 | if (idxptr2->session == ss) { |
487 | 0 | idxptr2->allocated = 0; |
488 | 0 | idxptr2->session = NULL; |
489 | 0 | } |
490 | 0 | } |
491 | | |
492 | | |
493 | | int |
494 | | unregister_index(netsnmp_variable_list * varbind, int remember, |
495 | | netsnmp_session * ss) |
496 | 0 | { |
497 | 0 | struct snmp_index *idxptr, *idxptr2; |
498 | 0 | struct snmp_index *prev_oid_ptr, *prev_idx_ptr; |
499 | 0 | int res, res2, i; |
500 | |
|
501 | 0 | #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING) |
502 | 0 | if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
503 | 0 | NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) { |
504 | 0 | return (agentx_unregister_index(ss, varbind)); |
505 | 0 | } |
506 | 0 | #endif |
507 | | /* |
508 | | * Look for the requested OID entry |
509 | | */ |
510 | 0 | prev_oid_ptr = NULL; |
511 | 0 | prev_idx_ptr = NULL; |
512 | 0 | res = 1; |
513 | 0 | res2 = 1; |
514 | 0 | for (idxptr = snmp_index_head; idxptr != NULL; |
515 | 0 | prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) { |
516 | 0 | if ((res = snmp_oid_compare(varbind->name, varbind->name_length, |
517 | 0 | idxptr->varbind->name, |
518 | 0 | idxptr->varbind->name_length)) <= 0) |
519 | 0 | break; |
520 | 0 | } |
521 | |
|
522 | 0 | if (res != 0) |
523 | 0 | return INDEX_ERR_NOT_ALLOCATED; |
524 | 0 | if (varbind->type != idxptr->varbind->type) |
525 | 0 | return INDEX_ERR_WRONG_TYPE; |
526 | | |
527 | 0 | for (idxptr2 = idxptr; idxptr2 != NULL; |
528 | 0 | prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) { |
529 | 0 | switch (varbind->type) { |
530 | 0 | case ASN_INTEGER: |
531 | 0 | res2 = |
532 | 0 | (*varbind->val.integer - |
533 | 0 | *idxptr2->varbind->val.integer); |
534 | 0 | break; |
535 | 0 | case ASN_OCTET_STR: |
536 | 0 | i = SNMP_MIN(varbind->val_len, |
537 | 0 | idxptr2->varbind->val_len); |
538 | 0 | res2 = |
539 | 0 | memcmp(varbind->val.string, |
540 | 0 | idxptr2->varbind->val.string, i); |
541 | 0 | break; |
542 | 0 | case ASN_OBJECT_ID: |
543 | 0 | res2 = |
544 | 0 | snmp_oid_compare(varbind->val.objid, |
545 | 0 | varbind->val_len / sizeof(oid), |
546 | 0 | idxptr2->varbind->val.objid, |
547 | 0 | idxptr2->varbind->val_len / |
548 | 0 | sizeof(oid)); |
549 | 0 | break; |
550 | 0 | default: |
551 | 0 | return INDEX_ERR_WRONG_TYPE; /* wrong type */ |
552 | 0 | } |
553 | 0 | if (res2 <= 0) |
554 | 0 | break; |
555 | 0 | } |
556 | 0 | if (res2 != 0 || (res2 == 0 && !idxptr2->allocated)) { |
557 | 0 | return INDEX_ERR_NOT_ALLOCATED; |
558 | 0 | } |
559 | 0 | if (ss != idxptr2->session) |
560 | 0 | 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 | 0 | if (remember) { |
569 | 0 | idxptr2->allocated = 0; /* Unused index */ |
570 | 0 | idxptr2->session = NULL; |
571 | 0 | return SNMP_ERR_NOERROR; |
572 | 0 | } |
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 | 0 | if (prev_idx_ptr) { |
579 | 0 | prev_idx_ptr->next_idx = idxptr2->next_idx; |
580 | 0 | } else if (prev_oid_ptr) { |
581 | 0 | if (idxptr2->next_idx) /* Use p_idx_ptr as a temp variable */ |
582 | 0 | prev_idx_ptr = idxptr2->next_idx; |
583 | 0 | else |
584 | 0 | prev_idx_ptr = idxptr2->next_oid; |
585 | 0 | while (prev_oid_ptr) { |
586 | 0 | prev_oid_ptr->next_oid = prev_idx_ptr; |
587 | 0 | prev_oid_ptr = prev_oid_ptr->next_idx; |
588 | 0 | } |
589 | 0 | } else { |
590 | 0 | if (idxptr2->next_idx) |
591 | 0 | snmp_index_head = idxptr2->next_idx; |
592 | 0 | else |
593 | 0 | snmp_index_head = idxptr2->next_oid; |
594 | 0 | } |
595 | 0 | snmp_free_var(idxptr2->varbind); |
596 | 0 | free(idxptr2); |
597 | 0 | return SNMP_ERR_NOERROR; |
598 | 0 | } |
599 | | |
600 | | netsnmp_feature_child_of(unregister_indexes,netsnmp_unused); |
601 | | #ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES |
602 | | int |
603 | | unregister_string_index(oid * name, size_t name_len, char *cp) |
604 | 0 | { |
605 | 0 | netsnmp_variable_list varbind; |
606 | |
|
607 | 0 | memset(&varbind, 0, sizeof(netsnmp_variable_list)); |
608 | 0 | varbind.type = ASN_OCTET_STR; |
609 | 0 | snmp_set_var_objid(&varbind, name, name_len); |
610 | 0 | snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp)); |
611 | 0 | return (unregister_index(&varbind, FALSE, main_session)); |
612 | 0 | } |
613 | | |
614 | | int |
615 | | unregister_int_index(oid * name, size_t name_len, int val) |
616 | 0 | { |
617 | 0 | netsnmp_variable_list varbind; |
618 | |
|
619 | 0 | memset(&varbind, 0, sizeof(netsnmp_variable_list)); |
620 | 0 | varbind.type = ASN_INTEGER; |
621 | 0 | snmp_set_var_objid(&varbind, name, name_len); |
622 | 0 | varbind.val.string = varbind.buf; |
623 | 0 | varbind.val_len = sizeof(long); |
624 | 0 | *varbind.val.integer = val; |
625 | 0 | return (unregister_index(&varbind, FALSE, main_session)); |
626 | 0 | } |
627 | | |
628 | | int |
629 | | unregister_oid_index(oid * name, size_t name_len, |
630 | | oid * value, size_t value_len) |
631 | 0 | { |
632 | 0 | netsnmp_variable_list varbind; |
633 | |
|
634 | 0 | memset(&varbind, 0, sizeof(netsnmp_variable_list)); |
635 | 0 | varbind.type = ASN_OBJECT_ID; |
636 | 0 | snmp_set_var_objid(&varbind, name, name_len); |
637 | 0 | snmp_set_var_value(&varbind, (u_char *) value, |
638 | 0 | value_len * sizeof(oid)); |
639 | 0 | return (unregister_index(&varbind, FALSE, main_session)); |
640 | 0 | } |
641 | | #endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES */ |
642 | | |
643 | | void |
644 | | dump_idx_registry(void) |
645 | 0 | { |
646 | 0 | struct snmp_index *idxptr, *idxptr2; |
647 | 0 | u_char *sbuf = NULL, *ebuf = NULL; |
648 | 0 | size_t sbuf_len = 0, sout_len = 0, ebuf_len = 0, eout_len = 0; |
649 | |
|
650 | 0 | if (snmp_index_head != NULL) { |
651 | 0 | printf("\nIndex Allocations:\n"); |
652 | 0 | } |
653 | |
|
654 | 0 | for (idxptr = snmp_index_head; idxptr != NULL; |
655 | 0 | idxptr = idxptr->next_oid) { |
656 | 0 | sout_len = 0; |
657 | 0 | if (sprint_realloc_objid(&sbuf, &sbuf_len, &sout_len, 1, |
658 | 0 | idxptr->varbind->name, |
659 | 0 | idxptr->varbind->name_length)) { |
660 | 0 | printf("%s indexes:\n", sbuf); |
661 | 0 | } else { |
662 | 0 | printf("%s [TRUNCATED] indexes:\n", sbuf); |
663 | 0 | } |
664 | |
|
665 | 0 | for (idxptr2 = idxptr; idxptr2 != NULL; |
666 | 0 | idxptr2 = idxptr2->next_idx) { |
667 | 0 | switch (idxptr2->varbind->type) { |
668 | 0 | case ASN_INTEGER: |
669 | 0 | printf(" %ld for session %8p, allocated %d\n", |
670 | 0 | *idxptr2->varbind->val.integer, idxptr2->session, |
671 | 0 | idxptr2->allocated); |
672 | 0 | break; |
673 | 0 | case ASN_OCTET_STR: |
674 | 0 | printf(" \"%s\" for session %8p, allocated %d\n", |
675 | 0 | idxptr2->varbind->val.string, idxptr2->session, |
676 | 0 | idxptr2->allocated); |
677 | 0 | break; |
678 | 0 | case ASN_OBJECT_ID: |
679 | 0 | eout_len = 0; |
680 | 0 | if (sprint_realloc_objid(&ebuf, &ebuf_len, &eout_len, 1, |
681 | 0 | idxptr2->varbind->val.objid, |
682 | 0 | idxptr2->varbind->val_len / |
683 | 0 | sizeof(oid))) { |
684 | 0 | printf(" %s for session %8p, allocated %d\n", ebuf, |
685 | 0 | idxptr2->session, idxptr2->allocated); |
686 | 0 | } else { |
687 | 0 | printf |
688 | 0 | (" %s [TRUNCATED] for sess %8p, allocated %d\n", |
689 | 0 | ebuf, idxptr2->session, idxptr2->allocated); |
690 | 0 | } |
691 | 0 | break; |
692 | 0 | default: |
693 | 0 | printf("unsupported type (%d/0x%02x)\n", |
694 | 0 | idxptr2->varbind->type, idxptr2->varbind->type); |
695 | 0 | } |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | 0 | if (sbuf != NULL) { |
700 | 0 | free(sbuf); |
701 | 0 | } |
702 | 0 | if (ebuf != NULL) { |
703 | 0 | free(ebuf); |
704 | 0 | } |
705 | 0 | } |
706 | | |
707 | | netsnmp_feature_child_of(count_indexes, netsnmp_unused); |
708 | | #ifndef NETSNMP_FEATURE_REMOVE_UNUSED |
709 | | unsigned long |
710 | | count_indexes(oid * name, size_t namelen, int include_unallocated) |
711 | 0 | { |
712 | 0 | struct snmp_index *i = NULL, *j = NULL; |
713 | 0 | unsigned long n = 0; |
714 | |
|
715 | 0 | for (i = snmp_index_head; i != NULL; i = i->next_oid) { |
716 | 0 | if (netsnmp_oid_equals(name, namelen, |
717 | 0 | i->varbind->name, |
718 | 0 | i->varbind->name_length) == 0) { |
719 | 0 | for (j = i; j != NULL; j = j->next_idx) { |
720 | 0 | if (j->allocated || include_unallocated) { |
721 | 0 | n++; |
722 | 0 | } |
723 | 0 | } |
724 | 0 | } |
725 | 0 | } |
726 | 0 | return n; |
727 | 0 | } |
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 |
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 |
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 |
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 |
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 |