net-snmp  5.4.1
snmp_vars.c
00001 /*
00002  * snmp_vars.c - return a pointer to the named variable.
00003  */
00009 /* Portions of this file are subject to the following copyright(s).  See
00010  * the Net-SNMP's COPYING file for more details and other copyrights
00011  * that may apply:
00012  */
00013 /* Portions of this file are subject to the following copyright(s).  See
00014  * the Net-SNMP's COPYING file for more details and other copyrights
00015  * that may apply:
00016  */
00017 /***********************************************************
00018         Copyright 1988, 1989, 1990 by Carnegie Mellon University
00019         Copyright 1989  TGV, Incorporated
00020 
00021                       All Rights Reserved
00022 
00023 Permission to use, copy, modify, and distribute this software and its
00024 documentation for any purpose and without fee is hereby granted,
00025 provided that the above copyright notice appear in all copies and that
00026 both that copyright notice and this permission notice appear in
00027 supporting documentation, and that the name of CMU and TGV not be used
00028 in advertising or publicity pertaining to distribution of the software
00029 without specific, written prior permission.
00030 
00031 CMU AND TGV DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
00032 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
00033 EVENT SHALL CMU OR TGV BE LIABLE FOR ANY SPECIAL, INDIRECT OR
00034 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
00035 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
00036 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00037 PERFORMANCE OF THIS SOFTWARE.
00038 ******************************************************************/
00039 /*
00040  * Portions of this file are copyrighted by:
00041  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00042  * Use is subject to license terms specified in the COPYING file
00043  * distributed with the Net-SNMP package.
00044  */
00045 
00046 /*
00047  * additions, fixes and enhancements for Linux by Erik Schoenfelder
00048  * (schoenfr@ibr.cs.tu-bs.de) 1994/1995.
00049  * Linux additions taken from CMU to UCD stack by Jennifer Bray of Origin
00050  * (jbray@origin-at.co.uk) 1997
00051  */
00052 /*
00053  * Portions of this file are copyrighted by:
00054  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00055  * Use is subject to license terms specified in the COPYING file
00056  * distributed with the Net-SNMP package.
00057  */
00058 
00059 /*
00060  * XXXWWW merge todo: incl/excl range changes in differences between
00061  * 1.194 and 1.199 
00062  */
00063 
00064 #include <net-snmp/net-snmp-config.h>
00065 #if HAVE_STRING_H
00066 #include <string.h>
00067 #endif
00068 #if HAVE_STDLIB_H
00069 #include <stdlib.h>
00070 #endif
00071 #include <sys/types.h>
00072 #include <stdio.h>
00073 #include <fcntl.h>
00074 
00075 #if TIME_WITH_SYS_TIME
00076 # ifdef WIN32
00077 #  include <sys/timeb.h>
00078 # else
00079 #  include <sys/time.h>
00080 # endif
00081 # include <time.h>
00082 #else
00083 # if HAVE_SYS_TIME_H
00084 #  include <sys/time.h>
00085 # else
00086 #  include <time.h>
00087 # endif
00088 #endif
00089 #if HAVE_WINSOCK_H
00090 # include <winsock.h>
00091 #endif
00092 #if HAVE_SYS_SOCKET_H
00093 # include <sys/socket.h>
00094 #endif
00095 #if HAVE_SYS_STREAM_H
00096 #   ifdef sysv5UnixWare7
00097 #      define _KMEMUSER 1 /* <sys/stream.h> needs this for queue_t */
00098 #   endif
00099 #include <sys/stream.h>
00100 #endif
00101 #if HAVE_SYS_SOCKETVAR_H
00102 # include <sys/socketvar.h>
00103 #endif
00104 #if HAVE_NETINET_IN_H
00105 #include <netinet/in.h>
00106 #endif
00107 #if HAVE_NETINET_IN_SYSTM_H
00108 #include <netinet/in_systm.h>
00109 #endif
00110 #if HAVE_NETINET_IP_H
00111 #include <netinet/ip.h>
00112 #endif
00113 #ifdef NETSNMP_ENABLE_IPV6
00114 #if HAVE_NETINET_IP6_H
00115 #include <netinet/ip6.h>
00116 #endif
00117 #endif
00118 #if HAVE_SYS_QUEUE_H
00119 #include <sys/queue.h>
00120 #endif
00121 #if HAVE_NET_ROUTE_H
00122 #include <net/route.h>
00123 #endif
00124 #if HAVE_NETINET_IP_VAR_H
00125 #include <netinet/ip_var.h>
00126 #endif
00127 #ifdef NETSNMP_ENABLE_IPV6
00128 #if HAVE_NETNETSNMP_ENABLE_IPV6_IP6_VAR_H
00129 #include <netinet6/ip6_var.h>
00130 #endif
00131 #endif
00132 #if HAVE_NETINET_IN_PCB_H
00133 #include <netinet/in_pcb.h>
00134 #endif
00135 #if HAVE_INET_MIB2_H
00136 #include <inet/mib2.h>
00137 #endif
00138 
00139 #include <net-snmp/net-snmp-includes.h>
00140 #include <net-snmp/agent/net-snmp-agent-includes.h>
00141 #include <net-snmp/agent/mib_modules.h>
00142 #include "kernel.h"
00143 
00144 #include "mibgroup/struct.h"
00145 #include "snmpd.h"
00146 #include "agentx/agentx_config.h"
00147 #include "agentx/subagent.h"
00148 #include "net-snmp/agent/all_helpers.h"
00149 #include "agent_module_includes.h"
00150 #include "mib_module_includes.h"
00151 #include "net-snmp/library/container.h"
00152 
00153 #ifndef  MIN
00154 #define  MIN(a,b)                     (((a) < (b)) ? (a) : (b))
00155 #endif
00156 
00157 static char     done_init_agent = 0;
00158 
00159 struct module_init_list *initlist = NULL;
00160 struct module_init_list *noinitlist = NULL;
00161 
00162 /*
00163  * mib clients are passed a pointer to a oid buffer.  Some mib clients
00164  * * (namely, those first noticed in mibII/vacm.c) modify this oid buffer
00165  * * before they determine if they really need to send results back out
00166  * * using it.  If the master agent determined that the client was not the
00167  * * right one to talk with, it will use the same oid buffer to pass to the
00168  * * rest of the clients, which may not longer be valid.  This should be
00169  * * fixed in all clients rather than the master.  However, its not a
00170  * * particularily easy bug to track down so this saves debugging time at
00171  * * the expense of a few memcpy's.
00172  */
00173 #define MIB_CLIENTS_ARE_EVIL 1
00174 
00175 extern netsnmp_subtree *subtrees;
00176 
00177 /*
00178  *      Each variable name is placed in the variable table, without the
00179  * terminating substring that determines the instance of the variable.  When
00180  * a string is found that is lexicographicly preceded by the input string,
00181  * the function for that entry is called to find the method of access of the
00182  * instance of the named variable.  If that variable is not found, NULL is
00183  * returned, and the search through the table continues (it will probably
00184  * stop at the next entry).  If it is found, the function returns a character
00185  * pointer and a length or a function pointer.  The former is the address
00186  * of the operand, the latter is a write routine for the variable.
00187  *
00188  * u_char *
00189  * findVar(name, length, exact, var_len, write_method)
00190  * oid      *name;          IN/OUT - input name requested, output name found
00191  * int      length;         IN/OUT - number of sub-ids in the in and out oid's
00192  * int      exact;          IN - TRUE if an exact match was requested.
00193  * int      len;            OUT - length of variable or 0 if function returned.
00194  * int      write_method;   OUT - pointer to function to set variable,
00195  *                                otherwise 0
00196  *
00197  *     The writeVar function is returned to handle row addition or complex
00198  * writes that require boundary checking or executing an action.
00199  * This routine will be called three times for each varbind in the packet.
00200  * The first time for each varbind, action is set to RESERVE1.  The type
00201  * and value should be checked during this pass.  If any other variables
00202  * in the MIB depend on this variable, this variable will be stored away
00203  * (but *not* committed!) in a place where it can be found by a call to
00204  * writeVar for a dependent variable, even in the same PDU.  During
00205  * the second pass, action is set to RESERVE2.  If this variable is dependent
00206  * on any other variables, it will check them now.  It must check to see
00207  * if any non-committed values have been stored for variables in the same
00208  * PDU that it depends on.  Sometimes resources will need to be reserved
00209  * in the first two passes to guarantee that the operation can proceed
00210  * during the third pass.  During the third pass, if there were no errors
00211  * in the first two passes, writeVar is called for every varbind with action
00212  * set to COMMIT.  It is now that the values should be written.  If there
00213  * were errors during the first two passes, writeVar is called in the third
00214  * pass once for each varbind, with the action set to FREE.  An opportunity
00215  * is thus provided to free those resources reserved in the first two passes.
00216  * 
00217  * writeVar(action, var_val, var_val_type, var_val_len, statP, name, name_len)
00218  * int      action;         IN - RESERVE1, RESERVE2, COMMIT, or FREE
00219  * u_char   *var_val;       IN - input or output buffer space
00220  * u_char   var_val_type;   IN - type of input buffer
00221  * int      var_val_len;    IN - input and output buffer len
00222  * u_char   *statP;         IN - pointer to local statistic
00223  * oid      *name           IN - pointer to name requested
00224  * int      name_len        IN - number of sub-ids in the name
00225  */
00226 
00227 long            long_return;
00228 #ifndef ibm032
00229 u_char          return_buf[258];
00230 #else
00231 u_char          return_buf[256];        /* nee 64 */
00232 #endif
00233 
00234 struct timeval  starttime;
00235 
00236 int             callback_master_num = -1;
00237 
00238 #ifdef NETSNMP_TRANSPORT_CALLBACK_DOMAIN
00239 netsnmp_session *callback_master_sess = NULL;
00240 
00241 static void
00242 _init_agent_callback_transport(void)
00243 {
00244     /*
00245      * always register a callback transport for internal use 
00246      */
00247     callback_master_sess = netsnmp_callback_open(0, handle_snmp_packet,
00248                                                  netsnmp_agent_check_packet,
00249                                                  netsnmp_agent_check_parse);
00250     if (callback_master_sess)
00251         callback_master_num = callback_master_sess->local_port;
00252 }
00253 #else
00254 #define _init_agent_callback_transport()
00255 #endif
00256 
00269 int
00270 init_agent(const char *app)
00271 {
00272     int             r = 0;
00273 
00274     if(++done_init_agent > 1) {
00275         snmp_log(LOG_WARNING, "ignoring extra call to init_agent (%d)\n", 
00276                  done_init_agent);
00277         return r;
00278     }
00279 
00280     /*
00281      * get current time (ie, the time the agent started) 
00282      */
00283     gettimeofday(&starttime, NULL);
00284     starttime.tv_sec--;
00285     starttime.tv_usec += 1000000L;
00286 
00287     /*
00288      * we handle alarm signals ourselves in the select loop 
00289      */
00290     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
00291                            NETSNMP_DS_LIB_ALARM_DONT_USE_SIG, 1);
00292 
00293 #ifdef NETSNMP_CAN_USE_NLIST
00294     init_kmem("/dev/kmem");
00295 #endif
00296 
00297     setup_tree();
00298 
00299     init_agent_read_config(app);
00300 
00301 #ifdef TESTING
00302     auto_nlist_print_tree(-2, 0);
00303 #endif
00304 
00305     _init_agent_callback_transport();
00306     
00307     netsnmp_init_helpers();
00308     init_traps();
00309     netsnmp_container_init_list();
00310 
00311 #if defined(USING_AGENTX_SUBAGENT_MODULE) || defined(USING_AGENTX_MASTER_MODULE)
00312     /*
00313      * initialize agentx configs
00314      */
00315     agentx_config_init();
00316     if(netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
00317                               NETSNMP_DS_AGENT_ROLE) == SUB_AGENT)
00318         subagent_init();
00319 #endif
00320 
00321     /*
00322      * Register configuration tokens from transport modules.  
00323      */
00324 #ifdef NETSNMP_TRANSPORT_UDP_DOMAIN
00325     netsnmp_udp_agent_config_tokens_register();
00326 #endif
00327 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
00328     netsnmp_udp6_agent_config_tokens_register();
00329 #endif
00330 #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN
00331     netsnmp_unix_agent_config_tokens_register();
00332 #endif
00333 
00334 #ifdef NETSNMP_EMBEDDED_PERL
00335     init_perl();
00336 #endif
00337 
00338 #ifdef USING_AGENTX_SUBAGENT_MODULE
00339     /*
00340      * don't init agent modules for a sub-agent
00341      */
00342     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00343                                NETSNMP_DS_AGENT_ROLE) == SUB_AGENT)
00344         return r;
00345 #endif
00346 
00347 #  include "agent_module_inits.h"
00348 
00349     return r;
00350 }                               /* end init_agent() */
00351 
00352 oid             nullOid[] = { 0, 0 };
00353 int             nullOidLen = sizeof(nullOid);
00354 
00355 void
00356 shutdown_agent(void) {
00357 
00358     /* probably some of this can be called as shutdown callback */
00359     shutdown_tree();
00360     clear_context();
00361     netsnmp_clear_callback_list();
00362     netsnmp_clear_tdomain_list();
00363     netsnmp_clear_handler_list();
00364     netsnmp_container_free_list();
00365     clear_sec_mod();
00366     clear_snmp_enum();
00367     clear_callback();
00368     clear_user_list();
00369 
00370     done_init_agent = 0;
00371 }
00372 
00373 
00374 void
00375 add_to_init_list(char *module_list)
00376 {
00377     struct module_init_list *newitem, **list;
00378     char           *cp;
00379     char           *st;
00380 
00381     if (module_list == NULL) {
00382         return;
00383     } else {
00384         cp = (char *) module_list;
00385     }
00386 
00387     if (*cp == '-' || *cp == '!') {
00388         cp++;
00389         list = &noinitlist;
00390     } else {
00391         list = &initlist;
00392     }
00393 
00394     cp = strtok_r(cp, ", :", &st);
00395     while (cp) {
00396         newitem = (struct module_init_list *) calloc(1, sizeof(*initlist));
00397         newitem->module_name = strdup(cp);
00398         newitem->next = *list;
00399         *list = newitem;
00400         cp = strtok_r(NULL, ", :", &st);
00401     }
00402 }
00403 
00404 int
00405 should_init(const char *module_name)
00406 {
00407     struct module_init_list *listp;
00408 
00409     /*
00410      * a definitive list takes priority 
00411      */
00412     if (initlist) {
00413         listp = initlist;
00414         while (listp) {
00415             if (strcmp(listp->module_name, module_name) == 0) {
00416                 DEBUGMSGTL(("mib_init", "initializing: %s\n",
00417                             module_name));
00418                 return DO_INITIALIZE;
00419             }
00420             listp = listp->next;
00421         }
00422         DEBUGMSGTL(("mib_init", "skipping:     %s\n", module_name));
00423         return DONT_INITIALIZE;
00424     }
00425 
00426     /*
00427      * initialize it only if not on the bad list (bad module, no bone) 
00428      */
00429     if (noinitlist) {
00430         listp = noinitlist;
00431         while (listp) {
00432             if (strcmp(listp->module_name, module_name) == 0) {
00433                 DEBUGMSGTL(("mib_init", "skipping:     %s\n",
00434                             module_name));
00435                 return DONT_INITIALIZE;
00436             }
00437             listp = listp->next;
00438         }
00439     }
00440     DEBUGMSGTL(("mib_init", "initializing: %s\n", module_name));
00441 
00442     /*
00443      * initialize it 
00444      */
00445     return DO_INITIALIZE;
00446 }