net-snmp 5.7
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 # include <sys/time.h>
00077 # include <time.h>
00078 #else
00079 # if HAVE_SYS_TIME_H
00080 #  include <sys/time.h>
00081 # else
00082 #  include <time.h>
00083 # endif
00084 #endif
00085 #if HAVE_SYS_SOCKET_H
00086 # include <sys/socket.h>
00087 #endif
00088 #if HAVE_SYS_STREAM_H
00089 #   ifdef sysv5UnixWare7
00090 #      define _KMEMUSER 1 /* <sys/stream.h> needs this for queue_t */
00091 #   endif
00092 #include <sys/stream.h>
00093 #endif
00094 #if HAVE_SYS_SOCKETVAR_H
00095 # include <sys/socketvar.h>
00096 #endif
00097 #if HAVE_NETINET_IN_H
00098 #include <netinet/in.h>
00099 #endif
00100 #if HAVE_NETINET_IN_SYSTM_H
00101 #include <netinet/in_systm.h>
00102 #endif
00103 #if HAVE_NETINET_IP_H
00104 #include <netinet/ip.h>
00105 #endif
00106 #ifdef NETSNMP_ENABLE_IPV6
00107 #if HAVE_NETINET_IP6_H
00108 #include <netinet/ip6.h>
00109 #endif
00110 #endif
00111 #if HAVE_SYS_QUEUE_H
00112 #include <sys/queue.h>
00113 #endif
00114 #if HAVE_NET_ROUTE_H
00115 #include <net/route.h>
00116 #endif
00117 #if HAVE_NETINET_IP_VAR_H
00118 #include <netinet/ip_var.h>
00119 #endif
00120 #ifdef NETSNMP_ENABLE_IPV6
00121 #if HAVE_NETNETSNMP_ENABLE_IPV6_IP6_VAR_H
00122 #include <netinet6/ip6_var.h>
00123 #endif
00124 #endif
00125 #if HAVE_NETINET_IN_PCB_H
00126 #include <netinet/in_pcb.h>
00127 #endif
00128 #if HAVE_INET_MIB2_H
00129 #include <inet/mib2.h>
00130 #endif
00131 
00132 #include <net-snmp/net-snmp-includes.h>
00133 #include <net-snmp/agent/net-snmp-agent-includes.h>
00134 #include <net-snmp/agent/mib_modules.h>
00135 #include <net-snmp/agent/agent_sysORTable.h>
00136 #include "kernel.h"
00137 
00138 #include "mibgroup/struct.h"
00139 #include "snmpd.h"
00140 #include "agentx/agentx_config.h"
00141 #include "agentx/subagent.h"
00142 #include "net-snmp/agent/all_helpers.h"
00143 #include "agent_module_includes.h"
00144 #include "mib_module_includes.h"
00145 #include "net-snmp/library/container.h"
00146 
00147 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL)
00148 #include <openssl/ssl.h>
00149 #include <openssl/x509v3.h>
00150 #include <net-snmp/library/cert_util.h>
00151 #endif
00152 
00153 #include "snmp_perl.h"
00154 
00155 #ifndef  MIN
00156 #define  MIN(a,b)                     (((a) < (b)) ? (a) : (b))
00157 #endif
00158 
00159 static char     done_init_agent = 0;
00160 
00161 struct module_init_list *initlist = NULL;
00162 struct module_init_list *noinitlist = NULL;
00163 
00164 /*
00165  * mib clients are passed a pointer to a oid buffer.  Some mib clients
00166  * * (namely, those first noticed in mibII/vacm.c) modify this oid buffer
00167  * * before they determine if they really need to send results back out
00168  * * using it.  If the master agent determined that the client was not the
00169  * * right one to talk with, it will use the same oid buffer to pass to the
00170  * * rest of the clients, which may not longer be valid.  This should be
00171  * * fixed in all clients rather than the master.  However, its not a
00172  * * particularily easy bug to track down so this saves debugging time at
00173  * * the expense of a few memcpy's.
00174  */
00175 #define MIB_CLIENTS_ARE_EVIL 1
00176 
00177 extern netsnmp_subtree *subtrees;
00178 
00179 /*
00180  *      Each variable name is placed in the variable table, without the
00181  * terminating substring that determines the instance of the variable.  When
00182  * a string is found that is lexicographicly preceded by the input string,
00183  * the function for that entry is called to find the method of access of the
00184  * instance of the named variable.  If that variable is not found, NULL is
00185  * returned, and the search through the table continues (it will probably
00186  * stop at the next entry).  If it is found, the function returns a character
00187  * pointer and a length or a function pointer.  The former is the address
00188  * of the operand, the latter is a write routine for the variable.
00189  *
00190  * u_char *
00191  * findVar(name, length, exact, var_len, write_method)
00192  * oid      *name;          IN/OUT - input name requested, output name found
00193  * int      length;         IN/OUT - number of sub-ids in the in and out oid's
00194  * int      exact;          IN - TRUE if an exact match was requested.
00195  * int      len;            OUT - length of variable or 0 if function returned.
00196  * int      write_method;   OUT - pointer to function to set variable,
00197  *                                otherwise 0
00198  *
00199  *     The writeVar function is returned to handle row addition or complex
00200  * writes that require boundary checking or executing an action.
00201  * This routine will be called three times for each varbind in the packet.
00202  * The first time for each varbind, action is set to RESERVE1.  The type
00203  * and value should be checked during this pass.  If any other variables
00204  * in the MIB depend on this variable, this variable will be stored away
00205  * (but *not* committed!) in a place where it can be found by a call to
00206  * writeVar for a dependent variable, even in the same PDU.  During
00207  * the second pass, action is set to RESERVE2.  If this variable is dependent
00208  * on any other variables, it will check them now.  It must check to see
00209  * if any non-committed values have been stored for variables in the same
00210  * PDU that it depends on.  Sometimes resources will need to be reserved
00211  * in the first two passes to guarantee that the operation can proceed
00212  * during the third pass.  During the third pass, if there were no errors
00213  * in the first two passes, writeVar is called for every varbind with action
00214  * set to COMMIT.  It is now that the values should be written.  If there
00215  * were errors during the first two passes, writeVar is called in the third
00216  * pass once for each varbind, with the action set to FREE.  An opportunity
00217  * is thus provided to free those resources reserved in the first two passes.
00218  * 
00219  * writeVar(action, var_val, var_val_type, var_val_len, statP, name, name_len)
00220  * int      action;         IN - RESERVE1, RESERVE2, COMMIT, or FREE
00221  * u_char   *var_val;       IN - input or output buffer space
00222  * u_char   var_val_type;   IN - type of input buffer
00223  * int      var_val_len;    IN - input and output buffer len
00224  * u_char   *statP;         IN - pointer to local statistic
00225  * oid      *name           IN - pointer to name requested
00226  * int      name_len        IN - number of sub-ids in the name
00227  */
00228 
00229 long            long_return;
00230 #ifndef ibm032
00231 u_char          return_buf[258];
00232 #else
00233 u_char          return_buf[256];        /* nee 64 */
00234 #endif
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     netsnmp_set_agent_starttime(NULL);
00284 
00285     /*
00286      * we handle alarm signals ourselves in the select loop 
00287      */
00288     netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
00289                            NETSNMP_DS_LIB_ALARM_DONT_USE_SIG, 1);
00290 
00291 #ifdef NETSNMP_CAN_USE_NLIST
00292     init_kmem("/dev/kmem");
00293 #endif
00294 
00295     setup_tree();
00296 
00297     init_agent_read_config(app);
00298 
00299 #ifdef TESTING
00300     auto_nlist_print_tree(-2, 0);
00301 #endif
00302 
00303     _init_agent_callback_transport();
00304     
00305     netsnmp_init_helpers();
00306     init_traps();
00307     netsnmp_container_init_list();
00308     init_agent_sysORTable();
00309 
00310 #if defined(USING_AGENTX_SUBAGENT_MODULE) || defined(USING_AGENTX_MASTER_MODULE)
00311     /*
00312      * initialize agentx configs
00313      */
00314     agentx_config_init();
00315 #if defined(USING_AGENTX_SUBAGENT_MODULE)
00316     if(netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
00317                               NETSNMP_DS_AGENT_ROLE) == SUB_AGENT)
00318         subagent_init();
00319 #endif
00320 #endif
00321 
00322     /*
00323      * Register configuration tokens from transport modules.  
00324      */
00325 #ifdef NETSNMP_TRANSPORT_UDP_DOMAIN
00326     netsnmp_udp_agent_config_tokens_register();
00327 #endif
00328 #ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
00329     netsnmp_udp6_agent_config_tokens_register();
00330 #endif
00331 #ifdef NETSNMP_TRANSPORT_UNIX_DOMAIN
00332     netsnmp_unix_agent_config_tokens_register();
00333 #endif
00334 
00335 #ifdef NETSNMP_EMBEDDED_PERL
00336     init_perl();
00337 #endif
00338 
00339 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL)
00340 
00341     netsnmp_certs_agent_init();
00342 #endif
00343 
00344 #ifdef USING_AGENTX_SUBAGENT_MODULE
00345     /*
00346      * don't init agent modules for a sub-agent
00347      */
00348     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
00349                                NETSNMP_DS_AGENT_ROLE) == SUB_AGENT)
00350         return r;
00351 #endif
00352 
00353 #  include "agent_module_inits.h"
00354 
00355     return r;
00356 }                               /* end init_agent() */
00357 
00358 oid             nullOid[] = { 0, 0 };
00359 int             nullOidLen = sizeof(nullOid);
00360 
00361 void
00362 shutdown_agent(void) {
00363 
00364     /* probably some of this can be called as shutdown callback */
00365     shutdown_tree();
00366     clear_context();
00367     netsnmp_clear_callback_list();
00368     netsnmp_clear_tdomain_list();
00369     netsnmp_clear_handler_list();
00370     shutdown_agent_sysORTable();
00371     netsnmp_container_free_list();
00372     clear_sec_mod();
00373     clear_snmp_enum();
00374     clear_callback();
00375     shutdown_secmod();
00376     netsnmp_addrcache_destroy();
00377 #ifdef NETSNMP_CAN_USE_NLIST
00378     free_kmem();
00379 #endif
00380 
00381     done_init_agent = 0;
00382 }
00383 
00384 
00385 void
00386 add_to_init_list(char *module_list)
00387 {
00388     struct module_init_list *newitem, **list;
00389     char           *cp;
00390     char           *st;
00391 
00392     if (module_list == NULL) {
00393         return;
00394     } else {
00395         cp = (char *) module_list;
00396     }
00397 
00398     if (*cp == '-' || *cp == '!') {
00399         cp++;
00400         list = &noinitlist;
00401     } else {
00402         list = &initlist;
00403     }
00404 
00405     cp = strtok_r(cp, ", :", &st);
00406     while (cp) {
00407         newitem = (struct module_init_list *) calloc(1, sizeof(*initlist));
00408         newitem->module_name = strdup(cp);
00409         newitem->next = *list;
00410         *list = newitem;
00411         cp = strtok_r(NULL, ", :", &st);
00412     }
00413 }
00414 
00415 int
00416 should_init(const char *module_name)
00417 {
00418     struct module_init_list *listp;
00419 
00420     /*
00421      * a definitive list takes priority 
00422      */
00423     if (initlist) {
00424         listp = initlist;
00425         while (listp) {
00426             if (strcmp(listp->module_name, module_name) == 0) {
00427                 DEBUGMSGTL(("mib_init", "initializing: %s\n",
00428                             module_name));
00429                 return DO_INITIALIZE;
00430             }
00431             listp = listp->next;
00432         }
00433         DEBUGMSGTL(("mib_init", "skipping:     %s\n", module_name));
00434         return DONT_INITIALIZE;
00435     }
00436 
00437     /*
00438      * initialize it only if not on the bad list (bad module, no bone) 
00439      */
00440     if (noinitlist) {
00441         listp = noinitlist;
00442         while (listp) {
00443             if (strcmp(listp->module_name, module_name) == 0) {
00444                 DEBUGMSGTL(("mib_init", "skipping:     %s\n",
00445                             module_name));
00446                 return DONT_INITIALIZE;
00447             }
00448             listp = listp->next;
00449         }
00450     }
00451     DEBUGMSGTL(("mib_init", "initializing: %s\n", module_name));
00452 
00453     /*
00454      * initialize it 
00455      */
00456     return DO_INITIALIZE;
00457 }