Coverage Report

Created: 2026-02-26 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/agent/agent_handler.c
Line
Count
Source
1
/* Portions of this file are subject to the following copyright(s).  See
2
 * the Net-SNMP's COPYING file for more details and other copyrights
3
 * that may apply:
4
 */
5
/*
6
 * Portions of this file are copyrighted by:
7
 * Copyright © 2003 Sun Microsystems, 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
 * Portions of this file are copyrighted by:
12
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
13
 * Use is subject to license terms specified in the COPYING file
14
 * distributed with the Net-SNMP package.
15
 */
16
#include <net-snmp/net-snmp-config.h>
17
#include <net-snmp/net-snmp-features.h>
18
19
#include <sys/types.h>
20
21
#ifdef HAVE_STRING_H
22
#include <string.h>
23
#endif
24
25
#include <net-snmp/net-snmp-includes.h>
26
#include <net-snmp/agent/net-snmp-agent-includes.h>
27
28
#include <net-snmp/agent/bulk_to_next.h>
29
30
netsnmp_feature_child_of(agent_handler, libnetsnmpagent);
31
32
netsnmp_feature_child_of(handler_mark_requests_as_delegated, agent_handler);
33
34
static netsnmp_mib_handler *_clone_handler(netsnmp_mib_handler *it);
35
36
/***********************************************************************/
37
/*
38
 * New Handler based API 
39
 */
40
/***********************************************************************/
41
/** @defgroup handler Net-SNMP Agent handler and extensibility API
42
 *  @ingroup agent
43
 *
44
 *  The basic theory goes something like this: In the past, with the
45
 *  original mib module api (which derived from the original CMU SNMP
46
 *  code) the underlying mib modules were passed very little
47
 *  information (only the truly most basic information about a
48
 *  request).  This worked well at the time but in today's world of
49
 *  subagents, device instrumentation, low resource consumption, etc,
50
 *  it just isn't flexible enough.  "handlers" are here to fix all that.
51
 *
52
 *  With the rewrite of the agent internals for the net-snmp 5.0
53
 *  release, we introduce a modular calling scheme that allows agent
54
 *  modules to be written in a very flexible manner, and more
55
 *  importantly allows reuse of code in a decent way (and without the
56
 *  memory and speed overheads of OO languages like C++).
57
 *
58
 *  Functionally, the notion of what a handler does is the same as the
59
 *  older api: A handler is @link netsnmp_create_handler() created@endlink and
60
 *  then @link netsnmp_register_handler() registered@endlink with the main
61
 *  agent at a given OID in the OID tree and gets called any time a
62
 *  request is made that it should respond to.  You probably should
63
 *  use one of the convenience helpers instead of doing anything else
64
 *  yourself though:
65
 *
66
 *  Most importantly, though, is that the handlers are built on the
67
 *  notion of modularity and reuse.  Specifically, rather than do all
68
 *  the really hard work (like parsing table indexes out of an
69
 *  incoming oid request) in each module, the API is designed to make
70
 *  it easy to write "helper" handlers that merely process some aspect
71
 *  of the request before passing it along to the final handler that
72
 *  returns the real answer.  Most people will want to make use of the
73
 *  @link instance instance@endlink, @link table table@endlink, @link
74
 *  table_iterator table_iterator@endlink, @link table_data
75
 *  table_data@endlink, or @link table_dataset table_dataset@endlink
76
 *  helpers to make their life easier.  These "helpers" interpret
77
 *  important aspects of the request and pass them on to you.
78
 *
79
 *  For instance, the @link table table@endlink helper is designed to
80
 *  hand you a list of extracted index values from an incoming
81
 *  request.  The @link table_iterator table_iterator@endlink helper
82
 *  is built on top of the table helper, and is designed to help you
83
 *  iterate through data stored elsewhere (like in a kernel) that is
84
 *  not in OID lexographical order (ie, don't write your own index/oid
85
 *  sorting routine, use this helper instead).  The beauty of the
86
 *  @link table_iterator table_iterator helper@endlink, as well as the @link
87
 *  instance instance@endlink helper is that they take care of the complex
88
 *  GETNEXT processing entirely for you and hand you everything you
89
 *  need to merely return the data as if it was a GET request.  Much
90
 *  less code and hair pulling.  I've pulled all my hair out to help
91
 *  you so that only one of us has to be bald.
92
 *
93
 * @{
94
 */
95
96
/** Creates a MIB handler structure.
97
 *  The new structure is allocated and filled using the given name
98
 *  and access method.
99
 *  The returned handler should then be @link netsnmp_register_handler()
100
 *  registered @endlink.
101
 *
102
 *  @param name is the handler name and is copied then assigned to
103
 *              netsnmp_mib_handler->handler_name
104
 *
105
 *  @param handler_access_method is a function pointer used as the access
106
 *     method for this handler registration instance for whatever required
107
 *         needs.
108
 *
109
 *  @return a pointer to a populated netsnmp_mib_handler struct to be
110
 *          registered
111
 *
112
 *  @see netsnmp_create_handler_registration()
113
 *  @see netsnmp_register_handler()
114
 */
115
netsnmp_mib_handler *
116
netsnmp_create_handler(const char *name,
117
                       Netsnmp_Node_Handler * handler_access_method)
118
46.5k
{
119
46.5k
    netsnmp_mib_handler *ret = SNMP_MALLOC_TYPEDEF(netsnmp_mib_handler);
120
46.5k
    if (ret) {
121
46.5k
        ret->access_method = handler_access_method;
122
46.5k
        if (NULL != name) {
123
46.5k
            ret->handler_name = strdup(name);
124
46.5k
            if (NULL == ret->handler_name)
125
0
                SNMP_FREE(ret);
126
46.5k
        }
127
46.5k
    }
128
46.5k
    return ret;
129
46.5k
}
130
131
/** Creates a MIB handler structure.
132
 *  The new structure is allocated and filled using the given name,
133
 *  access function, registration location OID and list of modes that
134
 *  the handler supports. If modes == 0, then modes will automatically
135
 *  be set to the default value of only HANDLER_CAN_DEFAULT, which is
136
 *  by default read-only GET and GETNEXT requests. A handler which supports
137
 *  sets but not row creation should set us a mode of HANDLER_CAN_SET_ONLY.
138
 *  @note This ends up calling netsnmp_create_handler(name, handler_access_method)
139
 *  @param name is the handler name and is copied then assigned to
140
 *              netsnmp_handler_registration->handlerName.
141
 *
142
 *  @param handler is a function pointer used as the access
143
 *  method for this handler registration instance for whatever required
144
 *  needs.
145
 *
146
 *  @param reg_oid is the registration location oid.
147
 *
148
 *  @param reg_oid_len is the length of reg_oid; can use the macro,
149
 *         OID_LENGTH
150
 *
151
 *  @param modes is used to configure read/write access.  If modes == 0, 
152
 *  then modes will automatically be set to the default 
153
 *  value of only HANDLER_CAN_DEFAULT, which is by default read-only GET 
154
 *  and GETNEXT requests.  The other two mode options are read only, 
155
 *  HANDLER_CAN_RONLY, and read/write, HANDLER_CAN_RWRITE.
156
 *
157
 *    - HANDLER_CAN_GETANDGETNEXT
158
 *    - HANDLER_CAN_SET
159
 *    - HANDLER_CAN_GETBULK      
160
 *
161
 *    - HANDLER_CAN_RONLY   (HANDLER_CAN_GETANDGETNEXT)
162
 *    - HANDLER_CAN_RWRITE  (HANDLER_CAN_GETANDGETNEXT | 
163
 *      HANDLER_CAN_SET)
164
 *    - HANDLER_CAN_DEFAULT HANDLER_CAN_RONLY
165
 *
166
 *  @return Returns a pointer to a netsnmp_handler_registration struct.
167
 *          NULL is returned only when memory could not be allocated for the 
168
 *          netsnmp_handler_registration struct.
169
 *
170
 *
171
 *  @see netsnmp_create_handler()
172
 *  @see netsnmp_register_handler()
173
 */
174
netsnmp_handler_registration *
175
netsnmp_handler_registration_create(const char *name,
176
                                    netsnmp_mib_handler *handler,
177
                                    const oid * reg_oid, size_t reg_oid_len,
178
                                    int modes)
179
0
{
180
0
    netsnmp_handler_registration *the_reg;
181
0
    the_reg = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration);
182
0
    if (!the_reg)
183
0
        return NULL;
184
185
0
    if (modes)
186
0
        the_reg->modes = modes;
187
0
    else
188
0
        the_reg->modes = HANDLER_CAN_DEFAULT;
189
190
0
    the_reg->handler = handler;
191
0
    the_reg->priority = DEFAULT_MIB_PRIORITY;
192
0
    if (name) {
193
0
        the_reg->handlerName = strdup(name);
194
0
        if (NULL == the_reg->handlerName) {
195
0
            SNMP_FREE(the_reg);
196
0
            return NULL;
197
0
        }
198
0
    }
199
0
    the_reg->rootoid = snmp_duplicate_objid(reg_oid, reg_oid_len);
200
0
    the_reg->rootoid_len = reg_oid_len;
201
0
    return the_reg;
202
0
}
203
204
/** Creates a handler registration structure with a new MIB handler.
205
 *  This function first @link netsnmp_create_handler() creates @endlink
206
 *  a MIB handler, then @link netsnmp_handler_registration_create()
207
 *  makes registration structure @endlink for it.
208
 *
209
 *  @param name is the handler name for netsnmp_create_handler()
210
 *
211
 *  @param handler_access_method is a function pointer used as the access
212
 *     method for netsnmp_create_handler()
213
 *
214
 *  @param reg_oid is the registration location oid.
215
 *
216
 *  @param reg_oid_len is the length of reg_oid; can use the macro,
217
 *         OID_LENGTH
218
 *
219
 *  @param modes is used to configure read/write access, as in
220
 *         netsnmp_handler_registration_create()
221
 *
222
 *  @return Returns a pointer to a netsnmp_handler_registration struct.
223
 *          If the structures creation failed, NULL is returned.
224
 *
225
 *  @see netsnmp_create_handler()
226
 *  @see netsnmp_handler_registration_create()
227
 */
228
netsnmp_handler_registration *
229
netsnmp_create_handler_registration(const char *name,
230
                                    Netsnmp_Node_Handler *
231
                                    handler_access_method, const oid * reg_oid,
232
                                    size_t reg_oid_len, int modes)
233
0
{
234
0
    netsnmp_handler_registration *rv = NULL;
235
0
    netsnmp_mib_handler *handler =
236
0
        netsnmp_create_handler(name, handler_access_method);
237
0
    if (handler) {
238
0
        rv = netsnmp_handler_registration_create(
239
0
            name, handler, reg_oid, reg_oid_len, modes);
240
0
        if (!rv)
241
0
            netsnmp_handler_free(handler);
242
0
    }
243
0
    return rv;
244
0
}
245
246
/** Registers a MIB handler inside the registration structure.
247
 *  Checks given registration handler for sanity, then
248
 *  @link netsnmp_register_mib() performs registration @endlink
249
 *  in the MIB tree, as defined by the netsnmp_handler_registration
250
 *  pointer. On success, SNMP_CALLBACK_APPLICATION is called.
251
 *  The registration struct may be created by call of
252
 *  netsnmp_create_handler_registration().
253
 *
254
 *  @param reginfo Pointer to a netsnmp_handler_registration struct.
255
 *
256
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
257
 *
258
 *  @see netsnmp_create_handler_registration()
259
 *  @see netsnmp_register_mib()
260
 */
261
int
262
netsnmp_register_handler(netsnmp_handler_registration *reginfo)
263
19.9k
{
264
19.9k
    netsnmp_mib_handler *handler;
265
19.9k
    int flags = 0;
266
267
19.9k
    if (reginfo == NULL) {
268
0
        snmp_log(LOG_ERR, "netsnmp_register_handler() called illegally\n");
269
0
        netsnmp_assert(reginfo != NULL);
270
0
        return SNMP_ERR_GENERR;
271
0
    }
272
273
19.9k
    DEBUGIF("handler::register") {
274
0
        DEBUGMSGTL(("handler::register", "Registering %s (", reginfo->handlerName));
275
0
        for (handler = reginfo->handler; handler; handler = handler->next) {
276
0
            DEBUGMSG(("handler::register", "::%s", handler->handler_name));
277
0
        }
278
279
0
        DEBUGMSG(("handler::register", ") at "));
280
0
        if (reginfo->rootoid && reginfo->range_subid) {
281
0
            DEBUGMSGOIDRANGE(("handler::register", reginfo->rootoid,
282
0
                              reginfo->rootoid_len, reginfo->range_subid,
283
0
                              reginfo->range_ubound));
284
0
        } else if (reginfo->rootoid) {
285
0
            DEBUGMSGOID(("handler::register", reginfo->rootoid,
286
0
                         reginfo->rootoid_len));
287
0
        } else {
288
0
            DEBUGMSG(("handler::register", "[null]"));
289
0
        }
290
0
        DEBUGMSG(("handler::register", "\n"));
291
0
    }
292
293
    /*
294
     * don't let them register for absolutely nothing.  Probably a mistake 
295
     */
296
19.9k
    if (0 == reginfo->modes) {
297
0
        reginfo->modes = HANDLER_CAN_DEFAULT;
298
0
        snmp_log(LOG_WARNING, "no registration modes specified for %s. "
299
0
                 "Defaulting to 0x%x\n", reginfo->handlerName, reginfo->modes);
300
0
    }
301
302
    /*
303
     * for handlers that can't GETBULK, force a conversion handler on them 
304
     */
305
19.9k
    if (!(reginfo->modes & HANDLER_CAN_GETBULK)) {
306
0
        handler = netsnmp_get_bulk_to_next_handler();
307
0
        if (!handler ||
308
0
            (netsnmp_inject_handler(reginfo, handler) != SNMPERR_SUCCESS)) {
309
0
            snmp_log(LOG_WARNING, "could not inject bulk to next handler\n");
310
0
            if (handler)
311
0
                netsnmp_handler_free(handler);
312
            /** should this be a critical error? */
313
0
            netsnmp_handler_registration_free(reginfo);
314
0
            return SNMP_ERR_GENERR;
315
0
        }
316
0
    }
317
318
39.9k
    for (handler = reginfo->handler; handler; handler = handler->next) {
319
19.9k
        if (handler->flags & MIB_HANDLER_INSTANCE)
320
0
            flags = FULLY_QUALIFIED_INSTANCE;
321
19.9k
    }
322
323
19.9k
    return netsnmp_register_mib(reginfo->handlerName,
324
19.9k
                                NULL, 0, 0,
325
19.9k
                                reginfo->rootoid, reginfo->rootoid_len,
326
19.9k
                                reginfo->priority,
327
19.9k
                                reginfo->range_subid,
328
19.9k
                                reginfo->range_ubound, NULL,
329
19.9k
                                reginfo->contextName, reginfo->timeout, flags,
330
19.9k
                                reginfo, 1);
331
19.9k
}
332
333
/** Unregisters a MIB handler described inside the registration structure.
334
 *  Removes a registration, performed earlier by
335
 *  netsnmp_register_handler(), from the MIB tree.
336
 *  Uses unregister_mib_context() to do the task.
337
 *
338
 *  @param reginfo Pointer to a netsnmp_handler_registration struct.
339
 *
340
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
341
 *
342
 *  @see netsnmp_register_handler()
343
 *  @see unregister_mib_context()
344
 */
345
int
346
netsnmp_unregister_handler(netsnmp_handler_registration *reginfo)
347
0
{
348
0
    if (!reginfo)
349
0
        return SNMPERR_SUCCESS;
350
0
    return unregister_mib_context(reginfo->rootoid, reginfo->rootoid_len,
351
0
                                  reginfo->priority,
352
0
                                  reginfo->range_subid, reginfo->range_ubound,
353
0
                                  reginfo->contextName);
354
0
}
355
356
/** Registers a MIB handler inside the registration structure.
357
 *  Checks given registration handler for sanity, then
358
 *  @link netsnmp_register_mib() performs registration @endlink
359
 *  in the MIB tree, as defined by the netsnmp_handler_registration
360
 *  pointer. Never calls SNMP_CALLBACK_APPLICATION.
361
 *  The registration struct may be created by call of
362
 *  netsnmp_create_handler_registration().
363
 *
364
 *  @param reginfo Pointer to a netsnmp_handler_registration struct.
365
 *
366
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
367
 *
368
 *  @see netsnmp_create_handler_registration()
369
 *  @see netsnmp_register_mib()
370
 */
371
int
372
netsnmp_register_handler_nocallback(netsnmp_handler_registration *reginfo)
373
0
{
374
0
    netsnmp_mib_handler *handler;
375
0
    if (reginfo == NULL) {
376
0
        snmp_log(LOG_ERR, "netsnmp_register_handler_nocallback() called illegally\n");
377
0
        netsnmp_assert(reginfo != NULL);
378
0
        return SNMP_ERR_GENERR;
379
0
    }
380
0
    DEBUGIF("handler::register") {
381
0
        DEBUGMSGTL(("handler::register",
382
0
                    "Registering (with no callback) "));
383
0
        for (handler = reginfo->handler; handler; handler = handler->next) {
384
0
            DEBUGMSG(("handler::register", "::%s", handler->handler_name));
385
0
        }
386
387
0
        DEBUGMSG(("handler::register", " at "));
388
0
        if (reginfo->rootoid && reginfo->range_subid) {
389
0
            DEBUGMSGOIDRANGE(("handler::register", reginfo->rootoid,
390
0
                              reginfo->rootoid_len, reginfo->range_subid,
391
0
                              reginfo->range_ubound));
392
0
        } else if (reginfo->rootoid) {
393
0
            DEBUGMSGOID(("handler::register", reginfo->rootoid,
394
0
                         reginfo->rootoid_len));
395
0
        } else {
396
0
            DEBUGMSG(("handler::register", "[null]"));
397
0
        }
398
0
        DEBUGMSG(("handler::register", "\n"));
399
0
    }
400
401
    /*
402
     * don't let them register for absolutely nothing.  Probably a mistake 
403
     */
404
0
    if (0 == reginfo->modes) {
405
0
        reginfo->modes = HANDLER_CAN_DEFAULT;
406
0
    }
407
408
0
    return netsnmp_register_mib(reginfo->handler->handler_name,
409
0
                                NULL, 0, 0,
410
0
                                reginfo->rootoid, reginfo->rootoid_len,
411
0
                                reginfo->priority,
412
0
                                reginfo->range_subid,
413
0
                                reginfo->range_ubound, NULL,
414
0
                                reginfo->contextName, reginfo->timeout, 0,
415
0
                                reginfo, 0);
416
0
}
417
418
/** Injects handler into the calling chain of handlers.
419
 *  The given MIB handler is inserted after the handler named before_what.
420
 *  If before_what is NULL, the handler is put at the top of the list,
421
 *  and hence will be the handler to be called first.
422
 *
423
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
424
 *
425
 *  @see netsnmp_create_handler_registration()
426
 *  @see netsnmp_inject_handler()
427
 */
428
int
429
netsnmp_inject_handler_before(netsnmp_handler_registration *reginfo,
430
                              netsnmp_mib_handler *handler,
431
                              const char *before_what)
432
0
{
433
0
    netsnmp_mib_handler *handler2 = handler;
434
435
0
    if (handler == NULL || reginfo == NULL) {
436
0
        snmp_log(LOG_ERR, "netsnmp_inject_handler() called illegally\n");
437
0
        netsnmp_assert(reginfo != NULL);
438
0
        netsnmp_assert(handler != NULL);
439
0
        return SNMP_ERR_GENERR;
440
0
    }
441
0
    while (handler2->next) {
442
0
        handler2 = handler2->next;  /* Find the end of a handler sub-chain */
443
0
    }
444
0
    if (reginfo->handler == NULL) {
445
0
        DEBUGMSGTL(("handler:inject", "injecting %s\n", handler->handler_name));
446
0
    }
447
0
    else {
448
0
        DEBUGMSGTL(("handler:inject", "injecting %s before %s\n",
449
0
                    handler->handler_name, reginfo->handler->handler_name));
450
0
    }
451
0
    if (before_what) {
452
0
        netsnmp_mib_handler *nexth, *prevh = NULL;
453
0
        if (reginfo->handler == NULL) {
454
0
            snmp_log(LOG_ERR, "no handler to inject before\n");
455
0
            return SNMP_ERR_GENERR;
456
0
        }
457
0
        for(nexth = reginfo->handler; nexth;
458
0
            prevh = nexth, nexth = nexth->next) {
459
0
            if (strcmp(nexth->handler_name, before_what) == 0)
460
0
                break;
461
0
        }
462
0
        if (!nexth) {
463
0
      snmp_log(LOG_ERR, "Cannot inject '%s' before '%s': not found\n", handler->handler_name, before_what);
464
0
      snmp_log(LOG_ERR, "The handlers are:\n");
465
0
      for (nexth = reginfo->handler; nexth; nexth = nexth->next)
466
0
    snmp_log(LOG_ERR, "  %s\n", nexth->handler_name);
467
0
            return SNMP_ERR_GENERR;
468
0
  }
469
0
        if (prevh) {
470
            /* after prevh and before nexth */
471
0
            prevh->next = handler;
472
0
            handler2->next = nexth;
473
0
            handler->prev = prevh;
474
0
            nexth->prev = handler2;
475
0
            return SNMPERR_SUCCESS;
476
0
        }
477
        /* else we're first, which is what we do next anyway so fall through */
478
0
    }
479
0
    handler2->next = reginfo->handler;
480
0
    if (reginfo->handler)
481
0
        reginfo->handler->prev = handler2;
482
0
    reginfo->handler = handler;
483
0
    return SNMPERR_SUCCESS;
484
0
}
485
486
/** Injects handler into the calling chain of handlers.
487
 *  The given MIB handler is put at the top of the list,
488
 *  and hence will be the handler to be called first.
489
 *
490
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
491
 *
492
 *  @see netsnmp_create_handler_registration()
493
 *  @see netsnmp_inject_handler_before()
494
 */
495
int
496
netsnmp_inject_handler(netsnmp_handler_registration *reginfo,
497
                       netsnmp_mib_handler *handler)
498
0
{
499
0
    return netsnmp_inject_handler_before(reginfo, handler, NULL);
500
0
}
501
502
/** Calls a MIB handlers chain, starting with specific handler.
503
 *  The given arguments and MIB handler are checked
504
 *  for sanity, then the handlers are called, one by one,
505
 *  until next handler is NULL.
506
 *
507
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
508
 */
509
NETSNMP_INLINE int
510
netsnmp_call_handler(netsnmp_mib_handler *next_handler,
511
                     netsnmp_handler_registration *reginfo,
512
                     netsnmp_agent_request_info *reqinfo,
513
                     netsnmp_request_info *requests)
514
208
{
515
208
    Netsnmp_Node_Handler *nh;
516
208
    int             ret;
517
518
208
    if (next_handler == NULL || reginfo == NULL || reqinfo == NULL ||
519
208
        requests == NULL) {
520
0
        snmp_log(LOG_ERR, "netsnmp_call_handler() called illegally\n");
521
0
        netsnmp_assert(next_handler != NULL);
522
0
        netsnmp_assert(reqinfo != NULL);
523
0
        netsnmp_assert(reginfo != NULL);
524
0
        netsnmp_assert(requests != NULL);
525
0
        return SNMP_ERR_GENERR;
526
0
    }
527
528
208
    do {
529
208
        nh = next_handler->access_method;
530
208
        if (!nh) {
531
0
            if (next_handler->next) {
532
0
                snmp_log(LOG_ERR, "no access method specified in handler %s.",
533
0
                         next_handler->handler_name);
534
0
                return SNMP_ERR_GENERR;
535
0
            }
536
            /*
537
             * The final handler registration in the chain may well not need
538
             * to include a handler routine, if the processing of this object
539
             * is handled completely by the agent toolkit helpers.
540
             */
541
0
            return SNMP_ERR_NOERROR;
542
0
        }
543
544
208
        DEBUGMSGTL(("handler:calling", "calling handler %s for mode %s\n",
545
208
                    next_handler->handler_name,
546
208
                    se_find_label_in_slist("agent_mode", reqinfo->mode)));
547
548
        /*
549
         * XXX: define acceptable return statuses
550
         */
551
208
        ret = (*nh) (next_handler, reginfo, reqinfo, requests);
552
553
208
        DEBUGMSGTL(("handler:returned", "handler %s returned %d\n",
554
208
                    next_handler->handler_name, ret));
555
556
208
        if (! (next_handler->flags & MIB_HANDLER_AUTO_NEXT))
557
208
            break;
558
559
        /*
560
         * did handler signal that it didn't want auto next this time around?
561
         */
562
0
        if(next_handler->flags & MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE) {
563
0
            next_handler->flags &= ~MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
564
0
            break;
565
0
        }
566
567
0
        next_handler = next_handler->next;
568
569
0
    } while(next_handler);
570
571
208
    return ret;
572
208
}
573
574
/** @private
575
 *  Calls all the MIB Handlers in registration struct for a given mode.
576
 *
577
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
578
 */
579
int
580
netsnmp_call_handlers(netsnmp_handler_registration *reginfo,
581
                      netsnmp_agent_request_info *reqinfo,
582
                      netsnmp_request_info *requests)
583
532
{
584
532
    netsnmp_request_info *request;
585
532
    int             status;
586
587
532
    if (reginfo == NULL || reqinfo == NULL || requests == NULL) {
588
0
        snmp_log(LOG_ERR, "netsnmp_call_handlers() called illegally\n");
589
0
        netsnmp_assert(reqinfo != NULL);
590
0
        netsnmp_assert(reginfo != NULL);
591
0
        netsnmp_assert(requests != NULL);
592
0
        return SNMP_ERR_GENERR;
593
0
    }
594
595
532
    if (reginfo->handler == NULL) {
596
0
        snmp_log(LOG_ERR, "no handler specified.");
597
0
        return SNMP_ERR_GENERR;
598
0
    }
599
600
532
    switch (reqinfo->mode) {
601
0
    case MODE_GETBULK:
602
208
    case MODE_GET:
603
208
    case MODE_GETNEXT:
604
208
        if (!(reginfo->modes & HANDLER_CAN_GETANDGETNEXT))
605
0
            return SNMP_ERR_NOERROR;    /* legal */
606
208
        break;
607
608
208
#ifndef NETSNMP_NO_WRITE_SUPPORT
609
208
    case MODE_SET_RESERVE1:
610
162
    case MODE_SET_RESERVE2:
611
162
    case MODE_SET_ACTION:
612
162
    case MODE_SET_COMMIT:
613
324
    case MODE_SET_FREE:
614
324
    case MODE_SET_UNDO:
615
324
        if (!(reginfo->modes & HANDLER_CAN_SET)) {
616
690
            for (; requests; requests = requests->next) {
617
366
                netsnmp_set_request_error(reqinfo, requests,
618
366
                                          SNMP_ERR_NOTWRITABLE);
619
366
            }
620
324
            return SNMP_ERR_NOERROR;
621
324
        }
622
0
        break;
623
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
624
625
0
    default:
626
0
        snmp_log(LOG_ERR, "unknown mode in netsnmp_call_handlers! bug!\n");
627
0
        return SNMP_ERR_GENERR;
628
532
    }
629
208
    DEBUGMSGTL(("handler:calling", "main handler %s\n",
630
208
                reginfo->handler->handler_name));
631
632
459
    for (request = requests ; request; request = request->next) {
633
251
        request->processed = 0;
634
251
    }
635
636
208
    status = netsnmp_call_handler(reginfo->handler, reginfo, reqinfo, requests);
637
638
208
    return status;
639
532
}
640
641
/** @private
642
 *  Calls the next MIB handler in the chain, after the current one.
643
 *  The given arguments and MIB handler are checked
644
 *  for sanity, then the next handler is called.
645
 *
646
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
647
 */
648
NETSNMP_INLINE int
649
netsnmp_call_next_handler(netsnmp_mib_handler *current,
650
                          netsnmp_handler_registration *reginfo,
651
                          netsnmp_agent_request_info *reqinfo,
652
                          netsnmp_request_info *requests)
653
0
{
654
655
0
    if (current == NULL || reginfo == NULL || reqinfo == NULL ||
656
0
        requests == NULL) {
657
0
        snmp_log(LOG_ERR, "netsnmp_call_next_handler() called illegally\n");
658
0
        netsnmp_assert(current != NULL);
659
0
        netsnmp_assert(reginfo != NULL);
660
0
        netsnmp_assert(reqinfo != NULL);
661
0
        netsnmp_assert(requests != NULL);
662
0
        return SNMP_ERR_GENERR;
663
0
    }
664
665
0
    return netsnmp_call_handler(current->next, reginfo, reqinfo, requests);
666
0
}
667
668
/** @private
669
 *  Calls the next MIB handler in the chain, after the current one.
670
 *  The given arguments and MIB handler are not validated before
671
 *  the call, only request is checked.
672
 *
673
 *  @return Returns SNMPERR_SUCCESS or SNMP_ERR_* error code.
674
 */
675
netsnmp_feature_child_of(netsnmp_call_next_handler_one_request,netsnmp_unused);
676
#ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_CALL_NEXT_HANDLER_ONE_REQUEST
677
NETSNMP_INLINE int
678
netsnmp_call_next_handler_one_request(netsnmp_mib_handler *current,
679
                                      netsnmp_handler_registration *reginfo,
680
                                      netsnmp_agent_request_info *reqinfo,
681
                                      netsnmp_request_info *requests)
682
0
{
683
0
    netsnmp_request_info *request;
684
0
    int ret;
685
    
686
0
    if (!requests) {
687
0
        snmp_log(LOG_ERR, "netsnmp_call_next_handler_ONE_REQUEST() called illegally\n");
688
0
        netsnmp_assert(requests != NULL);
689
0
        return SNMP_ERR_GENERR;
690
0
    }
691
692
0
    request = requests->next;
693
0
    requests->next = NULL;
694
0
    ret = netsnmp_call_handler(current->next, reginfo, reqinfo, requests);
695
0
    requests->next = request;
696
0
    return ret;
697
0
}
698
#endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_CALL_NEXT_HANDLER_ONE_REQUEST */
699
700
/** Deallocates resources associated with a given handler.
701
 *  The handler is removed from chain and then freed.
702
 *  After calling this function, the handler pointer is invalid
703
 *  and should be set to NULL.
704
 *
705
 *  @param handler is the MIB Handler to be freed
706
 */
707
void
708
netsnmp_handler_free(netsnmp_mib_handler *handler)
709
46.5k
{
710
46.5k
    if (handler != NULL) {
711
46.5k
        if (handler->next != NULL) {
712
            /** make sure we aren't pointing to ourselves.  */
713
6.65k
            netsnmp_assert(handler != handler->next); /* bugs caught: 1 */
714
6.65k
            netsnmp_handler_free(handler->next);
715
6.65k
            handler->next = NULL;
716
6.65k
        }
717
46.5k
        if ((handler->myvoid != NULL) && (handler->data_free != NULL))
718
3.32k
        {
719
3.32k
            handler->data_free(handler->myvoid);
720
3.32k
        }
721
46.5k
        SNMP_FREE(handler->handler_name);
722
46.5k
        SNMP_FREE(handler);
723
46.5k
    }
724
46.5k
}
725
726
/** Duplicates a MIB handler and all subsequent handlers.
727
 *  Creates a copy of all data in given handlers chain.
728
 *
729
 *  @param handler is the MIB Handler to be duplicated
730
 *
731
 *  @return Returns a pointer to the complete copy,
732
 *         or NULL if any problem occurred.
733
 *
734
 * @see _clone_handler()
735
 */
736
netsnmp_mib_handler *
737
netsnmp_handler_dup(netsnmp_mib_handler *handler)
738
0
{
739
0
    netsnmp_mib_handler *h = NULL;
740
741
0
    if (!handler)
742
0
        goto err;
743
744
0
    h = _clone_handler(handler);
745
0
    if (!h)
746
0
        goto err;
747
748
    /*
749
     * Providing a clone function without a free function is asking for
750
     * memory leaks, and providing a free function without clone function
751
     * is asking for memory corruption. Hence the log statement below.
752
     */
753
0
    if (!!handler->data_clone != !!handler->data_free)
754
0
        snmp_log(LOG_ERR, "data_clone / data_free inconsistent (%s)\n",
755
0
                 handler->handler_name);
756
0
    if (handler->myvoid && handler->data_clone) {
757
0
        h->myvoid = handler->data_clone(handler->myvoid);
758
0
        if (!h->myvoid)
759
0
            goto err;
760
0
    } else
761
0
        h->myvoid = handler->myvoid;
762
0
    h->data_clone = handler->data_clone;
763
0
    h->data_free = handler->data_free;
764
765
0
    if (handler->next != NULL) {
766
0
        h->next = netsnmp_handler_dup(handler->next);
767
0
        if (!h->next)
768
0
            goto err;
769
0
        h->next->prev = h;
770
0
    }
771
0
    h->prev = NULL;
772
0
    return h;
773
774
0
err:
775
0
    netsnmp_handler_free(h);
776
0
    return NULL;
777
0
}
778
779
/** Free resources associated with a handler registration object.
780
 *  The registration object and all MIB Handlers in the chain are
781
 *  freed. When the function ends, given pointer is no longer valid
782
 *  and should be set to NULL.
783
 *
784
 *  @param reginfo is the handler registration object to be freed
785
 */
786
void
787
netsnmp_handler_registration_free(netsnmp_handler_registration *reginfo)
788
19.9k
{
789
19.9k
    if (reginfo != NULL) {
790
19.9k
        netsnmp_handler_free(reginfo->handler);
791
19.9k
        SNMP_FREE(reginfo->handlerName);
792
19.9k
        SNMP_FREE(reginfo->contextName);
793
19.9k
        SNMP_FREE(reginfo->rootoid);
794
19.9k
        reginfo->rootoid_len = 0;
795
19.9k
        SNMP_FREE(reginfo);
796
19.9k
    }
797
19.9k
}
798
799
/** Duplicates handler registration object and all subsequent handlers.
800
 *  Creates a copy of the handler registration object and all its data.
801
 *
802
 *  @param reginfo is the handler registration object to be duplicated
803
 *
804
 *  @return Returns a pointer to the complete copy,
805
 *         or NULL if any problem occurred.
806
 *
807
 * @see netsnmp_handler_dup()
808
 */
809
netsnmp_handler_registration *
810
netsnmp_handler_registration_dup(netsnmp_handler_registration *reginfo)
811
0
{
812
0
    netsnmp_handler_registration *r = NULL;
813
814
0
    if (reginfo == NULL)
815
0
        return NULL;
816
817
0
    r = calloc(1, sizeof(netsnmp_handler_registration));
818
0
    if (!r)
819
0
        return r;
820
0
    r->modes = reginfo->modes;
821
0
    r->priority = reginfo->priority;
822
0
    r->range_subid = reginfo->range_subid;
823
0
    r->timeout = reginfo->timeout;
824
0
    r->range_ubound = reginfo->range_ubound;
825
0
    r->rootoid_len = reginfo->rootoid_len;
826
827
0
    if (reginfo->handlerName != NULL) {
828
0
        r->handlerName = strdup(reginfo->handlerName);
829
0
        if (r->handlerName == NULL)
830
0
            goto err;
831
0
    }
832
833
0
    if (reginfo->contextName != NULL) {
834
0
        r->contextName = strdup(reginfo->contextName);
835
0
        if (r->contextName == NULL)
836
0
            goto err;
837
0
    }
838
839
0
    if (reginfo->rootoid != NULL) {
840
        /*
841
         * + 1 to make the following code safe:
842
         * reginfo->rootoid[reginfo->rootoid_len++] = 0;
843
         * See also netsnmp_scalar_helper_handler().
844
         */
845
0
        r->rootoid = malloc((reginfo->rootoid_len + 1) * sizeof(oid));
846
0
        if (r->rootoid == NULL)
847
0
            goto err;
848
0
        memcpy(r->rootoid, reginfo->rootoid,
849
0
               reginfo->rootoid_len * sizeof(oid));
850
0
    }
851
852
0
    r->handler = netsnmp_handler_dup(reginfo->handler);
853
0
    if (r->handler == NULL)
854
0
        goto err;
855
0
    return r;
856
857
0
err:
858
0
    netsnmp_handler_registration_free(r);
859
0
    return NULL;
860
0
}
861
862
/** Creates a cache of information which can be saved for future reference.
863
 *  The cache is filled with pointers from parameters. Note that
864
 *  the input structures are not duplicated, but put directly into
865
 *  the new cache struct.
866
 *  Use netsnmp_handler_check_cache() later to make sure it's still
867
 *  valid before referencing it in the future.
868
 *
869
 * @see netsnmp_handler_check_cache()
870
 * @see netsnmp_free_delegated_cache()
871
 */
872
NETSNMP_INLINE netsnmp_delegated_cache *
873
netsnmp_create_delegated_cache(netsnmp_mib_handler *handler,
874
                               netsnmp_handler_registration *reginfo,
875
                               netsnmp_agent_request_info *reqinfo,
876
                               netsnmp_request_info *requests,
877
                               void *localinfo)
878
0
{
879
0
    netsnmp_delegated_cache *ret;
880
881
0
    ret = SNMP_MALLOC_TYPEDEF(netsnmp_delegated_cache);
882
0
    if (ret) {
883
0
        ret->transaction_id = reqinfo->asp->pdu->transid;
884
0
        ret->handler = handler;
885
0
        ret->reginfo = reginfo;
886
0
        ret->reqinfo = reqinfo;
887
0
        ret->requests = requests;
888
0
        ret->localinfo = localinfo;
889
0
    }
890
0
    return ret;
891
0
}
892
893
/** Check if a given delegated cache is still valid.
894
 *  The cache is valid if it's a part of transaction
895
 *  (ie, the agent still considers it to be an outstanding request).
896
 *
897
 *  @param dcache is the delegated cache to be checked.
898
 *
899
 *  @return Returns the cache pointer if it is still valid, NULL otherwise.
900
 *
901
 * @see netsnmp_create_delegated_cache()
902
 * @see netsnmp_free_delegated_cache()
903
 */
904
NETSNMP_INLINE netsnmp_delegated_cache *
905
netsnmp_handler_check_cache(netsnmp_delegated_cache *dcache)
906
0
{
907
0
    if (!dcache)
908
0
        return dcache;
909
910
0
    if (netsnmp_check_transaction_id(dcache->transaction_id) ==
911
0
        SNMPERR_SUCCESS)
912
0
        return dcache;
913
914
0
    return NULL;
915
0
}
916
917
/** Free a cache once it's no longer used.
918
 *  Deletes the data allocated by netsnmp_create_delegated_cache().
919
 *  Structures which were not allocated by netsnmp_create_delegated_cache()
920
 *  are not freed (pointers are dropped).
921
 *
922
 *  @param dcache is the delegated cache to be freed.
923
 *
924
 * @see netsnmp_create_delegated_cache()
925
 * @see netsnmp_handler_check_cache()
926
 */
927
NETSNMP_INLINE void
928
netsnmp_free_delegated_cache(netsnmp_delegated_cache *dcache)
929
0
{
930
    /*
931
     * right now, no extra data is there that needs to be freed 
932
     */
933
0
    if (dcache)
934
0
        SNMP_FREE(dcache);
935
936
0
    return;
937
0
}
938
939
940
#ifndef NETSNMP_FEATURE_REMOVE_HANDLER_MARK_REQUESTS_AS_DELEGATED
941
/** Sets a list of requests as delegated or not delegated.
942
 *  Sweeps through given chain of requests and sets 'delegated'
943
 *  flag accordingly to the isdelegaded parameter.
944
 *
945
 *  @param requests Request list.
946
 *  @param isdelegated New value of the 'delegated' flag.
947
 */
948
void
949
netsnmp_handler_mark_requests_as_delegated(netsnmp_request_info *requests,
950
                                           int isdelegated)
951
0
{
952
0
    while (requests) {
953
0
        requests->delegated = isdelegated;
954
0
        requests = requests->next;
955
0
    }
956
0
}
957
#endif /* NETSNMP_FEATURE_REMOVE_HANDLER_MARK_REQUESTS_AS_DELEGATED */
958
959
/** Adds data from node list to the request information structure.
960
 *  Data in the request can be later extracted and used by submodules.
961
 *
962
 * @param request Destination request information structure.
963
 *
964
 * @param node The data to be added to the linked list
965
 *             request->parent_data.
966
 *
967
 * @see netsnmp_request_remove_list_data()
968
 * @see netsnmp_request_get_list_data()
969
 */
970
NETSNMP_INLINE void
971
netsnmp_request_add_list_data(netsnmp_request_info *request,
972
                              netsnmp_data_list *node)
973
0
{
974
0
    if (request) {
975
0
        if (request->parent_data)
976
0
            netsnmp_add_list_data(&request->parent_data, node);
977
0
        else
978
0
            request->parent_data = node;
979
0
    }
980
0
}
981
982
/** Removes all data from a request.
983
 *
984
 * @param request the netsnmp request info structure
985
 *
986
 * @param name this is the name of the previously added data
987
 *
988
 * @return 0 on successful find-and-delete, 1 otherwise.
989
 *
990
 * @see netsnmp_request_add_list_data()
991
 * @see netsnmp_request_get_list_data()
992
 */
993
NETSNMP_INLINE int
994
netsnmp_request_remove_list_data(netsnmp_request_info *request,
995
                                 const char *name)
996
0
{
997
0
    if ((NULL == request) || (NULL ==request->parent_data))
998
0
        return 1;
999
1000
0
    return netsnmp_remove_list_node(&request->parent_data, name);
1001
0
}
1002
1003
/** Extracts data from a request.
1004
 *  Retrieves data that was previously added to the request,
1005
 *  usually by a parent module.
1006
 *
1007
 * @param request Source request information structure.
1008
 *
1009
 * @param name Used to compare against the request->parent_data->name value;
1010
 *             if a match is found, request->parent_data->data is returned.
1011
 *
1012
 * @return Gives a void pointer(request->parent_data->data); NULL is
1013
 *         returned if source data is NULL or the object is not found.
1014
 *
1015
 * @see netsnmp_request_add_list_data()
1016
 * @see netsnmp_request_remove_list_data()
1017
 */
1018
void    *
1019
netsnmp_request_get_list_data(netsnmp_request_info *request,
1020
                              const char *name)
1021
0
{
1022
0
    if (request)
1023
0
        return netsnmp_get_list_data(request->parent_data, name);
1024
0
    return NULL;
1025
0
}
1026
1027
/** Free the extra data stored in a request.
1028
 *  Deletes the data in given request only. Other chain items
1029
 *  are unaffected.
1030
 *
1031
 * @param request Request information structure to be modified.
1032
 *
1033
 * @see netsnmp_request_add_list_data()
1034
 * @see netsnmp_free_list_data()
1035
 */
1036
NETSNMP_INLINE void
1037
netsnmp_free_request_data_set(netsnmp_request_info *request)
1038
0
{
1039
0
    if (request)
1040
0
        netsnmp_free_list_data(request->parent_data);
1041
0
}
1042
1043
/** Free the extra data stored in a bunch of requests.
1044
 *  Deletes all data in the chain inside request.
1045
 *
1046
 * @param request Request information structure to be modified.
1047
 *
1048
 * @see netsnmp_request_add_list_data()
1049
 * @see netsnmp_free_request_data_set()
1050
 */
1051
NETSNMP_INLINE void
1052
netsnmp_free_request_data_sets(netsnmp_request_info *request)
1053
1.03k
{
1054
1.03k
    if (request && request->parent_data) {
1055
0
        netsnmp_free_all_list_data(request->parent_data);
1056
0
        request->parent_data = NULL;
1057
0
    }
1058
1.03k
}
1059
1060
/** Returns a MIB handler from a chain based on the name.
1061
 *
1062
 * @param reginfo Handler registration struct which contains the chain.
1063
 *
1064
 * @param name Target MIB Handler name string. The name is case
1065
 *        sensitive.
1066
 *
1067
 * @return The MIB Handler is returned, or NULL if not found.
1068
 *
1069
 * @see netsnmp_request_add_list_data()
1070
 */
1071
netsnmp_mib_handler *
1072
netsnmp_find_handler_by_name(netsnmp_handler_registration *reginfo,
1073
                             const char *name)
1074
0
{
1075
0
    netsnmp_mib_handler *it;
1076
0
    if (reginfo == NULL || name == NULL )
1077
0
        return NULL;
1078
0
    for (it = reginfo->handler; it; it = it->next) {
1079
0
        if (strcmp(it->handler_name, name) == 0) {
1080
0
            return it;
1081
0
        }
1082
0
    }
1083
0
    return NULL;
1084
0
}
1085
1086
/** Returns a handler's void pointer from a chain based on the name.
1087
 *
1088
 * @warning The void pointer data may change as a handler evolves.
1089
 *        Handlers should really advertise some function for you
1090
 *        to use instead.
1091
 *
1092
 * @param reginfo Handler registration struct which contains the chain.
1093
 *
1094
 * @param name Target MIB Handler name string. The name is case
1095
 *        sensitive.
1096
 *
1097
 * @return The MIB Handler's void * pointer is returned,
1098
 *        or NULL if the handler is not found.
1099
 *
1100
 * @see netsnmp_find_handler_by_name()
1101
 */
1102
void           *
1103
netsnmp_find_handler_data_by_name(netsnmp_handler_registration *reginfo,
1104
                                  const char *name)
1105
0
{
1106
0
    netsnmp_mib_handler *it = netsnmp_find_handler_by_name(reginfo, name);
1107
0
    if (it)
1108
0
        return it->myvoid;
1109
0
    return NULL;
1110
0
}
1111
1112
/** @private
1113
 *  Clones a MIB Handler with its basic properties.
1114
 *  Creates a copy of the given MIB Handler. Copies name, flags and
1115
 *  access methods only; not myvoid.
1116
 *
1117
 *  @see netsnmp_handler_dup()
1118
 */
1119
static netsnmp_mib_handler *
1120
_clone_handler(netsnmp_mib_handler *it)
1121
0
{
1122
0
    netsnmp_mib_handler *dup;
1123
1124
0
    if(NULL == it)
1125
0
        return NULL;
1126
1127
0
    dup = netsnmp_create_handler(it->handler_name, it->access_method);
1128
0
    if(NULL != dup)
1129
0
        dup->flags = it->flags;
1130
1131
0
    return dup;
1132
0
}
1133
1134
static netsnmp_data_list *handler_reg = NULL;
1135
1136
void
1137
handler_free_callback(void *handler)
1138
19.9k
{
1139
19.9k
    netsnmp_handler_free((netsnmp_mib_handler *)handler);
1140
19.9k
}
1141
1142
/** Registers a given handler by name, so that it can be found easily later.
1143
 *  Pointer to the handler is put into a list where it can be easily located
1144
 *  at any time.
1145
 *
1146
 * @param name Name string to be associated with the handler.
1147
 *
1148
 * @param handler Pointer the MIB Handler.
1149
 *
1150
 * @see netsnmp_clear_handler_list()
1151
 */
1152
void
1153
netsnmp_register_handler_by_name(const char *name,
1154
                                 netsnmp_mib_handler *handler)
1155
19.9k
{
1156
19.9k
    netsnmp_add_list_data(&handler_reg,
1157
19.9k
                          netsnmp_create_data_list(name, (void *) handler,
1158
19.9k
                                                   handler_free_callback));
1159
19.9k
    DEBUGMSGTL(("handler_registry", "registering helper %s\n", name));
1160
19.9k
}
1161
1162
/** Clears the entire MIB Handlers registration list.
1163
 *  MIB Handlers registration list is used to access any MIB Handler by
1164
 *  its name. The function frees the list memory and sets pointer to NULL.
1165
 *  Instead of calling this function directly, use shutdown_agent().
1166
 *
1167
 *  @see shutdown_agent()
1168
 *  @see netsnmp_register_handler_by_name()
1169
 */
1170
void
1171
netsnmp_clear_handler_list(void)
1172
3.32k
{
1173
3.32k
    DEBUGMSGTL(("agent_handler", "netsnmp_clear_handler_list() called\n"));
1174
3.32k
    netsnmp_free_all_list_data(handler_reg);
1175
3.32k
    handler_reg = NULL;
1176
3.32k
}
1177
1178
/** @private
1179
 *  Injects a handler into a subtree, peers and children when a given
1180
 *  subtrees name matches a passed in name.
1181
 */
1182
void
1183
netsnmp_inject_handler_into_subtree(netsnmp_subtree *tp, const char *name,
1184
                                    netsnmp_mib_handler *handler,
1185
                                    const char *before_what)
1186
0
{
1187
0
    netsnmp_subtree *tptr;
1188
0
    netsnmp_mib_handler *mh;
1189
1190
0
    for (tptr = tp; tptr != NULL; tptr = tptr->next) {
1191
        /*  if (tptr->children) { 
1192
              netsnmp_inject_handler_into_subtree(tptr->children,name,handler);
1193
      }   */
1194
0
        if (strcmp(tptr->label_a, name) == 0) {
1195
0
            DEBUGMSGTL(("injectHandler", "injecting handler %s into %s\n",
1196
0
                        handler->handler_name, tptr->label_a));
1197
0
            netsnmp_inject_handler_before(tptr->reginfo, _clone_handler(handler),
1198
0
                                          before_what);
1199
0
        } else if (tptr->reginfo != NULL &&
1200
0
       tptr->reginfo->handlerName != NULL &&
1201
0
                   strcmp(tptr->reginfo->handlerName, name) == 0) {
1202
0
            DEBUGMSGTL(("injectHandler", "injecting handler into %s/%s\n",
1203
0
                        tptr->label_a, tptr->reginfo->handlerName));
1204
0
            netsnmp_inject_handler_before(tptr->reginfo, _clone_handler(handler),
1205
0
                                          before_what);
1206
0
        } else if (tptr->reginfo != NULL) {
1207
0
            for (mh = tptr->reginfo->handler; mh != NULL; mh = mh->next) {
1208
0
                if (mh->handler_name && strcmp(mh->handler_name, name) == 0) {
1209
0
                    DEBUGMSGTL(("injectHandler", "injecting handler into %s\n",
1210
0
                                tptr->label_a));
1211
0
                    netsnmp_inject_handler_before(tptr->reginfo,
1212
0
                                                  _clone_handler(handler),
1213
0
                                                  before_what);
1214
0
                    break;
1215
0
                } else {
1216
0
                    DEBUGMSGTL(("injectHandler",
1217
0
                                "not injecting handler into %s\n",
1218
0
                                mh->handler_name));
1219
0
                }
1220
0
            }
1221
0
        }
1222
0
    }
1223
0
}
1224
1225
static int      doneit = 0;
1226
/** @private
1227
 *  Parses the "injectHandler" token line.
1228
 */
1229
void
1230
parse_injectHandler_conf(const char *token, char *cptr)
1231
0
{
1232
0
    char            handler_to_insert[256], reg_name[256];
1233
0
    subtree_context_cache *stc;
1234
0
    netsnmp_mib_handler *handler;
1235
1236
    /*
1237
     * XXXWWW: ensure instead that handler isn't inserted twice 
1238
     */
1239
0
    if (doneit)                 /* we only do this once without restart the agent */
1240
0
        return;
1241
1242
0
    cptr = copy_nword(cptr, handler_to_insert, sizeof(handler_to_insert));
1243
0
    handler = (netsnmp_mib_handler*)netsnmp_get_list_data(handler_reg, handler_to_insert);
1244
0
    if (!handler) {
1245
0
  netsnmp_config_error("no \"%s\" handler registered.",
1246
0
           handler_to_insert);
1247
0
        return;
1248
0
    }
1249
1250
0
    if (!cptr) {
1251
0
        config_perror("no INTONAME specified.  Can't do insertion.");
1252
0
        return;
1253
0
    }
1254
0
    cptr = copy_nword(cptr, reg_name, sizeof(reg_name));
1255
1256
0
    for (stc = get_top_context_cache(); stc; stc = stc->next) {
1257
0
        DEBUGMSGTL(("injectHandler", "Checking context tree %s (before=%s)\n",
1258
0
                    stc->context_name, (cptr)?cptr:"null"));
1259
0
        netsnmp_inject_handler_into_subtree(stc->first_subtree, reg_name,
1260
0
                                            handler, cptr);
1261
0
    }
1262
0
}
1263
1264
/** @private
1265
 *  Callback to ensure injectHandler parser doesn't do things twice.
1266
 *  @todo replace this with a method to check the handler chain instead.
1267
 */
1268
static int
1269
handler_mark_inject_handler_done(int majorID, int minorID,
1270
                    void *serverarg, void *clientarg)
1271
3.32k
{
1272
3.32k
    doneit = 1;
1273
3.32k
    return 0;
1274
3.32k
}
1275
1276
/** @private
1277
 *  Registers the injectHandle parser token.
1278
 *  Used in init_agent_read_config().
1279
 *
1280
 *  @see init_agent_read_config()
1281
 */
1282
void
1283
netsnmp_init_handler_conf(void)
1284
3.32k
{
1285
3.32k
    snmpd_register_config_handler("injectHandler",
1286
3.32k
                                  parse_injectHandler_conf,
1287
3.32k
                                  NULL, "injectHandler NAME INTONAME [BEFORE_OTHER_NAME]");
1288
3.32k
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
1289
3.32k
                           SNMP_CALLBACK_POST_READ_CONFIG,
1290
3.32k
                           handler_mark_inject_handler_done, NULL);
1291
1292
3.32k
    se_add_pair_to_slist("agent_mode", strdup("GET"), MODE_GET);
1293
3.32k
    se_add_pair_to_slist("agent_mode", strdup("GETNEXT"), MODE_GETNEXT);
1294
3.32k
    se_add_pair_to_slist("agent_mode", strdup("GETBULK"), MODE_GETBULK);
1295
3.32k
#ifndef NETSNMP_NO_WRITE_SUPPORT
1296
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_BEGIN"),
1297
3.32k
                         MODE_SET_BEGIN);
1298
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_RESERVE1"),
1299
3.32k
                         MODE_SET_RESERVE1);
1300
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_RESERVE2"),
1301
3.32k
                         MODE_SET_RESERVE2);
1302
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_ACTION"),
1303
3.32k
                         MODE_SET_ACTION);
1304
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_COMMIT"),
1305
3.32k
                         MODE_SET_COMMIT);
1306
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_FREE"), MODE_SET_FREE);
1307
3.32k
    se_add_pair_to_slist("agent_mode", strdup("SET_UNDO"), MODE_SET_UNDO);
1308
1309
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("pre-request"),
1310
3.32k
                         MODE_BSTEP_PRE_REQUEST);
1311
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("object_lookup"),
1312
3.32k
                         MODE_BSTEP_OBJECT_LOOKUP);
1313
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("check_value"),
1314
3.32k
                         MODE_BSTEP_CHECK_VALUE);
1315
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("row_create"),
1316
3.32k
                         MODE_BSTEP_ROW_CREATE);
1317
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("undo_setup"),
1318
3.32k
                         MODE_BSTEP_UNDO_SETUP);
1319
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("set_value"),
1320
3.32k
                         MODE_BSTEP_SET_VALUE);
1321
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("check_consistency"),
1322
3.32k
                         MODE_BSTEP_CHECK_CONSISTENCY);
1323
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("undo_set"),
1324
3.32k
                         MODE_BSTEP_UNDO_SET);
1325
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("commit"),
1326
3.32k
                         MODE_BSTEP_COMMIT);
1327
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("undo_commit"),
1328
3.32k
                         MODE_BSTEP_UNDO_COMMIT);
1329
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("irreversible_commit"),
1330
3.32k
                         MODE_BSTEP_IRREVERSIBLE_COMMIT);
1331
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("undo_cleanup"),
1332
3.32k
                         MODE_BSTEP_UNDO_CLEANUP);
1333
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("post_request"),
1334
3.32k
                         MODE_BSTEP_POST_REQUEST);
1335
3.32k
    se_add_pair_to_slist("babystep_mode", strdup("original"), 0xffff);
1336
3.32k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1337
1338
    /*
1339
     * xxx-rks: hmmm.. will this work for modes which are or'd together?
1340
     *          I'm betting not...
1341
     */
1342
3.32k
    se_add_pair_to_slist("handler_can_mode", strdup("GET/GETNEXT"),
1343
3.32k
                         HANDLER_CAN_GETANDGETNEXT);
1344
3.32k
    se_add_pair_to_slist("handler_can_mode", strdup("SET"),
1345
3.32k
                         HANDLER_CAN_SET);
1346
3.32k
    se_add_pair_to_slist("handler_can_mode", strdup("GETBULK"),
1347
3.32k
                         HANDLER_CAN_GETBULK);
1348
3.32k
    se_add_pair_to_slist("handler_can_mode", strdup("BABY_STEP"),
1349
3.32k
                         HANDLER_CAN_BABY_STEP);
1350
3.32k
}
1351
1352
/** @} */