1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-features.h>
3 #include <net-snmp/net-snmp-includes.h>
4 #include <net-snmp/agent/net-snmp-agent-includes.h>
5 #include <net-snmp/agent/scalar.h>
6 
7 #ifdef HAVE_STRING_H
8 #include <string.h>
9 #else
10 #include <strings.h>
11 #endif
12 
13 #include <net-snmp/agent/cache_handler.h>
14 #include "agent/nsCache.h"
15 
16 netsnmp_feature_require(cache_get_head);
17 
18 
19 /*
20  * use unadvertised function to get cache head. You really should not
21  * do this, since the internal storage mechanism might change.
22  */
23 extern netsnmp_cache *netsnmp_cache_get_head(void);
24 
25 
26 #define nsCache 1, 3, 6, 1, 4, 1, 8072, 1, 5
27 
28 /*
29  * OIDs for the cacheging control scalar objects
30  *
31  * Note that these we're registering the full object rather
32  *  than the (sole) valid instance in each case, in order
33  *  to handle requests for invalid instances properly.
34  */
35 
36 /*
37  * ... and for the cache table.
38  */
39 
40 #define  NSCACHE_TIMEOUT	2
41 #define  NSCACHE_STATUS		3
42 
43 #define NSCACHE_STATUS_ENABLED  1
44 #define NSCACHE_STATUS_DISABLED 2
45 #define NSCACHE_STATUS_EMPTY    3
46 #define NSCACHE_STATUS_ACTIVE   4
47 #define NSCACHE_STATUS_EXPIRED  5
48 
49 NETSNMP_IMPORT struct snmp_alarm *
50 sa_find_specific(unsigned int clientreg);
51 
52 
53 void
init_nsCache(void)54 init_nsCache(void)
55 {
56     const oid nsCacheTimeout_oid[]    = { nsCache, 1 };
57     const oid nsCacheEnabled_oid[]    = { nsCache, 2 };
58     const oid nsCacheTable_oid[]      = { nsCache, 3 };
59 
60     netsnmp_table_registration_info *table_info;
61     netsnmp_iterator_info           *iinfo;
62 
63     /*
64      * Register the scalar objects...
65      */
66     DEBUGMSGTL(("nsCacheScalars", "Initializing\n"));
67     netsnmp_register_scalar(
68         netsnmp_create_handler_registration(
69             "nsCacheTimeout", handle_nsCacheTimeout,
70             nsCacheTimeout_oid, OID_LENGTH(nsCacheTimeout_oid),
71             HANDLER_CAN_RWRITE)
72         );
73     netsnmp_register_scalar(
74         netsnmp_create_handler_registration(
75             "nsCacheEnabled", handle_nsCacheEnabled,
76             nsCacheEnabled_oid, OID_LENGTH(nsCacheEnabled_oid),
77             HANDLER_CAN_RWRITE)
78         );
79 
80     /*
81      * ... and the table.
82      * We need to define the column structure and indexing....
83      */
84 
85     table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
86     if (!table_info) {
87         return;
88     }
89     netsnmp_table_helper_add_indexes(table_info, ASN_PRIV_IMPLIED_OBJECT_ID, 0);
90     table_info->min_column = NSCACHE_TIMEOUT;
91     table_info->max_column = NSCACHE_STATUS;
92 
93 
94     /*
95      * .... and the iteration information ....
96      */
97     iinfo      = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
98     if (!iinfo) {
99         SNMP_FREE(table_info);
100         return;
101     }
102     iinfo->get_first_data_point = get_first_cache_entry;
103     iinfo->get_next_data_point  = get_next_cache_entry;
104     iinfo->table_reginfo        = table_info;
105 
106 
107     /*
108      * .... and register the table with the agent.
109      */
110     netsnmp_register_table_iterator2(
111         netsnmp_create_handler_registration(
112             "tzCacheTable", handle_nsCacheTable,
113             nsCacheTable_oid, OID_LENGTH(nsCacheTable_oid),
114             HANDLER_CAN_RWRITE),
115         iinfo);
116 }
117 
118 
119 /*
120  * nsCache scalar handling
121  */
122 
123 int
handle_nsCacheTimeout(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)124 handle_nsCacheTimeout(netsnmp_mib_handler *handler,
125                 netsnmp_handler_registration *reginfo,
126                 netsnmp_agent_request_info *reqinfo,
127                 netsnmp_request_info *requests)
128 {
129     long cache_default_timeout =
130         netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
131                                NETSNMP_DS_AGENT_CACHE_TIMEOUT);
132     netsnmp_request_info *request=NULL;
133 
134     switch (reqinfo->mode) {
135 
136     case MODE_GET:
137 	for (request = requests; request; request=request->next) {
138 	    snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
139                                      (u_char*)&cache_default_timeout,
140                                         sizeof(cache_default_timeout));
141 	}
142 	break;
143 
144 
145 #ifndef NETSNMP_NO_WRITE_SUPPORT
146     case MODE_SET_RESERVE1:
147 	for (request = requests; request; request=request->next) {
148             if ( request->status != 0 ) {
149                 return SNMP_ERR_NOERROR;	/* Already got an error */
150             }
151             if ( request->requestvb->type != ASN_INTEGER ) {
152                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
153                 return SNMP_ERR_WRONGTYPE;
154             }
155             if ( *request->requestvb->val.integer < 0 ) {
156                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
157                 return SNMP_ERR_WRONGVALUE;
158             }
159         }
160         break;
161 
162     case MODE_SET_COMMIT:
163         netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
164                            NETSNMP_DS_AGENT_CACHE_TIMEOUT,
165                            *requests->requestvb->val.integer);
166         break;
167 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
168     }
169 
170     return SNMP_ERR_NOERROR;
171 }
172 
173 
174 int
handle_nsCacheEnabled(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)175 handle_nsCacheEnabled(netsnmp_mib_handler *handler,
176                 netsnmp_handler_registration *reginfo,
177                 netsnmp_agent_request_info *reqinfo,
178                 netsnmp_request_info *requests)
179 {
180     long enabled;
181     netsnmp_request_info *request=NULL;
182 
183     switch (reqinfo->mode) {
184 
185     case MODE_GET:
186 	enabled =  (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
187                                            NETSNMP_DS_AGENT_NO_CACHING)
188                        ? NSCACHE_STATUS_ENABLED    /* Actually True/False */
189                        : NSCACHE_STATUS_DISABLED );
190 	for (request = requests; request; request=request->next) {
191 	    snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
192                                      (u_char*)&enabled, sizeof(enabled));
193 	}
194 	break;
195 
196 
197 #ifndef NETSNMP_NO_WRITE_SUPPORT
198     case MODE_SET_RESERVE1:
199 	for (request = requests; request; request=request->next) {
200             if ( request->status != 0 ) {
201                 return SNMP_ERR_NOERROR;	/* Already got an error */
202             }
203             if ( request->requestvb->type != ASN_INTEGER ) {
204                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
205                 return SNMP_ERR_WRONGTYPE;
206             }
207             if ((*request->requestvb->val.integer != NSCACHE_STATUS_ENABLED) &&
208                 (*request->requestvb->val.integer != NSCACHE_STATUS_DISABLED)) {
209                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
210                 return SNMP_ERR_WRONGVALUE;
211             }
212         }
213         break;
214 
215     case MODE_SET_COMMIT:
216         enabled = *requests->requestvb->val.integer;
217 	if (enabled == NSCACHE_STATUS_DISABLED)
218 	    enabled = 0;
219 	netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
220                                NETSNMP_DS_AGENT_NO_CACHING, enabled);
221         break;
222 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
223     }
224 
225     return SNMP_ERR_NOERROR;
226 }
227 
228 
229 /*
230  * nsCacheTable handling
231  */
232 
233 netsnmp_variable_list *
get_first_cache_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)234 get_first_cache_entry(void **loop_context, void **data_context,
235                       netsnmp_variable_list *index,
236                       netsnmp_iterator_info *data)
237 {
238     netsnmp_cache  *cache_head = netsnmp_cache_get_head();
239 
240     if ( !cache_head )
241         return NULL;
242 
243     snmp_set_var_value(index, (u_char*)cache_head->rootoid,
244 		         sizeof(oid) * cache_head->rootoid_len);
245     *loop_context = (void*)cache_head;
246     *data_context = (void*)cache_head;
247     return index;
248 }
249 
250 netsnmp_variable_list *
get_next_cache_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)251 get_next_cache_entry(void **loop_context, void **data_context,
252                       netsnmp_variable_list *index,
253                       netsnmp_iterator_info *data)
254 {
255     netsnmp_cache *cache = (netsnmp_cache *)*loop_context;
256     cache = cache->next;
257 
258     if ( !cache )
259         return NULL;
260 
261     snmp_set_var_value(index, (u_char*)cache->rootoid,
262 		         sizeof(oid) * cache->rootoid_len);
263     *loop_context = (void*)cache;
264     *data_context = (void*)cache;
265     return index;
266 }
267 
268 
269 int
handle_nsCacheTable(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)270 handle_nsCacheTable(netsnmp_mib_handler *handler,
271                 netsnmp_handler_registration *reginfo,
272                 netsnmp_agent_request_info *reqinfo,
273                 netsnmp_request_info *requests)
274 {
275     long status;
276     netsnmp_request_info       *request     = NULL;
277     netsnmp_table_request_info *table_info  = NULL;
278     netsnmp_cache              *cache_entry = NULL;
279 
280     switch (reqinfo->mode) {
281 
282     case MODE_GET:
283         for (request=requests; request; request=request->next) {
284             if (request->processed != 0)
285                 continue;
286 
287             cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request);
288             table_info  =                 netsnmp_extract_table_info(request);
289 
290             switch (table_info->colnum) {
291             case NSCACHE_TIMEOUT:
292                 if (!cache_entry) {
293                     netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
294                     continue;
295 		}
296 		status = cache_entry->timeout;
297 	        snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
298                                          (u_char*)&status, sizeof(status));
299 	        break;
300 
301             case NSCACHE_STATUS:
302                 if (!cache_entry) {
303                     netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
304                     continue;
305 		}
306 		status = (cache_entry->enabled ?
307 	                   (cache_entry->timestampM ?
308                              (cache_entry->timeout >= 0 &&
309                               !netsnmp_ready_monotonic(cache_entry->timestampM,
310                                                        1000*cache_entry->timeout) ?
311 	                        NSCACHE_STATUS_ACTIVE:
312 	                        NSCACHE_STATUS_EXPIRED) :
313 	                      NSCACHE_STATUS_EMPTY) :
314 	                    NSCACHE_STATUS_DISABLED);
315 	        snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
316                                          (u_char*)&status, sizeof(status));
317 	        break;
318 
319             default:
320                 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
321                 continue;
322 	    }
323 	}
324 	break;
325 
326 
327 #ifndef NETSNMP_NO_WRITE_SUPPORT
328     case MODE_SET_RESERVE1:
329         for (request=requests; request; request=request->next) {
330             if (request->processed != 0)
331                 continue;
332             if ( request->status != 0 ) {
333                 return SNMP_ERR_NOERROR;	/* Already got an error */
334             }
335             cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request);
336             table_info  =                 netsnmp_extract_table_info(request);
337 
338             switch (table_info->colnum) {
339             case NSCACHE_TIMEOUT:
340                 if (!cache_entry) {
341                     netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
342                     return SNMP_ERR_NOCREATION;
343 		}
344                 if ( request->requestvb->type != ASN_INTEGER ) {
345                     netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
346                     return SNMP_ERR_WRONGTYPE;
347                 }
348                 if (*request->requestvb->val.integer < 0 ) {
349                     netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
350                     return SNMP_ERR_WRONGVALUE;
351                 }
352 	        break;
353 
354             case NSCACHE_STATUS:
355                 if (!cache_entry) {
356                     netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
357                     return SNMP_ERR_NOCREATION;
358 		}
359                 if ( request->requestvb->type != ASN_INTEGER ) {
360                     netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
361                     return SNMP_ERR_WRONGTYPE;
362                 }
363                 status = *request->requestvb->val.integer;
364                 if (!((status == NSCACHE_STATUS_ENABLED  ) ||
365                       (status == NSCACHE_STATUS_DISABLED ) ||
366                       (status == NSCACHE_STATUS_EMPTY  ))) {
367                     netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
368                     return SNMP_ERR_WRONGVALUE;
369                 }
370 	        break;
371 
372             default:
373                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
374                 return SNMP_ERR_NOCREATION;	/* XXX - is this right ? */
375 	    }
376 	}
377 	break;
378 
379 
380     case MODE_SET_COMMIT:
381         for (request=requests; request; request=request->next) {
382             if (request->processed != 0)
383                 continue;
384             if ( request->status != 0 ) {
385                 return SNMP_ERR_NOERROR;	/* Already got an error */
386             }
387             cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request);
388             if (!cache_entry) {
389                 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_COMMITFAILED);
390                 return SNMP_ERR_COMMITFAILED;	/* Shouldn't happen! */
391             }
392             table_info  =                 netsnmp_extract_table_info(request);
393 
394             switch (table_info->colnum) {
395             case NSCACHE_TIMEOUT:
396                 cache_entry->timeout = *request->requestvb->val.integer;
397                 /*
398                  * check for auto repeat
399                  */
400                 if (cache_entry->timer_id) {
401                     struct snmp_alarm * sa =
402                         sa_find_specific(cache_entry->timer_id);
403                     if (NULL != sa)
404                         sa->t.tv_sec = cache_entry->timeout;
405                 }
406 	        break;
407 
408             case NSCACHE_STATUS:
409                 switch (*request->requestvb->val.integer) {
410                     case NSCACHE_STATUS_ENABLED:
411                         cache_entry->enabled = 1;
412                         break;
413 		    case NSCACHE_STATUS_DISABLED:
414                         cache_entry->enabled = 0;
415                         break;
416 		    case NSCACHE_STATUS_EMPTY:
417                         cache_entry->free_cache(cache_entry, cache_entry->magic);
418                         free(cache_entry->timestampM);
419                         cache_entry->timestampM = NULL;
420                         break;
421 		}
422 	        break;
423 	    }
424 	}
425 	break;
426 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
427     }
428 
429     return SNMP_ERR_NOERROR;
430 }
431