1 /* Portions of this file are subject to the following copyright(s). See
2 * the Net-SNMP's COPYING file for more details and other copyrights
3 * that may apply:
4 */
5 /*
6 * Portions of this file are copyrighted by:
7 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
8 * Use is subject to license terms specified in the COPYING file
9 * distributed with the Net-SNMP package.
10 *
11 * Portions of this file are copyrighted by:
12 * Copyright (c) 2016 VMware, Inc. All rights reserved.
13 * Use is subject to license terms specified in the COPYING file
14 * distributed with the Net-SNMP package.
15 */
16 #include <net-snmp/net-snmp-config.h>
17 #include <net-snmp/net-snmp-features.h>
18
19 #include <sys/types.h>
20
21 #if HAVE_STRING_H
22 #include <string.h>
23 #endif
24
25 #include <net-snmp/net-snmp-includes.h>
26 #include <net-snmp/agent/net-snmp-agent-includes.h>
27
28 #include <net-snmp/agent/bulk_to_next.h>
29
30 netsnmp_feature_child_of(agent_handler, libnetsnmpagent);
31
32 netsnmp_feature_child_of(handler_mark_requests_as_delegated, agent_handler);
33
34 static netsnmp_mib_handler *_clone_handler(netsnmp_mib_handler *it);
35
36 /***********************************************************************/
37 /*
38 * New Handler based API
39 */
40 /***********************************************************************/
41 /** @defgroup handler Net-SNMP Agent handler and extensibility API
42 * @ingroup agent
43 *
44 * The basic theory goes something like this: In the past, with the
45 * original mib module api (which derived from the original CMU SNMP
46 * code) the underlying mib modules were passed very little
47 * information (only the truly most basic information about a
48 * request). This worked well at the time but in todays world of
49 * subagents, device instrumentation, low resource consumption, etc,
50 * it just isn't flexible enough. "handlers" are here to fix all that.
51 *
52 * With the rewrite of the agent internals for the net-snmp 5.0
53 * release, we introduce a modular calling scheme that allows agent
54 * modules to be written in a very flexible manner, and more
55 * importantly allows reuse of code in a decent way (and without the
56 * memory and speed overheads of OO languages like C++).
57 *
58 * Functionally, the notion of what a handler does is the same as the
59 * older api: A handler is @link netsnmp_create_handler() created@endlink and
60 * then @link netsnmp_register_handler() registered@endlink with the main
61 * agent at a given OID in the OID tree and gets called any time a
62 * request is made that it should respond to. You probably should
63 * use one of the convenience helpers instead of doing anything else
64 * yourself though:
65 *
66 * Most importantly, though, is that the handlers are built on the
67 * notion of modularity and reuse. Specifically, rather than do all
68 * the really hard work (like parsing table indexes out of an
69 * incoming oid request) in each module, the API is designed to make
70 * it easy to write "helper" handlers that merely process some aspect
71 * of the request before passing it along to the final handler that
72 * returns the real answer. Most people will want to make use of the
73 * @link instance instance@endlink, @link table table@endlink, @link
74 * table_iterator table_iterator@endlink, @link table_data
75 * table_data@endlink, or @link table_dataset table_dataset@endlink
76 * helpers to make their life easier. These "helpers" interpert
77 * important aspects of the request and pass them on to you.
78 *
79 * For instance, the @link table table@endlink helper is designed to
80 * hand you a list of extracted index values from an incoming
81 * request. THe @link table_iterator table_iterator@endlink helper
82 * is built on top of the table helper, and is designed to help you
83 * iterate through data stored elsewhere (like in a kernel) that is
84 * not in OID lexographical order (ie, don't write your own index/oid
85 * sorting routine, use this helper instead). The beauty of the
86 * @link table_iterator table_iterator helper@endlink, as well as the @link
87 * instance instance@endlink helper is that they take care of the complex
88 * GETNEXT processing entirely for you and hand you everything you
89 * need to merely return the data as if it was a GET request. Much
90 * less code and hair pulling. I've pulled all my hair out to help
91 * you so that only one of us has to be bald.
92 *
93 * @{
94 */
95
96 /** Creates a MIB handler structure.
97 * The new structure is allocated and filled using the given name
98 * and access method.
99 * The returned handler should then be @link netsnmp_register_handler()
100 * registered @endlink.
101 *
102 * @param name is the handler name and is copied then assigned to
103 * netsnmp_mib_handler->handler_name
104 *
105 * @param handler_access_method is a function pointer used as the access
106 * method for this handler registration instance for whatever required
107 * needs.
108 *
109 * @return a pointer to a populated netsnmp_mib_handler struct to be
110 * registered
111 *
112 * @see netsnmp_create_handler_registration()
113 * @see netsnmp_register_handler()
114 */
115 netsnmp_mib_handler *
netsnmp_create_handler(const char * name,Netsnmp_Node_Handler * handler_access_method)116 netsnmp_create_handler(const char *name,
117 Netsnmp_Node_Handler * handler_access_method)
118 {
119 netsnmp_mib_handler *ret = SNMP_MALLOC_TYPEDEF(netsnmp_mib_handler);
120 if (ret) {
121 ret->access_method = handler_access_method;
122 if (NULL != name) {
123 ret->handler_name = strdup(name);
124 if (NULL == ret->handler_name)
125 SNMP_FREE(ret);
126 }
127 }
128 return ret;
129 }
130
131 /** Creates a MIB handler structure.
132 * The new structure is allocated and filled using the given name,
133 * access function, registration location OID and list of modes that
134 * the handler supports. If modes == 0, then modes will automatically
135 * be set to the default value of only HANDLER_CAN_DEFAULT, which is
136 * by default read-only GET and GETNEXT requests. A hander which supports
137 * sets but not row creation should set us a mode of HANDLER_CAN_SET_ONLY.
138 * @note This ends up calling netsnmp_create_handler(name, handler_access_method)
139 * @param name is the handler name and is copied then assigned to
140 * netsnmp_handler_registration->handlerName.
141 *
142 * @param handler is a function pointer used as the access
143 * method for this handler registration instance for whatever required
144 * needs.
145 *
146 * @param reg_oid is the registration location oid.
147 *
148 * @param reg_oid_len is the length of reg_oid; can use the macro,
149 * OID_LENGTH
150 *
151 * @param modes is used to configure read/write access. If modes == 0,
152 * then modes will automatically be set to the default
153 * value of only HANDLER_CAN_DEFAULT, which is by default read-only GET
154 * and GETNEXT requests. The other two mode options are read only,
155 * HANDLER_CAN_RONLY, and read/write, HANDLER_CAN_RWRITE.
156 *
157 * - HANDLER_CAN_GETANDGETNEXT
158 * - HANDLER_CAN_SET
159 * - HANDLER_CAN_GETBULK
160 *
161 * - HANDLER_CAN_RONLY (HANDLER_CAN_GETANDGETNEXT)
162 * - HANDLER_CAN_RWRITE (HANDLER_CAN_GETANDGETNEXT |
163 * HANDLER_CAN_SET)
164 * - HANDLER_CAN_DEFAULT HANDLER_CAN_RONLY
165 *
166 * @return Returns a pointer to a netsnmp_handler_registration struct.
167 * NULL is returned only when memory could not be allocated for the
168 * netsnmp_handler_registration struct.
169 *
170 *
171 * @see netsnmp_create_handler()
172 * @see netsnmp_register_handler()
173 */
174 netsnmp_handler_registration *
netsnmp_handler_registration_create(const char * name,netsnmp_mib_handler * handler,const oid * reg_oid,size_t reg_oid_len,int modes)175 netsnmp_handler_registration_create(const char *name,
176 netsnmp_mib_handler *handler,
177 const oid * reg_oid, size_t reg_oid_len,
178 int modes)
179 {
180 netsnmp_handler_registration *the_reg;
181 the_reg = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration);
182 if (!the_reg)
183 return NULL;
184
185 if (modes)
186 the_reg->modes = modes;
187 else
188 the_reg->modes = HANDLER_CAN_DEFAULT;
189
190 the_reg->handler = handler;
191 the_reg->priority = DEFAULT_MIB_PRIORITY;
192 if (name)
193 the_reg->handlerName = strdup(name);
194 the_reg->rootoid = snmp_duplicate_objid(reg_oid, reg_oid_len);
195 the_reg->rootoid_len = reg_oid_len;
196 return the_reg;
197 }
198
199 /** Creates a handler registration structure with a new MIB handler.
200 * This function first @link netsnmp_create_handler() creates @endlink
201 * a MIB handler, then @link netsnmp_handler_registration_create()
202 * makes registation structure @endlink for it.
203 *
204 * @param name is the handler name for netsnmp_create_handler()
205 *
206 * @param handler_access_method is a function pointer used as the access
207 * method for netsnmp_create_handler()
208 *
209 * @param reg_oid is the registration location oid.
210 *
211 * @param reg_oid_len is the length of reg_oid; can use the macro,
212 * OID_LENGTH
213 *
214 * @param modes is used to configure read/write access, as in
215 * netsnmp_handler_registration_create()
216 *
217 * @return Returns a pointer to a netsnmp_handler_registration struct.
218 * If the structures creation failed, NULL is returned.
219 *
220 * @see netsnmp_create_handler()
221 * @see netsnmp_handler_registration_create()
222 */
223 netsnmp_handler_registration *
netsnmp_create_handler_registration(const char * name,Netsnmp_Node_Handler * handler_access_method,const oid * reg_oid,size_t reg_oid_len,int modes)224 netsnmp_create_handler_registration(const char *name,
225 Netsnmp_Node_Handler *
226 handler_access_method, const oid * reg_oid,
227 size_t reg_oid_len, int modes)
228 {
229 netsnmp_handler_registration *rv = NULL;
230 netsnmp_mib_handler *handler =
231 netsnmp_create_handler(name, handler_access_method);
232 if (handler) {
233 rv = netsnmp_handler_registration_create(
234 name, handler, reg_oid, reg_oid_len, modes);
235 if (!rv)
236 netsnmp_handler_free(handler);
237 }
238 return rv;
239 }
240
241 /** Registers a MIB handler inside the registration structure.
242 * Checks given registation handler for sanity, then
243 * @link netsnmp_register_mib() performs registration @endlink
244 * in the MIB tree, as defined by the netsnmp_handler_registration
245 * pointer. On success, SNMP_CALLBACK_APPLICATION is called.
246 * The registration struct may be created by call of
247 * netsnmp_create_handler_registration().
248 *
249 * @param reginfo Pointer to a netsnmp_handler_registration struct.
250 *
251 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
252 *
253 * @see netsnmp_create_handler_registration()
254 * @see netsnmp_register_mib()
255 */
256 int
netsnmp_register_handler(netsnmp_handler_registration * reginfo)257 netsnmp_register_handler(netsnmp_handler_registration *reginfo)
258 {
259 netsnmp_mib_handler *handler;
260 int flags = 0;
261
262 if (reginfo == NULL) {
263 snmp_log(LOG_ERR, "netsnmp_register_handler() called illegally\n");
264 netsnmp_assert(reginfo != NULL);
265 return SNMP_ERR_GENERR;
266 }
267
268 DEBUGIF("handler::register") {
269 DEBUGMSGTL(("handler::register", "Registering %s (", reginfo->handlerName));
270 for (handler = reginfo->handler; handler; handler = handler->next) {
271 DEBUGMSG(("handler::register", "::%s", handler->handler_name));
272 }
273
274 DEBUGMSG(("handler::register", ") at "));
275 if (reginfo->rootoid && reginfo->range_subid) {
276 DEBUGMSGOIDRANGE(("handler::register", reginfo->rootoid,
277 reginfo->rootoid_len, reginfo->range_subid,
278 reginfo->range_ubound));
279 } else if (reginfo->rootoid) {
280 DEBUGMSGOID(("handler::register", reginfo->rootoid,
281 reginfo->rootoid_len));
282 } else {
283 DEBUGMSG(("handler::register", "[null]"));
284 }
285 DEBUGMSG(("handler::register", "\n"));
286 }
287
288 /*
289 * don't let them register for absolutely nothing. Probably a mistake
290 */
291 if (0 == reginfo->modes) {
292 reginfo->modes = HANDLER_CAN_DEFAULT;
293 snmp_log(LOG_WARNING, "no registration modes specified for %s. "
294 "Defaulting to 0x%x\n", reginfo->handlerName, reginfo->modes);
295 }
296
297 /*
298 * for handlers that can't GETBULK, force a conversion handler on them
299 */
300 if (!(reginfo->modes & HANDLER_CAN_GETBULK)) {
301 handler = netsnmp_get_bulk_to_next_handler();
302 if (!handler ||
303 (netsnmp_inject_handler(reginfo, handler) != SNMPERR_SUCCESS)) {
304 snmp_log(LOG_WARNING, "could not inject bulk to next handler\n");
305 if (handler)
306 netsnmp_handler_free(handler);
307 /** should this be a critical error? */
308 netsnmp_handler_registration_free(reginfo);
309 return SNMP_ERR_GENERR;
310 }
311 }
312
313 for (handler = reginfo->handler; handler; handler = handler->next) {
314 if (handler->flags & MIB_HANDLER_INSTANCE)
315 flags = FULLY_QUALIFIED_INSTANCE;
316 }
317
318 return netsnmp_register_mib(reginfo->handlerName,
319 NULL, 0, 0,
320 reginfo->rootoid, reginfo->rootoid_len,
321 reginfo->priority,
322 reginfo->range_subid,
323 reginfo->range_ubound, NULL,
324 reginfo->contextName, reginfo->timeout, flags,
325 reginfo, 1);
326 }
327
328 /** Unregisters a MIB handler described inside the registration structure.
329 * Removes a registration, performed earlier by
330 * netsnmp_register_handler(), from the MIB tree.
331 * Uses unregister_mib_context() to do the task.
332 *
333 * @param reginfo Pointer to a netsnmp_handler_registration struct.
334 *
335 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
336 *
337 * @see netsnmp_register_handler()
338 * @see unregister_mib_context()
339 */
340 int
netsnmp_unregister_handler(netsnmp_handler_registration * reginfo)341 netsnmp_unregister_handler(netsnmp_handler_registration *reginfo)
342 {
343 if (!reginfo)
344 return SNMPERR_SUCCESS;
345 return unregister_mib_context(reginfo->rootoid, reginfo->rootoid_len,
346 reginfo->priority,
347 reginfo->range_subid, reginfo->range_ubound,
348 reginfo->contextName);
349 }
350
351 /** Registers a MIB handler inside the registration structure.
352 * Checks given registation handler for sanity, then
353 * @link netsnmp_register_mib() performs registration @endlink
354 * in the MIB tree, as defined by the netsnmp_handler_registration
355 * pointer. Never calls SNMP_CALLBACK_APPLICATION.
356 * The registration struct may be created by call of
357 * netsnmp_create_handler_registration().
358 *
359 * @param reginfo Pointer to a netsnmp_handler_registration struct.
360 *
361 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
362 *
363 * @see netsnmp_create_handler_registration()
364 * @see netsnmp_register_mib()
365 */
366 int
netsnmp_register_handler_nocallback(netsnmp_handler_registration * reginfo)367 netsnmp_register_handler_nocallback(netsnmp_handler_registration *reginfo)
368 {
369 netsnmp_mib_handler *handler;
370 if (reginfo == NULL) {
371 snmp_log(LOG_ERR, "netsnmp_register_handler_nocallback() called illegally\n");
372 netsnmp_assert(reginfo != NULL);
373 return SNMP_ERR_GENERR;
374 }
375 DEBUGIF("handler::register") {
376 DEBUGMSGTL(("handler::register",
377 "Registering (with no callback) "));
378 for (handler = reginfo->handler; handler; handler = handler->next) {
379 DEBUGMSG(("handler::register", "::%s", handler->handler_name));
380 }
381
382 DEBUGMSG(("handler::register", " at "));
383 if (reginfo->rootoid && reginfo->range_subid) {
384 DEBUGMSGOIDRANGE(("handler::register", reginfo->rootoid,
385 reginfo->rootoid_len, reginfo->range_subid,
386 reginfo->range_ubound));
387 } else if (reginfo->rootoid) {
388 DEBUGMSGOID(("handler::register", reginfo->rootoid,
389 reginfo->rootoid_len));
390 } else {
391 DEBUGMSG(("handler::register", "[null]"));
392 }
393 DEBUGMSG(("handler::register", "\n"));
394 }
395
396 /*
397 * don't let them register for absolutely nothing. Probably a mistake
398 */
399 if (0 == reginfo->modes) {
400 reginfo->modes = HANDLER_CAN_DEFAULT;
401 }
402
403 return netsnmp_register_mib(reginfo->handler->handler_name,
404 NULL, 0, 0,
405 reginfo->rootoid, reginfo->rootoid_len,
406 reginfo->priority,
407 reginfo->range_subid,
408 reginfo->range_ubound, NULL,
409 reginfo->contextName, reginfo->timeout, 0,
410 reginfo, 0);
411 }
412
413 /** Injects handler into the calling chain of handlers.
414 * The given MIB handler is inserted after the handler named before_what.
415 * If before_what is NULL, the handler is put at the top of the list,
416 * and hence will be the handler to be called first.
417 *
418 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
419 *
420 * @see netsnmp_create_handler_registration()
421 * @see netsnmp_inject_handler()
422 */
423 int
netsnmp_inject_handler_before(netsnmp_handler_registration * reginfo,netsnmp_mib_handler * handler,const char * before_what)424 netsnmp_inject_handler_before(netsnmp_handler_registration *reginfo,
425 netsnmp_mib_handler *handler,
426 const char *before_what)
427 {
428 netsnmp_mib_handler *handler2 = handler;
429
430 if (handler == NULL || reginfo == NULL) {
431 snmp_log(LOG_ERR, "netsnmp_inject_handler() called illegally\n");
432 netsnmp_assert(reginfo != NULL);
433 netsnmp_assert(handler != NULL);
434 return SNMP_ERR_GENERR;
435 }
436 while (handler2->next) {
437 handler2 = handler2->next; /* Find the end of a handler sub-chain */
438 }
439 if (reginfo->handler == NULL) {
440 DEBUGMSGTL(("handler:inject", "injecting %s\n", handler->handler_name));
441 }
442 else {
443 DEBUGMSGTL(("handler:inject", "injecting %s before %s\n",
444 handler->handler_name, reginfo->handler->handler_name));
445 }
446 if (before_what) {
447 netsnmp_mib_handler *nexth, *prevh = NULL;
448 if (reginfo->handler == NULL) {
449 snmp_log(LOG_ERR, "no handler to inject before\n");
450 return SNMP_ERR_GENERR;
451 }
452 for(nexth = reginfo->handler; nexth;
453 prevh = nexth, nexth = nexth->next) {
454 if (strcmp(nexth->handler_name, before_what) == 0)
455 break;
456 }
457 if (!nexth) {
458 snmp_log(LOG_ERR, "Cannot inject '%s' before '%s': not found\n", handler->handler_name, before_what);
459 snmp_log(LOG_ERR, "The handlers are:\n");
460 for (nexth = reginfo->handler; nexth; nexth = nexth->next)
461 snmp_log(LOG_ERR, " %s\n", nexth->handler_name);
462 return SNMP_ERR_GENERR;
463 }
464 if (prevh) {
465 /* after prevh and before nexth */
466 prevh->next = handler;
467 handler2->next = nexth;
468 handler->prev = prevh;
469 nexth->prev = handler2;
470 return SNMPERR_SUCCESS;
471 }
472 /* else we're first, which is what we do next anyway so fall through */
473 }
474 handler2->next = reginfo->handler;
475 if (reginfo->handler)
476 reginfo->handler->prev = handler2;
477 reginfo->handler = handler;
478 return SNMPERR_SUCCESS;
479 }
480
481 /** Injects handler into the calling chain of handlers.
482 * The given MIB handler is put at the top of the list,
483 * and hence will be the handler to be called first.
484 *
485 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
486 *
487 * @see netsnmp_create_handler_registration()
488 * @see netsnmp_inject_handler_before()
489 */
490 int
netsnmp_inject_handler(netsnmp_handler_registration * reginfo,netsnmp_mib_handler * handler)491 netsnmp_inject_handler(netsnmp_handler_registration *reginfo,
492 netsnmp_mib_handler *handler)
493 {
494 return netsnmp_inject_handler_before(reginfo, handler, NULL);
495 }
496
497 /** Calls a MIB handlers chain, starting with specific handler.
498 * The given arguments and MIB handler are checked
499 * for sanity, then the handlers are called, one by one,
500 * until next handler is NULL.
501 *
502 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
503 */
504 NETSNMP_INLINE int
netsnmp_call_handler(netsnmp_mib_handler * next_handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)505 netsnmp_call_handler(netsnmp_mib_handler *next_handler,
506 netsnmp_handler_registration *reginfo,
507 netsnmp_agent_request_info *reqinfo,
508 netsnmp_request_info *requests)
509 {
510 Netsnmp_Node_Handler *nh;
511 int ret;
512
513 if (next_handler == NULL || reginfo == NULL || reqinfo == NULL ||
514 requests == NULL) {
515 snmp_log(LOG_ERR, "netsnmp_call_handler() called illegally\n");
516 netsnmp_assert(next_handler != NULL);
517 netsnmp_assert(reqinfo != NULL);
518 netsnmp_assert(reginfo != NULL);
519 netsnmp_assert(requests != NULL);
520 return SNMP_ERR_GENERR;
521 }
522
523 do {
524 nh = next_handler->access_method;
525 if (!nh) {
526 if (next_handler->next) {
527 snmp_log(LOG_ERR, "no access method specified in handler %s.",
528 next_handler->handler_name);
529 return SNMP_ERR_GENERR;
530 }
531 /*
532 * The final handler registration in the chain may well not need
533 * to include a handler routine, if the processing of this object
534 * is handled completely by the agent toolkit helpers.
535 */
536 return SNMP_ERR_NOERROR;
537 }
538
539 DEBUGMSGTL(("handler:calling", "calling handler %s for mode %s\n",
540 next_handler->handler_name,
541 se_find_label_in_slist("agent_mode", reqinfo->mode)));
542
543 /*
544 * XXX: define acceptable return statuses
545 */
546 ret = (*nh) (next_handler, reginfo, reqinfo, requests);
547
548 DEBUGMSGTL(("handler:returned", "handler %s returned %d\n",
549 next_handler->handler_name, ret));
550
551 if (! (next_handler->flags & MIB_HANDLER_AUTO_NEXT))
552 break;
553
554 /*
555 * did handler signal that it didn't want auto next this time around?
556 */
557 if(next_handler->flags & MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE) {
558 next_handler->flags &= ~MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
559 break;
560 }
561
562 next_handler = next_handler->next;
563
564 } while(next_handler);
565
566 return ret;
567 }
568
569 /** @private
570 * Calls all the MIB Handlers in registration struct for a given mode.
571 *
572 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
573 */
574 int
netsnmp_call_handlers(netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)575 netsnmp_call_handlers(netsnmp_handler_registration *reginfo,
576 netsnmp_agent_request_info *reqinfo,
577 netsnmp_request_info *requests)
578 {
579 netsnmp_request_info *request;
580 int status;
581
582 if (reginfo == NULL || reqinfo == NULL || requests == NULL) {
583 snmp_log(LOG_ERR, "netsnmp_call_handlers() called illegally\n");
584 netsnmp_assert(reqinfo != NULL);
585 netsnmp_assert(reginfo != NULL);
586 netsnmp_assert(requests != NULL);
587 return SNMP_ERR_GENERR;
588 }
589
590 if (reginfo->handler == NULL) {
591 snmp_log(LOG_ERR, "no handler specified.");
592 return SNMP_ERR_GENERR;
593 }
594
595 switch (reqinfo->mode) {
596 case MODE_GETBULK:
597 case MODE_GET:
598 case MODE_GETNEXT:
599 if (!(reginfo->modes & HANDLER_CAN_GETANDGETNEXT))
600 return SNMP_ERR_NOERROR; /* legal */
601 break;
602
603 #ifndef NETSNMP_NO_WRITE_SUPPORT
604 case MODE_SET_RESERVE1:
605 case MODE_SET_RESERVE2:
606 case MODE_SET_ACTION:
607 case MODE_SET_COMMIT:
608 case MODE_SET_FREE:
609 case MODE_SET_UNDO:
610 if (!(reginfo->modes & HANDLER_CAN_SET)) {
611 for (; requests; requests = requests->next) {
612 netsnmp_set_request_error(reqinfo, requests,
613 SNMP_ERR_NOTWRITABLE);
614 }
615 return SNMP_ERR_NOERROR;
616 }
617 break;
618 #endif /* NETSNMP_NO_WRITE_SUPPORT */
619
620 default:
621 snmp_log(LOG_ERR, "unknown mode in netsnmp_call_handlers! bug!\n");
622 return SNMP_ERR_GENERR;
623 }
624 DEBUGMSGTL(("handler:calling", "main handler %s\n",
625 reginfo->handler->handler_name));
626
627 for (request = requests ; request; request = request->next) {
628 request->processed = 0;
629 }
630
631 status = netsnmp_call_handler(reginfo->handler, reginfo, reqinfo, requests);
632
633 return status;
634 }
635
636 /** @private
637 * Calls the next MIB handler in the chain, after the current one.
638 * The given arguments and MIB handler are checked
639 * for sanity, then the next handler is called.
640 *
641 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
642 */
643 NETSNMP_INLINE int
netsnmp_call_next_handler(netsnmp_mib_handler * current,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)644 netsnmp_call_next_handler(netsnmp_mib_handler *current,
645 netsnmp_handler_registration *reginfo,
646 netsnmp_agent_request_info *reqinfo,
647 netsnmp_request_info *requests)
648 {
649
650 if (current == NULL || reginfo == NULL || reqinfo == NULL ||
651 requests == NULL) {
652 snmp_log(LOG_ERR, "netsnmp_call_next_handler() called illegally\n");
653 netsnmp_assert(current != NULL);
654 netsnmp_assert(reginfo != NULL);
655 netsnmp_assert(reqinfo != NULL);
656 netsnmp_assert(requests != NULL);
657 return SNMP_ERR_GENERR;
658 }
659
660 return netsnmp_call_handler(current->next, reginfo, reqinfo, requests);
661 }
662
663 /** @private
664 * Calls the next MIB handler in the chain, after the current one.
665 * The given arguments and MIB handler are not validated before
666 * the call, only request is checked.
667 *
668 * @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
669 */
670 netsnmp_feature_child_of(netsnmp_call_next_handler_one_request,netsnmp_unused);
671 #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_CALL_NEXT_HANDLER_ONE_REQUEST
672 NETSNMP_INLINE int
netsnmp_call_next_handler_one_request(netsnmp_mib_handler * current,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)673 netsnmp_call_next_handler_one_request(netsnmp_mib_handler *current,
674 netsnmp_handler_registration *reginfo,
675 netsnmp_agent_request_info *reqinfo,
676 netsnmp_request_info *requests)
677 {
678 netsnmp_request_info *request;
679 int ret;
680
681 if (!requests) {
682 snmp_log(LOG_ERR, "netsnmp_call_next_handler_ONE_REQUEST() called illegally\n");
683 netsnmp_assert(requests != NULL);
684 return SNMP_ERR_GENERR;
685 }
686
687 request = requests->next;
688 requests->next = NULL;
689 ret = netsnmp_call_handler(current->next, reginfo, reqinfo, requests);
690 requests->next = request;
691 return ret;
692 }
693 #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_CALL_NEXT_HANDLER_ONE_REQUEST */
694
695 /** Deallocates resources associated with a given handler.
696 * The handler is removed from chain and then freed.
697 * After calling this function, the handler pointer is invalid
698 * and should be set to NULL.
699 *
700 * @param handler is the MIB Handler to be freed
701 */
702 void
netsnmp_handler_free(netsnmp_mib_handler * handler)703 netsnmp_handler_free(netsnmp_mib_handler *handler)
704 {
705 if (handler != NULL) {
706 if (handler->next != NULL) {
707 /** make sure we aren't pointing to ourselves. */
708 netsnmp_assert(handler != handler->next); /* bugs caught: 1 */
709 netsnmp_handler_free(handler->next);
710 handler->next = NULL;
711 }
712 if ((handler->myvoid != NULL) && (handler->data_free != NULL))
713 {
714 handler->data_free(handler->myvoid);
715 }
716 SNMP_FREE(handler->handler_name);
717 SNMP_FREE(handler);
718 }
719 }
720
721 /** Duplicates a MIB handler and all subsequent handlers.
722 * Creates a copy of all data in given handlers chain.
723 *
724 * @param handler is the MIB Handler to be duplicated
725 *
726 * @return Returns a pointer to the complete copy,
727 * or NULL if any problem occured.
728 *
729 * @see _clone_handler()
730 */
731 netsnmp_mib_handler *
netsnmp_handler_dup(netsnmp_mib_handler * handler)732 netsnmp_handler_dup(netsnmp_mib_handler *handler)
733 {
734 netsnmp_mib_handler *h = NULL;
735
736 if (!handler)
737 goto err;
738
739 h = _clone_handler(handler);
740 if (!h)
741 goto err;
742
743 /*
744 * Providing a clone function without a free function is asking for
745 * memory leaks, and providing a free function without clone function
746 * is asking for memory corruption. Hence the log statement below.
747 */
748 if (!!handler->data_clone != !!handler->data_free)
749 snmp_log(LOG_ERR, "data_clone / data_free inconsistent (%s)\n",
750 handler->handler_name);
751 if (handler->myvoid && handler->data_clone) {
752 h->myvoid = handler->data_clone(handler->myvoid);
753 if (!h->myvoid)
754 goto err;
755 } else
756 h->myvoid = handler->myvoid;
757 h->data_clone = handler->data_clone;
758 h->data_free = handler->data_free;
759
760 if (handler->next != NULL) {
761 h->next = netsnmp_handler_dup(handler->next);
762 if (!h->next)
763 goto err;
764 h->next->prev = h;
765 }
766 h->prev = NULL;
767 return h;
768
769 err:
770 netsnmp_handler_free(h);
771 return NULL;
772 }
773
774 /** Free resources associated with a handler registration object.
775 * The registration object and all MIB Handlers in the chain are
776 * freed. When the function ends, given pointer is no longer valid
777 * and should be set to NULL.
778 *
779 * @param reginfo is the handler registration object to be freed
780 */
781 void
netsnmp_handler_registration_free(netsnmp_handler_registration * reginfo)782 netsnmp_handler_registration_free(netsnmp_handler_registration *reginfo)
783 {
784 if (reginfo != NULL) {
785 netsnmp_handler_free(reginfo->handler);
786 SNMP_FREE(reginfo->handlerName);
787 SNMP_FREE(reginfo->contextName);
788 SNMP_FREE(reginfo->rootoid);
789 reginfo->rootoid_len = 0;
790 SNMP_FREE(reginfo);
791 }
792 }
793
794 /** Duplicates handler registration object and all subsequent handlers.
795 * Creates a copy of the handler registration object and all its data.
796 *
797 * @param reginfo is the handler registration object to be duplicated
798 *
799 * @return Returns a pointer to the complete copy,
800 * or NULL if any problem occured.
801 *
802 * @see netsnmp_handler_dup()
803 */
804 netsnmp_handler_registration *
netsnmp_handler_registration_dup(netsnmp_handler_registration * reginfo)805 netsnmp_handler_registration_dup(netsnmp_handler_registration *reginfo)
806 {
807 netsnmp_handler_registration *r = NULL;
808
809 if (reginfo == NULL)
810 return NULL;
811
812 r = calloc(1, sizeof(netsnmp_handler_registration));
813 if (!r)
814 return r;
815 r->modes = reginfo->modes;
816 r->priority = reginfo->priority;
817 r->range_subid = reginfo->range_subid;
818 r->timeout = reginfo->timeout;
819 r->range_ubound = reginfo->range_ubound;
820 r->rootoid_len = reginfo->rootoid_len;
821
822 if (reginfo->handlerName != NULL) {
823 r->handlerName = strdup(reginfo->handlerName);
824 if (r->handlerName == NULL)
825 goto err;
826 }
827
828 if (reginfo->contextName != NULL) {
829 r->contextName = strdup(reginfo->contextName);
830 if (r->contextName == NULL)
831 goto err;
832 }
833
834 if (reginfo->rootoid != NULL) {
835 /*
836 * + 1 to make the following code safe:
837 * reginfo->rootoid[reginfo->rootoid_len++] = 0;
838 * See also netsnmp_scalar_helper_handler().
839 */
840 r->rootoid = malloc((reginfo->rootoid_len + 1) * sizeof(oid));
841 if (r->rootoid == NULL)
842 goto err;
843 memcpy(r->rootoid, reginfo->rootoid,
844 reginfo->rootoid_len * sizeof(oid));
845 }
846
847 r->handler = netsnmp_handler_dup(reginfo->handler);
848 if (r->handler == NULL)
849 goto err;
850 return r;
851
852 err:
853 netsnmp_handler_registration_free(r);
854 return NULL;
855 }
856
857 /** Creates a cache of information which can be saved for future reference.
858 * The cache is filled with pointers from parameters. Note that
859 * the input structures are not duplicated, but put directly into
860 * the new cache struct.
861 * Use netsnmp_handler_check_cache() later to make sure it's still
862 * valid before referencing it in the future.
863 *
864 * @see netsnmp_handler_check_cache()
865 * @see netsnmp_free_delegated_cache()
866 */
867 NETSNMP_INLINE netsnmp_delegated_cache *
netsnmp_create_delegated_cache(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests,void * localinfo)868 netsnmp_create_delegated_cache(netsnmp_mib_handler *handler,
869 netsnmp_handler_registration *reginfo,
870 netsnmp_agent_request_info *reqinfo,
871 netsnmp_request_info *requests,
872 void *localinfo)
873 {
874 netsnmp_delegated_cache *ret;
875
876 ret = SNMP_MALLOC_TYPEDEF(netsnmp_delegated_cache);
877 if (ret) {
878 ret->transaction_id = reqinfo->asp->pdu->transid;
879 ret->handler = handler;
880 ret->reginfo = reginfo;
881 ret->reqinfo = reqinfo;
882 ret->requests = requests;
883 ret->localinfo = localinfo;
884 }
885 return ret;
886 }
887
888 /** Check if a given delegated cache is still valid.
889 * The cache is valid if it's a part of transaction
890 * (ie, the agent still considers it to be an outstanding request).
891 *
892 * @param dcache is the delegated cache to be checked.
893 *
894 * @return Returns the cache pointer if it is still valid, NULL otherwise.
895 *
896 * @see netsnmp_create_delegated_cache()
897 * @see netsnmp_free_delegated_cache()
898 */
899 NETSNMP_INLINE netsnmp_delegated_cache *
netsnmp_handler_check_cache(netsnmp_delegated_cache * dcache)900 netsnmp_handler_check_cache(netsnmp_delegated_cache *dcache)
901 {
902 if (!dcache)
903 return dcache;
904
905 if (netsnmp_check_transaction_id(dcache->transaction_id) ==
906 SNMPERR_SUCCESS)
907 return dcache;
908
909 return NULL;
910 }
911
912 /** Free a cache once it's no longer used.
913 * Deletes the data allocated by netsnmp_create_delegated_cache().
914 * Structures which were not allocated by netsnmp_create_delegated_cache()
915 * are not freed (pointers are dropped).
916 *
917 * @param dcache is the delegated cache to be freed.
918 *
919 * @see netsnmp_create_delegated_cache()
920 * @see netsnmp_handler_check_cache()
921 */
922 NETSNMP_INLINE void
netsnmp_free_delegated_cache(netsnmp_delegated_cache * dcache)923 netsnmp_free_delegated_cache(netsnmp_delegated_cache *dcache)
924 {
925 /*
926 * right now, no extra data is there that needs to be freed
927 */
928 if (dcache)
929 SNMP_FREE(dcache);
930
931 return;
932 }
933
934
935 #ifndef NETSNMP_FEATURE_REMOVE_HANDLER_MARK_REQUESTS_AS_DELEGATED
936 /** Sets a list of requests as delegated or not delegated.
937 * Sweeps through given chain of requests and sets 'delegated'
938 * flag accordingly to the isdelegaded parameter.
939 *
940 * @param requests Request list.
941 * @param isdelegated New value of the 'delegated' flag.
942 */
943 void
netsnmp_handler_mark_requests_as_delegated(netsnmp_request_info * requests,int isdelegated)944 netsnmp_handler_mark_requests_as_delegated(netsnmp_request_info *requests,
945 int isdelegated)
946 {
947 while (requests) {
948 requests->delegated = isdelegated;
949 requests = requests->next;
950 }
951 }
952 #endif /* NETSNMP_FEATURE_REMOVE_HANDLER_MARK_REQUESTS_AS_DELEGATED */
953
954 /** Adds data from node list to the request information structure.
955 * Data in the request can be later extracted and used by submodules.
956 *
957 * @param request Destination request information structure.
958 *
959 * @param node The data to be added to the linked list
960 * request->parent_data.
961 *
962 * @see netsnmp_request_remove_list_data()
963 * @see netsnmp_request_get_list_data()
964 */
965 NETSNMP_INLINE void
netsnmp_request_add_list_data(netsnmp_request_info * request,netsnmp_data_list * node)966 netsnmp_request_add_list_data(netsnmp_request_info *request,
967 netsnmp_data_list *node)
968 {
969 if (request) {
970 if (request->parent_data)
971 netsnmp_add_list_data(&request->parent_data, node);
972 else
973 request->parent_data = node;
974 }
975 }
976
977 /** Removes all data from a request.
978 *
979 * @param request the netsnmp request info structure
980 *
981 * @param name this is the name of the previously added data
982 *
983 * @return 0 on successful find-and-delete, 1 otherwise.
984 *
985 * @see netsnmp_request_add_list_data()
986 * @see netsnmp_request_get_list_data()
987 */
988 NETSNMP_INLINE int
netsnmp_request_remove_list_data(netsnmp_request_info * request,const char * name)989 netsnmp_request_remove_list_data(netsnmp_request_info *request,
990 const char *name)
991 {
992 if ((NULL == request) || (NULL ==request->parent_data))
993 return 1;
994
995 return netsnmp_remove_list_node(&request->parent_data, name);
996 }
997
998 /** Extracts data from a request.
999 * Retrieves data that was previously added to the request,
1000 * usually by a parent module.
1001 *
1002 * @param request Source request information structure.
1003 *
1004 * @param name Used to compare against the request->parent_data->name value;
1005 * if a match is found, request->parent_data->data is returned.
1006 *
1007 * @return Gives a void pointer(request->parent_data->data); NULL is
1008 * returned if source data is NULL or the object is not found.
1009 *
1010 * @see netsnmp_request_add_list_data()
1011 * @see netsnmp_request_remove_list_data()
1012 */
1013 void *
netsnmp_request_get_list_data(netsnmp_request_info * request,const char * name)1014 netsnmp_request_get_list_data(netsnmp_request_info *request,
1015 const char *name)
1016 {
1017 if (request)
1018 return netsnmp_get_list_data(request->parent_data, name);
1019 return NULL;
1020 }
1021
1022 /** Free the extra data stored in a request.
1023 * Deletes the data in given request only. Other chain items
1024 * are unaffected.
1025 *
1026 * @param request Request information structure to be modified.
1027 *
1028 * @see netsnmp_request_add_list_data()
1029 * @see netsnmp_free_list_data()
1030 */
1031 NETSNMP_INLINE void
netsnmp_free_request_data_set(netsnmp_request_info * request)1032 netsnmp_free_request_data_set(netsnmp_request_info *request)
1033 {
1034 if (request)
1035 netsnmp_free_list_data(request->parent_data);
1036 }
1037
1038 /** Free the extra data stored in a bunch of requests.
1039 * Deletes all data in the chain inside request.
1040 *
1041 * @param request Request information structure to be modified.
1042 *
1043 * @see netsnmp_request_add_list_data()
1044 * @see netsnmp_free_request_data_set()
1045 */
1046 NETSNMP_INLINE void
netsnmp_free_request_data_sets(netsnmp_request_info * request)1047 netsnmp_free_request_data_sets(netsnmp_request_info *request)
1048 {
1049 if (request && request->parent_data) {
1050 netsnmp_free_all_list_data(request->parent_data);
1051 request->parent_data = NULL;
1052 }
1053 }
1054
1055 /** Returns a MIB handler from a chain based on the name.
1056 *
1057 * @param reginfo Handler registration struct which contains the chain.
1058 *
1059 * @param name Target MIB Handler name string. The name is case
1060 * sensitive.
1061 *
1062 * @return The MIB Handler is returned, or NULL if not found.
1063 *
1064 * @see netsnmp_request_add_list_data()
1065 */
1066 netsnmp_mib_handler *
netsnmp_find_handler_by_name(netsnmp_handler_registration * reginfo,const char * name)1067 netsnmp_find_handler_by_name(netsnmp_handler_registration *reginfo,
1068 const char *name)
1069 {
1070 netsnmp_mib_handler *it;
1071 if (reginfo == NULL || name == NULL )
1072 return NULL;
1073 for (it = reginfo->handler; it; it = it->next) {
1074 if (strcmp(it->handler_name, name) == 0) {
1075 return it;
1076 }
1077 }
1078 return NULL;
1079 }
1080
1081 /** Returns a handler's void pointer from a chain based on the name.
1082 *
1083 * @warning The void pointer data may change as a handler evolves.
1084 * Handlers should really advertise some function for you
1085 * to use instead.
1086 *
1087 * @param reginfo Handler registration struct which contains the chain.
1088 *
1089 * @param name Target MIB Handler name string. The name is case
1090 * sensitive.
1091 *
1092 * @return The MIB Handler's void * pointer is returned,
1093 * or NULL if the handler is not found.
1094 *
1095 * @see netsnmp_find_handler_by_name()
1096 */
1097 void *
netsnmp_find_handler_data_by_name(netsnmp_handler_registration * reginfo,const char * name)1098 netsnmp_find_handler_data_by_name(netsnmp_handler_registration *reginfo,
1099 const char *name)
1100 {
1101 netsnmp_mib_handler *it = netsnmp_find_handler_by_name(reginfo, name);
1102 if (it)
1103 return it->myvoid;
1104 return NULL;
1105 }
1106
1107 /** @private
1108 * Clones a MIB Handler with its basic properties.
1109 * Creates a copy of the given MIB Handler. Copies name, flags and
1110 * access methods only; not myvoid.
1111 *
1112 * @see netsnmp_handler_dup()
1113 */
1114 static netsnmp_mib_handler *
_clone_handler(netsnmp_mib_handler * it)1115 _clone_handler(netsnmp_mib_handler *it)
1116 {
1117 netsnmp_mib_handler *dup;
1118
1119 if(NULL == it)
1120 return NULL;
1121
1122 dup = netsnmp_create_handler(it->handler_name, it->access_method);
1123 if(NULL != dup)
1124 dup->flags = it->flags;
1125
1126 return dup;
1127 }
1128
1129 static netsnmp_data_list *handler_reg = NULL;
1130
1131 void
handler_free_callback(void * handler)1132 handler_free_callback(void *handler)
1133 {
1134 netsnmp_handler_free((netsnmp_mib_handler *)handler);
1135 }
1136
1137 /** Registers a given handler by name, so that it can be found easily later.
1138 * Pointer to the handler is put into a list where it can be easily located
1139 * at any time.
1140 *
1141 * @param name Name string to be associated with the handler.
1142 *
1143 * @param handler Pointer the MIB Handler.
1144 *
1145 * @see netsnmp_clear_handler_list()
1146 */
1147 void
netsnmp_register_handler_by_name(const char * name,netsnmp_mib_handler * handler)1148 netsnmp_register_handler_by_name(const char *name,
1149 netsnmp_mib_handler *handler)
1150 {
1151 netsnmp_add_list_data(&handler_reg,
1152 netsnmp_create_data_list(name, (void *) handler,
1153 handler_free_callback));
1154 DEBUGMSGTL(("handler_registry", "registering helper %s\n", name));
1155 }
1156
1157 /** Clears the entire MIB Handlers registration list.
1158 * MIB Handlers registration list is used to access any MIB Handler by
1159 * its name. The function frees the list memory and sets pointer to NULL.
1160 * Instead of calling this function directly, use shutdown_agent().
1161 *
1162 * @see shutdown_agent()
1163 * @see netsnmp_register_handler_by_name()
1164 */
1165 void
netsnmp_clear_handler_list(void)1166 netsnmp_clear_handler_list(void)
1167 {
1168 DEBUGMSGTL(("agent_handler", "netsnmp_clear_handler_list() called\n"));
1169 netsnmp_free_all_list_data(handler_reg);
1170 handler_reg = NULL;
1171 }
1172
1173 /** @private
1174 * Injects a handler into a subtree, peers and children when a given
1175 * subtrees name matches a passed in name.
1176 */
1177 void
netsnmp_inject_handler_into_subtree(netsnmp_subtree * tp,const char * name,netsnmp_mib_handler * handler,const char * before_what)1178 netsnmp_inject_handler_into_subtree(netsnmp_subtree *tp, const char *name,
1179 netsnmp_mib_handler *handler,
1180 const char *before_what)
1181 {
1182 netsnmp_subtree *tptr;
1183 netsnmp_mib_handler *mh;
1184
1185 for (tptr = tp; tptr != NULL; tptr = tptr->next) {
1186 /* if (tptr->children) {
1187 netsnmp_inject_handler_into_subtree(tptr->children,name,handler);
1188 } */
1189 if (strcmp(tptr->label_a, name) == 0) {
1190 DEBUGMSGTL(("injectHandler", "injecting handler %s into %s\n",
1191 handler->handler_name, tptr->label_a));
1192 netsnmp_inject_handler_before(tptr->reginfo, _clone_handler(handler),
1193 before_what);
1194 } else if (tptr->reginfo != NULL &&
1195 tptr->reginfo->handlerName != NULL &&
1196 strcmp(tptr->reginfo->handlerName, name) == 0) {
1197 DEBUGMSGTL(("injectHandler", "injecting handler into %s/%s\n",
1198 tptr->label_a, tptr->reginfo->handlerName));
1199 netsnmp_inject_handler_before(tptr->reginfo, _clone_handler(handler),
1200 before_what);
1201 } else if (tptr->reginfo != NULL) {
1202 for (mh = tptr->reginfo->handler; mh != NULL; mh = mh->next) {
1203 if (mh->handler_name && strcmp(mh->handler_name, name) == 0) {
1204 DEBUGMSGTL(("injectHandler", "injecting handler into %s\n",
1205 tptr->label_a));
1206 netsnmp_inject_handler_before(tptr->reginfo,
1207 _clone_handler(handler),
1208 before_what);
1209 break;
1210 } else {
1211 DEBUGMSGTL(("injectHandler",
1212 "not injecting handler into %s\n",
1213 mh->handler_name));
1214 }
1215 }
1216 }
1217 }
1218 }
1219
1220 static int doneit = 0;
1221 /** @private
1222 * Parses the "injectHandler" token line.
1223 */
1224 void
parse_injectHandler_conf(const char * token,char * cptr)1225 parse_injectHandler_conf(const char *token, char *cptr)
1226 {
1227 char handler_to_insert[256], reg_name[256];
1228 subtree_context_cache *stc;
1229 netsnmp_mib_handler *handler;
1230
1231 /*
1232 * XXXWWW: ensure instead that handler isn't inserted twice
1233 */
1234 if (doneit) /* we only do this once without restart the agent */
1235 return;
1236
1237 cptr = copy_nword(cptr, handler_to_insert, sizeof(handler_to_insert));
1238 handler = (netsnmp_mib_handler*)netsnmp_get_list_data(handler_reg, handler_to_insert);
1239 if (!handler) {
1240 netsnmp_config_error("no \"%s\" handler registered.",
1241 handler_to_insert);
1242 return;
1243 }
1244
1245 if (!cptr) {
1246 config_perror("no INTONAME specified. Can't do insertion.");
1247 return;
1248 }
1249 cptr = copy_nword(cptr, reg_name, sizeof(reg_name));
1250
1251 for (stc = get_top_context_cache(); stc; stc = stc->next) {
1252 DEBUGMSGTL(("injectHandler", "Checking context tree %s (before=%s)\n",
1253 stc->context_name, (cptr)?cptr:"null"));
1254 netsnmp_inject_handler_into_subtree(stc->first_subtree, reg_name,
1255 handler, cptr);
1256 }
1257 }
1258
1259 /** @private
1260 * Callback to ensure injectHandler parser doesn't do things twice.
1261 * @todo replace this with a method to check the handler chain instead.
1262 */
1263 static int
handler_mark_inject_handler_done(int majorID,int minorID,void * serverarg,void * clientarg)1264 handler_mark_inject_handler_done(int majorID, int minorID,
1265 void *serverarg, void *clientarg)
1266 {
1267 doneit = 1;
1268 return 0;
1269 }
1270
1271 /** @private
1272 * Registers the injectHandle parser token.
1273 * Used in init_agent_read_config().
1274 *
1275 * @see init_agent_read_config()
1276 */
1277 void
netsnmp_init_handler_conf(void)1278 netsnmp_init_handler_conf(void)
1279 {
1280 snmpd_register_config_handler("injectHandler",
1281 parse_injectHandler_conf,
1282 NULL, "injectHandler NAME INTONAME [BEFORE_OTHER_NAME]");
1283 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1284 SNMP_CALLBACK_POST_READ_CONFIG,
1285 handler_mark_inject_handler_done, NULL);
1286
1287 se_add_pair_to_slist("agent_mode", strdup("GET"), MODE_GET);
1288 se_add_pair_to_slist("agent_mode", strdup("GETNEXT"), MODE_GETNEXT);
1289 se_add_pair_to_slist("agent_mode", strdup("GETBULK"), MODE_GETBULK);
1290 #ifndef NETSNMP_NO_WRITE_SUPPORT
1291 se_add_pair_to_slist("agent_mode", strdup("SET_BEGIN"),
1292 MODE_SET_BEGIN);
1293 se_add_pair_to_slist("agent_mode", strdup("SET_RESERVE1"),
1294 MODE_SET_RESERVE1);
1295 se_add_pair_to_slist("agent_mode", strdup("SET_RESERVE2"),
1296 MODE_SET_RESERVE2);
1297 se_add_pair_to_slist("agent_mode", strdup("SET_ACTION"),
1298 MODE_SET_ACTION);
1299 se_add_pair_to_slist("agent_mode", strdup("SET_COMMIT"),
1300 MODE_SET_COMMIT);
1301 se_add_pair_to_slist("agent_mode", strdup("SET_FREE"), MODE_SET_FREE);
1302 se_add_pair_to_slist("agent_mode", strdup("SET_UNDO"), MODE_SET_UNDO);
1303
1304 se_add_pair_to_slist("babystep_mode", strdup("pre-request"),
1305 MODE_BSTEP_PRE_REQUEST);
1306 se_add_pair_to_slist("babystep_mode", strdup("object_lookup"),
1307 MODE_BSTEP_OBJECT_LOOKUP);
1308 se_add_pair_to_slist("babystep_mode", strdup("check_value"),
1309 MODE_BSTEP_CHECK_VALUE);
1310 se_add_pair_to_slist("babystep_mode", strdup("row_create"),
1311 MODE_BSTEP_ROW_CREATE);
1312 se_add_pair_to_slist("babystep_mode", strdup("undo_setup"),
1313 MODE_BSTEP_UNDO_SETUP);
1314 se_add_pair_to_slist("babystep_mode", strdup("set_value"),
1315 MODE_BSTEP_SET_VALUE);
1316 se_add_pair_to_slist("babystep_mode", strdup("check_consistency"),
1317 MODE_BSTEP_CHECK_CONSISTENCY);
1318 se_add_pair_to_slist("babystep_mode", strdup("undo_set"),
1319 MODE_BSTEP_UNDO_SET);
1320 se_add_pair_to_slist("babystep_mode", strdup("commit"),
1321 MODE_BSTEP_COMMIT);
1322 se_add_pair_to_slist("babystep_mode", strdup("undo_commit"),
1323 MODE_BSTEP_UNDO_COMMIT);
1324 se_add_pair_to_slist("babystep_mode", strdup("irreversible_commit"),
1325 MODE_BSTEP_IRREVERSIBLE_COMMIT);
1326 se_add_pair_to_slist("babystep_mode", strdup("undo_cleanup"),
1327 MODE_BSTEP_UNDO_CLEANUP);
1328 se_add_pair_to_slist("babystep_mode", strdup("post_request"),
1329 MODE_BSTEP_POST_REQUEST);
1330 se_add_pair_to_slist("babystep_mode", strdup("original"), 0xffff);
1331 #endif /* NETSNMP_NO_WRITE_SUPPORT */
1332
1333 /*
1334 * xxx-rks: hmmm.. will this work for modes which are or'd together?
1335 * I'm betting not...
1336 */
1337 se_add_pair_to_slist("handler_can_mode", strdup("GET/GETNEXT"),
1338 HANDLER_CAN_GETANDGETNEXT);
1339 se_add_pair_to_slist("handler_can_mode", strdup("SET"),
1340 HANDLER_CAN_SET);
1341 se_add_pair_to_slist("handler_can_mode", strdup("GETBULK"),
1342 HANDLER_CAN_GETBULK);
1343 se_add_pair_to_slist("handler_can_mode", strdup("BABY_STEP"),
1344 HANDLER_CAN_BABY_STEP);
1345 }
1346
1347 /** @} */
1348