~ubuntu-branches/ubuntu/wily/net-snmp/wily-proposed

« back to all changes in this revision

Viewing changes to .pc/CVE-2012-6151.patch/agent/snmp_agent.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2014-04-08 08:17:14 UTC
  • Revision ID: package-import@ubuntu.com-20140408081714-31du0g3p3ggkwe9o
Tags: 5.7.2~dfsg-8.1ubuntu3
* SECURITY UPDATE: denial of service via AgentX subagent timeout
  - debian/patches/CVE-2012-6151.patch: track cancelled sessions in
    agent/mibgroup/agentx/{master.c,master_admin.c}, agent/snmp_agent.c,
    include/net-snmp/agent/snmp_agent.h.
  - CVE-2012-6151
* SECURITY UPDATE: denial of service when ICMP-MIB is in use
  - debian/patches/CVE-2014-2284.patch: fix ICMP mib table handling in
    agent/mibgroup/mibII/icmp.c, agent/mibgroup/mibII/kernel_linux.*.
  - CVE-2014-2284
* SECURITY UPDATE: denial of service in perl trap handler
  - debian/patches/CVE-2014-2285.patch: handle empty community string in
    perl/TrapReceiver/TrapReceiver.xs.
  - CVE-2014-2285

Show diffs side-by-side

added added

removed removed

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