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, ®_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