Coverage Report

Created: 2026-05-23 07:02

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