Coverage Report

Created: 2024-09-11 06:05

/src/net-snmp/agent/snmp_agent.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * snmp_agent.c
3
 *
4
 * Simple Network Management Protocol (RFC 1067).
5
 */
6
/* Portions of this file are subject to the following copyrights.  See
7
 * the Net-SNMP's COPYING file for more details and other copyrights
8
 * that may apply:
9
 */
10
/***********************************************************
11
  Copyright 1988, 1989 by Carnegie Mellon University
12
13
                      All Rights Reserved
14
15
Permission to use, copy, modify, and distribute this software and its 
16
documentation for any purpose and without fee is hereby granted, 
17
provided that the above copyright notice appear in all copies and that
18
both that copyright notice and this permission notice appear in 
19
supporting documentation, and that the name of CMU not be
20
used in advertising or publicity pertaining to distribution of the
21
software without specific, written prior permission.  
22
23
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29
SOFTWARE.
30
******************************************************************/
31
/*
32
 * Portions of this file are copyrighted by:
33
 * Copyright © 2003 Sun Microsystems, Inc. All rights 
34
 * reserved.  Use is subject to license terms specified in the 
35
 * COPYING file distributed with the Net-SNMP package.
36
 *
37
 * Portions of this file are copyrighted by:
38
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
39
 * Use is subject to license terms specified in the COPYING file
40
 * distributed with the Net-SNMP package.
41
 */
42
/** @defgroup snmp_agent net-snmp agent related processing 
43
 *  @ingroup agent
44
 *
45
 * @{
46
 */
47
#include <net-snmp/net-snmp-config.h>
48
#include <net-snmp/net-snmp-features.h>
49
50
#include <sys/types.h>
51
#ifdef HAVE_LIMITS_H
52
#include <limits.h>
53
#endif
54
#ifdef HAVE_STDLIB_H
55
#include <stdlib.h>
56
#endif
57
#ifdef HAVE_UNISTD_H
58
#include <unistd.h>
59
#endif
60
#ifdef HAVE_STRING_H
61
#include <string.h>
62
#endif
63
#ifdef TIME_WITH_SYS_TIME
64
# include <sys/time.h>
65
# include <time.h>
66
#else
67
# ifdef HAVE_SYS_TIME_H
68
#  include <sys/time.h>
69
# else
70
#  include <time.h>
71
# endif
72
#endif
73
#ifdef HAVE_SYS_SELECT_H
74
#include <sys/select.h>
75
#endif
76
#ifdef HAVE_NETINET_IN_H
77
#include <netinet/in.h>
78
#endif
79
#include <errno.h>
80
81
#define SNMP_NEED_REQUEST_LIST
82
#include <net-snmp/net-snmp-includes.h>
83
#include <net-snmp/agent/net-snmp-agent-includes.h>
84
#include <net-snmp/agent/agent_callbacks.h>
85
#include <net-snmp/library/large_fd_set.h>
86
#include <net-snmp/library/snmp_assert.h>
87
#include "agent_global_vars.h"
88
89
#ifdef HAVE_SYSLOG_H
90
#include <syslog.h>
91
#endif
92
93
#ifdef NETSNMP_USE_LIBWRAP
94
#include <tcpd.h>
95
int             allow_severity = LOG_INFO;
96
int             deny_severity = LOG_WARNING;
97
#endif
98
99
#include "snmpd.h"
100
#include <net-snmp/agent/mib_module_config.h>
101
#include <net-snmp/agent/mib_modules.h>
102
103
#ifdef USING_AGENTX_PROTOCOL_MODULE
104
#include "agentx/protocol.h"
105
#endif
106
107
#ifdef USING_AGENTX_MASTER_MODULE
108
#include "agentx/master.h"
109
#endif
110
111
#ifdef USING_SMUX_MODULE
112
#include "smux/smux.h"
113
#endif
114
115
netsnmp_feature_child_of(snmp_agent, libnetsnmpagent);
116
netsnmp_feature_child_of(agent_debugging_utilities, libnetsnmpagent);
117
118
netsnmp_feature_child_of(allocate_globalcacheid, snmp_agent);
119
netsnmp_feature_child_of(free_agent_snmp_session_by_session, snmp_agent);
120
netsnmp_feature_child_of(check_all_requests_error, snmp_agent);
121
netsnmp_feature_child_of(check_requests_error, snmp_agent);
122
netsnmp_feature_child_of(request_set_error_idx, snmp_agent);
123
netsnmp_feature_child_of(set_agent_uptime, snmp_agent);
124
netsnmp_feature_child_of(agent_check_and_process, snmp_agent);
125
126
netsnmp_feature_child_of(dump_sess_list, agent_debugging_utilities);
127
128
netsnmp_feature_child_of(agent_remove_list_data, netsnmp_unused);
129
netsnmp_feature_child_of(set_all_requests_error, netsnmp_unused);
130
netsnmp_feature_child_of(addrcache_age, netsnmp_unused);
131
netsnmp_feature_child_of(delete_subtree_cache, netsnmp_unused);
132
133
#ifndef NETSNMP_NO_PDU_STATS
134
135
static netsnmp_container *_pdu_stats = NULL;
136
static int _pdu_stats_max = 0;
137
static u_long _pdu_stats_threshold = 0;
138
static u_long _pdu_stats_current_lowest = 0;
139
140
netsnmp_container *
141
netsnmp_get_pdu_stats(void)
142
0
{
143
0
    return _pdu_stats;
144
0
}
145
146
int _pdu_stats_compare(const void *p, const void *q)
147
0
{
148
0
    const netsnmp_pdu_stats *lhs = p, *rhs = q;
149
150
0
    if (NULL == lhs || NULL == rhs) {
151
0
        snmp_log(LOG_WARNING,
152
0
                 "WARNING: results undefined for compares with NULL\n");
153
0
        return 0;
154
0
    }
155
156
    /** we want list sorted in reverse order, so invert tests */
157
0
    if (lhs->processing_time > rhs->processing_time)
158
0
        return -1;
159
0
    else if (lhs->processing_time < rhs->processing_time)
160
0
        return 1;
161
162
0
    if (lhs->timestamp > rhs->timestamp)
163
0
        return -1;
164
0
    else if (lhs->timestamp < rhs->timestamp)
165
0
        return 1;
166
167
0
    return 0;
168
0
}
169
170
171
static void
172
2.62k
_pdu_stats_init(void) {
173
2.62k
    static int done = 0;
174
2.62k
    if ((NULL != _pdu_stats) || (++done != 1))
175
2.62k
        return;
176
177
1
    _pdu_stats = netsnmp_container_find("netsnmp_pdustats:binary_array");
178
1
    if (NULL == _pdu_stats) {
179
0
        done = 0;
180
0
        return;
181
0
    }
182
183
1
    _pdu_stats->compare = _pdu_stats_compare;
184
1
    _pdu_stats->get_subset = NULL; /** subsets not supported */
185
186
1
    _pdu_stats_max = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
187
1
                                        NETSNMP_DS_AGENT_PDU_STATS_MAX);
188
1
    _pdu_stats_threshold =
189
1
        netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
190
1
                           NETSNMP_DS_AGENT_PDU_STATS_THRESHOLD);
191
1
    if (_pdu_stats_threshold < 100)
192
1
        _pdu_stats_threshold = 100;
193
1
    DEBUGMSGTL(("stats:pdu", "max: %d, threshold %ld ms\n", _pdu_stats_max,
194
1
                _pdu_stats_threshold));
195
1
}
196
197
198
static void
199
_pdu_stats_shutdown(void)
200
2.62k
{
201
2.62k
    netsnmp_pdu_stats *entry;
202
2.62k
    int x = 0;
203
204
2.62k
    if (NULL == _pdu_stats)
205
2.62k
        return;
206
207
1
    for( ; x < CONTAINER_SIZE(_pdu_stats); ++x) {
208
0
        CONTAINER_GET_AT(_pdu_stats, x, (void**)&entry);
209
0
        if (NULL == entry)
210
0
            continue;
211
0
        snmp_free_pdu(entry->pdu);
212
0
        free(entry);
213
0
    }
214
1
    CONTAINER_FREE(_pdu_stats);
215
1
    _pdu_stats = NULL;
216
1
}
217
218
219
static void
220
_dump_pdu_stats(void)
221
0
{
222
0
    int x = 0;
223
0
    struct tm *tm;
224
0
    char timestr[40];
225
0
    netsnmp_pdu_stats *entry;
226
227
0
    for( ; x < CONTAINER_SIZE(_pdu_stats); ++x) {
228
0
        netsnmp_pdu    *response;
229
0
        netsnmp_variable_list *vars;
230
0
        CONTAINER_GET_AT(_pdu_stats, x, (void**)&entry);
231
0
        if (NULL == entry) {
232
0
            DEBUGMSGT_NC(("9:stats:pdu", "[%d] ERROR\n", x));
233
0
            continue;
234
0
        }
235
0
        tm = localtime(&entry->timestamp);
236
0
        if (NULL == tm)
237
0
            sprintf(timestr, "UNKNOWN");
238
0
        else if (strftime(timestr, sizeof(timestr), "%m/%d/%Y %H:%M:%S",
239
0
                          tm) == 0)
240
0
            sprintf(timestr, "UNKNOWN");
241
242
0
        DEBUGMSGT_NC(("9:stats:pdu", "[%d] %ld ms, %s\n",
243
0
                      x, entry->processing_time, timestr));
244
0
        response = entry->pdu;
245
0
        if (response->errstat == SNMP_ERR_NOERROR) {
246
0
            for (vars = response->variables; vars;
247
0
                 vars = vars->next_variable) {
248
0
                DEBUGMSGT_NC(("9:stats:pdu", "    vb "));
249
0
                DEBUGMSGVAR(("9:stats:pdu", vars));
250
0
                DEBUGMSG_NC(("9:stats:pdu", "\n"));
251
0
            }
252
0
        } else {
253
0
            DEBUGMSGT_NC(("9:stats:pdu", "Error in packet: Reason: %s\n",
254
0
                          snmp_errstring(response->errstat)));
255
0
            if (response->errindex != 0) {
256
0
                int count;
257
0
                DEBUGMSGT_NC(("9:stats:pdu", "Failed object: "));
258
0
                for (count = 1, vars = response->variables;
259
0
                     vars && count != response->errindex;
260
0
                     vars = vars->next_variable, count++)
261
0
                    /*EMPTY*/;
262
0
                if (vars) {
263
0
                    DEBUGMSGOID(("9:stats:pdu", vars->name,
264
0
                                 vars->name_length));
265
0
                }
266
0
                DEBUGMSG_NC(("9:stats:pdu", "\n"));
267
0
            }
268
0
        }
269
0
    }
270
0
}
271
#endif /* NETSNMP_NO_PDU_STATS */
272
273
274
NETSNMP_INLINE void
275
netsnmp_agent_add_list_data(netsnmp_agent_request_info *ari,
276
                            netsnmp_data_list *node)
277
0
{
278
0
    if (ari) {
279
0
  if (ari->agent_data) {
280
0
            netsnmp_add_list_data(&ari->agent_data, node);
281
0
        } else {
282
0
            ari->agent_data = node;
283
0
  }
284
0
    }
285
0
}
286
287
#ifndef NETSNMP_FEATURE_REMOVE_AGENT_REMOVE_LIST_DATA
288
NETSNMP_INLINE int
289
netsnmp_agent_remove_list_data(netsnmp_agent_request_info *ari,
290
                               const char * name)
291
0
{
292
0
    if ((NULL == ari) || (NULL == ari->agent_data))
293
0
        return 1;
294
295
0
    return netsnmp_remove_list_node(&ari->agent_data, name);
296
0
}
297
#endif /* NETSNMP_FEATURE_REMOVE_AGENT_REMOVE_LIST_DATA */
298
299
NETSNMP_INLINE void    *
300
netsnmp_agent_get_list_data(netsnmp_agent_request_info *ari,
301
                            const char *name)
302
0
{
303
0
    if (ari) {
304
0
        return netsnmp_get_list_data(ari->agent_data, name);
305
0
    }
306
0
    return NULL;
307
0
}
308
309
NETSNMP_INLINE void
310
netsnmp_free_agent_data_set(netsnmp_agent_request_info *ari)
311
0
{
312
0
    if (ari) {
313
0
        netsnmp_free_list_data(ari->agent_data);
314
0
    }
315
0
}
316
317
NETSNMP_INLINE void
318
netsnmp_free_agent_data_sets(netsnmp_agent_request_info *ari)
319
0
{
320
0
    if (ari) {
321
0
        netsnmp_free_all_list_data(ari->agent_data);
322
0
    }
323
0
}
324
325
NETSNMP_INLINE void
326
netsnmp_free_agent_request_info(netsnmp_agent_request_info *ari)
327
9.90k
{
328
9.90k
    if (ari) {
329
9.90k
        if (ari->agent_data) {
330
0
            netsnmp_free_all_list_data(ari->agent_data);
331
0
  }
332
9.90k
        SNMP_FREE(ari);
333
9.90k
    }
334
9.90k
}
335
336
const oid version_sysoid[] = { NETSNMP_SYSTEM_MIB };
337
const int version_sysoid_len = OID_LENGTH(version_sysoid);
338
339
28.8k
#define SNMP_ADDRCACHE_SIZE 10
340
0
#define SNMP_ADDRCACHE_MAXAGE 300 /* in seconds */
341
342
enum {
343
    SNMP_ADDRCACHE_UNUSED = 0,
344
    SNMP_ADDRCACHE_USED = 1
345
};
346
347
struct addrCache {
348
    char           *addr;
349
    int            status;
350
    struct timeval lastHitM;
351
};
352
353
static struct addrCache addrCache[SNMP_ADDRCACHE_SIZE];
354
int             log_addresses = 0;
355
356
357
358
typedef struct _agent_nsap {
359
    int             handle;
360
    netsnmp_transport *t;
361
    void           *s;          /*  Opaque internal session pointer.  */
362
    struct _agent_nsap *next;
363
} agent_nsap;
364
365
static agent_nsap *agent_nsap_list = NULL;
366
static netsnmp_agent_session *agent_session_list = NULL;
367
netsnmp_agent_session *netsnmp_processing_set = NULL;
368
netsnmp_agent_session *agent_delegated_list = NULL;
369
netsnmp_agent_session *netsnmp_agent_queued_list = NULL;
370
371
372
int             handle_pdu(netsnmp_agent_session *asp);
373
int             netsnmp_handle_request(netsnmp_agent_session *asp,
374
                                       int status);
375
int             check_delayed_request(netsnmp_agent_session *asp);
376
int             handle_getnext_loop(netsnmp_agent_session *asp);
377
int             handle_set_loop(netsnmp_agent_session *asp);
378
379
int             netsnmp_remove_from_delegated(netsnmp_agent_session *asp);
380
381
382
int      netsnmp_running = 1;
383
384
#ifndef NETSNMP_FEATURE_REMOVE_ALLOCATE_GLOBALCACHEID
385
static int      current_globalid = 0;
386
387
int
388
netsnmp_allocate_globalcacheid(void)
389
0
{
390
0
    return ++current_globalid;
391
0
}
392
#endif /* NETSNMP_FEATURE_REMOVE_ALLOCATE_GLOBALCACHEID */
393
394
int
395
netsnmp_get_local_cachid(netsnmp_cachemap *cache_store, int globalid)
396
0
{
397
0
    while (cache_store != NULL) {
398
0
        if (cache_store->globalid == globalid)
399
0
            return cache_store->cacheid;
400
0
        cache_store = cache_store->next;
401
0
    }
402
0
    return -1;
403
0
}
404
405
netsnmp_cachemap *
406
netsnmp_get_or_add_local_cachid(netsnmp_cachemap **cache_store,
407
                                int globalid, int localid)
408
0
{
409
0
    netsnmp_cachemap *tmpp;
410
411
0
    tmpp = SNMP_MALLOC_TYPEDEF(netsnmp_cachemap);
412
0
    if (tmpp != NULL) {
413
0
        if (*cache_store) {
414
0
            tmpp->next = *cache_store;
415
0
            *cache_store = tmpp;
416
0
        } else {
417
0
            *cache_store = tmpp;
418
0
        }
419
420
0
        tmpp->globalid = globalid;
421
0
        tmpp->cacheid = localid;
422
0
    }
423
0
    return tmpp;
424
0
}
425
426
void
427
netsnmp_free_cachemap(netsnmp_cachemap *cache_store)
428
0
{
429
0
    netsnmp_cachemap *tmpp;
430
0
    while (cache_store) {
431
0
        tmpp = cache_store;
432
0
        cache_store = cache_store->next;
433
0
        SNMP_FREE(tmpp);
434
0
    }
435
0
}
436
437
438
typedef struct agent_set_cache_s {
439
    /*
440
     * match on these 2 
441
     */
442
    int             transID;
443
    netsnmp_session *sess;
444
445
    /*
446
     * store this info 
447
     */
448
    netsnmp_tree_cache *treecache;
449
    int             treecache_len;
450
    int             treecache_num;
451
452
    int             vbcount;
453
    netsnmp_request_info *requests;
454
    netsnmp_variable_list *saved_vars;
455
    netsnmp_data_list *agent_data;
456
457
    /*
458
     * list 
459
     */
460
    struct agent_set_cache_s *next;
461
} agent_set_cache;
462
463
static agent_set_cache *Sets = NULL;
464
465
agent_set_cache *
466
save_set_cache(netsnmp_agent_session *asp)
467
7.03k
{
468
7.03k
    agent_set_cache *ptr;
469
470
7.03k
    if (!asp || !asp->reqinfo || !asp->pdu)
471
0
        return NULL;
472
473
7.03k
    ptr = SNMP_MALLOC_TYPEDEF(agent_set_cache);
474
7.03k
    if (ptr == NULL)
475
0
        return NULL;
476
477
    /*
478
     * Save the important information 
479
     */
480
7.03k
    DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p saved in cache (mode %d)\n",
481
7.03k
                asp, asp->reqinfo, asp->pdu->command));
482
7.03k
    ptr->transID = asp->pdu->transid;
483
7.03k
    ptr->sess = asp->session;
484
7.03k
    ptr->treecache = asp->treecache;
485
7.03k
    ptr->treecache_len = asp->treecache_len;
486
7.03k
    ptr->treecache_num = asp->treecache_num;
487
7.03k
    ptr->agent_data = asp->reqinfo->agent_data;
488
7.03k
    ptr->requests = asp->requests;
489
7.03k
    ptr->saved_vars = asp->pdu->variables; /* requests contains pointers to variables */
490
7.03k
    ptr->vbcount = asp->vbcount;
491
492
    /*
493
     * make the agent forget about what we've saved 
494
     */
495
7.03k
    asp->treecache = NULL;
496
7.03k
    asp->reqinfo->agent_data = NULL;
497
7.03k
    asp->pdu->variables = NULL;
498
7.03k
    asp->requests = NULL;
499
500
7.03k
    ptr->next = Sets;
501
7.03k
    Sets = ptr;
502
503
7.03k
    return ptr;
504
7.03k
}
505
506
int
507
get_set_cache(netsnmp_agent_session *asp)
508
496
{
509
496
    agent_set_cache *ptr, *prev = NULL;
510
511
496
    for (ptr = Sets; ptr != NULL; ptr = ptr->next) {
512
496
        if (ptr->sess == asp->session && ptr->transID == asp->pdu->transid) {
513
            /*
514
             * remove this item from list
515
             */
516
496
            if (prev)
517
0
                prev->next = ptr->next;
518
496
            else
519
496
                Sets = ptr->next;
520
521
            /*
522
             * found it.  Get the needed data 
523
             */
524
496
            asp->treecache = ptr->treecache;
525
496
            asp->treecache_len = ptr->treecache_len;
526
496
            asp->treecache_num = ptr->treecache_num;
527
528
            /*
529
             * Free previously allocated requests before overwriting by
530
             * cached ones, otherwise memory leaks!
531
             */
532
496
      if (asp->requests) {
533
                /*
534
                 * I don't think this case should ever happen. Please email
535
                 * the net-snmp-coders@lists.sourceforge.net if you have
536
                 * a test case that hits this condition. -- rstory
537
                 */
538
0
    int i;
539
0
                netsnmp_assert(NULL == asp->requests); /* see note above */
540
0
    for (i = 0; i < asp->vbcount; i++) {
541
0
        netsnmp_free_request_data_sets(&asp->requests[i]);
542
0
    }
543
0
    free(asp->requests);
544
0
      }
545
      /*
546
       * If we replace asp->requests with the info from the set cache,
547
       * we should replace asp->pdu->variables also with the cached
548
       * info, as asp->requests contains pointers to them.  And we
549
       * should also free the current asp->pdu->variables list...
550
       */
551
496
      if (ptr->saved_vars) {
552
0
    if (asp->pdu->variables)
553
0
        snmp_free_varbind(asp->pdu->variables);
554
0
    asp->pdu->variables = ptr->saved_vars;
555
0
                asp->vbcount = ptr->vbcount;
556
0
            }
557
496
            asp->requests = ptr->requests;
558
559
496
            netsnmp_assert(NULL != asp->reqinfo);
560
496
            asp->reqinfo->asp = asp;
561
496
            asp->reqinfo->agent_data = ptr->agent_data;
562
            
563
            /*
564
             * update request reqinfo, if it's out of date.
565
             * yyy-rks: investigate when/why sometimes they match,
566
             * sometimes they don't.
567
             */
568
496
            if(asp->requests && asp->requests->agent_req_info != asp->reqinfo) {
569
                /*
570
                 * - one don't match case: agentx subagents. prev asp & reqinfo
571
                 *   freed, request reqinfo ptrs not cleared.
572
                 */
573
493
                netsnmp_request_info *tmp = asp->requests;
574
493
                DEBUGMSGTL(("verbose:asp",
575
493
                            "  reqinfo %p doesn't match cached reqinfo %p\n",
576
493
                            asp->reqinfo, asp->requests->agent_req_info));
577
986
                for(; tmp; tmp = tmp->next)
578
493
                    tmp->agent_req_info = asp->reqinfo;
579
493
            } else if (asp->requests) {
580
                /*
581
                 * - match case: ?
582
                 */
583
3
                DEBUGMSGTL(("verbose:asp",
584
3
                            "  reqinfo %p matches cached reqinfo %p\n",
585
3
                            asp->reqinfo, asp->requests->agent_req_info));
586
3
            } else {
587
0
                DEBUGMSGTL(("verbose:asp", "  asp->requests is NULL\n"));
588
0
            }
589
590
496
            SNMP_FREE(ptr);
591
496
            return SNMP_ERR_NOERROR;
592
496
        }
593
0
        prev = ptr;
594
0
    }
595
0
    return SNMP_ERR_GENERR;
596
496
}
597
598
/* Bulkcache holds the values for the *repeating* varbinds (only),
599
 *   but ordered "by column" - i.e. the repetitions for each
600
 *   repeating varbind follow on immediately from one another,
601
 *   rather than being interleaved, as required by the protocol.
602
 *
603
 * So we need to rearrange the varbind list so it's ordered "by row".
604
 *
605
 * In the following code chunk:
606
 *     n            = # non-repeating varbinds
607
 *     r            = # repeating varbinds
608
 *     asp->vbcount = # varbinds in the incoming PDU
609
 *         (So asp->vbcount = n+r)
610
 *
611
 *     repeats = Desired # of repetitions (of 'r' varbinds)
612
 */
613
NETSNMP_STATIC_INLINE void
614
_reorder_getbulk(netsnmp_agent_session *asp)
615
551
{
616
551
    int             i, n = 0, r = 0;
617
551
    int             repeats;
618
551
    int             j, k;
619
551
    int             all_eoMib;
620
551
    netsnmp_variable_list *prev = NULL, *curr;
621
622
551
    if (NULL == asp || NULL == asp->pdu || asp->vbcount == 0)
623
354
        return;
624
625
197
    if (asp->pdu->errstat < asp->vbcount) {
626
119
        n = asp->pdu->errstat;
627
119
    } else {
628
78
        n = asp->vbcount;
629
78
    }
630
197
    if ((r = asp->vbcount - n) < 0) {
631
0
        r = 0;
632
0
    }
633
634
197
    DEBUGMSGTL(("snmp_agent:bulk", "reorder n=%d, r=%d\n", n, r));
635
636
    /* we do nothing if there is nothing repeated */
637
197
    if (r == 0)
638
78
        return;
639
640
119
    repeats = asp->pdu->errindex;
641
    /* Fix endOfMibView entries. */
642
316
    for (i = 0; i < r; i++) {
643
197
        prev = NULL;
644
7.81k
        for (j = 0; j < repeats; j++) {
645
7.61k
      curr = asp->bulkcache[i * repeats + j];
646
            /*
647
             *  If we don't have a valid name for a given repetition
648
             *   (and probably for all the ones that follow as well),
649
             *   extend the previous result to indicate 'endOfMibView'.
650
             *  Or if the repetition already has type endOfMibView make
651
             *   sure it has the correct objid (i.e. that of the previous
652
             *   entry or that of the original request).
653
             */
654
7.61k
            if (curr->name_length == 0 || curr->type == SNMP_ENDOFMIBVIEW) {
655
7.61k
    if (prev == NULL) {
656
        /* Use objid from original pdu. */
657
197
        prev = asp->orig_pdu->variables;
658
312
        for (k = i; prev && k > 0; k--)
659
115
      prev = prev->next_variable;
660
197
    }
661
7.61k
    if (prev) {
662
7.61k
        snmp_set_var_objid(curr, prev->name, prev->name_length);
663
7.61k
        snmp_set_var_typed_value(curr, SNMP_ENDOFMIBVIEW, NULL, 0);
664
7.61k
    }
665
7.61k
            }
666
7.61k
            prev = curr;
667
7.61k
        }
668
197
    }
669
670
    /*
671
     * For each of the original repeating varbinds (except the last),
672
     *  go through the block of results for that varbind,
673
     *  and link each instance to the corresponding instance
674
     *  in the next block.
675
     */
676
197
    for (i = 0; i < r - 1; i++) {
677
1.69k
        for (j = 0; j < repeats; j++) {
678
1.61k
            asp->bulkcache[i * repeats + j]->next_variable =
679
1.61k
                asp->bulkcache[(i + 1) * repeats + j];
680
1.61k
        }
681
78
    }
682
683
    /*
684
     * For the last of the original repeating varbinds,
685
     *  go through that block of results, and link each
686
     *  instance to the *next* instance in the *first* block.
687
     *
688
     * The very last instance of this block is left untouched
689
     *  since it (correctly) points to the end of the list.
690
     */
691
6.00k
    for (j = 0; j < repeats - 1; j++) {
692
5.88k
  asp->bulkcache[(r - 1) * repeats + j]->next_variable = 
693
5.88k
      asp->bulkcache[j + 1];
694
5.88k
    }
695
696
    /*
697
     * If we've got a full row of endOfMibViews, then we
698
     *  can truncate the result varbind list after that.
699
     *
700
     * Look for endOfMibView exception values in the list of
701
     *  repetitions for the first varbind, and check the 
702
     *  corresponding instances for the other varbinds
703
     *  (following the next_variable links).
704
     *
705
     * If they're all endOfMibView too, then we can terminate
706
     *  the linked list there, and free any redundant varbinds.
707
     */
708
119
    all_eoMib = 0;
709
119
    for (i = 0; i < repeats; i++) {
710
119
        if (asp->bulkcache[i]->type == SNMP_ENDOFMIBVIEW) {
711
119
            all_eoMib = 1;
712
119
            for (j = 1, prev=asp->bulkcache[i];
713
197
                 j < r;
714
119
                 j++, prev=prev->next_variable) {
715
78
                if (prev->type != SNMP_ENDOFMIBVIEW) {
716
0
                    all_eoMib = 0;
717
0
                    break;  /* Found a real value */
718
0
                }
719
78
            }
720
119
            if (all_eoMib) {
721
                /*
722
                 * This is indeed a full endOfMibView row.
723
                 * Terminate the list here & free the rest.
724
                 */
725
119
                snmp_free_varbind( prev->next_variable );
726
119
                prev->next_variable = NULL;
727
119
                break;
728
119
            }
729
119
        }
730
119
    }
731
119
}
732
733
734
/* EndOfMibView replies to a GETNEXT request should according to RFC3416
735
 *  have the object ID set to that of the request. Our tree search 
736
 *  algorithm will sometimes break that requirement. This function will
737
 *  fix that.
738
 */
739
NETSNMP_STATIC_INLINE void
740
_fix_endofmibview(netsnmp_agent_session *asp)
741
95
{
742
95
    netsnmp_variable_list *vb, *ovb;
743
744
95
    if (asp->vbcount == 0)  /* Nothing to do! */
745
61
        return;
746
747
34
    for (vb = asp->pdu->variables, ovb = asp->orig_pdu->variables;
748
78
   vb && ovb; vb = vb->next_variable, ovb = ovb->next_variable) {
749
44
  if (vb->type == SNMP_ENDOFMIBVIEW)
750
44
      snmp_set_var_objid(vb, ovb->name, ovb->name_length);
751
44
    }
752
34
}
753
754
#ifndef NETSNMP_FEATURE_REMOVE_AGENT_CHECK_AND_PROCESS
755
/**
756
 * This function checks for packets arriving on the SNMP port and
757
 * processes them(snmp_read) if some are found, using the select(). If block
758
 * is non zero, the function call blocks until a packet arrives
759
 *
760
 * @param block used to control blocking in the select() function, 1 = block
761
 *        forever, and 0 = don't block
762
 *
763
 * @return  Returns a positive integer if packets were processed, and -1 if an
764
 * error was found.
765
 *
766
 */
767
int
768
agent_check_and_process(int block)
769
0
{
770
0
    int                  numfds;
771
0
    netsnmp_large_fd_set readfds;
772
0
    netsnmp_large_fd_set writefds;
773
0
    netsnmp_large_fd_set exceptfds;
774
0
    struct timeval       timeout = { LONG_MAX, 0 }, *tvp = &timeout;
775
0
    int                  count;
776
0
    int                  fakeblock = 0;
777
778
0
    numfds = 0;
779
0
    netsnmp_large_fd_set_init(&readfds, FD_SETSIZE);
780
0
    netsnmp_large_fd_set_init(&writefds, FD_SETSIZE);
781
0
    netsnmp_large_fd_set_init(&exceptfds, FD_SETSIZE);
782
0
    NETSNMP_LARGE_FD_ZERO(&readfds);
783
0
    NETSNMP_LARGE_FD_ZERO(&writefds);
784
0
    NETSNMP_LARGE_FD_ZERO(&exceptfds);
785
0
    snmp_select_info2(&numfds, &readfds, tvp, &fakeblock);
786
0
    if (block != 0 && fakeblock != 0) {
787
        /*
788
         * There are no alarms registered, and the caller asked for blocking, so
789
         * let select() block forever.  
790
         */
791
792
0
        tvp = NULL;
793
0
    } else if (block != 0 && fakeblock == 0) {
794
        /*
795
         * The caller asked for blocking, but there is an alarm due sooner than
796
         * LONG_MAX seconds from now, so use the modified timeout returned by
797
         * snmp_select_info as the timeout for select().  
798
         */
799
800
0
    } else if (block == 0) {
801
        /*
802
         * The caller does not want us to block at all.  
803
         */
804
805
0
        timerclear(tvp);
806
0
    }
807
808
0
#ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
809
0
    netsnmp_external_event_info2(&numfds, &readfds, &writefds, &exceptfds);
810
0
#endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
811
812
0
    count = netsnmp_large_fd_set_select(numfds, &readfds, &writefds, &exceptfds, tvp);
813
814
0
    if (count > 0) {
815
        /*
816
         * packets found, process them 
817
         */
818
0
#ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
819
0
        netsnmp_dispatch_external_events2(&count, &readfds, &writefds, &exceptfds);
820
0
#endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
821
822
0
        snmp_read2(&readfds);
823
0
    } else
824
0
        switch (count) {
825
0
        case 0:
826
0
            snmp_timeout();
827
0
            break;
828
0
        case -1:
829
0
            if (errno != EINTR) {
830
0
                snmp_log_perror("select");
831
0
            }
832
0
            count = -1;
833
0
            goto exit;
834
0
        default:
835
0
            snmp_log(LOG_ERR, "select returned %d\n", count);
836
0
            count = -1;
837
0
            goto exit;
838
0
        }                       /* endif -- count>0 */
839
840
    /*
841
     * see if persistent store needs to be saved
842
     */
843
0
    snmp_store_if_needed();
844
845
    /*
846
     * Run requested alarms.  
847
     */
848
0
    run_alarms();
849
850
0
    netsnmp_check_outstanding_agent_requests();
851
852
0
 exit:
853
0
    netsnmp_large_fd_set_cleanup(&readfds);
854
0
    netsnmp_large_fd_set_cleanup(&writefds);
855
0
    netsnmp_large_fd_set_cleanup(&exceptfds);
856
0
    return count;
857
0
}
858
#endif /* NETSNMP_FEATURE_REMOVE_AGENT_CHECK_AND_PROCESS */
859
860
/*
861
 * Set up the address cache.  
862
 */
863
void
864
netsnmp_addrcache_initialise(void)
865
0
{
866
0
    int             i = 0;
867
868
0
    for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
869
0
        addrCache[i].addr = NULL;
870
0
        addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
871
0
    }
872
0
}
873
874
void netsnmp_addrcache_destroy(void)
875
2.62k
{
876
2.62k
    int             i = 0;
877
878
28.8k
    for (i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
879
26.2k
        if (addrCache[i].status == SNMP_ADDRCACHE_USED) {
880
0
            free(addrCache[i].addr);
881
0
            addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
882
0
        }
883
26.2k
    }
884
2.62k
}
885
886
/*
887
 * Adds a new entry to the cache of addresses that
888
 * have recently made connections to the agent.
889
 * Returns 0 if the entry already exists (but updates
890
 * the entry with a new timestamp) and 1 if the
891
 * entry did not previously exist.
892
 *
893
 * Implements a simple LRU cache replacement
894
 * policy. Uses a linear search, which should be
895
 * okay, as long as SNMP_ADDRCACHE_SIZE remains
896
 * relatively small.
897
 *
898
 * @retval 0 : updated existing entry
899
 * @retval 1 : added new entry
900
 */
901
int
902
netsnmp_addrcache_add(const char *addr)
903
0
{
904
0
    int oldest = -1; /* Index of the oldest cache entry */
905
0
    int unused = -1; /* Index of the first free cache entry */
906
0
    int i; /* Looping variable */
907
0
    int rc = -1;
908
0
    struct timeval now; /* What time is it now? */
909
0
    struct timeval aged; /* Oldest allowable cache entry */
910
911
    /*
912
     * First get the current and oldest allowable timestamps
913
     */
914
0
    netsnmp_get_monotonic_clock(&now);
915
0
    aged.tv_sec = now.tv_sec - SNMP_ADDRCACHE_MAXAGE;
916
0
    aged.tv_usec = now.tv_usec;
917
918
    /*
919
     * Now look for a place to put this thing
920
     */
921
0
    for(i = 0; i < SNMP_ADDRCACHE_SIZE; i++) {
922
0
        if (addrCache[i].status == SNMP_ADDRCACHE_UNUSED) { /* If unused */
923
            /*
924
             * remember this location, in case addr isn't in the cache
925
             */
926
0
            if (unused < 0)
927
0
                unused = i;
928
0
        }
929
0
        else { /* If used */
930
0
            if ((NULL != addr) && (strcmp(addrCache[i].addr, addr) == 0)) {
931
                /*
932
                 * found a match
933
                 */
934
0
                addrCache[i].lastHitM = now;
935
0
                if (timercmp(&addrCache[i].lastHitM, &aged, <))
936
0
        rc = 1; /* should have expired, so is new */
937
0
    else
938
0
        rc = 0; /* not expired, so is existing entry */
939
0
                break;
940
0
            }
941
0
            else {
942
                /*
943
                 * Used, but not this address. check if it's stale.
944
                 */
945
0
                if (timercmp(&addrCache[i].lastHitM, &aged, <)) {
946
                    /*
947
                     * Stale, reuse
948
                     */
949
0
                    SNMP_FREE(addrCache[i].addr);
950
0
                    addrCache[i].status = SNMP_ADDRCACHE_UNUSED;
951
                    /*
952
                     * remember this location, in case addr isn't in the cache
953
                     */
954
0
        if (unused < 0)
955
0
                        unused = i;
956
0
                }
957
0
          else {
958
                    /*
959
                     * Still fresh, but a candidate for LRU replacement
960
                     */
961
0
                    if (oldest < 0)
962
0
                        oldest = i;
963
0
                    else if (timercmp(&addrCache[i].lastHitM,
964
0
                                      &addrCache[oldest].lastHitM, <))
965
0
                        oldest = i;
966
0
                } /* fresh */
967
0
            } /* used, no match */
968
0
        } /* used */
969
0
    } /* for loop */
970
971
0
    if ((-1 == rc) && (NULL != addr)) {
972
        /*
973
         * We didn't find the entry in the cache
974
         */
975
0
        if (unused >= 0) {
976
            /*
977
             * If we have a slot free anyway, use it
978
             */
979
0
            addrCache[unused].addr = strdup(addr);
980
0
            addrCache[unused].status = SNMP_ADDRCACHE_USED;
981
0
            addrCache[unused].lastHitM = now;
982
0
        }
983
0
        else { /* Otherwise, replace oldest entry */
984
0
            if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
985
0
                                       NETSNMP_DS_AGENT_VERBOSE))
986
0
                snmp_log(LOG_INFO, "Purging address from address cache: %s",
987
0
                         addrCache[oldest].addr);
988
            
989
0
            free(addrCache[oldest].addr);
990
0
            addrCache[oldest].addr = strdup(addr);
991
0
            addrCache[oldest].lastHitM = now;
992
0
        }
993
0
        rc = 1;
994
0
    }
995
0
    if ((log_addresses && (1 == rc)) ||
996
0
        netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
997
0
                               NETSNMP_DS_AGENT_VERBOSE)) {
998
0
        snmp_log(LOG_INFO, "Received SNMP packet(s) from %s\n", addr);
999
0
     }
1000
1001
0
    return rc;
1002
0
}
1003
1004
/*
1005
 * Age the entries in the address cache.  
1006
 *
1007
 * backwards compatability; not used anywhere
1008
 */
1009
#ifndef NETSNMP_FEATURE_REMOVE_ADDRCACHE_AGE
1010
void
1011
netsnmp_addrcache_age(void)
1012
0
{
1013
0
    (void)netsnmp_addrcache_add(NULL);
1014
0
}
1015
#endif /* NETSNMP_FEATURE_REMOVE_ADDRCACHE_AGE */
1016
1017
/*******************************************************************-o-******
1018
 * netsnmp_agent_check_packet
1019
 *
1020
 * Parameters:
1021
 *  session, transport, transport_data, transport_data_length
1022
 *      
1023
 * Returns:
1024
 *  1 On success.
1025
 *  0 On error.
1026
 *
1027
 * Handler for all incoming messages (a.k.a. packets) for the agent.  If using
1028
 * the libwrap utility, log the connection and deny/allow the access. Print
1029
 * output when appropriate, and increment the incoming counter.
1030
 *
1031
 */
1032
1033
int
1034
netsnmp_agent_check_packet(netsnmp_session * session,
1035
                           netsnmp_transport *transport,
1036
                           void *transport_data, int transport_data_length)
1037
0
{
1038
0
    char           *addr_string = NULL;
1039
#ifdef  NETSNMP_USE_LIBWRAP
1040
    char *tcpudpaddr = NULL, *name;
1041
    short not_log_connection;
1042
1043
    name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1044
                                 NETSNMP_DS_LIB_APPTYPE);
1045
1046
    /* not_log_connection will be 1 if we should skip the messages */
1047
    not_log_connection = netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1048
                                                NETSNMP_DS_AGENT_DONT_LOG_TCPWRAPPERS_CONNECTS);
1049
1050
    /*
1051
     * handle the error case
1052
     * default to logging the messages
1053
     */
1054
    if (not_log_connection == SNMPERR_GENERR) not_log_connection = 0;
1055
#endif
1056
1057
    /*
1058
     * Log the message and/or dump the message.
1059
     * Optionally cache the network address of the sender.
1060
     */
1061
1062
0
    if (transport != NULL && transport->f_fmtaddr != NULL) {
1063
        /*
1064
         * Okay I do know how to format this address for logging.  
1065
         */
1066
0
        addr_string = transport->f_fmtaddr(transport, transport_data,
1067
0
                                           transport_data_length);
1068
        /*
1069
         * Don't forget to free() it.  
1070
         */
1071
0
    }
1072
#ifdef  NETSNMP_USE_LIBWRAP
1073
    /* Catch udp,udp6,tcp,tcp6 transports using "[" */
1074
    if (addr_string)
1075
        tcpudpaddr = strstr(addr_string, "[");
1076
    if ( tcpudpaddr != 0 ) {
1077
        char sbuf[64];
1078
        char *xp;
1079
1080
        strlcpy(sbuf, tcpudpaddr + 1, sizeof(sbuf));
1081
        xp = strstr(sbuf, "]");
1082
        if (xp)
1083
            *xp = '\0';
1084
 
1085
        if (hosts_ctl(name, STRING_UNKNOWN, sbuf, STRING_UNKNOWN)) {
1086
            if (!not_log_connection) {
1087
                snmp_log(allow_severity, "Connection from %s\n", addr_string);
1088
            }
1089
        } else {
1090
            snmp_log(deny_severity, "Connection from %s REFUSED\n",
1091
                     addr_string);
1092
            SNMP_FREE(addr_string);
1093
            return 0;
1094
        }
1095
    } else {
1096
        /*
1097
         * don't log callback connections.
1098
         * What about 'Local IPC', 'IPX' and 'AAL5 PVC'?
1099
         */
1100
        if (0 == strncmp(addr_string, "callback", 8))
1101
            ;
1102
        else if (hosts_ctl(name, STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN)){
1103
            if (!not_log_connection) {
1104
                snmp_log(allow_severity, "Connection from <UNKNOWN> (%s)\n", addr_string);
1105
            };
1106
            SNMP_FREE(addr_string);
1107
            addr_string = strdup("<UNKNOWN>");
1108
        } else {
1109
            snmp_log(deny_severity, "Connection from <UNKNOWN> (%s) REFUSED\n", addr_string);
1110
            SNMP_FREE(addr_string);
1111
            return 0;
1112
        }
1113
    }
1114
#endif                          /*NETSNMP_USE_LIBWRAP */
1115
1116
0
    snmp_increment_statistic(STAT_SNMPINPKTS);
1117
1118
0
    if (addr_string != NULL) {
1119
0
        netsnmp_addrcache_add(addr_string);
1120
0
        SNMP_FREE(addr_string);
1121
0
    }
1122
0
    return 1;
1123
0
}
1124
1125
1126
int
1127
netsnmp_agent_check_parse(netsnmp_session * session, netsnmp_pdu *pdu,
1128
                          int result)
1129
0
{
1130
0
    if (result == 0) {
1131
0
        if (snmp_get_do_logging() &&
1132
0
      netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1133
0
           NETSNMP_DS_AGENT_VERBOSE)) {
1134
0
            netsnmp_variable_list *var_ptr;
1135
1136
0
            switch (pdu->command) {
1137
0
            case SNMP_MSG_GET:
1138
0
                snmp_log(LOG_DEBUG, "  GET message\n");
1139
0
                break;
1140
0
            case SNMP_MSG_GETNEXT:
1141
0
                snmp_log(LOG_DEBUG, "  GETNEXT message\n");
1142
0
                break;
1143
0
            case SNMP_MSG_RESPONSE:
1144
0
                snmp_log(LOG_DEBUG, "  RESPONSE message\n");
1145
0
                break;
1146
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
1147
0
            case SNMP_MSG_SET:
1148
0
                snmp_log(LOG_DEBUG, "  SET message\n");
1149
0
                break;
1150
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1151
0
            case SNMP_MSG_TRAP:
1152
0
                snmp_log(LOG_DEBUG, "  TRAP message\n");
1153
0
                break;
1154
0
            case SNMP_MSG_GETBULK:
1155
0
                snmp_log(LOG_DEBUG, "  GETBULK message, non-rep=%ld, max_rep=%ld\n",
1156
0
                         pdu->errstat, pdu->errindex);
1157
0
                break;
1158
0
            case SNMP_MSG_INFORM:
1159
0
                snmp_log(LOG_DEBUG, "  INFORM message\n");
1160
0
                break;
1161
0
            case SNMP_MSG_TRAP2:
1162
0
                snmp_log(LOG_DEBUG, "  TRAP2 message\n");
1163
0
                break;
1164
0
            case SNMP_MSG_REPORT:
1165
0
                snmp_log(LOG_DEBUG, "  REPORT message\n");
1166
0
                break;
1167
1168
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
1169
0
            case SNMP_MSG_INTERNAL_SET_RESERVE1:
1170
0
                snmp_log(LOG_DEBUG, "  INTERNAL RESERVE1 message\n");
1171
0
                break;
1172
1173
0
            case SNMP_MSG_INTERNAL_SET_RESERVE2:
1174
0
                snmp_log(LOG_DEBUG, "  INTERNAL RESERVE2 message\n");
1175
0
                break;
1176
1177
0
            case SNMP_MSG_INTERNAL_SET_ACTION:
1178
0
                snmp_log(LOG_DEBUG, "  INTERNAL ACTION message\n");
1179
0
                break;
1180
1181
0
            case SNMP_MSG_INTERNAL_SET_COMMIT:
1182
0
                snmp_log(LOG_DEBUG, "  INTERNAL COMMIT message\n");
1183
0
                break;
1184
1185
0
            case SNMP_MSG_INTERNAL_SET_FREE:
1186
0
                snmp_log(LOG_DEBUG, "  INTERNAL FREE message\n");
1187
0
                break;
1188
1189
0
            case SNMP_MSG_INTERNAL_SET_UNDO:
1190
0
                snmp_log(LOG_DEBUG, "  INTERNAL UNDO message\n");
1191
0
                break;
1192
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1193
1194
0
            default:
1195
0
                snmp_log(LOG_DEBUG, "  UNKNOWN message, type=%02X\n",
1196
0
                         pdu->command);
1197
0
                snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
1198
0
                return 0;
1199
0
            }
1200
1201
0
            for (var_ptr = pdu->variables; var_ptr != NULL;
1202
0
                 var_ptr = var_ptr->next_variable) {
1203
0
                size_t          c_oidlen = 256, c_outlen = 0;
1204
0
                u_char         *c_oid = (u_char *) malloc(c_oidlen);
1205
1206
0
                if (c_oid) {
1207
0
                    if (!sprint_realloc_objid
1208
0
                        (&c_oid, &c_oidlen, &c_outlen, 1, var_ptr->name,
1209
0
                         var_ptr->name_length)) {
1210
0
                        snmp_log(LOG_DEBUG, "    -- %s [TRUNCATED]\n",
1211
0
                                 c_oid);
1212
0
                    } else {
1213
0
                        snmp_log(LOG_DEBUG, "    -- %s\n", c_oid);
1214
0
                    }
1215
0
                    SNMP_FREE(c_oid);
1216
0
                }
1217
0
            }
1218
0
        }
1219
0
        return 1;
1220
0
    }
1221
0
    return 0;                   /* XXX: does it matter what the return value
1222
                                 * is?  Yes: if we return 0, then the PDU is
1223
                                 * dumped.  */
1224
0
}
1225
1226
1227
/*
1228
 * Global access to the primary session structure for this agent.
1229
 * for Index Allocation use initially. 
1230
 */
1231
1232
/*
1233
 * I don't understand what this is for at the moment.  AFAICS as long as it
1234
 * gets set and points at a session, that's fine.  ???  
1235
 */
1236
1237
netsnmp_session *main_session = NULL;
1238
1239
1240
1241
/*
1242
 * Set up an agent session on the given transport.  Return a handle
1243
 * which may later be used to de-register this transport.  A return
1244
 * value of -1 indicates an error.  
1245
 */
1246
1247
int
1248
netsnmp_register_agent_nsap(netsnmp_transport *t)
1249
2.62k
{
1250
2.62k
    netsnmp_session *s, *sp = NULL;
1251
2.62k
    agent_nsap     *a = NULL, *n = NULL, **prevNext = &agent_nsap_list;
1252
2.62k
    int             handle = 0;
1253
2.62k
    struct session_list *isp = NULL;
1254
1255
2.62k
    if (t == NULL) {
1256
0
        return -1;
1257
0
    }
1258
1259
2.62k
    DEBUGMSGTL(("netsnmp_register_agent_nsap", "fd %d\n", t->sock));
1260
1261
2.62k
    n = (agent_nsap *) malloc(sizeof(agent_nsap));
1262
2.62k
    if (n == NULL) {
1263
0
        return -1;
1264
0
    }
1265
2.62k
    s = (netsnmp_session *) malloc(sizeof(netsnmp_session));
1266
2.62k
    if (s == NULL) {
1267
0
        SNMP_FREE(n);
1268
0
        return -1;
1269
0
    }
1270
2.62k
    snmp_sess_init(s);
1271
1272
    /*
1273
     * Set up the session appropriately for an agent.  
1274
     */
1275
1276
2.62k
    s->version = SNMP_DEFAULT_VERSION;
1277
2.62k
    s->callback = handle_snmp_packet;
1278
2.62k
    s->authenticator = NULL;
1279
2.62k
    s->flags = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, 
1280
2.62k
          NETSNMP_DS_AGENT_FLAGS);
1281
2.62k
    s->isAuthoritative = SNMP_SESS_AUTHORITATIVE;
1282
1283
    /* Optional supplemental transport configuration information and
1284
       final call to actually open the transport */
1285
2.62k
    if (netsnmp_sess_config_transport(s->transport_configuration, t)
1286
2.62k
        != SNMPERR_SUCCESS) {
1287
0
        SNMP_FREE(s);
1288
0
        SNMP_FREE(n);
1289
0
        return -1;
1290
0
    }
1291
1292
1293
2.62k
    if (t->f_open)
1294
0
        t = t->f_open(t);
1295
1296
2.62k
    if (NULL == t) {
1297
0
        SNMP_FREE(s);
1298
0
        SNMP_FREE(n);
1299
0
        return -1;
1300
0
    }
1301
1302
2.62k
    t->flags |= NETSNMP_TRANSPORT_FLAG_OPENED;
1303
1304
2.62k
    sp = snmp_add(s, t, netsnmp_agent_check_packet,
1305
2.62k
                  netsnmp_agent_check_parse);
1306
2.62k
    if (sp == NULL) {
1307
0
        SNMP_FREE(s);
1308
0
        SNMP_FREE(n);
1309
0
        return -1;
1310
0
    }
1311
1312
2.62k
    isp = snmp_sess_pointer(sp);
1313
2.62k
    if (isp == NULL) {          /*  over-cautious  */
1314
0
        SNMP_FREE(s);
1315
0
        SNMP_FREE(n);
1316
0
        return -1;
1317
0
    }
1318
1319
2.62k
    n->s = isp;
1320
2.62k
    n->t = t;
1321
1322
2.62k
    if (main_session == NULL) {
1323
2.62k
        main_session = snmp_sess_session(isp);
1324
2.62k
    }
1325
1326
2.62k
    for (a = agent_nsap_list; a != NULL && handle + 1 >= a->handle;
1327
2.62k
         a = a->next) {
1328
0
        handle = a->handle;
1329
0
        prevNext = &(a->next);
1330
0
    }
1331
1332
2.62k
    if (handle < INT_MAX) {
1333
2.62k
        n->handle = handle + 1;
1334
2.62k
        n->next = a;
1335
2.62k
        *prevNext = n;
1336
2.62k
        SNMP_FREE(s);
1337
2.62k
        DEBUGMSGTL(("netsnmp_register_agent_nsap", "handle %d\n", n->handle));
1338
2.62k
        return n->handle;
1339
2.62k
    } else {
1340
0
        SNMP_FREE(s);
1341
0
        SNMP_FREE(n);
1342
0
        return -1;
1343
0
    }
1344
2.62k
}
1345
1346
void
1347
netsnmp_deregister_agent_nsap(int handle)
1348
2.62k
{
1349
2.62k
    agent_nsap     *a = NULL, **prevNext = &agent_nsap_list;
1350
2.62k
    int             main_session_deregistered = 0;
1351
1352
2.62k
    DEBUGMSGTL(("netsnmp_deregister_agent_nsap", "handle %d\n", handle));
1353
1354
2.62k
    for (a = agent_nsap_list; a != NULL && a->handle < handle; a = a->next) {
1355
0
        prevNext = &(a->next);
1356
0
    }
1357
1358
2.62k
    if (a != NULL && a->handle == handle) {
1359
2.62k
        *prevNext = a->next;
1360
2.62k
  if (snmp_sess_session_lookup(a->s)) {
1361
2.62k
            if (main_session == snmp_sess_session(a->s)) {
1362
2.62k
                main_session_deregistered = 1;
1363
2.62k
            }
1364
2.62k
            snmp_close(snmp_sess_session(a->s));
1365
            /*
1366
             * The above free()s the transport and session pointers.  
1367
             */
1368
2.62k
        }
1369
2.62k
        SNMP_FREE(a);
1370
2.62k
    }
1371
1372
    /*
1373
     * If we've deregistered the session that main_session used to point to,
1374
     * then make it point to another one, or in the last resort, make it equal
1375
     * to NULL.  Basically this shouldn't ever happen in normal operation
1376
     * because main_session starts off pointing at the first session added by
1377
     * init_master_agent(), which then discards the handle.  
1378
     */
1379
1380
2.62k
    if (main_session_deregistered) {
1381
2.62k
        if (agent_nsap_list != NULL) {
1382
0
            DEBUGMSGTL(("snmp_agent",
1383
0
      "WARNING: main_session ptr changed from %p to %p\n",
1384
0
                        main_session, snmp_sess_session(agent_nsap_list->s)));
1385
0
            main_session = snmp_sess_session(agent_nsap_list->s);
1386
2.62k
        } else {
1387
2.62k
            DEBUGMSGTL(("snmp_agent",
1388
2.62k
      "WARNING: main_session ptr changed from %p to NULL\n",
1389
2.62k
                        main_session));
1390
2.62k
            main_session = NULL;
1391
2.62k
        }
1392
2.62k
    }
1393
2.62k
}
1394
1395
int
1396
netsnmp_agent_listen_on(const char *port)
1397
2.62k
{
1398
2.62k
    netsnmp_transport *transport;
1399
2.62k
    int                handle;
1400
1401
2.62k
    if (NULL == port)
1402
0
        return -1;
1403
1404
2.62k
    transport = netsnmp_transport_open_server("snmp", port);
1405
2.62k
    if (transport == NULL) {
1406
0
        snmp_log(LOG_ERR, "Error opening specified endpoint \"%s\"\n", port);
1407
0
        return -1;
1408
0
    }
1409
1410
2.62k
    handle = netsnmp_register_agent_nsap(transport);
1411
2.62k
    if (handle < 0) {
1412
0
        snmp_log(LOG_ERR, "Error registering specified transport \"%s\" as an "
1413
0
                 "agent NSAP\n", port);
1414
0
        return -1;
1415
2.62k
    } else {
1416
2.62k
        DEBUGMSGTL(("snmp_agent",
1417
2.62k
                    "init_master_agent; \"%s\" registered as an agent NSAP\n",
1418
2.62k
                    port));
1419
2.62k
    }
1420
1421
2.62k
    return handle;
1422
2.62k
}
1423
1424
/*
1425
 * 
1426
 * This function has been modified to use the experimental
1427
 * netsnmp_register_agent_nsap interface.  The major responsibility of this
1428
 * function now is to interpret a string specified to the agent (via -p on the
1429
 * command line, or from a configuration file) as a list of agent NSAPs on
1430
 * which to listen for SNMP packets.  Typically, when you add a new transport
1431
 * domain "foo", you add code here such that if the "foo" code is compiled
1432
 * into the agent (SNMP_TRANSPORT_FOO_DOMAIN is defined), then a token of the
1433
 * form "foo:bletch-3a0054ef%wob&wob" gets turned into the appropriate
1434
 * transport descriptor.  netsnmp_register_agent_nsap is then called with that
1435
 * transport descriptor and sets up a listening agent session on it.
1436
 * 
1437
 * Everything then works much as normal: the agent runs in an infinite loop
1438
 * (in the snmpd.c/receive()routine), which calls snmp_read() when a request
1439
 * is readable on any of the given transports.  This routine then traverses
1440
 * the library 'Sessions' list to identify the relevant session and eventually
1441
 * invokes '_sess_read'.  This then processes the incoming packet, calling the
1442
 * pre_parse, parse, post_parse and callback routines in turn.
1443
 * 
1444
 * JBPN 20001117
1445
 */
1446
1447
int
1448
init_master_agent(void)
1449
2.62k
{
1450
2.62k
    char           *cptr;
1451
2.62k
    char           *buf = NULL;
1452
2.62k
    char           *st;
1453
1454
    /* default to a default cache size */
1455
2.62k
    netsnmp_set_lookup_cache_size(-1);
1456
1457
2.62k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1458
2.62k
             NETSNMP_DS_AGENT_ROLE) != MASTER_AGENT) {
1459
0
        DEBUGMSGTL(("snmp_agent",
1460
0
                    "init_master_agent; not master agent\n"));
1461
1462
0
        netsnmp_assert("agent role !master && !sub_agent");
1463
        
1464
0
        return 0;               /*  No error if ! MASTER_AGENT  */
1465
0
    }
1466
1467
2.62k
#ifndef NETSNMP_NO_LISTEN_SUPPORT
1468
    /*
1469
     * Have specific agent ports been specified?  
1470
     */
1471
2.62k
    cptr = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, 
1472
2.62k
         NETSNMP_DS_AGENT_PORTS);
1473
1474
2.62k
    if (cptr) {
1475
0
        buf = strdup(cptr);
1476
0
        if (!buf) {
1477
0
            snmp_log(LOG_ERR,
1478
0
                     "Error processing transport \"%s\"\n", cptr);
1479
0
            return 1;
1480
0
        }
1481
2.62k
    } else {
1482
        /*
1483
         * No, so just specify the default port.  
1484
         */
1485
2.62k
        buf = strdup("");
1486
2.62k
    }
1487
1488
2.62k
    DEBUGMSGTL(("snmp_agent", "final port spec: \"%s\"\n", buf));
1489
2.62k
    st = buf;
1490
2.62k
    do {
1491
        /*
1492
         * Specification format: 
1493
         * 
1494
         * NONE:                      (a pseudo-transport)
1495
         * UDP:[address:]port        (also default if no transport is specified)
1496
         * TCP:[address:]port         (if supported)
1497
         * Unix:pathname              (if supported)
1498
         * AAL5PVC:itf.vpi.vci        (if supported)
1499
         * IPX:[network]:node[/port] (if supported)
1500
         * 
1501
         */
1502
1503
2.62k
  cptr = st;
1504
2.62k
  st = strchr(st, ',');
1505
2.62k
  if (st)
1506
0
      *st++ = '\0';
1507
1508
2.62k
        DEBUGMSGTL(("snmp_agent", "installing master agent on port %s\n",
1509
2.62k
                    cptr));
1510
1511
2.62k
        if (strncasecmp(cptr, "none", 4) == 0) {
1512
0
            DEBUGMSGTL(("snmp_agent",
1513
0
                        "init_master_agent; pseudo-transport \"none\" "
1514
0
      "requested\n"));
1515
0
            break;
1516
0
        }
1517
2.62k
        if (-1 == netsnmp_agent_listen_on(cptr)) {
1518
0
            SNMP_FREE(buf);
1519
0
            return 1;
1520
0
        }
1521
2.62k
    } while(st && *st != '\0');
1522
2.62k
    SNMP_FREE(buf);
1523
2.62k
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
1524
1525
2.62k
#ifdef USING_AGENTX_MASTER_MODULE
1526
2.62k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1527
2.62k
             NETSNMP_DS_AGENT_AGENTX_MASTER) == 1)
1528
0
        real_init_master();
1529
2.62k
#endif
1530
2.62k
#ifdef USING_SMUX_MODULE
1531
2.62k
    if(should_init("smux"))
1532
0
    real_init_smux();
1533
2.62k
#endif
1534
1535
2.62k
#ifndef NETSNMP_NO_PDU_STATS
1536
2.62k
    _pdu_stats_init();
1537
2.62k
#endif /* NETSNMP_NO_PDU_STATS */
1538
1539
2.62k
    return 0;
1540
2.62k
}
1541
1542
void
1543
clear_nsap_list(void)
1544
2.62k
{
1545
2.62k
    DEBUGMSGTL(("clear_nsap_list", "clear the nsap list\n"));
1546
1547
5.25k
    while (agent_nsap_list != NULL)
1548
2.62k
  netsnmp_deregister_agent_nsap(agent_nsap_list->handle);
1549
2.62k
}
1550
1551
void
1552
shutdown_master_agent(void)
1553
2.62k
{
1554
2.62k
    clear_nsap_list();
1555
1556
2.62k
#ifndef NETSNMP_NO_PDU_STATS
1557
2.62k
    _pdu_stats_shutdown();
1558
2.62k
#endif /* NETSNMP_NO_PDU_STATS */
1559
2.62k
}
1560
1561
1562
netsnmp_agent_session *
1563
init_agent_snmp_session(netsnmp_session * session, netsnmp_pdu *pdu)
1564
10.5k
{
1565
10.5k
    netsnmp_agent_session *asp = calloc(1, sizeof(netsnmp_agent_session));
1566
1567
10.5k
    if (asp == NULL) {
1568
0
        return NULL;
1569
0
    }
1570
1571
10.5k
    DEBUGMSGTL(("snmp_agent","agent_sesion %8p created\n", asp));
1572
10.5k
    asp->session = session;
1573
10.5k
    asp->pdu = snmp_clone_pdu(pdu);
1574
10.5k
    if (!asp->pdu)
1575
0
        goto err;
1576
10.5k
    asp->orig_pdu = snmp_clone_pdu(pdu);
1577
10.5k
    if (!asp->orig_pdu)
1578
0
        goto err;
1579
10.5k
    asp->rw = READ;
1580
10.5k
    asp->exact = TRUE;
1581
10.5k
    asp->next = NULL;
1582
10.5k
    asp->mode = RESERVE1;
1583
10.5k
    asp->status = SNMP_ERR_NOERROR;
1584
10.5k
    asp->index = 0;
1585
10.5k
    asp->oldmode = 0;
1586
10.5k
    asp->treecache_num = -1;
1587
10.5k
    asp->treecache_len = 0;
1588
10.5k
    asp->reqinfo = SNMP_MALLOC_TYPEDEF(netsnmp_agent_request_info);
1589
10.5k
    asp->flags = SNMP_AGENT_FLAGS_NONE;
1590
10.5k
    DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p created\n",
1591
10.5k
                asp, asp->reqinfo));
1592
1593
10.5k
    return asp;
1594
1595
0
err:
1596
0
    snmp_free_pdu(asp->orig_pdu);
1597
0
    snmp_free_pdu(asp->pdu);
1598
0
    free(asp);
1599
0
    return NULL;
1600
10.5k
}
1601
1602
void
1603
free_agent_snmp_session(netsnmp_agent_session *asp)
1604
9.90k
{
1605
9.90k
    if (!asp)
1606
0
        return;
1607
1608
9.90k
    DEBUGMSGTL(("snmp_agent","agent_session %8p released\n", asp));
1609
1610
9.90k
    netsnmp_remove_from_delegated(asp);
1611
    
1612
9.90k
    DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p freed\n",
1613
9.90k
                asp, asp->reqinfo));
1614
1615
9.90k
    if (asp->orig_pdu)
1616
0
        snmp_free_pdu(asp->orig_pdu);
1617
9.90k
    if (asp->pdu)
1618
0
        snmp_free_pdu(asp->pdu);
1619
9.90k
    if (asp->reqinfo)
1620
9.90k
        netsnmp_free_agent_request_info(asp->reqinfo);
1621
9.90k
    SNMP_FREE(asp->treecache);
1622
9.90k
    SNMP_FREE(asp->bulkcache);
1623
9.90k
    if (asp->requests) {
1624
2.85k
        int             i;
1625
3.60k
        for (i = 0; i < asp->vbcount; i++) {
1626
745
            netsnmp_free_request_data_sets(&asp->requests[i]);
1627
745
        }
1628
2.85k
        SNMP_FREE(asp->requests);
1629
2.85k
    }
1630
9.90k
    if (asp->cache_store) {
1631
0
        netsnmp_free_cachemap(asp->cache_store);
1632
0
        asp->cache_store = NULL;
1633
0
    }
1634
9.90k
    SNMP_FREE(asp);
1635
9.90k
}
1636
1637
int
1638
netsnmp_check_for_delegated(netsnmp_agent_session *asp)
1639
18.9k
{
1640
18.9k
    int             i;
1641
18.9k
    netsnmp_request_info *request;
1642
1643
18.9k
    if (NULL == asp->treecache)
1644
10
        return 0;
1645
1646
18.9k
    if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS)
1647
0
        return 0;
1648
    
1649
19.6k
    for (i = 0; i <= asp->treecache_num; i++) {
1650
1.57k
        for (request = asp->treecache[i].requests_begin; request;
1651
847
             request = request->next) {
1652
847
            if (request->delegated)
1653
0
                return 1;
1654
847
        }
1655
725
    }
1656
18.9k
    return 0;
1657
18.9k
}
1658
1659
int
1660
netsnmp_check_delegated_chain_for(netsnmp_agent_session *asp)
1661
9.90k
{
1662
9.90k
    netsnmp_agent_session *asptmp;
1663
9.90k
    for (asptmp = agent_delegated_list; asptmp; asptmp = asptmp->next) {
1664
0
        if (asptmp == asp)
1665
0
            return 1;
1666
0
    }
1667
9.90k
    return 0;
1668
9.90k
}
1669
1670
int
1671
netsnmp_check_for_delegated_and_add(netsnmp_agent_session *asp)
1672
9.90k
{
1673
9.90k
    if (netsnmp_check_for_delegated(asp)) {
1674
0
        if (!netsnmp_check_delegated_chain_for(asp)) {
1675
            /*
1676
             * add to delegated request chain 
1677
             */
1678
0
            asp->next = agent_delegated_list;
1679
0
            agent_delegated_list = asp;
1680
0
            DEBUGMSGTL(("snmp_agent", "delegate session == %8p\n", asp));
1681
0
        }
1682
0
        return 1;
1683
0
    }
1684
9.90k
    return 0;
1685
9.90k
}
1686
1687
int
1688
netsnmp_remove_from_delegated(netsnmp_agent_session *asp)
1689
9.90k
{
1690
9.90k
    netsnmp_agent_session *curr, *prev = NULL;
1691
    
1692
9.90k
    for (curr = agent_delegated_list; curr; prev = curr, curr = curr->next) {
1693
        /*
1694
         * is this us?
1695
         */
1696
0
        if (curr != asp)
1697
0
            continue;
1698
        
1699
        /*
1700
         * remove from queue 
1701
         */
1702
0
        if (prev != NULL)
1703
0
            prev->next = asp->next;
1704
0
        else
1705
0
            agent_delegated_list = asp->next;
1706
1707
0
        DEBUGMSGTL(("snmp_agent", "remove delegated session == %8p\n", asp));
1708
1709
0
        return 1;
1710
0
    }
1711
1712
9.90k
    return 0;
1713
9.90k
}
1714
1715
/*
1716
 * netsnmp_remove_delegated_requests_for_session
1717
 *
1718
 * called when a session is being closed. Check all delegated requests to
1719
 * see if the are waiting on this session, and if set, set the status for
1720
 * that request to GENERR.
1721
 */
1722
int
1723
netsnmp_remove_delegated_requests_for_session(netsnmp_session *sess)
1724
0
{
1725
0
    netsnmp_agent_session *asp;
1726
0
    int total_count = 0;
1727
    
1728
0
    for (asp = agent_delegated_list; asp; asp = asp->next) {
1729
        /*
1730
         * check each request
1731
         */
1732
0
        int i;
1733
0
        int count = 0;
1734
0
        netsnmp_request_info *request;
1735
0
        for (i = 0; i <= asp->treecache_num; i++) {
1736
0
            for (request = asp->treecache[i].requests_begin; request;
1737
0
                 request = request->next) {
1738
                /*
1739
                 * check session
1740
                 */
1741
0
                netsnmp_assert(NULL!=request->subtree);
1742
0
                if(request->subtree->session != sess)
1743
0
                    continue;
1744
1745
                /*
1746
                 * matched! mark request as done
1747
                 */
1748
0
                netsnmp_request_set_error(request, SNMP_ERR_GENERR);
1749
0
                ++count;
1750
0
            }
1751
0
        }
1752
0
        if (count) {
1753
0
            asp->flags |= SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS;
1754
0
            total_count += count;
1755
0
        }
1756
0
    }
1757
1758
    /*
1759
     * if we found any, that request may be finished now
1760
     */
1761
0
    if(total_count) {
1762
0
        DEBUGMSGTL(("snmp_agent", "removed %d delegated request(s) for session "
1763
0
                    "%8p\n", total_count, sess));
1764
0
        netsnmp_check_delegated_requests();
1765
0
    }
1766
    
1767
0
    return total_count;
1768
0
}
1769
1770
#if 0
1771
int
1772
netsnmp_check_queued_chain_for(netsnmp_agent_session *asp)
1773
{
1774
    netsnmp_agent_session *asptmp;
1775
    for (asptmp = netsnmp_agent_queued_list; asptmp; asptmp = asptmp->next) {
1776
        if (asptmp == asp)
1777
            return 1;
1778
    }
1779
    return 0;
1780
}
1781
#endif
1782
1783
int
1784
netsnmp_add_queued(netsnmp_agent_session *asp)
1785
0
{
1786
0
    netsnmp_agent_session *asp_tmp;
1787
1788
    /*
1789
     * first item?
1790
     */
1791
0
    if (NULL == netsnmp_agent_queued_list) {
1792
0
        netsnmp_agent_queued_list = asp;
1793
0
        return 1;
1794
0
    }
1795
1796
1797
    /*
1798
     * add to end of queued request chain 
1799
     */
1800
0
    asp_tmp = netsnmp_agent_queued_list;
1801
0
    for (; asp_tmp; asp_tmp = asp_tmp->next) {
1802
        /*
1803
         * already in queue?
1804
         */
1805
0
        if (asp_tmp == asp)
1806
0
            break;
1807
1808
        /*
1809
         * end of queue?
1810
         */
1811
0
        if (NULL == asp_tmp->next)
1812
0
            asp_tmp->next = asp;
1813
0
    }
1814
0
    return 1;
1815
0
}
1816
1817
#ifndef NETSNMP_NO_PDU_STATS
1818
/*
1819
 * netsnmp_pdu_stats_process: record time for pdu processing
1820
 */
1821
int
1822
netsnmp_pdu_stats_process(netsnmp_agent_session *asp)
1823
0
{
1824
0
    netsnmp_pdu_stats *new_entry, *old = NULL;
1825
0
    struct timeval tv_end;
1826
0
    marker_t start, end = &tv_end;
1827
0
    u_long msec;
1828
1829
0
    if (NULL == asp) {
1830
0
        DEBUGMSGTL(("stats:pdu", "netsnmp_pdu_stats_process bad params\n"));
1831
0
        return -1;
1832
0
    }
1833
1834
    /** get start/end time */
1835
0
    netsnmp_set_monotonic_marker(&end);
1836
0
    start = (marker_t)netsnmp_agent_get_list_data(asp->reqinfo,
1837
0
                                                  "netsnmp_pdu_stats");
1838
0
    if (NULL == start) {
1839
0
        DEBUGMSGTL(("stats:pdu:stop", "start time not found!\n"));
1840
0
        return -1;
1841
0
    }
1842
1843
0
    msec = uatime_diff(start, end);
1844
0
    DEBUGMSGTL(("stats:pdu:stop", "pdu processing took %ld msec\n", msec));
1845
1846
    /** bail if below threshold or less than current low time */
1847
0
    if (msec <= _pdu_stats_threshold || msec < _pdu_stats_current_lowest) {
1848
0
        DEBUGMSGTL(("9:stats:pdu",
1849
0
                    "time below thresholds (%ld/%ld); ignoring\n",
1850
0
                    _pdu_stats_threshold, _pdu_stats_current_lowest));
1851
0
        return 0;
1852
0
    }
1853
1854
    /** insert in list. if list goes over max size, truncate last entry. */
1855
0
    new_entry = SNMP_MALLOC_TYPEDEF(netsnmp_pdu_stats);
1856
0
    if (NULL == new_entry) {
1857
0
        snmp_log(LOG_ERR, "malloc failed for pdu stats entry\n");
1858
0
        return -1;
1859
0
    }
1860
0
    new_entry->processing_time = msec;
1861
0
    time(&new_entry->timestamp);
1862
0
    new_entry->pdu = snmp_clone_pdu(asp->pdu);
1863
1864
0
    CONTAINER_INSERT(_pdu_stats, new_entry);
1865
1866
0
    if (CONTAINER_SIZE(_pdu_stats) > _pdu_stats_max) {
1867
0
        DEBUGMSGTL(("9:stats:pdu", "dropping old/low stat\n"));
1868
0
        CONTAINER_REMOVE_AT(_pdu_stats, _pdu_stats_max, (void**)&old);
1869
0
        if (old) {
1870
0
            snmp_free_pdu(old->pdu);
1871
0
            free(old);
1872
0
        }
1873
0
    }
1874
1875
0
    if (CONTAINER_SIZE(_pdu_stats) < _pdu_stats_max)
1876
0
        _pdu_stats_current_lowest = 0; /* take anything over threshold */
1877
0
    else {
1878
0
        CONTAINER_GET_AT(_pdu_stats, _pdu_stats_max - 1, (void**)&old);
1879
0
        if (old)
1880
0
            _pdu_stats_current_lowest = old->processing_time;
1881
0
    }
1882
1883
0
    DEBUGIF("9:stats:pdu") {
1884
0
        _dump_pdu_stats();
1885
0
    }
1886
1887
0
    return 1;
1888
1889
0
}
1890
#endif /* NETSNMP_NO_PDU_STATS */
1891
1892
int
1893
netsnmp_wrap_up_request(netsnmp_agent_session *asp, int status)
1894
9.90k
{
1895
9.90k
#ifndef NETSNMP_NO_PDU_STATS
1896
9.90k
    if (_pdu_stats_max > 0)
1897
0
        netsnmp_pdu_stats_process(asp);
1898
9.90k
#endif /* NETSNMP_NO_PDU_STATS */
1899
1900
    /*
1901
     * if this request was a set, clear the global now that we are
1902
     * done.
1903
     */
1904
9.90k
    if (asp == netsnmp_processing_set) {
1905
280
        DEBUGMSGTL(("snmp_agent", "SET request complete, asp = %8p\n",
1906
280
                    asp));
1907
280
        netsnmp_processing_set = NULL;
1908
280
    }
1909
1910
9.90k
    if (asp->pdu) {
1911
        /*
1912
         * If we've got an error status, then this needs to be
1913
         *  passed back up to the higher levels....
1914
         */
1915
9.90k
        if ( status != 0  && asp->status == 0 )
1916
1.52k
            asp->status = status;
1917
1918
9.90k
        switch (asp->pdu->command) {
1919
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
1920
0
            case SNMP_MSG_INTERNAL_SET_BEGIN:
1921
6.75k
            case SNMP_MSG_INTERNAL_SET_RESERVE1:
1922
6.81k
            case SNMP_MSG_INTERNAL_SET_RESERVE2:
1923
7.03k
            case SNMP_MSG_INTERNAL_SET_ACTION:
1924
                /*
1925
                 * some stuff needs to be saved in special subagent cases 
1926
                 */
1927
7.03k
                save_set_cache(asp);
1928
7.03k
                break;
1929
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1930
1931
95
            case SNMP_MSG_GETNEXT:
1932
95
                _fix_endofmibview(asp);
1933
95
                break;
1934
1935
551
            case SNMP_MSG_GETBULK:
1936
                /*
1937
                 * for a GETBULK response we need to rearrange the varbinds 
1938
                 */
1939
551
                _reorder_getbulk(asp);
1940
551
                break;
1941
9.90k
        }
1942
1943
        /*
1944
         * May need to "dumb down" a SET error status for a
1945
         * v1 query.  See RFC2576 - section 4.3
1946
         */
1947
9.90k
#ifndef NETSNMP_DISABLE_SNMPV1
1948
9.90k
#ifndef NETSNMP_NO_WRITE_SUPPORT
1949
9.90k
        if ((asp->pdu->command == SNMP_MSG_SET) &&
1950
9.90k
            (asp->pdu->version == SNMP_VERSION_1)) {
1951
280
            switch (asp->status) {
1952
0
                case SNMP_ERR_WRONGVALUE:
1953
0
                case SNMP_ERR_WRONGENCODING:
1954
10
                case SNMP_ERR_WRONGTYPE:
1955
10
                case SNMP_ERR_WRONGLENGTH:
1956
10
                case SNMP_ERR_INCONSISTENTVALUE:
1957
10
                    status = SNMP_ERR_BADVALUE;
1958
10
                    asp->status = SNMP_ERR_BADVALUE;
1959
10
                    break;
1960
0
                case SNMP_ERR_NOACCESS:
1961
112
                case SNMP_ERR_NOTWRITABLE:
1962
112
                case SNMP_ERR_NOCREATION:
1963
112
                case SNMP_ERR_INCONSISTENTNAME:
1964
112
                case SNMP_ERR_AUTHORIZATIONERROR:
1965
112
                    status = SNMP_ERR_NOSUCHNAME;
1966
112
                    asp->status = SNMP_ERR_NOSUCHNAME;
1967
112
                    break;
1968
0
                case SNMP_ERR_RESOURCEUNAVAILABLE:
1969
0
                case SNMP_ERR_COMMITFAILED:
1970
0
                case SNMP_ERR_UNDOFAILED:
1971
0
                    status = SNMP_ERR_GENERR;
1972
0
                    asp->status = SNMP_ERR_GENERR;
1973
0
                    break;
1974
280
            }
1975
280
        }
1976
9.90k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1977
        /*
1978
         * Similarly we may need to "dumb down" v2 exception
1979
         *  types to throw an error for a v1 query.
1980
         *  See RFC2576 - section 4.1.2.3
1981
         */
1982
9.90k
        if (
1983
9.90k
#ifndef NETSNMP_NO_WRITE_SUPPORT
1984
9.90k
            (asp->pdu->command != SNMP_MSG_SET) &&
1985
9.90k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1986
9.90k
            (asp->pdu->version == SNMP_VERSION_1) && asp->index < 1) {
1987
9.62k
            netsnmp_variable_list *var_ptr = asp->pdu->variables;
1988
9.62k
            int                    i = 1;
1989
1990
10.2k
            while (var_ptr != NULL) {
1991
586
                switch (var_ptr->type) {
1992
152
                    case SNMP_NOSUCHOBJECT:
1993
152
                    case SNMP_NOSUCHINSTANCE:
1994
527
                    case SNMP_ENDOFMIBVIEW:
1995
527
                    case ASN_COUNTER64:
1996
527
                        status = SNMP_ERR_NOSUCHNAME;
1997
527
                        asp->status = SNMP_ERR_NOSUCHNAME;
1998
527
                        asp->index = i;
1999
527
                        break;
2000
586
                }
2001
586
                var_ptr = var_ptr->next_variable;
2002
586
                ++i;
2003
586
            }
2004
9.62k
        }
2005
        
2006
280
        else
2007
280
        {
2008
280
          status = asp->status ;
2009
280
        }
2010
9.90k
#endif /* snmpv1 support */
2011
2012
        /** so far so good? try and build packet */
2013
9.90k
        if (status == SNMP_ERR_NOERROR) {
2014
7.95k
            struct session_list *slp = snmp_sess_pointer(asp->session);
2015
2016
            /** build packet to send */
2017
7.95k
            asp->pdu->command = SNMP_MSG_RESPONSE;
2018
7.95k
            asp->pdu->errstat = asp->status;
2019
7.95k
            asp->pdu->errindex = asp->index;
2020
7.95k
            status = _build_initial_pdu_packet(slp, asp->pdu,
2021
7.95k
                                               SNMP_MSG_GETBULK == asp->orig_pdu->command);
2022
7.95k
            if (SNMPERR_SUCCESS != status){
2023
7.95k
                if (SNMPERR_TOO_LONG == asp->session->s_snmp_errno)
2024
0
                    status = asp->status = SNMP_ERR_TOOBIG;
2025
7.95k
                else
2026
7.95k
                    status = asp->status = SNMP_ERR_GENERR;
2027
7.95k
            }
2028
7.95k
        }
2029
2030
9.90k
        if (status == SNMP_ERR_NOERROR)
2031
0
            snmp_increment_statistic_by(
2032
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
2033
0
                (asp->pdu->command == SNMP_MSG_SET ?
2034
0
                 STAT_SNMPINTOTALSETVARS : STAT_SNMPINTOTALREQVARS),
2035
#else
2036
                STAT_SNMPINTOTALREQVARS,
2037
#endif
2038
0
                count_varbinds(asp->pdu->variables));
2039
9.90k
    } /** if asp->pdu */
2040
2041
    /*
2042
     * Update the snmp error-count statistics
2043
     *   XXX - should we include the V2 errors in this or not?
2044
     */
2045
9.90k
#define INCLUDE_V2ERRORS_IN_V1STATS
2046
2047
9.90k
    switch (status) {
2048
0
#ifdef INCLUDE_V2ERRORS_IN_V1STATS
2049
0
    case SNMP_ERR_WRONGVALUE:
2050
0
    case SNMP_ERR_WRONGENCODING:
2051
0
    case SNMP_ERR_WRONGTYPE:
2052
0
    case SNMP_ERR_WRONGLENGTH:
2053
0
    case SNMP_ERR_INCONSISTENTVALUE:
2054
0
#endif
2055
10
    case SNMP_ERR_BADVALUE:
2056
10
        snmp_increment_statistic(STAT_SNMPOUTBADVALUES);
2057
10
        break;
2058
0
#ifdef INCLUDE_V2ERRORS_IN_V1STATS
2059
0
    case SNMP_ERR_NOACCESS:
2060
0
    case SNMP_ERR_NOTWRITABLE:
2061
0
    case SNMP_ERR_NOCREATION:
2062
0
    case SNMP_ERR_INCONSISTENTNAME:
2063
0
    case SNMP_ERR_AUTHORIZATIONERROR:
2064
0
#endif
2065
425
    case SNMP_ERR_NOSUCHNAME:
2066
425
        snmp_increment_statistic(STAT_SNMPOUTNOSUCHNAMES);
2067
425
        break;
2068
0
#ifdef INCLUDE_V2ERRORS_IN_V1STATS
2069
0
    case SNMP_ERR_RESOURCEUNAVAILABLE:
2070
0
    case SNMP_ERR_COMMITFAILED:
2071
0
    case SNMP_ERR_UNDOFAILED:
2072
0
#endif
2073
7.95k
    case SNMP_ERR_GENERR:
2074
7.95k
        snmp_increment_statistic(STAT_SNMPOUTGENERRS);
2075
7.95k
        break;
2076
2077
0
    case SNMP_ERR_TOOBIG:
2078
0
        snmp_increment_statistic(STAT_SNMPOUTTOOBIGS);
2079
0
        break;
2080
9.90k
    }
2081
2082
9.90k
    if ((status != SNMP_ERR_NOERROR) || (NULL == asp->pdu)) {
2083
        /** Use a copy of the original request to report failures. */
2084
9.90k
        snmp_free_pdu(asp->pdu);
2085
9.90k
        asp->pdu = asp->orig_pdu;
2086
9.90k
        asp->orig_pdu = NULL;
2087
9.90k
    }
2088
9.90k
    if (asp->pdu) {
2089
9.90k
        int rc;
2090
2091
9.90k
        asp->pdu->command = SNMP_MSG_RESPONSE;
2092
9.90k
        asp->pdu->errstat = asp->status;
2093
9.90k
        asp->pdu->errindex = asp->index;
2094
9.90k
        rc = snmp_send(asp->session, asp->pdu);
2095
9.90k
        if (rc == 0 && asp->session->s_snmp_errno != SNMPERR_SUCCESS) {
2096
0
            netsnmp_variable_list *var_ptr;
2097
0
            snmp_perror("send response");
2098
0
            for (var_ptr = asp->pdu->variables; var_ptr != NULL;
2099
0
                     var_ptr = var_ptr->next_variable) {
2100
0
                size_t  c_oidlen = 256, c_outlen = 0;
2101
0
                u_char *c_oid = (u_char *) malloc(c_oidlen);
2102
2103
0
                if (c_oid) {
2104
0
                    if (!sprint_realloc_objid (&c_oid, &c_oidlen, &c_outlen, 1,
2105
0
                                               var_ptr->name,
2106
0
                                               var_ptr->name_length)) {
2107
0
                        snmp_log(LOG_ERR, "    -- %s [TRUNCATED]\n", c_oid);
2108
0
                    } else {
2109
0
                        snmp_log(LOG_ERR, "    -- %s\n", c_oid);
2110
0
                    }
2111
0
                    SNMP_FREE(c_oid);
2112
0
                }
2113
0
            }
2114
0
        }
2115
9.90k
        if (rc == 0)
2116
9.90k
            snmp_free_pdu(asp->pdu);
2117
9.90k
        snmp_increment_statistic(STAT_SNMPOUTPKTS);
2118
9.90k
        snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
2119
9.90k
        asp->pdu = NULL;
2120
9.90k
        netsnmp_remove_and_free_agent_snmp_session(asp);
2121
9.90k
    }
2122
9.90k
    return 1;
2123
9.90k
}
2124
2125
#ifndef NETSNMP_FEATURE_REMOVE_DUMP_SESS_LIST
2126
void
2127
dump_sess_list(void)
2128
0
{
2129
0
    netsnmp_agent_session *a;
2130
2131
0
    DEBUGMSGTL(("snmp_agent", "DUMP agent_sess_list -> "));
2132
0
    for (a = agent_session_list; a != NULL; a = a->next) {
2133
0
        DEBUGMSG(("snmp_agent", "%8p[session %8p] -> ", a, a->session));
2134
0
    }
2135
0
    DEBUGMSG(("snmp_agent", "[NIL]\n"));
2136
0
}
2137
#endif /* NETSNMP_FEATURE_REMOVE_DUMP_SESS_LIST */
2138
2139
void
2140
netsnmp_remove_and_free_agent_snmp_session(netsnmp_agent_session *asp)
2141
9.90k
{
2142
9.90k
    netsnmp_agent_session *a, **prevNext = &agent_session_list;
2143
2144
9.90k
    DEBUGMSGTL(("snmp_agent", "REMOVE session == %8p\n", asp));
2145
2146
9.90k
    for (a = agent_session_list; a != NULL; a = *prevNext) {
2147
0
        if (a == asp) {
2148
0
            *prevNext = a->next;
2149
0
            a->next = NULL;
2150
0
            free_agent_snmp_session(a);
2151
0
            asp = NULL;
2152
0
            break;
2153
0
        } else {
2154
0
            prevNext = &(a->next);
2155
0
        }
2156
0
    }
2157
2158
9.90k
    if (a == NULL && asp != NULL) {
2159
        /*
2160
         * We couldn't find it on the list, so free it anyway.  
2161
         */
2162
9.90k
        free_agent_snmp_session(asp);
2163
9.90k
    }
2164
9.90k
}
2165
2166
#ifndef NETSNMP_FEATURE_REMOVE_FREE_AGENT_SNMP_SESSION_BY_SESSION
2167
void
2168
netsnmp_free_agent_snmp_session_by_session(netsnmp_session * sess,
2169
                                           void (*free_request)
2170
                                           (netsnmp_request_list *))
2171
0
{
2172
0
    netsnmp_agent_session *a, *next, **prevNext = &agent_session_list;
2173
2174
0
    DEBUGMSGTL(("snmp_agent", "REMOVE session == %8p\n", sess));
2175
2176
0
    for (a = agent_session_list; a != NULL; a = next) {
2177
0
        if (a->session == sess) {
2178
0
            *prevNext = a->next;
2179
0
            next = a->next;
2180
0
            free_agent_snmp_session(a);
2181
0
        } else {
2182
0
            prevNext = &(a->next);
2183
0
            next = a->next;
2184
0
        }
2185
0
    }
2186
0
}
2187
#endif /* NETSNMP_FEATURE_REMOVE_FREE_AGENT_SNMP_SESSION_BY_SESSION */
2188
2189
/** handles an incoming SNMP packet into the agent */
2190
int
2191
handle_snmp_packet(int op, netsnmp_session * session, int reqid,
2192
                   netsnmp_pdu *pdu, void *magic)
2193
10.5k
{
2194
10.5k
    netsnmp_agent_session *asp;
2195
10.5k
    int             status, access_ret, rc;
2196
2197
    /*
2198
     * We only support receiving here.  
2199
     */
2200
10.5k
    if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
2201
0
        return 1;
2202
0
    }
2203
2204
    /*
2205
     * RESPONSE messages won't get this far, but TRAP-like messages
2206
     * might.  
2207
     */
2208
10.5k
    if (pdu->command == SNMP_MSG_TRAP || pdu->command == SNMP_MSG_INFORM ||
2209
10.5k
        pdu->command == SNMP_MSG_TRAP2) {
2210
603
        DEBUGMSGTL(("snmp_agent", "received trap-like PDU (%02x)\n",
2211
603
                    pdu->command));
2212
603
        pdu->command = SNMP_MSG_TRAP2;
2213
603
        snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
2214
603
        return 1;
2215
603
    }
2216
2217
    /*
2218
     * send snmpv3 authfail trap.
2219
     */
2220
9.90k
    if (pdu->version  == SNMP_VERSION_3 && 
2221
9.90k
        session->s_snmp_errno == SNMPERR_USM_AUTHENTICATIONFAILURE) {
2222
0
            snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2223
0
                                SNMPD_CALLBACK_AUTH_FAILURE, pdu);
2224
0
           send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
2225
0
           return 1;
2226
0
    } 
2227
  
2228
9.90k
    if (magic == NULL) {
2229
0
        asp = init_agent_snmp_session(session, pdu);
2230
0
        status = SNMP_ERR_NOERROR;
2231
0
        if (asp == NULL)
2232
0
            return 1;
2233
9.90k
    } else {
2234
9.90k
        asp = (netsnmp_agent_session *) magic;
2235
9.90k
        status = asp->status;
2236
9.90k
    }
2237
2238
#if defined(NETSNMP_DISABLE_SET_SUPPORT) && !defined(NETSNMP_NO_WRITE_SUPPORT)
2239
    if (pdu->command == SNMP_MSG_SET) {
2240
        /** Silvercreek protocol tests send set with 0 varbinds */
2241
        if (NULL == pdu->variables)
2242
            return netsnmp_wrap_up_request(asp, SNMP_ERR_NOERROR);
2243
        asp->index = 1;
2244
        return netsnmp_wrap_up_request(asp, SNMP_ERR_NOTWRITABLE);
2245
    }
2246
#endif /* NETSNMP_DISABLE_SET_SUPPORT && !NETSNMP_NO_WRITE_SUPPORT */
2247
2248
9.90k
    if ((access_ret = check_access(asp->pdu)) != 0) {
2249
0
        if (access_ret == VACM_NOSUCHCONTEXT) {
2250
            /*
2251
             * rfc3413 section 3.2, step 5 says that we increment the
2252
             * counter but don't return a response of any kind 
2253
             */
2254
2255
            /*
2256
             * we currently don't support unavailable contexts, as
2257
             * there is no reason to that I currently know of 
2258
             */
2259
0
            snmp_increment_statistic(STAT_SNMPUNKNOWNCONTEXTS);
2260
2261
            /*
2262
             * drop the request 
2263
             */
2264
0
            netsnmp_remove_and_free_agent_snmp_session(asp);
2265
0
            return 0;
2266
0
        } else {
2267
            /*
2268
             * access control setup is incorrect 
2269
             */
2270
0
            snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
2271
0
                                SNMPD_CALLBACK_AUTH_FAILURE, pdu);
2272
0
            send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
2273
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
2274
#if defined(NETSNMP_DISABLE_SNMPV1)
2275
            if (asp->pdu->version != SNMP_VERSION_2c) {
2276
#else
2277
#if defined(NETSNMP_DISABLE_SNMPV2C)
2278
            if (asp->pdu->version != SNMP_VERSION_1) {
2279
#else
2280
0
            if (asp->pdu->version != SNMP_VERSION_1
2281
0
                && asp->pdu->version != SNMP_VERSION_2c) {
2282
0
#endif
2283
0
#endif
2284
0
                asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
2285
0
                asp->pdu->command = SNMP_MSG_RESPONSE;
2286
0
                snmp_increment_statistic(STAT_SNMPOUTPKTS);
2287
0
                if (!snmp_send(asp->session, asp->pdu))
2288
0
                    snmp_free_pdu(asp->pdu);
2289
0
                asp->pdu = NULL;
2290
0
                netsnmp_remove_and_free_agent_snmp_session(asp);
2291
0
                return 1;
2292
0
            } else {
2293
0
#endif /* support for community based SNMP */
2294
                /*
2295
                 * drop the request 
2296
                 */
2297
0
                netsnmp_remove_and_free_agent_snmp_session(asp);
2298
0
                return 0;
2299
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
2300
0
            }
2301
0
#endif /* support for community based SNMP */
2302
0
        }
2303
0
    }
2304
2305
9.90k
    rc = netsnmp_handle_request(asp, status);
2306
2307
    /*
2308
     * done 
2309
     */
2310
9.90k
    DEBUGMSGTL(("snmp_agent", "end of handle_snmp_packet, asp = %8p\n",
2311
9.90k
                asp));
2312
9.90k
    return rc;
2313
9.90k
}
2314
2315
netsnmp_request_info *
2316
netsnmp_add_varbind_to_cache(netsnmp_agent_session *asp, int vbcount,
2317
                             netsnmp_variable_list * varbind_ptr,
2318
                             netsnmp_subtree *tp)
2319
745
{
2320
745
    netsnmp_request_info *request = NULL;
2321
2322
745
    DEBUGMSGTL(("snmp_agent", "add_vb_to_cache(%8p, %d, ", asp, vbcount));
2323
745
    DEBUGMSGOID(("snmp_agent", varbind_ptr->name,
2324
745
                 varbind_ptr->name_length));
2325
745
    DEBUGMSG(("snmp_agent", ", %8p)\n", tp));
2326
2327
745
    if (tp &&
2328
745
        (asp->pdu->command == SNMP_MSG_GETNEXT ||
2329
745
         asp->pdu->command == SNMP_MSG_GETBULK)) {
2330
375
        int result;
2331
375
        int prefix_len;
2332
2333
375
        prefix_len = netsnmp_oid_find_prefix(tp->start_a,
2334
375
                                             tp->start_len,
2335
375
                                             tp->end_a, tp->end_len);
2336
375
        if (prefix_len < 1) {
2337
375
            result = VACM_NOTINVIEW; /* ack...  bad bad thing happened */
2338
375
        } else {
2339
0
            result =
2340
0
                netsnmp_acm_check_subtree(asp->pdu, tp->start_a, prefix_len);
2341
0
        }
2342
2343
847
        while (result == VACM_NOTINVIEW) {
2344
            /* the entire subtree is not in view. Skip it. */
2345
            /** @todo make this be more intelligent about ranges.
2346
                Right now we merely take the highest level
2347
                commonality of a registration range and use that.
2348
                At times we might be able to be smarter about
2349
                checking the range itself as opposed to the node
2350
                above where the range exists, but I doubt this will
2351
                come up all that frequently. */
2352
847
            tp = tp->next;
2353
847
            if (tp) {
2354
472
                prefix_len = netsnmp_oid_find_prefix(tp->start_a,
2355
472
                                                     tp->start_len,
2356
472
                                                     tp->end_a,
2357
472
                                                     tp->end_len);
2358
472
                if (prefix_len < 1) {
2359
                    /* ack...  bad bad thing happened */
2360
472
                    result = VACM_NOTINVIEW;
2361
472
                } else {
2362
0
                    result =
2363
0
                        netsnmp_acm_check_subtree(asp->pdu,
2364
0
                                                  tp->start_a, prefix_len);
2365
0
                }
2366
472
            }
2367
375
            else
2368
375
                break;
2369
847
        }
2370
375
    }
2371
745
    if (tp == NULL) {
2372
        /*
2373
         * no appropriate registration found 
2374
         */
2375
        /*
2376
         * make up the response ourselves 
2377
         */
2378
375
        switch (asp->pdu->command) {
2379
44
        case SNMP_MSG_GETNEXT:
2380
375
        case SNMP_MSG_GETBULK:
2381
375
            varbind_ptr->type = SNMP_ENDOFMIBVIEW;
2382
375
            break;
2383
2384
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
2385
0
        case SNMP_MSG_SET:
2386
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2387
0
        case SNMP_MSG_GET:
2388
0
            varbind_ptr->type = SNMP_NOSUCHOBJECT;
2389
0
            break;
2390
2391
0
        default:
2392
0
            return NULL;        /* shouldn't get here */
2393
375
        }
2394
375
    } else {
2395
370
        int cacheid;
2396
2397
370
        DEBUGMSGTL(("snmp_agent", "tp->start "));
2398
370
        DEBUGMSGOID(("snmp_agent", tp->start_a, tp->start_len));
2399
370
        DEBUGMSG(("snmp_agent", ", tp->end "));
2400
370
        DEBUGMSGOID(("snmp_agent", tp->end_a, tp->end_len));
2401
370
        DEBUGMSG(("snmp_agent", ", \n"));
2402
2403
        /*
2404
         * malloc the request structure 
2405
         */
2406
370
        request = &(asp->requests[vbcount - 1]);
2407
370
        request->index = vbcount;
2408
370
        request->delegated = 0;
2409
370
        request->processed = 0;
2410
370
        request->status = 0;
2411
370
        request->subtree = tp;
2412
370
        request->agent_req_info = asp->reqinfo;
2413
370
        if (request->parent_data) {
2414
0
            netsnmp_free_request_data_sets(request);
2415
0
        }
2416
370
        DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
2417
370
                    asp, asp->reqinfo));
2418
2419
        /*
2420
         * for non-SET modes, set the type to NULL 
2421
         */
2422
370
#ifndef NETSNMP_NO_WRITE_SUPPORT
2423
370
        if (!MODE_IS_SET(asp->pdu->command)) {
2424
211
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2425
211
            DEBUGMSGTL(("verbose:asp", "asp %p reqinfo %p assigned to request\n",
2426
211
                    asp, asp->reqinfo));
2427
211
            if (varbind_ptr->type == ASN_PRIV_INCL_RANGE) {
2428
0
                DEBUGMSGTL(("snmp_agent", "varbind %d is inclusive\n",
2429
0
                            request->index));
2430
0
                request->inclusive = 1;
2431
0
            }
2432
211
            varbind_ptr->type = ASN_NULL;
2433
211
#ifndef NETSNMP_NO_WRITE_SUPPORT
2434
211
        }
2435
370
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2436
2437
        /*
2438
         * place them in a cache 
2439
         */
2440
370
        if (tp->global_cacheid) {
2441
            /*
2442
             * we need to merge all marked subtrees together 
2443
             */
2444
0
            if (asp->cache_store && -1 !=
2445
0
                (cacheid = netsnmp_get_local_cachid(asp->cache_store,
2446
0
                                                    tp->global_cacheid))) {
2447
0
            } else {
2448
0
                cacheid = ++(asp->treecache_num);
2449
0
                netsnmp_get_or_add_local_cachid(&asp->cache_store,
2450
0
                                                tp->global_cacheid,
2451
0
                                                cacheid);
2452
0
                goto mallocslot;        /* XXX: ick */
2453
0
            }
2454
370
        } else if (tp->cacheid > -1 && tp->cacheid <= asp->treecache_num &&
2455
370
                   asp->treecache[tp->cacheid].subtree == tp) {
2456
            /*
2457
             * we have already added a request to this tree
2458
             * pointer before 
2459
             */
2460
62
            cacheid = tp->cacheid;
2461
308
        } else {
2462
308
            cacheid = ++(asp->treecache_num);
2463
308
          mallocslot:
2464
            /*
2465
             * new slot needed 
2466
             */
2467
308
            if (asp->treecache_num >= asp->treecache_len) {
2468
                /*
2469
                 * expand cache array 
2470
                 */
2471
                /*
2472
                 * WWW: non-linear expansion needed (with cap) 
2473
                 */
2474
0
#define CACHE_GROW_SIZE 16
2475
0
                asp->treecache_len =
2476
0
                    (asp->treecache_len + CACHE_GROW_SIZE);
2477
0
                asp->treecache =
2478
0
                    (netsnmp_tree_cache *)realloc(asp->treecache,
2479
0
                            sizeof(netsnmp_tree_cache) *
2480
0
                            asp->treecache_len);
2481
0
                if (asp->treecache == NULL)
2482
0
                    return NULL;
2483
0
                memset(asp->treecache + cacheid, 0,
2484
0
                       sizeof(netsnmp_tree_cache) * (CACHE_GROW_SIZE));
2485
0
            }
2486
308
            asp->treecache[cacheid].subtree = tp;
2487
308
            asp->treecache[cacheid].requests_begin = request;
2488
308
            tp->cacheid = cacheid;
2489
308
        }
2490
2491
        /*
2492
         * if this is a search type, get the ending range oid as well 
2493
         */
2494
370
        if (asp->pdu->command == SNMP_MSG_GETNEXT ||
2495
370
            asp->pdu->command == SNMP_MSG_GETBULK) {
2496
0
            request->range_end = tp->end_a;
2497
0
            request->range_end_len = tp->end_len;
2498
370
        } else {
2499
370
            request->range_end = NULL;
2500
370
            request->range_end_len = 0;
2501
370
        }
2502
2503
        /*
2504
         * link into chain 
2505
         */
2506
370
        if (asp->treecache[cacheid].requests_end)
2507
62
            asp->treecache[cacheid].requests_end->next = request;
2508
370
        request->next = NULL;
2509
370
        request->prev = asp->treecache[cacheid].requests_end;
2510
370
        asp->treecache[cacheid].requests_end = request;
2511
2512
        /*
2513
         * add the given request to the list of requests they need
2514
         * to handle results for 
2515
         */
2516
370
        request->requestvb = request->requestvb_start = varbind_ptr;
2517
370
    }
2518
745
    return request;
2519
745
}
2520
2521
/*
2522
 * check the ACM(s) for the results on each of the varbinds.
2523
 * If ACM disallows it, replace the value with type
2524
 * 
2525
 * Returns number of varbinds with ACM errors
2526
 */
2527
int
2528
check_acm(netsnmp_agent_session *asp, u_char type)
2529
1.06k
{
2530
1.06k
    int             view;
2531
1.06k
    int             i, j, k;
2532
1.06k
    netsnmp_request_info *request;
2533
1.06k
    int             ret = 0;
2534
1.06k
    netsnmp_variable_list *vb, *vb2, *vbc;
2535
1.06k
    int             earliest = 0;
2536
2537
1.31k
    for (i = 0; i <= asp->treecache_num; i++) {
2538
252
        for (request = asp->treecache[i].requests_begin;
2539
563
             request; request = request->next) {
2540
            /*
2541
             * for each request, run it through in_a_view() 
2542
             */
2543
311
            earliest = 0;
2544
311
            for(j = request->repeat, vb = request->requestvb_start;
2545
622
                vb && j > -1;
2546
311
                j--, vb = vb->next_variable) {
2547
311
                if (vb->type != ASN_NULL &&
2548
311
                    vb->type != ASN_PRIV_RETRY) { /* not yet processed */
2549
159
                    view =
2550
159
                        in_a_view(vb->name, &vb->name_length,
2551
159
                                  asp->pdu, vb->type);
2552
2553
                    /*
2554
                     * if a ACM error occurs, mark it as type passed in 
2555
                     */
2556
159
                    if (view != VACM_SUCCESS) {
2557
0
                        ret++;
2558
0
                        if (request->repeat < request->orig_repeat) {
2559
                            /* basically this means a GETBULK */
2560
0
                            request->repeat++;
2561
0
                            if (!earliest) {
2562
0
                                request->requestvb = vb;
2563
0
                                earliest = 1;
2564
0
                            }
2565
2566
                            /* ugh.  if a whole now exists, we need to
2567
                               move the contents up the chain and fill
2568
                               in at the end else we won't end up
2569
                               lexographically sorted properly */
2570
0
                            if (j > -1 && vb->next_variable &&
2571
0
                                vb->next_variable->type != ASN_NULL &&
2572
0
                                vb->next_variable->type != ASN_PRIV_RETRY) {
2573
0
                                for(k = j, vbc = vb, vb2 = vb->next_variable;
2574
0
                                    k > -2 && vbc && vb2;
2575
0
                                    k--, vbc = vb2, vb2 = vb2->next_variable) {
2576
                                    /* clone next into the current */
2577
0
                                    snmp_clone_var(vb2, vbc);
2578
0
                                    vbc->next_variable = vb2;
2579
0
                                }
2580
0
                            }
2581
0
                        }
2582
0
                        snmp_set_var_typed_value(vb, type, NULL, 0);
2583
0
                        if (ASN_PRIV_RETRY == type)
2584
0
                            request->inclusive = 0;
2585
0
                    }
2586
159
                }
2587
311
            }
2588
311
        }
2589
252
    }
2590
1.06k
    return ret;
2591
1.06k
}
2592
2593
2594
int
2595
netsnmp_create_subtree_cache(netsnmp_agent_session *asp)
2596
9.39k
{
2597
9.39k
    netsnmp_subtree *tp;
2598
9.39k
    netsnmp_variable_list *varbind_ptr, *vbsave, *vbptr, **prevNext;
2599
9.39k
    int             view;
2600
9.39k
    int             vbcount = 0;
2601
9.39k
    int             bulkcount = 0, bulkrep = 0;
2602
9.39k
    int             i = 0, n = 0, r = 0;
2603
9.39k
    netsnmp_request_info *request;
2604
2605
9.39k
    if (NULL == asp || NULL == asp->pdu)
2606
0
        return SNMP_ERR_GENERR;
2607
2608
9.39k
    if (asp->pdu->msgMaxSize == 0)
2609
9.39k
        asp->pdu->msgMaxSize = netsnmp_max_send_msg_size();
2610
9.39k
    DEBUGMSGTL(("msgMaxSize", "pdu max size %lu\n", asp->pdu->msgMaxSize));
2611
2612
9.39k
    if (asp->treecache == NULL && asp->treecache_len == 0) {
2613
9.39k
        asp->treecache_len = SNMP_MAX(1 + asp->vbcount / 4, 16);
2614
9.39k
        asp->treecache = calloc(asp->treecache_len, sizeof(netsnmp_tree_cache));
2615
9.39k
        if (asp->treecache == NULL)
2616
0
            return SNMP_ERR_GENERR;
2617
9.39k
    }
2618
9.39k
    asp->treecache_num = -1;
2619
2620
9.39k
    if (asp->pdu->command == SNMP_MSG_GETBULK) {
2621
        /*
2622
         * getbulk prep 
2623
         */
2624
551
        int             count = count_varbinds(asp->pdu->variables);
2625
551
        if (asp->pdu->errstat < 0) {
2626
277
            asp->pdu->errstat = 0;
2627
277
        }
2628
551
        if (asp->pdu->errindex < 0) {
2629
113
            asp->pdu->errindex = 0;
2630
113
        }
2631
2632
551
        if (asp->pdu->errstat < count) {
2633
126
            n = asp->pdu->errstat;
2634
425
        } else {
2635
425
            n = count;
2636
425
        }
2637
551
        if ((r = count - n) <= 0) {
2638
425
            r = 0;
2639
425
            asp->bulkcache = NULL;
2640
425
        } else {
2641
126
            int           maxbulk =
2642
126
                netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
2643
126
                                   NETSNMP_DS_AGENT_MAX_GETBULKREPEATS);
2644
126
            int maxresponses =
2645
126
                netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
2646
126
                                   NETSNMP_DS_AGENT_MAX_GETBULKRESPONSES);
2647
126
            int avgvarbind =
2648
126
                netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
2649
126
                                   NETSNMP_DS_AGENT_AVG_BULKVARBINDSIZE);
2650
2651
126
            if (maxresponses == 0)
2652
126
                maxresponses = 100;   /* more than reasonable default */
2653
2654
            /* ensure that the total number of responses fits in a mallocable
2655
             * result vector
2656
             */
2657
126
            if (maxresponses < 0 ||
2658
126
                maxresponses > (int)(INT_MAX / sizeof(struct varbind_list *)))
2659
0
                maxresponses = (int)(INT_MAX / sizeof(struct varbind_list *));
2660
126
            DEBUGMSGTL(("snmp_agent:bulk", "maxresponse %d\n", maxresponses));
2661
2662
            /* reduce maxresponses by dividing the sessions max size by a
2663
             * (very) rough approximation of the size of an average
2664
             * varbind. 15 seems to be a reasonable balance between getting
2665
             * enough varbinds to fill the packet vs retrieving varbinds
2666
             * that will be discarded to make the response fit the packet size.
2667
             */
2668
126
            if (avgvarbind == 0)
2669
126
                avgvarbind = 15;
2670
2671
126
            if (maxresponses > (asp->pdu->msgMaxSize / avgvarbind)) {
2672
0
                maxresponses = asp->pdu->msgMaxSize / avgvarbind;
2673
0
                DEBUGMSGTL(("snmp_agent:bulk",
2674
0
                            "lowering maxresponse to %d based pdusession msgMaxSize %ld and avgBulkVarbindSize %d\n",
2675
0
                            maxresponses, asp->pdu->msgMaxSize, avgvarbind));
2676
0
            }
2677
2678
             /* ensure that the maximum number of repetitions will fit in the
2679
             * result vector
2680
             */
2681
126
            if (maxbulk <= 0 || maxbulk > maxresponses / r)
2682
126
                maxbulk = maxresponses / r;
2683
2684
            /* limit getbulk number of repeats to a configured size */
2685
126
            if (asp->pdu->errindex > maxbulk) {
2686
64
                asp->pdu->errindex = maxbulk;
2687
64
                DEBUGMSGTL(("snmp_agent:bulk",
2688
64
                            "lowering requested getbulk repeats to %ld\n",
2689
64
                            asp->pdu->errindex));
2690
64
            }
2691
2692
126
            asp->bulkcache =
2693
126
                (netsnmp_variable_list **) malloc(
2694
126
                    (n + asp->pdu->errindex * r) * sizeof(struct varbind_list *));
2695
2696
126
            if (!asp->bulkcache) {
2697
0
                DEBUGMSGTL(("snmp_agent:bulk", "Bulkcache malloc failed\n"));
2698
0
                return SNMP_ERR_GENERR;
2699
0
            }
2700
126
        }
2701
551
        DEBUGMSGTL(("snmp_agent:bulk", "GETBULK N = %d, M = %ld, R = %d\n",
2702
551
                    n, asp->pdu->errindex, r));
2703
551
    }
2704
2705
    /*
2706
     * collect varbinds into their registered trees 
2707
     */
2708
9.39k
    prevNext = &(asp->pdu->variables);
2709
10.1k
    for (varbind_ptr = asp->pdu->variables; varbind_ptr;
2710
9.39k
         varbind_ptr = vbsave) {
2711
2712
        /*
2713
         * getbulk mess with this pointer, so save it 
2714
         */
2715
763
        vbsave = varbind_ptr->next_variable;
2716
2717
763
        if (asp->pdu->command == SNMP_MSG_GETBULK) {
2718
349
            if (n > 0) {
2719
134
                n--;
2720
215
            } else {
2721
                /*
2722
                 * repeat request varbinds on GETBULK.  These will
2723
                 * have to be properly rearranged later though as
2724
                 * responses are supposed to actually be interlaced
2725
                 * with each other.  This is done with the asp->bulkcache. 
2726
                 */
2727
215
                bulkrep = asp->pdu->errindex - 1;
2728
215
                if (asp->pdu->errindex > 0) {
2729
197
                    vbptr = varbind_ptr;
2730
197
                    asp->bulkcache[bulkcount++] = vbptr;
2731
2732
7.61k
                    for (i = 1; i < asp->pdu->errindex; i++) {
2733
7.41k
                        vbptr->next_variable =
2734
7.41k
                            SNMP_MALLOC_STRUCT(variable_list);
2735
                        /*
2736
                         * don't clone the oid as it's got to be
2737
                         * overwritten anyway 
2738
                         */
2739
7.41k
                        if (!vbptr->next_variable) {
2740
                            /*
2741
                             * XXXWWW: ack!!! 
2742
                             */
2743
0
                            DEBUGMSGTL(("snmp_agent", "NextVar malloc failed\n"));
2744
7.41k
                        } else {
2745
7.41k
                            vbptr = vbptr->next_variable;
2746
7.41k
                            vbptr->name_length = 0;
2747
7.41k
                            vbptr->type = ASN_NULL;
2748
7.41k
                            asp->bulkcache[bulkcount++] = vbptr;
2749
7.41k
                        }
2750
7.41k
                    }
2751
197
                    vbptr->next_variable = vbsave;
2752
197
                } else {
2753
                    /*
2754
                     * 0 repeats requested for this varbind, so take it off
2755
                     * the list.  
2756
                     */
2757
18
                    vbptr = varbind_ptr;
2758
18
                    *prevNext = vbptr->next_variable;
2759
18
                    vbptr->next_variable = NULL;
2760
18
                    snmp_free_varbind(vbptr);
2761
18
                    asp->vbcount--;
2762
18
                    continue;
2763
18
                }
2764
215
            }
2765
349
        }
2766
2767
        /*
2768
         * count the varbinds 
2769
         */
2770
745
        ++vbcount;
2771
2772
        /*
2773
         * find the owning tree 
2774
         */
2775
745
        tp = netsnmp_subtree_find(varbind_ptr->name, varbind_ptr->name_length,
2776
745
          NULL, asp->pdu->contextName);
2777
2778
        /*
2779
         * check access control 
2780
         */
2781
745
        switch (asp->pdu->command) {
2782
152
        case SNMP_MSG_GET:
2783
152
            view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
2784
152
                             asp->pdu, varbind_ptr->type);
2785
152
            if (view != VACM_SUCCESS)
2786
0
                snmp_set_var_typed_value(varbind_ptr, SNMP_NOSUCHOBJECT,
2787
0
                                         NULL, 0);
2788
152
            break;
2789
2790
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
2791
159
        case SNMP_MSG_SET:
2792
159
            view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
2793
159
                             asp->pdu, varbind_ptr->type);
2794
159
            if (view != VACM_SUCCESS) {
2795
0
                asp->index = vbcount;
2796
0
                return SNMP_ERR_NOACCESS;
2797
0
            }
2798
159
            break;
2799
159
#endif /* NETSNMP_NO_WRITE_SUPPORT */
2800
2801
159
        case SNMP_MSG_GETNEXT:
2802
375
        case SNMP_MSG_GETBULK:
2803
434
        default:
2804
434
            view = VACM_SUCCESS;
2805
            /*
2806
             * XXXWWW: check VACM here to see if "tp" is even worthwhile 
2807
             */
2808
745
        }
2809
745
        if (view == VACM_SUCCESS) {
2810
745
            request = netsnmp_add_varbind_to_cache(asp, vbcount, varbind_ptr,
2811
745
               tp);
2812
745
            if (request && asp->pdu->command == SNMP_MSG_GETBULK) {
2813
0
                request->repeat = request->orig_repeat = bulkrep;
2814
0
            }
2815
745
        }
2816
2817
745
        prevNext = &(varbind_ptr->next_variable);
2818
745
    }
2819
2820
9.39k
    return SNMPERR_SUCCESS;
2821
9.39k
}
2822
2823
/*
2824
 * this function is only applicable in getnext like contexts 
2825
 */
2826
int
2827
netsnmp_reassign_requests(netsnmp_agent_session *asp)
2828
0
{
2829
    /*
2830
     * assume all the requests have been filled or rejected by the
2831
     * subtrees, so reassign the rejected ones to the next subtree in
2832
     * the chain 
2833
     */
2834
2835
0
    int             i;
2836
2837
    /*
2838
     * get old info 
2839
     */
2840
0
    netsnmp_tree_cache *old_treecache = asp->treecache;
2841
2842
    /*
2843
     * malloc new space 
2844
     */
2845
0
    asp->treecache = calloc(asp->treecache_len, sizeof(netsnmp_tree_cache));
2846
2847
0
    if (asp->treecache == NULL)
2848
0
        return SNMP_ERR_GENERR;
2849
2850
0
    asp->treecache_num = -1;
2851
0
    if (asp->cache_store) {
2852
0
        netsnmp_free_cachemap(asp->cache_store);
2853
0
        asp->cache_store = NULL;
2854
0
    }
2855
2856
0
    for (i = 0; i < asp->vbcount; i++) {
2857
0
        if (asp->requests[i].requestvb == NULL) {
2858
            /*
2859
             * Occurs when there's a mixture of still active
2860
             *   and "endOfMibView" repetitions
2861
             */
2862
0
            continue;
2863
0
        }
2864
0
        if (asp->requests[i].requestvb->type == ASN_NULL) {
2865
0
            if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
2866
0
                                              asp->requests[i].requestvb,
2867
0
                                              asp->requests[i].subtree->next)) {
2868
0
                SNMP_FREE(old_treecache);
2869
0
            }
2870
0
        } else if (asp->requests[i].requestvb->type == ASN_PRIV_RETRY) {
2871
            /*
2872
             * re-add the same subtree 
2873
             */
2874
0
            asp->requests[i].requestvb->type = ASN_NULL;
2875
0
            if (!netsnmp_add_varbind_to_cache(asp, asp->requests[i].index,
2876
0
                                              asp->requests[i].requestvb,
2877
0
                                              asp->requests[i].subtree)) {
2878
0
                SNMP_FREE(old_treecache);
2879
0
            }
2880
0
        }
2881
0
    }
2882
2883
0
    SNMP_FREE(old_treecache);
2884
0
    return SNMP_ERR_NOERROR;
2885
0
}
2886
2887
void
2888
netsnmp_delete_request_infos(netsnmp_request_info *reqlist)
2889
0
{
2890
0
    while (reqlist) {
2891
0
        netsnmp_free_request_data_sets(reqlist);
2892
0
        reqlist = reqlist->next;
2893
0
    }
2894
0
}
2895
2896
#ifndef NETSNMP_FEATURE_REMOVE_DELETE_SUBTREE_CACHE
2897
void
2898
netsnmp_delete_subtree_cache(netsnmp_agent_session *asp)
2899
0
{
2900
0
    while (asp->treecache_num >= 0) {
2901
        /*
2902
         * don't delete subtrees 
2903
         */
2904
0
        netsnmp_delete_request_infos(asp->treecache[asp->treecache_num].
2905
0
                                     requests_begin);
2906
0
        asp->treecache_num--;
2907
0
    }
2908
0
}
2909
#endif /* NETSNMP_FEATURE_REMOVE_DELETE_SUBTREE_CACHE */
2910
2911
#ifndef NETSNMP_FEATURE_REMOVE_CHECK_ALL_REQUESTS_ERROR
2912
/*
2913
 * check all requests for errors
2914
 *
2915
 * @Note:
2916
 * This function is a little different from the others in that
2917
 * it does not use any linked lists, instead using the original
2918
 * asp requests array. This is of particular importance for
2919
 * cases where the linked lists are unreliable. One known instance
2920
 * of this scenario occurs when the row_merge helper is used, which
2921
 * may temporarily disrupts linked lists during its (and its children's)
2922
 * handling of requests.
2923
 */
2924
int
2925
netsnmp_check_all_requests_error(netsnmp_agent_session *asp,
2926
                                 int look_for_specific)
2927
0
{
2928
0
    int i;
2929
2930
    /*
2931
     * find any errors marked in the requests 
2932
     */
2933
0
    for( i = 0; i < asp->vbcount; ++i ) {
2934
0
        if ((SNMP_ERR_NOERROR != asp->requests[i].status) &&
2935
0
            (!look_for_specific ||
2936
0
             asp->requests[i].status == look_for_specific))
2937
0
            return asp->requests[i].status;
2938
0
    }
2939
2940
0
    return SNMP_ERR_NOERROR;
2941
0
}
2942
#endif /* NETSNMP_FEATURE_REMOVE_CHECK_ALL_REQUESTS_ERROR */
2943
2944
#ifndef NETSNMP_FEATURE_REMOVE_CHECK_REQUESTS_ERROR
2945
int
2946
netsnmp_check_requests_error(netsnmp_request_info *requests)
2947
0
{
2948
    /*
2949
     * find any errors marked in the requests 
2950
     */
2951
0
    for (;requests;requests = requests->next) {
2952
0
        if (requests->status != SNMP_ERR_NOERROR)
2953
0
            return requests->status;
2954
0
    }
2955
0
    return SNMP_ERR_NOERROR;
2956
0
}
2957
#endif /* NETSNMP_FEATURE_REMOVE_CHECK_REQUESTS_ERROR */
2958
2959
int
2960
netsnmp_check_requests_status(netsnmp_agent_session *asp,
2961
                              netsnmp_request_info *requests,
2962
                              int look_for_specific)
2963
391
{
2964
    /*
2965
     * find any errors marked in the requests 
2966
     */
2967
861
    while (requests) {
2968
470
        if(requests->agent_req_info != asp->reqinfo) {
2969
0
            DEBUGMSGTL(("verbose:asp",
2970
0
                        "**reqinfo %p doesn't match cached reqinfo %p\n",
2971
0
                        asp->reqinfo, requests->agent_req_info));
2972
0
        }
2973
470
        if (requests->status != SNMP_ERR_NOERROR &&
2974
470
            (!look_for_specific || requests->status == look_for_specific)
2975
470
            && (look_for_specific || asp->index == 0
2976
318
                || requests->index <= asp->index)) {
2977
224
            asp->index = requests->index;
2978
224
            asp->status = requests->status;
2979
224
        }
2980
470
        requests = requests->next;
2981
470
    }
2982
391
    return asp->status;
2983
391
}
2984
2985
int
2986
netsnmp_check_all_requests_status(netsnmp_agent_session *asp,
2987
                                  int look_for_specific)
2988
0
{
2989
0
    int             i;
2990
0
    for (i = 0; i <= asp->treecache_num; i++) {
2991
0
        netsnmp_check_requests_status(asp,
2992
0
                                      asp->treecache[i].requests_begin,
2993
0
                                      look_for_specific);
2994
0
    }
2995
0
    return asp->status;
2996
0
}
2997
2998
int
2999
handle_var_requests(netsnmp_agent_session *asp)
3000
8.90k
{
3001
8.90k
    int             i, retstatus = SNMP_ERR_NOERROR,
3002
8.90k
        status = SNMP_ERR_NOERROR, final_status = SNMP_ERR_NOERROR;
3003
8.90k
    netsnmp_handler_registration *reginfo;
3004
3005
8.90k
    asp->reqinfo->asp = asp;
3006
8.90k
    asp->reqinfo->mode = asp->mode;
3007
3008
    /*
3009
     * now, have the subtrees in the cache go search for their results 
3010
     */
3011
9.29k
    for (i = 0; i <= asp->treecache_num; i++) {
3012
        /*
3013
         * don't call handlers w/null reginfo.
3014
         * - when is this? sub agent disconnected while request processing?
3015
         * - should this case encompass more of this subroutine?
3016
         *   - does check_request_status make send if handlers weren't called?
3017
         */
3018
391
        if(NULL != asp->treecache[i].subtree->reginfo) {
3019
391
            reginfo = asp->treecache[i].subtree->reginfo;
3020
391
            status = netsnmp_call_handlers(reginfo, asp->reqinfo,
3021
391
                                           asp->treecache[i].requests_begin);
3022
391
        }
3023
0
        else
3024
0
            status = SNMP_ERR_GENERR;
3025
3026
        /*
3027
         * find any errors marked in the requests.  For later parts of
3028
         * SET processing, only check for new errors specific to that
3029
         * set processing directive (which must supersede the previous
3030
         * errors).
3031
         */
3032
391
        switch (asp->mode) {
3033
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3034
0
        case MODE_SET_COMMIT:
3035
0
            retstatus = netsnmp_check_requests_status(asp,
3036
0
                  asp->treecache[i].
3037
0
                  requests_begin,
3038
0
                  SNMP_ERR_COMMITFAILED);
3039
0
            break;
3040
3041
0
        case MODE_SET_UNDO:
3042
0
            retstatus = netsnmp_check_requests_status(asp,
3043
0
                  asp->treecache[i].
3044
0
                  requests_begin,
3045
0
                  SNMP_ERR_UNDOFAILED);
3046
0
            break;
3047
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3048
3049
391
        default:
3050
391
            retstatus = netsnmp_check_requests_status(asp,
3051
391
                  asp->treecache[i].
3052
391
                  requests_begin, 0);
3053
391
            break;
3054
391
        }
3055
3056
        /*
3057
         * always take lowest varbind if possible 
3058
         */
3059
391
        if (retstatus != SNMP_ERR_NOERROR) {
3060
278
            status = retstatus;
3061
278
  }
3062
3063
        /*
3064
         * other things we know less about (no index) 
3065
         */
3066
        /*
3067
         * WWW: drop support for this? 
3068
         */
3069
391
        if (final_status == SNMP_ERR_NOERROR && status != SNMP_ERR_NOERROR) {
3070
            /*
3071
             * we can't break here, since some processing needs to be
3072
             * done for all requests anyway (IE, SET handling for UNDO
3073
             * needs to be called regardless of previous status
3074
             * results.
3075
             * WWW:  This should be predictable though and
3076
             * breaking should be possible in some cases (eg GET,
3077
             * GETNEXT, ...) 
3078
             */
3079
224
            final_status = status;
3080
224
        }
3081
391
    }
3082
3083
8.90k
    return final_status;
3084
8.90k
}
3085
3086
void
3087
netsnmp_check_delegated_requests(void)
3088
0
{
3089
0
    netsnmp_agent_session *asp, *prev_asp = NULL, *next_asp = NULL;
3090
3091
0
    for (asp = agent_delegated_list; asp; asp = next_asp) {
3092
0
        next_asp = asp->next;   /* save in case we clean up asp */
3093
0
        if (!netsnmp_check_for_delegated(asp)) {
3094
3095
            /*
3096
             * we're done with this one, remove from queue 
3097
             */
3098
0
            if (prev_asp != NULL)
3099
0
                prev_asp->next = asp->next;
3100
0
            else
3101
0
                agent_delegated_list = asp->next;
3102
0
            asp->next = NULL;
3103
3104
            /*
3105
             * check request status
3106
             */
3107
0
            netsnmp_check_all_requests_status(asp, 0);
3108
            
3109
            /*
3110
             * continue processing or finish up 
3111
             */
3112
0
            check_delayed_request(asp);
3113
3114
            /*
3115
             * if head was removed, don't drop it if it
3116
             * was it re-queued
3117
             */
3118
0
            if ((prev_asp == NULL) && (agent_delegated_list == asp)) {
3119
0
                prev_asp = asp;
3120
0
            }
3121
0
        } else {
3122
3123
            /*
3124
             * asp is still on the queue
3125
             */
3126
0
            prev_asp = asp;
3127
0
        }
3128
0
    }
3129
0
}
3130
3131
/*
3132
 * loop through our sessions known delegated sessions and check to see
3133
 * if they've completed yet. If there are no more delegated sessions,
3134
 * check for and process any queued requests
3135
 */
3136
void
3137
netsnmp_check_outstanding_agent_requests(void)
3138
0
{
3139
0
    netsnmp_agent_session *asp;
3140
3141
    /*
3142
     * deal with delegated requests
3143
     */
3144
0
    netsnmp_check_delegated_requests();
3145
3146
    /*
3147
     * if we are processing a set and there are more delegated
3148
     * requests, keep waiting before getting to queued requests.
3149
     */
3150
0
    if (netsnmp_processing_set && (NULL != agent_delegated_list))
3151
0
        return;
3152
3153
0
    while (netsnmp_agent_queued_list) {
3154
3155
        /*
3156
         * if we are processing a set, the first item better be
3157
         * the set being (or waiting to be) processed.
3158
         */
3159
0
        netsnmp_assert((!netsnmp_processing_set) ||
3160
0
                       (netsnmp_processing_set == netsnmp_agent_queued_list));
3161
3162
        /*
3163
         * if the top request is a set, don't pop it
3164
         * off if there are delegated requests
3165
         */
3166
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3167
0
        if ((netsnmp_agent_queued_list->pdu->command == SNMP_MSG_SET) &&
3168
0
            (agent_delegated_list)) {
3169
3170
0
            netsnmp_assert(netsnmp_processing_set == NULL);
3171
3172
0
            netsnmp_processing_set = netsnmp_agent_queued_list;
3173
0
            DEBUGMSGTL(("snmp_agent", "SET request remains queued while "
3174
0
                        "delegated requests finish, asp = %8p\n",
3175
0
                        agent_delegated_list));
3176
0
            break;
3177
0
        }
3178
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3179
3180
        /*
3181
         * pop the first request and process it
3182
         */
3183
0
        asp = netsnmp_agent_queued_list;
3184
0
        netsnmp_agent_queued_list = asp->next;
3185
0
        DEBUGMSGTL(("snmp_agent",
3186
0
                    "processing queued request, asp = %8p\n", asp));
3187
3188
0
        netsnmp_handle_request(asp, asp->status);
3189
3190
        /*
3191
         * if we hit a set, stop
3192
         */
3193
0
        if (NULL != netsnmp_processing_set)
3194
0
            break;
3195
0
    }
3196
0
}
3197
3198
/** Decide if the requested transaction_id is still being processed
3199
   within the agent.  This is used to validate whether a delayed cache
3200
   (containing possibly freed pointers) is still usable.
3201
3202
   returns SNMPERR_SUCCESS if it's still valid, or SNMPERR_GENERR if not. */
3203
int
3204
netsnmp_check_transaction_id(int transaction_id)
3205
0
{
3206
0
    netsnmp_agent_session *asp;
3207
3208
0
    for (asp = agent_delegated_list; asp; asp = asp->next) {
3209
0
        if (asp->pdu->transid == transaction_id)
3210
0
            return SNMPERR_SUCCESS;
3211
0
    }
3212
0
    return SNMPERR_GENERR;
3213
0
}
3214
3215
3216
/*
3217
 * check_delayed_request(asp)
3218
 *
3219
 * Called to reexamine a set of requests and continue processing them
3220
 * once all the previous (delayed) requests have been handled one way
3221
 * or another.
3222
 */
3223
3224
int
3225
check_delayed_request(netsnmp_agent_session *asp)
3226
0
{
3227
0
    int             status = SNMP_ERR_NOERROR;
3228
3229
0
    DEBUGMSGTL(("snmp_agent", "processing delegated request, asp = %8p\n",
3230
0
                asp));
3231
3232
0
    switch (asp->mode) {
3233
0
    case SNMP_MSG_GETBULK:
3234
0
    case SNMP_MSG_GETNEXT:
3235
0
        netsnmp_check_all_requests_status(asp, 0);
3236
0
        if (asp->flags & SNMP_AGENT_FLAGS_CANCEL_IN_PROGRESS) {
3237
0
            DEBUGMSGTL(("snmp_agent","canceling next walk for asp %p\n", asp));
3238
0
            break;
3239
0
        }
3240
0
        handle_getnext_loop(asp);
3241
0
        if (netsnmp_check_for_delegated(asp) &&
3242
0
            netsnmp_check_transaction_id(asp->pdu->transid) !=
3243
0
            SNMPERR_SUCCESS) {
3244
            /*
3245
             * add to delegated request chain 
3246
             */
3247
0
            if (!netsnmp_check_delegated_chain_for(asp)) {
3248
0
                asp->next = agent_delegated_list;
3249
0
                agent_delegated_list = asp;
3250
0
            }
3251
0
        }
3252
0
        break;
3253
3254
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3255
0
    case MODE_SET_COMMIT:
3256
0
        netsnmp_check_all_requests_status(asp, SNMP_ERR_COMMITFAILED);
3257
0
        goto settop;
3258
3259
0
    case MODE_SET_UNDO:
3260
0
        netsnmp_check_all_requests_status(asp, SNMP_ERR_UNDOFAILED);
3261
0
        goto settop;
3262
3263
0
    case MODE_SET_BEGIN:
3264
0
    case MODE_SET_RESERVE1:
3265
0
    case MODE_SET_RESERVE2:
3266
0
    case MODE_SET_ACTION:
3267
0
    case MODE_SET_FREE:
3268
0
      settop:
3269
        /* If we should do only one pass, this mean we */
3270
        /* should not reenter this function */
3271
0
        if ((asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
3272
            /* We should have finished the processing after the first */
3273
            /* handle_set_loop, so just wrap up */
3274
0
            break;
3275
0
        }
3276
0
        handle_set_loop(asp);
3277
0
        if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
3278
3279
0
            if (netsnmp_check_for_delegated_and_add(asp)) {
3280
                /*
3281
                 * add to delegated request chain 
3282
                 */
3283
0
                if (!asp->status)
3284
0
                    asp->status = status;
3285
0
            }
3286
3287
0
            return SNMP_ERR_NOERROR;
3288
0
        }
3289
0
        break;
3290
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3291
3292
0
    default:
3293
0
        break;
3294
0
    }
3295
3296
    /*
3297
     * if we don't have anything outstanding (delegated), wrap up 
3298
     */
3299
0
    if (!netsnmp_check_for_delegated(asp))
3300
0
        return netsnmp_wrap_up_request(asp, status);
3301
3302
0
    return 1;
3303
0
}
3304
3305
/** returns 1 if there are valid GETNEXT requests left.  Returns 0 if not. */
3306
int
3307
check_getnext_results(netsnmp_agent_session *asp)
3308
646
{
3309
    /*
3310
     * get old info 
3311
     */
3312
646
    netsnmp_tree_cache *old_treecache = asp->treecache;
3313
646
    int             old_treecache_num = asp->treecache_num;
3314
646
    int             count = 0;
3315
646
    int             i, special = 0;
3316
646
    netsnmp_request_info *request;
3317
3318
646
    if (asp->mode == SNMP_MSG_GET) {
3319
        /*
3320
         * Special case for doing INCLUSIVE getNext operations in
3321
         * AgentX subagents.  
3322
         */
3323
0
        DEBUGMSGTL(("snmp_agent",
3324
0
                    "asp->mode == SNMP_MSG_GET in ch_getnext\n"));
3325
0
        asp->mode = asp->oldmode;
3326
0
        special = 1;
3327
0
    }
3328
3329
646
    for (i = 0; i <= old_treecache_num; i++) {
3330
0
        for (request = old_treecache[i].requests_begin; request;
3331
0
             request = request->next) {
3332
3333
            /*
3334
             * If we have just done the special case AgentX GET, then any
3335
             * requests which were not INCLUSIVE will now have a wrong
3336
             * response, so junk them and retry from the same place (except
3337
             * that this time the handler will be called in "inexact"
3338
             * mode).  
3339
             */
3340
3341
0
            if (special) {
3342
0
                if (!request->inclusive) {
3343
0
                    DEBUGMSGTL(("snmp_agent",
3344
0
                                "request %d wasn't inclusive\n",
3345
0
                                request->index));
3346
0
                    snmp_set_var_typed_value(request->requestvb,
3347
0
                                             ASN_PRIV_RETRY, NULL, 0);
3348
0
                } else if (request->requestvb->type == ASN_NULL ||
3349
0
                           request->requestvb->type == SNMP_NOSUCHINSTANCE ||
3350
0
                           request->requestvb->type == SNMP_NOSUCHOBJECT) {
3351
                    /*
3352
                     * it was inclusive, but no results.  Still retry this
3353
                     * search. 
3354
                     */
3355
0
                    snmp_set_var_typed_value(request->requestvb,
3356
0
                                             ASN_PRIV_RETRY, NULL, 0);
3357
0
                }
3358
0
            }
3359
3360
            /*
3361
             * out of range? 
3362
             */
3363
0
            if (snmp_oid_compare(request->requestvb->name,
3364
0
                                 request->requestvb->name_length,
3365
0
                                 request->range_end,
3366
0
                                 request->range_end_len) >= 0) {
3367
                /*
3368
                 * ack, it's beyond the accepted end of range. 
3369
                 */
3370
                /*
3371
                 * fix it by setting the oid to the end of range oid instead 
3372
                 */
3373
0
                DEBUGMSGTL(("check_getnext_results",
3374
0
                            "request response %d out of range\n",
3375
0
                            request->index));
3376
                /*
3377
                 * I'm not sure why inclusive is set unconditionally here (see
3378
                 * comments for revision 1.161), but it causes a problem for
3379
                 * GETBULK over an overridden variable. The bulk-to-next
3380
                 * handler re-uses the same request for multiple varbinds,
3381
                 * and once inclusive was set, it was never cleared. So, a
3382
                 * hack. Instead of setting it to 1, set it to 2, so bulk-to
3383
                 * next can clear it later. As of the time of this hack, all
3384
                 * checks of this var are boolean checks (not == 1), so this
3385
                 * should be safe. Cross your fingers.
3386
                 */
3387
0
                request->inclusive = 2;
3388
                /*
3389
                 * XXX: should set this to the original OID? 
3390
                 */
3391
0
                snmp_set_var_objid(request->requestvb,
3392
0
                                   request->range_end,
3393
0
                                   request->range_end_len);
3394
0
                snmp_set_var_typed_value(request->requestvb, ASN_NULL,
3395
0
                                         NULL, 0);
3396
0
            }
3397
3398
            /*
3399
             * mark any existent requests with illegal results as NULL 
3400
             */
3401
0
            if (request->requestvb->type == SNMP_ENDOFMIBVIEW) {
3402
                /*
3403
                 * illegal response from a subagent.  Change it back to NULL 
3404
                 *  xxx-rks: err, how do we know this is a subagent?
3405
                 */
3406
0
                request->requestvb->type = ASN_NULL;
3407
0
                request->inclusive = 1;
3408
0
            }
3409
3410
0
            if (request->requestvb->type == ASN_NULL ||
3411
0
                request->requestvb->type == ASN_PRIV_RETRY ||
3412
0
                (asp->reqinfo->mode == MODE_GETBULK
3413
0
                 && request->repeat > 0))
3414
0
                count++;
3415
0
        }
3416
0
    }
3417
646
    return count;
3418
646
}
3419
3420
/** repeatedly calls getnext handlers looking for an answer till all
3421
   requests are satisfied.  It's expected that one pass has been made
3422
   before entering this function */
3423
int
3424
handle_getnext_loop(netsnmp_agent_session *asp)
3425
646
{
3426
646
    int             status, rough_size, count = 0, total, val_len;
3427
646
    netsnmp_variable_list *var_ptr, *last_var = NULL;
3428
3429
646
    if (NULL == asp || NULL == asp->pdu)
3430
0
        return SNMP_ERR_GENERR;
3431
3432
646
    total = count_varbinds(asp->pdu->variables);
3433
3434
    /*
3435
     * loop 
3436
     */
3437
646
    while (netsnmp_running) {
3438
3439
        /*
3440
         * bail for now if anything is delegated. 
3441
         */
3442
646
        if (netsnmp_check_for_delegated(asp)) {
3443
0
            return SNMP_ERR_NOERROR;
3444
0
        }
3445
3446
        /*
3447
         * check vacm against results 
3448
         */
3449
646
        check_acm(asp, ASN_PRIV_RETRY);
3450
3451
        /*
3452
         * need to keep going we're not done yet. 
3453
         */
3454
646
        if (!check_getnext_results(asp))
3455
            /*
3456
             * nothing left, quit now 
3457
             */
3458
646
            break;
3459
3460
0
        count = rough_size = 0;
3461
0
        DEBUGMSGTL(("results:intermediate",
3462
0
                    "getnext results, before next pass:\n"));
3463
0
        for (var_ptr = asp->pdu->variables; var_ptr; 
3464
0
             var_ptr = var_ptr->next_variable) {
3465
0
            if ((var_ptr->type == ASN_NULL && 0 == var_ptr->name_length) ||
3466
0
                (var_ptr->type == ASN_PRIV_RETRY)) {
3467
0
                continue;
3468
0
            }
3469
0
            ++count;
3470
0
            DEBUGIF("results:intermediate") {
3471
0
                DEBUGMSGTL(("results:intermediate", "\t"));
3472
0
                DEBUGMSGVAR(("results:intermediate", var_ptr));
3473
0
                DEBUGMSG(("results:intermediate", "\n"));
3474
0
            }
3475
            /*
3476
             * make a very rough guesstimate of the encoded varbind size by
3477
             * adding the name and val lengths. If these rough sizes add up
3478
             * to more than the msgMaxSize, stop gathering new varbinds.
3479
             *
3480
             * [Increasing the accuracy of this estimate would allow us to
3481
             * do better at filling packets and collecting fewer varbinds that
3482
             * we'll later have to trim. This is left as an exercise for the
3483
             * reader.]
3484
             */
3485
0
            rough_size += var_ptr->name_length;
3486
            /** sizeof(oid) is 8 on 64bit systems :-( Hardcode for 4 */
3487
0
            if (var_ptr->type == ASN_OBJECT_ID && sizeof(long) == 8)
3488
0
                val_len = (var_ptr->val_len / 2);
3489
0
            else
3490
0
                val_len = var_ptr->val_len;
3491
3492
0
            DEBUGMSGTL(("results:intermediate", "\t+ %" NETSNMP_PRIz "d %d = %d\n",
3493
0
                        var_ptr->name_length, val_len, rough_size));
3494
0
            if (rough_size > asp->pdu->msgMaxSize) {
3495
0
                DEBUGMSGTL(("results",
3496
0
                            "estimating packet too big; stop gathering\n"));
3497
0
                asp->pdu->flags |= UCD_MSG_FLAG_BULK_TOOBIG |
3498
0
                    UCD_MSG_FLAG_FORWARD_ENCODE;
3499
0
                var_ptr->type = ASN_PRIV_STOP;
3500
0
                if (NULL != last_var)
3501
0
                    last_var->next_variable = NULL;
3502
0
                break;
3503
0
            }
3504
0
            last_var = var_ptr;
3505
0
        }
3506
0
        if (rough_size > asp->pdu->msgMaxSize)
3507
0
            break;
3508
3509
0
        netsnmp_reassign_requests(asp);
3510
0
        status = handle_var_requests(asp);
3511
0
        if (status != SNMP_ERR_NOERROR) {
3512
0
            return status;      /* should never really happen */
3513
0
        }
3514
0
    }
3515
646
    DEBUGMSGTL(("results:summary", "gathered %d/%d varbinds\n", count,
3516
646
                total));
3517
646
    if (!netsnmp_running) {
3518
0
        return SNMP_ERR_GENERR;
3519
0
    }
3520
646
    return SNMP_ERR_NOERROR;
3521
646
}
3522
3523
#ifndef NETSNMP_NO_WRITE_SUPPORT
3524
int
3525
handle_set(netsnmp_agent_session *asp)
3526
8.38k
{
3527
8.38k
    int             status;
3528
    /*
3529
     * SETS require 3-4 passes through the var_op_list.
3530
     * The first two
3531
     * passes verify that all types, lengths, and values are valid
3532
     * and may reserve resources and the third does the set and a
3533
     * fourth executes any actions.  Then the identical GET RESPONSE
3534
     * packet is returned.
3535
     * If either of the first two passes returns an error, another
3536
     * pass is made so that any reserved resources can be freed.
3537
     * If the third pass returns an error, another pass is
3538
     * made so that
3539
     * any changes can be reversed.
3540
     * If the fourth pass (or any of the error handling passes)
3541
     * return an error, we'd rather not know about it!
3542
     */
3543
8.38k
    if (!(asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY)) {
3544
1.12k
        switch (asp->mode) {
3545
270
        case MODE_SET_BEGIN:
3546
270
            snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
3547
270
            asp->rw = WRITE;    /* WWW: still needed? */
3548
270
            asp->mode = MODE_SET_RESERVE1;
3549
270
            asp->status = SNMP_ERR_NOERROR;
3550
270
            break;
3551
3552
270
        case MODE_SET_RESERVE1:
3553
3554
270
            if (asp->status != SNMP_ERR_NOERROR)
3555
112
                asp->mode = MODE_SET_FREE;
3556
158
            else
3557
158
                asp->mode = MODE_SET_RESERVE2;
3558
270
            break;
3559
3560
158
        case MODE_SET_RESERVE2:
3561
158
            if (asp->status != SNMP_ERR_NOERROR)
3562
0
                asp->mode = MODE_SET_FREE;
3563
158
            else
3564
158
                asp->mode = MODE_SET_ACTION;
3565
158
            break;
3566
3567
158
        case MODE_SET_ACTION:
3568
158
            if (asp->status != SNMP_ERR_NOERROR)
3569
0
                asp->mode = MODE_SET_UNDO;
3570
158
            else
3571
158
                asp->mode = MODE_SET_COMMIT;
3572
158
            break;
3573
3574
158
        case MODE_SET_COMMIT:
3575
158
            if (asp->status != SNMP_ERR_NOERROR) {
3576
0
                asp->mode = FINISHED_FAILURE;
3577
158
            } else {
3578
158
                asp->mode = FINISHED_SUCCESS;
3579
158
            }
3580
158
            break;
3581
3582
0
        case MODE_SET_UNDO:
3583
0
            asp->mode = FINISHED_FAILURE;
3584
0
            break;
3585
3586
112
        case MODE_SET_FREE:
3587
112
            asp->mode = FINISHED_FAILURE;
3588
112
            break;
3589
1.12k
        }
3590
1.12k
    }
3591
3592
8.38k
    if (asp->mode != FINISHED_SUCCESS && asp->mode != FINISHED_FAILURE) {
3593
8.11k
        DEBUGMSGTL(("agent_set", "doing set mode = %d (%s)\n", asp->mode,
3594
8.11k
                    se_find_label_in_slist("agent_mode", asp->mode)));
3595
8.11k
        status = handle_var_requests(asp);
3596
8.11k
        DEBUGMSGTL(("agent_set", "did set mode = %d, status = %d\n",
3597
8.11k
                    asp->mode, status));
3598
8.11k
        if ((status != SNMP_ERR_NOERROR && asp->status == SNMP_ERR_NOERROR) ||
3599
8.11k
      status == SNMP_ERR_COMMITFAILED || 
3600
8.11k
      status == SNMP_ERR_UNDOFAILED) {
3601
0
            asp->status = status;
3602
0
        }
3603
8.11k
    }
3604
8.38k
    return asp->status;
3605
8.38k
}
3606
3607
int
3608
handle_set_loop(netsnmp_agent_session *asp)
3609
7.52k
{
3610
8.65k
    while (asp->mode != FINISHED_FAILURE && asp->mode != FINISHED_SUCCESS) {
3611
8.38k
        handle_set(asp);
3612
8.38k
        if (netsnmp_check_for_delegated(asp)) {
3613
0
            return SNMP_ERR_NOERROR;
3614
0
  }
3615
8.38k
        if (asp->pdu->flags & UCD_MSG_FLAG_ONE_PASS_ONLY) {
3616
7.25k
            return asp->status;
3617
7.25k
  }
3618
8.38k
    }
3619
270
    return asp->status;
3620
7.52k
}
3621
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3622
3623
int
3624
netsnmp_handle_request(netsnmp_agent_session *asp, int status)
3625
9.90k
{
3626
9.90k
#ifndef NETSNMP_NO_PDU_STATS
3627
9.90k
    if (_pdu_stats_max > 0) {
3628
        /** tag new pdus with a start time */
3629
0
        marker_t start;
3630
0
        start = (marker_t)netsnmp_agent_get_list_data(asp->reqinfo,
3631
0
                                                      "netsnmp_pdu_stats");
3632
0
        if (NULL == start) {
3633
0
            netsnmp_data_list *data_list;
3634
0
            DEBUGMSGTL(("stats:pdu:start", "starting pdu processing\n"));
3635
3636
0
            netsnmp_set_monotonic_marker(&start); /* will alloc space */
3637
0
            data_list = netsnmp_create_data_list("netsnmp_pdu_stats", start,
3638
0
                                                 free);
3639
0
            if (NULL == data_list) {
3640
0
                free(start);
3641
0
                snmp_log(LOG_WARNING, "error creating data list for stats\n");
3642
0
            } else
3643
0
                netsnmp_agent_add_list_data(asp->reqinfo, data_list);
3644
0
        }
3645
0
    }
3646
9.90k
#endif /* NETSNMP_NO_PDU_STATS */
3647
3648
    /*
3649
     * if this isn't a delegated request trying to finish,
3650
     * processing of a set request should not start until all
3651
     * delegated requests have completed, and no other new requests
3652
     * should be processed until the set request completes.
3653
     */
3654
9.90k
    if ((0 == netsnmp_check_delegated_chain_for(asp)) &&
3655
9.90k
        (asp != netsnmp_processing_set)) {
3656
        /*
3657
         * if we are processing a set and this is not a delegated
3658
         * request, queue the request
3659
         */
3660
9.90k
        if (netsnmp_processing_set) {
3661
0
            netsnmp_add_queued(asp);
3662
0
            DEBUGMSGTL(("snmp_agent",
3663
0
                        "request queued while processing set, "
3664
0
                        "asp = %8p\n", asp));
3665
0
            return 1;
3666
0
        }
3667
3668
        /*
3669
         * check for set request
3670
         */
3671
9.90k
#ifndef NETSNMP_NO_WRITE_SUPPORT
3672
9.90k
        if (asp->pdu->command == SNMP_MSG_SET) {
3673
280
            netsnmp_processing_set = asp;
3674
3675
            /*
3676
             * if there are delegated requests, we must wait for them
3677
             * to finish.
3678
             */
3679
280
            if (agent_delegated_list) {
3680
0
                DEBUGMSGTL(("snmp_agent", "SET request queued while "
3681
0
                            "delegated requests finish, asp = %8p\n",
3682
0
                            asp));
3683
0
                netsnmp_add_queued(asp);
3684
0
                return 1;
3685
0
            }
3686
280
        }
3687
9.90k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3688
9.90k
    }
3689
3690
    /*
3691
     * process the request 
3692
     */
3693
9.90k
    status = handle_pdu(asp);
3694
3695
    /*
3696
     * print the results in appropriate debugging mode 
3697
     */
3698
9.90k
    DEBUGIF("results") {
3699
0
        netsnmp_variable_list *var_ptr;
3700
0
        DEBUGMSGTL(("results", "request results (status = %d):\n",
3701
0
                    status));
3702
0
        for (var_ptr = asp->pdu->variables; var_ptr;
3703
0
             var_ptr = var_ptr->next_variable) {
3704
0
            DEBUGMSGTL(("results", "\t"));
3705
0
            DEBUGMSGVAR(("results", var_ptr));
3706
0
            DEBUGMSG(("results", "\n"));
3707
0
        }
3708
0
    }
3709
3710
    /*
3711
     * check for uncompleted requests 
3712
     */
3713
9.90k
    if (netsnmp_check_for_delegated_and_add(asp)) {
3714
        /*
3715
         * add to delegated request chain 
3716
         */
3717
0
        asp->status = status;
3718
9.90k
    } else {
3719
        /*
3720
         * if we don't have anything outstanding (delegated), wrap up
3721
         */
3722
9.90k
        return netsnmp_wrap_up_request(asp, status);
3723
9.90k
    }
3724
3725
0
    return 1;
3726
9.90k
}
3727
3728
static int
3729
check_set_pdu_for_null_varbind(netsnmp_agent_session *asp)
3730
280
{
3731
280
    int i;
3732
280
    netsnmp_variable_list *v = NULL;
3733
3734
439
    for (i = 1, v = asp->pdu->variables; v != NULL; i++, v = v->next_variable) {
3735
169
  if (v->type == ASN_NULL) {
3736
      /*
3737
       * Protect SET implementations that do not protect themselves
3738
       * against wrong type.
3739
       */
3740
10
      DEBUGMSGTL(("snmp_agent", "disallowing SET with NULL var for varbind %d\n", i));
3741
10
      asp->index = i;
3742
10
      return SNMP_ERR_WRONGTYPE;
3743
10
  }
3744
169
    }
3745
270
    return SNMP_ERR_NOERROR;
3746
280
}
3747
3748
int
3749
handle_pdu(netsnmp_agent_session *asp)
3750
9.90k
{
3751
9.90k
    int             status, inclusives = 0;
3752
9.90k
    netsnmp_variable_list *v = NULL;
3753
3754
9.90k
#ifndef NETSNMP_NO_WRITE_SUPPORT
3755
    /*
3756
     * Check for ASN_NULL in SET request
3757
     */
3758
9.90k
    if (asp->pdu->command == SNMP_MSG_SET) {
3759
280
  status = check_set_pdu_for_null_varbind(asp);
3760
280
  if (status != SNMP_ERR_NOERROR) {
3761
10
      return status;
3762
10
  }
3763
280
    }
3764
9.89k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3765
3766
    /*
3767
     * for illegal requests, mark all nodes as ASN_NULL 
3768
     */
3769
9.89k
    switch (asp->pdu->command) {
3770
3771
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3772
57
    case SNMP_MSG_INTERNAL_SET_RESERVE2:
3773
276
    case SNMP_MSG_INTERNAL_SET_ACTION:
3774
401
    case SNMP_MSG_INTERNAL_SET_COMMIT:
3775
452
    case SNMP_MSG_INTERNAL_SET_FREE:
3776
496
    case SNMP_MSG_INTERNAL_SET_UNDO:
3777
496
        status = get_set_cache(asp);
3778
496
        if (status != SNMP_ERR_NOERROR)
3779
0
            return status;
3780
496
        break;
3781
496
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3782
3783
496
    case SNMP_MSG_GET:
3784
240
    case SNMP_MSG_GETNEXT:
3785
791
    case SNMP_MSG_GETBULK:
3786
1.33k
        for (v = asp->pdu->variables; v != NULL; v = v->next_variable) {
3787
545
            if (v->type == ASN_PRIV_INCL_RANGE) {
3788
                /*
3789
                 * Leave the type for now (it gets set to
3790
                 * ASN_NULL in netsnmp_add_varbind_to_cache,
3791
                 * called by netsnmp_create_subtree_cache below).
3792
                 * If we set it to ASN_NULL now, we wouldn't be
3793
                 * able to distinguish INCLUSIVE search
3794
                 * ranges.  
3795
                 */
3796
0
                inclusives++;
3797
545
            } else {
3798
545
                snmp_set_var_typed_value(v, ASN_NULL, NULL, 0);
3799
545
            }
3800
545
        }
3801
791
        NETSNMP_FALLTHROUGH;
3802
3803
2.63k
    default:
3804
2.63k
#ifndef NETSNMP_NO_WRITE_SUPPORT
3805
2.63k
    case SNMP_MSG_INTERNAL_SET_BEGIN:
3806
9.39k
    case SNMP_MSG_INTERNAL_SET_RESERVE1:
3807
9.39k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3808
9.39k
        asp->vbcount = count_varbinds(asp->pdu->variables);
3809
9.39k
        asp->requests =
3810
9.39k
            calloc(asp->vbcount ? asp->vbcount : 1,
3811
9.39k
                   sizeof(netsnmp_request_info));
3812
        /*
3813
         * collect varbinds 
3814
         */
3815
9.39k
        status = netsnmp_create_subtree_cache(asp);
3816
9.39k
        if (status != SNMP_ERR_NOERROR)
3817
0
            return status;
3818
9.89k
    }
3819
3820
9.89k
    asp->mode = asp->pdu->command;
3821
9.89k
    switch (asp->mode) {
3822
145
    case SNMP_MSG_GET:
3823
        /*
3824
         * increment the message type counter 
3825
         */
3826
145
        snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
3827
3828
        /*
3829
         * check vacm ahead of time 
3830
         */
3831
145
        check_acm(asp, SNMP_NOSUCHOBJECT);
3832
3833
        /*
3834
         * get the results 
3835
         */
3836
145
        status = handle_var_requests(asp);
3837
3838
        /*
3839
         * Deal with unhandled results -> noSuchInstance (rather
3840
         * than noSuchObject -- in that case, the type will
3841
         * already have been set to noSuchObject when we realised
3842
         * we couldn't find an appropriate tree).  
3843
         */
3844
145
        if (status == SNMP_ERR_NOERROR)
3845
145
            snmp_replace_var_types(asp->pdu->variables, ASN_NULL,
3846
145
                                   SNMP_NOSUCHINSTANCE);
3847
145
        break;
3848
3849
95
    case SNMP_MSG_GETNEXT:
3850
95
        snmp_increment_statistic(STAT_SNMPINGETNEXTS);
3851
95
        NETSNMP_FALLTHROUGH;
3852
3853
646
    case SNMP_MSG_GETBULK:     /* note: there is no getbulk stat */
3854
        /*
3855
         * loop through our mib tree till we find an
3856
         * appropriate response to return to the caller. 
3857
         */
3858
3859
646
        if (inclusives) {
3860
            /*
3861
             * This is a special case for AgentX INCLUSIVE getNext
3862
             * requests where a result lexi-equal to the request is okay
3863
             * but if such a result does not exist, we still want the
3864
             * lexi-next one.  So basically we do a GET first, and if any
3865
             * of the INCLUSIVE requests are satisfied, we use that
3866
             * value.  Then, unsatisfied INCLUSIVE requests, and
3867
             * non-INCLUSIVE requests get done as normal.  
3868
             */
3869
3870
0
            DEBUGMSGTL(("snmp_agent", "inclusive range(s) in getNext\n"));
3871
0
            asp->oldmode = asp->mode;
3872
0
            asp->mode = SNMP_MSG_GET;
3873
0
        }
3874
3875
        /*
3876
         * first pass 
3877
         */
3878
646
        status = handle_var_requests(asp);
3879
646
        if (status != SNMP_ERR_NOERROR) {
3880
0
            if (!inclusives)
3881
0
                return status;  /* should never really happen */
3882
0
            else
3883
0
                asp->status = SNMP_ERR_NOERROR;
3884
0
        }
3885
3886
        /*
3887
         * loop through our mib tree till we find an
3888
         * appropriate response to return to the caller. 
3889
         */
3890
3891
646
        status = handle_getnext_loop(asp);
3892
646
        break;
3893
3894
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3895
270
    case SNMP_MSG_SET:
3896
#ifdef NETSNMP_DISABLE_SET_SUPPORT
3897
        return SNMP_ERR_NOTWRITABLE;
3898
#else
3899
        /*
3900
         * check access permissions first 
3901
         */
3902
270
        if (check_acm(asp, SNMP_NOSUCHOBJECT))
3903
0
            return SNMP_ERR_NOTWRITABLE;
3904
3905
270
        asp->mode = MODE_SET_BEGIN;
3906
270
        status = handle_set_loop(asp);
3907
270
#endif
3908
270
        break;
3909
3910
0
    case SNMP_MSG_INTERNAL_SET_BEGIN:
3911
6.75k
    case SNMP_MSG_INTERNAL_SET_RESERVE1:
3912
6.81k
    case SNMP_MSG_INTERNAL_SET_RESERVE2:
3913
7.03k
    case SNMP_MSG_INTERNAL_SET_ACTION:
3914
7.15k
    case SNMP_MSG_INTERNAL_SET_COMMIT:
3915
7.21k
    case SNMP_MSG_INTERNAL_SET_FREE:
3916
7.25k
    case SNMP_MSG_INTERNAL_SET_UNDO:
3917
7.25k
        asp->pdu->flags |= UCD_MSG_FLAG_ONE_PASS_ONLY;
3918
7.25k
        status = handle_set_loop(asp);
3919
        /*
3920
         * asp related cache is saved in cleanup 
3921
         */
3922
7.25k
        break;
3923
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3924
3925
64
    case SNMP_MSG_RESPONSE:
3926
64
        snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
3927
64
        return SNMP_ERR_NOERROR;
3928
3929
0
    case SNMP_MSG_TRAP:
3930
0
    case SNMP_MSG_TRAP2:
3931
0
        snmp_increment_statistic(STAT_SNMPINTRAPS);
3932
0
        return SNMP_ERR_NOERROR;
3933
3934
1.51k
    default:
3935
        /*
3936
         * WWW: are reports counted somewhere ? 
3937
         */
3938
1.51k
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3939
1.51k
        return SNMPERR_GENERR;  /* shouldn't get here */
3940
        /*
3941
         * WWW 
3942
         */
3943
9.89k
    }
3944
8.31k
    return status;
3945
9.89k
}
3946
3947
/** set error for a request
3948
 * \internal external interface: netsnmp_request_set_error
3949
 */
3950
NETSNMP_STATIC_INLINE int
3951
_request_set_error(netsnmp_request_info *request, int mode, int error_value)
3952
470
{
3953
470
    if (!request)
3954
0
        return SNMPERR_NO_VARS;
3955
3956
470
    request->processed = 1;
3957
470
    request->delegated = REQUEST_IS_NOT_DELEGATED;
3958
3959
470
    switch (error_value) {
3960
152
    case SNMP_NOSUCHOBJECT:
3961
152
    case SNMP_NOSUCHINSTANCE:
3962
152
    case SNMP_ENDOFMIBVIEW:
3963
        /*
3964
         * these are exceptions that should be put in the varbind
3965
         * in the case of a GET but should be translated for a SET
3966
         * into a real error status code and put in the request 
3967
         */
3968
152
        switch (mode) {
3969
152
        case MODE_GET:
3970
152
        case MODE_GETNEXT:
3971
152
        case MODE_GETBULK:
3972
152
            request->requestvb->type = error_value;
3973
152
            break;
3974
3975
            /*
3976
             * These are technically illegal to set by the
3977
             * client APIs for these modes.  But accepting
3978
             * them here allows the 'sparse_table' helper to
3979
             * provide some common table handling processing
3980
             *
3981
            snmp_log(LOG_ERR, "Illegal error_value %d for mode %d ignored\n",
3982
                     error_value, mode);
3983
            return SNMPERR_VALUE;
3984
             */
3985
3986
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3987
0
        case SNMP_MSG_INTERNAL_SET_RESERVE1:
3988
0
            request->status = SNMP_ERR_NOCREATION;
3989
0
            break;
3990
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
3991
3992
0
        default:
3993
0
            request->status = SNMP_ERR_NOSUCHNAME;      /* WWW: correct? */
3994
0
            break;
3995
152
        }
3996
152
        break;                  /* never get here */
3997
3998
318
    default:
3999
318
        if (error_value < 0) {
4000
            /*
4001
             * illegal local error code.  translate to generr 
4002
             */
4003
            /*
4004
             * WWW: full translation map? 
4005
             */
4006
0
            snmp_log(LOG_ERR, "Illegal error_value %d translated to %d\n",
4007
0
                     error_value, SNMP_ERR_GENERR);
4008
0
            request->status = SNMP_ERR_GENERR;
4009
318
        } else {
4010
            /*
4011
             * WWW: translations and mode checking? 
4012
             */
4013
318
            request->status = error_value;
4014
318
        }
4015
318
        break;
4016
470
    }
4017
470
    return SNMPERR_SUCCESS;
4018
470
}
4019
4020
/** set error for a request
4021
 * @param request request which has error
4022
 * @param error_value error value for request
4023
 */
4024
int
4025
netsnmp_request_set_error(netsnmp_request_info *request, int error_value)
4026
0
{
4027
0
    if (!request || !request->agent_req_info)
4028
0
        return SNMPERR_NO_VARS;
4029
4030
0
    return _request_set_error(request, request->agent_req_info->mode,
4031
0
                              error_value);
4032
0
}
4033
4034
#ifndef NETSNMP_FEATURE_REMOVE_REQUEST_SET_ERROR_IDX
4035
/** set error for a request within a request list
4036
 * @param request head of the request list
4037
 * @param error_value error value for request
4038
 * @param idx index of the request which has the error
4039
 */
4040
int
4041
netsnmp_request_set_error_idx(netsnmp_request_info *request,
4042
                              int error_value, int idx)
4043
0
{
4044
0
    int i;
4045
0
    netsnmp_request_info *req = request;
4046
4047
0
    if (!request || !request->agent_req_info)
4048
0
        return SNMPERR_NO_VARS;
4049
4050
    /*
4051
     * Skip to the indicated varbind
4052
     */
4053
0
    for ( i=2; i<=idx; i++) {
4054
0
        req = req->next;
4055
0
        if (!req)
4056
0
            return SNMPERR_NO_VARS;
4057
0
    }
4058
    
4059
0
    return _request_set_error(req, request->agent_req_info->mode,
4060
0
                              error_value);
4061
0
}
4062
#endif /* NETSNMP_FEATURE_REMOVE_REQUEST_SET_ERROR_IDX */
4063
4064
/** set error for all requests
4065
 * @param requests request list
4066
 * @param error error value for requests
4067
 * @return SNMPERR_SUCCESS, or an error code
4068
 */
4069
NETSNMP_INLINE int
4070
netsnmp_request_set_error_all( netsnmp_request_info *requests, int error)
4071
113
{
4072
113
    int mode, rc, result = SNMPERR_SUCCESS;
4073
4074
113
    if((NULL == requests) || (NULL == requests->agent_req_info))
4075
0
        return SNMPERR_NO_VARS;
4076
    
4077
113
    mode = requests->agent_req_info->mode; /* every req has same mode */
4078
    
4079
265
    for(; requests ; requests = requests->next) {
4080
4081
        /** paranoid sanity checks */
4082
152
        netsnmp_assert(NULL != requests->agent_req_info);
4083
152
        netsnmp_assert(mode == requests->agent_req_info->mode);
4084
4085
        /*
4086
         * set error for this request. Log any errors, save the last
4087
         * to return to the user.
4088
         */
4089
152
        if((rc = _request_set_error(requests, mode, error))) {
4090
0
            snmp_log(LOG_WARNING,"got %d while setting request error\n", rc);
4091
0
            result = rc;
4092
0
        }
4093
152
    }
4094
113
    return result;
4095
113
}
4096
4097
/**
4098
 * Return the difference between pm and the agent start time in hundredths of
4099
 * a second.
4100
 * \deprecated Don't use in new code.
4101
 *
4102
 * @param[in] pm An absolute time as e.g. reported by gettimeofday().
4103
 */
4104
u_long
4105
netsnmp_marker_uptime(marker_t pm)
4106
0
{
4107
0
    u_long          res;
4108
0
    const_marker_t  start = netsnmp_get_agent_starttime();
4109
4110
0
    res = uatime_hdiff(start, pm);
4111
0
    return res;
4112
0
}
4113
4114
/**
4115
 * Return the difference between tv and the agent start time in hundredths of
4116
 * a second.
4117
 *
4118
 * \deprecated Use netsnmp_get_agent_uptime() instead.
4119
 *
4120
 * @param[in] tv An absolute time as e.g. reported by gettimeofday().
4121
 */
4122
u_long
4123
netsnmp_timeval_uptime(struct timeval * tv)
4124
0
{
4125
0
    return netsnmp_marker_uptime((marker_t) tv);
4126
0
}
4127
4128
4129
struct timeval  starttime;
4130
static struct timeval starttimeM;
4131
4132
/**
4133
 * Return a pointer to the variable in which the Net-SNMP start time has
4134
 * been stored.
4135
 *
4136
 * @note Use netsnmp_get_agent_runtime() instead of this function if you need
4137
 *   to know how much time elapsed since netsnmp_set_agent_starttime() has been
4138
 *   called.
4139
 */
4140
const_marker_t        
4141
netsnmp_get_agent_starttime(void)
4142
0
{
4143
0
    return &starttime;
4144
0
}
4145
4146
/**
4147
 * Report the time that elapsed since the agent start time in hundredths of a
4148
 * second.
4149
 *
4150
 * @see See also netsnmp_set_agent_starttime().
4151
 */
4152
uint64_t
4153
netsnmp_get_agent_runtime(void)
4154
0
{
4155
0
    struct timeval now, delta;
4156
4157
0
    netsnmp_get_monotonic_clock(&now);
4158
0
    NETSNMP_TIMERSUB(&now, &starttimeM, &delta);
4159
0
    return (uint64_t)(delta.tv_sec * (uint64_t)100 + delta.tv_usec / 10000);
4160
0
}
4161
4162
/**
4163
 * Set the time at which Net-SNMP started either to the current time
4164
 * (if s == NULL) or to *s (if s is not NULL).
4165
 *
4166
 * @see See also netsnmp_set_agent_uptime().
4167
 */
4168
void            
4169
netsnmp_set_agent_starttime(marker_t s)
4170
2.62k
{
4171
2.62k
    if (s) {
4172
0
        struct timeval nowA, nowM;
4173
4174
0
        starttime = *(struct timeval*)s;
4175
0
        gettimeofday(&nowA, NULL);
4176
0
        netsnmp_get_monotonic_clock(&nowM);
4177
0
        NETSNMP_TIMERSUB(&starttime, &nowA, &starttimeM);
4178
0
        NETSNMP_TIMERADD(&starttimeM, &nowM, &starttimeM);
4179
2.62k
    } else {
4180
2.62k
        gettimeofday(&starttime, NULL);
4181
2.62k
        netsnmp_get_monotonic_clock(&starttimeM);
4182
2.62k
    }
4183
2.62k
}
4184
4185
4186
/**
4187
 * Return the current value of 'sysUpTime' 
4188
 */
4189
u_long
4190
netsnmp_get_agent_uptime(void)
4191
0
{
4192
0
    struct timeval now, delta;
4193
4194
0
    netsnmp_get_monotonic_clock(&now);
4195
0
    NETSNMP_TIMERSUB(&now, &starttimeM, &delta);
4196
0
    return (u_long)(delta.tv_sec * 100UL + delta.tv_usec / 10000);
4197
0
}
4198
4199
#ifndef NETSNMP_FEATURE_REMOVE_SET_AGENT_UPTIME
4200
/**
4201
 * Set the start time from which 'sysUpTime' is computed.
4202
 *
4203
 * @param[in] hsec New sysUpTime in hundredths of a second.
4204
 *
4205
 * @see See also netsnmp_set_agent_starttime().
4206
 */
4207
void
4208
netsnmp_set_agent_uptime(u_long hsec)
4209
0
{
4210
0
    struct timeval  nowA, nowM;
4211
0
    struct timeval  new_uptime;
4212
4213
0
    gettimeofday(&nowA, NULL);
4214
0
    netsnmp_get_monotonic_clock(&nowM);
4215
0
    new_uptime.tv_sec = hsec / 100;
4216
0
    new_uptime.tv_usec = (uint32_t)(hsec - new_uptime.tv_sec * 100) * 10000L;
4217
0
    NETSNMP_TIMERSUB(&nowA, &new_uptime, &starttime);
4218
0
    NETSNMP_TIMERSUB(&nowM, &new_uptime, &starttimeM);
4219
0
}
4220
#endif /* NETSNMP_FEATURE_REMOVE_SET_AGENT_UPTIME */
4221
4222
4223
/*************************************************************************
4224
 *
4225
 * deprecated functions
4226
 *
4227
 */
4228
4229
/** set error for a request
4230
 * \deprecated, use netsnmp_request_set_error instead
4231
 * @param reqinfo agent_request_info pointer for request
4232
 * @param request request_info pointer
4233
 * @param error_value error value for requests
4234
 * @return error_value
4235
 */
4236
int
4237
netsnmp_set_request_error(netsnmp_agent_request_info *reqinfo,
4238
                          netsnmp_request_info *request, int error_value)
4239
318
{
4240
318
    if (!request || !reqinfo)
4241
0
        return error_value;
4242
4243
318
    _request_set_error(request, reqinfo->mode, error_value);
4244
    
4245
318
    return error_value;
4246
318
}
4247
4248
/** set error for a request
4249
 * \deprecated, use netsnmp_request_set_error instead
4250
 * @param mode Net-SNMP agent processing mode
4251
 * @param request request_info pointer
4252
 * @param error_value error value for requests
4253
 * @return error_value
4254
 */
4255
int
4256
netsnmp_set_mode_request_error(int mode, netsnmp_request_info *request,
4257
                               int error_value)
4258
0
{
4259
0
    _request_set_error(request, mode, error_value);
4260
    
4261
0
    return error_value;
4262
0
}
4263
4264
/** set error for all request
4265
 * \deprecated use netsnmp_request_set_error_all
4266
 * @param reqinfo agent_request_info pointer for requests
4267
 * @param requests request list
4268
 * @param error_value error value for requests
4269
 * @return error_value
4270
 */
4271
#ifndef NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR
4272
int
4273
netsnmp_set_all_requests_error(netsnmp_agent_request_info *reqinfo,
4274
                               netsnmp_request_info *requests,
4275
                               int error_value)
4276
0
{
4277
0
    netsnmp_request_set_error_all(requests, error_value);
4278
0
    return error_value;
4279
0
}
4280
#endif /* NETSNMP_FEATURE_REMOVE_SET_ALL_REQUESTS_ERROR */
4281
/** @} */