1 /*
2  * Portions of this file are subject to the following copyright(s).  See
3  * the Net-SNMP's COPYING file for more details and other copyrights
4  * that may apply:
5  *
6  * Portions of this file are copyrighted by:
7  * Copyright (c) 2016 VMware, 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 #include <net-snmp/net-snmp-config.h>
12 
13 #include <net-snmp/net-snmp-includes.h>
14 #include <net-snmp/agent/net-snmp-agent-includes.h>
15 
16 #include <net-snmp/agent/old_api.h>
17 
18 #if HAVE_STRING_H
19 #include <string.h>
20 #else
21 #include <strings.h>
22 #endif
23 
24 #include <net-snmp/agent/agent_callbacks.h>
25 
26 #include <stddef.h>
27 
28 #define MIB_CLIENTS_ARE_EVIL 1
29 
30 #ifdef HAVE_DMALLOC_H
free_wrapper(void * p)31 static void free_wrapper(void * p)
32 {
33     free(p);
34 }
35 #else
36 #define free_wrapper free
37 #endif
38 
39 /*
40  * don't use these!
41  */
42 void            set_current_agent_session(netsnmp_agent_session *asp);
43 
44 /** @defgroup old_api old_api
45  *  Calls mib module code written in the old style of code.
46  *  @ingroup handler
47  *  This is a backwards compatilibity module that allows code written
48  *  in the old API to be run under the new handler based architecture.
49  *  Use it by calling netsnmp_register_old_api().
50  *  @{
51  */
52 
53 /** returns a old_api handler that should be the final calling
54  * handler.  Don't use this function.  Use the netsnmp_register_old_api()
55  * function instead.
56  */
57 netsnmp_mib_handler *
get_old_api_handler(void)58 get_old_api_handler(void)
59 {
60     return netsnmp_create_handler("old_api", netsnmp_old_api_helper);
61 }
62 
63 struct variable *
netsnmp_duplicate_variable(const struct variable * var)64 netsnmp_duplicate_variable(const struct variable *var)
65 {
66     struct variable *var2 = NULL;
67 
68     if (var) {
69         const int varsize = offsetof(struct variable, name) + var->namelen * sizeof(var->name[0]);
70         var2 = malloc(varsize);
71         if (var2)
72             memcpy(var2, var, varsize);
73     }
74     return var2;
75 }
76 
77 /** Registers an old API set into the mib tree.  Functionally this
78  * mimics the old register_mib_context() function (and in fact the new
79  * register_mib_context() function merely calls this new old_api one).
80  */
81 int
netsnmp_register_old_api(const char * moduleName,const struct variable * var,size_t varsize,size_t numvars,const oid * mibloc,size_t mibloclen,int priority,int range_subid,oid range_ubound,netsnmp_session * ss,const char * context,int timeout,int flags)82 netsnmp_register_old_api(const char *moduleName,
83                          const struct variable *var,
84                          size_t varsize,
85                          size_t numvars,
86                          const oid * mibloc,
87                          size_t mibloclen,
88                          int priority,
89                          int range_subid,
90                          oid range_ubound,
91                          netsnmp_session * ss,
92                          const char *context, int timeout, int flags)
93 {
94 
95     unsigned int    i;
96     int             res;
97 
98     /*
99      * register all subtree nodes
100      */
101     for (i = 0; i < numvars; i++) {
102         struct variable *vp;
103         netsnmp_handler_registration *reginfo =
104             SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration);
105         if (reginfo == NULL)
106             return SNMP_ERR_GENERR;
107 
108 	vp = netsnmp_duplicate_variable((const struct variable *)
109 					((const char *) var + varsize * i));
110 
111         reginfo->handler = get_old_api_handler();
112         reginfo->handlerName = strdup(moduleName);
113         reginfo->rootoid_len = (mibloclen + vp->namelen);
114         reginfo->rootoid =
115             (oid *) malloc(reginfo->rootoid_len * sizeof(oid));
116         if (NULL == reginfo->handler || NULL == reginfo->handlerName ||
117             NULL == reginfo->rootoid) {
118             netsnmp_handler_free(reginfo->handler);
119             SNMP_FREE(vp);
120             SNMP_FREE(reginfo->handlerName);
121             SNMP_FREE(reginfo->rootoid);
122             SNMP_FREE(reginfo);
123             return SNMP_ERR_GENERR;
124         }
125 
126         memcpy(reginfo->rootoid, mibloc, mibloclen * sizeof(oid));
127         memcpy(reginfo->rootoid + mibloclen, vp->name, vp->namelen
128                * sizeof(oid));
129         reginfo->handler->myvoid = (void *) vp;
130         reginfo->handler->data_clone
131 	    = (void *(*)(void *))netsnmp_duplicate_variable;
132         reginfo->handler->data_free = free;
133 
134         reginfo->priority = priority;
135         reginfo->range_subid = range_subid;
136 
137         reginfo->range_ubound = range_ubound;
138         reginfo->timeout = timeout;
139         reginfo->contextName = (context) ? strdup(context) : NULL;
140         reginfo->modes = vp->acl == NETSNMP_OLDAPI_RONLY ? HANDLER_CAN_RONLY :
141                          HANDLER_CAN_RWRITE;
142 
143         /*
144          * register ourselves in the mib tree
145          */
146         res = netsnmp_register_handler(reginfo);
147         if (MIB_REGISTERED_OK != res) {
148             /** reginfo already freed on error. */
149             snmp_log(LOG_WARNING, "old_api handler registration failed\n");
150             return res;
151         }
152     }
153     return SNMPERR_SUCCESS;
154 }
155 
156 /** registers a row within a mib table */
157 int
netsnmp_register_mib_table_row(const char * moduleName,const struct variable * var,size_t varsize,size_t numvars,oid * mibloc,size_t mibloclen,int priority,int var_subid,netsnmp_session * ss,const char * context,int timeout,int flags)158 netsnmp_register_mib_table_row(const char *moduleName,
159                                const struct variable *var,
160                                size_t varsize,
161                                size_t numvars,
162                                oid * mibloc,
163                                size_t mibloclen,
164                                int priority,
165                                int var_subid,
166                                netsnmp_session * ss,
167                                const char *context, int timeout, int flags)
168 {
169     unsigned int    i = 0, rc = 0;
170     oid             ubound = 0;
171 
172     for (i = 0; i < numvars; i++) {
173         const struct variable *vr =
174             (const struct variable *) ((const char *) var + (i * varsize));
175         netsnmp_handler_registration *r;
176         if ( var_subid > (int)mibloclen ) {
177             break;    /* doesn't make sense */
178         }
179         r = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration);
180 
181         if (r == NULL) {
182             /*
183              * Unregister whatever we have registered so far, and
184              * return an error.
185              */
186             snmp_log(LOG_ERR, "mib table row registration failed\n");
187             rc = MIB_REGISTRATION_FAILED;
188             break;
189         }
190 
191         r->handler = get_old_api_handler();
192         r->handlerName = strdup(moduleName);
193         r->rootoid_len = mibloclen;
194         r->rootoid = (oid *) malloc(r->rootoid_len * sizeof(oid));
195         if (r->handler == NULL || r->handlerName == NULL ||
196             r->rootoid == NULL) {
197             netsnmp_handler_registration_free(r);
198             rc = MIB_REGISTRATION_FAILED;
199             break;
200         }
201         memcpy(r->rootoid, mibloc, mibloclen * sizeof(oid));
202         memcpy((u_char *) (r->rootoid + (var_subid - vr->namelen)), vr->name,
203                vr->namelen * sizeof(oid));
204         DEBUGMSGTL(("netsnmp_register_mib_table_row", "rootoid "));
205         DEBUGMSGOID(("netsnmp_register_mib_table_row", r->rootoid,
206                      r->rootoid_len));
207         DEBUGMSG(("netsnmp_register_mib_table_row", "(%d)\n",
208                      (var_subid - vr->namelen)));
209         r->handler->myvoid = netsnmp_duplicate_variable(vr);
210         r->handler->data_clone = (void *(*)(void *))netsnmp_duplicate_variable;
211         r->handler->data_free = free;
212 
213         r->contextName = (context) ? strdup(context) : NULL;
214         if (r->handler->myvoid == NULL ||
215             (context != NULL && r->contextName == NULL)) {
216             netsnmp_handler_registration_free(r);
217             rc = MIB_REGISTRATION_FAILED;
218             break;
219         }
220 
221         r->priority = priority;
222         r->range_subid = 0;     /* var_subid; */
223         r->range_ubound = 0;    /* range_ubound; */
224         r->timeout = timeout;
225         r->modes = HANDLER_CAN_RWRITE;
226 
227         /*
228          * Register this column and row
229          */
230         if ((rc =
231              netsnmp_register_handler_nocallback(r)) !=
232             MIB_REGISTERED_OK) {
233             snmp_log(LOG_ERR, "mib table row registration failed\n");
234             DEBUGMSGTL(("netsnmp_register_mib_table_row",
235                         "register failed %d\n", rc));
236             /** reginfo already freed */
237             break;
238         }
239 
240         if (vr->namelen > 0) {
241             if (vr->name[vr->namelen - 1] > ubound) {
242                 ubound = vr->name[vr->namelen - 1];
243             }
244         }
245     }
246 
247     if (rc == MIB_REGISTERED_OK) {
248         struct register_parameters reg_parms;
249 
250         reg_parms.name = mibloc;
251         reg_parms.namelen = mibloclen;
252         reg_parms.priority = priority;
253         reg_parms.flags = (u_char) flags;
254         reg_parms.range_subid = var_subid;
255         reg_parms.range_ubound = ubound;
256         reg_parms.timeout = timeout;
257         reg_parms.contextName = context;
258         rc = snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
259                                  SNMPD_CALLBACK_REGISTER_OID, &reg_parms);
260     }
261 
262     return rc;
263 }
264 
265 /** implements the old_api handler */
266 int
netsnmp_old_api_helper(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)267 netsnmp_old_api_helper(netsnmp_mib_handler *handler,
268                        netsnmp_handler_registration *reginfo,
269                        netsnmp_agent_request_info *reqinfo,
270                        netsnmp_request_info *requests)
271 {
272 
273 #if MIB_CLIENTS_ARE_EVIL
274     oid             save[MAX_OID_LEN];
275     size_t          savelen = 0;
276 #endif
277     struct variable compat_var, *cvp = &compat_var;
278     int             exact = 1;
279     int             status;
280 
281     struct variable *vp;
282     netsnmp_old_api_cache *cacheptr;
283     netsnmp_agent_session *oldasp = NULL;
284     u_char         *access = NULL;
285     WriteMethod    *write_method = NULL;
286     size_t          len;
287     size_t          tmp_len;
288     oid             tmp_name[MAX_OID_LEN];
289 
290     vp = (struct variable *) handler->myvoid;
291 
292     /*
293      * create old variable structure with right information
294      */
295     memcpy(cvp->name, reginfo->rootoid,
296            reginfo->rootoid_len * sizeof(oid));
297     cvp->namelen = reginfo->rootoid_len;
298     cvp->type = vp->type;
299     cvp->magic = vp->magic;
300     cvp->acl = vp->acl;
301     cvp->findVar = vp->findVar;
302 
303     switch (reqinfo->mode) {
304     case MODE_GETNEXT:
305     case MODE_GETBULK:
306         exact = 0;
307     }
308 
309     for (; requests; requests = requests->next) {
310 
311 #if MIB_CLIENTS_ARE_EVIL
312         savelen = requests->requestvb->name_length;
313         memcpy(save, requests->requestvb->name, savelen * sizeof(oid));
314 #endif
315 
316         switch (reqinfo->mode) {
317         case MODE_GET:
318         case MODE_GETNEXT:
319 #ifndef NETSNMP_NO_WRITE_SUPPORT
320         case MODE_SET_RESERVE1:
321 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
322             /*
323              * Actually call the old mib-module function
324              */
325             if (vp && vp->findVar) {
326                 tmp_len = requests->requestvb->name_length*sizeof(oid);
327                 memcpy(tmp_name, requests->requestvb->name, tmp_len);
328                 /** clear the rest of tmp_name to keep valgrind happy */
329                 memset(&tmp_name[requests->requestvb->name_length], 0x0,
330                        sizeof(tmp_name)-tmp_len);
331                 tmp_len = requests->requestvb->name_length;
332                 access = (*(vp->findVar)) (cvp, tmp_name, &tmp_len,
333                                            exact, &len, &write_method);
334                 snmp_set_var_objid( requests->requestvb, tmp_name, tmp_len );
335             }
336             else
337                 access = NULL;
338 
339 #ifdef WWW_FIX
340             if (IS_DELEGATED(cvp->type)) {
341                 add_method = (AddVarMethod *) statP;
342                 requests->delayed = 1;
343                 have_delegated = 1;
344                 continue;       /* WWW: This may not get to the right place */
345             }
346 #endif
347 
348             /*
349              * WWW: end range checking
350              */
351             if (access) {
352                 /*
353                  * result returned
354                  */
355 #ifndef NETSNMP_NO_WRITE_SUPPORT
356                 if (reqinfo->mode != MODE_SET_RESERVE1)
357 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
358                     snmp_set_var_typed_value(requests->requestvb,
359                                              cvp->type, access, len);
360             } else {
361                 /*
362                  * no result returned
363                  */
364 #if MIB_CLIENTS_ARE_EVIL
365                 if (access == NULL) {
366                     if (netsnmp_oid_equals(requests->requestvb->name,
367                                          requests->requestvb->name_length,
368                                          save, savelen) != 0) {
369                         DEBUGMSGTL(("old_api", "evil_client: %s\n",
370                                     reginfo->handlerName));
371                         memcpy(requests->requestvb->name, save,
372                                savelen * sizeof(oid));
373                         requests->requestvb->name_length = savelen;
374                     }
375                 }
376 #endif
377             }
378 
379             /*
380              * AAA: fall through for everything that is a set (see BBB)
381              */
382 #ifndef NETSNMP_NO_WRITE_SUPPORT
383             if (reqinfo->mode != MODE_SET_RESERVE1)
384 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
385                 break;
386 
387             cacheptr = SNMP_MALLOC_TYPEDEF(netsnmp_old_api_cache);
388             if (!cacheptr)
389                 return netsnmp_set_request_error(reqinfo, requests,
390                                                  SNMP_ERR_RESOURCEUNAVAILABLE);
391             cacheptr->data = access;
392             cacheptr->write_method = write_method;
393             write_method = NULL;
394             netsnmp_request_add_list_data(requests,
395                                           netsnmp_create_data_list
396                                           (OLD_API_NAME, cacheptr,
397                                            &free_wrapper));
398             /*
399              * BBB: fall through for everything that is a set (see AAA)
400              */
401 	    /* FALL THROUGH */
402 
403         default:
404             /*
405              * WWW: explicitly list the SET conditions
406              */
407             /*
408              * (the rest of the) SET contions
409              */
410             cacheptr =
411                 (netsnmp_old_api_cache *)
412                 netsnmp_request_get_list_data(requests, OLD_API_NAME);
413 
414             if (cacheptr == NULL || cacheptr->write_method == NULL) {
415                 /*
416                  * WWW: try to set ourselves if possible?
417                  */
418                 return netsnmp_set_request_error(reqinfo, requests,
419                                                  SNMP_ERR_NOTWRITABLE);
420             }
421 
422             oldasp = netsnmp_get_current_agent_session();
423             set_current_agent_session(reqinfo->asp);
424             status =
425                 (*(cacheptr->write_method)) (reqinfo->mode,
426                                              requests->requestvb->val.
427                                              string,
428                                              requests->requestvb->type,
429                                              requests->requestvb->val_len,
430                                              cacheptr->data,
431                                              requests->requestvb->name,
432                                              requests->requestvb->
433                                              name_length);
434             set_current_agent_session(oldasp);
435 
436             if (status != SNMP_ERR_NOERROR) {
437                 netsnmp_set_request_error(reqinfo, requests, status);
438             }
439 
440             /*
441              * clean up is done by the automatic freeing of the
442              * cache stored in the request.
443              */
444 
445             break;
446         }
447     }
448     return SNMP_ERR_NOERROR;
449 }
450 
451 /** @} */
452 
453 /*
454  * don't use this!
455  */
456 static netsnmp_agent_session *current_agent_session = NULL;
457 netsnmp_agent_session *
netsnmp_get_current_agent_session(void)458 netsnmp_get_current_agent_session(void)
459 {
460     return current_agent_session;
461 }
462 
463 /*
464  * don't use this!
465  */
466 void
set_current_agent_session(netsnmp_agent_session * asp)467 set_current_agent_session(netsnmp_agent_session *asp)
468 {
469     current_agent_session = asp;
470 }
471