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