1 /*
2 * default_store.c: storage space for defaults
3 */
4 /* Portions of this file are subject to the following copyright(s). See
5 * the Net-SNMP's COPYING file for more details and other copyrights
6 * that may apply:
7 */
8 /*
9 * Portions of this file are copyrighted by:
10 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
11 * Use is subject to license terms specified in the COPYING file
12 * distributed with the Net-SNMP package.
13 */
14 /** @defgroup default_store storage space for defaults
15 * @ingroup library
16 *
17 The purpose of the default storage is three-fold:
18
19 1) To create a global storage space without creating a
20 whole bunch of globally accessible variables or a
21 whole bunch of access functions to work with more
22 privately restricted variables.
23
24 2) To provide a single location where the thread lock-
25 ing needs to be implemented. At the time of this
26 writing, however, thread locking is not yet in
27 place.
28
29 3) To reduce the number of cross dependencies between
30 code pieces that may or may not be linked together
31 in the long run. This provides for a single loca-
32 tion in which configuration data, for example, can
33 be stored for a separate section of code that may
34 not be linked in to the application in question.
35
36 The functions defined here implement these goals.
37
38 Currently, three data types are supported: booleans, inte-
39 gers, and strings. Each of these data types have separate
40 storage spaces. In addition, the storage space for each
41 data type is divided further by the application level.
42 Currently, there are two storage spaces. The first is
43 reserved for the SNMP library itself. The second is
44 intended for use in applications and is not modified or
45 checked by the library, and, therefore, this is the space
46 usable by you.
47
48 These definitions correspond with the "storid" argument to the API
49 - \#define NETSNMP_DS_LIBRARY_ID 0
50 - \#define NETSNMP_DS_APPLICATION_ID 1
51 - \#define NETSNMP_DS_TOKEN_ID 2
52
53 These definitions correspond with the "which" argument to the API,
54 when the storeid argument is NETSNMP_DS_LIBRARY_ID
55
56 library booleans
57
58 - \#define NETSNMP_DS_LIB_MIB_ERRORS 0
59 - \#define NETSNMP_DS_LIB_SAVE_MIB_DESCRS 1
60 - \#define NETSNMP_DS_LIB_MIB_COMMENT_TERM 2
61 - \#define NETSNMP_DS_LIB_MIB_PARSE_LABEL 3
62 - \#define NETSNMP_DS_LIB_DUMP_PACKET 4
63 - \#define NETSNMP_DS_LIB_LOG_TIMESTAMP 5
64 - \#define NETSNMP_DS_LIB_DONT_READ_CONFIGS 6
65 - \#define NETSNMP_DS_LIB_MIB_REPLACE 7 replace objects from latest module
66 - \#define NETSNMP_DS_LIB_PRINT_NUMERIC_ENUM 8 print only numeric enum values
67 - \#define NETSNMP_DS_LIB_PRINT_NUMERIC_OIDS 9 print only numeric enum values
68 - \#define NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS 10 dont print oid indexes specially
69 - \#define NETSNMP_DS_LIB_ALARM_DONT_USE_SIG 11 don't use the alarm() signal
70 - \#define NETSNMP_DS_LIB_PRINT_FULL_OID 12 print fully qualified oids
71 - \#define NETSNMP_DS_LIB_QUICK_PRINT 13 print very brief output for parsing
72 - \#define NETSNMP_DS_LIB_RANDOM_ACCESS 14 random access to oid labels
73 - \#define NETSNMP_DS_LIB_REGEX_ACCESS 15 regex matching to oid labels
74 - \#define NETSNMP_DS_LIB_DONT_CHECK_RANGE 16 don't check values for ranges on send
75 - \#define NETSNMP_DS_LIB_NO_TOKEN_WARNINGS 17 no warn about unknown config tokens
76 - \#define NETSNMP_DS_LIB_NUMERIC_TIMETICKS 18 print timeticks as a number
77 - \#define NETSNMP_DS_LIB_ESCAPE_QUOTES 19 shell escape quote marks in oids
78 - \#define NETSNMP_DS_LIB_REVERSE_ENCODE 20 encode packets from back to front
79 - \#define NETSNMP_DS_LIB_PRINT_BARE_VALUE 21 just print value (not OID = value)
80 - \#define NETSNMP_DS_LIB_EXTENDED_INDEX 22 print extended index format [x1][x2]
81 - \#define NETSNMP_DS_LIB_PRINT_HEX_TEXT 23 print ASCII text along with hex strings
82 - \#define NETSNMP_DS_LIB_PRINT_UCD_STYLE_OID 24 print OID's using the UCD-style prefix suppression
83 - \#define NETSNMP_DS_LIB_READ_UCD_STYLE_OID 25 require top-level OIDs to be prefixed with a dot
84 - \#define NETSNMP_DS_LIB_HAVE_READ_PREMIB_CONFIG 26 have the pre-mib parsing config tokens been processed
85 - \#define NETSNMP_DS_LIB_HAVE_READ_CONFIG 27 have the config tokens been processed
86 - \#define NETSNMP_DS_LIB_QUICKE_PRINT 28
87 - \#define NETSNMP_DS_LIB_DONT_PRINT_UNITS 29 don't print UNITS suffix
88 - \#define NETSNMP_DS_LIB_NO_DISPLAY_HINT 30 don't apply DISPLAY-HINTs
89 - \#define NETSNMP_DS_LIB_16BIT_IDS 31 restrict requestIDs, etc to 16-bit values
90 - \#define NETSNMP_DS_LIB_DONT_PERSIST_STATE 32 don't save/load any persistant state
91 - \#define NETSNMP_DS_LIB_2DIGIT_HEX_OUTPUT 33 print a leading 0 on hex values <= 'f'
92
93
94 library integers
95
96 - \#define NETSNMP_DS_LIB_MIB_WARNINGS 0
97 - \#define NETSNMP_DS_LIB_SECLEVEL 1
98 - \#define NETSNMP_DS_LIB_SNMPVERSION 2
99 - \#define NETSNMP_DS_LIB_DEFAULT_PORT 3
100 - \#define NETSNMP_DS_LIB_OID_OUTPUT_FORMAT 4
101 - \#define NETSNMP_DS_LIB_STRING_OUTPUT_FORMAT 5
102
103 library strings
104
105 - \#define NETSNMP_DS_LIB_SECNAME 0
106 - \#define NETSNMP_DS_LIB_CONTEXT 1
107 - \#define NETSNMP_DS_LIB_PASSPHRASE 2
108 - \#define NETSNMP_DS_LIB_AUTHPASSPHRASE 3
109 - \#define NETSNMP_DS_LIB_PRIVPASSPHRASE 4
110 - \#define NETSNMP_DS_LIB_OPTIONALCONFIG 5
111 - \#define NETSNMP_DS_LIB_APPTYPE 6
112 - \#define NETSNMP_DS_LIB_COMMUNITY 7
113 - \#define NETSNMP_DS_LIB_PERSISTENT_DIR 8
114 - \#define NETSNMP_DS_LIB_CONFIGURATION_DIR 9
115 - \#define NETSNMP_DS_LIB_SECMODEL 10
116 - \#define NETSNMP_DS_LIB_MIBDIRS 11
117 - \#define NETSNMP_DS_LIB_OIDSUFFIX 12
118 - \#define NETSNMP_DS_LIB_OIDPREFIX 13
119 - \#define NETSNMP_DS_LIB_CLIENT_ADDR 14
120 - \#define NETSNMP_DS_LIB_TEMP_FILE_PATTERN 15
121 - \#define NETSNMP_DS_LIB_AUTHMASTERKEY 16
122 - \#define NETSNMP_DS_LIB_PRIVMASTERKEY 17
123 - \#define NETSNMP_DS_LIB_AUTHLOCALIZEDKEY 18
124 - \#define NETSNMP_DS_LIB_PRIVLOCALIZEDKEY 19
125
126 * @{
127 */
128 #include <net-snmp/net-snmp-config.h>
129 #include <net-snmp/net-snmp-features.h>
130 #include <sys/types.h>
131 #if HAVE_STDLIB_H
132 #include <stdlib.h>
133 #endif
134 #if HAVE_NETINET_IN_H
135 #include <netinet/in.h>
136 #endif
137 #if HAVE_STDLIB_H
138 #include <stdlib.h>
139 #endif
140 #if HAVE_STRING_H
141 #include <string.h>
142 #else
143 #include <strings.h>
144 #endif
145
146 #if HAVE_UNISTD_H
147 #include <unistd.h>
148 #endif
149
150 #include <net-snmp/types.h>
151 #include <net-snmp/output_api.h>
152 #include <net-snmp/config_api.h>
153 #include <net-snmp/library/default_store.h> /* for "internal" definitions */
154 #include <net-snmp/utilities.h>
155
156 #include <net-snmp/library/snmp_api.h>
157
158 netsnmp_feature_child_of(default_store_all, libnetsnmp);
159
160 netsnmp_feature_child_of(default_store_void, default_store_all);
161
162 #ifndef NETSNMP_FEATURE_REMOVE_DEFAULT_STORE_VOID
163 #endif /* NETSNMP_FEATURE_REMOVE_DEFAULT_STORE_VOID */
164
165
166 static const char * stores [NETSNMP_DS_MAX_IDS] = { "LIB", "APP", "TOK" };
167
168 typedef struct netsnmp_ds_read_config_s {
169 u_char type;
170 char *token;
171 char *ftype;
172 int storeid;
173 int which;
174 struct netsnmp_ds_read_config_s *next;
175 } netsnmp_ds_read_config;
176
177 static netsnmp_ds_read_config *netsnmp_ds_configs = NULL;
178
179 static int netsnmp_ds_integers[NETSNMP_DS_MAX_IDS][NETSNMP_DS_MAX_SUBIDS];
180 static char netsnmp_ds_booleans[NETSNMP_DS_MAX_IDS][NETSNMP_DS_MAX_SUBIDS/8];
181 static char *netsnmp_ds_strings[NETSNMP_DS_MAX_IDS][NETSNMP_DS_MAX_SUBIDS];
182 #ifndef NETSNMP_FEATURE_REMOVE_DEFAULT_STORE_VOID
183 static void *netsnmp_ds_voids[NETSNMP_DS_MAX_IDS][NETSNMP_DS_MAX_SUBIDS];
184 #endif /* NETSNMP_FEATURE_REMOVE_DEFAULT_STORE_VOID */
185
186 /**
187 * Stores "true" or "false" given an int value for value into
188 * netsnmp_ds_booleans[store][which] slot.
189 *
190 * @param storeid an index to the boolean storage container's first index(store)
191 *
192 * @param which an index to the boolean storage container's second index(which)
193 *
194 * @param value if > 0, "true" is set into the slot otherwise "false"
195 *
196 * @return Returns SNMPPERR_GENERR if the storeid and which parameters do not
197 * correspond to a valid slot, or SNMPERR_SUCCESS otherwise.
198 */
199 int
netsnmp_ds_set_boolean(int storeid,int which,int value)200 netsnmp_ds_set_boolean(int storeid, int which, int value)
201 {
202 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
203 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
204 return SNMPERR_GENERR;
205 }
206
207 DEBUGMSGTL(("netsnmp_ds_set_boolean", "Setting %s:%d = %d/%s\n",
208 stores[storeid], which, value, ((value) ? "True" : "False")));
209
210 if (value > 0) {
211 netsnmp_ds_booleans[storeid][which/8] |= (1 << (which % 8));
212 } else {
213 netsnmp_ds_booleans[storeid][which/8] &= (0xff7f >> (7 - (which % 8)));
214 }
215
216 return SNMPERR_SUCCESS;
217 }
218
219 int
netsnmp_ds_toggle_boolean(int storeid,int which)220 netsnmp_ds_toggle_boolean(int storeid, int which)
221 {
222 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
223 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
224 return SNMPERR_GENERR;
225 }
226
227 if ((netsnmp_ds_booleans[storeid][which/8] & (1 << (which % 8))) == 0) {
228 netsnmp_ds_booleans[storeid][which/8] |= (1 << (which % 8));
229 } else {
230 netsnmp_ds_booleans[storeid][which/8] &= (0xff7f >> (7 - (which % 8)));
231 }
232
233 DEBUGMSGTL(("netsnmp_ds_toggle_boolean", "Setting %s:%d = %d/%s\n",
234 stores[storeid], which, netsnmp_ds_booleans[storeid][which/8],
235 ((netsnmp_ds_booleans[storeid][which/8]) ? "True" : "False")));
236
237 return SNMPERR_SUCCESS;
238 }
239
240 int
netsnmp_ds_get_boolean(int storeid,int which)241 netsnmp_ds_get_boolean(int storeid, int which)
242 {
243 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
244 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
245 return SNMPERR_GENERR;
246 }
247
248 return (netsnmp_ds_booleans[storeid][which/8] & (1 << (which % 8))) ? 1:0;
249 }
250
251 int
netsnmp_ds_set_int(int storeid,int which,int value)252 netsnmp_ds_set_int(int storeid, int which, int value)
253 {
254 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
255 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
256 return SNMPERR_GENERR;
257 }
258
259 DEBUGMSGTL(("netsnmp_ds_set_int", "Setting %s:%d = %d\n",
260 stores[storeid], which, value));
261
262 netsnmp_ds_integers[storeid][which] = value;
263 return SNMPERR_SUCCESS;
264 }
265
266 int
netsnmp_ds_get_int(int storeid,int which)267 netsnmp_ds_get_int(int storeid, int which)
268 {
269 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
270 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
271 return SNMPERR_GENERR;
272 }
273
274 return netsnmp_ds_integers[storeid][which];
275 }
276
277 int
netsnmp_ds_set_string(int storeid,int which,const char * value)278 netsnmp_ds_set_string(int storeid, int which, const char *value)
279 {
280 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
281 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
282 return SNMPERR_GENERR;
283 }
284
285 DEBUGMSGTL(("netsnmp_ds_set_string", "Setting %s:%d = \"%s\"\n",
286 stores[storeid], which, (value ? value : "(null)")));
287
288 /*
289 * is some silly person is calling us with our own pointer?
290 */
291 if (netsnmp_ds_strings[storeid][which] == value)
292 return SNMPERR_SUCCESS;
293
294 snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
295 if (netsnmp_ds_strings[storeid][which] != NULL) {
296 free(netsnmp_ds_strings[storeid][which]);
297 netsnmp_ds_strings[storeid][which] = NULL;
298 }
299 snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
300
301 if (value) {
302 netsnmp_ds_strings[storeid][which] = strdup(value);
303 } else {
304 netsnmp_ds_strings[storeid][which] = NULL;
305 }
306
307 return SNMPERR_SUCCESS;
308 }
309
310 char *
netsnmp_ds_get_string(int storeid,int which)311 netsnmp_ds_get_string(int storeid, int which)
312 {
313 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
314 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
315 return NULL;
316 }
317
318 return netsnmp_ds_strings[storeid][which];
319 }
320
321 #ifndef NETSNMP_FEATURE_REMOVE_DEFAULT_STORE_VOID
322 int
netsnmp_ds_set_void(int storeid,int which,void * value)323 netsnmp_ds_set_void(int storeid, int which, void *value)
324 {
325 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
326 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
327 return SNMPERR_GENERR;
328 }
329
330 DEBUGMSGTL(("netsnmp_ds_set_void", "Setting %s:%d = %p\n",
331 stores[storeid], which, value));
332
333 netsnmp_ds_voids[storeid][which] = value;
334
335 return SNMPERR_SUCCESS;
336 }
337
338 void *
netsnmp_ds_get_void(int storeid,int which)339 netsnmp_ds_get_void(int storeid, int which)
340 {
341 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
342 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS) {
343 return NULL;
344 }
345
346 return netsnmp_ds_voids[storeid][which];
347 }
348 #endif /* NETSNMP_FEATURE_REMOVE_DEFAULT_STORE_VOID */
349
350 int
netsnmp_ds_parse_boolean(char * line)351 netsnmp_ds_parse_boolean(char *line)
352 {
353 char *value, *endptr;
354 int itmp;
355 char *st;
356
357 value = strtok_r(line, " \t\n", &st);
358 if (strcasecmp(value, "yes") == 0 ||
359 strcasecmp(value, "true") == 0) {
360 return 1;
361 } else if (strcasecmp(value, "no") == 0 ||
362 strcasecmp(value, "false") == 0) {
363 return 0;
364 } else {
365 itmp = strtol(value, &endptr, 10);
366 if (*endptr != 0 || itmp < 0 || itmp > 1) {
367 config_perror("Should be yes|no|true|false|0|1");
368 return -1;
369 }
370 return itmp;
371 }
372 }
373
374 void
netsnmp_ds_handle_config(const char * token,char * line)375 netsnmp_ds_handle_config(const char *token, char *line)
376 {
377 netsnmp_ds_read_config *drsp;
378 char buf[SNMP_MAXBUF];
379 char *value, *endptr;
380 int itmp;
381 char *st;
382
383 DEBUGMSGTL(("netsnmp_ds_handle_config", "handling %s\n", token));
384
385 for (drsp = netsnmp_ds_configs;
386 drsp != NULL && strcasecmp(token, drsp->token) != 0;
387 drsp = drsp->next);
388
389 if (drsp != NULL) {
390 DEBUGMSGTL(("netsnmp_ds_handle_config",
391 "setting: token=%s, type=%d, id=%s, which=%d\n",
392 drsp->token, drsp->type, stores[drsp->storeid],
393 drsp->which));
394
395 switch (drsp->type) {
396 case ASN_BOOLEAN:
397 itmp = netsnmp_ds_parse_boolean(line);
398 if ( itmp != -1 )
399 netsnmp_ds_set_boolean(drsp->storeid, drsp->which, itmp);
400 DEBUGMSGTL(("netsnmp_ds_handle_config", "bool: %d\n", itmp));
401 break;
402
403 case ASN_INTEGER:
404 value = strtok_r(line, " \t\n", &st);
405 itmp = strtol(value, &endptr, 10);
406 if (*endptr != 0) {
407 config_perror("Bad integer value");
408 } else {
409 netsnmp_ds_set_int(drsp->storeid, drsp->which, itmp);
410 }
411 DEBUGMSGTL(("netsnmp_ds_handle_config", "int: %d\n", itmp));
412 break;
413
414 case ASN_OCTET_STR:
415 if (*line == '"') {
416 copy_nword(line, buf, sizeof(buf));
417 netsnmp_ds_set_string(drsp->storeid, drsp->which, buf);
418 } else {
419 netsnmp_ds_set_string(drsp->storeid, drsp->which, line);
420 }
421 DEBUGMSGTL(("netsnmp_ds_handle_config", "string: %s\n", line));
422 break;
423
424 default:
425 snmp_log(LOG_ERR, "netsnmp_ds_handle_config: type %d (0x%02x)\n",
426 drsp->type, drsp->type);
427 break;
428 }
429 } else {
430 snmp_log(LOG_ERR, "netsnmp_ds_handle_config: no registration for %s\n",
431 token);
432 }
433 }
434
435
436 int
netsnmp_ds_register_config(u_char type,const char * ftype,const char * token,int storeid,int which)437 netsnmp_ds_register_config(u_char type, const char *ftype, const char *token,
438 int storeid, int which)
439 {
440 netsnmp_ds_read_config *drsp;
441
442 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
443 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS || token == NULL) {
444 return SNMPERR_GENERR;
445 }
446
447 if (netsnmp_ds_configs == NULL) {
448 netsnmp_ds_configs = SNMP_MALLOC_TYPEDEF(netsnmp_ds_read_config);
449 if (netsnmp_ds_configs == NULL)
450 return SNMPERR_GENERR;
451 drsp = netsnmp_ds_configs;
452 } else {
453 for (drsp = netsnmp_ds_configs; drsp->next != NULL; drsp = drsp->next);
454 drsp->next = SNMP_MALLOC_TYPEDEF(netsnmp_ds_read_config);
455 if (drsp->next == NULL)
456 return SNMPERR_GENERR;
457 drsp = drsp->next;
458 }
459
460 drsp->type = type;
461 drsp->ftype = strdup(ftype);
462 drsp->token = strdup(token);
463 drsp->storeid = storeid;
464 drsp->which = which;
465
466 switch (type) {
467 case ASN_BOOLEAN:
468 register_config_handler(ftype, token, netsnmp_ds_handle_config, NULL,
469 "(1|yes|true|0|no|false)");
470 break;
471
472 case ASN_INTEGER:
473 register_config_handler(ftype, token, netsnmp_ds_handle_config, NULL,
474 "integerValue");
475 break;
476
477 case ASN_OCTET_STR:
478 register_config_handler(ftype, token, netsnmp_ds_handle_config, NULL,
479 "string");
480 break;
481
482 }
483 return SNMPERR_SUCCESS;
484 }
485
486 int
netsnmp_ds_register_premib(u_char type,const char * ftype,const char * token,int storeid,int which)487 netsnmp_ds_register_premib(u_char type, const char *ftype, const char *token,
488 int storeid, int which)
489 {
490 netsnmp_ds_read_config *drsp;
491
492 if (storeid < 0 || storeid >= NETSNMP_DS_MAX_IDS ||
493 which < 0 || which >= NETSNMP_DS_MAX_SUBIDS || token == NULL) {
494 return SNMPERR_GENERR;
495 }
496
497 if (netsnmp_ds_configs == NULL) {
498 netsnmp_ds_configs = SNMP_MALLOC_TYPEDEF(netsnmp_ds_read_config);
499 if (netsnmp_ds_configs == NULL)
500 return SNMPERR_GENERR;
501 drsp = netsnmp_ds_configs;
502 } else {
503 for (drsp = netsnmp_ds_configs; drsp->next != NULL; drsp = drsp->next);
504 drsp->next = SNMP_MALLOC_TYPEDEF(netsnmp_ds_read_config);
505 if (drsp->next == NULL)
506 return SNMPERR_GENERR;
507 drsp = drsp->next;
508 }
509
510 drsp->type = type;
511 drsp->ftype = strdup(ftype);
512 drsp->token = strdup(token);
513 drsp->storeid = storeid;
514 drsp->which = which;
515
516 switch (type) {
517 case ASN_BOOLEAN:
518 register_prenetsnmp_mib_handler(ftype, token, netsnmp_ds_handle_config,
519 NULL, "(1|yes|true|0|no|false)");
520 break;
521
522 case ASN_INTEGER:
523 register_prenetsnmp_mib_handler(ftype, token, netsnmp_ds_handle_config,
524 NULL, "integerValue");
525 break;
526
527 case ASN_OCTET_STR:
528 register_prenetsnmp_mib_handler(ftype, token, netsnmp_ds_handle_config,
529 NULL, "string");
530 break;
531
532 }
533 return SNMPERR_SUCCESS;
534 }
535
536 void
netsnmp_ds_shutdown(void)537 netsnmp_ds_shutdown(void)
538 {
539 netsnmp_ds_read_config *drsp;
540 int i, j;
541
542 snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
543 for (drsp = netsnmp_ds_configs; drsp; drsp = netsnmp_ds_configs) {
544 netsnmp_ds_configs = drsp->next;
545
546 if (drsp->ftype && drsp->token) {
547 unregister_config_handler(drsp->ftype, drsp->token);
548 }
549 if (drsp->ftype != NULL) {
550 free(drsp->ftype);
551 }
552 if (drsp->token != NULL) {
553 free(drsp->token);
554 }
555 free(drsp);
556 }
557
558 for (i = 0; i < NETSNMP_DS_MAX_IDS; i++) {
559 for (j = 0; j < NETSNMP_DS_MAX_SUBIDS; j++) {
560 if (netsnmp_ds_strings[i][j] != NULL) {
561 free(netsnmp_ds_strings[i][j]);
562 netsnmp_ds_strings[i][j] = NULL;
563 }
564 }
565 }
566 snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
567 }
568 /** @} */
569