net-snmp 5.7
agent_handler.c
00001 /* Portions of this file are subject to the following copyright(s).  See
00002  * the Net-SNMP's COPYING file for more details and other copyrights
00003  * that may apply:
00004  */
00005 /*
00006  * Portions of this file are copyrighted by:
00007  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00008  * Use is subject to license terms specified in the COPYING file
00009  * distributed with the Net-SNMP package.
00010  */
00011 #include <net-snmp/net-snmp-config.h>
00012 #include <net-snmp/net-snmp-features.h>
00013 
00014 #include <sys/types.h>
00015 
00016 #if HAVE_STRING_H
00017 #include <string.h>
00018 #endif
00019 
00020 #include <net-snmp/net-snmp-includes.h>
00021 #include <net-snmp/agent/net-snmp-agent-includes.h>
00022 
00023 #include <net-snmp/agent/bulk_to_next.h>
00024 
00025 netsnmp_feature_child_of(agent_handler, libnetsnmpagent)
00026 
00027 netsnmp_feature_child_of(handler_mark_requests_as_delegated, agent_handler)
00028 
00029 static netsnmp_mib_handler *_clone_handler(netsnmp_mib_handler *it);
00030 
00031 /***********************************************************************/
00032 /*
00033  * New Handler based API 
00034  */
00035 /***********************************************************************/
00110 netsnmp_mib_handler *
00111 netsnmp_create_handler(const char *name,
00112                        Netsnmp_Node_Handler * handler_access_method)
00113 {
00114     netsnmp_mib_handler *ret = SNMP_MALLOC_TYPEDEF(netsnmp_mib_handler);
00115     if (ret) {
00116         ret->access_method = handler_access_method;
00117         if (NULL != name) {
00118             ret->handler_name = strdup(name);
00119             if (NULL == ret->handler_name)
00120                 SNMP_FREE(ret);
00121         }
00122     }
00123     return ret;
00124 }
00125 
00169 netsnmp_handler_registration *
00170 netsnmp_handler_registration_create(const char *name,
00171                                     netsnmp_mib_handler *handler,
00172                                     const oid * reg_oid, size_t reg_oid_len,
00173                                     int modes)
00174 {
00175     netsnmp_handler_registration *the_reg;
00176     the_reg = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration);
00177     if (!the_reg)
00178         return NULL;
00179 
00180     if (modes)
00181         the_reg->modes = modes;
00182     else
00183         the_reg->modes = HANDLER_CAN_DEFAULT;
00184 
00185     the_reg->handler = handler;
00186     the_reg->priority = DEFAULT_MIB_PRIORITY;
00187     if (name)
00188         the_reg->handlerName = strdup(name);
00189     the_reg->rootoid = snmp_duplicate_objid(reg_oid, reg_oid_len);
00190     the_reg->rootoid_len = reg_oid_len;
00191     return the_reg;
00192 }
00193 
00218 netsnmp_handler_registration *
00219 netsnmp_create_handler_registration(const char *name,
00220                                     Netsnmp_Node_Handler *
00221                                     handler_access_method, const oid * reg_oid,
00222                                     size_t reg_oid_len, int modes)
00223 {
00224     netsnmp_handler_registration *rv = NULL;
00225     netsnmp_mib_handler *handler =
00226         netsnmp_create_handler(name, handler_access_method);
00227     if (handler) {
00228         rv = netsnmp_handler_registration_create(
00229             name, handler, reg_oid, reg_oid_len, modes);
00230         if (!rv)
00231             netsnmp_handler_free(handler);
00232     }
00233     return rv;
00234 }
00235 
00251 int
00252 netsnmp_register_handler(netsnmp_handler_registration *reginfo)
00253 {
00254     netsnmp_mib_handler *handler;
00255     int flags = 0;
00256 
00257     if (reginfo == NULL) {
00258         snmp_log(LOG_ERR, "netsnmp_register_handler() called illegally\n");
00259         netsnmp_assert(reginfo != NULL);
00260         return SNMP_ERR_GENERR;
00261     }
00262 
00263     DEBUGIF("handler::register") {
00264         DEBUGMSGTL(("handler::register", "Registering %s (", reginfo->handlerName));
00265         for (handler = reginfo->handler; handler; handler = handler->next) {
00266             DEBUGMSG(("handler::register", "::%s", handler->handler_name));
00267         }
00268 
00269         DEBUGMSG(("handler::register", ") at "));
00270         if (reginfo->rootoid && reginfo->range_subid) {
00271             DEBUGMSGOIDRANGE(("handler::register", reginfo->rootoid,
00272                               reginfo->rootoid_len, reginfo->range_subid,
00273                               reginfo->range_ubound));
00274         } else if (reginfo->rootoid) {
00275             DEBUGMSGOID(("handler::register", reginfo->rootoid,
00276                          reginfo->rootoid_len));
00277         } else {
00278             DEBUGMSG(("handler::register", "[null]"));
00279         }
00280         DEBUGMSG(("handler::register", "\n"));
00281     }
00282 
00283     /*
00284      * don't let them register for absolutely nothing.  Probably a mistake 
00285      */
00286     if (0 == reginfo->modes) {
00287         reginfo->modes = HANDLER_CAN_DEFAULT;
00288         snmp_log(LOG_WARNING, "no registration modes specified for %s. "
00289                  "Defaulting to 0x%x\n", reginfo->handlerName, reginfo->modes);
00290     }
00291 
00292     /*
00293      * for handlers that can't GETBULK, force a conversion handler on them 
00294      */
00295     if (!(reginfo->modes & HANDLER_CAN_GETBULK)) {
00296         netsnmp_inject_handler(reginfo,
00297                                netsnmp_get_bulk_to_next_handler());
00298     }
00299 
00300     for (handler = reginfo->handler; handler; handler = handler->next) {
00301         if (handler->flags & MIB_HANDLER_INSTANCE)
00302             flags = FULLY_QUALIFIED_INSTANCE;
00303     }
00304 
00305     return netsnmp_register_mib(reginfo->handlerName,
00306                                 NULL, 0, 0,
00307                                 reginfo->rootoid, reginfo->rootoid_len,
00308                                 reginfo->priority,
00309                                 reginfo->range_subid,
00310                                 reginfo->range_ubound, NULL,
00311                                 reginfo->contextName, reginfo->timeout, flags,
00312                                 reginfo, 1);
00313 }
00314 
00327 int
00328 netsnmp_unregister_handler(netsnmp_handler_registration *reginfo)
00329 {
00330     return unregister_mib_context(reginfo->rootoid, reginfo->rootoid_len,
00331                                   reginfo->priority,
00332                                   reginfo->range_subid, reginfo->range_ubound,
00333                                   reginfo->contextName);
00334 }
00335 
00351 int
00352 netsnmp_register_handler_nocallback(netsnmp_handler_registration *reginfo)
00353 {
00354     netsnmp_mib_handler *handler;
00355     if (reginfo == NULL) {
00356         snmp_log(LOG_ERR, "netsnmp_register_handler_nocallback() called illegally\n");
00357         netsnmp_assert(reginfo != NULL);
00358         return SNMP_ERR_GENERR;
00359     }
00360     DEBUGIF("handler::register") {
00361         DEBUGMSGTL(("handler::register",
00362                     "Registering (with no callback) "));
00363         for (handler = reginfo->handler; handler; handler = handler->next) {
00364             DEBUGMSG(("handler::register", "::%s", handler->handler_name));
00365         }
00366 
00367         DEBUGMSG(("handler::register", " at "));
00368         if (reginfo->rootoid && reginfo->range_subid) {
00369             DEBUGMSGOIDRANGE(("handler::register", reginfo->rootoid,
00370                               reginfo->rootoid_len, reginfo->range_subid,
00371                               reginfo->range_ubound));
00372         } else if (reginfo->rootoid) {
00373             DEBUGMSGOID(("handler::register", reginfo->rootoid,
00374                          reginfo->rootoid_len));
00375         } else {
00376             DEBUGMSG(("handler::register", "[null]"));
00377         }
00378         DEBUGMSG(("handler::register", "\n"));
00379     }
00380 
00381     /*
00382      * don't let them register for absolutely nothing.  Probably a mistake 
00383      */
00384     if (0 == reginfo->modes) {
00385         reginfo->modes = HANDLER_CAN_DEFAULT;
00386     }
00387 
00388     return netsnmp_register_mib(reginfo->handler->handler_name,
00389                                 NULL, 0, 0,
00390                                 reginfo->rootoid, reginfo->rootoid_len,
00391                                 reginfo->priority,
00392                                 reginfo->range_subid,
00393                                 reginfo->range_ubound, NULL,
00394                                 reginfo->contextName, reginfo->timeout, 0,
00395                                 reginfo, 0);
00396 }
00397 
00408 int
00409 netsnmp_inject_handler_before(netsnmp_handler_registration *reginfo,
00410                               netsnmp_mib_handler *handler,
00411                               const char *before_what)
00412 {
00413     netsnmp_mib_handler *handler2 = handler;
00414 
00415     if (handler == NULL || reginfo == NULL) {
00416         snmp_log(LOG_ERR, "netsnmp_inject_handler() called illegally\n");
00417         netsnmp_assert(reginfo != NULL);
00418         netsnmp_assert(handler != NULL);
00419         return SNMP_ERR_GENERR;
00420     }
00421     while (handler2->next) {
00422         handler2 = handler2->next;  /* Find the end of a handler sub-chain */
00423     }
00424     if (reginfo->handler == NULL) {
00425         DEBUGMSGTL(("handler:inject", "injecting %s\n", handler->handler_name));
00426     }
00427     else {
00428         DEBUGMSGTL(("handler:inject", "injecting %s before %s\n",
00429                     handler->handler_name, reginfo->handler->handler_name));
00430     }
00431     if (before_what) {
00432         netsnmp_mib_handler *nexth, *prevh = NULL;
00433         if (reginfo->handler == NULL) {
00434             snmp_log(LOG_ERR, "no handler to inject before\n");
00435             return SNMP_ERR_GENERR;
00436         }
00437         for(nexth = reginfo->handler; nexth;
00438             prevh = nexth, nexth = nexth->next) {
00439             if (strcmp(nexth->handler_name, before_what) == 0)
00440                 break;
00441         }
00442         if (!nexth)
00443             return SNMP_ERR_GENERR;
00444         if (prevh) {
00445             /* after prevh and before nexth */
00446             prevh->next = handler;
00447             handler2->next = nexth;
00448             handler->prev = prevh;
00449             nexth->prev = handler2;
00450             return SNMPERR_SUCCESS;
00451         }
00452         /* else we're first, which is what we do next anyway so fall through */
00453     }
00454     handler2->next = reginfo->handler;
00455     if (reginfo->handler)
00456         reginfo->handler->prev = handler2;
00457     reginfo->handler = handler;
00458     return SNMPERR_SUCCESS;
00459 }
00460 
00470 int
00471 netsnmp_inject_handler(netsnmp_handler_registration *reginfo,
00472                        netsnmp_mib_handler *handler)
00473 {
00474     return netsnmp_inject_handler_before(reginfo, handler, NULL);
00475 }
00476 
00484 NETSNMP_INLINE int
00485 netsnmp_call_handler(netsnmp_mib_handler *next_handler,
00486                      netsnmp_handler_registration *reginfo,
00487                      netsnmp_agent_request_info *reqinfo,
00488                      netsnmp_request_info *requests)
00489 {
00490     Netsnmp_Node_Handler *nh;
00491     int             ret;
00492 
00493     if (next_handler == NULL || reginfo == NULL || reqinfo == NULL ||
00494         requests == NULL) {
00495         snmp_log(LOG_ERR, "netsnmp_call_handler() called illegally\n");
00496         netsnmp_assert(next_handler != NULL);
00497         netsnmp_assert(reqinfo != NULL);
00498         netsnmp_assert(reginfo != NULL);
00499         netsnmp_assert(requests != NULL);
00500         return SNMP_ERR_GENERR;
00501     }
00502 
00503     do {
00504         nh = next_handler->access_method;
00505         if (!nh) {
00506             if (next_handler->next) {
00507                 snmp_log(LOG_ERR, "no access method specified in handler %s.",
00508                          next_handler->handler_name);
00509                 return SNMP_ERR_GENERR;
00510             }
00511             /*
00512              * The final handler registration in the chain may well not need
00513              * to include a handler routine, if the processing of this object
00514              * is handled completely by the agent toolkit helpers.
00515              */
00516             return SNMP_ERR_NOERROR;
00517         }
00518 
00519         DEBUGMSGTL(("handler:calling", "calling handler %s for mode %s\n",
00520                     next_handler->handler_name,
00521                     se_find_label_in_slist("agent_mode", reqinfo->mode)));
00522 
00523         /*
00524          * XXX: define acceptable return statuses
00525          */
00526         ret = (*nh) (next_handler, reginfo, reqinfo, requests);
00527 
00528         DEBUGMSGTL(("handler:returned", "handler %s returned %d\n",
00529                     next_handler->handler_name, ret));
00530 
00531         if (! (next_handler->flags & MIB_HANDLER_AUTO_NEXT))
00532             break;
00533 
00534         /*
00535          * did handler signal that it didn't want auto next this time around?
00536          */
00537         if(next_handler->flags & MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE) {
00538             next_handler->flags &= ~MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
00539             break;
00540         }
00541 
00542         next_handler = next_handler->next;
00543 
00544     } while(next_handler);
00545 
00546     return ret;
00547 }
00548 
00554 int
00555 netsnmp_call_handlers(netsnmp_handler_registration *reginfo,
00556                       netsnmp_agent_request_info *reqinfo,
00557                       netsnmp_request_info *requests)
00558 {
00559     netsnmp_request_info *request;
00560     int             status;
00561 
00562     if (reginfo == NULL || reqinfo == NULL || requests == NULL) {
00563         snmp_log(LOG_ERR, "netsnmp_call_handlers() called illegally\n");
00564         netsnmp_assert(reqinfo != NULL);
00565         netsnmp_assert(reginfo != NULL);
00566         netsnmp_assert(requests != NULL);
00567         return SNMP_ERR_GENERR;
00568     }
00569 
00570     if (reginfo->handler == NULL) {
00571         snmp_log(LOG_ERR, "no handler specified.");
00572         return SNMP_ERR_GENERR;
00573     }
00574 
00575     switch (reqinfo->mode) {
00576     case MODE_GETBULK:
00577     case MODE_GET:
00578     case MODE_GETNEXT:
00579         if (!(reginfo->modes & HANDLER_CAN_GETANDGETNEXT))
00580             return SNMP_ERR_NOERROR;    /* legal */
00581         break;
00582 
00583 #ifndef NETSNMP_NO_WRITE_SUPPORT
00584     case MODE_SET_RESERVE1:
00585     case MODE_SET_RESERVE2:
00586     case MODE_SET_ACTION:
00587     case MODE_SET_COMMIT:
00588     case MODE_SET_FREE:
00589     case MODE_SET_UNDO:
00590         if (!(reginfo->modes & HANDLER_CAN_SET)) {
00591             for (; requests; requests = requests->next) {
00592                 netsnmp_set_request_error(reqinfo, requests,
00593                                           SNMP_ERR_NOTWRITABLE);
00594             }
00595             return SNMP_ERR_NOERROR;
00596         }
00597         break;
00598 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00599 
00600     default:
00601         snmp_log(LOG_ERR, "unknown mode in netsnmp_call_handlers! bug!\n");
00602         return SNMP_ERR_GENERR;
00603     }
00604     DEBUGMSGTL(("handler:calling", "main handler %s\n",
00605                 reginfo->handler->handler_name));
00606 
00607     for (request = requests ; request; request = request->next) {
00608         request->processed = 0;
00609     }
00610 
00611     status = netsnmp_call_handler(reginfo->handler, reginfo, reqinfo, requests);
00612 
00613     return status;
00614 }
00615 
00623 NETSNMP_INLINE int
00624 netsnmp_call_next_handler(netsnmp_mib_handler *current,
00625                           netsnmp_handler_registration *reginfo,
00626                           netsnmp_agent_request_info *reqinfo,
00627                           netsnmp_request_info *requests)
00628 {
00629 
00630     if (current == NULL || reginfo == NULL || reqinfo == NULL ||
00631         requests == NULL) {
00632         snmp_log(LOG_ERR, "netsnmp_call_next_handler() called illegally\n");
00633         netsnmp_assert(current != NULL);
00634         netsnmp_assert(reginfo != NULL);
00635         netsnmp_assert(reqinfo != NULL);
00636         netsnmp_assert(requests != NULL);
00637         return SNMP_ERR_GENERR;
00638     }
00639 
00640     return netsnmp_call_handler(current->next, reginfo, reqinfo, requests);
00641 }
00642 
00650 netsnmp_feature_child_of(netsnmp_call_next_handler_one_request,netsnmp_unused)
00651 #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_CALL_NEXT_HANDLER_ONE_REQUEST
00652 NETSNMP_INLINE int
00653 netsnmp_call_next_handler_one_request(netsnmp_mib_handler *current,
00654                                       netsnmp_handler_registration *reginfo,
00655                                       netsnmp_agent_request_info *reqinfo,
00656                                       netsnmp_request_info *requests)
00657 {
00658     netsnmp_request_info *request;
00659     int ret;
00660     
00661     if (!requests) {
00662         snmp_log(LOG_ERR, "netsnmp_call_next_handler_ONE_REQUEST() called illegally\n");
00663         netsnmp_assert(requests != NULL);
00664         return SNMP_ERR_GENERR;
00665     }
00666 
00667     request = requests->next;
00668     requests->next = NULL;
00669     ret = netsnmp_call_handler(current->next, reginfo, reqinfo, requests);
00670     requests->next = request;
00671     return ret;
00672 }
00673 #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_CALL_NEXT_HANDLER_ONE_REQUEST */
00674 
00682 void
00683 netsnmp_handler_free(netsnmp_mib_handler *handler)
00684 {
00685     if (handler != NULL) {
00686         if (handler->next != NULL) {
00688             netsnmp_assert(handler != handler->next); /* bugs caught: 1 */
00689             netsnmp_handler_free(handler->next);
00690             handler->next = NULL;
00691         }
00692         if ((handler->myvoid != NULL) && (handler->data_free != NULL))
00693         {
00694             handler->data_free(handler->myvoid);
00695         }
00696         SNMP_FREE(handler->handler_name);
00697         SNMP_FREE(handler);
00698     }
00699 }
00700 
00711 netsnmp_mib_handler *
00712 netsnmp_handler_dup(netsnmp_mib_handler *handler)
00713 {
00714     netsnmp_mib_handler *h = NULL;
00715 
00716     if (!handler)
00717         goto err;
00718 
00719     h = _clone_handler(handler);
00720     if (!h)
00721         goto err;
00722 
00723     /*
00724      * Providing a clone function without a free function is asking for
00725      * memory leaks, and providing a free function without clone function
00726      * is asking for memory corruption. Hence the log statement below.
00727      */
00728     if (!!handler->data_clone != !!handler->data_free)
00729         snmp_log(LOG_ERR, "data_clone / data_free inconsistent (%s)\n",
00730                  handler->handler_name);
00731     if (handler->myvoid && handler->data_clone) {
00732         h->myvoid = handler->data_clone(handler->myvoid);
00733         if (!h->myvoid)
00734             goto err;
00735     } else
00736         h->myvoid = handler->myvoid;
00737     h->data_clone = handler->data_clone;
00738     h->data_free = handler->data_free;
00739 
00740     if (handler->next != NULL) {
00741         h->next = netsnmp_handler_dup(handler->next);
00742         if (!h->next)
00743             goto err;
00744         h->next->prev = h;
00745     }
00746     h->prev = NULL;
00747     return h;
00748 
00749 err:
00750     netsnmp_handler_free(h);
00751     return NULL;
00752 }
00753 
00761 void
00762 netsnmp_handler_registration_free(netsnmp_handler_registration *reginfo)
00763 {
00764     if (reginfo != NULL) {
00765         netsnmp_handler_free(reginfo->handler);
00766         SNMP_FREE(reginfo->handlerName);
00767         SNMP_FREE(reginfo->contextName);
00768         SNMP_FREE(reginfo->rootoid);
00769         reginfo->rootoid_len = 0;
00770         SNMP_FREE(reginfo);
00771     }
00772 }
00773 
00784 netsnmp_handler_registration *
00785 netsnmp_handler_registration_dup(netsnmp_handler_registration *reginfo)
00786 {
00787     netsnmp_handler_registration *r = NULL;
00788 
00789     if (reginfo == NULL) {
00790         return NULL;
00791     }
00792 
00793 
00794     r = (netsnmp_handler_registration *) calloc(1,
00795                                                 sizeof
00796                                                 (netsnmp_handler_registration));
00797 
00798     if (r != NULL) {
00799         r->modes = reginfo->modes;
00800         r->priority = reginfo->priority;
00801         r->range_subid = reginfo->range_subid;
00802         r->timeout = reginfo->timeout;
00803         r->range_ubound = reginfo->range_ubound;
00804         r->rootoid_len = reginfo->rootoid_len;
00805 
00806         if (reginfo->handlerName != NULL) {
00807             r->handlerName = strdup(reginfo->handlerName);
00808             if (r->handlerName == NULL) {
00809                 netsnmp_handler_registration_free(r);
00810                 return NULL;
00811             }
00812         }
00813 
00814         if (reginfo->contextName != NULL) {
00815             r->contextName = strdup(reginfo->contextName);
00816             if (r->contextName == NULL) {
00817                 netsnmp_handler_registration_free(r);
00818                 return NULL;
00819             }
00820         }
00821 
00822         if (reginfo->rootoid != NULL) {
00823             r->rootoid =
00824                 snmp_duplicate_objid(reginfo->rootoid, reginfo->rootoid_len);
00825             if (r->rootoid == NULL) {
00826                 netsnmp_handler_registration_free(r);
00827                 return NULL;
00828             }
00829         }
00830 
00831         r->handler = netsnmp_handler_dup(reginfo->handler);
00832         if (r->handler == NULL) {
00833             netsnmp_handler_registration_free(r);
00834             return NULL;
00835         }
00836         return r;
00837     }
00838 
00839     return NULL;
00840 }
00841 
00852 NETSNMP_INLINE netsnmp_delegated_cache *
00853 netsnmp_create_delegated_cache(netsnmp_mib_handler *handler,
00854                                netsnmp_handler_registration *reginfo,
00855                                netsnmp_agent_request_info *reqinfo,
00856                                netsnmp_request_info *requests,
00857                                void *localinfo)
00858 {
00859     netsnmp_delegated_cache *ret;
00860 
00861     ret = SNMP_MALLOC_TYPEDEF(netsnmp_delegated_cache);
00862     if (ret) {
00863         ret->transaction_id = reqinfo->asp->pdu->transid;
00864         ret->handler = handler;
00865         ret->reginfo = reginfo;
00866         ret->reqinfo = reqinfo;
00867         ret->requests = requests;
00868         ret->localinfo = localinfo;
00869     }
00870     return ret;
00871 }
00872 
00884 NETSNMP_INLINE netsnmp_delegated_cache *
00885 netsnmp_handler_check_cache(netsnmp_delegated_cache *dcache)
00886 {
00887     if (!dcache)
00888         return dcache;
00889 
00890     if (netsnmp_check_transaction_id(dcache->transaction_id) ==
00891         SNMPERR_SUCCESS)
00892         return dcache;
00893 
00894     return NULL;
00895 }
00896 
00907 NETSNMP_INLINE void
00908 netsnmp_free_delegated_cache(netsnmp_delegated_cache *dcache)
00909 {
00910     /*
00911      * right now, no extra data is there that needs to be freed 
00912      */
00913     if (dcache)
00914         SNMP_FREE(dcache);
00915 
00916     return;
00917 }
00918 
00919 
00920 #ifndef NETSNMP_FEATURE_REMOVE_HANDLER_MARK_REQUESTS_AS_DELEGATED
00921 
00927 void
00928 netsnmp_handler_mark_requests_as_delegated(netsnmp_request_info *requests,
00929                                            int isdelegated)
00930 {
00931     while (requests) {
00932         requests->delegated = isdelegated;
00933         requests = requests->next;
00934     }
00935 }
00936 #endif /* NETSNMP_FEATURE_REMOVE_HANDLER_MARK_REQUESTS_AS_DELEGATED */
00937 
00949 NETSNMP_INLINE void
00950 netsnmp_request_add_list_data(netsnmp_request_info *request,
00951                               netsnmp_data_list *node)
00952 {
00953     if (request) {
00954         if (request->parent_data)
00955             netsnmp_add_list_data(&request->parent_data, node);
00956         else
00957             request->parent_data = node;
00958     }
00959 }
00960 
00972 NETSNMP_INLINE int
00973 netsnmp_request_remove_list_data(netsnmp_request_info *request,
00974                                  const char *name)
00975 {
00976     if ((NULL == request) || (NULL ==request->parent_data))
00977         return 1;
00978 
00979     return netsnmp_remove_list_node(&request->parent_data, name);
00980 }
00981 
00997 void    *
00998 netsnmp_request_get_list_data(netsnmp_request_info *request,
00999                               const char *name)
01000 {
01001     if (request)
01002         return netsnmp_get_list_data(request->parent_data, name);
01003     return NULL;
01004 }
01005 
01015 NETSNMP_INLINE void
01016 netsnmp_free_request_data_set(netsnmp_request_info *request)
01017 {
01018     if (request)
01019         netsnmp_free_list_data(request->parent_data);
01020 }
01021 
01030 NETSNMP_INLINE void
01031 netsnmp_free_request_data_sets(netsnmp_request_info *request)
01032 {
01033     if (request && request->parent_data) {
01034         netsnmp_free_all_list_data(request->parent_data);
01035         request->parent_data = NULL;
01036     }
01037 }
01038 
01050 netsnmp_mib_handler *
01051 netsnmp_find_handler_by_name(netsnmp_handler_registration *reginfo,
01052                              const char *name)
01053 {
01054     netsnmp_mib_handler *it;
01055     if (reginfo == NULL || name == NULL )
01056         return NULL;
01057     for (it = reginfo->handler; it; it = it->next) {
01058         if (strcmp(it->handler_name, name) == 0) {
01059             return it;
01060         }
01061     }
01062     return NULL;
01063 }
01064 
01081 void           *
01082 netsnmp_find_handler_data_by_name(netsnmp_handler_registration *reginfo,
01083                                   const char *name)
01084 {
01085     netsnmp_mib_handler *it = netsnmp_find_handler_by_name(reginfo, name);
01086     if (it)
01087         return it->myvoid;
01088     return NULL;
01089 }
01090 
01098 static netsnmp_mib_handler *
01099 _clone_handler(netsnmp_mib_handler *it)
01100 {
01101     netsnmp_mib_handler *dup;
01102 
01103     if(NULL == it)
01104         return NULL;
01105 
01106     dup = netsnmp_create_handler(it->handler_name, it->access_method);
01107     if(NULL != dup)
01108         dup->flags = it->flags;
01109 
01110     return dup;
01111 }
01112 
01113 static netsnmp_data_list *handler_reg = NULL;
01114 
01115 void
01116 handler_free_callback(void *handler)
01117 {
01118     netsnmp_handler_free((netsnmp_mib_handler *)handler);
01119 }
01120 
01131 void
01132 netsnmp_register_handler_by_name(const char *name,
01133                                  netsnmp_mib_handler *handler)
01134 {
01135     netsnmp_add_list_data(&handler_reg,
01136                           netsnmp_create_data_list(name, (void *) handler,
01137                                                    handler_free_callback));
01138     DEBUGMSGTL(("handler_registry", "registering helper %s\n", name));
01139 }
01140 
01149 void
01150 netsnmp_clear_handler_list(void)
01151 {
01152     DEBUGMSGTL(("agent_handler", "netsnmp_clear_handler_list() called\n"));
01153     netsnmp_free_all_list_data(handler_reg);
01154     handler_reg = NULL;
01155 }
01156 
01161 void
01162 netsnmp_inject_handler_into_subtree(netsnmp_subtree *tp, const char *name,
01163                                     netsnmp_mib_handler *handler,
01164                                     const char *before_what)
01165 {
01166     netsnmp_subtree *tptr;
01167     netsnmp_mib_handler *mh;
01168 
01169     for (tptr = tp; tptr != NULL; tptr = tptr->next) {
01170         /*  if (tptr->children) { 
01171               netsnmp_inject_handler_into_subtree(tptr->children,name,handler);
01172             }   */
01173         if (strcmp(tptr->label_a, name) == 0) {
01174             DEBUGMSGTL(("injectHandler", "injecting handler %s into %s\n",
01175                         handler->handler_name, tptr->label_a));
01176             netsnmp_inject_handler_before(tptr->reginfo, _clone_handler(handler),
01177                                           before_what);
01178         } else if (tptr->reginfo != NULL &&
01179                    tptr->reginfo->handlerName != NULL &&
01180                    strcmp(tptr->reginfo->handlerName, name) == 0) {
01181             DEBUGMSGTL(("injectHandler", "injecting handler into %s/%s\n",
01182                         tptr->label_a, tptr->reginfo->handlerName));
01183             netsnmp_inject_handler_before(tptr->reginfo, _clone_handler(handler),
01184                                           before_what);
01185         } else {
01186             for (mh = tptr->reginfo->handler; mh != NULL; mh = mh->next) {
01187                 if (mh->handler_name && strcmp(mh->handler_name, name) == 0) {
01188                     DEBUGMSGTL(("injectHandler", "injecting handler into %s\n",
01189                                 tptr->label_a));
01190                     netsnmp_inject_handler_before(tptr->reginfo,
01191                                                   _clone_handler(handler),
01192                                                   before_what);
01193                     break;
01194                 } else {
01195                     DEBUGMSGTL(("injectHandler",
01196                                 "not injecting handler into %s\n",
01197                                 mh->handler_name));
01198                 }
01199             }
01200         }
01201     }
01202 }
01203 
01204 static int      doneit = 0;
01208 void
01209 parse_injectHandler_conf(const char *token, char *cptr)
01210 {
01211     char            handler_to_insert[256], reg_name[256];
01212     subtree_context_cache *stc;
01213     netsnmp_mib_handler *handler;
01214 
01215     /*
01216      * XXXWWW: ensure instead that handler isn't inserted twice 
01217      */
01218     if (doneit)                 /* we only do this once without restart the agent */
01219         return;
01220 
01221     cptr = copy_nword(cptr, handler_to_insert, sizeof(handler_to_insert));
01222     handler = (netsnmp_mib_handler*)netsnmp_get_list_data(handler_reg, handler_to_insert);
01223     if (!handler) {
01224         netsnmp_config_error("no \"%s\" handler registered.",
01225                              handler_to_insert);
01226         return;
01227     }
01228 
01229     if (!cptr) {
01230         config_perror("no INTONAME specified.  Can't do insertion.");
01231         return;
01232     }
01233     cptr = copy_nword(cptr, reg_name, sizeof(reg_name));
01234 
01235     for (stc = get_top_context_cache(); stc; stc = stc->next) {
01236         DEBUGMSGTL(("injectHandler", "Checking context tree %s (before=%s)\n",
01237                     stc->context_name, (cptr)?cptr:"null"));
01238         netsnmp_inject_handler_into_subtree(stc->first_subtree, reg_name,
01239                                             handler, cptr);
01240     }
01241 }
01242 
01247 static int
01248 handler_mark_inject_handler_done(int majorID, int minorID,
01249                     void *serverarg, void *clientarg)
01250 {
01251     doneit = 1;
01252     return 0;
01253 }
01254 
01261 void
01262 netsnmp_init_handler_conf(void)
01263 {
01264     snmpd_register_config_handler("injectHandler",
01265                                   parse_injectHandler_conf,
01266                                   NULL, "injectHandler NAME INTONAME [BEFORE_OTHER_NAME]");
01267     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
01268                            SNMP_CALLBACK_POST_READ_CONFIG,
01269                            handler_mark_inject_handler_done, NULL);
01270 
01271     se_add_pair_to_slist("agent_mode", strdup("GET"), MODE_GET);
01272     se_add_pair_to_slist("agent_mode", strdup("GETNEXT"), MODE_GETNEXT);
01273     se_add_pair_to_slist("agent_mode", strdup("GETBULK"), MODE_GETBULK);
01274 #ifndef NETSNMP_NO_WRITE_SUPPORT
01275     se_add_pair_to_slist("agent_mode", strdup("SET_BEGIN"),
01276                          MODE_SET_BEGIN);
01277     se_add_pair_to_slist("agent_mode", strdup("SET_RESERVE1"),
01278                          MODE_SET_RESERVE1);
01279     se_add_pair_to_slist("agent_mode", strdup("SET_RESERVE2"),
01280                          MODE_SET_RESERVE2);
01281     se_add_pair_to_slist("agent_mode", strdup("SET_ACTION"),
01282                          MODE_SET_ACTION);
01283     se_add_pair_to_slist("agent_mode", strdup("SET_COMMIT"),
01284                          MODE_SET_COMMIT);
01285     se_add_pair_to_slist("agent_mode", strdup("SET_FREE"), MODE_SET_FREE);
01286     se_add_pair_to_slist("agent_mode", strdup("SET_UNDO"), MODE_SET_UNDO);
01287 
01288     se_add_pair_to_slist("babystep_mode", strdup("pre-request"),
01289                          MODE_BSTEP_PRE_REQUEST);
01290     se_add_pair_to_slist("babystep_mode", strdup("object_lookup"),
01291                          MODE_BSTEP_OBJECT_LOOKUP);
01292     se_add_pair_to_slist("babystep_mode", strdup("check_value"),
01293                          MODE_BSTEP_CHECK_VALUE);
01294     se_add_pair_to_slist("babystep_mode", strdup("row_create"),
01295                          MODE_BSTEP_ROW_CREATE);
01296     se_add_pair_to_slist("babystep_mode", strdup("undo_setup"),
01297                          MODE_BSTEP_UNDO_SETUP);
01298     se_add_pair_to_slist("babystep_mode", strdup("set_value"),
01299                          MODE_BSTEP_SET_VALUE);
01300     se_add_pair_to_slist("babystep_mode", strdup("check_consistency"),
01301                          MODE_BSTEP_CHECK_CONSISTENCY);
01302     se_add_pair_to_slist("babystep_mode", strdup("undo_set"),
01303                          MODE_BSTEP_UNDO_SET);
01304     se_add_pair_to_slist("babystep_mode", strdup("commit"),
01305                          MODE_BSTEP_COMMIT);
01306     se_add_pair_to_slist("babystep_mode", strdup("undo_commit"),
01307                          MODE_BSTEP_UNDO_COMMIT);
01308     se_add_pair_to_slist("babystep_mode", strdup("irreversible_commit"),
01309                          MODE_BSTEP_IRREVERSIBLE_COMMIT);
01310     se_add_pair_to_slist("babystep_mode", strdup("undo_cleanup"),
01311                          MODE_BSTEP_UNDO_CLEANUP);
01312     se_add_pair_to_slist("babystep_mode", strdup("post_request"),
01313                          MODE_BSTEP_POST_REQUEST);
01314     se_add_pair_to_slist("babystep_mode", strdup("original"), 0xffff);
01315 #endif /* NETSNMP_NO_WRITE_SUPPORT */
01316 
01317     /*
01318      * xxx-rks: hmmm.. will this work for modes which are or'd together?
01319      *          I'm betting not...
01320      */
01321     se_add_pair_to_slist("handler_can_mode", strdup("GET/GETNEXT"),
01322                          HANDLER_CAN_GETANDGETNEXT);
01323     se_add_pair_to_slist("handler_can_mode", strdup("SET"),
01324                          HANDLER_CAN_SET);
01325     se_add_pair_to_slist("handler_can_mode", strdup("GETBULK"),
01326                          HANDLER_CAN_GETBULK);
01327     se_add_pair_to_slist("handler_can_mode", strdup("BABY_STEP"),
01328                          HANDLER_CAN_BABY_STEP);
01329 }
01330