Coverage Report

Created: 2026-08-28 09:48

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