Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmp_api.c
Line
Count
Source
1
2
/* Portions of this file are subject to the following copyright(s).  See
3
 * the Net-SNMP's COPYING file for more details and other copyrights
4
 * that may apply:
5
 */
6
/******************************************************************
7
  Copyright 1989, 1991, 1992 by Carnegie Mellon University
8
9
                      All Rights Reserved
10
11
Permission to use, copy, modify, and distribute this software and its
12
documentation for any purpose and without fee is hereby granted,
13
provided that the above copyright notice appear in all copies and that
14
both that copyright notice and this permission notice appear in
15
supporting documentation, and that the name of CMU not be
16
used in advertising or publicity pertaining to distribution of the
17
software without specific, written prior permission.
18
19
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25
SOFTWARE.
26
******************************************************************/
27
/*
28
 * Portions of this file are copyrighted by:
29
 * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
30
 * Use is subject to license terms specified in the COPYING file
31
 * distributed with the Net-SNMP package.
32
 *
33
 * Portions of this file are copyrighted by:
34
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
35
 * Use is subject to license terms specified in the COPYING file
36
 * distributed with the Net-SNMP package.
37
 */
38
39
/** @defgroup library The Net-SNMP library
40
 *  @{
41
 */
42
/*
43
 * snmp_api.c - API for access to snmp.
44
 */
45
#include <net-snmp/net-snmp-config.h>
46
#include <net-snmp/net-snmp-features.h>
47
48
#include <stdio.h>
49
#include <ctype.h>
50
#ifdef HAVE_STDLIB_H
51
#include <stdlib.h>
52
#endif
53
#ifdef HAVE_STRING_H
54
#include <string.h>
55
#else
56
#include <strings.h>
57
#endif
58
#ifdef HAVE_UNISTD_H
59
#include <unistd.h>
60
#endif
61
#include <sys/types.h>
62
#ifdef HAVE_SYS_PARAM_H
63
#include <sys/param.h>
64
#endif
65
#ifdef TIME_WITH_SYS_TIME
66
# include <sys/time.h>
67
# include <time.h>
68
#else
69
# ifdef HAVE_SYS_TIME_H
70
#  include <sys/time.h>
71
# else
72
#  include <time.h>
73
# endif
74
#endif
75
#ifdef HAVE_NETINET_IN_H
76
#include <netinet/in.h>
77
#endif
78
#ifdef HAVE_ARPA_INET_H
79
#include <arpa/inet.h>
80
#endif
81
#ifdef HAVE_SYS_SELECT_H
82
#include <sys/select.h>
83
#endif
84
#ifdef HAVE_IO_H
85
#include <io.h>
86
#endif
87
#ifdef HAVE_SYS_SOCKET_H
88
#include <sys/socket.h>
89
#endif
90
#ifdef HAVE_SYS_UN_H
91
#include <sys/un.h>
92
#endif
93
#ifdef HAVE_NETDB_H
94
#include <netdb.h>
95
#endif
96
#ifdef HAVE_NET_IF_DL_H
97
#ifndef dynix
98
#include <net/if_dl.h>
99
#else
100
#include <sys/net/if_dl.h>
101
#endif
102
#endif
103
#include <errno.h>
104
105
#ifdef HAVE_LOCALE_H
106
#include <locale.h>
107
#endif
108
109
#include <net-snmp/types.h>
110
#include <net-snmp/output_api.h>
111
#include <net-snmp/config_api.h>
112
#include <net-snmp/utilities.h>
113
#include <net-snmp/agent/agent_callbacks.h>
114
115
#include <net-snmp/library/asn1.h>
116
#include <net-snmp/library/snmp.h>      /* for xdump & {build,parse}_var_op */
117
#include <net-snmp/library/snmp_api.h>
118
#include <net-snmp/library/snmp_client.h>
119
#include <net-snmp/library/parse.h>
120
#include <net-snmp/library/mib.h>
121
#include <net-snmp/library/int64.h>
122
#include <net-snmp/library/snmpv3.h>
123
#include <net-snmp/library/callback.h>
124
#include <net-snmp/library/container.h>
125
#include <net-snmp/library/snmp_secmod.h>
126
#include <net-snmp/library/large_fd_set.h>
127
#ifdef NETSNMP_SECMOD_USM
128
#include <net-snmp/library/snmpusm.h>
129
#endif
130
#ifdef NETSNMP_SECMOD_KSM
131
#include <net-snmp/library/snmpksm.h>
132
#endif
133
#include <net-snmp/library/keytools.h>
134
#include <net-snmp/library/lcd_time.h>
135
#include <net-snmp/library/snmp_alarm.h>
136
#include <net-snmp/library/snmp_transport.h>
137
#include <net-snmp/library/snmp_service.h>
138
#include <net-snmp/library/vacm.h>
139
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL)
140
#include <openssl/ssl.h>
141
#include <net-snmp/library/cert_util.h>
142
#endif
143
144
netsnmp_feature_child_of(statistics, libnetsnmp);
145
netsnmp_feature_child_of(snmp_api, libnetsnmp);
146
netsnmp_feature_child_of(oid_is_subtree, snmp_api);
147
netsnmp_feature_child_of(snmpv3_probe_contextEngineID_rfc5343, snmp_api);
148
149
static int      _snmp_store_needed = 0;
150
151
#include "../agent/mibgroup/agentx/protocol.h"
152
#include <net-snmp/library/transform_oids.h>
153
#ifndef timercmp
154
#define timercmp(tvp, uvp, cmp) \
155
  /* CSTYLED */ \
156
  ((tvp)->tv_sec cmp (uvp)->tv_sec || \
157
  ((tvp)->tv_sec == (uvp)->tv_sec && \
158
  /* CSTYLED */ \
159
  (tvp)->tv_usec cmp (uvp)->tv_usec))
160
#endif
161
#ifndef timerclear
162
#define timerclear(tvp)   (tvp)->tv_sec = (tvp)->tv_usec = 0
163
#endif
164
165
/*
166
 * Globals.
167
 */
168
#ifndef NETSNMP_STREAM_QUEUE_LEN
169
#define NETSNMP_STREAM_QUEUE_LEN  5
170
#endif
171
#ifndef NETSNMP_STREAM_FRAME_TIMEOUT
172
0
#define NETSNMP_STREAM_FRAME_TIMEOUT 30
173
#endif
174
#ifndef NETSNMP_STREAM_MAX_SESSIONS
175
0
#define NETSNMP_STREAM_MAX_SESSIONS 32
176
#endif
177
#ifndef NETSNMP_STREAM_MAX_SESSIONS_PER_PEER
178
0
#define NETSNMP_STREAM_MAX_SESSIONS_PER_PEER 8
179
#endif
180
181
#ifndef BSD4_3
182
#define BSD4_2
183
#endif
184
185
static const oid default_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
186
/*
187
 * enterprises.cmu.systems.cmuSNMP 
188
 */
189
190
#define DEFAULT_COMMUNITY   "public"
191
0
#define DEFAULT_RETRIES     5
192
0
#define DEFAULT_TIMEOUT     (1000L * 1000L)
193
#define DEFAULT_REMPORT     SNMP_PORT
194
0
#define DEFAULT_ENTERPRISE  default_enterprise
195
0
#define DEFAULT_TIME      0
196
197
/*
198
 * A list of all the outstanding requests for a particular session.
199
 */
200
typedef struct request_list {
201
    struct request_list *next_request;
202
    long            request_id;     /* request id */
203
    long            message_id;     /* message id */
204
    netsnmp_callback callback;      /* user callback per request (NULL if unused) */
205
    void           *cb_data;        /* user callback data per request (NULL if unused) */
206
    char            cb_data_refcounted;
207
    int             retries;        /* Number of retries */
208
    u_long          timeout;        /* length to wait for timeout */
209
    struct timeval  timeM;   /* Time this request was made [monotonic clock] */
210
    struct timeval  expireM; /* Time this request is due to expire [monotonic clock]. */
211
    struct snmp_session *session;
212
    netsnmp_pdu    *pdu;    /* The pdu for this request
213
           * (saved so it can be retransmitted */
214
} netsnmp_request_list;
215
216
/*
217
 * Internal information about the state of the snmp session.
218
 */
219
struct snmp_internal_session {
220
    netsnmp_request_list *requests;     /* Info about outstanding requests */
221
    netsnmp_request_list *requestsEnd;  /* ptr to end of list */
222
    int             (*hook_pre) (netsnmp_session *, netsnmp_transport *,
223
                                 void *, int);
224
    int             (*hook_parse) (netsnmp_session *, netsnmp_pdu *,
225
                                   u_char *, size_t);
226
    int             (*hook_post) (netsnmp_session *, netsnmp_pdu *, int);
227
    int             (*hook_build) (netsnmp_session *, netsnmp_pdu *,
228
                                   u_char *, size_t *);
229
    int             (*hook_realloc_build) (netsnmp_session *,
230
                                           netsnmp_pdu *, u_char **,
231
                                           size_t *, size_t *);
232
    int             (*check_packet) (u_char *, size_t);
233
    netsnmp_pdu    *(*hook_create_pdu) (netsnmp_transport *,
234
                                        void *, size_t);
235
236
    u_char       *packet;      /* curr rcv packet data (may be incomplete) */
237
    size_t        packet_len;  /* length of data received so far */
238
    size_t        packet_size; /* size of buffer for packet data */
239
    struct timeval packet_deadline; /* incomplete stream frame deadline */
240
    int            accepted_stream;
241
    int            stream_peer_valid;
242
    netsnmp_sockaddr_storage stream_peer;
243
244
    u_char       *obuf;         /* send packet buffer */
245
    size_t        obuf_size;    /* size of buffer for packet data */
246
    u_char       *opacket;      /* send packet data (within obuf) */
247
    size_t        opacket_len;  /* length of data */
248
};
249
250
/*
251
 * information about received packet
252
 */
253
typedef struct snmp_rcv_packet_s {
254
    u_char   *packet;
255
    size_t    packet_len;
256
    void     *opaque;
257
    int       olength;
258
} snmp_rcv_packet;
259
260
static const char *api_errors[-SNMPERR_MAX + 1] = {
261
    "No error",                 /* SNMPERR_SUCCESS */
262
    "Generic error",            /* SNMPERR_GENERR */
263
    "Invalid local port",       /* SNMPERR_BAD_LOCPORT */
264
    "Unknown host",             /* SNMPERR_BAD_ADDRESS */
265
    "Unknown session",          /* SNMPERR_BAD_SESSION */
266
    "Too long",                 /* SNMPERR_TOO_LONG */
267
    "No socket",                /* SNMPERR_NO_SOCKET */
268
    "Cannot send V2 PDU on V1 session", /* SNMPERR_V2_IN_V1 */
269
    "Cannot send V1 PDU on V2 session", /* SNMPERR_V1_IN_V2 */
270
    "Bad value for non-repeaters",      /* SNMPERR_BAD_REPEATERS */
271
    "Bad value for max-repetitions",    /* SNMPERR_BAD_REPETITIONS */
272
    "Error building ASN.1 representation",      /* SNMPERR_BAD_ASN1_BUILD */
273
    "Failure in sendto",        /* SNMPERR_BAD_SENDTO */
274
    "Bad parse of ASN.1 type",  /* SNMPERR_BAD_PARSE */
275
    "Bad version specified",    /* SNMPERR_BAD_VERSION */
276
    "Bad source party specified",       /* SNMPERR_BAD_SRC_PARTY */
277
    "Bad destination party specified",  /* SNMPERR_BAD_DST_PARTY */
278
    "Bad context specified",    /* SNMPERR_BAD_CONTEXT */
279
    "Bad community specified",  /* SNMPERR_BAD_COMMUNITY */
280
    "Cannot send noAuth/Priv",       /* SNMPERR_NOAUTH_DESPRIV */
281
    "Bad ACL definition",       /* SNMPERR_BAD_ACL */
282
    "Bad Party definition",     /* SNMPERR_BAD_PARTY */
283
    "Session abort failure",    /* SNMPERR_ABORT */
284
    "Unknown PDU type",         /* SNMPERR_UNKNOWN_PDU */
285
    "Timeout",                  /* SNMPERR_TIMEOUT */
286
    "Failure in recvfrom",      /* SNMPERR_BAD_RECVFROM */
287
    "Unable to determine contextEngineID",      /* SNMPERR_BAD_ENG_ID */
288
    "No securityName specified",        /* SNMPERR_BAD_SEC_NAME */
289
    "Unable to determine securityLevel",        /* SNMPERR_BAD_SEC_LEVEL  */
290
    "ASN.1 parse error in message",     /* SNMPERR_ASN_PARSE_ERR */
291
    "Unknown security model in message",        /* SNMPERR_UNKNOWN_SEC_MODEL */
292
    "Invalid message (e.g. msgFlags)",  /* SNMPERR_INVALID_MSG */
293
    "Unknown engine ID",        /* SNMPERR_UNKNOWN_ENG_ID */
294
    "Unknown user name",        /* SNMPERR_UNKNOWN_USER_NAME */
295
    "Unsupported security level",       /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
296
    "Authentication failure (incorrect password, community or key)",    /* SNMPERR_AUTHENTICATION_FAILURE */
297
    "Not in time window",       /* SNMPERR_NOT_IN_TIME_WINDOW */
298
    "Decryption error",         /* SNMPERR_DECRYPTION_ERR */
299
    "SCAPI general failure",    /* SNMPERR_SC_GENERAL_FAILURE */
300
    "SCAPI sub-system not configured",  /* SNMPERR_SC_NOT_CONFIGURED */
301
    "Key tools not available",  /* SNMPERR_KT_NOT_AVAILABLE */
302
    "Unknown Report message",   /* SNMPERR_UNKNOWN_REPORT */
303
    "USM generic error",        /* SNMPERR_USM_GENERICERROR */
304
    "USM unknown security name (no such user exists)",  /* SNMPERR_USM_UNKNOWNSECURITYNAME */
305
    "USM unsupported security level (this user has not been configured for that level of security)",    /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
306
    "USM encryption error",     /* SNMPERR_USM_ENCRYPTIONERROR */
307
    "USM authentication failure (incorrect password or key)",   /* SNMPERR_USM_AUTHENTICATIONFAILURE */
308
    "USM parse error",          /* SNMPERR_USM_PARSEERROR */
309
    "USM unknown engineID",     /* SNMPERR_USM_UNKNOWNENGINEID */
310
    "USM not in time window",   /* SNMPERR_USM_NOTINTIMEWINDOW */
311
    "USM decryption error",     /* SNMPERR_USM_DECRYPTIONERROR */
312
    "MIB not initialized",      /* SNMPERR_NOMIB */
313
    "Value out of range",       /* SNMPERR_RANGE */
314
    "Sub-id out of range",      /* SNMPERR_MAX_SUBID */
315
    "Bad sub-id in object identifier",  /* SNMPERR_BAD_SUBID */
316
    "Object identifier too long",       /* SNMPERR_LONG_OID */
317
    "Bad value name",           /* SNMPERR_BAD_NAME */
318
    "Bad value notation",       /* SNMPERR_VALUE */
319
    "Unknown Object Identifier",        /* SNMPERR_UNKNOWN_OBJID */
320
    "No PDU in snmp_send",      /* SNMPERR_NULL_PDU */
321
    "Missing variables in PDU", /* SNMPERR_NO_VARS */
322
    "Bad variable type",        /* SNMPERR_VAR_TYPE */
323
    "Out of memory (malloc failure)",   /* SNMPERR_MALLOC */
324
    "Kerberos related error",   /* SNMPERR_KRB5 */
325
    "Protocol error",   /* SNMPERR_PROTOCOL */
326
    "OID not increasing",       /* SNMPERR_OID_NONINCREASING */
327
    "Context probe",            /* SNMPERR_JUST_A_CONTEXT_PROBE */
328
    "Configuration data found but the transport can't be configured", /* SNMPERR_TRANSPORT_NO_CONFIG */
329
    "Transport configuration failed", /* SNMPERR_TRANSPORT_CONFIG_ERROR */
330
};
331
332
static const char *secLevelName[] = {
333
    "BAD_SEC_LEVEL",
334
    "noAuthNoPriv",
335
    "authNoPriv",
336
    "authPriv"
337
};
338
339
/*
340
 * Multiple threads may changes these variables.
341
 * Suggest using the Single API, which does not use Sessions.
342
 *
343
 * Reqid may need to be protected. Time will tell...
344
 *
345
 */
346
/*
347
 * MTCRITICAL_RESOURCE
348
 */
349
/*
350
 * use token in comments to individually protect these resources 
351
 */
352
struct session_list *Sessions = NULL;   /* MT_LIB_SESSION */
353
static long     Reqid = 0;      /* MT_LIB_REQUESTID */
354
static long     Msgid = 0;      /* MT_LIB_MESSAGEID */
355
static long     Sessid = 0;     /* MT_LIB_SESSIONID */
356
static long     Transid = 0;    /* MT_LIB_TRANSID */
357
int             snmp_errno = 0;
358
/*
359
 * END MTCRITICAL_RESOURCE
360
 */
361
362
/*
363
 * global error detail storage
364
 */
365
static char     snmp_detail[192];
366
static int      snmp_detail_f = 0;
367
368
/*
369
 * return configured max message size for outgoing packets
370
 */
371
int
372
netsnmp_max_send_msg_size(void)
373
0
{
374
0
    u_int max = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
375
0
                                   NETSNMP_DS_LIB_MSG_SEND_MAX);
376
0
    if (0 == max)
377
0
        max = SNMP_MAX_PACKET_LEN;
378
0
    else if (max < SNMP_MIN_MAX_LEN)
379
0
        max = SNMP_MIN_MAX_LEN; /* minimum max size per SNMP specs */
380
0
    else if (max > SNMP_MAX_PACKET_LEN)
381
0
        max = SNMP_MAX_PACKET_LEN;
382
383
0
    return max;
384
0
}
385
386
#ifndef HAVE_STRERROR
387
const char     *
388
strerror(int err)
389
{
390
    extern const char *sys_errlist[];
391
    extern int      sys_nerr;
392
393
    if (err < 0 || err >= sys_nerr)
394
        return "Unknown error";
395
    return sys_errlist[err];
396
}
397
#endif
398
399
const char *
400
snmp_pdu_type(int type)
401
0
{
402
0
    static char unknown[20];
403
0
    switch(type) {
404
0
    case SNMP_MSG_GET:
405
0
        return "GET";
406
0
    case SNMP_MSG_GETNEXT:
407
0
        return "GETNEXT";
408
0
    case SNMP_MSG_GETBULK:
409
0
        return "GETBULK";
410
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
411
0
    case SNMP_MSG_SET:
412
0
        return "SET";
413
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
414
0
    case SNMP_MSG_RESPONSE:
415
0
        return "RESPONSE";
416
0
    case SNMP_MSG_TRAP:
417
0
        return "TRAP";
418
0
    case SNMP_MSG_INFORM:
419
0
        return "INFORM";
420
0
    case SNMP_MSG_TRAP2:
421
0
        return "TRAP2";
422
0
    case SNMP_MSG_REPORT:
423
0
        return "REPORT";
424
0
    default:
425
0
        snprintf(unknown, sizeof(unknown), "?0x%2X?", type);
426
0
  return unknown;
427
0
    }
428
0
}
429
430
#define DEBUGPRINTPDUTYPE(token, type) \
431
0
    DEBUGDUMPSECTION(token, snmp_pdu_type(type))
432
433
long
434
snmp_get_next_reqid(void)
435
0
{
436
0
    long            retVal;
437
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
438
0
    retVal = 1 + Reqid;         /*MTCRITICAL_RESOURCE */
439
0
    if (!retVal)
440
0
        retVal = 2;
441
0
    Reqid = retVal;
442
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
443
0
        retVal &= 0x7fff; /* mask to 15 bits */
444
0
    else
445
0
        retVal &= 0x7fffffff; /* mask to 31 bits */
446
447
0
    if (!retVal) {
448
0
        Reqid = retVal = 2;
449
0
    }
450
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
451
0
    return retVal;
452
0
}
453
454
long
455
snmp_get_next_msgid(void)
456
0
{
457
0
    long            retVal;
458
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
459
0
    retVal = 1 + Msgid;         /*MTCRITICAL_RESOURCE */
460
0
    if (!retVal)
461
0
        retVal = 2;
462
0
    Msgid = retVal;
463
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
464
0
        retVal &= 0x7fff; /* mask to 15 bits */
465
0
    else
466
0
        retVal &= 0x7fffffff; /* mask to 31 bits */
467
468
0
    if (!retVal) {
469
0
        Msgid = retVal = 2;
470
0
    }
471
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
472
0
    return retVal;
473
0
}
474
475
long
476
snmp_get_next_sessid(void)
477
0
{
478
0
    long            retVal;
479
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
480
0
    retVal = 1 + Sessid;        /*MTCRITICAL_RESOURCE */
481
0
    if (!retVal)
482
0
        retVal = 2;
483
0
    Sessid = retVal;
484
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
485
0
        retVal &= 0x7fff; /* mask to 15 bits */
486
0
    else
487
0
        retVal &= 0x7fffffff; /* mask to 31 bits */
488
489
0
    if (!retVal) {
490
0
        Sessid = retVal = 2;
491
0
    }
492
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
493
0
    return retVal;
494
0
}
495
496
long
497
snmp_get_next_transid(void)
498
0
{
499
0
    long            retVal;
500
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
501
0
    retVal = 1 + Transid;       /*MTCRITICAL_RESOURCE */
502
0
    if (!retVal)
503
0
        retVal = 2;
504
0
    Transid = retVal;
505
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
506
0
        retVal &= 0x7fff; /* mask to 15 bits */
507
0
    else
508
0
        retVal &= 0x7fffffff; /* mask to 31 bits */
509
510
0
    if (!retVal) {
511
0
        Transid = retVal = 2;
512
0
    }
513
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
514
0
    return retVal;
515
0
}
516
517
void
518
snmp_perror(const char *prog_string)
519
0
{
520
0
    const char     *str;
521
0
    int             xerr;
522
0
    xerr = snmp_errno;          /*MTCRITICAL_RESOURCE */
523
0
    str = snmp_api_errstring(xerr);
524
0
    snmp_log(LOG_ERR, "%s: %s\n", prog_string, str);
525
0
}
526
527
void
528
snmp_set_detail(const char *detail_string)
529
0
{
530
0
    if (detail_string != NULL) {
531
0
        strlcpy(snmp_detail, detail_string, sizeof(snmp_detail));
532
0
        snmp_detail_f = 1;
533
0
    }
534
0
}
535
536
/*
537
 * returns pointer to static data 
538
 */
539
/*
540
 * results not guaranteed in multi-threaded use 
541
 */
542
const char     *
543
snmp_api_errstring(int snmp_errnumber)
544
0
{
545
0
    const char     *msg = "";
546
0
    static char     msg_buf[SPRINT_MAX_LEN];
547
548
0
    if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
549
0
        msg = api_errors[-snmp_errnumber];
550
0
    } else if (snmp_errnumber != SNMPERR_SUCCESS) {
551
0
        msg = NULL;
552
0
    }
553
0
    if (!msg) {
554
0
  snprintf(msg_buf, sizeof(msg_buf), "Unknown error: %d", snmp_errnumber);
555
0
        msg_buf[sizeof(msg_buf)-1] = '\0';
556
0
    } else if (snmp_detail_f) {
557
0
        snprintf(msg_buf, sizeof(msg_buf), "%s (%s)", msg, snmp_detail);
558
0
        msg_buf[sizeof(msg_buf)-1] = '\0';
559
0
        snmp_detail_f = 0;
560
0
    } else {
561
0
        strlcpy(msg_buf, msg, sizeof(msg_buf));
562
0
    }
563
564
0
    return (msg_buf);
565
0
}
566
567
/*
568
 * snmp_error - return error data
569
 * Inputs :  address of errno, address of snmp_errno, address of string
570
 * Caller must free the string returned after use.
571
 */
572
void
573
snmp_error(netsnmp_session * psess,
574
           int *p_errno, int *p_snmp_errno, char **p_str)
575
0
{
576
0
    char            buf[SPRINT_MAX_LEN];
577
0
    int             snmp_errnumber;
578
579
0
    if (p_errno)
580
0
        *p_errno = psess->s_errno;
581
0
    if (p_snmp_errno)
582
0
        *p_snmp_errno = psess->s_snmp_errno;
583
0
    if (p_str == NULL)
584
0
        return;
585
586
0
    strcpy(buf, "");
587
0
    snmp_errnumber = psess->s_snmp_errno;
588
0
    if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
589
0
  if (snmp_detail_f) {
590
0
            snprintf(buf, sizeof(buf), "%s (%s)", api_errors[-snmp_errnumber],
591
0
        snmp_detail);
592
0
            buf[sizeof(buf)-1] = '\0';
593
0
      snmp_detail_f = 0;
594
0
  }
595
0
  else
596
0
      strlcpy(buf, api_errors[-snmp_errnumber], sizeof(buf));
597
0
    } else {
598
0
        if (snmp_errnumber) {
599
0
            snprintf(buf, sizeof(buf), "Unknown Error %d", snmp_errnumber);
600
0
            buf[sizeof(buf)-1] = '\0';
601
0
        }
602
0
    }
603
604
    /*
605
     * append a useful system errno interpretation. 
606
     */
607
0
    if (psess->s_errno) {
608
0
        const char* error = strerror(psess->s_errno);
609
0
        if(error == NULL)
610
0
            error = "Unknown Error";
611
0
        snprintf (&buf[strlen(buf)], sizeof(buf)-strlen(buf),
612
0
                 " (%s)", error);
613
0
    }
614
0
    buf[sizeof(buf)-1] = '\0';
615
0
    *p_str = strdup(buf);
616
0
}
617
618
/*
619
 * snmp_sess_error - same as snmp_error for single session API use.
620
 */
621
void
622
snmp_sess_error(struct session_list *slp, int *p_errno, int *p_snmp_errno,
623
                char **p_str)
624
0
{
625
0
    if ((slp) && (slp->session))
626
0
        snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
627
0
}
628
629
/*
630
 * netsnmp_sess_log_error(): print a error stored in a session pointer 
631
 */
632
void
633
netsnmp_sess_log_error(int priority,
634
                       const char *prog_string, netsnmp_session * ss)
635
0
{
636
0
    char           *err;
637
0
    snmp_error(ss, NULL, NULL, &err);
638
0
    snmp_log(priority, "%s: %s\n", prog_string, err);
639
0
    SNMP_FREE(err);
640
0
}
641
642
/*
643
 * snmp_sess_perror(): print a error stored in a session pointer 
644
 */
645
void
646
snmp_sess_perror(const char *prog_string, netsnmp_session * ss)
647
0
{
648
0
    netsnmp_sess_log_error(LOG_ERR, prog_string, ss);
649
0
}
650
651
long int netsnmp_random(void)
652
0
{
653
0
#if defined(HAVE_RANDOM)
654
    /*
655
     * The function random() is a more sophisticated random number generator
656
     * which uses nonlinear feedback and an internal table that is 124 bytes
657
     * (992 bits) long. The function returns random values that are 32 bits in
658
     * length. All of the bits generated by random() are usable. The random()
659
     * function is adequate for simulations and games, but should not be used
660
     * for security related applications such as picking cryptographic keys or
661
     * simulating one-time pads.
662
     */
663
0
    return random();
664
#elif defined(HAVE_LRAND48)
665
    /*
666
     * As with random(), lrand48() provides excellent random numbers for
667
     * simulations and games, but should not be used for security-related
668
     * applications such as picking cryptographic keys or simulating one-time
669
     * pads; linear congruential algorithms are too easy to break.
670
     */
671
    return lrand48();
672
#elif defined(HAVE_RAND)
673
    /*
674
     * The original UNIX random number generator, rand(), is not a very good
675
     * random number generator. It uses a 32-bit seed and maintains a 32-bit
676
     * internal state.
677
     */
678
    return rand();
679
#else
680
#error "Neither random(), nor lrand48() nor rand() are available"
681
#endif
682
0
}
683
684
void netsnmp_srandom(unsigned int seed)
685
0
{
686
0
#if defined(HAVE_SRANDOM)
687
0
    srandom(seed);
688
#elif defined(HAVE_SRAND48)
689
    srand48(seed);
690
#elif defined(HAVE_SRAND)
691
    srand(seed);
692
#else
693
#error "Neither srandom(), nor srand48() nor srand() are available"
694
#endif
695
0
}
696
697
/*
698
 * Primordial SNMP library initialization.
699
 * Initializes mutex locks.
700
 * Invokes minimum required initialization for displaying MIB objects.
701
 * Gets initial request ID for all transactions,
702
 * and finds which port SNMP over UDP uses.
703
 * SNMP over AppleTalk is not currently supported.
704
 *
705
 * Warning: no debug messages here.
706
 */
707
static char _init_snmp_init_done = 0;
708
static void
709
_init_snmp(void)
710
0
{
711
712
0
    struct timeval  tv;
713
0
    long            tmpReqid, tmpMsgid;
714
715
0
    if (_init_snmp_init_done)
716
0
        return;
717
0
    _init_snmp_init_done = 1;
718
0
    Reqid = 1;
719
720
0
    snmp_res_init();            /* initialize the mt locking structures */
721
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
722
0
    netsnmp_init_mib_internals();
723
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
724
0
    netsnmp_tdomain_init();
725
726
0
    gettimeofday(&tv, (struct timezone *) 0);
727
    /*
728
     * Now = tv;
729
     */
730
731
    /*
732
     * get pseudo-random values for request ID and message ID 
733
     */
734
0
    netsnmp_srandom((unsigned)(tv.tv_sec ^ tv.tv_usec));
735
0
    tmpReqid = netsnmp_random();
736
0
    tmpMsgid = netsnmp_random();
737
738
    /*
739
     * don't allow zero value to repeat init 
740
     */
741
0
    if (tmpReqid == 0)
742
0
        tmpReqid = 1;
743
0
    if (tmpMsgid == 0)
744
0
        tmpMsgid = 1;
745
0
    Reqid = tmpReqid;
746
0
    Msgid = tmpMsgid;
747
748
0
    netsnmp_register_default_domain("snmp", "udp udp6");
749
0
    netsnmp_register_default_domain("snmptrap", "udp udp6");
750
751
0
    netsnmp_register_default_target("snmp", "udp", ":161");
752
0
    netsnmp_register_default_target("snmp", "tcp", ":161");
753
0
    netsnmp_register_default_target("snmp", "udp6", ":161");
754
0
    netsnmp_register_default_target("snmp", "tcp6", ":161");
755
0
    netsnmp_register_default_target("snmp", "dtlsudp", ":10161");
756
0
    netsnmp_register_default_target("snmp", "tlstcp", ":10161");
757
0
    netsnmp_register_default_target("snmp", "ipx", "/36879");
758
759
0
    netsnmp_register_default_target("snmptrap", "udp", ":162");
760
0
    netsnmp_register_default_target("snmptrap", "tcp", ":162");
761
0
    netsnmp_register_default_target("snmptrap", "udp6", ":162");
762
0
    netsnmp_register_default_target("snmptrap", "tcp6", ":162");
763
0
    netsnmp_register_default_target("snmptrap", "dtlsudp", ":10162");
764
0
    netsnmp_register_default_target("snmptrap", "tlstcp", ":10162");
765
0
    netsnmp_register_default_target("snmptrap", "ipx", "/36880");
766
767
0
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
768
0
                       NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH, 16);
769
0
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RETRIES,
770
0
                       DEFAULT_RETRIES);
771
0
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
772
0
         NETSNMP_DS_LIB_MIB_ERRORS, 1);
773
774
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
775
0
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
776
0
         NETSNMP_DS_LIB_REVERSE_ENCODE,
777
0
         NETSNMP_DEFAULT_ASNENCODING_DIRECTION);
778
0
#endif
779
0
}
780
781
/*
782
 * Initializes the session structure.
783
 * May perform one time minimal library initialization.
784
 * No MIB file processing is done via this call.
785
 */
786
void
787
snmp_sess_init(netsnmp_session * session)
788
0
{
789
0
    _init_snmp();
790
791
    /*
792
     * initialize session to default values 
793
     */
794
795
0
    memset(session, 0, sizeof(netsnmp_session));
796
0
    session->timeout = SNMP_DEFAULT_TIMEOUT;
797
0
    session->retries = SNMP_DEFAULT_RETRIES;
798
0
    session->version = SNMP_DEFAULT_VERSION;
799
0
    session->securityModel = SNMP_DEFAULT_SECMODEL;
800
0
    session->rcvMsgMaxSize = netsnmp_max_send_msg_size();
801
0
    session->sndMsgMaxSize = netsnmp_max_send_msg_size();
802
0
    session->flags |= SNMP_FLAGS_DONT_PROBE;
803
0
}
804
805
806
static void
807
register_default_handlers(void)
808
0
{
809
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dumpPacket",
810
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET);
811
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "reverseEncodeBER",
812
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE);
813
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "defaultPort",
814
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT);
815
0
#ifndef NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION
816
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv3",
817
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V3);
818
0
#endif /* NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION */
819
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
820
0
#ifndef NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION
821
0
#if !defined(NETSNMP_DISABLE_SNMPV1)
822
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv1",
823
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V1);
824
0
#endif
825
0
#if !defined(NETSNMP_DISABLE_SNMPV2C)
826
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv2c",
827
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V2c);
828
0
#endif
829
0
#endif /* NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION */
830
0
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defCommunity",
831
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_COMMUNITY);
832
0
#endif /* !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) */
833
0
    netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
834
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_TOKEN_WARNINGS);
835
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noRangeCheck",
836
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
837
0
    netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "persistentDir",
838
0
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PERSISTENT_DIR);
839
0
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tempFilePattern",
840
0
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TEMP_FILE_PATTERN);
841
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noDisplayHint",
842
0
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
843
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "16bitIDs",
844
0
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
845
0
    netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "clientaddr",
846
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
847
0
    netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "clientaddrUsesPort",
848
0
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR_USES_PORT);
849
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverSendBuf",
850
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERSENDBUF);
851
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverRecvBuf",
852
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERRECVBUF);
853
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientSendBuf",
854
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTSENDBUF);
855
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientRecvBuf",
856
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTRECVBUF);
857
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "sendMessageMaxSize",
858
0
                               NETSNMP_DS_LIBRARY_ID,
859
0
                               NETSNMP_DS_LIB_MSG_SEND_MAX);
860
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentLoad",
861
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD);
862
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentSave",
863
0
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE);
864
0
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp",
865
0
                               "noContextEngineIDDiscovery",
866
0
                               NETSNMP_DS_LIBRARY_ID,
867
0
                               NETSNMP_DS_LIB_NO_DISCOVERY);
868
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "timeout",
869
0
                   NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TIMEOUT);
870
0
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "retries",
871
0
                   NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RETRIES);
872
0
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "outputPrecision",
873
0
                               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION);
874
875
876
0
    netsnmp_register_service_handlers();
877
0
}
878
879
static int init_snmp_init_done = 0; /* To prevent double init's. */
880
/**
881
 * Calls the functions to do config file loading and  mib module parsing
882
 * in the correct order.
883
 *
884
 * @param type label for the config file "type"
885
 *
886
 * @return void
887
 *
888
 * @see init_agent
889
 */
890
void
891
init_snmp(const char *type)
892
0
{
893
0
    if (init_snmp_init_done) {
894
0
        return;
895
0
    }
896
897
0
    init_snmp_init_done = 1;
898
899
    /*
900
     * make the type available everywhere else 
901
     */
902
0
    if (type && !netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
903
0
               NETSNMP_DS_LIB_APPTYPE)) {
904
0
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
905
0
            NETSNMP_DS_LIB_APPTYPE, type);
906
0
    }
907
908
0
    _init_snmp();
909
910
    /*
911
     * set our current locale properly to initialize isprint() type functions 
912
     *
913
     * Do not use setlocale on qnx, it is buggy 
914
     * https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setlocale.html
915
     */
916
0
#if defined(HAVE_SETLOCALE) && !defined(__QNX__)
917
0
    setlocale(LC_CTYPE, "");
918
0
#endif
919
920
0
    snmp_debug_init();    /* should be done first, to turn on debugging ASAP */
921
0
    netsnmp_container_init_list();
922
0
    init_callbacks();
923
0
    init_snmp_logging();
924
0
    snmp_init_statistics();
925
0
    register_mib_handlers();
926
0
    register_default_handlers();
927
0
    init_snmp_transport();
928
0
    init_snmpv3(type);
929
0
    init_snmp_alarm();
930
0
    init_snmp_enum(type);
931
0
    init_vacm();
932
0
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
933
0
    netsnmp_certs_init();
934
0
#endif
935
#ifdef DNSSEC_LOCAL_VALIDATION
936
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dnssecWarnOnly",
937
                               NETSNMP_DS_LIBRARY_ID,
938
                               NETSNMP_DS_LIB_DNSSEC_WARN_ONLY);
939
#endif
940
941
0
    read_premib_configs();
942
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
943
0
    netsnmp_init_mib();
944
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
945
946
0
    read_configs();
947
948
0
}                               /* end init_snmp() */
949
950
/**
951
 * set a flag indicating that the persistent store needs to be saved.
952
 */
953
void
954
snmp_store_needed(const char *type)
955
0
{
956
0
    DEBUGMSGTL(("snmp_store", "setting needed flag...\n"));
957
0
    _snmp_store_needed = 1;
958
0
}
959
960
void
961
snmp_store_if_needed(void)
962
0
{
963
0
    if (0 == _snmp_store_needed)
964
0
        return;
965
    
966
0
    DEBUGMSGTL(("snmp_store", "store needed...\n"));
967
0
    snmp_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
968
0
                                     NETSNMP_DS_LIB_APPTYPE));
969
0
    _snmp_store_needed = 0;
970
0
}
971
972
void
973
snmp_store(const char *type)
974
0
{
975
0
    DEBUGMSGTL(("snmp_store", "storing stuff...\n"));
976
0
    snmp_save_persistent(type);
977
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
978
0
    snmp_clean_persistent(type);
979
0
}
980
981
982
/**
983
 * Shuts down the application, saving any needed persistent storage,
984
 * and appropriate clean up.
985
 * 
986
 * @param type Label for the config file "type" used
987
 *
988
 * @return void
989
 */
990
void
991
snmp_shutdown(const char *type)
992
0
{
993
0
    snmp_store(type);
994
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
995
0
    shutdown_snmp_logging();
996
0
    snmp_alarm_unregister_all();
997
0
    netsnmp_query_shutdown();
998
0
    snmp_close_sessions();
999
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
1000
0
    shutdown_mib();
1001
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
1002
0
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
1003
0
    netsnmp_certs_shutdown();
1004
0
#endif
1005
0
#if !defined(NETSNMP_FEATURE_REMOVE_FILTER_SOURCE)
1006
0
    netsnmp_transport_filter_cleanup();
1007
0
#endif
1008
0
    unregister_all_config_handlers();
1009
0
    netsnmp_container_free_list();
1010
0
    clear_sec_mod();
1011
0
    clear_snmp_enum();
1012
0
    netsnmp_clear_tdomain_list();
1013
0
    clear_callback();
1014
0
    netsnmp_ds_shutdown();
1015
0
    netsnmp_clear_default_target();
1016
0
    netsnmp_clear_default_domain();
1017
0
    shutdown_secmod();
1018
0
    shutdown_snmp_transport();
1019
0
    shutdown_data_list();
1020
0
    snmp_debug_shutdown();    /* should be done last */
1021
1022
0
    init_snmp_init_done  = 0;
1023
0
    _init_snmp_init_done = 0;
1024
0
}
1025
1026
/*
1027
 * inserts session into session list
1028
 */
1029
void  snmp_session_insert(struct session_list *slp)
1030
0
{
1031
0
    if (NULL == slp)
1032
0
        return;
1033
1034
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
1035
0
    slp->next = Sessions;
1036
0
    Sessions = slp;
1037
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
1038
0
}
1039
1040
/*
1041
 * Sets up the session with the snmp_session information provided by the user.
1042
 * Then opens and binds the necessary low-level transport.  A handle to the
1043
 * created session is returned (this is NOT the same as the pointer passed to
1044
 * snmp_open()).  On any error, NULL is returned and snmp_errno is set to the
1045
 * appropriate error code.
1046
 */
1047
netsnmp_session *
1048
snmp_open(netsnmp_session *session)
1049
0
{
1050
0
    struct session_list *slp;
1051
1052
0
    slp = snmp_sess_open(session);
1053
0
    if (!slp) {
1054
0
        return NULL;
1055
0
    }
1056
1057
0
    slp->session->flags &= ~SNMP_FLAGS_SESSION_USER;
1058
1059
0
    snmp_session_insert(slp);
1060
1061
0
    return (slp->session);
1062
0
}
1063
1064
/*
1065
 * extended open 
1066
 */
1067
netsnmp_feature_child_of(snmp_open_ex, netsnmp_unused);
1068
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_OPEN_EX
1069
netsnmp_session *
1070
snmp_open_ex(netsnmp_session *session,
1071
             int (*fpre_parse)  (netsnmp_session *, netsnmp_transport *,
1072
                                void *, int),
1073
             int (*fparse)  (netsnmp_session *, netsnmp_pdu *, u_char *,
1074
         size_t),
1075
       int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
1076
1077
             int (*fbuild)  (netsnmp_session *, netsnmp_pdu *, u_char *,
1078
         size_t *),
1079
       int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
1080
         u_char **, size_t *, size_t *),
1081
             int (*fcheck)  (u_char *, size_t)
1082
       )
1083
0
{
1084
0
    struct session_list *slp;
1085
1086
0
    slp = snmp_sess_open(session);
1087
0
    if (!slp) {
1088
0
        return NULL;
1089
0
    }
1090
0
    slp->internal->hook_pre = fpre_parse;
1091
0
    slp->internal->hook_parse = fparse;
1092
0
    slp->internal->hook_post = fpost_parse;
1093
0
    slp->internal->hook_build = fbuild;
1094
0
    slp->internal->hook_realloc_build = frbuild;
1095
0
    slp->internal->check_packet = fcheck;
1096
1097
0
    slp->session->flags &= ~SNMP_FLAGS_SESSION_USER;
1098
1099
0
    snmp_session_insert(slp);
1100
1101
0
    return (slp->session);
1102
0
}
1103
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_OPEN_EX */
1104
1105
static struct session_list *
1106
_sess_copy(netsnmp_session * in_session)
1107
0
{
1108
0
    struct session_list *slp;
1109
0
    struct snmp_internal_session *isp;
1110
0
    netsnmp_session *session;
1111
0
    struct snmp_secmod_def *sptr;
1112
0
    char           *cp;
1113
0
    u_char         *ucp;
1114
1115
0
    in_session->s_snmp_errno = 0;
1116
0
    in_session->s_errno = 0;
1117
1118
    /*
1119
     * Copy session structure and link into list 
1120
     */
1121
0
    slp = calloc(1, sizeof(struct session_list));
1122
0
    if (slp == NULL) {
1123
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1124
0
        return (NULL);
1125
0
    }
1126
1127
0
    slp->transport = NULL;
1128
1129
0
    isp = calloc(1, sizeof(struct snmp_internal_session));
1130
1131
0
    if (isp == NULL) {
1132
0
        snmp_sess_close(slp);
1133
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1134
0
        return (NULL);
1135
0
    }
1136
1137
0
    slp->internal = isp;
1138
0
    slp->session = netsnmp_memdup(in_session, sizeof(netsnmp_session));
1139
0
    if (slp->session == NULL) {
1140
0
        snmp_sess_close(slp);
1141
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1142
0
        return (NULL);
1143
0
    }
1144
0
    session = slp->session;
1145
1146
    /*
1147
     * zero out pointers so if we have to free the session we wont free mem
1148
     * owned by in_session 
1149
     */
1150
0
    session->localname = NULL;
1151
0
    session->peername = NULL;
1152
0
    session->community = NULL;
1153
0
    session->contextEngineID = NULL;
1154
0
    session->contextName = NULL;
1155
0
    session->securityEngineID = NULL;
1156
0
    session->securityName = NULL;
1157
0
    session->securityAuthProto = NULL;
1158
0
    session->securityAuthLocalKey = NULL;
1159
0
    session->securityPrivProto = NULL;
1160
0
    session->securityPrivLocalKey = NULL;
1161
0
    session->sessUser = NULL;
1162
0
    session->paramName = NULL;
1163
0
#ifndef NETSNMP_NO_TRAP_STATS
1164
0
    session->trap_stats = NULL;
1165
0
#endif
1166
    /*
1167
     * session now points to the new structure that still contains pointers to
1168
     * data allocated elsewhere.  Some of this data is copied to space malloc'd
1169
     * here, and the pointer replaced with the new one.
1170
     */
1171
1172
0
    if (in_session->peername != NULL) {
1173
0
        session->peername =
1174
0
            netsnmp_strdup_and_null((u_char*)in_session->peername,
1175
0
                                    strlen(in_session->peername));
1176
0
        if (session->peername == NULL) {
1177
0
            snmp_sess_close(slp);
1178
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1179
0
            return (NULL);
1180
0
        }
1181
0
    }
1182
1183
    /*
1184
     * Fill in defaults if necessary 
1185
     */
1186
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1187
0
    if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
1188
0
        ucp = netsnmp_memdup(in_session->community, in_session->community_len);
1189
0
    } else {
1190
0
        if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1191
0
          NETSNMP_DS_LIB_COMMUNITY)) != NULL) {
1192
0
            session->community_len = strlen(cp);
1193
0
            ucp = (u_char *) strdup(cp);
1194
0
        } else {
1195
#ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
1196
            session->community_len = strlen(DEFAULT_COMMUNITY);
1197
            ucp = netsnmp_memdup(DEFAULT_COMMUNITY, session->community_len);
1198
#else
1199
0
            ucp = (u_char *) strdup("");
1200
0
#endif
1201
0
        }
1202
0
    }
1203
1204
0
    if (ucp == NULL) {
1205
0
        snmp_sess_close(slp);
1206
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1207
0
        return (NULL);
1208
0
    }
1209
0
    session->community = ucp;   /* replace pointer with pointer to new data */
1210
0
#endif
1211
1212
0
    if (session->securityLevel <= 0) {
1213
0
        session->securityLevel =
1214
0
            netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECLEVEL);
1215
0
    }
1216
1217
0
    if (in_session->securityEngineIDLen > 0) {
1218
0
        ucp = netsnmp_memdup(in_session->securityEngineID,
1219
0
                             in_session->securityEngineIDLen);
1220
0
        if (ucp == NULL) {
1221
0
            snmp_sess_close(slp);
1222
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1223
0
            return (NULL);
1224
0
        }
1225
0
        session->securityEngineID = ucp;
1226
0
        session->securityEngineIDLen = in_session->securityEngineIDLen;
1227
0
    }
1228
1229
0
    if (in_session->contextEngineIDLen > 0) {
1230
0
        ucp = netsnmp_memdup(in_session->contextEngineID,
1231
0
                             in_session->contextEngineIDLen);
1232
0
        if (ucp == NULL) {
1233
0
            snmp_sess_close(slp);
1234
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1235
0
            return (NULL);
1236
0
        }
1237
0
        session->contextEngineID = ucp;
1238
0
        session->contextEngineIDLen = in_session->contextEngineIDLen;
1239
0
    } else if (in_session->securityEngineIDLen > 0) {
1240
        /*
1241
         * default contextEngineID to securityEngineIDLen if defined 
1242
         */
1243
0
        ucp = netsnmp_memdup(in_session->securityEngineID,
1244
0
                             in_session->securityEngineIDLen);
1245
0
        if (ucp == NULL) {
1246
0
            snmp_sess_close(slp);
1247
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1248
0
            return (NULL);
1249
0
        }
1250
0
        session->contextEngineID = ucp;
1251
0
        session->contextEngineIDLen = in_session->securityEngineIDLen;
1252
0
    }
1253
1254
0
    if (in_session->contextName) {
1255
0
        session->contextName = strdup(in_session->contextName);
1256
0
        if (session->contextName == NULL) {
1257
0
            snmp_sess_close(slp);
1258
0
            return (NULL);
1259
0
        }
1260
0
        session->contextNameLen = in_session->contextNameLen;
1261
0
    } else {
1262
0
        if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1263
0
                                        NETSNMP_DS_LIB_CONTEXT)) != NULL)
1264
0
            cp = strdup(cp);
1265
0
        else
1266
0
            cp = strdup(SNMP_DEFAULT_CONTEXT);
1267
0
        if (cp == NULL) {
1268
0
            snmp_sess_close(slp);
1269
0
            return (NULL);
1270
0
        }
1271
0
        session->contextName = cp;
1272
0
        session->contextNameLen = strlen(cp);
1273
0
    }
1274
1275
0
    if (in_session->securityName) {
1276
0
        session->securityName = strdup(in_session->securityName);
1277
0
        if (session->securityName == NULL) {
1278
0
            snmp_sess_close(slp);
1279
0
            return (NULL);
1280
0
        }
1281
0
    } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1282
0
             NETSNMP_DS_LIB_SECNAME)) != NULL) {
1283
0
        cp = strdup(cp);
1284
0
        if (cp == NULL) {
1285
0
            snmp_sess_close(slp);
1286
0
            return (NULL);
1287
0
        }
1288
0
        session->securityName = cp;
1289
0
        session->securityNameLen = strlen(cp);
1290
0
    }
1291
1292
0
    if (in_session->securityAuthLocalKey) {
1293
0
            session->securityAuthLocalKey =
1294
0
                netsnmp_memdup(in_session->securityAuthLocalKey,
1295
0
                               in_session->securityAuthLocalKeyLen);
1296
0
            session->securityAuthLocalKeyLen =
1297
0
                in_session->securityAuthLocalKeyLen;
1298
0
    }
1299
1300
0
    if (in_session->securityPrivLocalKey) {
1301
0
            session->securityPrivLocalKey =
1302
0
                netsnmp_memdup(in_session->securityPrivLocalKey,
1303
0
                               in_session->securityPrivLocalKeyLen);
1304
0
            session->securityPrivLocalKeyLen =
1305
0
                in_session->securityPrivLocalKeyLen;
1306
0
    }
1307
1308
0
    if (session->transport_configuration) {
1309
0
        session->transport_configuration =
1310
0
            CONTAINER_DUP(session->transport_configuration, NULL, 0);
1311
0
        if (!session->transport_configuration) {
1312
0
            snmp_sess_close(slp);
1313
0
            return NULL;
1314
0
        }
1315
0
    }
1316
1317
0
    if (session->retries == SNMP_DEFAULT_RETRIES) {
1318
0
        int retry = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1319
0
                                       NETSNMP_DS_LIB_RETRIES);
1320
0
        if (retry < 0)
1321
0
            session->retries = DEFAULT_RETRIES;
1322
0
        else
1323
0
            session->retries = retry;
1324
0
    }
1325
0
    if (session->timeout == SNMP_DEFAULT_TIMEOUT) {
1326
0
        int timeout = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1327
0
                                         NETSNMP_DS_LIB_TIMEOUT);
1328
0
        if (timeout <= 0)
1329
0
            session->timeout = DEFAULT_TIMEOUT;
1330
0
        else
1331
0
            session->timeout = timeout * 1000L * 1000L;
1332
0
    }
1333
0
    session->sessid = snmp_get_next_sessid();
1334
1335
0
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT,
1336
0
                        session);
1337
1338
0
    if ((sptr = find_sec_mod(session->securityModel)) != NULL) {
1339
        /*
1340
         * security module specific copying 
1341
         */
1342
0
        if (sptr->session_setup) {
1343
0
            int ret = (*sptr->session_setup) (in_session, session);
1344
0
            if (ret != SNMPERR_SUCCESS) {
1345
0
                snmp_sess_close(slp);
1346
0
                return NULL;
1347
0
            }
1348
0
        }
1349
1350
        /*
1351
         * security module specific opening
1352
         */
1353
0
        if (sptr->session_open) {
1354
0
            int ret = (*sptr->session_open) (session);
1355
0
            if (ret != SNMPERR_SUCCESS) {
1356
0
                snmp_sess_close(slp);
1357
0
                return NULL;
1358
0
            }
1359
0
        }
1360
0
    }
1361
1362
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
1363
0
    if (in_session->sessUser) {
1364
0
        struct usmUser *user;
1365
1366
0
        user = calloc(1, sizeof(struct usmUser));
1367
0
        if (user == NULL) {
1368
0
            snmp_sess_close(slp);
1369
0
            return NULL;
1370
0
        }
1371
0
        session->sessUser = usm_cloneFrom_user(in_session->sessUser, user);
1372
0
        if (session->sessUser == NULL) {
1373
0
            usm_free_user(user);
1374
0
            snmp_sess_close(slp);
1375
0
            return NULL;
1376
0
        }
1377
0
    }
1378
0
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1379
1380
0
    if (in_session->paramName) {
1381
0
        session->paramName = strdup(in_session->paramName);
1382
0
        if (session->paramName == NULL) {
1383
0
            snmp_sess_close(slp);
1384
0
            return NULL;
1385
0
        }
1386
0
    }
1387
0
#ifndef NETSNMP_NO_TRAP_STATS
1388
0
    if (in_session->trap_stats) {
1389
0
        session->trap_stats = netsnmp_memdup(in_session->trap_stats,
1390
0
                                             sizeof(*in_session->trap_stats));
1391
0
        if (session->trap_stats == NULL) {
1392
0
            snmp_sess_close(slp);
1393
0
            return NULL;
1394
0
        }
1395
0
    }
1396
0
#endif
1397
1398
0
    return (slp);
1399
0
}
1400
1401
static struct session_list *
1402
snmp_sess_copy(netsnmp_session * pss)
1403
0
{
1404
0
    struct session_list *psl;
1405
0
    psl = _sess_copy(pss);
1406
0
    if (!psl) {
1407
0
        if (!pss->s_snmp_errno) {
1408
0
            pss->s_snmp_errno = SNMPERR_GENERR;
1409
0
        }
1410
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
1411
0
    }
1412
0
    return psl;
1413
0
}
1414
1415
/**
1416
 * Allocate a PDU for probing for the engineID
1417
 *
1418
 * The returned PDU can be used to probe synchronously or asynchronously.
1419
 * SNMP_FLAGS_DONT_PROBE must be set to disable internal synchronous probing,
1420
 * when response is received and all callbacks have executed the rest of PDUs
1421
 * can be sent as usual.
1422
 */
1423
netsnmp_pdu *snmpv3_probe_usm_pdu_create(void)
1424
0
{
1425
0
        netsnmp_pdu     *pdu;
1426
1427
0
        pdu = snmp_pdu_create(SNMP_MSG_GET);
1428
0
        if (!pdu)
1429
0
                return NULL;
1430
1431
0
        pdu->version = SNMP_VERSION_3;
1432
0
        pdu->securityName = strdup("");
1433
0
        if (!pdu->securityName) {
1434
0
                snmp_free_pdu(pdu);
1435
0
                return NULL;
1436
0
        }
1437
0
        pdu->securityNameLen = 0;
1438
0
        pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1439
0
        pdu->securityModel = SNMP_SEC_MODEL_USM;
1440
1441
0
        return pdu;
1442
0
}
1443
1444
#ifndef NETSNMP_FEATURE_REMOVE_SNMPV3_PROBE_CONTEXTENGINEID_RFC5343
1445
/**
1446
 * probe for engineID using RFC 5343 probing mechanisms
1447
 *
1448
 * Designed to be a callback for within a security model's probe_engineid hook.
1449
 * Since it's likely multiple security models won't have engineIDs to
1450
 * probe for then this function is a callback likely to be used by
1451
 * multiple future security models.  E.G. both SSH and DTLS.
1452
 */
1453
int
1454
snmpv3_probe_contextEngineID_rfc5343(struct session_list *slp,
1455
                                     netsnmp_session *session)
1456
0
{
1457
0
    netsnmp_pdu    *pdu = NULL, *response = NULL;
1458
0
    static const oid snmpEngineIDoid[]   = { 1,3,6,1,6,3,10,2,1,1,0};
1459
0
    static size_t   snmpEngineIDoid_len = 11;
1460
1461
0
    static char     probeEngineID[] = { (char)0x80, 0, 0, 0, 6 };
1462
0
    static size_t   probeEngineID_len = sizeof(probeEngineID);
1463
    
1464
0
    int status;
1465
1466
0
    pdu = snmp_pdu_create(SNMP_MSG_GET);
1467
0
    if (!pdu)
1468
0
        return SNMP_ERR_GENERR;
1469
0
    pdu->version = SNMP_VERSION_3;
1470
    /* don't require a securityName */
1471
0
    if (session->securityName) {
1472
0
        pdu->securityName = strdup(session->securityName);
1473
0
        if (!pdu->securityName) {
1474
0
            snmp_free_pdu(pdu);
1475
0
            return SNMP_ERR_GENERR;
1476
0
        }
1477
0
        pdu->securityNameLen = strlen(pdu->securityName);
1478
0
    }
1479
0
    pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1480
0
    pdu->securityModel = session->securityModel;
1481
0
    pdu->contextEngineID = netsnmp_memdup(probeEngineID, probeEngineID_len);
1482
0
    if (!pdu->contextEngineID) {
1483
0
        snmp_log(LOG_ERR, "failed to clone memory for rfc5343 probe\n");
1484
0
        snmp_free_pdu(pdu);
1485
0
        return SNMP_ERR_GENERR;
1486
0
    }
1487
0
    pdu->contextEngineIDLen = probeEngineID_len;
1488
    
1489
0
    snmp_add_null_var(pdu, snmpEngineIDoid, snmpEngineIDoid_len);
1490
1491
0
    DEBUGMSGTL(("snmp_api", "probing for engineID using rfc5343 methods...\n"));
1492
0
    session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
1493
0
    status = snmp_sess_synch_response(slp, pdu, &response);
1494
1495
0
    if ((response == NULL) || (status != STAT_SUCCESS)) {
1496
0
        snmp_log(LOG_ERR, "failed rfc5343 contextEngineID probing\n");
1497
0
        if (response)
1498
0
            snmp_free_pdu(response);
1499
0
        return SNMP_ERR_GENERR;
1500
0
    }
1501
1502
    /* check that the response makes sense */
1503
0
    if (NULL != response->variables &&
1504
0
        NULL != response->variables->name &&
1505
0
        snmp_oid_compare(response->variables->name,
1506
0
                         response->variables->name_length,
1507
0
                         snmpEngineIDoid, snmpEngineIDoid_len) == 0 &&
1508
0
        ASN_OCTET_STR == response->variables->type  &&
1509
0
        NULL != response->variables->val.string &&
1510
0
        response->variables->val_len > 0) {
1511
0
        free(session->contextEngineID);
1512
0
        session->contextEngineID =
1513
0
            netsnmp_memdup(response->variables->val.string,
1514
0
                           response->variables->val_len);
1515
0
        if (!session->contextEngineID) {
1516
0
            snmp_log(LOG_ERR, "failed rfc5343 contextEngineID probing: memory allocation failed\n");
1517
0
            session->contextEngineIDLen = 0;
1518
0
            snmp_free_pdu(response);
1519
0
            return SNMP_ERR_GENERR;
1520
0
        }
1521
0
        session->contextEngineIDLen = response->variables->val_len;
1522
        
1523
        /* technically there likely isn't a securityEngineID but just
1524
           in case anyone goes looking we might as well have one */
1525
0
        free(session->securityEngineID);
1526
0
        session->securityEngineID =
1527
0
            netsnmp_memdup(response->variables->val.string,
1528
0
                           response->variables->val_len);
1529
0
        if (!session->securityEngineID) {
1530
0
            snmp_log(LOG_ERR, "failed rfc5343 securityEngineID probing: memory allocation failed\n");
1531
0
            session->securityEngineIDLen = 0;
1532
0
            snmp_free_pdu(response);
1533
0
            return SNMP_ERR_GENERR;
1534
0
        }
1535
        
1536
0
        session->securityEngineIDLen = response->variables->val_len;
1537
        
1538
0
        if (snmp_get_do_debugging()) {
1539
0
            size_t i;
1540
0
            DEBUGMSGTL(("snmp_sess_open",
1541
0
                        "  probe found engineID:  "));
1542
0
            for (i = 0; i < session->securityEngineIDLen; i++)
1543
0
                DEBUGMSG(("snmp_sess_open", "%02x",
1544
0
                          session->securityEngineID[i]));
1545
0
            DEBUGMSG(("snmp_sess_open", "\n"));
1546
0
        }
1547
0
    }
1548
0
    if (response)
1549
0
        snmp_free_pdu(response);
1550
0
    return SNMPERR_SUCCESS;
1551
0
}
1552
#endif /* NETSNMP_FEATURE_REMOVE_SNMPV3_PROBE_CONTEXTENGINEID_RFC5343 */
1553
1554
1555
/**
1556
 * probe for peer engineID
1557
 *
1558
 * @param slp         session list pointer.
1559
 * @param in_session  session for errors
1560
 *
1561
 * @note
1562
 *  - called by _sess_open(), snmp_sess_add_ex()
1563
 *  - in_session is the user supplied session provided to those functions.
1564
 *  - the first session in slp should the internal allocated copy of in_session
1565
 *
1566
 * @return 0 : error
1567
 * @return 1 : ok
1568
 *
1569
 */
1570
int
1571
snmpv3_engineID_probe(struct session_list *slp,
1572
                      netsnmp_session * in_session)
1573
0
{
1574
0
    netsnmp_session *session;
1575
0
    int             status;
1576
0
    struct snmp_secmod_def *sptr = NULL;
1577
1578
0
    if (slp == NULL || slp->session == NULL) {
1579
0
        return 0;
1580
0
    }
1581
1582
0
    session = slp->session;
1583
0
    netsnmp_assert_or_return(session != NULL, 0);
1584
0
    sptr = find_sec_mod(session->securityModel);
1585
1586
    /*
1587
     * If we are opening a V3 session and we don't know engineID we must probe
1588
     * it -- this must be done after the session is created and inserted in the
1589
     * list so that the response can handled correctly. 
1590
     */
1591
1592
0
    if (session->version == SNMP_VERSION_3 &&
1593
0
        (0 == (session->flags & SNMP_FLAGS_DONT_PROBE))) {
1594
0
        if (NULL != sptr && NULL != sptr->probe_engineid) {
1595
0
            DEBUGMSGTL(("snmp_api", "probing for engineID using security model callback...\n"));
1596
            /* security model specific mechanism of determining engineID */
1597
0
            status = (*sptr->probe_engineid) (slp, in_session);
1598
0
            if (status != SNMPERR_SUCCESS)
1599
0
                return 0;
1600
0
        } else {
1601
            /* XXX: default to the default RFC5343 contextEngineID Probe? */
1602
0
            return 0;
1603
0
        }
1604
0
    }
1605
1606
    /*
1607
     * see if there is a hook to call now that we're done probing for an
1608
     * engineID
1609
     */
1610
0
    if (sptr && sptr->post_probe_engineid) {
1611
0
        status = (*sptr->post_probe_engineid)(slp, in_session);
1612
0
        if (status != SNMPERR_SUCCESS)
1613
0
            return 0;
1614
0
    }
1615
1616
0
    return 1;
1617
0
}
1618
1619
/*******************************************************************-o-******
1620
 * netsnmp_sess_config_transport
1621
 *
1622
 * Parameters:
1623
 *  *in_session
1624
 *  *in_transport
1625
 *
1626
 * Returns:
1627
 *      SNMPERR_SUCCESS                     - Yay
1628
 *      SNMPERR_GENERR                      - Generic Error
1629
 *      SNMPERR_TRANSPORT_CONFIG_ERROR      - Transport rejected config
1630
 *      SNMPERR_TRANSPORT_NO_CONFIG         - Transport can't config
1631
 */
1632
int
1633
netsnmp_sess_config_transport(netsnmp_container *transport_configuration,
1634
                              netsnmp_transport *transport)
1635
0
{
1636
    /* Optional supplemental transport configuration information and
1637
       final call to actually open the transport */
1638
0
    if (transport_configuration) {
1639
0
        DEBUGMSGTL(("snmp_sess", "configuring transport\n"));
1640
0
        if (transport->f_config) {
1641
0
            netsnmp_iterator *iter;
1642
0
            netsnmp_transport_config *config_data;
1643
0
            int ret = 0;
1644
1645
0
            iter = CONTAINER_ITERATOR(transport_configuration);
1646
0
            if (NULL == iter) {
1647
0
                return SNMPERR_GENERR;
1648
0
            }
1649
1650
0
            for(config_data = (netsnmp_transport_config*)ITERATOR_FIRST(iter); config_data;
1651
0
                config_data = (netsnmp_transport_config*)ITERATOR_NEXT(iter)) {
1652
0
                ret = transport->f_config(transport, config_data->key,
1653
0
                                          config_data->value);
1654
0
                if (ret)
1655
0
                    break;
1656
0
            }
1657
0
            ITERATOR_RELEASE(iter);
1658
0
            if (ret)
1659
0
                return SNMPERR_TRANSPORT_CONFIG_ERROR;
1660
0
        } else {
1661
0
            return SNMPERR_TRANSPORT_NO_CONFIG;
1662
0
        }
1663
0
    }
1664
0
    return SNMPERR_SUCCESS;
1665
0
}
1666
1667
 
1668
/**
1669
 * Copies configuration from the session and calls f_open
1670
 * This function copies any configuration stored in the session
1671
 * pointer to the transport if it has a f_config pointer and then
1672
 * calls the transport's f_open function to actually open the
1673
 * connection.
1674
 *
1675
 * @param in_session A pointer to the session that config information is in.
1676
 * @param transport A pointer to the transport to config/open.
1677
 *
1678
 * @return SNMPERR_SUCCESS : on success
1679
 */
1680
1681
/*******************************************************************-o-******
1682
 * netsnmp_sess_config_transport
1683
 *
1684
 * Parameters:
1685
 *  *in_session
1686
 *  *in_transport
1687
 *
1688
 * Returns:
1689
 *      SNMPERR_SUCCESS                     - Yay
1690
 *      SNMPERR_GENERR                      - Generic Error
1691
 *      SNMPERR_TRANSPORT_CONFIG_ERROR      - Transport rejected config
1692
 *      SNMPERR_TRANSPORT_NO_CONFIG         - Transport can't config
1693
 */
1694
int
1695
netsnmp_sess_config_and_open_transport(netsnmp_session *in_session,
1696
                                       netsnmp_transport *transport)
1697
0
{
1698
0
    int rc;
1699
    
1700
0
    DEBUGMSGTL(("snmp_sess", "opening transport: %x\n", transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED));
1701
1702
    /* don't double open */
1703
0
    if (transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED)
1704
0
        return SNMPERR_SUCCESS;
1705
1706
0
    if ((rc = netsnmp_sess_config_transport(in_session->transport_configuration,
1707
0
                                            transport)) != SNMPERR_SUCCESS) {
1708
0
        in_session->s_snmp_errno = rc;
1709
0
        in_session->s_errno = 0;
1710
0
        return rc;
1711
0
    }
1712
        
1713
0
    if (transport->f_open)
1714
0
        transport = transport->f_open(transport);
1715
1716
0
    if (transport == NULL) {
1717
0
        DEBUGMSGTL(("snmp_sess", "couldn't open transport connection\n"));
1718
0
        in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
1719
0
        in_session->s_errno = errno;
1720
0
        snmp_set_detail(in_session->peername);
1721
0
        return SNMPERR_BAD_ADDRESS;
1722
0
    }
1723
1724
    /** if transport has a max size, make sure session is the same (or less) */
1725
0
    if (in_session->rcvMsgMaxSize > transport->msgMaxSize) {
1726
0
        DEBUGMSGTL(("snmp_sess",
1727
0
                    "limiting session rcv size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1728
0
                    in_session->rcvMsgMaxSize, transport->msgMaxSize));
1729
0
        in_session->rcvMsgMaxSize = transport->msgMaxSize;
1730
0
    }
1731
1732
0
    if (in_session->sndMsgMaxSize > transport->msgMaxSize) {
1733
0
        DEBUGMSGTL(("snmp_sess",
1734
0
                    "limiting session snd size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1735
0
                    in_session->sndMsgMaxSize, transport->msgMaxSize));
1736
0
        in_session->sndMsgMaxSize = transport->msgMaxSize;
1737
0
    }
1738
1739
0
    transport->flags |= NETSNMP_TRANSPORT_FLAG_OPENED;
1740
0
    DEBUGMSGTL(("snmp_sess", "done opening transport: %x\n", transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED));
1741
0
    return SNMPERR_SUCCESS;
1742
0
}
1743
1744
/*******************************************************************-o-******
1745
 * snmp_sess_open
1746
 *
1747
 * Parameters:
1748
 *  *in_session
1749
 *
1750
 * Returns:
1751
 *      Pointer to a session in the session list   -OR-   FIX -- right?
1752
 *  NULL on failure.
1753
 *
1754
 * The "spin-free" version of snmp_open.
1755
 */
1756
static struct session_list *
1757
_sess_open(netsnmp_session * in_session)
1758
0
{
1759
0
    netsnmp_transport *transport = NULL;
1760
0
    int rc;
1761
1762
0
    in_session->s_snmp_errno = 0;
1763
0
    in_session->s_errno = 0;
1764
1765
0
    _init_snmp();
1766
1767
0
    {
1768
0
        char *clientaddr_save = NULL;
1769
1770
0
        if (NULL != in_session->localname) {
1771
0
            clientaddr_save =
1772
0
                netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1773
0
                                      NETSNMP_DS_LIB_CLIENT_ADDR);
1774
0
            if (clientaddr_save)
1775
0
                clientaddr_save = strdup(clientaddr_save);
1776
1777
0
            netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1778
0
                                  NETSNMP_DS_LIB_CLIENT_ADDR,
1779
0
                                  in_session->localname);
1780
0
        }
1781
1782
0
        if (in_session->flags & SNMP_FLAGS_STREAM_SOCKET) {
1783
0
            transport =
1784
0
                netsnmp_tdomain_transport_full("snmp", in_session->peername,
1785
0
                                               in_session->local_port, "tcp,tcp6",
1786
0
                                               NULL);
1787
0
        } else {
1788
0
            transport =
1789
0
                netsnmp_tdomain_transport_full("snmp", in_session->peername,
1790
0
                                               in_session->local_port, NULL,
1791
0
                                               NULL);
1792
0
        }
1793
1794
0
        if (NULL != in_session->localname)
1795
0
            netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1796
0
                                  NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
1797
0
        free(clientaddr_save);
1798
0
    }
1799
1800
0
    if (transport == NULL) {
1801
0
        DEBUGMSGTL(("_sess_open", "couldn't interpret peername\n"));
1802
0
        in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
1803
0
        in_session->s_errno = errno;
1804
0
        snmp_set_detail(in_session->peername);
1805
0
        return NULL;
1806
0
    }
1807
1808
    /* Optional supplemental transport configuration information and
1809
       final call to actually open the transport */
1810
0
    if ((rc = netsnmp_sess_config_and_open_transport(in_session, transport))
1811
0
        != SNMPERR_SUCCESS) {
1812
0
        netsnmp_transport_free(transport);
1813
0
        transport = NULL;
1814
0
        return NULL;
1815
0
    }
1816
1817
0
#if defined(SO_BROADCAST) && defined(SOL_SOCKET)
1818
0
    if ( in_session->flags & SNMP_FLAGS_UDP_BROADCAST) {
1819
0
        int   b = 1;
1820
0
        int   rc;
1821
1822
0
        rc = setsockopt(transport->sock, SOL_SOCKET, SO_BROADCAST,
1823
0
                        (char *)&b, sizeof(b));
1824
1825
0
        if ( rc != 0 ) {
1826
0
            in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS; /* good as any? */
1827
0
            in_session->s_errno = errno;
1828
1829
0
            DEBUGMSGTL(("_sess_open", "couldn't enable UDP_BROADCAST\n"));
1830
0
            transport->f_close(transport);
1831
0
            netsnmp_transport_free(transport);
1832
0
            return NULL;
1833
0
        }
1834
0
    }
1835
0
#endif
1836
1837
0
    return snmp_sess_add(in_session, transport, NULL, NULL);
1838
0
}
1839
1840
/*
1841
 * EXTENDED SESSION API ------------------------------------------ 
1842
 * 
1843
 * snmp_sess_add_ex, snmp_sess_add, snmp_add 
1844
 * 
1845
 * Analogous to snmp_open family of functions, but taking a netsnmp_transport
1846
 * pointer as an extra argument.  Unlike snmp_open et al. it doesn't attempt
1847
 * to interpret the in_session->peername as a transport endpoint specifier,
1848
 * but instead uses the supplied transport.  JBPN
1849
 * 
1850
 */
1851
1852
netsnmp_session *
1853
snmp_add(netsnmp_session * in_session,
1854
         netsnmp_transport *transport,
1855
         int (*fpre_parse) (netsnmp_session *, netsnmp_transport *, void *,
1856
                            int), int (*fpost_parse) (netsnmp_session *,
1857
                                                      netsnmp_pdu *, int))
1858
0
{
1859
0
    struct session_list *slp;
1860
1861
0
    slp = snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
1862
0
                           fpost_parse, NULL, NULL, NULL, NULL);
1863
0
    if (slp == NULL) {
1864
0
        return NULL;
1865
0
    }
1866
1867
0
    snmp_session_insert(slp);
1868
1869
0
    return (slp->session);
1870
0
}
1871
1872
netsnmp_session *
1873
snmp_add_full(netsnmp_session * in_session,
1874
              netsnmp_transport *transport,
1875
              int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1876
                                 void *, int),
1877
              int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
1878
                             size_t),
1879
              int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
1880
              int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
1881
                             size_t *), int (*frbuild) (netsnmp_session *,
1882
                                                        netsnmp_pdu *,
1883
                                                        u_char **,
1884
                                                        size_t *,
1885
                                                        size_t *),
1886
              int (*fcheck) (u_char *, size_t),
1887
              netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
1888
                                           size_t))
1889
0
{
1890
0
    struct session_list *slp;
1891
1892
0
    slp = snmp_sess_add_ex(in_session, transport, fpre_parse, fparse,
1893
0
                           fpost_parse, fbuild, frbuild, fcheck, fcreate_pdu);
1894
0
    if (slp == NULL) {
1895
0
        return NULL;
1896
0
    }
1897
1898
0
    snmp_session_insert(slp);
1899
1900
0
    return (slp->session);
1901
0
}
1902
1903
struct session_list *
1904
snmp_sess_add_ex(netsnmp_session * in_session,
1905
                 netsnmp_transport *transport,
1906
                 int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1907
                                    void *, int),
1908
                 int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
1909
                                size_t),
1910
                 int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
1911
                                     int),
1912
                 int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
1913
                                size_t *),
1914
                 int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
1915
                                 u_char **, size_t *, size_t *),
1916
                 int (*fcheck) (u_char *, size_t),
1917
                 netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
1918
                                              size_t))
1919
0
{
1920
0
    struct session_list *slp;
1921
0
    int rc;
1922
    
1923
0
    _init_snmp();
1924
1925
0
    if (transport == NULL)
1926
0
        return NULL;
1927
1928
0
    if (NULL != in_session && (in_session->rcvMsgMaxSize < SNMP_MIN_MAX_LEN ||
1929
0
                               in_session->sndMsgMaxSize < SNMP_MIN_MAX_LEN)) {
1930
0
        DEBUGMSGTL(("snmp_sess_add",
1931
0
                    "invalid session (msg sizes). need snmp_sess_init"));
1932
0
        in_session = NULL; /* force transport cleanup below */
1933
0
    }
1934
1935
0
    if (in_session == NULL) {
1936
0
        transport->f_close(transport);
1937
0
        netsnmp_transport_free(transport);
1938
0
        return NULL;
1939
0
    }
1940
1941
    /* if the transport hasn't been fully opened yet, open it now */
1942
0
    if ((rc = netsnmp_sess_config_and_open_transport(in_session, transport))
1943
0
        != SNMPERR_SUCCESS) {
1944
0
        return NULL;
1945
0
    }
1946
1947
0
    DEBUGMSGTL(("snmp_sess_add", "fd %" NETSNMP_FMT_SKT "\n",
1948
0
                transport->sock));
1949
1950
0
    if ((slp = snmp_sess_copy(in_session)) == NULL) {
1951
0
        transport->f_close(transport);
1952
0
        netsnmp_transport_free(transport);
1953
0
        return (NULL);
1954
0
    }
1955
1956
0
    slp->transport = transport;
1957
0
    slp->internal->hook_pre = fpre_parse;
1958
0
    slp->internal->hook_parse = fparse;
1959
0
    slp->internal->hook_post = fpost_parse;
1960
0
    slp->internal->hook_build = fbuild;
1961
0
    slp->internal->hook_realloc_build = frbuild;
1962
0
    slp->internal->check_packet = fcheck;
1963
0
    slp->internal->hook_create_pdu = fcreate_pdu;
1964
1965
    /** don't let session max exceed transport max */
1966
0
    if (slp->session->rcvMsgMaxSize > transport->msgMaxSize) {
1967
0
        DEBUGMSGTL(("snmp_sess_add",
1968
0
                    "limiting session rcv size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1969
0
                    slp->session->rcvMsgMaxSize, transport->msgMaxSize));
1970
0
        slp->session->rcvMsgMaxSize = transport->msgMaxSize;
1971
0
    }
1972
0
    if (slp->session->sndMsgMaxSize > transport->msgMaxSize) {
1973
0
        DEBUGMSGTL(("snmp_sess_add",
1974
0
                    "limiting session snd size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1975
0
                    slp->session->sndMsgMaxSize, transport->msgMaxSize));
1976
0
        slp->session->sndMsgMaxSize = transport->msgMaxSize;
1977
0
    }
1978
1979
0
    if (transport->f_setup_session &&
1980
0
        transport->f_setup_session(transport, slp->session) != SNMPERR_SUCCESS)
1981
0
        goto close_session;
1982
1983
    /* Anything below this point should only be done if the transport
1984
       had no say in the matter */
1985
0
    if (slp->session->securityLevel == 0)
1986
0
        slp->session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1987
1988
0
    if (slp->session->version == SNMP_VERSION_3) {
1989
0
        DEBUGMSGTL(("snmp_sess_add",
1990
0
                    "adding v3 session -- maybe engineID probe now\n"));
1991
0
        if (!snmpv3_engineID_probe(slp, slp->session)) {
1992
0
            DEBUGMSGTL(("snmp_sess_add", "engine ID probe failed\n"));
1993
0
            goto close_session;
1994
0
        }
1995
0
    }
1996
1997
0
    slp->session->flags &= ~SNMP_FLAGS_DONT_PROBE;
1998
1999
0
    return slp;
2000
2001
0
close_session:
2002
0
    snmp_sess_close(slp);
2003
0
    return NULL;
2004
0
}                               /*  end snmp_sess_add_ex()  */
2005
2006
struct session_list *
2007
snmp_sess_add(netsnmp_session * in_session,
2008
              netsnmp_transport *transport,
2009
              int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
2010
                                 void *, int),
2011
              int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int))
2012
0
{
2013
0
    return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
2014
0
                            fpost_parse, NULL, NULL, NULL, NULL);
2015
0
}
2016
2017
2018
2019
struct session_list *
2020
snmp_sess_open(netsnmp_session * pss)
2021
0
{
2022
0
    struct session_list *slp;
2023
2024
0
    pss->flags |= SNMP_FLAGS_SESSION_USER;
2025
2026
0
    slp = _sess_open(pss);
2027
0
    if (!slp) {
2028
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
2029
0
    }
2030
0
    return slp;
2031
0
}
2032
2033
int
2034
0
create_user_from_session(netsnmp_session * session) {
2035
0
#ifdef NETSNMP_SECMOD_USM
2036
0
    return usm_create_user_from_session(session);
2037
#else
2038
    snmp_log(LOG_ERR, "create_user_from_session called when USM wasn't compiled in");
2039
    netsnmp_assert(0 == 1);
2040
    return SNMP_ERR_GENERR;
2041
#endif
2042
0
}
2043
2044
static void netsnmp_free_one_tr_cfg(void *data, void *context)
2045
0
{
2046
0
    netsnmp_transport_config *c = data;
2047
2048
0
    free(c->key);
2049
0
    free(c->value);
2050
0
    free(c);
2051
0
}
2052
2053
static void netsnmp_free_transport_config(netsnmp_container *tc)
2054
0
{
2055
0
    if (!tc)
2056
0
        return;
2057
2058
0
    CONTAINER_CLEAR(tc, netsnmp_free_one_tr_cfg, NULL);
2059
0
    CONTAINER_FREE(tc);
2060
0
}
2061
2062
/* Free the memory owned by a session but not the session object itself. */
2063
void netsnmp_cleanup_session(netsnmp_session *s)
2064
0
{
2065
0
    free(s->localname);
2066
0
    free(s->peername);
2067
0
    free(s->community);
2068
0
    free(s->contextEngineID);
2069
0
    free(s->contextName);
2070
0
    free(s->securityEngineID);
2071
0
    free(s->securityName);
2072
0
    free(s->securityAuthProto);
2073
0
    free(s->securityAuthLocalKey);
2074
0
    free(s->securityPrivProto);
2075
0
    free(s->securityPrivLocalKey);
2076
0
    free(s->paramName);
2077
0
#ifndef NETSNMP_NO_TRAP_STATS
2078
0
    free(s->trap_stats);
2079
0
#endif /* NETSNMP_NO_TRAP_STATS */
2080
0
    usm_free_user(s->sessUser);
2081
0
    netsnmp_free_transport_config(s->transport_configuration);
2082
0
    memset(s, 0, sizeof(*s));
2083
0
}
2084
2085
/*
2086
 *  Do a "deep free()" of a netsnmp_session.
2087
 *
2088
 *  CAUTION:  SHOULD ONLY BE USED FROM snmp_sess_close() OR SIMILAR.
2089
 *                                                      (hence it is static)
2090
 */
2091
static void
2092
snmp_free_session(netsnmp_session * s)
2093
0
{
2094
0
    if (!s)
2095
0
        return;
2096
2097
0
    netsnmp_cleanup_session(s);
2098
2099
    /*
2100
     * clear session from any callbacks
2101
     */
2102
0
    netsnmp_callback_clear_client_arg(s, 0, 0);
2103
2104
0
    free(s);
2105
0
}
2106
2107
/* Remove request @rp from session @isp. @orp is the request before @rp. */
2108
static void
2109
remove_request(struct snmp_internal_session *isp,
2110
               netsnmp_request_list *orp, netsnmp_request_list *rp)
2111
0
{
2112
0
    if (orp)
2113
0
        orp->next_request = rp->next_request;
2114
0
    else
2115
0
        isp->requests = rp->next_request;
2116
0
    if (isp->requestsEnd == rp)
2117
0
        isp->requestsEnd = orp;
2118
0
    if (rp->cb_data_refcounted) {
2119
0
        netsnmp_refcnt_void *aux = (netsnmp_refcnt_void*) rp->cb_data;
2120
0
        if (aux) {
2121
0
            aux->refcnt--;
2122
0
            if (aux->refcnt <= 0) {
2123
0
                free(aux);
2124
0
            }
2125
0
        }
2126
0
    }
2127
0
    snmp_free_pdu(rp->pdu);
2128
0
}
2129
2130
/*
2131
 * Close the input session.  Frees all data allocated for the session,
2132
 * dequeues any pending requests, and closes any sockets allocated for
2133
 * the session.  Returns 0 on error, 1 otherwise.
2134
 */
2135
int
2136
snmp_sess_close(struct session_list *slp)
2137
0
{
2138
0
    netsnmp_transport *transport;
2139
0
    struct snmp_internal_session *isp;
2140
0
    netsnmp_session *sesp = NULL;
2141
0
    struct snmp_secmod_def *sptr;
2142
2143
0
    if (slp == NULL) {
2144
0
        return 0;
2145
0
    }
2146
2147
0
    if (slp->session != NULL &&
2148
0
        (sptr = find_sec_mod(slp->session->securityModel)) != NULL &&
2149
0
        sptr->session_close != NULL) {
2150
0
        (*sptr->session_close) (slp->session);
2151
0
    }
2152
2153
0
    isp = slp->internal;
2154
0
    slp->internal = NULL;
2155
2156
0
    if (isp) {
2157
0
        netsnmp_request_list *rp, *orp;
2158
2159
0
        SNMP_FREE(isp->packet);
2160
2161
        /*
2162
         * Free each element in the input request list.  
2163
         */
2164
0
        rp = isp->requests;
2165
0
        while (rp) {
2166
0
            orp = rp;
2167
0
            rp = rp->next_request;
2168
0
            if (orp->callback) {
2169
0
                orp->callback(NETSNMP_CALLBACK_OP_TIMED_OUT,
2170
0
                              slp->session, orp->pdu->reqid,
2171
0
                              orp->pdu, orp->cb_data);
2172
0
            }
2173
0
            remove_request(isp, NULL, orp);
2174
0
            free(orp);
2175
0
        }
2176
2177
0
        free(isp);
2178
0
    }
2179
2180
0
    transport = slp->transport;
2181
0
    slp->transport = NULL;
2182
2183
0
    if (transport) {
2184
0
        transport->f_close(transport);
2185
0
        netsnmp_transport_free(transport);
2186
0
    }
2187
2188
0
    sesp = slp->session;
2189
0
    slp->session = NULL;
2190
2191
    /*
2192
     * The following is necessary to avoid memory leakage when closing AgentX 
2193
     * sessions that may have multiple subsessions.  These hang off the main
2194
     * session at ->subsession, and chain through ->next.  
2195
     */
2196
2197
0
    if (sesp != NULL && sesp->subsession != NULL) {
2198
0
        netsnmp_session *subsession = sesp->subsession, *tmpsub;
2199
2200
0
        while (subsession != NULL) {
2201
0
            DEBUGMSGTL(("snmp_sess_close",
2202
0
                        "closing session %p, subsession %p\n", sesp,
2203
0
                        subsession));
2204
0
            tmpsub = subsession->next;
2205
0
            snmp_free_session(subsession);
2206
0
            subsession = tmpsub;
2207
0
        }
2208
0
    }
2209
2210
0
    snmp_free_session(sesp);
2211
0
    free(slp);
2212
0
    return 1;
2213
0
}
2214
2215
int
2216
snmp_close(netsnmp_session * session)
2217
0
{
2218
0
    struct session_list *slp = NULL, *oslp = NULL;
2219
2220
0
    {                           /*MTCRITICAL_RESOURCE */
2221
0
        snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
2222
0
        if (Sessions && Sessions->session == session) { /* If first entry */
2223
0
            slp = Sessions;
2224
0
            Sessions = slp->next;
2225
0
        } else {
2226
0
            for (slp = Sessions; slp; slp = slp->next) {
2227
0
                if (slp->session == session) {
2228
0
                    if (oslp)   /* if we found entry that points here */
2229
0
                        oslp->next = slp->next; /* link around this entry */
2230
0
                    break;
2231
0
                }
2232
0
                oslp = slp;
2233
0
            }
2234
0
        }
2235
0
        snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
2236
0
    }                           /*END MTCRITICAL_RESOURCE */
2237
0
    if (slp == NULL) {
2238
0
        return 0;
2239
0
    }
2240
0
    return snmp_sess_close(slp);
2241
0
}
2242
2243
int
2244
snmp_close_sessions(void)
2245
0
{
2246
0
    struct session_list *slp;
2247
2248
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
2249
0
    while (Sessions) {
2250
0
        slp = Sessions;
2251
0
        Sessions = Sessions->next;
2252
0
        snmp_sess_close(slp);
2253
0
    }
2254
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
2255
0
    return 1;
2256
0
}
2257
2258
static void
2259
snmpv3_calc_msg_flags(int sec_level, int msg_command, u_char * flags)
2260
0
{
2261
0
    *flags = 0;
2262
0
    if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2263
0
        *flags = SNMP_MSG_FLAG_AUTH_BIT;
2264
0
    else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
2265
0
        *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
2266
2267
0
    if (SNMP_CMD_CONFIRMED(msg_command))
2268
0
        *flags |= SNMP_MSG_FLAG_RPRT_BIT;
2269
2270
0
    return;
2271
0
}
2272
2273
static int
2274
snmpv3_verify_msg(netsnmp_request_list *rp, netsnmp_pdu *pdu)
2275
0
{
2276
0
    netsnmp_pdu    *rpdu;
2277
2278
    /* XX: This function silently rejects. Add error handling. */
2279
0
    if (!rp || !rp->pdu || !pdu)
2280
0
        return 0;
2281
    /*
2282
     * Reports don't have to match anything according to the spec 
2283
     */
2284
0
    if (pdu->command == SNMP_MSG_REPORT)
2285
0
        return 1;
2286
0
    rpdu = rp->pdu;
2287
0
    if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid)
2288
0
        return 0;
2289
0
    if (rpdu->version != pdu->version)
2290
0
        return 0;
2291
0
    if (rpdu->securityModel != pdu->securityModel)
2292
0
        return 0;
2293
0
    if (rpdu->securityLevel != pdu->securityLevel)
2294
0
        return 0;
2295
2296
0
    if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen)
2297
0
        return 0;
2298
0
    if (pdu->contextEngineIDLen &&
2299
0
        memcmp(rpdu->contextEngineID, pdu->contextEngineID,
2300
0
               pdu->contextEngineIDLen))
2301
0
        return 0;
2302
0
    if (rpdu->contextNameLen != pdu->contextNameLen)
2303
0
        return 0;
2304
0
    if (pdu->contextNameLen &&
2305
0
        memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
2306
0
        return 0;
2307
2308
    /* tunneled transports don't have a securityEngineID...  that's
2309
       USM specific (and maybe other future ones) */
2310
0
    if (pdu->securityModel == SNMP_SEC_MODEL_USM &&
2311
0
        (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
2312
0
         (pdu->securityEngineIDLen &&
2313
0
          memcmp(rpdu->securityEngineID, pdu->securityEngineID,
2314
0
                 pdu->securityEngineIDLen))))
2315
0
        return 0;
2316
2317
    /* the securityName must match though regardless of secmodel */
2318
0
    if (rpdu->securityNameLen != pdu->securityNameLen ||
2319
0
        memcmp(rpdu->securityName, pdu->securityName,
2320
0
               pdu->securityNameLen))
2321
0
        return 0;
2322
0
    return 1;
2323
0
}
2324
2325
2326
/*
2327
 * SNMPv3
2328
 * * Takes a session and a pdu and serializes the ASN PDU into the area
2329
 * * pointed to by packet.  out_length is the size of the data area available.
2330
 * * Returns the length of the completed packet in out_length.  If any errors
2331
 * * occur, -1 is returned.  If all goes well, 0 is returned.
2332
 */
2333
static int
2334
snmpv3_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
2335
             netsnmp_session * session, netsnmp_pdu *pdu)
2336
0
{
2337
0
    int             ret;
2338
2339
0
    session->s_snmp_errno = 0;
2340
0
    session->s_errno = 0;
2341
2342
    /*
2343
     * do validation for PDU types 
2344
     */
2345
0
    switch (pdu->command) {
2346
0
    case SNMP_MSG_RESPONSE:
2347
0
    case SNMP_MSG_TRAP2:
2348
0
    case SNMP_MSG_REPORT:
2349
0
        netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2350
0
        NETSNMP_FALLTHROUGH;
2351
0
    case SNMP_MSG_INFORM:
2352
0
#ifndef NETSNMP_NOTIFY_ONLY
2353
0
    case SNMP_MSG_GET:
2354
0
    case SNMP_MSG_GETNEXT:
2355
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
2356
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
2357
0
    case SNMP_MSG_SET:
2358
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
2359
0
        if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2360
0
            pdu->errstat = 0;
2361
0
        if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2362
0
            pdu->errindex = 0;
2363
0
        break;
2364
2365
0
#ifndef NETSNMP_NOTIFY_ONLY
2366
0
    case SNMP_MSG_GETBULK:
2367
0
        if (pdu->max_repetitions < 0) {
2368
0
            session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
2369
0
            return -1;
2370
0
        }
2371
0
        if (pdu->non_repeaters < 0) {
2372
0
            session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
2373
0
            return -1;
2374
0
        }
2375
0
        break;
2376
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
2377
2378
0
    case SNMP_MSG_TRAP:
2379
0
        session->s_snmp_errno = SNMPERR_V1_IN_V2;
2380
0
        return -1;
2381
2382
0
    default:
2383
0
        session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
2384
0
        return -1;
2385
0
    }
2386
2387
    /* Do we need to set the session security engineid? */
2388
0
    if (pdu->securityEngineIDLen == 0) {
2389
0
        if (session->securityEngineIDLen) {
2390
0
            snmpv3_clone_engineID(&pdu->securityEngineID,
2391
0
                                  &pdu->securityEngineIDLen,
2392
0
                                  session->securityEngineID,
2393
0
                                  session->securityEngineIDLen);
2394
0
        }
2395
0
    }
2396
    
2397
    /* Do we need to set the session context engineid? */
2398
0
    if (pdu->contextEngineIDLen == 0) {
2399
0
        if (session->contextEngineIDLen) {
2400
0
            snmpv3_clone_engineID(&pdu->contextEngineID,
2401
0
                                  &pdu->contextEngineIDLen,
2402
0
                                  session->contextEngineID,
2403
0
                                  session->contextEngineIDLen);
2404
0
        } else if (pdu->securityEngineIDLen) {
2405
0
            snmpv3_clone_engineID(&pdu->contextEngineID,
2406
0
                                  &pdu->contextEngineIDLen,
2407
0
                                  pdu->securityEngineID,
2408
0
                                  pdu->securityEngineIDLen);
2409
0
        }
2410
0
    }
2411
2412
0
    if (pdu->contextName == NULL) {
2413
0
        if (!session->contextName) {
2414
0
            session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
2415
0
            return -1;
2416
0
        }
2417
0
        pdu->contextName = strdup(session->contextName);
2418
0
        if (pdu->contextName == NULL) {
2419
0
            session->s_snmp_errno = SNMPERR_GENERR;
2420
0
            return -1;
2421
0
        }
2422
0
        pdu->contextNameLen = session->contextNameLen;
2423
0
    }
2424
0
    if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
2425
0
        pdu->securityModel = session->securityModel;
2426
0
        if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
2427
0
            pdu->securityModel = se_find_value_in_slist("snmp_secmods", netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECMODEL));
2428
            
2429
0
            if (pdu->securityModel <= 0) {
2430
0
                pdu->securityModel = SNMP_SEC_MODEL_USM;
2431
0
            }
2432
0
        }
2433
0
    }
2434
0
    if (pdu->securityNameLen == 0 && pdu->securityName == NULL) {
2435
0
        if (session->securityModel != SNMP_SEC_MODEL_TSM &&
2436
0
            session->securityNameLen == 0) {
2437
0
            session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
2438
0
            return -1;
2439
0
        }
2440
0
        if (session->securityName) {
2441
0
            pdu->securityName = strdup(session->securityName);
2442
0
            if (pdu->securityName == NULL) {
2443
0
                session->s_snmp_errno = SNMPERR_GENERR;
2444
0
                return -1;
2445
0
            }
2446
0
            pdu->securityNameLen = session->securityNameLen;
2447
0
        } else {
2448
0
            pdu->securityName = strdup("");
2449
0
            session->securityName = strdup("");
2450
0
            if (pdu->securityName == NULL || session->securityName == NULL) {
2451
0
                SNMP_FREE(pdu->securityName);
2452
0
                SNMP_FREE(session->securityName);
2453
0
                session->s_snmp_errno = SNMPERR_GENERR;
2454
0
                return -1;
2455
0
            }
2456
0
        }
2457
0
    }
2458
0
    if (pdu->securityLevel == 0) {
2459
0
        if (session->securityLevel == 0) {
2460
0
            session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
2461
0
            return -1;
2462
0
        }
2463
0
        pdu->securityLevel = session->securityLevel;
2464
0
    }
2465
0
    DEBUGMSGTL(("snmp_build",
2466
0
                "Building SNMPv3 message (secName:\"%s\", secLevel:%s)...\n",
2467
0
                ((session->securityName) ? (char *) session->securityName :
2468
0
                 ((pdu->securityName) ? (char *) pdu->securityName :
2469
0
                  "ERROR: undefined")),
2470
0
                (pdu->securityLevel >= 0 && pdu->securityLevel < 4) ?
2471
0
                secLevelName[pdu->securityLevel] : "ERROR: invalid"));
2472
2473
0
    DEBUGDUMPSECTION("send", "SNMPv3 Message");
2474
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2475
0
    if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
2476
0
        ret = snmpv3_packet_realloc_rbuild(pkt, pkt_len, offset,
2477
0
                                           session, pdu, NULL, 0);
2478
0
    } else {
2479
0
#endif
2480
0
        ret = snmpv3_packet_build(session, pdu, *pkt, pkt_len, NULL, 0);
2481
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2482
0
    }
2483
0
#endif
2484
0
    DEBUGINDENTLESS();
2485
0
    if (-1 != ret) {
2486
0
        session->s_snmp_errno = ret;
2487
0
    }
2488
2489
0
    return ret;
2490
2491
0
}                               /* end snmpv3_build() */
2492
2493
2494
2495
2496
static u_char  *
2497
snmpv3_header_build(netsnmp_session * session, const netsnmp_pdu *pdu,
2498
                    u_char * packet, size_t * out_length,
2499
                    size_t length, u_char ** msg_hdr_e)
2500
0
{
2501
0
    u_char         *global_hdr, *global_hdr_e;
2502
0
    u_char         *cp;
2503
0
    u_char          msg_flags;
2504
0
    long            max_size;
2505
0
    long            sec_model;
2506
0
    u_char         *pb, *pb0e;
2507
2508
    /*
2509
     * Save current location and build SEQUENCE tag and length placeholder
2510
     * * for SNMP message sequence (actual length inserted later)
2511
     */
2512
0
    cp = asn_build_sequence(packet, out_length,
2513
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2514
0
                            length);
2515
0
    if (cp == NULL)
2516
0
        return NULL;
2517
0
    if (msg_hdr_e != NULL)
2518
0
        *msg_hdr_e = cp;
2519
0
    pb0e = cp;
2520
2521
2522
    /*
2523
     * store the version field - msgVersion
2524
     */
2525
0
    DEBUGDUMPHEADER("send", "SNMP Version Number");
2526
0
    cp = asn_build_int(cp, out_length,
2527
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2528
0
                                 ASN_INTEGER), (const long *) &pdu->version,
2529
0
                       sizeof(pdu->version));
2530
0
    DEBUGINDENTLESS();
2531
0
    if (cp == NULL)
2532
0
        return NULL;
2533
2534
0
    global_hdr = cp;
2535
    /*
2536
     * msgGlobalData HeaderData 
2537
     */
2538
0
    DEBUGDUMPSECTION("send", "msgGlobalData");
2539
0
    cp = asn_build_sequence(cp, out_length,
2540
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
2541
0
    if (cp == NULL)
2542
0
        return NULL;
2543
0
    global_hdr_e = cp;
2544
2545
2546
    /*
2547
     * msgID 
2548
     */
2549
0
    DEBUGDUMPHEADER("send", "msgID");
2550
0
    cp = asn_build_int(cp, out_length,
2551
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2552
0
                                 ASN_INTEGER), &pdu->msgid,
2553
0
                       sizeof(pdu->msgid));
2554
0
    DEBUGINDENTLESS();
2555
0
    if (cp == NULL)
2556
0
        return NULL;
2557
2558
    /*
2559
     * msgMaxSize 
2560
     */
2561
0
    max_size = netsnmp_max_send_msg_size();
2562
0
    if (session->rcvMsgMaxSize < max_size)
2563
0
        max_size = session->rcvMsgMaxSize;
2564
0
    DEBUGDUMPHEADER("send:msgMaxSize1", "msgMaxSize");
2565
0
    cp = asn_build_int(cp, out_length,
2566
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2567
0
                                 ASN_INTEGER), &max_size,
2568
0
                       sizeof(max_size));
2569
0
    DEBUGINDENTLESS();
2570
0
    if (cp == NULL)
2571
0
        return NULL;
2572
2573
    /*
2574
     * msgFlags 
2575
     */
2576
0
    snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
2577
0
    DEBUGDUMPHEADER("send", "msgFlags");
2578
0
    cp = asn_build_string(cp, out_length,
2579
0
                          (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2580
0
                                    ASN_OCTET_STR), &msg_flags,
2581
0
                          sizeof(msg_flags));
2582
0
    DEBUGINDENTLESS();
2583
0
    if (cp == NULL)
2584
0
        return NULL;
2585
2586
    /*
2587
     * msgSecurityModel 
2588
     */
2589
0
    sec_model = pdu->securityModel;
2590
0
    DEBUGDUMPHEADER("send", "msgSecurityModel");
2591
0
    cp = asn_build_int(cp, out_length,
2592
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2593
0
                                 ASN_INTEGER), &sec_model,
2594
0
                       sizeof(sec_model));
2595
0
    DEBUGINDENTADD(-4);         /* return from global data indent */
2596
0
    if (cp == NULL)
2597
0
        return NULL;
2598
2599
2600
    /*
2601
     * insert actual length of globalData
2602
     */
2603
0
    pb = asn_build_sequence(global_hdr, out_length,
2604
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2605
0
                            cp - global_hdr_e);
2606
0
    if (pb == NULL)
2607
0
        return NULL;
2608
2609
2610
    /*
2611
     * insert the actual length of the entire packet
2612
     */
2613
0
    pb = asn_build_sequence(packet, out_length,
2614
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2615
0
                            length + (cp - pb0e));
2616
0
    if (pb == NULL)
2617
0
        return NULL;
2618
2619
0
    return cp;
2620
2621
0
}                               /* end snmpv3_header_build() */
2622
2623
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2624
2625
int
2626
snmpv3_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2627
                             size_t * offset, netsnmp_session * session,
2628
                             netsnmp_pdu *pdu)
2629
0
{
2630
0
    size_t          start_offset = *offset;
2631
0
    u_char          msg_flags;
2632
0
    long            max_size, sec_model;
2633
0
    int             rc = 0;
2634
2635
    /*
2636
     * msgSecurityModel.  
2637
     */
2638
0
    sec_model = pdu->securityModel;
2639
0
    DEBUGDUMPHEADER("send", "msgSecurityModel");
2640
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2641
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2642
0
                                          ASN_INTEGER), &sec_model,
2643
0
                                sizeof(sec_model));
2644
0
    DEBUGINDENTLESS();
2645
0
    if (rc == 0) {
2646
0
        return 0;
2647
0
    }
2648
2649
    /*
2650
     * msgFlags.  
2651
     */
2652
0
    snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
2653
0
    DEBUGDUMPHEADER("send", "msgFlags");
2654
0
    rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2655
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2656
0
                                             | ASN_OCTET_STR), &msg_flags,
2657
0
                                   sizeof(msg_flags));
2658
0
    DEBUGINDENTLESS();
2659
0
    if (rc == 0) {
2660
0
        return 0;
2661
0
    }
2662
2663
    /*
2664
     * msgMaxSize.  
2665
     */
2666
0
    max_size = netsnmp_max_send_msg_size();
2667
0
    if (session->rcvMsgMaxSize < max_size)
2668
0
        max_size = session->rcvMsgMaxSize;
2669
0
    DEBUGDUMPHEADER("send:msgMaxSize2", "msgMaxSize");
2670
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2671
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2672
0
                                          ASN_INTEGER), &max_size,
2673
0
                                sizeof(max_size));
2674
0
    DEBUGINDENTLESS();
2675
0
    if (rc == 0) {
2676
0
        return 0;
2677
0
    }
2678
2679
    /*
2680
     * msgID.  
2681
     */
2682
0
    DEBUGDUMPHEADER("send", "msgID");
2683
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2684
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2685
0
                                          ASN_INTEGER), &pdu->msgid,
2686
0
                                sizeof(pdu->msgid));
2687
0
    DEBUGINDENTLESS();
2688
0
    if (rc == 0) {
2689
0
        return 0;
2690
0
    }
2691
2692
    /*
2693
     * Global data sequence.  
2694
     */
2695
0
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
2696
0
                                     (u_char) (ASN_SEQUENCE |
2697
0
                                               ASN_CONSTRUCTOR),
2698
0
                                     *offset - start_offset);
2699
0
    if (rc == 0) {
2700
0
        return 0;
2701
0
    }
2702
2703
    /*
2704
     * Store the version field - msgVersion.  
2705
     */
2706
0
    DEBUGDUMPHEADER("send", "SNMP Version Number");
2707
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2708
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2709
0
                                          ASN_INTEGER),
2710
0
                                (long *) &pdu->version,
2711
0
                                sizeof(pdu->version));
2712
0
    DEBUGINDENTLESS();
2713
0
    return rc;
2714
0
}                               /* end snmpv3_header_realloc_rbuild() */
2715
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2716
2717
static u_char  *
2718
snmpv3_scopedPDU_header_build(const netsnmp_pdu *pdu,
2719
                              u_char * packet, size_t * out_length,
2720
                              u_char ** spdu_e)
2721
0
{
2722
0
    u_char         *scopedPdu, *pb;
2723
2724
0
    pb = scopedPdu = packet;
2725
0
    pb = asn_build_sequence(pb, out_length,
2726
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
2727
0
    if (pb == NULL)
2728
0
        return NULL;
2729
0
    if (spdu_e)
2730
0
        *spdu_e = pb;
2731
2732
0
    DEBUGDUMPHEADER("send", "contextEngineID");
2733
0
    pb = asn_build_string(pb, out_length,
2734
0
                          (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
2735
0
                          pdu->contextEngineID, pdu->contextEngineIDLen);
2736
0
    DEBUGINDENTLESS();
2737
0
    if (pb == NULL)
2738
0
        return NULL;
2739
2740
0
    DEBUGDUMPHEADER("send", "contextName");
2741
0
    pb = asn_build_string(pb, out_length,
2742
0
                          (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
2743
0
                          (u_char *) pdu->contextName,
2744
0
                          pdu->contextNameLen);
2745
0
    DEBUGINDENTLESS();
2746
0
    if (pb == NULL)
2747
0
        return NULL;
2748
2749
0
    return pb;
2750
2751
0
}                               /* end snmpv3_scopedPDU_header_build() */
2752
2753
2754
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2755
int
2756
snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2757
                                       size_t * offset, netsnmp_pdu *pdu,
2758
                                       size_t body_len)
2759
0
{
2760
0
    size_t          start_offset = *offset;
2761
0
    int             rc = 0;
2762
2763
    /*
2764
     * contextName.  
2765
     */
2766
0
    DEBUGDUMPHEADER("send", "contextName");
2767
0
    rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2768
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2769
0
                                             | ASN_OCTET_STR),
2770
0
                                   (u_char *) pdu->contextName,
2771
0
                                   pdu->contextNameLen);
2772
0
    DEBUGINDENTLESS();
2773
0
    if (rc == 0) {
2774
0
        return 0;
2775
0
    }
2776
2777
    /*
2778
     * contextEngineID.  
2779
     */
2780
0
    DEBUGDUMPHEADER("send", "contextEngineID");
2781
0
    rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2782
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2783
0
                                             | ASN_OCTET_STR),
2784
0
                                   pdu->contextEngineID,
2785
0
                                   pdu->contextEngineIDLen);
2786
0
    DEBUGINDENTLESS();
2787
0
    if (rc == 0) {
2788
0
        return 0;
2789
0
    }
2790
2791
0
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
2792
0
                                     (u_char) (ASN_SEQUENCE |
2793
0
                                               ASN_CONSTRUCTOR),
2794
0
                                     *offset - start_offset + body_len);
2795
2796
0
    return rc;
2797
0
}                               /* end snmpv3_scopedPDU_header_realloc_rbuild() */
2798
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2799
2800
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2801
/*
2802
 * returns 0 if success, -1 if fail, not 0 if SM build failure 
2803
 */
2804
int
2805
snmpv3_packet_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2806
                             size_t * offset, netsnmp_session * session,
2807
                             netsnmp_pdu *pdu, u_char * pdu_data,
2808
                             size_t pdu_data_len)
2809
0
{
2810
0
    u_char         *scoped_pdu, *hdrbuf = NULL, *hdr = NULL;
2811
0
    size_t          hdrbuf_len = SNMP_MAX_MSG_V3_HDRS, hdr_offset =
2812
0
        0, spdu_offset = 0;
2813
0
    size_t          body_end_offset = *offset, body_len = 0;
2814
0
    struct snmp_secmod_def *sptr = NULL;
2815
0
    int             rc = 0;
2816
2817
    /*
2818
     * Build a scopedPDU structure into the packet buffer.  
2819
     */
2820
0
    DEBUGPRINTPDUTYPE("send", pdu->command);
2821
0
    if (pdu_data) {
2822
0
        while ((*pkt_len - *offset) < pdu_data_len) {
2823
0
            if (!asn_realloc(pkt, pkt_len)) {
2824
0
                return -1;
2825
0
            }
2826
0
        }
2827
2828
0
        *offset += pdu_data_len;
2829
0
        memcpy(*pkt + *pkt_len - *offset, pdu_data, pdu_data_len);
2830
0
    } else {
2831
0
        rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
2832
0
        if (rc == 0) {
2833
0
            return -1;
2834
0
        }
2835
0
    }
2836
0
    body_len = *offset - body_end_offset;
2837
2838
0
    DEBUGDUMPSECTION("send", "ScopedPdu");
2839
0
    rc = snmpv3_scopedPDU_header_realloc_rbuild(pkt, pkt_len, offset,
2840
0
                                                pdu, body_len);
2841
0
    if (rc == 0) {
2842
0
        return -1;
2843
0
    }
2844
0
    spdu_offset = *offset;
2845
0
    DEBUGINDENTADD(-4);         /*  Return from Scoped PDU.  */
2846
2847
0
    if ((hdrbuf = (u_char *) malloc(hdrbuf_len)) == NULL) {
2848
0
        return -1;
2849
0
    }
2850
2851
0
    rc = snmpv3_header_realloc_rbuild(&hdrbuf, &hdrbuf_len, &hdr_offset,
2852
0
                                      session, pdu);
2853
0
    if (rc == 0) {
2854
0
        SNMP_FREE(hdrbuf);
2855
0
        return -1;
2856
0
    }
2857
0
    hdr = hdrbuf + hdrbuf_len - hdr_offset;
2858
0
    scoped_pdu = *pkt + *pkt_len - spdu_offset;
2859
2860
    /*
2861
     * Call the security module to possibly encrypt and authenticate the
2862
     * message---the entire message to transmitted on the wire is returned.  
2863
     */
2864
2865
0
    sptr = find_sec_mod(pdu->securityModel);
2866
0
    DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
2867
0
    if (sptr && sptr->encode_reverse) {
2868
0
        struct snmp_secmod_outgoing_params parms;
2869
2870
0
        parms.msgProcModel = pdu->msgParseModel;
2871
0
        parms.globalData = hdr;
2872
0
        parms.globalDataLen = hdr_offset;
2873
0
        parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
2874
0
        parms.secModel = pdu->securityModel;
2875
0
        parms.secEngineID = pdu->securityEngineID;
2876
0
        parms.secEngineIDLen = pdu->securityEngineIDLen;
2877
0
        parms.secName = pdu->securityName;
2878
0
        parms.secNameLen = pdu->securityNameLen;
2879
0
        parms.secLevel = pdu->securityLevel;
2880
0
        parms.scopedPdu = scoped_pdu;
2881
0
        parms.scopedPduLen = spdu_offset;
2882
0
        parms.secStateRef = pdu->securityStateRef;
2883
0
        parms.wholeMsg = pkt;
2884
0
        parms.wholeMsgLen = pkt_len;
2885
0
        parms.wholeMsgOffset = offset;
2886
0
        parms.session = session;
2887
0
        parms.pdu = pdu;
2888
2889
0
        rc = (*sptr->encode_reverse) (&parms);
2890
0
    } else {
2891
0
        if (!sptr) {
2892
0
            snmp_log(LOG_ERR,
2893
0
                     "no such security service available: %d\n",
2894
0
                     pdu->securityModel);
2895
0
        } else if (!sptr->encode_reverse) {
2896
0
            snmp_log(LOG_ERR,
2897
0
                     "security service %d doesn't support reverse encoding.\n",
2898
0
                     pdu->securityModel);
2899
0
        }
2900
0
        rc = -1;
2901
0
    }
2902
2903
0
    DEBUGINDENTLESS();
2904
0
    SNMP_FREE(hdrbuf);
2905
0
    return rc;
2906
0
}                               /* end snmpv3_packet_realloc_rbuild() */
2907
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2908
2909
/*
2910
 * returns 0 if success, -1 if fail, not 0 if SM build failure 
2911
 */
2912
int
2913
snmpv3_packet_build(netsnmp_session * session, netsnmp_pdu *pdu,
2914
                    u_char * packet, size_t * out_length,
2915
                    u_char * pdu_data, size_t pdu_data_len)
2916
0
{
2917
0
    u_char         *global_data, *sec_params, *spdu_hdr_e;
2918
0
    size_t          global_data_len, sec_params_len;
2919
0
    u_char          spdu_buf[SNMP_MAX_MSG_SIZE];
2920
0
    size_t          spdu_buf_len, spdu_len;
2921
0
    u_char         *cp;
2922
0
    int             result;
2923
0
    struct snmp_secmod_def *sptr;
2924
2925
0
    global_data = packet;
2926
2927
    /*
2928
     * build the headers for the packet, returned addr = start of secParams
2929
     */
2930
0
    sec_params = snmpv3_header_build(session, pdu, global_data,
2931
0
                                     out_length, 0, NULL);
2932
0
    if (sec_params == NULL)
2933
0
        return -1;
2934
0
    global_data_len = sec_params - global_data;
2935
0
    sec_params_len = *out_length;       /* length left in packet buf for sec_params */
2936
2937
2938
    /*
2939
     * build a scopedPDU structure into spdu_buf
2940
     */
2941
0
    spdu_buf_len = sizeof(spdu_buf);
2942
0
    DEBUGDUMPSECTION("send", "ScopedPdu");
2943
0
    cp = snmpv3_scopedPDU_header_build(pdu, spdu_buf, &spdu_buf_len,
2944
0
                                       &spdu_hdr_e);
2945
0
    if (cp == NULL)
2946
0
        return -1;
2947
2948
    /*
2949
     * build the PDU structure onto the end of spdu_buf 
2950
     */
2951
0
    DEBUGPRINTPDUTYPE("send", ((pdu_data) ? *pdu_data : 0x00));
2952
0
    if (pdu_data) {
2953
0
        if (cp + pdu_data_len > spdu_buf + sizeof(spdu_buf)) {
2954
0
            snmp_log(LOG_ERR, "%s: PDU too big (%" NETSNMP_PRIz "d > %" NETSNMP_PRIz "d)\n",
2955
0
                     NETSNMP_FUNCTION, pdu_data_len, sizeof(spdu_buf));
2956
0
            return -1;
2957
0
        }
2958
0
        memcpy(cp, pdu_data, pdu_data_len);
2959
0
        cp += pdu_data_len;
2960
0
    } else {
2961
0
        cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
2962
0
        if (cp == NULL)
2963
0
            return -1;
2964
0
    }
2965
0
    DEBUGINDENTADD(-4);         /* return from Scoped PDU */
2966
2967
    /*
2968
     * re-encode the actual ASN.1 length of the scopedPdu
2969
     */
2970
0
    spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
2971
0
    spdu_buf_len = sizeof(spdu_buf);
2972
0
    if (asn_build_sequence(spdu_buf, &spdu_buf_len,
2973
0
                           (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2974
0
                           spdu_len) == NULL)
2975
0
        return -1;
2976
0
    spdu_len = cp - spdu_buf;   /* the length of the entire scopedPdu */
2977
2978
2979
    /*
2980
     * call the security module to possibly encrypt and authenticate the
2981
     * message - the entire message to transmitted on the wire is returned
2982
     */
2983
0
    cp = NULL;
2984
0
    *out_length = sizeof(spdu_buf);
2985
0
    DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
2986
0
    sptr = find_sec_mod(pdu->securityModel);
2987
0
    if (sptr && sptr->encode_forward) {
2988
0
        struct snmp_secmod_outgoing_params parms;
2989
0
        parms.msgProcModel = pdu->msgParseModel;
2990
0
        parms.globalData = global_data;
2991
0
        parms.globalDataLen = global_data_len;
2992
0
        parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
2993
0
        parms.secModel = pdu->securityModel;
2994
0
        parms.secEngineID = pdu->securityEngineID;
2995
0
        parms.secEngineIDLen = pdu->securityEngineIDLen;
2996
0
        parms.secName = pdu->securityName;
2997
0
        parms.secNameLen = pdu->securityNameLen;
2998
0
        parms.secLevel = pdu->securityLevel;
2999
0
        parms.scopedPdu = spdu_buf;
3000
0
        parms.scopedPduLen = spdu_len;
3001
0
        parms.secStateRef = pdu->securityStateRef;
3002
0
        parms.secParams = sec_params;
3003
0
        parms.secParamsLen = &sec_params_len;
3004
0
        parms.wholeMsg = &cp;
3005
0
        parms.wholeMsgLen = out_length;
3006
0
        parms.session = session;
3007
0
        parms.pdu = pdu;
3008
0
        result = (*sptr->encode_forward) (&parms);
3009
0
    } else {
3010
0
        if (!sptr) {
3011
0
            snmp_log(LOG_ERR, "no such security service available: %d\n",
3012
0
                     pdu->securityModel);
3013
0
        } else if (!sptr->encode_forward) {
3014
0
            snmp_log(LOG_ERR,
3015
0
                     "security service %d doesn't support forward out encoding.\n",
3016
0
                     pdu->securityModel);
3017
0
        }
3018
0
        result = -1;
3019
0
    }
3020
0
    DEBUGINDENTLESS();
3021
0
    return result;
3022
3023
0
}                               /* end snmpv3_packet_build() */
3024
3025
3026
/*
3027
 * Takes a session and a pdu and serializes the ASN PDU into the area
3028
 * pointed to by *pkt.  *pkt_len is the size of the data area available.
3029
 * Returns the length of the completed packet in *offset.  If any errors
3030
 * occur, -1 is returned.  If all goes well, 0 is returned.
3031
 */
3032
3033
static int
3034
_snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
3035
            netsnmp_session * session, netsnmp_pdu *pdu)
3036
0
{
3037
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3038
0
    u_char         *h0e = NULL;
3039
0
    size_t          start_offset = *offset;
3040
0
    long            version;
3041
0
    int             rc = 0;
3042
0
    size_t          length;
3043
0
#endif /* support for community based SNMP */
3044
3045
0
    u_char         *cp;
3046
3047
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(pdu->version)) {
3048
0
        DEBUGMSGTL(("snmp_send", "build packet (version 0x%02x disabled)\n",
3049
0
                    (u_int)pdu->version));
3050
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
3051
0
        return -1;
3052
0
    }
3053
3054
0
    session->s_snmp_errno = 0;
3055
0
    session->s_errno = 0;
3056
3057
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3058
0
    if ((pdu->flags & UCD_MSG_FLAG_BULK_TOOBIG) ||
3059
0
        (0 == netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
3060
0
                                     NETSNMP_DS_LIB_REVERSE_ENCODE))) {
3061
0
        pdu->flags |= UCD_MSG_FLAG_FORWARD_ENCODE;
3062
0
    }
3063
0
#endif /* NETSNMP_USE_REVERSE_ASNENCODING */
3064
3065
0
    if (pdu->version == SNMP_VERSION_3) {
3066
0
        return snmpv3_build(pkt, pkt_len, offset, session, pdu);
3067
0
    }
3068
3069
0
    switch (pdu->command) {
3070
0
    case SNMP_MSG_RESPONSE:
3071
0
        netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
3072
0
#ifndef NETSNMP_NOTIFY_ONLY
3073
0
        NETSNMP_FALLTHROUGH;
3074
0
    case SNMP_MSG_GET:
3075
0
    case SNMP_MSG_GETNEXT:
3076
0
        NETSNMP_FALLTHROUGH;
3077
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
3078
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
3079
0
    case SNMP_MSG_SET:
3080
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
3081
        /*
3082
         * all versions support these PDU types 
3083
         */
3084
        /*
3085
         * initialize defaulted PDU fields 
3086
         */
3087
3088
0
        if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
3089
0
            pdu->errstat = 0;
3090
0
        if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
3091
0
            pdu->errindex = 0;
3092
0
        break;
3093
3094
0
    case SNMP_MSG_TRAP2:
3095
0
        netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
3096
0
        NETSNMP_FALLTHROUGH;
3097
0
    case SNMP_MSG_INFORM:
3098
0
#ifndef NETSNMP_DISABLE_SNMPV1
3099
        /*
3100
         * not supported in SNMPv1 and SNMPsec 
3101
         */
3102
0
        if (pdu->version == SNMP_VERSION_1) {
3103
0
            session->s_snmp_errno = SNMPERR_V2_IN_V1;
3104
0
            return -1;
3105
0
        }
3106
0
#endif
3107
0
        if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
3108
0
            pdu->errstat = 0;
3109
0
        if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
3110
0
            pdu->errindex = 0;
3111
0
        break;
3112
3113
0
#ifndef NETSNMP_NOTIFY_ONLY
3114
0
    case SNMP_MSG_GETBULK:
3115
        /*
3116
         * not supported in SNMPv1 and SNMPsec 
3117
         */
3118
0
#ifndef NETSNMP_DISABLE_SNMPV1
3119
0
        if (pdu->version == SNMP_VERSION_1) {
3120
0
            session->s_snmp_errno = SNMPERR_V2_IN_V1;
3121
0
            return -1;
3122
0
        }
3123
0
#endif
3124
0
        if (pdu->max_repetitions < 0) {
3125
0
            session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
3126
0
            return -1;
3127
0
        }
3128
0
        if (pdu->non_repeaters < 0) {
3129
0
            session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
3130
0
            return -1;
3131
0
        }
3132
0
        break;
3133
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
3134
3135
0
    case SNMP_MSG_TRAP:
3136
        /*
3137
         * *only* supported in SNMPv1 and SNMPsec 
3138
         */
3139
0
#ifndef NETSNMP_DISABLE_SNMPV1
3140
0
        if (pdu->version != SNMP_VERSION_1) {
3141
0
            session->s_snmp_errno = SNMPERR_V1_IN_V2;
3142
0
            return -1;
3143
0
        }
3144
0
#endif
3145
        /*
3146
         * initialize defaulted Trap PDU fields 
3147
         */
3148
0
        pdu->reqid = 1;         /* give a bogus non-error reqid for traps */
3149
0
        if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
3150
0
            pdu->enterprise = netsnmp_memdup(DEFAULT_ENTERPRISE,
3151
0
                                             sizeof(DEFAULT_ENTERPRISE));
3152
0
            if (pdu->enterprise == NULL) {
3153
0
                session->s_snmp_errno = SNMPERR_MALLOC;
3154
0
                return -1;
3155
0
            }
3156
0
            pdu->enterprise_length =
3157
0
                OID_LENGTH(DEFAULT_ENTERPRISE);
3158
0
        }
3159
0
        if (pdu->time == SNMP_DEFAULT_TIME)
3160
0
            pdu->time = DEFAULT_TIME;
3161
        /*
3162
         * don't expect a response 
3163
         */
3164
0
        pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
3165
0
        break;
3166
3167
0
    case SNMP_MSG_REPORT:      /* SNMPv3 only */
3168
0
    default:
3169
0
        session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
3170
0
        return -1;
3171
0
    }
3172
3173
    /*
3174
     * save length 
3175
     */
3176
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3177
0
    length = *pkt_len;
3178
0
#endif
3179
3180
    /*
3181
     * setup administrative fields based on version 
3182
     */
3183
    /*
3184
     * build the message wrapper and all the administrative fields
3185
     * upto the PDU sequence
3186
     * (note that actual length of message will be inserted later) 
3187
     */
3188
0
    switch (pdu->version) {
3189
0
#ifndef NETSNMP_DISABLE_SNMPV1
3190
0
    case SNMP_VERSION_1:
3191
0
#endif
3192
0
#ifndef NETSNMP_DISABLE_SNMPV2C
3193
0
    case SNMP_VERSION_2c:
3194
0
#endif
3195
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3196
#ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
3197
        if (pdu->community_len == 0) {
3198
            if (session->community_len == 0) {
3199
                session->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
3200
                return -1;
3201
            }
3202
            pdu->community = netsnmp_memdup(session->community,
3203
                                            session->community_len);
3204
            if (pdu->community == NULL) {
3205
                session->s_snmp_errno = SNMPERR_MALLOC;
3206
                return -1;
3207
            }
3208
            pdu->community_len = session->community_len;
3209
        }
3210
#else                           /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
3211
0
        if (pdu->community_len == 0 && pdu->command != SNMP_MSG_RESPONSE) {
3212
            /*
3213
             * copy session community exactly to pdu community 
3214
             */
3215
0
            if (0 == session->community_len) {
3216
0
                SNMP_FREE(pdu->community);
3217
0
            } else if (pdu->community_len == session->community_len) {
3218
0
                memmove(pdu->community,
3219
0
                        session->community, session->community_len);
3220
0
            } else {
3221
0
                SNMP_FREE(pdu->community);
3222
0
                pdu->community = netsnmp_memdup(session->community,
3223
0
                                                session->community_len);
3224
0
                if (pdu->community == NULL) {
3225
0
                    session->s_snmp_errno = SNMPERR_MALLOC;
3226
0
                    return -1;
3227
0
                }
3228
0
            }
3229
0
            pdu->community_len = session->community_len;
3230
0
        }
3231
0
#endif                          /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
3232
3233
0
        DEBUGMSGTL(("snmp_send", "Building SNMPv%ld message...\n",
3234
0
                    (1 + pdu->version)));
3235
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3236
0
        if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
3237
0
            DEBUGPRINTPDUTYPE("send", pdu->command);
3238
0
            rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
3239
0
            if (rc == 0) {
3240
0
                return -1;
3241
0
            }
3242
3243
0
            DEBUGDUMPHEADER("send", "Community String");
3244
0
            rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
3245
0
                                           (u_char) (ASN_UNIVERSAL |
3246
0
                                                     ASN_PRIMITIVE |
3247
0
                                                     ASN_OCTET_STR),
3248
0
                                           pdu->community,
3249
0
                                           pdu->community_len);
3250
0
            DEBUGINDENTLESS();
3251
0
            if (rc == 0) {
3252
0
                return -1;
3253
0
            }
3254
3255
3256
            /*
3257
             * Store the version field.  
3258
             */
3259
0
            DEBUGDUMPHEADER("send", "SNMP Version Number");
3260
3261
0
            version = pdu->version;
3262
0
            rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3263
0
                                        (u_char) (ASN_UNIVERSAL |
3264
0
                                                  ASN_PRIMITIVE |
3265
0
                                                  ASN_INTEGER),
3266
0
                                        (long *) &version,
3267
0
                                        sizeof(version));
3268
0
            DEBUGINDENTLESS();
3269
0
            if (rc == 0) {
3270
0
                return -1;
3271
0
            }
3272
3273
            /*
3274
             * Build the final sequence.  
3275
             */
3276
0
#ifndef NETSNMP_DISABLE_SNMPV1
3277
0
            if (pdu->version == SNMP_VERSION_1) {
3278
0
                DEBUGDUMPSECTION("send", "SNMPv1 Message");
3279
0
            } else {
3280
0
#endif
3281
0
                DEBUGDUMPSECTION("send", "SNMPv2c Message");
3282
0
#ifndef NETSNMP_DISABLE_SNMPV1
3283
0
            }
3284
0
#endif
3285
0
            rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3286
0
                                             (u_char) (ASN_SEQUENCE |
3287
0
                                                       ASN_CONSTRUCTOR),
3288
0
                                             *offset - start_offset);
3289
0
            DEBUGINDENTLESS();
3290
3291
0
            if (rc == 0) {
3292
0
                return -1;
3293
0
            }
3294
0
            return 0;
3295
0
        } else {
3296
3297
0
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3298
            /*
3299
             * Save current location and build SEQUENCE tag and length
3300
             * placeholder for SNMP message sequence
3301
             * (actual length will be inserted later) 
3302
             */
3303
0
            cp = asn_build_sequence(*pkt, pkt_len,
3304
0
                                    (u_char) (ASN_SEQUENCE |
3305
0
                                              ASN_CONSTRUCTOR), 0);
3306
0
            if (cp == NULL) {
3307
0
                return -1;
3308
0
            }
3309
0
            h0e = cp;
3310
3311
0
#ifndef NETSNMP_DISABLE_SNMPV1
3312
0
            if (pdu->version == SNMP_VERSION_1) {
3313
0
                DEBUGDUMPSECTION("send", "SNMPv1 Message");
3314
0
            } else {
3315
0
#endif
3316
0
                DEBUGDUMPSECTION("send", "SNMPv2c Message");
3317
0
#ifndef NETSNMP_DISABLE_SNMPV1
3318
0
            }
3319
0
#endif
3320
3321
            /*
3322
             * store the version field 
3323
             */
3324
0
            DEBUGDUMPHEADER("send", "SNMP Version Number");
3325
3326
0
            version = pdu->version;
3327
0
            cp = asn_build_int(cp, pkt_len,
3328
0
                               (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3329
0
                                         ASN_INTEGER), (long *) &version,
3330
0
                               sizeof(version));
3331
0
            DEBUGINDENTLESS();
3332
0
            if (cp == NULL)
3333
0
                return -1;
3334
3335
            /*
3336
             * store the community string 
3337
             */
3338
0
            DEBUGDUMPHEADER("send", "Community String");
3339
0
            cp = asn_build_string(cp, pkt_len,
3340
0
                                  (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3341
0
                                            ASN_OCTET_STR), pdu->community,
3342
0
                                  pdu->community_len);
3343
0
            DEBUGINDENTLESS();
3344
0
            if (cp == NULL)
3345
0
                return -1;
3346
0
            break;
3347
3348
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3349
0
        }
3350
0
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3351
0
        break;
3352
0
#endif /* support for community based SNMP */
3353
0
    case SNMP_VERSION_2p:
3354
0
    case SNMP_VERSION_sec:
3355
0
    case SNMP_VERSION_2u:
3356
0
    case SNMP_VERSION_2star:
3357
0
    default:
3358
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
3359
0
        return -1;
3360
0
    }
3361
3362
0
    DEBUGPRINTPDUTYPE("send", pdu->command);
3363
0
    cp = snmp_pdu_build(pdu, cp, pkt_len);
3364
0
    DEBUGINDENTADD(-4);         /* return from entire v1/v2c message */
3365
0
    if (cp == NULL)
3366
0
        return -1;
3367
3368
    /*
3369
     * insert the actual length of the message sequence 
3370
     */
3371
0
    switch (pdu->version) {
3372
0
#ifndef NETSNMP_DISABLE_SNMPV1
3373
0
    case SNMP_VERSION_1:
3374
0
#endif
3375
0
#ifndef NETSNMP_DISABLE_SNMPV2C
3376
0
    case SNMP_VERSION_2c:
3377
0
#endif
3378
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3379
0
        asn_build_sequence(*pkt, &length,
3380
0
                           (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3381
0
                           cp - h0e);
3382
0
        break;
3383
0
#endif /* support for community based SNMP */
3384
3385
0
    case SNMP_VERSION_2p:
3386
0
    case SNMP_VERSION_sec:
3387
0
    case SNMP_VERSION_2u:
3388
0
    case SNMP_VERSION_2star:
3389
0
    default:
3390
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
3391
0
        return -1;
3392
0
    }
3393
0
    *pkt_len = cp - *pkt;
3394
0
    return 0;
3395
0
}
3396
3397
/**
3398
 * Serialize a PDU into ASN format.
3399
 * @param pkt     [out] Serialized PDU.
3400
 * @param pkt_len [out] Size of pkt.
3401
 * @param offset  [out] Number of bytes written into *pkt.
3402
 * @param pss     [in]  Session pointer.
3403
 * @param pdu     [in]  PDU to serialize.
3404
 *
3405
 * @returns 0 upon success; -1 upon failure.
3406
 */
3407
int
3408
snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
3409
           netsnmp_session * pss, netsnmp_pdu *pdu)
3410
0
{
3411
0
    int             rc;
3412
3413
0
    rc = _snmp_build(pkt, pkt_len, offset, pss, pdu);
3414
0
    if (rc) {
3415
0
        if (!pss->s_snmp_errno) {
3416
0
            snmp_log(LOG_ERR, "snmp_build: unknown failure\n");
3417
0
            pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
3418
0
        }
3419
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
3420
0
        rc = -1;
3421
0
    }
3422
0
    return rc;
3423
0
}
3424
3425
/*
3426
 * on error, returns NULL (likely an encoding problem). 
3427
 */
3428
u_char         *
3429
snmp_pdu_build(const netsnmp_pdu *pdu, u_char * cp, size_t * out_length)
3430
0
{
3431
0
    u_char         *h1, *h1e, *h2, *h2e, *save_ptr;
3432
0
    netsnmp_variable_list *vp, *save_vp = NULL;
3433
0
    size_t          length, save_length;
3434
3435
0
    length = *out_length;
3436
    /*
3437
     * Save current location and build PDU tag and length placeholder
3438
     * (actual length will be inserted later) 
3439
     */
3440
0
    h1 = cp;
3441
0
    cp = asn_build_sequence(cp, out_length, (u_char) pdu->command, 0);
3442
0
    if (cp == NULL)
3443
0
        return NULL;
3444
0
    h1e = cp;
3445
3446
    /*
3447
     * store fields in the PDU preceding the variable-bindings sequence
3448
     */
3449
0
    if (pdu->command != SNMP_MSG_TRAP) {
3450
        /*
3451
         * PDU is not an SNMPv1 trap 
3452
         */
3453
3454
0
        DEBUGDUMPHEADER("send", "request_id");
3455
        /*
3456
         * request id 
3457
         */
3458
0
        cp = asn_build_int(cp, out_length,
3459
0
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3460
0
                                     ASN_INTEGER), &pdu->reqid,
3461
0
                           sizeof(pdu->reqid));
3462
0
        DEBUGINDENTLESS();
3463
0
        if (cp == NULL)
3464
0
            return NULL;
3465
3466
        /*
3467
         * error status (getbulk non-repeaters) 
3468
         */
3469
0
        DEBUGDUMPHEADER("send", "error status");
3470
0
        cp = asn_build_int(cp, out_length,
3471
0
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3472
0
                                     ASN_INTEGER), &pdu->errstat,
3473
0
                           sizeof(pdu->errstat));
3474
0
        DEBUGINDENTLESS();
3475
0
        if (cp == NULL)
3476
0
            return NULL;
3477
3478
        /*
3479
         * error index (getbulk max-repetitions) 
3480
         */
3481
0
        DEBUGDUMPHEADER("send", "error index");
3482
0
        cp = asn_build_int(cp, out_length,
3483
0
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3484
0
                                     ASN_INTEGER), &pdu->errindex,
3485
0
                           sizeof(pdu->errindex));
3486
0
        DEBUGINDENTLESS();
3487
0
        if (cp == NULL)
3488
0
            return NULL;
3489
0
    } else {
3490
        /*
3491
         * an SNMPv1 trap PDU 
3492
         */
3493
3494
        /*
3495
         * enterprise 
3496
         */
3497
0
        DEBUGDUMPHEADER("send", "enterprise OBJID");
3498
0
        cp = asn_build_objid(cp, out_length,
3499
0
                             (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3500
0
                                       ASN_OBJECT_ID),
3501
0
                             pdu->enterprise, pdu->enterprise_length);
3502
0
        DEBUGINDENTLESS();
3503
0
        if (cp == NULL)
3504
0
            return NULL;
3505
3506
        /*
3507
         * agent-addr 
3508
         */
3509
0
        DEBUGDUMPHEADER("send", "agent Address");
3510
0
        cp = asn_build_string(cp, out_length,
3511
0
                              (u_char) (ASN_IPADDRESS | ASN_PRIMITIVE),
3512
0
                              (const u_char *) pdu->agent_addr, 4);
3513
0
        DEBUGINDENTLESS();
3514
0
        if (cp == NULL)
3515
0
            return NULL;
3516
3517
        /*
3518
         * generic trap 
3519
         */
3520
0
        DEBUGDUMPHEADER("send", "generic trap number");
3521
0
        cp = asn_build_int(cp, out_length,
3522
0
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3523
0
                                     ASN_INTEGER),
3524
0
                           (const long *) &pdu->trap_type,
3525
0
                           sizeof(pdu->trap_type));
3526
0
        DEBUGINDENTLESS();
3527
0
        if (cp == NULL)
3528
0
            return NULL;
3529
3530
        /*
3531
         * specific trap 
3532
         */
3533
0
        DEBUGDUMPHEADER("send", "specific trap number");
3534
0
        cp = asn_build_int(cp, out_length,
3535
0
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3536
0
                                     ASN_INTEGER),
3537
0
                           (const long *) &pdu->specific_type,
3538
0
                           sizeof(pdu->specific_type));
3539
0
        DEBUGINDENTLESS();
3540
0
        if (cp == NULL)
3541
0
            return NULL;
3542
3543
        /*
3544
         * timestamp  
3545
         */
3546
0
        DEBUGDUMPHEADER("send", "timestamp");
3547
0
        cp = asn_build_unsigned_int(cp, out_length,
3548
0
                                    (u_char) (ASN_TIMETICKS |
3549
0
                                              ASN_PRIMITIVE), &pdu->time,
3550
0
                                    sizeof(pdu->time));
3551
0
        DEBUGINDENTLESS();
3552
0
        if (cp == NULL)
3553
0
            return NULL;
3554
0
    }
3555
3556
    /*
3557
     * Save current location and build SEQUENCE tag and length placeholder
3558
     * for variable-bindings sequence
3559
     * (actual length will be inserted later) 
3560
     */
3561
0
    h2 = cp;
3562
0
    cp = asn_build_sequence(cp, out_length,
3563
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
3564
0
    if (cp == NULL)
3565
0
        return NULL;
3566
0
    h2e = cp;
3567
3568
    /*
3569
     * Store variable-bindings 
3570
     */
3571
0
    DEBUGDUMPSECTION("send", "VarBindList");
3572
0
    for (vp = pdu->variables; vp; vp = vp->next_variable) {
3573
        /*
3574
         * if estimated getbulk response size exceeded packet max size,
3575
         * processing was stopped before bulk cache was filled and type
3576
         * was set to ASN_PRIV_STOP, indicating that the rest of the varbinds
3577
         * in the cache are empty and we can stop encoding them.
3578
         */
3579
0
        if (ASN_PRIV_STOP == vp->type)
3580
0
            break;
3581
3582
        /*
3583
         * save current ptr and length so that if we exceed the packet length
3584
         * encoding this varbind and this is a bulk response, we can drop
3585
         * the failed varbind (and any that follow it) and continue encoding
3586
         * the (shorter) bulk response.
3587
         */
3588
0
        save_ptr = cp;
3589
0
        save_length = *out_length;
3590
3591
0
        DEBUGDUMPSECTION("send", "VarBind");
3592
0
        cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
3593
0
                               vp->val_len, vp->val.string, out_length);
3594
0
        DEBUGINDENTLESS();
3595
0
        if (cp == NULL) {
3596
0
            if (save_vp && (pdu->flags & UCD_MSG_FLAG_BULK_TOOBIG)) {
3597
0
                DEBUGDUMPSECTION("send",
3598
0
                                 "VarBind would exceed packet size; dropped");
3599
0
                cp = save_ptr;
3600
0
                *out_length = save_length;
3601
0
                break;
3602
0
            } else
3603
0
                return NULL;
3604
0
        }
3605
0
        save_vp = vp;
3606
0
    }
3607
0
    DEBUGINDENTLESS();
3608
3609
    /** did we run out of room? (should only happen for bulk responses) */
3610
0
    if (vp && save_vp) {
3611
0
        save_vp->next_variable = NULL; /* truncate variable list */
3612
        /** count remaining varbinds in list, then free them */
3613
0
        save_vp = vp;
3614
0
        for(save_length = 0; save_vp; save_vp = save_vp->next_variable)
3615
0
            ++save_length;
3616
0
        DEBUGMSGTL(("send", "trimmed %" NETSNMP_PRIz "d variables\n", save_length));
3617
0
        snmp_free_varbind(vp);
3618
0
    }
3619
3620
    /*
3621
     * insert actual length of variable-bindings sequence 
3622
     */
3623
0
    asn_build_sequence(h2, &length,
3624
0
                       (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3625
0
                       cp - h2e);
3626
3627
    /*
3628
     * insert actual length of PDU sequence 
3629
     */
3630
0
    asn_build_sequence(h1, &length, (u_char) pdu->command, cp - h1e);
3631
3632
0
    return cp;
3633
0
}
3634
3635
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3636
/*
3637
 * On error, returns 0 (likely an encoding problem).  
3638
 */
3639
int
3640
snmp_pdu_realloc_rbuild(u_char ** pkt, size_t * pkt_len, size_t * offset,
3641
                        const netsnmp_pdu *pdu)
3642
0
{
3643
0
#ifndef VPCACHE_SIZE
3644
0
#define VPCACHE_SIZE 50
3645
0
#endif
3646
0
    netsnmp_variable_list *vpcache[VPCACHE_SIZE];
3647
0
    netsnmp_variable_list *vp, *tmpvp;
3648
0
    size_t          start_offset = *offset;
3649
0
    int             i, wrapped = 0, notdone, final, rc = 0;
3650
3651
0
    DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "starting\n"));
3652
0
    for (vp = pdu->variables, i = VPCACHE_SIZE - 1; vp;
3653
0
         vp = vp->next_variable, i--) {
3654
        /*
3655
         * if estimated getbulk response size exceeded packet max size,
3656
         * processing was stopped before bulk cache was filled and type
3657
         * was set to ASN_PRIV_STOP, indicating that the rest of the varbinds
3658
         * in the cache are empty and we can stop encoding them.
3659
         */
3660
0
        if (ASN_PRIV_STOP == vp->type)
3661
0
            break;
3662
0
        if (i < 0) {
3663
0
            wrapped = notdone = 1;
3664
0
            i = VPCACHE_SIZE - 1;
3665
0
            DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
3666
0
        }
3667
0
        vpcache[i] = vp;
3668
0
    }
3669
0
    final = i + 1;
3670
3671
0
    do {
3672
0
        for (i = final; i < VPCACHE_SIZE; i++) {
3673
0
            vp = vpcache[i];
3674
0
            DEBUGDUMPSECTION("send", "VarBind");
3675
0
            rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
3676
0
                                            vp->name, &vp->name_length,
3677
0
                                            vp->type,
3678
0
                                            (u_char *) vp->val.string,
3679
0
                                            vp->val_len);
3680
0
            DEBUGINDENTLESS();
3681
0
            if (rc == 0) {
3682
0
                return 0;
3683
0
            }
3684
0
        }
3685
3686
0
        DEBUGINDENTLESS();
3687
0
        if (wrapped) {
3688
0
            notdone = 1;
3689
0
            for (i = 0; i < final; i++) {
3690
0
                vp = vpcache[i];
3691
0
                DEBUGDUMPSECTION("send", "VarBind");
3692
0
                rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
3693
0
                                                vp->name, &vp->name_length,
3694
0
                                                vp->type,
3695
0
                                                (u_char *) vp->val.string,
3696
0
                                                vp->val_len);
3697
0
                DEBUGINDENTLESS();
3698
0
                if (rc == 0) {
3699
0
                    return 0;
3700
0
                }
3701
0
            }
3702
3703
0
            if (final == 0) {
3704
0
                tmpvp = vpcache[VPCACHE_SIZE - 1];
3705
0
            } else {
3706
0
                tmpvp = vpcache[final - 1];
3707
0
            }
3708
0
            wrapped = 0;
3709
3710
0
            for (vp = pdu->variables, i = VPCACHE_SIZE - 1;
3711
0
                 vp && vp != tmpvp; vp = vp->next_variable, i--) {
3712
0
                if (i < 0) {
3713
0
                    wrapped = 1;
3714
0
                    i = VPCACHE_SIZE - 1;
3715
0
                    DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
3716
0
                }
3717
0
                vpcache[i] = vp;
3718
0
            }
3719
0
            final = i + 1;
3720
0
        } else {
3721
0
            notdone = 0;
3722
0
        }
3723
0
    } while (notdone);
3724
3725
    /*
3726
     * Save current location and build SEQUENCE tag and length placeholder for
3727
     * variable-bindings sequence (actual length will be inserted later).  
3728
     */
3729
3730
0
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3731
0
                                     (u_char) (ASN_SEQUENCE |
3732
0
                                               ASN_CONSTRUCTOR),
3733
0
                                     *offset - start_offset);
3734
0
    if (rc == 0) {
3735
0
        return 0;
3736
0
    }
3737
3738
    /*
3739
     * Store fields in the PDU preceding the variable-bindings sequence.
3740
     */
3741
0
    if (pdu->command != SNMP_MSG_TRAP) {
3742
        /*
3743
         * Error index (getbulk max-repetitions).  
3744
         */
3745
0
        DEBUGDUMPHEADER("send", "error index");
3746
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3747
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3748
0
                                              | ASN_INTEGER),
3749
0
                                    &pdu->errindex, sizeof(pdu->errindex));
3750
0
        DEBUGINDENTLESS();
3751
0
        if (rc == 0) {
3752
0
            return 0;
3753
0
        }
3754
3755
        /*
3756
         * Error status (getbulk non-repeaters).  
3757
         */
3758
0
        DEBUGDUMPHEADER("send", "error status");
3759
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3760
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3761
0
                                              | ASN_INTEGER),
3762
0
                                    &pdu->errstat, sizeof(pdu->errstat));
3763
0
        DEBUGINDENTLESS();
3764
0
        if (rc == 0) {
3765
0
            return 0;
3766
0
        }
3767
3768
        /*
3769
         * Request ID.  
3770
         */
3771
0
        DEBUGDUMPHEADER("send", "request_id");
3772
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3773
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3774
0
                                              | ASN_INTEGER), &pdu->reqid,
3775
0
                                    sizeof(pdu->reqid));
3776
0
        DEBUGINDENTLESS();
3777
0
        if (rc == 0) {
3778
0
            return 0;
3779
0
        }
3780
0
    } else {
3781
        /*
3782
         * An SNMPv1 trap PDU.  
3783
         */
3784
3785
        /*
3786
         * Timestamp.  
3787
         */
3788
0
        DEBUGDUMPHEADER("send", "timestamp");
3789
0
        rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, 1,
3790
0
                                             (u_char) (ASN_TIMETICKS |
3791
0
                                                       ASN_PRIMITIVE),
3792
0
                                             &pdu->time,
3793
0
                                             sizeof(pdu->time));
3794
0
        DEBUGINDENTLESS();
3795
0
        if (rc == 0) {
3796
0
            return 0;
3797
0
        }
3798
3799
        /*
3800
         * Specific trap.  
3801
         */
3802
0
        DEBUGDUMPHEADER("send", "specific trap number");
3803
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3804
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3805
0
                                              | ASN_INTEGER),
3806
0
                                    (const long *) &pdu->specific_type,
3807
0
                                    sizeof(pdu->specific_type));
3808
0
        DEBUGINDENTLESS();
3809
0
        if (rc == 0) {
3810
0
            return 0;
3811
0
        }
3812
3813
        /*
3814
         * Generic trap.  
3815
         */
3816
0
        DEBUGDUMPHEADER("send", "generic trap number");
3817
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3818
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3819
0
                                              | ASN_INTEGER),
3820
0
                                    (const long *) &pdu->trap_type,
3821
0
                                    sizeof(pdu->trap_type));
3822
0
        DEBUGINDENTLESS();
3823
0
        if (rc == 0) {
3824
0
            return 0;
3825
0
        }
3826
3827
        /*
3828
         * Agent-addr.  
3829
         */
3830
0
        DEBUGDUMPHEADER("send", "agent Address");
3831
0
        rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
3832
0
                                       (u_char) (ASN_IPADDRESS |
3833
0
                                                 ASN_PRIMITIVE),
3834
0
                                       (const u_char *) pdu->agent_addr, 4);
3835
0
        DEBUGINDENTLESS();
3836
0
        if (rc == 0) {
3837
0
            return 0;
3838
0
        }
3839
3840
        /*
3841
         * Enterprise.  
3842
         */
3843
0
        DEBUGDUMPHEADER("send", "enterprise OBJID");
3844
0
        rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, 1,
3845
0
                                      (u_char) (ASN_UNIVERSAL |
3846
0
                                                ASN_PRIMITIVE |
3847
0
                                                ASN_OBJECT_ID),
3848
0
                                      (oid *) pdu->enterprise,
3849
0
                                      pdu->enterprise_length);
3850
0
        DEBUGINDENTLESS();
3851
0
        if (rc == 0) {
3852
0
            return 0;
3853
0
        }
3854
0
    }
3855
3856
    /*
3857
     * Build the PDU sequence.  
3858
     */
3859
0
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3860
0
                                     (u_char) pdu->command,
3861
0
                                     *offset - start_offset);
3862
0
    return rc;
3863
0
}
3864
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3865
3866
/*
3867
 * Parses the packet received to determine version, either directly
3868
 * from packets version field or inferred from ASN.1 construct.
3869
 */
3870
static int
3871
snmp_parse_version(u_char * data, size_t length)
3872
0
{
3873
0
    u_char          type;
3874
0
    long            version = SNMPERR_BAD_VERSION;
3875
3876
0
    data = asn_parse_sequence(data, &length, &type,
3877
0
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
3878
0
    if (data) {
3879
0
        DEBUGDUMPHEADER("recv", "SNMP Version");
3880
0
        data =
3881
0
            asn_parse_int(data, &length, &type, &version, sizeof(version));
3882
0
        DEBUGINDENTLESS();
3883
0
        if (!data || type != ASN_INTEGER) {
3884
0
            return SNMPERR_BAD_VERSION;
3885
0
        }
3886
0
    }
3887
0
    return version;
3888
0
}
3889
3890
3891
int
3892
snmpv3_parse(netsnmp_pdu *pdu,
3893
             u_char * data,
3894
             size_t * length,
3895
             u_char ** after_header, netsnmp_session * sess)
3896
0
{
3897
0
    u_char          type, msg_flags;
3898
0
    long            ver, msg_sec_model;
3899
0
    size_t          max_size_response;
3900
0
    u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
3901
0
    size_t          tmp_buf_len;
3902
0
    u_char          pdu_buf[SNMP_MAX_MSG_SIZE];
3903
0
    u_char         *mallocbuf = NULL;
3904
0
    size_t          pdu_buf_len = SNMP_MAX_MSG_SIZE;
3905
0
    u_char         *sec_params;
3906
0
    u_char         *msg_data;
3907
0
    u_char         *cp;
3908
0
    size_t          asn_len, msg_len;
3909
0
    int             ret, ret_val;
3910
0
    struct snmp_secmod_def *sptr;
3911
3912
3913
0
    msg_data = data;
3914
0
    msg_len = *length;
3915
3916
3917
    /*
3918
     * message is an ASN.1 SEQUENCE  
3919
     */
3920
0
    DEBUGDUMPSECTION("recv", "SNMPv3 Message");
3921
0
    data = asn_parse_sequence(data, length, &type,
3922
0
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
3923
0
    if (data == NULL) {
3924
        /*
3925
         * error msg detail is set 
3926
         */
3927
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3928
0
        DEBUGINDENTLESS();
3929
0
        return SNMPERR_ASN_PARSE_ERR;
3930
0
    }
3931
3932
    /*
3933
     * parse msgVersion  
3934
     */
3935
0
    DEBUGDUMPHEADER("recv", "SNMP Version Number");
3936
0
    data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
3937
0
    DEBUGINDENTLESS();
3938
0
    if (data == NULL) {
3939
0
        ERROR_MSG("bad parse of version");
3940
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3941
0
        DEBUGINDENTLESS();
3942
0
        return SNMPERR_ASN_PARSE_ERR;
3943
0
    }
3944
0
    pdu->version = ver;
3945
3946
    /*
3947
     * parse msgGlobalData sequence  
3948
     */
3949
0
    cp = data;
3950
0
    asn_len = *length;
3951
0
    DEBUGDUMPSECTION("recv", "msgGlobalData");
3952
0
    data = asn_parse_sequence(data, &asn_len, &type,
3953
0
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3954
0
                              "msgGlobalData");
3955
0
    if (data == NULL) {
3956
        /*
3957
         * error msg detail is set 
3958
         */
3959
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3960
0
        DEBUGINDENTADD(-4);
3961
0
        return SNMPERR_ASN_PARSE_ERR;
3962
0
    }
3963
0
    *length -= data - cp;       /* subtract off the length of the header */
3964
3965
    /*
3966
     * msgID 
3967
     */
3968
0
    DEBUGDUMPHEADER("recv", "msgID");
3969
0
    data =
3970
0
        asn_parse_int(data, length, &type, &pdu->msgid,
3971
0
                      sizeof(pdu->msgid));
3972
0
    DEBUGINDENTLESS();
3973
0
    if (data == NULL || type != ASN_INTEGER) {
3974
0
        ERROR_MSG("error parsing msgID");
3975
0
        DEBUGINDENTADD(-4);
3976
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3977
0
        return SNMPERR_ASN_PARSE_ERR;
3978
0
    }
3979
3980
    /*
3981
     * Check the msgID we received is a legal value.  If not, then increment
3982
     * snmpInASNParseErrs and return the appropriate error (see RFC 2572,
3983
     * para. 7.2, section 2 -- note that a bad msgID means that the received
3984
     * message is NOT a serialization of an SNMPv3Message, since the msgID
3985
     * field is out of bounds).  
3986
     */
3987
3988
0
    if (pdu->msgid < 0 || pdu->msgid > SNMP_MAX_PACKET_LEN) {
3989
0
        snmp_log(LOG_ERR, "Received bad msgID (%ld %s %s).\n", pdu->msgid,
3990
0
                 (pdu->msgid < 0) ? "<" : ">",
3991
0
                 (pdu->msgid < 0) ? "0" : "2^31 - 1");
3992
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3993
0
        DEBUGINDENTADD(-4);
3994
0
        return SNMPERR_ASN_PARSE_ERR;
3995
0
    }
3996
3997
    /*
3998
     * msgMaxSize 
3999
     */
4000
0
    DEBUGDUMPHEADER("recv:msgMaxSize", "msgMaxSize");
4001
0
    data = asn_parse_int(data, length, &type, &pdu->msgMaxSize,
4002
0
                         sizeof(pdu->msgMaxSize));
4003
0
    DEBUGINDENTLESS();
4004
0
    if (data == NULL || type != ASN_INTEGER) {
4005
0
        ERROR_MSG("error parsing msgMaxSize");
4006
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4007
0
        DEBUGINDENTADD(-4);
4008
0
        return SNMPERR_ASN_PARSE_ERR;
4009
0
    }
4010
4011
    /*
4012
     * Check the msgMaxSize we received is a legal value.  If not, then
4013
     * increment snmpInASNParseErrs and return the appropriate error (see RFC
4014
     * 2572, para. 7.2, section 2 -- note that a bad msgMaxSize means that the
4015
     * received message is NOT a serialization of an SNMPv3Message, since the
4016
     * msgMaxSize field is out of bounds).
4017
     */
4018
4019
0
    if (pdu->msgMaxSize < SNMP_MIN_MAX_LEN) {
4020
0
        snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu < 484).\n",
4021
0
                 pdu->msgMaxSize);
4022
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4023
0
        DEBUGINDENTADD(-4);
4024
0
        return SNMPERR_ASN_PARSE_ERR;
4025
0
    } else if (pdu->msgMaxSize > SNMP_MAX_PACKET_LEN) {
4026
0
        snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu > 2^31 - 1).\n",
4027
0
                 pdu->msgMaxSize);
4028
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4029
0
        DEBUGINDENTADD(-4);
4030
0
        return SNMPERR_ASN_PARSE_ERR;
4031
0
    } else {
4032
0
        DEBUGMSGTL(("snmpv3_parse:msgMaxSize", "msgMaxSize %lu received\n",
4033
0
                    pdu->msgMaxSize));
4034
        /** don't increase max msg size if we've already got one */
4035
0
        if (sess->sndMsgMaxSize < pdu->msgMaxSize) {
4036
0
            DEBUGMSGTL(("snmpv3_parse:msgMaxSize",
4037
0
                        "msgMaxSize %" NETSNMP_PRIz "d greater than session max %ld; reducing\n",
4038
0
                        sess->sndMsgMaxSize, pdu->msgMaxSize));
4039
0
            pdu->msgMaxSize = sess->sndMsgMaxSize;
4040
0
        }
4041
0
    }
4042
4043
    /*
4044
     * msgFlags 
4045
     */
4046
0
    tmp_buf_len = SNMP_MAX_MSG_SIZE;
4047
0
    DEBUGDUMPHEADER("recv", "msgFlags");
4048
0
    data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
4049
0
    DEBUGINDENTLESS();
4050
0
    if (data == NULL || type != ASN_OCTET_STR || tmp_buf_len != 1) {
4051
0
        ERROR_MSG("error parsing msgFlags");
4052
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4053
0
        DEBUGINDENTADD(-4);
4054
0
        return SNMPERR_ASN_PARSE_ERR;
4055
0
    }
4056
0
    msg_flags = *tmp_buf;
4057
0
    if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
4058
0
        pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
4059
0
    else
4060
0
        pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
4061
4062
    /*
4063
     * msgSecurityModel 
4064
     */
4065
0
    DEBUGDUMPHEADER("recv", "msgSecurityModel");
4066
0
    data = asn_parse_int(data, length, &type, &msg_sec_model,
4067
0
                         sizeof(msg_sec_model));
4068
0
    DEBUGINDENTADD(-4);         /* return from global data indent */
4069
0
    if (data == NULL || type != ASN_INTEGER ||
4070
0
        msg_sec_model < 1 || msg_sec_model > 0x7fffffff) {
4071
0
        ERROR_MSG("error parsing msgSecurityModel");
4072
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4073
0
        DEBUGINDENTLESS();
4074
0
        return SNMPERR_ASN_PARSE_ERR;
4075
0
    }
4076
0
    sptr = find_sec_mod(msg_sec_model);
4077
0
    if (!sptr) {
4078
0
        snmp_log(LOG_WARNING, "unknown security model: %ld\n",
4079
0
                 msg_sec_model);
4080
0
        snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
4081
0
        DEBUGINDENTLESS();
4082
0
        return SNMPERR_UNKNOWN_SEC_MODEL;
4083
0
    }
4084
0
    pdu->securityModel = msg_sec_model;
4085
4086
0
    if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT &&
4087
0
        !(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
4088
0
        ERROR_MSG("invalid message, illegal msgFlags");
4089
0
        snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
4090
0
        DEBUGINDENTLESS();
4091
0
        return SNMPERR_INVALID_MSG;
4092
0
    }
4093
0
    pdu->securityLevel = ((msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
4094
0
                          ? ((msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
4095
0
                             ? SNMP_SEC_LEVEL_AUTHPRIV
4096
0
                             : SNMP_SEC_LEVEL_AUTHNOPRIV)
4097
0
                          : SNMP_SEC_LEVEL_NOAUTH);
4098
    /*
4099
     * end of msgGlobalData 
4100
     */
4101
4102
    /*
4103
     * securtityParameters OCTET STRING begins after msgGlobalData 
4104
     */
4105
0
    sec_params = data;
4106
0
    SNMP_FREE(pdu->contextEngineID);
4107
0
    pdu->contextEngineID = calloc(1, SNMP_MAX_ENG_SIZE);
4108
0
    pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
4109
4110
    /*
4111
     * Note: there is no length limit on the msgAuthoritativeEngineID field,
4112
     * although we would EXPECT it to be limited to 32 (the SnmpEngineID TC
4113
     * limit).  We'll use double that here to be on the safe side.  
4114
     */
4115
4116
0
    SNMP_FREE(pdu->securityEngineID);
4117
0
    pdu->securityEngineID = calloc(1, SNMP_MAX_ENG_SIZE * 2);
4118
0
    pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE * 2;
4119
0
    SNMP_FREE(pdu->securityName);
4120
0
    pdu->securityName = calloc(1, SNMP_MAX_SEC_NAME_SIZE);
4121
0
    pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
4122
4123
0
    if ((pdu->securityName == NULL) ||
4124
0
        (pdu->securityEngineID == NULL) ||
4125
0
        (pdu->contextEngineID == NULL)) {
4126
0
        return SNMPERR_MALLOC;
4127
0
    }
4128
4129
0
    if (pdu_buf_len < msg_len
4130
0
        && pdu->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
4131
        /*
4132
         * space needed is larger than we have in the default buffer 
4133
         */
4134
0
        mallocbuf = calloc(1, msg_len);
4135
0
        if (mallocbuf == NULL)
4136
0
            return SNMPERR_MALLOC;
4137
0
        pdu_buf_len = msg_len;
4138
0
        cp = mallocbuf;
4139
0
    } else {
4140
0
        memset(pdu_buf, 0, pdu_buf_len);
4141
0
        cp = pdu_buf;
4142
0
    }
4143
4144
0
    DEBUGDUMPSECTION("recv", "SM msgSecurityParameters");
4145
0
    if (sptr->decode) {
4146
0
        struct snmp_secmod_incoming_params parms;
4147
0
        parms.msgProcModel = pdu->msgParseModel;
4148
0
        parms.maxMsgSize = pdu->msgMaxSize;
4149
0
        parms.secParams = sec_params;
4150
0
        parms.secModel = msg_sec_model;
4151
0
        parms.secLevel = pdu->securityLevel;
4152
0
        parms.wholeMsg = msg_data;
4153
0
        parms.wholeMsgLen = msg_len;
4154
0
        parms.secEngineID = pdu->securityEngineID;
4155
0
        parms.secEngineIDLen = &pdu->securityEngineIDLen;
4156
0
        parms.secName = pdu->securityName;
4157
0
        parms.secNameLen = &pdu->securityNameLen;
4158
0
        parms.scopedPdu = &cp;
4159
0
        parms.scopedPduLen = &pdu_buf_len;
4160
0
        parms.maxSizeResponse = &max_size_response;
4161
0
        parms.secStateRef = &pdu->securityStateRef;
4162
0
        parms.sess = sess;
4163
0
        parms.pdu = pdu;
4164
0
        parms.msg_flags = msg_flags;
4165
0
        ret_val = (*sptr->decode) (&parms);
4166
0
    } else {
4167
0
        SNMP_FREE(mallocbuf);
4168
0
        DEBUGINDENTLESS();
4169
0
        snmp_log(LOG_WARNING, "security service %ld can't decode packets\n",
4170
0
                 msg_sec_model);
4171
0
        return (-1);
4172
0
    }
4173
4174
0
    if (ret_val != SNMPERR_SUCCESS) {
4175
0
        DEBUGDUMPSECTION("recv", "ScopedPDU");
4176
        /*
4177
         * Parse as much as possible -- though I don't see the point? [jbpn].  
4178
         */
4179
0
        if (cp) {
4180
0
            cp = snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len);
4181
0
        }
4182
0
        if (cp) {
4183
0
            DEBUGPRINTPDUTYPE("recv", *cp);
4184
0
            snmp_pdu_parse(pdu, cp, &pdu_buf_len);
4185
0
            DEBUGINDENTADD(-8);
4186
0
        } else {
4187
0
            DEBUGINDENTADD(-4);
4188
0
        }
4189
4190
0
        SNMP_FREE(mallocbuf);
4191
0
        return ret_val;
4192
0
    }
4193
4194
    /*
4195
     * parse plaintext ScopedPDU sequence 
4196
     */
4197
0
    *length = pdu_buf_len;
4198
0
    DEBUGDUMPSECTION("recv", "ScopedPDU");
4199
0
    data = snmpv3_scopedPDU_parse(pdu, cp, length);
4200
0
    if (data == NULL) {
4201
0
        snmp_log(LOG_WARNING, "security service %ld error parsing ScopedPDU\n",
4202
0
                 msg_sec_model);
4203
0
        ERROR_MSG("error parsing PDU");
4204
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4205
0
        DEBUGINDENTADD(-4);
4206
0
        SNMP_FREE(mallocbuf);
4207
0
        return SNMPERR_ASN_PARSE_ERR;
4208
0
    }
4209
4210
    /*
4211
     * parse the PDU.  
4212
     */
4213
0
    if (after_header != NULL) {
4214
0
        *after_header = data;
4215
0
        tmp_buf_len = *length;
4216
0
    }
4217
4218
0
    DEBUGPRINTPDUTYPE("recv", *data);
4219
0
    ret = snmp_pdu_parse(pdu, data, length);
4220
0
    DEBUGINDENTADD(-8);
4221
4222
0
    if (after_header != NULL) {
4223
0
        *length = tmp_buf_len;
4224
0
    }
4225
4226
0
    if (ret != SNMPERR_SUCCESS) {
4227
0
        snmp_log(LOG_WARNING, "security service %ld error parsing ScopedPDU\n",
4228
0
                 msg_sec_model);
4229
0
        ERROR_MSG("error parsing PDU");
4230
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4231
0
        SNMP_FREE(mallocbuf);
4232
0
        return SNMPERR_ASN_PARSE_ERR;
4233
0
    }
4234
4235
0
    SNMP_FREE(mallocbuf);
4236
0
    return SNMPERR_SUCCESS;
4237
0
}                               /* end snmpv3_parse() */
4238
4239
static void
4240
free_securityStateRef(netsnmp_pdu* pdu)
4241
0
{
4242
0
    struct snmp_secmod_def *sptr;
4243
4244
0
    if (!pdu->securityStateRef)
4245
0
        return;
4246
4247
0
    sptr = find_sec_mod(pdu->securityModel);
4248
0
    if (sptr) {
4249
0
        if (sptr->pdu_free_state_ref) {
4250
0
            (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
4251
0
        } else {
4252
0
            snmp_log(LOG_ERR,
4253
0
                     "Security Model %d can't free state references\n",
4254
0
                     pdu->securityModel);
4255
0
  }
4256
0
    } else {
4257
0
  snmp_log(LOG_ERR,
4258
0
     "Can't find security model to free ptr: %d\n",
4259
0
     pdu->securityModel);
4260
0
    }
4261
0
    pdu->securityStateRef = NULL;
4262
0
}
4263
4264
0
#define ERROR_STAT_LENGTH 11
4265
4266
int
4267
snmpv3_make_report(netsnmp_pdu *pdu, int error)
4268
0
{
4269
4270
0
    long            ltmp;
4271
0
    static const oid unknownSecurityLevel[] =
4272
0
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
4273
0
    static const oid notInTimeWindow[] =
4274
0
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
4275
0
    static const oid unknownUserName[] =
4276
0
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
4277
0
    static const oid unknownEngineID[] =
4278
0
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
4279
0
    static const oid wrongDigest[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
4280
0
    static const oid decryptionError[] =
4281
0
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
4282
0
    const oid      *err_var;
4283
0
    int             err_var_len;
4284
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4285
0
    int             stat_ind;
4286
0
#endif
4287
4288
0
    switch (error) {
4289
0
    case SNMPERR_USM_UNKNOWNENGINEID:
4290
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4291
0
        stat_ind = STAT_USMSTATSUNKNOWNENGINEIDS;
4292
0
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4293
0
        err_var = unknownEngineID;
4294
0
        err_var_len = ERROR_STAT_LENGTH;
4295
0
        break;
4296
0
    case SNMPERR_USM_UNKNOWNSECURITYNAME:
4297
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4298
0
        stat_ind = STAT_USMSTATSUNKNOWNUSERNAMES;
4299
0
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4300
0
        err_var = unknownUserName;
4301
0
        err_var_len = ERROR_STAT_LENGTH;
4302
0
        break;
4303
0
    case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
4304
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4305
0
        stat_ind = STAT_USMSTATSUNSUPPORTEDSECLEVELS;
4306
0
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4307
0
        err_var = unknownSecurityLevel;
4308
0
        err_var_len = ERROR_STAT_LENGTH;
4309
0
        break;
4310
0
    case SNMPERR_USM_AUTHENTICATIONFAILURE:
4311
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4312
0
        stat_ind = STAT_USMSTATSWRONGDIGESTS;
4313
0
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4314
0
        err_var = wrongDigest;
4315
0
        err_var_len = ERROR_STAT_LENGTH;
4316
0
        break;
4317
0
    case SNMPERR_USM_NOTINTIMEWINDOW:
4318
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4319
0
        stat_ind = STAT_USMSTATSNOTINTIMEWINDOWS;
4320
0
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4321
0
        err_var = notInTimeWindow;
4322
0
        err_var_len = ERROR_STAT_LENGTH;
4323
0
        break;
4324
0
    case SNMPERR_USM_DECRYPTIONERROR:
4325
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4326
0
        stat_ind = STAT_USMSTATSDECRYPTIONERRORS;
4327
0
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4328
0
        err_var = decryptionError;
4329
0
        err_var_len = ERROR_STAT_LENGTH;
4330
0
        break;
4331
0
    default:
4332
0
        return SNMPERR_GENERR;
4333
0
    }
4334
4335
0
    snmp_free_varbind(pdu->variables);  /* free the current varbind */
4336
4337
0
    pdu->variables = NULL;
4338
0
    SNMP_FREE(pdu->securityEngineID);
4339
0
    pdu->securityEngineID =
4340
0
        snmpv3_generate_engineID(&pdu->securityEngineIDLen);
4341
0
    SNMP_FREE(pdu->contextEngineID);
4342
0
    pdu->contextEngineID =
4343
0
        snmpv3_generate_engineID(&pdu->contextEngineIDLen);
4344
0
    pdu->command = SNMP_MSG_REPORT;
4345
0
    pdu->errstat = 0;
4346
0
    pdu->errindex = 0;
4347
0
    SNMP_FREE(pdu->contextName);
4348
0
    pdu->contextNameLen = 0;
4349
0
    pdu->contextName = strdup("");
4350
0
    if (!pdu->contextName)
4351
0
        return SNMPERR_MALLOC;
4352
0
    pdu->contextNameLen = strlen(pdu->contextName);
4353
4354
    /*
4355
     * reports shouldn't cache previous data. 
4356
     */
4357
    /*
4358
     * FIX - yes they should but USM needs to follow new EoP to determine
4359
     * which cached values to use 
4360
     */
4361
0
    free_securityStateRef(pdu);
4362
4363
0
    if (error == SNMPERR_USM_NOTINTIMEWINDOW) {
4364
0
        pdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
4365
0
    } else {
4366
0
        pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
4367
0
    }
4368
4369
    /*
4370
     * find the appropriate error counter  
4371
     */
4372
0
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4373
0
    ltmp = snmp_get_statistic(stat_ind);
4374
#else /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4375
    ltmp = 1;
4376
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4377
4378
    /*
4379
     * return the appropriate error counter  
4380
     */
4381
0
    snmp_pdu_add_variable(pdu, err_var, err_var_len,
4382
0
                          ASN_COUNTER, & ltmp, sizeof(ltmp));
4383
4384
0
    return SNMPERR_SUCCESS;
4385
0
}                               /* end snmpv3_make_report() */
4386
4387
4388
int
4389
snmpv3_get_report_type(netsnmp_pdu *pdu)
4390
0
{
4391
0
    static const oid snmpMPDStats[] = { 1, 3, 6, 1, 6, 3, 11, 2, 1 };
4392
0
    static const oid targetStats[]  = { 1, 3, 6, 1, 6, 3, 12, 1    };
4393
0
    static const oid usmStats[]     = { 1, 3, 6, 1, 6, 3, 15, 1, 1 };
4394
0
    netsnmp_variable_list *vp;
4395
0
    int             rpt_type = SNMPERR_UNKNOWN_REPORT;
4396
4397
0
    if (pdu == NULL || pdu->variables == NULL)
4398
0
        return rpt_type;
4399
0
    vp = pdu->variables;
4400
    /* MPD or USM based report statistics objects have the same length prefix
4401
     *   so the actual statistics OID will have this length,
4402
     *   plus one subidentifier for the scalar MIB object itself,
4403
     *   and one for the instance subidentifier
4404
     */
4405
0
    if (vp->name_length == REPORT_STATS_LEN + 2) {
4406
0
        if (memcmp(snmpMPDStats, vp->name, REPORT_STATS_LEN * sizeof(oid)) == 0) {
4407
0
            switch (vp->name[REPORT_STATS_LEN]) {
4408
0
            case REPORT_snmpUnknownSecurityModels_NUM:
4409
0
                rpt_type = SNMPERR_UNKNOWN_SEC_MODEL;
4410
0
                break;
4411
0
            case REPORT_snmpInvalidMsgs_NUM:
4412
0
                rpt_type = SNMPERR_INVALID_MSG;
4413
0
                break;
4414
0
            case REPORT_snmpUnknownPDUHandlers_NUM:
4415
0
                rpt_type = SNMPERR_BAD_VERSION;
4416
0
                break;
4417
0
            }
4418
0
        } else if (memcmp(usmStats, vp->name, REPORT_STATS_LEN * sizeof(oid)) == 0) {
4419
0
            switch (vp->name[REPORT_STATS_LEN]) {
4420
0
            case REPORT_usmStatsUnsupportedSecLevels_NUM:
4421
0
                rpt_type = SNMPERR_UNSUPPORTED_SEC_LEVEL;
4422
0
                break;
4423
0
            case REPORT_usmStatsNotInTimeWindows_NUM:
4424
0
                rpt_type = SNMPERR_NOT_IN_TIME_WINDOW;
4425
0
                break;
4426
0
            case REPORT_usmStatsUnknownUserNames_NUM:
4427
0
                rpt_type = SNMPERR_UNKNOWN_USER_NAME;
4428
0
                break;
4429
0
            case REPORT_usmStatsUnknownEngineIDs_NUM:
4430
0
                rpt_type = SNMPERR_UNKNOWN_ENG_ID;
4431
0
                break;
4432
0
            case REPORT_usmStatsWrongDigests_NUM:
4433
0
                rpt_type = SNMPERR_AUTHENTICATION_FAILURE;
4434
0
                break;
4435
0
            case REPORT_usmStatsDecryptionErrors_NUM:
4436
0
                rpt_type = SNMPERR_DECRYPTION_ERR;
4437
0
                break;
4438
0
            }
4439
0
        }
4440
0
    }
4441
    /* Context-based report statistics from the Target MIB are similar
4442
     *   but the OID prefix has a different length
4443
     */
4444
0
    if (vp->name_length == REPORT_STATS_LEN2 + 2) {
4445
0
        if (memcmp(targetStats, vp->name, REPORT_STATS_LEN2 * sizeof(oid)) == 0) {
4446
0
            switch (vp->name[REPORT_STATS_LEN2]) {
4447
0
            case REPORT_snmpUnavailableContexts_NUM:
4448
0
                rpt_type = SNMPERR_BAD_CONTEXT;
4449
0
                break;
4450
0
            case REPORT_snmpUnknownContexts_NUM:
4451
0
                rpt_type = SNMPERR_BAD_CONTEXT;
4452
0
                break;
4453
0
            }
4454
0
        }
4455
0
    }
4456
0
    DEBUGMSGTL(("report", "Report type: %d\n", rpt_type));
4457
0
    return rpt_type;
4458
0
}
4459
4460
/*
4461
 * Parses the packet received on the input session, and places the data into
4462
 * the input pdu.  length is the length of the input packet.
4463
 * If any errors are encountered, -1 or USM error is returned.
4464
 * Otherwise, a 0 is returned.
4465
 */
4466
static int
4467
_snmp_parse(struct session_list *slp,
4468
            netsnmp_session * session,
4469
            netsnmp_pdu *pdu, u_char * data, size_t length)
4470
0
{
4471
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
4472
0
    u_char          community[COMMUNITY_MAX_LEN];
4473
0
    size_t          community_length = COMMUNITY_MAX_LEN;
4474
0
#endif
4475
0
    int             result = -1;
4476
4477
0
    static const oid snmpEngineIDoid[]   = { 1,3,6,1,6,3,10,2,1,1,0};
4478
0
    static size_t   snmpEngineIDoid_len = 11;
4479
4480
0
    static char     ourEngineID[SNMP_SEC_PARAM_BUF_SIZE];
4481
0
    static size_t   ourEngineID_len = sizeof(ourEngineID);
4482
4483
0
    netsnmp_pdu    *pdu2 = NULL;
4484
4485
0
    session->s_snmp_errno = 0;
4486
0
    session->s_errno = 0;
4487
4488
    /*
4489
     * Ensure all incoming PDUs have a unique means of identification 
4490
     * (This is not restricted to AgentX handling,
4491
     * though that is where the need becomes visible)   
4492
     */
4493
0
    pdu->transid = snmp_get_next_transid();
4494
4495
0
    if (session->version != SNMP_DEFAULT_VERSION) {
4496
0
        pdu->version = session->version;
4497
0
    } else {
4498
0
        pdu->version = snmp_parse_version(data, length);
4499
0
    }
4500
4501
0
    switch (pdu->version) {
4502
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
4503
0
#ifndef NETSNMP_DISABLE_SNMPV1
4504
0
    case SNMP_VERSION_1:
4505
0
#endif
4506
0
#ifndef NETSNMP_DISABLE_SNMPV2C
4507
0
    case SNMP_VERSION_2c:
4508
0
#endif
4509
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK_V1V2(pdu->version,unsupported_version);
4510
0
        DEBUGMSGTL(("snmp_api", "Parsing SNMPv%ld message...\n",
4511
0
                    (1 + pdu->version)));
4512
4513
        /*
4514
         * authenticates message and returns length if valid 
4515
         */
4516
0
#ifndef NETSNMP_DISABLE_SNMPV1
4517
0
        if (pdu->version == SNMP_VERSION_1) {
4518
0
            DEBUGDUMPSECTION("recv", "SNMPv1 message\n");
4519
0
        } else {
4520
0
#endif
4521
0
            DEBUGDUMPSECTION("recv", "SNMPv2c message\n");
4522
0
#ifndef NETSNMP_DISABLE_SNMPV1
4523
0
        }
4524
0
#endif
4525
0
        data = snmp_comstr_parse(data, &length,
4526
0
                                 community, &community_length,
4527
0
                                 &pdu->version);
4528
0
        if (data == NULL)
4529
0
            return -1;
4530
4531
0
        if (pdu->version != session->version &&
4532
0
            session->version != SNMP_DEFAULT_VERSION) {
4533
0
            session->s_snmp_errno = SNMPERR_BAD_VERSION;
4534
0
            return -1;
4535
0
        }
4536
4537
        /*
4538
         * maybe get the community string. 
4539
         */
4540
0
        pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
4541
0
        pdu->securityModel = 
4542
0
#ifndef NETSNMP_DISABLE_SNMPV1
4543
0
            (pdu->version == SNMP_VERSION_1) ? SNMP_SEC_MODEL_SNMPv1 : 
4544
0
#endif
4545
0
                                               SNMP_SEC_MODEL_SNMPv2c;
4546
0
        SNMP_FREE(pdu->community);
4547
0
        pdu->community_len = 0;
4548
0
        pdu->community = (u_char *) 0;
4549
0
        if (community_length) {
4550
0
            pdu->community_len = community_length;
4551
0
            pdu->community = netsnmp_memdup(community, community_length);
4552
0
            if (pdu->community == NULL) {
4553
0
                session->s_snmp_errno = SNMPERR_MALLOC;
4554
0
                return -1;
4555
0
            }
4556
0
        }
4557
0
        if (session->authenticator) {
4558
0
            data = session->authenticator(data, &length,
4559
0
                                          community, community_length);
4560
0
            if (data == NULL) {
4561
0
                session->s_snmp_errno = SNMPERR_AUTHENTICATION_FAILURE;
4562
0
                return -1;
4563
0
            }
4564
0
        }
4565
4566
0
        DEBUGDUMPSECTION("recv", "PDU");
4567
0
        result = snmp_pdu_parse(pdu, data, &length);
4568
0
        if (result < 0) {
4569
            /*
4570
             * This indicates a parse error.  
4571
             */
4572
0
            snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4573
0
        }
4574
0
        DEBUGINDENTADD(-6);
4575
0
        break;
4576
0
#endif /* support for community based SNMP */
4577
4578
0
    case SNMP_VERSION_3:
4579
0
        NETSNMP_RUNTIME_PROTOCOL_CHECK_V3(SNMP_VERSION_3,unsupported_version);
4580
0
        result = snmpv3_parse(pdu, data, &length, NULL, session);
4581
0
        DEBUGMSGTL(("snmp_parse",
4582
0
                    "Parsed SNMPv3 message (secName:%s, secLevel:%s): %s\n",
4583
0
                    pdu->securityName,
4584
0
                    (pdu->securityLevel >= 0 && pdu->securityLevel < 4) ?
4585
0
                    secLevelName[pdu->securityLevel] : "ERROR: invalid",
4586
0
                    snmp_api_errstring(result)));
4587
4588
0
        if (result == SNMPERR_USM_UNKNOWNSECURITYNAME) {
4589
0
            snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
4590
0
                                SNMPD_CALLBACK_AUTH_FAILURE, pdu);
4591
0
        }
4592
        
4593
0
        if (result) {
4594
0
            struct snmp_secmod_def *secmod =
4595
0
                find_sec_mod(pdu->securityModel);
4596
0
            if (!slp) {
4597
0
                session->s_snmp_errno = result;
4598
0
            } else {
4599
                /*
4600
                 * Call the security model to special handle any errors
4601
                 */
4602
4603
0
                if (secmod && secmod->handle_report) {
4604
0
                    (*secmod->handle_report)(slp, slp->transport, session,
4605
0
                                             result, pdu);
4606
0
                }
4607
0
            }
4608
0
            free_securityStateRef(pdu);
4609
0
        }
4610
4611
        /* Implement RFC5343 here for two reasons:
4612
           1) From a security perspective it handles this otherwise
4613
              always approved request earlier.  It bypasses the need
4614
              for authorization to the snmpEngineID scalar, which is
4615
              what is what RFC3415 appendix A species as ok.  Note
4616
              that we haven't bypassed authentication since if there
4617
              was an authentication error it would have been handled
4618
              above in the if(result) part at the latest.
4619
           2) From an application point of view if we let this request
4620
              get all the way to the application, it'd require that
4621
              all application types supporting discovery also fire up
4622
              a minimal agent in order to handle just this request
4623
              which seems like overkill.  Though there is no other
4624
              application types that currently need discovery (NRs
4625
              accept notifications from contextEngineIDs that derive
4626
              from the NO not the NR).  Also a lame excuse for doing
4627
              it here.
4628
           3) Less important technically, but the net-snmp agent
4629
              doesn't currently handle registrations of different
4630
              engineIDs either and it would have been a lot more work
4631
              to implement there since we'd need to support that
4632
              first. :-/ Supporting multiple context engineIDs should
4633
              be done anyway, so it's not a valid excuse here.
4634
           4) There is a lot less to do if we trump the agent at this
4635
              point; IE, the agent does a lot more unnecessary
4636
              processing when the only thing that should ever be in
4637
              this context by definition is the single scalar.
4638
        */
4639
4640
        /* special RFC5343 engineID discovery engineID check */
4641
0
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
4642
0
                                    NETSNMP_DS_LIB_NO_DISCOVERY) &&
4643
0
            SNMP_MSG_RESPONSE       != pdu->command &&
4644
0
            NULL                    != pdu->contextEngineID &&
4645
0
            pdu->contextEngineIDLen == 5 &&
4646
0
            pdu->contextEngineID[0] == 0x80 &&
4647
0
            pdu->contextEngineID[1] == 0x00 &&
4648
0
            pdu->contextEngineID[2] == 0x00 &&
4649
0
            pdu->contextEngineID[3] == 0x00 &&
4650
0
            pdu->contextEngineID[4] == 0x06) {
4651
4652
            /* define a result so it doesn't get past us at this point
4653
               and gets dropped by future parts of the stack */
4654
0
            result = SNMPERR_JUST_A_CONTEXT_PROBE;
4655
4656
0
            DEBUGMSGTL(("snmpv3_contextid", "starting context ID discovery\n"));
4657
            /* ensure exactly one variable */
4658
0
            if (NULL != pdu->variables &&
4659
0
                NULL == pdu->variables->next_variable &&
4660
4661
                /* if it's a GET, match it exactly */
4662
0
                ((SNMP_MSG_GET == pdu->command &&
4663
0
                  snmp_oid_compare(snmpEngineIDoid,
4664
0
                                   snmpEngineIDoid_len,
4665
0
                                   pdu->variables->name,
4666
0
                                   pdu->variables->name_length) == 0)
4667
                 /* if it's a GETNEXT ensure it's less than the engineID oid */
4668
0
                 ||
4669
0
                 (SNMP_MSG_GETNEXT == pdu->command &&
4670
0
                  snmp_oid_compare(snmpEngineIDoid,
4671
0
                                   snmpEngineIDoid_len,
4672
0
                                   pdu->variables->name,
4673
0
                                   pdu->variables->name_length) > 0)
4674
0
                    )) {
4675
4676
0
                DEBUGMSGTL(("snmpv3_contextid",
4677
0
                            "  One correct variable found\n"));
4678
4679
                /* Note: we're explicitly not handling a GETBULK.  Deal. */
4680
4681
                /* set up the response */
4682
0
                pdu2 = snmp_clone_pdu(pdu);
4683
0
                if (NULL == pdu2) {
4684
0
                    snmp_log(LOG_ERR, "failed to clone PDU for rfc5343 probe\n");
4685
0
                    if (pdu->securityStateRef)
4686
0
                        free_securityStateRef(pdu);
4687
0
                    return result;
4688
0
                }
4689
4690
                /* free the current varbind */
4691
0
                snmp_free_varbind(pdu2->variables);
4692
4693
                /* set the variables */
4694
0
                pdu2->variables = NULL;
4695
0
                pdu2->command = SNMP_MSG_RESPONSE;
4696
0
                pdu2->errstat = 0;
4697
0
                pdu2->errindex = 0;
4698
4699
0
                ourEngineID_len =
4700
0
                    snmpv3_get_engineID((u_char*)ourEngineID, ourEngineID_len);
4701
0
                if (0 != ourEngineID_len) {
4702
4703
0
                    DEBUGMSGTL(("snmpv3_contextid",
4704
0
                                "  responding with our engineID\n"));
4705
4706
0
                    snmp_pdu_add_variable(pdu2,
4707
0
                                          snmpEngineIDoid, snmpEngineIDoid_len,
4708
0
                                          ASN_OCTET_STR,
4709
0
                                          ourEngineID, ourEngineID_len);
4710
                    
4711
                    /* send the response */
4712
0
                    if (0 == snmp_sess_send(slp, pdu2)) {
4713
4714
0
                        DEBUGMSGTL(("snmpv3_contextid",
4715
0
                                    "  sent it off!\n"));
4716
4717
0
                        snmp_free_pdu(pdu2);
4718
                        
4719
0
                        snmp_log(LOG_ERR, "sending a response to the context engineID probe failed\n");
4720
0
                    }
4721
0
                } else {
4722
0
                    snmp_log(LOG_ERR, "failed to get our own engineID!\n");
4723
0
                    snmp_free_pdu(pdu2);
4724
0
                }
4725
0
            } else {
4726
0
                snmp_log(LOG_WARNING,
4727
0
                         "received an odd context engineID probe\n");
4728
0
            }
4729
0
            if (pdu->securityStateRef)
4730
0
                free_securityStateRef(pdu);
4731
0
        }
4732
4733
0
        break;
4734
0
    case SNMPERR_BAD_VERSION:
4735
0
        ERROR_MSG("error parsing snmp message version");
4736
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4737
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
4738
0
        break;
4739
4740
0
        unsupported_version:  /* goto label */
4741
0
    case SNMP_VERSION_sec:
4742
0
    case SNMP_VERSION_2u:
4743
0
    case SNMP_VERSION_2star:
4744
0
    case SNMP_VERSION_2p:
4745
0
    default:
4746
0
        ERROR_MSG("unsupported snmp message version");
4747
0
        snmp_increment_statistic(STAT_SNMPINBADVERSIONS);
4748
4749
        /*
4750
         * need better way to determine OS independent
4751
         * INT32_MAX value, for now hardcode
4752
         */
4753
0
        if (pdu->version < 0 || pdu->version > 2147483647) {
4754
0
            snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4755
0
        }
4756
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
4757
0
        break;
4758
0
    }
4759
4760
0
    return result;
4761
0
}
4762
4763
/**
4764
 * Parse a PDU.
4765
 * @param slp    [in]  Session pointer (struct session_list).
4766
 * @param pss    [in]  Session pointer (netsnmp_session).
4767
 * @param pdu    [out] Parsed PDU.
4768
 * @param data   [in]  PDU to parse.
4769
 * @param length [in]  Length of data.
4770
 *
4771
 * @returns 0 upon success; -1 upon failure.
4772
 */
4773
int
4774
snmp_parse(struct session_list *slp, netsnmp_session *pss,
4775
           netsnmp_pdu *pdu, u_char *data, size_t length)
4776
0
{
4777
0
    int             rc;
4778
4779
0
    rc = _snmp_parse(slp, pss, pdu, data, length);
4780
0
    if (rc) {
4781
0
        if (!pss->s_snmp_errno) {
4782
0
            pss->s_snmp_errno = SNMPERR_BAD_PARSE;
4783
0
        }
4784
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
4785
0
    }
4786
4787
0
    return rc;
4788
0
}
4789
4790
int
4791
snmp_pdu_parse(netsnmp_pdu *pdu, u_char * data, size_t * length)
4792
0
{
4793
0
    u_char          type;
4794
0
    u_char          msg_type;
4795
0
    u_char         *var_val;
4796
0
    size_t          len;
4797
0
    size_t          four;
4798
0
    netsnmp_variable_list *vp = NULL, *vplast = NULL;
4799
0
    oid             objid[MAX_OID_LEN];
4800
0
    u_char         *p;
4801
4802
    /*
4803
     * Get the PDU type 
4804
     */
4805
0
    data = asn_parse_header(data, length, &msg_type);
4806
0
    if (data == NULL)
4807
0
        return -1;
4808
0
    DEBUGMSGTL(("dumpv_recv","    Command %s\n", snmp_pdu_type(msg_type)));
4809
0
    pdu->command = msg_type;
4810
0
    pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
4811
4812
    /*
4813
     * get the fields in the PDU preceding the variable-bindings sequence
4814
     */
4815
0
    switch (pdu->command) {
4816
0
    case SNMP_MSG_TRAP:
4817
        /*
4818
         * enterprise 
4819
         */
4820
0
        pdu->enterprise_length = MAX_OID_LEN;
4821
0
        data = asn_parse_objid(data, length, &type, objid,
4822
0
                               &pdu->enterprise_length);
4823
0
        if (data == NULL)
4824
0
            return -1;
4825
0
        SNMP_FREE(pdu->enterprise);
4826
0
        pdu->enterprise = netsnmp_memdup(objid,
4827
0
                                         pdu->enterprise_length * sizeof(oid));
4828
0
        if (pdu->enterprise == NULL) {
4829
0
            return -1;
4830
0
        }
4831
4832
        /*
4833
         * agent-addr 
4834
         */
4835
0
        four = 4;
4836
0
        data = asn_parse_string(data, length, &type,
4837
0
                                (u_char *) pdu->agent_addr, &four);
4838
0
        if (data == NULL)
4839
0
            return -1;
4840
4841
        /*
4842
         * generic trap 
4843
         */
4844
0
        data = asn_parse_int(data, length, &type, (long *) &pdu->trap_type,
4845
0
                             sizeof(pdu->trap_type));
4846
0
        if (data == NULL)
4847
0
            return -1;
4848
        /*
4849
         * specific trap 
4850
         */
4851
0
        data =
4852
0
            asn_parse_int(data, length, &type,
4853
0
                          (long *) &pdu->specific_type,
4854
0
                          sizeof(pdu->specific_type));
4855
0
        if (data == NULL)
4856
0
            return -1;
4857
4858
        /*
4859
         * timestamp  
4860
         */
4861
0
        data = asn_parse_unsigned_int(data, length, &type, &pdu->time,
4862
0
                                      sizeof(pdu->time));
4863
0
        if (data == NULL)
4864
0
            return -1;
4865
4866
0
        break;
4867
4868
0
    case SNMP_MSG_RESPONSE:
4869
0
    case SNMP_MSG_REPORT:
4870
0
        pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
4871
0
        NETSNMP_FALLTHROUGH;
4872
4873
0
    case SNMP_MSG_TRAP2:
4874
0
    case SNMP_MSG_INFORM:
4875
0
#ifndef NETSNMP_NOTIFY_ONLY
4876
0
    case SNMP_MSG_GET:
4877
0
    case SNMP_MSG_GETNEXT:
4878
0
    case SNMP_MSG_GETBULK:
4879
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
4880
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
4881
0
    case SNMP_MSG_SET:
4882
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
4883
        /*
4884
         * PDU is not an SNMPv1 TRAP 
4885
         */
4886
4887
        /*
4888
         * request id 
4889
         */
4890
0
        DEBUGDUMPHEADER("recv", "request_id");
4891
0
        data = asn_parse_int(data, length, &type, &pdu->reqid,
4892
0
                             sizeof(pdu->reqid));
4893
0
        DEBUGINDENTLESS();
4894
0
        if (data == NULL) {
4895
0
            return -1;
4896
0
        }
4897
4898
        /*
4899
         * error status (getbulk non-repeaters) 
4900
         */
4901
0
        DEBUGDUMPHEADER("recv", "error status");
4902
0
        data = asn_parse_int(data, length, &type, &pdu->errstat,
4903
0
                             sizeof(pdu->errstat));
4904
0
        DEBUGINDENTLESS();
4905
0
        if (data == NULL) {
4906
0
            return -1;
4907
0
        }
4908
4909
        /*
4910
         * error index (getbulk max-repetitions) 
4911
         */
4912
0
        DEBUGDUMPHEADER("recv", "error index");
4913
0
        data = asn_parse_int(data, length, &type, &pdu->errindex,
4914
0
                             sizeof(pdu->errindex));
4915
0
        DEBUGINDENTLESS();
4916
0
        if (data == NULL) {
4917
0
            return -1;
4918
0
        }
4919
0
  break;
4920
4921
0
    default:
4922
0
        snmp_log(LOG_ERR, "Bad PDU type received: 0x%.2x\n", pdu->command);
4923
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4924
0
        return -1;
4925
0
    }
4926
4927
    /*
4928
     * get header for variable-bindings sequence 
4929
     */
4930
0
    DEBUGDUMPSECTION("recv", "VarBindList");
4931
0
    data = asn_parse_sequence(data, length, &type,
4932
0
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
4933
0
                              "varbinds");
4934
0
    if (data == NULL)
4935
0
        goto fail;
4936
4937
0
    snmp_free_varbind(pdu->variables);
4938
0
    pdu->variables = NULL;
4939
4940
    /*
4941
     * get each varBind sequence 
4942
     */
4943
0
    while ((int) *length > 0) {
4944
0
        vp = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
4945
0
        if (NULL == vp)
4946
0
            goto fail;
4947
4948
0
        vp->name_length = MAX_OID_LEN;
4949
0
        DEBUGDUMPSECTION("recv", "VarBind");
4950
0
        data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
4951
0
                                 &vp->val_len, &var_val, length);
4952
0
        if (data == NULL)
4953
0
            goto fail;
4954
0
        if (snmp_set_var_objid(vp, objid, vp->name_length))
4955
0
            goto fail;
4956
4957
0
        len = SNMP_MAX_PACKET_LEN;
4958
0
        DEBUGDUMPHEADER("recv", "Value");
4959
0
        switch ((short) vp->type) {
4960
0
        case ASN_INTEGER:
4961
0
            vp->val.integer = (long *) vp->buf;
4962
0
            vp->val_len = sizeof(long);
4963
0
            p = asn_parse_int(var_val, &len, &vp->type,
4964
0
                          (long *) vp->val.integer,
4965
0
                          sizeof(*vp->val.integer));
4966
0
            if (!p)
4967
0
                goto fail;
4968
0
            break;
4969
0
        case ASN_COUNTER:
4970
0
        case ASN_GAUGE:
4971
0
        case ASN_TIMETICKS:
4972
0
        case ASN_UINTEGER:
4973
0
            vp->val.integer = (long *) vp->buf;
4974
0
            vp->val_len = sizeof(u_long);
4975
0
            p = asn_parse_unsigned_int(var_val, &len, &vp->type,
4976
0
                                   (u_long *) vp->val.integer,
4977
0
                                   vp->val_len);
4978
0
            if (!p)
4979
0
                goto fail;
4980
0
            break;
4981
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
4982
0
        case ASN_OPAQUE_COUNTER64:
4983
0
        case ASN_OPAQUE_U64:
4984
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
4985
0
        case ASN_COUNTER64:
4986
0
            vp->val.counter64 = (struct counter64 *) vp->buf;
4987
0
            vp->val_len = sizeof(struct counter64);
4988
0
            p = asn_parse_unsigned_int64(var_val, &len, &vp->type,
4989
0
                                     (struct counter64 *) vp->val.
4990
0
                                     counter64, vp->val_len);
4991
0
            if (!p)
4992
0
                goto fail;
4993
0
            break;
4994
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
4995
0
        case ASN_OPAQUE_FLOAT:
4996
0
            vp->val.floatVal = (float *) vp->buf;
4997
0
            vp->val_len = sizeof(float);
4998
0
            p = asn_parse_float(var_val, &len, &vp->type,
4999
0
                            vp->val.floatVal, vp->val_len);
5000
0
            if (!p)
5001
0
                goto fail;
5002
0
            break;
5003
0
        case ASN_OPAQUE_DOUBLE:
5004
0
            vp->val.doubleVal = (double *) vp->buf;
5005
0
            vp->val_len = sizeof(double);
5006
0
            p = asn_parse_double(var_val, &len, &vp->type,
5007
0
                             vp->val.doubleVal, vp->val_len);
5008
0
            if (!p)
5009
0
                goto fail;
5010
0
            break;
5011
0
        case ASN_OPAQUE_I64:
5012
0
            vp->val.counter64 = (struct counter64 *) vp->buf;
5013
0
            vp->val_len = sizeof(struct counter64);
5014
0
            p = asn_parse_signed_int64(var_val, &len, &vp->type,
5015
0
                                   (struct counter64 *) vp->val.counter64,
5016
0
                                   sizeof(*vp->val.counter64));
5017
5018
0
            if (!p)
5019
0
                goto fail;
5020
0
            break;
5021
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
5022
0
        case ASN_IPADDRESS:
5023
0
            if (vp->val_len != 4)
5024
0
                goto fail;
5025
0
            NETSNMP_FALLTHROUGH;
5026
0
        case ASN_OCTET_STR:
5027
0
        case ASN_OPAQUE:
5028
0
        case ASN_NSAP:
5029
0
            if (vp->val_len < sizeof(vp->buf)) {
5030
0
                vp->val.string = (u_char *) vp->buf;
5031
0
            } else {
5032
0
                vp->val.string = (u_char *) malloc(vp->val_len);
5033
0
            }
5034
0
            if (vp->val.string == NULL) {
5035
0
                goto fail;
5036
0
            }
5037
0
            p = asn_parse_string(var_val, &len, &vp->type, vp->val.string,
5038
0
                             &vp->val_len);
5039
0
            if (!p)
5040
0
                goto fail;
5041
0
            break;
5042
0
        case ASN_OBJECT_ID:
5043
0
            vp->val_len = MAX_OID_LEN;
5044
0
            p = asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
5045
0
            if (!p)
5046
0
                goto fail;
5047
0
            vp->val_len *= sizeof(oid);
5048
0
            vp->val.objid = netsnmp_memdup(objid, vp->val_len);
5049
0
            if (vp->val.objid == NULL)
5050
0
                goto fail;
5051
0
            break;
5052
0
        case SNMP_NOSUCHOBJECT:
5053
0
        case SNMP_NOSUCHINSTANCE:
5054
0
        case SNMP_ENDOFMIBVIEW:
5055
0
        case ASN_NULL:
5056
0
            break;
5057
0
        case ASN_BIT_STR:
5058
0
            vp->val.bitstring = (u_char *) malloc(vp->val_len);
5059
0
            if (vp->val.bitstring == NULL) {
5060
0
                goto fail;
5061
0
            }
5062
0
            p = asn_parse_bitstring(var_val, &len, &vp->type,
5063
0
                                vp->val.bitstring, &vp->val_len);
5064
0
            if (!p)
5065
0
                goto fail;
5066
0
            break;
5067
0
        default:
5068
0
            snmp_log(LOG_ERR, "bad type returned (%x)\n", vp->type);
5069
0
            goto fail;
5070
0
            break;
5071
0
        }
5072
0
        DEBUGINDENTADD(-4);
5073
5074
0
        if (NULL == vplast) {
5075
0
            pdu->variables = vp;
5076
0
        } else {
5077
0
            vplast->next_variable = vp;
5078
0
        }
5079
0
        vplast = vp;
5080
0
        vp = NULL;
5081
0
    }
5082
0
    return 0;
5083
5084
0
  fail:
5085
0
    {
5086
0
        const char *errstr = snmp_api_errstring(SNMPERR_SUCCESS);
5087
0
        DEBUGMSGTL(("recv", "error while parsing VarBindList:%s\n", errstr));
5088
0
    }
5089
    /** if we were parsing a var, remove it from the pdu and free it */
5090
0
    if (vp)
5091
0
        snmp_free_var(vp);
5092
5093
0
    return -1;
5094
0
}
5095
5096
/*
5097
 * snmp v3 utility function to parse into the scopedPdu. stores contextName
5098
 * and contextEngineID in pdu struct. Also stores pdu->command (handy for 
5099
 * Report generation).
5100
 * 
5101
 * returns pointer to begining of PDU or NULL on error.
5102
 */
5103
u_char         *
5104
snmpv3_scopedPDU_parse(netsnmp_pdu *pdu, u_char * cp, size_t * length)
5105
0
{
5106
0
    u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
5107
0
    size_t          tmp_buf_len;
5108
0
    u_char          type;
5109
0
    size_t          asn_len;
5110
0
    u_char         *data;
5111
5112
0
    pdu->command = 0;           /* initialize so we know if it got parsed */
5113
0
    asn_len = *length;
5114
0
    data = asn_parse_sequence(cp, &asn_len, &type,
5115
0
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
5116
0
                              "plaintext scopedPDU");
5117
0
    if (data == NULL) {
5118
0
        return NULL;
5119
0
    }
5120
0
    *length -= data - cp;
5121
5122
    /*
5123
     * contextEngineID from scopedPdu  
5124
     */
5125
0
    DEBUGDUMPHEADER("recv", "contextEngineID");
5126
0
    data = asn_parse_string(data, length, &type, pdu->contextEngineID,
5127
0
                            &pdu->contextEngineIDLen);
5128
0
    DEBUGINDENTLESS();
5129
0
    if (data == NULL) {
5130
0
        ERROR_MSG("error parsing contextEngineID from scopedPdu");
5131
0
        return NULL;
5132
0
    }
5133
5134
    /*
5135
     * parse contextName from scopedPdu
5136
     */
5137
0
    tmp_buf_len = SNMP_MAX_CONTEXT_SIZE;
5138
0
    DEBUGDUMPHEADER("recv", "contextName");
5139
0
    data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
5140
0
    DEBUGINDENTLESS();
5141
0
    if (data == NULL) {
5142
0
        ERROR_MSG("error parsing contextName from scopedPdu");
5143
0
        return NULL;
5144
0
    }
5145
5146
0
    SNMP_FREE(pdu->contextName);
5147
0
    pdu->contextName = netsnmp_memdup_nt(tmp_buf, tmp_buf_len,
5148
0
                                         &pdu->contextNameLen);
5149
0
    if (pdu->contextName == NULL) {
5150
0
        ERROR_MSG("error copying contextName from scopedPdu");
5151
0
        return NULL;
5152
0
    }
5153
5154
    /*
5155
     * Get the PDU type 
5156
     */
5157
0
    asn_len = *length;
5158
0
    cp = asn_parse_header(data, &asn_len, &type);
5159
0
    if (cp == NULL)
5160
0
        return NULL;
5161
5162
0
    pdu->command = type;
5163
5164
0
    return data;
5165
0
}
5166
5167
5168
/* ===========================================================================
5169
 *
5170
 * build pdu packet
5171
 */
5172
static int
5173
netsnmp_build_packet(struct snmp_internal_session *isp, netsnmp_session *sp,
5174
                     netsnmp_pdu *pdu, u_char **pktbuf_p,
5175
                     size_t *pktbuf_len_p, u_char **pkt_p, size_t *len_p)
5176
0
{
5177
0
    size_t offset = 0;
5178
0
    int    result;
5179
5180
0
    if (isp && isp->hook_realloc_build) {
5181
0
        result = isp->hook_realloc_build(sp, pdu, pktbuf_p, pktbuf_len_p,
5182
0
                                         &offset);
5183
5184
0
        *pkt_p = *pktbuf_p;
5185
0
        *len_p = offset;
5186
0
    } else if (isp && isp->hook_build) {
5187
0
        *pkt_p = *pktbuf_p;
5188
0
        *len_p = *pktbuf_len_p;
5189
0
        result = isp->hook_build(sp, pdu, *pktbuf_p, len_p);
5190
0
    } else {
5191
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
5192
0
        if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
5193
0
            result = snmp_build(pktbuf_p, pktbuf_len_p, &offset, sp, pdu);
5194
0
            *pkt_p = *pktbuf_p + *pktbuf_len_p - offset;
5195
0
            *len_p = offset;
5196
0
        } else {
5197
0
#endif
5198
0
            *pkt_p = *pktbuf_p;
5199
0
            *len_p = *pktbuf_len_p;
5200
0
            result = snmp_build(pktbuf_p, len_p, &offset, sp, pdu);
5201
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
5202
0
        }
5203
0
#endif
5204
0
    }
5205
5206
0
    return result;
5207
0
}
5208
5209
int
5210
_build_initial_pdu_packet(struct session_list *slp, netsnmp_pdu *pdu, int bulk)
5211
0
{
5212
0
    netsnmp_session *session;
5213
0
    struct snmp_internal_session *isp;
5214
0
    netsnmp_transport *transport = NULL;
5215
0
    u_char         *pktbuf = NULL, *packet = NULL;
5216
0
    size_t          pktbuf_len = 0, length = 0, orig_length = 0;
5217
0
    int             result, orig_count = 0, curr_count = 0;
5218
5219
0
    if (slp == NULL) {
5220
0
        return SNMPERR_GENERR;
5221
0
    }
5222
0
    session = slp->session;
5223
5224
0
    isp = slp->internal;
5225
0
    transport = slp->transport;
5226
0
    if (!session || !isp || !transport) {
5227
0
        DEBUGMSGTL(("sess_async_send", "send fail: closing...\n"));
5228
0
        return SNMPERR_GENERR;
5229
0
    }
5230
5231
0
    if (pdu == NULL) {
5232
0
        session->s_snmp_errno = SNMPERR_NULL_PDU;
5233
0
        return SNMPERR_GENERR;
5234
0
    }
5235
5236
0
    SNMP_FREE(isp->obuf); /* should already be NULL */
5237
5238
0
    session->s_snmp_errno = 0;
5239
0
    session->s_errno = 0;
5240
5241
    /*
5242
     * Check/setup the version.  
5243
     */
5244
0
    if (pdu->version == SNMP_DEFAULT_VERSION) {
5245
0
        if (session->version == SNMP_DEFAULT_VERSION) {
5246
0
            session->s_snmp_errno = SNMPERR_BAD_VERSION;
5247
0
            return SNMPERR_GENERR;
5248
0
        }
5249
0
        pdu->version = session->version;
5250
0
    } else if (session->version == SNMP_DEFAULT_VERSION) {
5251
        /*
5252
         * It's OK  
5253
         */
5254
0
    } else if (pdu->version != session->version) {
5255
        /*
5256
         * ENHANCE: we should support multi-lingual sessions  
5257
         */
5258
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
5259
0
        return SNMPERR_GENERR;
5260
0
    }
5261
0
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(pdu->version)) {
5262
0
        DEBUGMSGTL(("sess_async_send", "version disabled at runtime\n"));
5263
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
5264
0
        return SNMPERR_GENERR;
5265
0
    }
5266
5267
    /*
5268
     * do we expect a response?
5269
     */
5270
0
    switch (pdu->command) {
5271
5272
0
        case SNMP_MSG_RESPONSE:
5273
0
        case SNMP_MSG_TRAP:
5274
0
        case SNMP_MSG_TRAP2:
5275
0
        case SNMP_MSG_REPORT:
5276
0
        case AGENTX_MSG_CLEANUPSET:
5277
0
        case AGENTX_MSG_RESPONSE:
5278
0
            pdu->flags &= ~UCD_MSG_FLAG_EXPECT_RESPONSE;
5279
0
            break;
5280
            
5281
0
        default:
5282
0
            pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
5283
0
            break;
5284
0
    }
5285
5286
    /*
5287
     * Check if we need to perform a v3 engineID probe. Call post probe hook to
5288
     * create user from information in a session even if SNMP_FLAGS_DONT_PROBE
5289
     * is set, as this may indicate that probe was already sent by other means
5290
     * for example asynchronously.
5291
     */
5292
0
    if ((pdu->version == SNMP_VERSION_3) &&
5293
0
        (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE)) {
5294
0
        int rc;
5295
0
        DEBUGMSGTL(("snmpv3_build", "delayed probe for engineID\n"));
5296
0
        rc = snmpv3_engineID_probe(slp, session);
5297
0
        if (rc == 0)
5298
0
            return 0; /* s_snmp_errno already set */
5299
0
    }
5300
5301
    /*
5302
     * determine max packet size
5303
     */
5304
0
    if (pdu->msgMaxSize == 0) {
5305
0
        pdu->msgMaxSize = netsnmp_max_send_msg_size();
5306
0
        if (pdu->msgMaxSize > transport->msgMaxSize)
5307
0
            pdu->msgMaxSize = transport->msgMaxSize;
5308
0
        if (pdu->msgMaxSize > session->sndMsgMaxSize)
5309
0
            pdu->msgMaxSize = session->sndMsgMaxSize;
5310
0
        DEBUGMSGTL(("sess_async_send", "max PDU size: %ld\n",
5311
0
                    pdu->msgMaxSize));
5312
0
    }
5313
0
    netsnmp_assert(pdu->msgMaxSize > 0);
5314
5315
    /*
5316
     * allocate initial packet buffer. Buffer will be grown as needed
5317
     * while building the packet.
5318
     */
5319
0
    pktbuf_len = SNMP_MIN_MAX_LEN;
5320
0
    if ((pktbuf = (u_char *)malloc(pktbuf_len)) == NULL) {
5321
0
        DEBUGMSGTL(("sess_async_send",
5322
0
                    "couldn't malloc initial packet buffer\n"));
5323
0
        session->s_snmp_errno = SNMPERR_MALLOC;
5324
0
        return SNMPERR_MALLOC;
5325
0
    }
5326
5327
#ifdef TEMPORARILY_DISABLED
5328
    /*
5329
     *  NULL variable are allowed in certain PDU types.
5330
     *  In particular, SNMPv3 engineID probes are of this form.
5331
     *  There is an internal PDU flag to indicate that this
5332
     *    is acceptable, but until the construction of engineID
5333
     *    probes can be amended to set this flag, we'll simply
5334
     *    skip this test altogether.
5335
     */
5336
    if (pdu->variables == NULL) {
5337
        switch (pdu->command) {
5338
#ifndef NETSNMP_NO_WRITE_SUPPORT
5339
        case SNMP_MSG_SET:
5340
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
5341
        case SNMP_MSG_GET:
5342
        case SNMP_MSG_GETNEXT:
5343
        case SNMP_MSG_GETBULK:
5344
        case SNMP_MSG_RESPONSE:
5345
        case SNMP_MSG_TRAP2:
5346
        case SNMP_MSG_REPORT:
5347
        case SNMP_MSG_INFORM:
5348
            session->s_snmp_errno = snmp_errno = SNMPERR_NO_VARS;
5349
            return SNMPERR_NO_VARS;
5350
        case SNMP_MSG_TRAP:
5351
            break;
5352
        }
5353
    }
5354
#endif
5355
5356
5357
    /*
5358
     * Build the message to send. If a bulk response is too big, switch to
5359
     * forward encoding and set a flag to drop varbinds to make it fit.
5360
     */
5361
0
    do {
5362
0
        packet = NULL;
5363
0
        length = 0;
5364
0
        result = netsnmp_build_packet(isp, session, pdu, &pktbuf, &pktbuf_len,
5365
0
                                      &packet, &length);
5366
0
        if (0 != result)
5367
0
            break;
5368
5369
0
        if (orig_count) { /* 2nd pass, see how many varbinds remain */
5370
0
            curr_count = count_varbinds(pdu->variables);
5371
0
            DEBUGMSGTL(("sess_async_send", " vb count: %d -> %d\n", orig_count,
5372
0
                        curr_count));
5373
0
            DEBUGMSGTL(("sess_async_send", " pdu_len: %" NETSNMP_PRIz "d -> %" NETSNMP_PRIz "d (max %ld)\n",
5374
0
                        orig_length, length, pdu->msgMaxSize));
5375
0
        }
5376
5377
        /** if length is less than max size, we're done (success). */
5378
0
        if (length <= pdu->msgMaxSize)
5379
0
            break;
5380
5381
0
        DEBUGMSGTL(("sess_async_send", "length %" NETSNMP_PRIz "d exceeds maximum %ld\n",
5382
0
                    length, pdu->msgMaxSize));
5383
5384
        /** packet too big. if this is not a bulk request, we're done (err). */
5385
0
        if (!bulk) {
5386
0
           session->s_snmp_errno = SNMPERR_TOO_LONG;
5387
0
           break;
5388
0
        }
5389
5390
        /** rebuild bulk response with truncation and fixed size */
5391
0
        pdu->flags |= UCD_MSG_FLAG_FORWARD_ENCODE | UCD_MSG_FLAG_BULK_TOOBIG;
5392
0
        pktbuf_len = pdu->msgMaxSize;
5393
5394
        /** save original number of varbinds & length */
5395
0
        if (0 == orig_count) {
5396
0
            curr_count = orig_count = count_varbinds(pdu->variables);
5397
0
            orig_length = length;
5398
0
        }
5399
5400
0
    } while(1);
5401
5402
0
    DEBUGMSGTL(("sess_async_send",
5403
0
                "final pktbuf_len after building packet %" NETSNMP_PRIz "u\n",
5404
0
                pktbuf_len));
5405
0
    if (curr_count != orig_count)
5406
0
        DEBUGMSGTL(("sess_async_send",
5407
0
                    "sending %d of %d varbinds (-%d) from bulk response\n",
5408
0
                    curr_count, orig_count, orig_count - curr_count));
5409
5410
0
    if (length > pdu->msgMaxSize) {
5411
0
        DEBUGMSGTL(("sess_async_send",
5412
0
                    "length of packet (%" NETSNMP_PRIz "u) exceeded pdu maximum (%lu)\n",
5413
0
                    length, pdu->msgMaxSize));
5414
0
        netsnmp_assert(SNMPERR_TOO_LONG == session->s_snmp_errno);
5415
0
    }
5416
5417
0
    if ((SNMPERR_TOO_LONG == session->s_snmp_errno) || (result < 0)) {
5418
0
        DEBUGMSGTL(("sess_async_send", "encoding failure\n"));
5419
0
        SNMP_FREE(pktbuf);
5420
0
        return SNMPERR_GENERR;
5421
0
    }
5422
5423
0
    isp->obuf = pktbuf;
5424
0
    isp->obuf_size = pktbuf_len;
5425
0
    isp->opacket = packet;
5426
0
    isp->opacket_len = length;
5427
5428
0
    return SNMPERR_SUCCESS;
5429
0
}
5430
5431
/*
5432
 * These functions send PDUs using an active session:
5433
 * snmp_send             - traditional API, no callback
5434
 * snmp_async_send       - traditional API, with callback
5435
 * snmp_sess_send        - single session API, no callback
5436
 * snmp_sess_async_send  - single session API, with callback
5437
 *
5438
 * Call snmp_build to create a serialized packet (the pdu).
5439
 * If necessary, set some of the pdu data from the
5440
 * session defaults.
5441
 * If there is an expected response for this PDU,
5442
 * queue a corresponding request on the list
5443
 * of outstanding requests for this session,
5444
 * and store the callback vectors in the request.
5445
 *
5446
 * Send the pdu to the target identified by this session.
5447
 * Return on success:
5448
 *   The request id of the pdu is returned, and the pdu is freed.
5449
 * Return on failure:
5450
 *   Zero (0) is returned.
5451
 *   The caller must call snmp_free_pdu if 0 is returned.
5452
 */
5453
int
5454
snmp_send(netsnmp_session * session, netsnmp_pdu *pdu)
5455
0
{
5456
0
    return snmp_async_send(session, pdu, NULL, NULL);
5457
0
}
5458
5459
int
5460
snmp_sess_send(struct session_list *slp, netsnmp_pdu *pdu)
5461
0
{
5462
0
    return snmp_sess_async_send(slp, pdu, NULL, NULL);
5463
0
}
5464
5465
int
5466
snmp_async_send(netsnmp_session * session,
5467
                netsnmp_pdu *pdu, snmp_callback callback, void *cb_data)
5468
0
{
5469
0
    struct session_list *sessp = snmp_sess_pointer(session);
5470
0
    return snmp_sess_async_send(sessp, pdu, callback, cb_data);
5471
0
}
5472
5473
int
5474
snmp_async_send_cp(netsnmp_session * session, netsnmp_pdu *pdu,
5475
                   snmp_callback callback, void *cb_data, int cp_inc)
5476
0
{
5477
0
    void           *sessp = snmp_sess_pointer(session);
5478
0
    return snmp_sess_async_send_cp(sessp, pdu, callback, cb_data, cp_inc);
5479
0
}
5480
5481
/**
5482
 * Send a PDU asynchronously.
5483
 *
5484
 * @param[in] slp      Session pointer.
5485
 * @param[in] pdu      PDU to send.
5486
 * @param[in] callback Callback function called after processing of the PDU
5487
 *                     finished. This function is called if the PDU has not
5488
 *                     been sent or after a response has been received. Must
5489
 *                     not free @pdu.
5490
 * @param[in] cb_data  Will be passed as fifth argument to @callback.
5491
 *
5492
 * @return If successful, returns the request id of @pdu and frees @pdu.
5493
 * If not successful, returns zero and expects the caller to free @pdu.
5494
 */
5495
static int
5496
_sess_async_send(struct session_list *slp,
5497
                 netsnmp_pdu *pdu, snmp_callback callback, void *cb_data,
5498
                 int cp_inc)
5499
0
{
5500
0
    netsnmp_session *session;
5501
0
    struct snmp_internal_session *isp;
5502
0
    netsnmp_transport *transport = NULL;
5503
0
    int             result;
5504
0
    long            reqid;
5505
5506
0
    if (slp == NULL || NULL == slp->session || NULL ==slp->internal ||
5507
0
                NULL == slp->transport) {
5508
0
        return 0;
5509
0
    }
5510
5511
0
    session = slp->session;
5512
0
    isp = slp->internal;
5513
0
    transport = slp->transport;
5514
5515
0
    if (NULL == isp->opacket) {
5516
0
        result = _build_initial_pdu_packet(slp, pdu, 0);
5517
0
        if ((SNMPERR_SUCCESS != result) || (NULL == isp->opacket)) {
5518
0
            if (callback) {
5519
0
                switch (session->s_snmp_errno) {
5520
                    /*
5521
                     * some of these probably don't make sense here, but
5522
                     * it's a rough first cut.
5523
                     */
5524
0
                    case SNMPERR_BAD_ENG_ID:
5525
0
                    case SNMPERR_BAD_SEC_LEVEL:
5526
0
                    case SNMPERR_UNKNOWN_SEC_MODEL:
5527
0
                    case SNMPERR_UNKNOWN_ENG_ID:
5528
0
                    case SNMPERR_UNKNOWN_USER_NAME:
5529
0
                    case SNMPERR_UNSUPPORTED_SEC_LEVEL:
5530
0
                    case SNMPERR_AUTHENTICATION_FAILURE:
5531
0
                    case SNMPERR_NOT_IN_TIME_WINDOW:
5532
0
                    case SNMPERR_USM_GENERICERROR:
5533
0
                    case SNMPERR_USM_UNKNOWNSECURITYNAME:
5534
0
                    case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
5535
0
                    case SNMPERR_USM_ENCRYPTIONERROR:
5536
0
                    case SNMPERR_USM_AUTHENTICATIONFAILURE:
5537
0
                    case SNMPERR_USM_PARSEERROR:
5538
0
                    case SNMPERR_USM_UNKNOWNENGINEID:
5539
0
                    case SNMPERR_USM_NOTINTIMEWINDOW:
5540
0
                        callback(NETSNMP_CALLBACK_OP_SEC_ERROR, session,
5541
0
                                 pdu->reqid, pdu, cb_data);
5542
0
                        break;
5543
0
                    case SNMPERR_TIMEOUT: /* engineID probe timed out */
5544
0
                        callback(NETSNMP_CALLBACK_OP_TIMED_OUT, session,
5545
0
                                 pdu->reqid, pdu, cb_data);
5546
0
                        break;
5547
0
                    default:
5548
0
                        callback(NETSNMP_CALLBACK_OP_SEND_FAILED, session,
5549
0
                                 pdu->reqid, pdu, cb_data);
5550
0
                        break;
5551
0
                }
5552
0
            }
5553
            /** no packet to send?? */
5554
0
            return 0;
5555
0
        }
5556
0
    }
5557
5558
    /*
5559
     * Send the message.  
5560
     */
5561
5562
0
    DEBUGMSGTL(("sess_process_packet", "sending message id#%ld reqid#%ld len %"
5563
0
                NETSNMP_PRIz "u\n", pdu->msgid, pdu->reqid, isp->opacket_len));
5564
0
    result = netsnmp_transport_send(transport, isp->opacket, isp->opacket_len,
5565
0
                                    &(pdu->transport_data),
5566
0
                                    &(pdu->transport_data_length));
5567
5568
0
    SNMP_FREE(isp->obuf);
5569
0
    isp->opacket = NULL; /* opacket was in obuf, so no free needed */
5570
0
    isp->opacket_len = 0;
5571
5572
0
    if (result < 0) {
5573
0
        session->s_snmp_errno = SNMPERR_BAD_SENDTO;
5574
0
        session->s_errno = errno;
5575
0
        if (callback)
5576
0
            callback(NETSNMP_CALLBACK_OP_SEND_FAILED, session,
5577
0
                     pdu->reqid, pdu, cb_data);
5578
0
        return 0;
5579
0
    }
5580
5581
0
    reqid = pdu->reqid;
5582
5583
    /*
5584
     * Bug 2387: 0 is a valid request id, so since reqid is used as a return
5585
     * code with 0 meaning an error, set reqid to 1 if there is no error. This
5586
     * does not affect the request id in the packet and fixes a memory leak
5587
     * for incoming PDUs with a request id of 0. This could cause some
5588
     * confusion if the caller is expecting the request id to match the
5589
     * return code, as the documentation states it will. Most example code
5590
     * just checks for non-zero, so hopefully this wont be an issue.
5591
     */
5592
0
    if (0 == reqid && (SNMPERR_SUCCESS == session->s_snmp_errno))
5593
0
        ++reqid;
5594
5595
    /*
5596
     * Add to pending requests list if we expect a response.  
5597
     */
5598
0
    if (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) {
5599
0
        netsnmp_request_list *rp;
5600
0
        struct timeval  tv;
5601
5602
0
        rp = calloc(1, sizeof(netsnmp_request_list));
5603
0
        if (rp == NULL) {
5604
0
            session->s_snmp_errno = SNMPERR_GENERR;
5605
0
            return 0;
5606
0
        }
5607
5608
0
        netsnmp_get_monotonic_clock(&tv);
5609
0
        rp->pdu = pdu;
5610
0
        rp->request_id = pdu->reqid;
5611
0
        rp->message_id = pdu->msgid;
5612
0
        rp->callback = callback;
5613
0
        if (cp_inc && cb_data) {
5614
0
            netsnmp_refcnt_void *aux_cb_data = (netsnmp_refcnt_void*) cb_data;
5615
0
            aux_cb_data->refcnt++;
5616
0
            rp->cb_data_refcounted = 1;
5617
0
  }
5618
0
        rp->cb_data = cb_data;
5619
0
        rp->retries = 0;
5620
0
        if (pdu->flags & UCD_MSG_FLAG_PDU_TIMEOUT) {
5621
0
            rp->timeout = pdu->time * 1000000L;
5622
0
        } else {
5623
0
            rp->timeout = session->timeout;
5624
0
        }
5625
0
        rp->timeM = tv;
5626
0
        tv.tv_usec += rp->timeout;
5627
0
        tv.tv_sec += tv.tv_usec / 1000000L;
5628
0
        tv.tv_usec %= 1000000L;
5629
0
        rp->expireM = tv;
5630
5631
        /*
5632
         * XX lock should be per session ! 
5633
         */
5634
0
        snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
5635
0
        if (isp->requestsEnd) {
5636
0
            rp->next_request = isp->requestsEnd->next_request;
5637
0
            isp->requestsEnd->next_request = rp;
5638
0
            isp->requestsEnd = rp;
5639
0
        } else {
5640
0
            rp->next_request = isp->requests;
5641
0
            isp->requests = rp;
5642
0
            isp->requestsEnd = rp;
5643
0
        }
5644
0
        snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
5645
0
    } else {
5646
        /*
5647
         * No response expected...  
5648
         */
5649
0
        if (reqid) {
5650
            /*
5651
             * Free v1 or v2 TRAP PDU iff no error  
5652
             */
5653
0
            snmp_free_pdu(pdu);
5654
0
        }
5655
0
    }
5656
5657
0
    return reqid;
5658
0
}
5659
5660
/**
5661
 * Send a PDU asynchronously.
5662
 *
5663
 * @param[in] sessp    Session pointer.
5664
 * @param[in] pdu      PDU to send.
5665
 * @param[in] callback Callback function called after processing of the PDU
5666
 *                     finished. This function is called if the PDU has not
5667
 *                     been sent or after a response has been received. Must
5668
 *                     not free @p pdu.
5669
 * @param[in] cb_data  Will be passed as fifth argument to @p callback.
5670
 *
5671
 * @return If successful, returns the request id of @p pdu and frees @p pdu.
5672
 * If not successful, returns zero and expects the caller to free @p pdu.
5673
 */
5674
int
5675
snmp_sess_async_send(struct session_list *slp,
5676
                     netsnmp_pdu *pdu,
5677
                     snmp_callback callback, void *cb_data)
5678
0
{
5679
5680
0
    return snmp_sess_async_send_cp(slp, pdu, callback, cb_data, 0);
5681
0
}
5682
5683
int
5684
snmp_sess_async_send_cp(struct session_list *slp, netsnmp_pdu *pdu,
5685
                        snmp_callback callback, void *cb_data,
5686
                        int cp_inc)
5687
0
{
5688
0
    int             rc;
5689
5690
0
    if (slp == NULL) {
5691
0
        snmp_errno = SNMPERR_BAD_SESSION;       /*MTCRITICAL_RESOURCE */
5692
0
        return (0);
5693
0
    }
5694
    /*
5695
     * send pdu
5696
     */
5697
5698
0
    rc = _sess_async_send(slp, pdu, callback, cb_data, cp_inc);
5699
0
    if (rc == 0)
5700
0
        SET_SNMP_ERROR(slp->session->s_snmp_errno);
5701
0
    return rc;
5702
0
}
5703
5704
5705
/*
5706
 * Frees the variable and any malloc'd data associated with it.
5707
 */
5708
void
5709
snmp_free_var_internals(netsnmp_variable_list * var)
5710
0
{
5711
0
    if (!var)
5712
0
        return;
5713
5714
0
    if (var->name != var->name_loc)
5715
0
        SNMP_FREE(var->name);
5716
0
    if (var->val.string != var->buf)
5717
0
        SNMP_FREE(var->val.string);
5718
0
    if (var->data) {
5719
0
        if (var->dataFreeHook) {
5720
0
            var->dataFreeHook(var->data);
5721
0
            var->data = NULL;
5722
0
        } else {
5723
0
            SNMP_FREE(var->data);
5724
0
        }
5725
0
    }
5726
0
}
5727
5728
void
5729
snmp_free_var(netsnmp_variable_list * var)
5730
0
{
5731
0
    snmp_free_var_internals(var);
5732
0
    free(var);
5733
0
}
5734
5735
void
5736
snmp_free_varbind(netsnmp_variable_list * var)
5737
0
{
5738
0
    netsnmp_variable_list *ptr;
5739
0
    while (var) {
5740
0
        ptr = var->next_variable;
5741
0
        snmp_free_var(var);
5742
0
        var = ptr;
5743
0
    }
5744
0
}
5745
5746
/*
5747
 * Frees the pdu and any malloc'd data associated with it.
5748
 */
5749
void
5750
snmp_free_pdu(netsnmp_pdu *pdu)
5751
0
{
5752
0
    struct snmp_secmod_def *sptr;
5753
5754
0
    if (!pdu)
5755
0
        return;
5756
5757
0
    free_securityStateRef(pdu);
5758
5759
0
    sptr = find_sec_mod(pdu->securityModel);
5760
0
    if (sptr && sptr->pdu_free)
5761
0
        (*sptr->pdu_free)(pdu);
5762
5763
0
    snmp_free_varbind(pdu->variables);
5764
0
    free(pdu->enterprise);
5765
0
    free(pdu->community);
5766
0
    free(pdu->contextEngineID);
5767
0
    free(pdu->securityEngineID);
5768
0
    free(pdu->contextName);
5769
0
    free(pdu->securityName);
5770
0
    free(pdu->transport_data);
5771
0
    free(pdu);
5772
0
}
5773
5774
netsnmp_pdu    *
5775
snmp_create_sess_pdu(netsnmp_transport *transport, void *opaque,
5776
                     size_t olength)
5777
0
{
5778
0
    netsnmp_pdu *pdu = calloc(1, sizeof(netsnmp_pdu));
5779
0
    if (pdu == NULL) {
5780
0
        DEBUGMSGTL(("sess_process_packet", "can't malloc space for PDU\n"));
5781
0
        return NULL;
5782
0
    }
5783
5784
    /*
5785
     * Save the transport-level data specific to this reception (e.g. UDP
5786
     * source address).  
5787
     */
5788
5789
0
    pdu->transport_data = opaque;
5790
0
    pdu->transport_data_length = olength;
5791
0
    pdu->tDomain = transport->domain;
5792
0
    pdu->tDomainLen = transport->domain_length;
5793
0
    return pdu;
5794
0
}
5795
5796
5797
/*
5798
 * This function parses a packet into a PDU
5799
 */
5800
static netsnmp_pdu *
5801
_sess_process_packet_parse_pdu(struct session_list *slp, netsnmp_session * sp,
5802
                               struct snmp_internal_session *isp,
5803
                               netsnmp_transport *transport,
5804
                               void *opaque, int olength,
5805
                               u_char * packetptr, int length)
5806
0
{
5807
0
  netsnmp_pdu    *pdu;
5808
0
  int             ret = 0;
5809
0
  int             dump = 0, filter = 0;
5810
5811
0
  debug_indent_reset();
5812
5813
0
  DEBUGMSGTL(("sess_process_packet",
5814
0
        "session %p fd %" NETSNMP_FMT_SKT " pkt %p length %d\n", slp,
5815
0
        transport->sock, packetptr, length));
5816
5817
0
  dump = netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
5818
0
                                NETSNMP_DS_LIB_DUMP_PACKET);
5819
0
#ifndef NETSNMP_FEATURE_REMOVE_FILTER_SOURCE
5820
0
  filter = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
5821
0
                                  NETSNMP_DS_LIB_FILTER_TYPE);
5822
0
#endif
5823
0
  if (dump || filter) {
5824
0
      int filtered = 0;
5825
0
      char *addrtxt = netsnmp_transport_peer_string(transport, opaque, olength);
5826
5827
0
      if (!addrtxt) {
5828
0
          DEBUGMSGTL(("sess_process_packet",
5829
0
                      "Failed to resolve peer address\n"));
5830
0
          SNMP_FREE(opaque);
5831
0
          return NULL;
5832
0
      }
5833
5834
0
      snmp_log(LOG_DEBUG, "\nReceived %d byte packet from %s\n",
5835
0
               length, addrtxt);
5836
5837
0
      if (dump)
5838
0
          xdump(packetptr, length, "");
5839
5840
0
#ifndef NETSNMP_FEATURE_REMOVE_FILTER_SOURCE
5841
0
      if (filter) {
5842
0
          char *sourceaddr = NULL, *c = strchr(addrtxt, '[');
5843
0
          const char *dropstr = NULL;
5844
0
          if (c) {
5845
0
              sourceaddr = ++c;
5846
0
              c = strchr(sourceaddr, ']');
5847
0
              if (c)
5848
0
                  *c = 0;
5849
0
              filtered = netsnmp_transport_filter_check(sourceaddr);
5850
0
          }
5851
0
          else if (!strncmp(addrtxt, "callback", 8)) {
5852
              /* do not filter internal request */
5853
0
              DEBUGMSGTL(("sess_process_packet:filter",
5854
0
                          "bypass packet from %s \n",
5855
0
                          addrtxt));
5856
0
              filtered = 1;
5857
0
          }
5858
0
          if ((filter == -1) && filtered)
5859
0
              dropstr = "matched blacklist";
5860
0
          else if ((filter == 1) && !filtered)
5861
0
              dropstr = "didn't match whitelist";
5862
0
          if (dropstr) {
5863
0
              DEBUGMSGTL(("sess_process_packet:filter",
5864
0
                          "packet from %s %s\n",
5865
0
                          sourceaddr ? sourceaddr : "UNKNOWN", dropstr));
5866
0
              SNMP_FREE(opaque);
5867
0
              SNMP_FREE(addrtxt);
5868
0
              return NULL;
5869
0
          }
5870
0
      }
5871
0
#endif
5872
5873
0
      SNMP_FREE(addrtxt);
5874
0
  }
5875
5876
  /*
5877
   * Do transport-level filtering (e.g. IP-address based allow/deny).  
5878
   */
5879
5880
0
  if (isp->hook_pre) {
5881
0
    if (isp->hook_pre(sp, transport, opaque, olength) == 0) {
5882
0
      DEBUGMSGTL(("sess_process_packet", "pre-parse fail\n"));
5883
0
      SNMP_FREE(opaque);
5884
0
      return NULL;
5885
0
    }
5886
0
  }
5887
5888
0
  if (isp->hook_create_pdu) {
5889
0
    pdu = isp->hook_create_pdu(transport, opaque, olength);
5890
0
  } else {
5891
0
    pdu = snmp_create_sess_pdu(transport, opaque, olength);
5892
0
  }
5893
5894
0
  if (pdu == NULL) {
5895
0
    snmp_log(LOG_ERR, "pdu failed to be created\n");
5896
0
    SNMP_FREE(opaque);
5897
0
    return NULL;
5898
0
  }
5899
5900
  /* if the transport was a magic tunnel, mark the PDU as having come
5901
     through one. */
5902
0
  if (transport->flags & NETSNMP_TRANSPORT_FLAG_TUNNELED) {
5903
0
      pdu->flags |= UCD_MSG_FLAG_TUNNELED;
5904
0
  }
5905
5906
0
  if (isp->hook_parse) {
5907
0
    ret = isp->hook_parse(sp, pdu, packetptr, length);
5908
0
  } else {
5909
0
    ret = snmp_parse(slp, sp, pdu, packetptr, length);
5910
0
  }
5911
5912
0
  DEBUGMSGTL(("sess_process_packet", "received message id#%ld reqid#%ld len "
5913
0
              "%u\n", pdu->msgid, pdu->reqid, length));
5914
5915
0
  if (ret != SNMP_ERR_NOERROR) {
5916
0
    DEBUGMSGTL(("sess_process_packet", "parse fail\n"));
5917
0
  }
5918
5919
0
  if (isp->hook_post) {
5920
0
    if (isp->hook_post(sp, pdu, ret) == 0) {
5921
0
      DEBUGMSGTL(("sess_process_packet", "post-parse fail\n"));
5922
0
      ret = SNMPERR_ASN_PARSE_ERR;
5923
0
    }
5924
0
  }
5925
5926
0
  if (ret != SNMP_ERR_NOERROR) {
5927
0
    snmp_free_pdu(pdu);
5928
0
    return NULL;
5929
0
  }
5930
5931
0
  return pdu;
5932
0
}
5933
5934
static int
5935
snmp_resend_request(struct session_list *slp, netsnmp_request_list *orp,
5936
                    netsnmp_request_list *rp, int incr_retries)
5937
0
{
5938
0
    struct snmp_internal_session *isp;
5939
0
    netsnmp_session *sp;
5940
0
    netsnmp_transport *transport;
5941
0
    u_char         *pktbuf = NULL, *packet = NULL;
5942
0
    size_t          pktbuf_len = 0, length = 0;
5943
0
    struct timeval  tv, now;
5944
0
    int             result = 0;
5945
5946
0
    sp = slp->session;
5947
0
    isp = slp->internal;
5948
0
    transport = slp->transport;
5949
0
    if (!sp || !isp || !transport) {
5950
0
        DEBUGMSGTL(("sess_read", "resend fail: closing...\n"));
5951
0
        return 0;
5952
0
    }
5953
5954
0
    if ((pktbuf = (u_char *)malloc(2048)) == NULL) {
5955
0
        DEBUGMSGTL(("sess_resend",
5956
0
                    "couldn't malloc initial packet buffer\n"));
5957
0
        return 0;
5958
0
    } else {
5959
0
        pktbuf_len = 2048;
5960
0
    }
5961
5962
0
    if (incr_retries) {
5963
0
        rp->retries++;
5964
0
    }
5965
5966
    /*
5967
     * Always increment msgId for resent messages.  
5968
     */
5969
0
    rp->pdu->msgid = rp->message_id = snmp_get_next_msgid();
5970
5971
0
    result = netsnmp_build_packet(isp, sp, rp->pdu, &pktbuf, &pktbuf_len,
5972
0
                                  &packet, &length);
5973
0
    if (result < 0) {
5974
        /*
5975
         * This should never happen.  
5976
         */
5977
0
        DEBUGMSGTL(("sess_resend", "encoding failure\n"));
5978
0
        SNMP_FREE(pktbuf);
5979
0
        return -1;
5980
0
    }
5981
5982
0
    DEBUGMSGTL(("sess_process_packet", "resending message id#%ld reqid#%ld "
5983
0
                "rp_reqid#%ld rp_msgid#%ld len %" NETSNMP_PRIz "u\n",
5984
0
                rp->pdu->msgid, rp->pdu->reqid, rp->request_id, rp->message_id, length));
5985
0
    result = netsnmp_transport_send(transport, packet, length,
5986
0
                                    &(rp->pdu->transport_data),
5987
0
                                    &(rp->pdu->transport_data_length));
5988
5989
    /*
5990
     * We are finished with the local packet buffer, if we allocated one (due
5991
     * to there being no saved packet).  
5992
     */
5993
5994
0
    if (pktbuf != NULL) {
5995
0
        SNMP_FREE(pktbuf);
5996
0
        packet = NULL;
5997
0
    }
5998
5999
0
    if (result < 0) {
6000
0
        sp->s_snmp_errno = SNMPERR_BAD_SENDTO;
6001
0
        sp->s_errno = errno;
6002
0
        snmp_set_detail(strerror(errno));
6003
0
        if (rp->callback) {
6004
0
            rp->callback(NETSNMP_CALLBACK_OP_SEND_FAILED, sp,
6005
0
                         rp->pdu->reqid, rp->pdu, rp->cb_data);
6006
0
            remove_request(isp, orp, rp);
6007
0
            free(rp);
6008
0
  }
6009
0
        return -1;
6010
0
    } else {
6011
0
        netsnmp_get_monotonic_clock(&now);
6012
0
        tv = now;
6013
0
        rp->timeM = tv;
6014
0
        tv.tv_usec += rp->timeout;
6015
0
        tv.tv_sec += tv.tv_usec / 1000000L;
6016
0
        tv.tv_usec %= 1000000L;
6017
0
        rp->expireM = tv;
6018
0
        if (rp->callback)
6019
0
            rp->callback(NETSNMP_CALLBACK_OP_RESEND, sp,
6020
0
                         rp->pdu->reqid, rp->pdu, rp->cb_data);
6021
0
    }
6022
0
    return 0;
6023
0
}
6024
6025
/*
6026
 * This function processes a PDU and calls the relevant callbacks.
6027
 */
6028
static int
6029
_sess_process_packet_handle_pdu(struct session_list *slp, netsnmp_session * sp,
6030
                                struct snmp_internal_session *isp,
6031
                                netsnmp_transport *transport, netsnmp_pdu *pdu)
6032
0
{
6033
0
  netsnmp_request_list *rp, *orp = NULL;
6034
0
  int             handled = 0;
6035
6036
0
  if (pdu->flags & UCD_MSG_FLAG_RESPONSE_PDU) {
6037
    /*
6038
     * Call USM to free any securityStateRef supplied with the message.  
6039
     */
6040
0
    free_securityStateRef(pdu);
6041
6042
0
    for (rp = isp->requests; rp; orp = rp, rp = rp->next_request) {
6043
0
      snmp_callback   callback;
6044
0
      void           *magic;
6045
6046
0
      if (pdu->version == SNMP_VERSION_3) {
6047
  /*
6048
   * msgId must match for v3 messages.  
6049
   */
6050
0
  if (rp->message_id != pdu->msgid) {
6051
0
            DEBUGMSGTL(("sess_process_packet", "unmatched msg id: %ld != %ld\n",
6052
0
                        rp->message_id, pdu->msgid));
6053
0
      continue;
6054
0
  }
6055
6056
  /*
6057
   * Check that message fields match original, if not, no further
6058
   * processing.  
6059
   */
6060
0
  if (!snmpv3_verify_msg(rp, pdu)) {
6061
0
    break;
6062
0
  }
6063
0
      } else {
6064
0
  if (rp->request_id != pdu->reqid) {
6065
0
    continue;
6066
0
  }
6067
0
      }
6068
6069
0
      if (rp->callback) {
6070
0
  callback = rp->callback;
6071
0
  magic = rp->cb_data;
6072
0
      } else {
6073
0
  callback = sp->callback;
6074
0
  magic = sp->callback_magic;
6075
0
      }
6076
0
      handled = 1;
6077
6078
      /*
6079
       * MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock
6080
       * should be per session ! 
6081
       */
6082
6083
0
      if (pdu->command == SNMP_MSG_REPORT) {
6084
0
        if (sp->s_snmp_errno == SNMPERR_NOT_IN_TIME_WINDOW ||
6085
0
            snmpv3_get_report_type(pdu) == SNMPERR_NOT_IN_TIME_WINDOW) {
6086
          /*
6087
           * trigger immediate retry on recoverable Reports 
6088
           * * (notInTimeWindow), incr_retries == TRUE to prevent
6089
           * * inifinite resend                      
6090
           */
6091
0
          if (rp->retries <= sp->retries) {
6092
0
            snmp_resend_request(slp, orp, rp, TRUE);
6093
0
            break;
6094
0
          } else {
6095
            /* We're done with retries, so no longer waiting for a response */
6096
0
            if (callback) {
6097
0
              callback(NETSNMP_CALLBACK_OP_SEC_ERROR, sp, pdu->reqid, pdu,
6098
0
                       magic);
6099
0
            }
6100
0
          }
6101
0
        } else {
6102
0
          if (SNMPV3_IGNORE_UNAUTH_REPORTS) {
6103
0
            break;
6104
0
          } else { /* We're done with retries */
6105
0
            if (callback) {
6106
0
              callback(NETSNMP_CALLBACK_OP_SEC_ERROR, sp, pdu->reqid, pdu,
6107
0
                       magic);
6108
0
            }
6109
0
          }
6110
0
        }
6111
6112
        /*
6113
         * Handle engineID discovery.  
6114
         */
6115
0
        if (!sp->securityEngineIDLen && pdu->securityEngineIDLen) {
6116
0
          sp->securityEngineID = malloc(pdu->securityEngineIDLen);
6117
0
          if (sp->securityEngineID == NULL) {
6118
            /*
6119
             * TODO FIX: recover after message callback *?
6120
             */
6121
0
            snmp_log(LOG_ERR, "malloc failed handling pdu\n");
6122
0
            snmp_free_pdu(pdu);
6123
0
            return -1;
6124
0
          }
6125
0
          memcpy(sp->securityEngineID, pdu->securityEngineID,
6126
0
                 pdu->securityEngineIDLen);
6127
0
          sp->securityEngineIDLen = pdu->securityEngineIDLen;
6128
0
          if (!sp->contextEngineIDLen) {
6129
0
            sp->contextEngineID = malloc(pdu->securityEngineIDLen);
6130
0
            if (sp->contextEngineID == NULL) {
6131
              /*
6132
               * TODO FIX: recover after message callback *?
6133
               */
6134
0
              snmp_log(LOG_ERR, "malloc failed handling pdu\n");
6135
0
              snmp_free_pdu(pdu);
6136
0
              return -1;
6137
0
            }
6138
0
            memcpy(sp->contextEngineID, pdu->securityEngineID,
6139
0
                   pdu->securityEngineIDLen);
6140
0
            sp->contextEngineIDLen = pdu->securityEngineIDLen;
6141
0
          }
6142
0
        }
6143
0
      }
6144
6145
0
      if (callback == NULL
6146
0
    || callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE, sp,
6147
0
          pdu->reqid, pdu, magic) == 1) {
6148
  /*
6149
   * Successful, so delete request.  
6150
   */
6151
0
  remove_request(isp, orp, rp);
6152
0
  free(rp);
6153
  /*
6154
   * There shouldn't be any more requests with the same reqid.  
6155
   */
6156
0
  break;
6157
0
      }
6158
      /*
6159
       * MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);  ?* XX lock should be per session ! 
6160
       */
6161
0
    }
6162
0
  } else {
6163
0
    if (sp->callback) {
6164
      /*
6165
       * MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION); 
6166
       */
6167
0
      handled = 1;
6168
0
      sp->callback(NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE,
6169
0
       sp, pdu->reqid, pdu, sp->callback_magic);
6170
      /*
6171
       * MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION); 
6172
       */
6173
0
    }
6174
0
  }
6175
6176
0
  if (!handled) {
6177
0
    if (sp->flags & SNMP_FLAGS_SHARED_SOCKET)
6178
0
      return -2;
6179
0
    snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
6180
0
    DEBUGMSGTL(("sess_process_packet", "unhandled PDU\n"));
6181
0
  }
6182
6183
0
  snmp_free_pdu(pdu);
6184
0
  return 0;
6185
0
}
6186
6187
/*
6188
 * This function processes a complete (according to asn_check_packet or the
6189
 * AgentX equivalent) packet, parsing it into a PDU and calling the relevant
6190
 * callbacks.  On entry, packetptr points at the packet in the session's
6191
 * buffer and length is the length of the packet.  Return codes:
6192
 *   0: pdu handled (pdu deleted)
6193
 *  -1: parse error (pdu deleted)
6194
 *  -2: pdu not found for shared session (pdu NOT deleted)
6195
 */
6196
static int
6197
_sess_process_packet(struct session_list *slp, netsnmp_session * sp,
6198
                     struct snmp_internal_session *isp,
6199
                     netsnmp_transport *transport,
6200
                     void *opaque, int olength,
6201
                     u_char * packetptr, int length)
6202
0
{
6203
0
    netsnmp_pdu         *pdu;
6204
0
    int                  rc;
6205
6206
0
    pdu = _sess_process_packet_parse_pdu(slp, sp, isp, transport, opaque,
6207
0
                                         olength, packetptr, length);
6208
0
    if (NULL == pdu)
6209
0
        return -1;
6210
6211
    /*
6212
     * find session to process pdu. usually that will be the current session,
6213
     * but with the introduction of shared transports, another session may
6214
     * have the same socket.
6215
     */
6216
0
    do {
6217
0
        rc = _sess_process_packet_handle_pdu(slp, sp, isp, transport, pdu);
6218
0
        if (-2 != rc || !(transport->flags & NETSNMP_TRANSPORT_FLAG_SHARED))
6219
0
            break;
6220
6221
        /** -2 means pdu not in request list. check other sessions */
6222
0
        do  {
6223
0
            slp = slp->next;
6224
0
        } while (slp && slp->transport->sock != transport->sock);
6225
0
        if (!slp)
6226
0
            break; /* no more sessions with same socket */
6227
6228
0
        sp = slp->session;
6229
0
        isp = slp->internal;
6230
0
        transport = slp->transport;
6231
0
    } while(slp);
6232
6233
0
    if (-2 == rc) { /* did not find session for pdu */
6234
0
        snmp_increment_statistic(STAT_SNMPUNKNOWNPDUHANDLERS);
6235
0
        DEBUGMSGTL(("sess_process_packet", "unhandled PDU\n"));
6236
0
        snmp_free_pdu(pdu);
6237
0
    }
6238
6239
0
  return rc;
6240
0
}
6241
6242
static void
6243
_sess_set_packet_deadline(struct snmp_internal_session *isp)
6244
0
{
6245
0
    netsnmp_get_monotonic_clock(&isp->packet_deadline);
6246
0
    isp->packet_deadline.tv_sec += NETSNMP_STREAM_FRAME_TIMEOUT;
6247
0
}
6248
6249
static int
6250
_sess_packet_deadline_expired(struct snmp_internal_session *isp)
6251
0
{
6252
0
    struct timeval now;
6253
6254
0
    if (isp == NULL || !timerisset(&isp->packet_deadline))
6255
0
        return 0;
6256
0
    netsnmp_get_monotonic_clock(&now);
6257
0
    return !timercmp(&now, &isp->packet_deadline, <);
6258
0
}
6259
6260
static int
6261
_sess_same_stream_peer(const netsnmp_sockaddr_storage *a,
6262
                       const netsnmp_sockaddr_storage *b)
6263
0
{
6264
0
    if (a->sa.sa_family != b->sa.sa_family)
6265
0
        return 0;
6266
0
    if (a->sa.sa_family == AF_INET)
6267
0
        return memcmp(&a->sin.sin_addr, &b->sin.sin_addr,
6268
0
                      sizeof(a->sin.sin_addr)) == 0;
6269
0
#ifdef NETSNMP_ENABLE_IPV6
6270
0
    if (a->sa.sa_family == AF_INET6)
6271
0
        return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr,
6272
0
                      sizeof(a->sin6.sin6_addr)) == 0;
6273
0
#endif
6274
0
    return 0;
6275
0
}
6276
6277
static int
6278
_sess_stream_accept_allowed(NETSNMP_SOCKET sock,
6279
                            netsnmp_sockaddr_storage *peer,
6280
                            int *peer_valid)
6281
0
{
6282
0
    struct session_list *slp;
6283
0
    socklen_t peer_len = sizeof(*peer);
6284
0
    int accepted = 0, same_peer = 0;
6285
6286
0
    memset(peer, 0, sizeof(*peer));
6287
0
    *peer_valid = getpeername(sock, &peer->sa, &peer_len) == 0;
6288
0
    for (slp = Sessions; slp; slp = slp->next) {
6289
0
        struct snmp_internal_session *isp = slp->internal;
6290
6291
0
        if (isp == NULL || !isp->accepted_stream || slp->transport == NULL ||
6292
0
            !NETSNMP_IS_VALID_SOCKET(slp->transport->sock))
6293
0
            continue;
6294
0
        accepted++;
6295
0
        if (*peer_valid && isp->stream_peer_valid &&
6296
0
            _sess_same_stream_peer(peer, &isp->stream_peer))
6297
0
            same_peer++;
6298
0
    }
6299
0
    return accepted < NETSNMP_STREAM_MAX_SESSIONS &&
6300
0
        same_peer < NETSNMP_STREAM_MAX_SESSIONS_PER_PEER;
6301
0
}
6302
6303
static void
6304
_sess_close_stream(struct session_list *slp)
6305
0
{
6306
0
    netsnmp_session *sp = slp->session;
6307
0
    struct snmp_internal_session *isp = slp->internal;
6308
0
    netsnmp_transport *transport = slp->transport;
6309
6310
0
    if (sp->callback != NULL) {
6311
0
        DEBUGMSGTL(("sess_read", "perform callback with op=DISCONNECT\n"));
6312
0
        (void)sp->callback(NETSNMP_CALLBACK_OP_DISCONNECT, sp, 0, NULL,
6313
0
                           sp->callback_magic);
6314
0
    }
6315
0
    DEBUGMSGTL(("sess_read", "fd %" NETSNMP_FMT_SKT " closed\n",
6316
0
                transport->sock));
6317
0
    transport->f_close(transport);
6318
0
    SNMP_FREE(isp->packet);
6319
0
    isp->packet_size = 0;
6320
0
    isp->packet_len = 0;
6321
0
    isp->accepted_stream = 0;
6322
0
    timerclear(&isp->packet_deadline);
6323
0
}
6324
6325
/*
6326
 * Checks to see if any of the fd's set in the fdset belong to
6327
 * snmp.  Each socket with it's fd set has a packet read from it
6328
 * and snmp_parse is called on the packet received.  The resulting pdu
6329
 * is passed to the callback routine for that session.  If the callback
6330
 * routine returns successfully, the pdu and it's request are deleted.
6331
 */
6332
void
6333
snmp_read(fd_set * fdset)
6334
0
{
6335
0
    netsnmp_large_fd_set lfdset;
6336
6337
0
    netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
6338
0
    netsnmp_copy_fd_set_to_large_fd_set(&lfdset, fdset);
6339
0
    snmp_read2(&lfdset);
6340
0
    netsnmp_large_fd_set_cleanup(&lfdset);
6341
0
}
6342
6343
void
6344
snmp_read2(netsnmp_large_fd_set * fdset)
6345
0
{
6346
0
    struct session_list *slp, *next;
6347
6348
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
6349
0
    for (slp = Sessions; slp; slp = next) {
6350
0
        next = slp->next;
6351
0
        if (_sess_packet_deadline_expired(slp->internal)) {
6352
0
            _sess_close_stream(slp);
6353
0
            continue;
6354
0
        }
6355
0
        snmp_sess_read2(slp, fdset);
6356
0
    }
6357
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
6358
0
}
6359
6360
/*
6361
 * accept new connections
6362
 * returns 0 if success, -1 if fail
6363
 */
6364
static int
6365
_sess_read_accept(struct session_list *slp)
6366
0
{
6367
0
    netsnmp_session *sp = slp ? slp->session : NULL;
6368
0
    struct snmp_internal_session *isp = slp ? slp->internal : NULL;
6369
0
    netsnmp_transport *transport = slp ? slp->transport : NULL;
6370
0
    netsnmp_transport *new_transport;
6371
0
    struct session_list *nslp;
6372
0
    netsnmp_sockaddr_storage peer;
6373
0
    int             peer_valid;
6374
0
    NETSNMP_SOCKET    data_sock;
6375
6376
0
    if (NULL == slp || NULL == sp || NULL == transport || NULL == isp ||
6377
0
        !(transport->flags & NETSNMP_TRANSPORT_FLAG_LISTEN))
6378
0
        return -1;
6379
6380
0
    data_sock = transport->f_accept(transport);
6381
0
    if (!NETSNMP_IS_VALID_SOCKET(data_sock)) {
6382
0
        sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
6383
0
        sp->s_errno = errno;
6384
0
        snmp_set_detail(strerror(errno));
6385
0
        return -1;
6386
0
    }
6387
0
    if (!_sess_stream_accept_allowed(data_sock, &peer, &peer_valid)) {
6388
0
#ifndef HAVE_CLOSESOCKET
6389
0
        close(data_sock);
6390
#else
6391
        closesocket(data_sock);
6392
#endif
6393
0
        return 0;
6394
0
    }
6395
6396
    /*
6397
     * We've successfully accepted a new stream-based connection.
6398
     * It's not too clear what should happen here if we are using the
6399
     * single-session API at this point.  Basically a "session
6400
     * accepted" callback is probably needed to hand the new session
6401
     * over to the application.
6402
     *
6403
     * However, for now, as in th original snmp_api, we will ASSUME
6404
     * that we're using the traditional API, and simply add the new
6405
     * session to the list.  Note we don't have to get the Session
6406
     * list lock here, because under that assumption we already hold
6407
     * it (this is also why we don't just use snmp_add).
6408
     *
6409
     * The moral of the story is: don't use listening stream-based
6410
     * transports in a multi-threaded environment because something
6411
     * will go HORRIBLY wrong (and also that SNMP/TCP is not trivial).
6412
     *
6413
     * Another open issue: what should happen to sockets that have
6414
     * been accept()ed from a listening socket when that original
6415
     * socket is closed?  If they are left open, then attempting to
6416
     * re-open the listening socket will fail, which is semantically
6417
     * confusing.  Perhaps there should be some kind of chaining in
6418
     * the transport structure so that they can all be closed.
6419
     * Discuss.  ;-)
6420
     */
6421
0
    new_transport=netsnmp_transport_copy(transport);
6422
0
    if (new_transport == NULL) {
6423
0
        sp->s_snmp_errno = SNMPERR_MALLOC;
6424
0
        sp->s_errno = errno;
6425
0
        snmp_set_detail(strerror(errno));
6426
0
#ifndef HAVE_CLOSESOCKET
6427
0
        close(data_sock);
6428
#else
6429
        closesocket(data_sock);
6430
#endif
6431
0
        return -1;
6432
0
    }
6433
0
    nslp = NULL;
6434
6435
0
    new_transport->sock = data_sock;
6436
0
    new_transport->flags &= ~NETSNMP_TRANSPORT_FLAG_LISTEN;
6437
6438
0
    nslp = snmp_sess_add_ex(sp, new_transport, isp->hook_pre, isp->hook_parse,
6439
0
                         isp->hook_post, isp->hook_build,
6440
0
                         isp->hook_realloc_build, isp->check_packet,
6441
0
                         isp->hook_create_pdu);
6442
6443
0
    if (nslp != NULL) {
6444
0
        nslp->internal->accepted_stream = 1;
6445
0
        nslp->internal->stream_peer_valid = peer_valid;
6446
0
        if (peer_valid)
6447
0
            nslp->internal->stream_peer = peer;
6448
0
        _sess_set_packet_deadline(nslp->internal);
6449
0
        snmp_session_insert(nslp);
6450
        /** Tell the new session about its existence if possible. */
6451
0
        DEBUGMSGTL(("sess_read",
6452
0
                    "perform callback with op=CONNECT\n"));
6453
0
        if (nslp->session->callback)
6454
0
            (void)nslp->session->callback(NETSNMP_CALLBACK_OP_CONNECT,
6455
0
                                          nslp->session, 0, NULL,
6456
0
                                          sp->callback_magic);
6457
0
    }
6458
6459
0
    return 0;
6460
0
}
6461
6462
/*
6463
 * Same as snmp_read, but works just one non-stream session.
6464
 * returns 0 if success, -1 if protocol err, -2 if no packet to process
6465
 * MTR: can't lock here and at snmp_read
6466
 * Beware recursive send maybe inside snmp_read callback function.
6467
 */
6468
static int
6469
_sess_read_dgram_packet(struct session_list *slp, snmp_rcv_packet *rcvp)
6470
0
{
6471
0
    netsnmp_session *sp = slp ? slp->session : NULL;
6472
0
    struct snmp_internal_session *isp = slp ? slp->internal : NULL;
6473
0
    netsnmp_transport *transport = slp ? slp->transport : NULL;
6474
6475
0
    if (!sp || !isp || !transport || !rcvp ) {
6476
0
        DEBUGMSGTL(("sess_read_packet", "missing arguments\n"));
6477
0
        return -2;
6478
0
    }
6479
6480
0
    if (transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM)
6481
0
        return -2;
6482
6483
0
    if (NULL != rcvp->packet) {
6484
0
        snmp_log(LOG_WARNING, "overwriting existing saved packet; sess %p\n",
6485
0
                 sp);
6486
0
        SNMP_FREE(rcvp->packet);
6487
0
    }
6488
6489
0
    if ((rcvp->packet = (u_char *) malloc(SNMP_MAX_RCV_MSG_SIZE)) == NULL) {
6490
0
        DEBUGMSGTL(("sess_read_packet", "can't malloc %u bytes for packet\n",
6491
0
                    SNMP_MAX_RCV_MSG_SIZE));
6492
0
        return -2;
6493
0
    }
6494
6495
0
    rcvp->packet_len = netsnmp_transport_recv(transport, rcvp->packet,
6496
0
                                              SNMP_MAX_RCV_MSG_SIZE,
6497
0
                                              &rcvp->opaque, &rcvp->olength);
6498
0
    if (rcvp->packet_len == -1) {
6499
0
        sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
6500
0
        sp->s_errno = errno;
6501
0
        snmp_set_detail(strerror(errno));
6502
0
        SNMP_FREE(rcvp->packet);
6503
0
        SNMP_FREE(rcvp->opaque);
6504
0
        return -1;
6505
0
    }
6506
6507
0
    if (0 == rcvp->packet_len &&
6508
0
        transport->flags & NETSNMP_TRANSPORT_FLAG_EMPTY_PKT) {
6509
        /* this allows for a transport that needs to return from
6510
         * packet processing that doesn't necessarily have any
6511
         * consumable data in it. */
6512
6513
        /* reset the flag since it's a per-message flag */
6514
0
        transport->flags &= (~NETSNMP_TRANSPORT_FLAG_EMPTY_PKT);
6515
6516
        /** free packet */
6517
0
        SNMP_FREE(rcvp->packet);
6518
0
        SNMP_FREE(rcvp->opaque);
6519
6520
0
        return -2;
6521
0
    }
6522
6523
0
    return 0;
6524
0
}
6525
6526
static int
6527
__sess_read(struct session_list *slp)
6528
0
{
6529
0
    netsnmp_session *sp = slp ? slp->session : NULL;
6530
0
    struct snmp_internal_session *isp = slp ? slp->internal : NULL;
6531
0
    netsnmp_transport *transport = slp ? slp->transport : NULL;
6532
0
    size_t          pdulen = 0;
6533
0
    size_t          rxbuf_len;
6534
0
    size_t          stream_limit;
6535
0
    u_char         *rxbuf = NULL;
6536
0
    int             length = 0, olength = 0, rc = 0;
6537
0
    void           *opaque = NULL;
6538
6539
0
    if (NULL == slp || NULL == sp || NULL == isp || NULL == transport) {
6540
0
        snmp_log(LOG_ERR, "bad parameters to __sess_read\n");
6541
0
        return SNMPERR_GENERR;
6542
0
    }
6543
6544
    /* to avoid subagent crash */
6545
0
    if (!NETSNMP_IS_VALID_SOCKET(transport->sock)) {
6546
0
        snmp_log(LOG_INFO, "transport->sock is invalid\n");
6547
0
        return 0; 
6548
0
    }
6549
6550
0
    sp->s_snmp_errno = 0;
6551
0
    sp->s_errno = 0;
6552
6553
0
    stream_limit = sp->rcvMsgMaxSize ?
6554
0
        SNMP_MIN(SNMP_MAX_PACKET_LEN, sp->rcvMsgMaxSize) :
6555
0
        SNMP_MAX_PACKET_LEN;
6556
0
    rxbuf_len = SNMP_MIN(SNMP_MAX_RCV_MSG_SIZE, stream_limit);
6557
6558
0
    if (transport->flags & NETSNMP_TRANSPORT_FLAG_LISTEN)
6559
0
        return _sess_read_accept(slp);
6560
6561
0
    if (!(transport->flags & NETSNMP_TRANSPORT_FLAG_STREAM)) {
6562
0
        snmp_rcv_packet rcvp;
6563
0
        u_char *pptr;
6564
0
        size_t len_remaining, pdulen;
6565
0
        void *ocopy = NULL;
6566
6567
0
        memset(&rcvp, 0x0, sizeof(rcvp));
6568
6569
        /** read the packet */
6570
0
        rc = _sess_read_dgram_packet(slp, &rcvp);
6571
0
        if (-1 == rc) /* protocol error */
6572
0
            return -1;
6573
0
        else if (-2 == rc) /* no packet to process */
6574
0
            return 0;
6575
6576
0
        pptr = rcvp.packet;
6577
0
        len_remaining = rcvp.packet_len;
6578
0
        rc = 0;
6579
6580
0
        while (len_remaining > 0) {
6581
0
            if (isp->check_packet) {
6582
0
                pdulen = isp->check_packet(pptr, len_remaining);
6583
0
            } else {
6584
0
                pdulen = asn_check_packet(pptr, len_remaining);
6585
0
            }
6586
0
            if (pdulen == 0 || pdulen > len_remaining || pdulen > SNMP_MAX_PACKET_LEN) {
6587
                /* Not a valid packet or incomplete in datagram mode */
6588
0
                if (pptr == rcvp.packet) {
6589
0
                    SNMP_FREE(rcvp.opaque);
6590
0
                }
6591
0
                break;
6592
0
            }
6593
0
            if (pdulen < len_remaining) {
6594
0
                if (rcvp.olength > 0 && rcvp.opaque != NULL) {
6595
0
                    ocopy = malloc(rcvp.olength);
6596
0
                    if (ocopy != NULL) {
6597
0
                        memcpy(ocopy, rcvp.opaque, rcvp.olength);
6598
0
                    }
6599
0
                }
6600
0
            } else {
6601
0
                ocopy = rcvp.opaque;
6602
0
                rcvp.opaque = NULL;
6603
0
            }
6604
0
            rc = _sess_process_packet(slp, sp, isp, transport,
6605
0
                                      ocopy, ocopy ? rcvp.olength : 0,
6606
0
                                      pptr, pdulen);
6607
0
            ocopy = NULL;
6608
0
            pptr += pdulen;
6609
0
            len_remaining -= pdulen;
6610
0
        }
6611
0
        SNMP_FREE(rcvp.packet);
6612
0
        SNMP_FREE(rcvp.opaque);
6613
0
        return rc;
6614
0
    }
6615
6616
    /** stream transport */
6617
6618
0
        if (isp->packet_len >= stream_limit) {
6619
0
            _sess_close_stream(slp);
6620
0
            return -1;
6621
0
        }
6622
0
        rxbuf_len = SNMP_MIN(rxbuf_len, stream_limit - isp->packet_len);
6623
6624
0
        if (isp->packet == NULL) {
6625
            /*
6626
             * We have no saved packet.  Allocate one.  
6627
             */
6628
0
            if ((isp->packet = (u_char *) malloc(rxbuf_len)) == NULL) {
6629
0
                DEBUGMSGTL(("sess_read", "can't malloc %" NETSNMP_PRIz
6630
0
                            "u bytes for rxbuf\n", rxbuf_len));
6631
0
                return 0;
6632
0
            } else {
6633
0
                rxbuf = isp->packet;
6634
0
                isp->packet_size = rxbuf_len;
6635
0
                isp->packet_len = 0;
6636
0
            }
6637
0
        } else {
6638
            /*
6639
             * We have saved a partial packet from last time.  Extend that, if
6640
             * necessary, and receive new data after the old data.  
6641
             */
6642
0
            u_char         *newbuf;
6643
6644
0
            if (isp->packet_size < isp->packet_len + rxbuf_len) {
6645
0
                newbuf =
6646
0
                    (u_char *) realloc(isp->packet,
6647
0
                                       isp->packet_len + rxbuf_len);
6648
0
                if (newbuf == NULL) {
6649
0
                    DEBUGMSGTL(("sess_read",
6650
0
                                "can't malloc %" NETSNMP_PRIz
6651
0
                                "u more for rxbuf (%" NETSNMP_PRIz "u tot)\n",
6652
0
                                rxbuf_len, isp->packet_len + rxbuf_len));
6653
0
                    return 0;
6654
0
                } else {
6655
0
                    isp->packet = newbuf;
6656
0
                    isp->packet_size = isp->packet_len + rxbuf_len;
6657
0
                    rxbuf = isp->packet + isp->packet_len;
6658
0
                }
6659
0
            } else {
6660
0
                rxbuf = isp->packet + isp->packet_len;
6661
0
                rxbuf_len = isp->packet_size - isp->packet_len;
6662
0
            }
6663
0
        }
6664
6665
0
    length = netsnmp_transport_recv(transport, rxbuf, rxbuf_len, &opaque,
6666
0
                                    &olength);
6667
6668
0
    if (0 == length && transport->flags & NETSNMP_TRANSPORT_FLAG_EMPTY_PKT) {
6669
        /* this allows for a transport that needs to return from
6670
         * packet processing that doesn't necessarily have any
6671
         * consumable data in it. */
6672
6673
        /* reset the flag since it's a per-message flag */
6674
0
        transport->flags &= (~NETSNMP_TRANSPORT_FLAG_EMPTY_PKT);
6675
6676
0
        return 0;
6677
0
    }
6678
6679
    /*
6680
     * Remote end closed connection.  
6681
     */
6682
0
    if (length <= 0) {
6683
        /*
6684
         * Alert the application if possible.  
6685
         */
6686
0
        _sess_close_stream(slp);
6687
0
        SNMP_FREE(opaque);
6688
0
        return -1;
6689
0
    }
6690
6691
0
    {
6692
0
        u_char *pptr = isp->packet;
6693
0
  void *ocopy = NULL;
6694
6695
0
        isp->packet_len += length;
6696
6697
0
        while (isp->packet_len > 0) {
6698
6699
            /*
6700
             * Get the total data length we're expecting (and need to wait
6701
             * for).
6702
             */
6703
0
            if (isp->check_packet) {
6704
0
                pdulen = isp->check_packet(pptr, isp->packet_len);
6705
0
            } else {
6706
0
                pdulen = asn_check_packet(pptr, isp->packet_len);
6707
0
            }
6708
6709
0
            DEBUGMSGTL(("sess_read",
6710
0
                        "  loop packet_len %" NETSNMP_PRIz "u, PDU length %"
6711
0
                        NETSNMP_PRIz "u\n", isp->packet_len, pdulen));
6712
6713
0
            if ((int)pdulen < 0 || pdulen > SNMP_MAX_PACKET_LEN ||
6714
0
                (sp->rcvMsgMaxSize && pdulen > sp->rcvMsgMaxSize)) {
6715
                /*
6716
                 * Illegal length, drop the connection.  
6717
                 */
6718
0
                snmp_log(LOG_ERR, 
6719
0
       "Received broken packet. Closing session.\n");
6720
0
                _sess_close_stream(slp);
6721
0
                SNMP_FREE(opaque);
6722
0
                return -1;
6723
0
            }
6724
6725
0
            if (pdulen > isp->packet_len || pdulen == 0) {
6726
                /*
6727
                 * We don't have a complete packet yet.  If we've already
6728
                 * processed a packet, break out so we'll shift this packet
6729
                 * to the start of the buffer. If we're already at the
6730
                 * start, simply return and wait for more data to arrive.
6731
                 */
6732
0
                DEBUGMSGTL(("sess_read",
6733
0
                            "pkt not complete (need %" NETSNMP_PRIz "u got %"
6734
0
                            NETSNMP_PRIz "u so far)\n", pdulen,
6735
0
                            isp->packet_len));
6736
6737
0
                if (pptr != isp->packet)
6738
0
                    break; /* opaque freed for us outside of loop. */
6739
6740
0
                if (!timerisset(&isp->packet_deadline))
6741
0
                    _sess_set_packet_deadline(isp);
6742
0
                SNMP_FREE(opaque);
6743
0
                return 0;
6744
0
            }
6745
6746
            /*  We have *at least* one complete packet in the buffer now.  If
6747
    we have possibly more than one packet, we must copy the opaque
6748
    pointer because we may need to reuse it for a later packet.  */
6749
6750
0
      if (pdulen < isp->packet_len) {
6751
0
    if (olength > 0 && opaque != NULL) {
6752
0
        ocopy = malloc(olength);
6753
0
        if (ocopy != NULL) {
6754
0
      memcpy(ocopy, opaque, olength);
6755
0
        }
6756
0
    }
6757
0
      } else if (pdulen == isp->packet_len) {
6758
    /*  Common case -- exactly one packet.  No need to copy the
6759
        opaque pointer.  */
6760
0
    ocopy = opaque;
6761
0
    opaque = NULL;
6762
0
      }
6763
6764
0
            if ((rc = _sess_process_packet(slp, sp, isp, transport,
6765
0
                                           ocopy, ocopy?olength:0, pptr,
6766
0
                                           pdulen))) {
6767
                /*
6768
                 * Something went wrong while processing this packet -- set the
6769
                 * errno.  
6770
                 */
6771
0
                if (sp->s_snmp_errno != 0) {
6772
0
                    SET_SNMP_ERROR(sp->s_snmp_errno);
6773
0
                }
6774
0
            }
6775
0
            timerclear(&isp->packet_deadline);
6776
6777
      /*  ocopy has been free()d by _sess_process_packet by this point,
6778
    so set it to NULL.  */
6779
6780
0
      ocopy = NULL;
6781
6782
      /*  Step past the packet we've just dealt with.  */
6783
6784
0
            pptr += pdulen;
6785
0
            isp->packet_len -= pdulen;
6786
0
        }
6787
6788
  /*  If we had more than one packet, then we were working with copies
6789
      of the opaque pointer, so we still need to free() the opaque
6790
      pointer itself.  */
6791
6792
0
  SNMP_FREE(opaque);
6793
6794
0
        if (isp->packet_len >= stream_limit) {
6795
            /*
6796
             * Obviously this should never happen!  
6797
             */
6798
0
            snmp_log(LOG_ERR,
6799
0
                     "too large packet_len = %" NETSNMP_PRIz
6800
0
                     "u, dropping connection %" NETSNMP_FMT_SKT "\n",
6801
0
                     isp->packet_len, transport->sock);
6802
0
            _sess_close_stream(slp);
6803
0
            return -1;
6804
0
        } else if (isp->packet_len == 0) {
6805
            /*
6806
             * This is good: it means the packet buffer contained an integral
6807
             * number of PDUs, so we don't have to save any data for next
6808
             * time.  We can free() the buffer now to keep the memory
6809
             * footprint down.
6810
             */
6811
0
            SNMP_FREE(isp->packet);
6812
0
            isp->packet_size = 0;
6813
0
            isp->packet_len = 0;
6814
0
            timerclear(&isp->packet_deadline);
6815
0
            return rc;
6816
0
        }
6817
6818
        /*
6819
         * If we get here, then there is a partial packet of length
6820
         * isp->packet_len bytes starting at pptr left over.  Move that to the
6821
         * start of the buffer, and then realloc() the buffer down to size to
6822
         * reduce the memory footprint.  
6823
         */
6824
6825
0
        memmove(isp->packet, pptr, isp->packet_len);
6826
0
        if (!timerisset(&isp->packet_deadline))
6827
0
            _sess_set_packet_deadline(isp);
6828
0
        DEBUGMSGTL(("sess_read",
6829
0
                    "end: memmove(%p, %p, %" NETSNMP_PRIz "u); realloc(%p, %"
6830
0
                    NETSNMP_PRIz "u)\n",
6831
0
                    isp->packet, pptr, isp->packet_len,
6832
0
        isp->packet, isp->packet_len));
6833
6834
0
        if ((rxbuf = (u_char *)realloc(isp->packet, isp->packet_len)) == NULL) {
6835
            /*
6836
             * I don't see why this should ever fail, but it's not a big deal.
6837
             */
6838
0
            DEBUGMSGTL(("sess_read", "realloc() failed\n"));
6839
0
        } else {
6840
0
            DEBUGMSGTL(("sess_read", "realloc() okay, old buffer %p, new %p\n",
6841
0
                        isp->packet, rxbuf));
6842
0
            isp->packet = rxbuf;
6843
0
            isp->packet_size = isp->packet_len;
6844
0
        }
6845
0
    }
6846
6847
0
    return rc;
6848
0
}
6849
6850
/*
6851
 * Same as snmp_read, but works just one session.
6852
 * returns 0 if success, -1 if fail
6853
 * MTR: can't lock here and at snmp_read
6854
 * Beware recursive send maybe inside snmp_read callback function.
6855
 */
6856
int
6857
_sess_read(struct session_list *slp, netsnmp_large_fd_set * fdset)
6858
0
{
6859
0
    netsnmp_transport *transport;
6860
6861
0
    if (!slp || !fdset)
6862
0
        return 0;
6863
6864
0
    transport = slp->transport;
6865
6866
0
    if (!transport || !NETSNMP_LARGE_FD_ISSET(transport->sock, fdset)) {
6867
0
        DEBUGMSGTL(("sess_read", "not reading transport socket\n"));
6868
0
        return 0;
6869
0
    }
6870
6871
0
    return __sess_read(slp);
6872
0
}
6873
6874
6875
6876
/*
6877
 * returns 0 if success, -1 if fail 
6878
 */
6879
int
6880
snmp_sess_read(struct session_list *slp, fd_set * fdset)
6881
0
{
6882
0
  int rc;
6883
0
  netsnmp_large_fd_set lfdset;
6884
  
6885
0
  netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
6886
0
  netsnmp_copy_fd_set_to_large_fd_set(&lfdset, fdset);
6887
0
  rc = snmp_sess_read2(slp, &lfdset);
6888
0
  netsnmp_large_fd_set_cleanup(&lfdset);
6889
0
  return rc;
6890
0
}
6891
6892
int
6893
snmp_sess_read2(struct session_list *slp, netsnmp_large_fd_set * fdset)
6894
0
{
6895
0
    netsnmp_session *pss;
6896
0
    int             rc;
6897
6898
0
    rc = _sess_read(slp, fdset);
6899
0
    pss = slp->session;
6900
0
    if (rc && pss->s_snmp_errno) {
6901
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
6902
0
    }
6903
0
    return rc;
6904
0
}
6905
6906
/**
6907
 * For the transport of the specified session, check if pending buffered data
6908
 * is available (via the .f_pending() callback) and read it into the session.
6909
 * The .f_pending() callback is only defined by transports such as TLS-TCP that
6910
 * buffer data in memory. Must be called before waiting for socket events in an
6911
 * event loop.
6912
 *
6913
 * @param[in] sessp Pointer to the session to poll. Must not be NULL.
6914
 *
6915
 * @see snmp_poll
6916
 */
6917
void
6918
snmp_sess_poll(struct session_list *sessp)
6919
0
{
6920
0
    netsnmp_assert(sessp);
6921
6922
0
    while (sessp->transport && sessp->transport->f_pending &&
6923
0
           sessp->transport->f_pending(sessp->transport))
6924
0
        __sess_read(sessp);
6925
0
}
6926
6927
/**
6928
 * Poll all active sessions in the global session list for pending buffered
6929
 * transport data and process any data found.
6930
 *
6931
 * @see snmp_sess_poll
6932
 */
6933
void
6934
snmp_poll(void)
6935
0
{
6936
0
    struct session_list *slp;
6937
6938
0
    for (slp = Sessions; slp; slp = slp->next)
6939
0
        snmp_sess_poll(slp);
6940
0
}
6941
6942
/**
6943
 * Returns info about what snmp requires from a select statement.
6944
 * numfds is the number of fds in the list that are significant.
6945
 * All file descriptors opened for SNMP are OR'd into the fdset.
6946
 * If activity occurs on any of these file descriptors, snmp_read
6947
 * should be called with that file descriptor set
6948
 *
6949
 * The timeout is the latest time that SNMP can wait for a timeout.  The
6950
 * select should be done with the minimum time between timeout and any other
6951
 * timeouts necessary.  This should be checked upon each invocation of select.
6952
 * If a timeout is received, snmp_timeout should be called to check if the
6953
 * timeout was for SNMP.  (snmp_timeout is idempotent)
6954
 *
6955
 * The value of block indicates how the timeout value is interpreted.
6956
 * If block is true on input, the timeout value will be treated as undefined,
6957
 * but it must be available for setting in snmp_select_info.  On return,
6958
 * block is set to true if the value returned for timeout is undefined;
6959
 * when block is set to false, timeout may be used as a parameter to 'select'.
6960
 *
6961
 * snmp_select_info returns the number of open sockets.  (i.e. The number of
6962
 * sessions open)
6963
 *
6964
 * @see See also snmp_sess_select_info2_flags().
6965
 */
6966
int
6967
snmp_select_info(int *numfds, fd_set *fdset, struct timeval *timeout,
6968
                 int *block)
6969
0
{
6970
0
    return snmp_sess_select_info(NULL, numfds, fdset, timeout, block);
6971
0
}
6972
6973
/**
6974
 * @see See also snmp_sess_select_info2_flags().
6975
 */
6976
int
6977
snmp_select_info2(int *numfds, netsnmp_large_fd_set *fdset,
6978
      struct timeval *timeout, int *block)
6979
0
{
6980
0
    return snmp_sess_select_info2(NULL, numfds, fdset, timeout, block);
6981
0
}
6982
6983
/**
6984
 * @see See also snmp_sess_select_info2_flags().
6985
 */
6986
int
6987
snmp_sess_select_info(struct session_list *slp, int *numfds, fd_set *fdset,
6988
                      struct timeval *timeout, int *block)
6989
0
{
6990
0
    return snmp_sess_select_info_flags(slp, numfds, fdset, timeout, block,
6991
0
                                       NETSNMP_SELECT_NOFLAGS);
6992
0
}
6993
        
6994
/**
6995
 * @see See also snmp_sess_select_info2_flags().
6996
 */
6997
int
6998
snmp_sess_select_info_flags(struct session_list *slp, int *numfds, fd_set *fdset,
6999
                            struct timeval *timeout, int *block, int flags)
7000
0
{
7001
0
  int rc;
7002
0
  netsnmp_large_fd_set lfdset;
7003
7004
0
  netsnmp_large_fd_set_init(&lfdset, FD_SETSIZE);
7005
0
  netsnmp_copy_fd_set_to_large_fd_set(&lfdset, fdset);
7006
0
  rc = snmp_sess_select_info2_flags(slp, numfds, &lfdset, timeout,
7007
0
                                    block, flags);
7008
0
  if (netsnmp_copy_large_fd_set_to_fd_set(fdset, &lfdset) < 0) {
7009
0
      snmp_log(LOG_ERR,
7010
0
       "Use snmp_sess_select_info2() for processing"
7011
0
       " large file descriptors\n");
7012
0
  }
7013
0
  netsnmp_large_fd_set_cleanup(&lfdset);
7014
0
  return rc;
7015
0
}
7016
7017
/**
7018
 * @see See also snmp_sess_select_info2_flags().
7019
 */
7020
int
7021
snmp_sess_select_info2(struct session_list *slp, int *numfds, netsnmp_large_fd_set *fdset,
7022
           struct timeval *timeout, int *block)
7023
0
{
7024
0
    return snmp_sess_select_info2_flags(slp, numfds, fdset, timeout, block,
7025
0
                                        NETSNMP_SELECT_NOFLAGS);
7026
0
}
7027
7028
/**
7029
 * Compute/update the arguments to be passed to select().
7030
 *
7031
 * @param[in]     sessp   Which sessions to process: either a pointer to a
7032
 *   specific session or NULL which means to process all sessions.
7033
 * @param[in,out] numfds  On POSIX systems one more than the the largest file
7034
 *   descriptor that is present in *fdset. On systems that use Winsock (MinGW
7035
 *   and MSVC), do not use the value written into *numfds.
7036
 * @param[in,out] fdset   A large file descriptor set to which all file
7037
 *   descriptors will be added that are associated with one of the examined
7038
 *   sessions.
7039
 * @param[in,out] timeout On input, if *block = 1, the maximum time the caller
7040
 *   will block while waiting for Net-SNMP activity. On output, if this function
7041
 *   has set *block to 0, the maximum time the caller is allowed to wait before
7042
 *   invoking the Net-SNMP processing functions (snmp_read(), snmp_timeout()
7043
 *   and run_alarms()). If this function has set *block to 1, *timeout won't
7044
 *   have been modified and no alarms are active.
7045
 * @param[in,out] block   On input, whether the caller prefers to block forever
7046
 *   when no alarms are active. On output, 0 means that no alarms are active
7047
 *   nor that there is a timeout pending for any of the processed sessions.
7048
 * @param[in]     flags   Either 0 or NETSNMP_SELECT_NOALARMS.
7049
 *
7050
 * @return Number of sessions processed by this function.
7051
 *
7052
 * @see See also agent_check_and_process() for an example of how to use this
7053
 *   function.
7054
 */
7055
int
7056
snmp_sess_select_info2_flags(struct session_list *sessp, int *numfds,
7057
                             netsnmp_large_fd_set * fdset,
7058
                             struct timeval *timeout, int *block, int flags)
7059
0
{
7060
0
    struct session_list *slp, *next = NULL;
7061
0
    netsnmp_request_list *rp;
7062
0
    struct timeval  now, earliest, alarm_tm;
7063
0
    int             active = 0, requests = 0;
7064
0
    int             next_alarm = 0;
7065
0
    int             has_pending_data = 0;
7066
0
    int             packet_deadlines = 0;
7067
7068
0
    timerclear(&earliest);
7069
7070
    /*
7071
     * For each session examined, add its socket to the fdset,
7072
     * and if it is the earliest timeout to expire, mark it as lowest.
7073
     * If a single session is specified, do just for that session.
7074
     */
7075
7076
0
    DEBUGMSGTL(("sess_select", "for %s session%s: ",
7077
0
                sessp ? "single" : "all", sessp ? "" : "s"));
7078
7079
0
    for (slp = sessp ? sessp : Sessions; slp; slp = next) {
7080
0
        next = slp->next;
7081
7082
0
        if (slp->transport == NULL) {
7083
            /*
7084
             * Close in progress -- skip this one.  
7085
             */
7086
0
            DEBUGMSG(("sess_select", "skip "));
7087
0
            continue;
7088
0
        }
7089
7090
0
        if (!NETSNMP_IS_VALID_SOCKET(slp->transport->sock)) {
7091
            /*
7092
             * This session was marked for deletion.  
7093
             */
7094
0
            DEBUGMSG(("sess_select", "delete\n"));
7095
0
            if (sessp == NULL) {
7096
0
                snmp_close(slp->session);
7097
0
            } else {
7098
0
                snmp_sess_close(slp);
7099
0
            }
7100
0
            DEBUGMSGTL(("sess_select", "for %s session%s: ",
7101
0
                        sessp ? "single" : "all", sessp ? "" : "s"));
7102
0
            continue;
7103
0
        }
7104
7105
0
        DEBUGMSG(("sess_select", "%" NETSNMP_FMT_SKT " ",
7106
0
                  slp->transport->sock));
7107
0
        if ((slp->transport->sock + 1) > *numfds) {
7108
0
            *numfds = (slp->transport->sock + 1);
7109
0
        }
7110
7111
0
        NETSNMP_LARGE_FD_SET(slp->transport->sock, fdset);
7112
0
        if (slp->transport->f_pending &&
7113
0
            slp->transport->f_pending(slp->transport)) {
7114
0
            has_pending_data = 1;
7115
0
        }
7116
0
        if (slp->internal != NULL && slp->internal->requests) {
7117
            /*
7118
             * Found another session with outstanding requests.  
7119
             */
7120
0
            requests++;
7121
0
            for (rp = slp->internal->requests; rp; rp = rp->next_request) {
7122
0
                if (!timerisset(&earliest)
7123
0
                    || (timerisset(&rp->expireM)
7124
0
                        && timercmp(&rp->expireM, &earliest, <))) {
7125
0
                    earliest = rp->expireM;
7126
0
                    DEBUGMSG(("verbose:sess_select","(to in %d.%06d sec) ",
7127
0
                               (int)earliest.tv_sec, (int)earliest.tv_usec));
7128
0
                }
7129
0
            }
7130
0
        }
7131
0
        if (slp->internal != NULL &&
7132
0
            timerisset(&slp->internal->packet_deadline)) {
7133
0
            packet_deadlines++;
7134
0
            if (!timerisset(&earliest) ||
7135
0
                timercmp(&slp->internal->packet_deadline, &earliest, <))
7136
0
                earliest = slp->internal->packet_deadline;
7137
0
        }
7138
7139
0
        active++;
7140
0
        if (sessp) {
7141
            /*
7142
             * Single session processing.  
7143
             */
7144
0
            break;
7145
0
        }
7146
0
    }
7147
0
    DEBUGMSG(("sess_select", "\n"));
7148
7149
0
    if (has_pending_data) {
7150
0
        DEBUGMSGT(("sess_select",
7151
0
                   "pending transport data present, setting timeout to 0\n"));
7152
0
        timerclear(timeout);
7153
0
        *block = 0;
7154
0
        return active;
7155
0
    }
7156
7157
0
    netsnmp_get_monotonic_clock(&now);
7158
7159
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7160
0
                               NETSNMP_DS_LIB_ALARM_DONT_USE_SIG) &&
7161
0
        !(flags & NETSNMP_SELECT_NOALARMS)) {
7162
0
        next_alarm = netsnmp_get_next_alarm_time(&alarm_tm, &now);
7163
0
        if (next_alarm)
7164
0
            DEBUGMSGT(("sess_select","next alarm at %ld.%06ld sec\n",
7165
0
                       (long)alarm_tm.tv_sec, (long)alarm_tm.tv_usec));
7166
0
    }
7167
0
    if (next_alarm == 0 && requests == 0 && packet_deadlines == 0) {
7168
        /*
7169
         * If none are active, skip arithmetic.  
7170
         */
7171
0
        DEBUGMSGT(("sess_select","blocking:no session requests or alarms.\n"));
7172
0
        *block = 1; /* can block - timeout value is undefined if no requests */
7173
0
        return active;
7174
0
    }
7175
7176
0
    if (next_alarm &&
7177
0
        (!timerisset(&earliest) || timercmp(&alarm_tm, &earliest, <)))
7178
0
        earliest = alarm_tm;
7179
7180
0
    NETSNMP_TIMERSUB(&earliest, &now, &earliest);
7181
0
    if (earliest.tv_sec < 0) {
7182
0
        time_t overdue_ms = -(earliest.tv_sec * 1000 + earliest.tv_usec / 1000);
7183
0
        if (overdue_ms >= 10)
7184
0
            DEBUGMSGT(("verbose:sess_select","timer overdue by %ld ms\n",
7185
0
                       (long) overdue_ms));
7186
0
        timerclear(&earliest);
7187
0
    } else {
7188
0
        DEBUGMSGT(("verbose:sess_select","timer due in %d.%06d sec\n",
7189
0
                   (int)earliest.tv_sec, (int)earliest.tv_usec));
7190
0
    }
7191
7192
    /*
7193
     * if it was blocking before or our delta time is less, reset timeout 
7194
     */
7195
0
    if ((*block || (timercmp(&earliest, timeout, <)))) {
7196
0
        DEBUGMSGT(("verbose:sess_select",
7197
0
                   "setting timer to %d.%06d sec, clear block (was %d)\n",
7198
0
                   (int)earliest.tv_sec, (int)earliest.tv_usec, *block));
7199
0
        *timeout = earliest;
7200
0
        *block = 0;
7201
0
    }
7202
0
    return active;
7203
0
}
7204
7205
/*
7206
 * snmp_timeout should be called whenever the timeout from snmp_select_info
7207
 * expires, but it is idempotent, so snmp_timeout can be polled (probably a
7208
 * cpu expensive proposition).  snmp_timeout checks to see if any of the
7209
 * sessions have an outstanding request that has timed out.  If it finds one
7210
 * (or more), and that pdu has more retries available, a new packet is formed
7211
 * from the pdu and is resent.  If there are no more retries available, the
7212
 *  callback for the session is used to alert the user of the timeout.
7213
 */
7214
void
7215
snmp_timeout(void)
7216
0
{
7217
0
    struct session_list *slp, *next;
7218
7219
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
7220
0
    for (slp = Sessions; slp; slp = next) {
7221
0
        next = slp->next;
7222
0
        snmp_sess_timeout(slp);
7223
0
    }
7224
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
7225
0
}
7226
7227
void
7228
snmp_sess_timeout(struct session_list *slp)
7229
0
{
7230
0
    netsnmp_session *sp;
7231
0
    struct snmp_internal_session *isp;
7232
0
    netsnmp_request_list *rp, *orp = NULL, *freeme = NULL;
7233
0
    struct timeval  now;
7234
0
    snmp_callback   callback;
7235
0
    void           *magic;
7236
0
    struct snmp_secmod_def *sptr;
7237
7238
0
    sp = slp->session;
7239
0
    isp = slp->internal;
7240
0
    if (!sp || !isp) {
7241
0
        DEBUGMSGTL(("sess_read", "timeout fail: closing...\n"));
7242
0
        return;
7243
0
    }
7244
7245
0
    netsnmp_get_monotonic_clock(&now);
7246
7247
0
    if (_sess_packet_deadline_expired(isp)) {
7248
0
        snmp_log(LOG_WARNING,
7249
0
                 "Incomplete stream frame timed out. Closing session.\n");
7250
0
        _sess_close_stream(slp);
7251
0
        return;
7252
0
    }
7253
7254
    /*
7255
     * For each request outstanding, check to see if it has expired.
7256
     */
7257
0
    for (rp = isp->requests; rp; rp = rp->next_request) {
7258
0
        if (freeme != NULL) {
7259
            /*
7260
             * frees rp's after the for loop goes on to the next_request 
7261
             */
7262
0
            free(freeme);
7263
0
            freeme = NULL;
7264
0
        }
7265
7266
0
        if ((timercmp(&rp->expireM, &now, <))) {
7267
0
            if ((sptr = find_sec_mod(rp->pdu->securityModel)) != NULL &&
7268
0
                sptr->pdu_timeout != NULL) {
7269
                /*
7270
                 * call security model if it needs to know about this 
7271
                 */
7272
0
                (*sptr->pdu_timeout) (rp->pdu);
7273
0
            }
7274
7275
            /*
7276
             * this timer has expired 
7277
             */
7278
0
            if (rp->retries >= sp->retries) {
7279
0
                if (rp->callback) {
7280
0
                    callback = rp->callback;
7281
0
                    magic = rp->cb_data;
7282
0
                } else {
7283
0
                    callback = sp->callback;
7284
0
                    magic = sp->callback_magic;
7285
0
                }
7286
7287
                /*
7288
                 * No more chances, delete this entry 
7289
                 */
7290
0
                if (callback) {
7291
0
                    callback(NETSNMP_CALLBACK_OP_TIMED_OUT, sp,
7292
0
                             rp->pdu->reqid, rp->pdu, magic);
7293
0
                }
7294
0
                remove_request(isp, orp, rp);
7295
0
                freeme = rp;
7296
0
                continue;       /* don't update orp below */
7297
0
            } else {
7298
0
                if (snmp_resend_request(slp, orp, rp, TRUE)) {
7299
0
                    break;
7300
0
                }
7301
0
            }
7302
0
        }
7303
0
        orp = rp;
7304
0
    }
7305
7306
0
    if (freeme != NULL) {
7307
0
        free(freeme);
7308
0
        freeme = NULL;
7309
0
    }
7310
0
}
7311
7312
/*
7313
 * lexicographical compare two object identifiers.
7314
 * * Returns -1 if name1 < name2,
7315
 * *          0 if name1 = name2,
7316
 * *          1 if name1 > name2
7317
 * *
7318
 * * Caution: this method is called often by
7319
 * *          command responder applications (ie, agent).
7320
 */
7321
int
7322
snmp_oid_ncompare(const oid * in_name1,
7323
                  size_t len1,
7324
                  const oid * in_name2, size_t len2, size_t max_len)
7325
0
{
7326
0
    register int    len;
7327
0
    register const oid *name1 = in_name1;
7328
0
    register const oid *name2 = in_name2;
7329
0
    size_t          min_len;
7330
7331
    /*
7332
     * len = minimum of len1 and len2 
7333
     */
7334
0
    if (len1 < len2)
7335
0
        min_len = len1;
7336
0
    else
7337
0
        min_len = len2;
7338
7339
0
    if (min_len > max_len)
7340
0
        min_len = max_len;
7341
7342
0
    len = min_len;
7343
7344
    /*
7345
     * find first non-matching OID 
7346
     */
7347
0
    while (len-- > 0) {
7348
        /*
7349
         * these must be done in separate comparisons, since
7350
         * subtracting them and using that result has problems with
7351
         * subids > 2^31. 
7352
         */
7353
0
        if (*(name1) != *(name2)) {
7354
0
            if (*(name1) < *(name2))
7355
0
                return -1;
7356
0
            return 1;
7357
0
        }
7358
0
        name1++;
7359
0
        name2++;
7360
0
    }
7361
7362
0
    if (min_len != max_len) {
7363
        /*
7364
         * both OIDs equal up to length of shorter OID 
7365
         */
7366
0
        if (len1 < len2)
7367
0
            return -1;
7368
0
        if (len2 < len1)
7369
0
            return 1;
7370
0
    }
7371
7372
0
    return 0;
7373
0
}
7374
7375
/**
7376
 * Lexicographically compare two object identifiers.
7377
 *
7378
 * @param[in] in_name1 Left hand side OID.
7379
 * @param[in] len1     Length of LHS OID.
7380
 * @param[in] in_name2 Right hand side OID.
7381
 * @param[in] len2     Length of RHS OID.
7382
 * 
7383
 * Caution: this method is called often by
7384
 *          command responder applications (ie, agent).
7385
 *
7386
 * @return -1 if name1 < name2, 0 if name1 = name2, 1 if name1 > name2
7387
 */
7388
int
7389
snmp_oid_compare(const oid * in_name1,
7390
                 size_t len1, const oid * in_name2, size_t len2)
7391
0
{
7392
0
    register int    len;
7393
0
    register const oid *name1 = in_name1;
7394
0
    register const oid *name2 = in_name2;
7395
7396
    /*
7397
     * len = minimum of len1 and len2 
7398
     */
7399
0
    if (len1 < len2)
7400
0
        len = len1;
7401
0
    else
7402
0
        len = len2;
7403
    /*
7404
     * find first non-matching OID 
7405
     */
7406
0
    while (len-- > 0) {
7407
        /*
7408
         * these must be done in separate comparisons, since
7409
         * subtracting them and using that result has problems with
7410
         * subids > 2^31. 
7411
         */
7412
0
        if (*(name1) != *(name2)) {
7413
0
            if (*(name1) < *(name2))
7414
0
                return -1;
7415
0
            return 1;
7416
0
        }
7417
0
        name1++;
7418
0
        name2++;
7419
0
    }
7420
    /*
7421
     * both OIDs equal up to length of shorter OID 
7422
     */
7423
0
    if (len1 < len2)
7424
0
        return -1;
7425
0
    if (len2 < len1)
7426
0
        return 1;
7427
0
    return 0;
7428
0
}
7429
7430
/**
7431
 * Lexicographically compare two object identifiers.
7432
 *
7433
 * @param[in] in_name1 Left hand side OID.
7434
 * @param[in] len1     Length of LHS OID.
7435
 * @param[in] in_name2 Right hand side OID.
7436
 * @param[in] len2     Length of RHS OID.
7437
 * @param[out] offpt   First offset at which the two OIDs differ.
7438
 * 
7439
 * Caution: this method is called often by command responder applications (i.e.,
7440
 * agent).
7441
 *
7442
 * @return -1 if name1 < name2, 0 if name1 = name2, 1 if name1 > name2 and
7443
 * offpt = len where name1 != name2
7444
 */
7445
int
7446
netsnmp_oid_compare_ll(const oid * in_name1, size_t len1, const oid * in_name2,
7447
                       size_t len2, size_t *offpt)
7448
0
{
7449
0
    register int    len;
7450
0
    register const oid *name1 = in_name1;
7451
0
    register const oid *name2 = in_name2;
7452
0
    int initlen;
7453
7454
    /*
7455
     * len = minimum of len1 and len2 
7456
     */
7457
0
    if (len1 < len2)
7458
0
        initlen = len = len1;
7459
0
    else
7460
0
        initlen = len = len2;
7461
    /*
7462
     * find first non-matching OID 
7463
     */
7464
0
    while (len-- > 0) {
7465
        /*
7466
         * these must be done in separate comparisons, since
7467
         * subtracting them and using that result has problems with
7468
         * subids > 2^31. 
7469
         */
7470
0
        if (*(name1) != *(name2)) {
7471
0
            *offpt = initlen - len;
7472
0
            if (*(name1) < *(name2))
7473
0
                return -1;
7474
0
            return 1;
7475
0
        }
7476
0
        name1++;
7477
0
        name2++;
7478
0
    }
7479
    /*
7480
     * both OIDs equal up to length of shorter OID 
7481
     */
7482
0
    *offpt = initlen - len;
7483
0
    if (len1 < len2)
7484
0
        return -1;
7485
0
    if (len2 < len1)
7486
0
        return 1;
7487
0
    return 0;
7488
0
}
7489
7490
/** Compares 2 OIDs to determine if they are equal up until the shortest length.
7491
 * @param in_name1 A pointer to the first oid.
7492
 * @param len1     length of the first OID (in segments, not bytes)
7493
 * @param in_name2 A pointer to the second oid.
7494
 * @param len2     length of the second OID (in segments, not bytes)
7495
 * @return 0 if they are equal, 1 if in_name1 is > in_name2, or -1 if <.
7496
 */ 
7497
int
7498
snmp_oidtree_compare(const oid * in_name1,
7499
                     size_t len1, const oid * in_name2, size_t len2)
7500
0
{
7501
0
    int len = len1 < len2 ? len1 : len2;
7502
7503
0
    return snmp_oid_compare(in_name1, len, in_name2, len);
7504
0
}
7505
7506
int
7507
snmp_oidsubtree_compare(const oid * in_name1,
7508
                     size_t len1, const oid * in_name2, size_t len2)
7509
0
{
7510
0
    int len = len1 < len2 ? len1 : len2;
7511
7512
0
    return snmp_oid_compare(in_name1, len1, in_name2, len);
7513
0
}
7514
7515
/** Compares 2 OIDs to determine if they are exactly equal.
7516
 *  This should be faster than doing a snmp_oid_compare for different
7517
 *  length OIDs, since the length is checked first and if != returns
7518
 *  immediately.  Might be very slightly faster if lengths are ==.
7519
 * @param in_name1 A pointer to the first oid.
7520
 * @param len1     length of the first OID (in segments, not bytes)
7521
 * @param in_name2 A pointer to the second oid.
7522
 * @param len2     length of the second OID (in segments, not bytes)
7523
 * @return 0 if they are equal, 1 if they are not.
7524
 */ 
7525
int
7526
netsnmp_oid_equals(const oid * in_name1,
7527
                   size_t len1, const oid * in_name2, size_t len2)
7528
0
{
7529
0
    register const oid *name1 = in_name1;
7530
0
    register const oid *name2 = in_name2;
7531
0
    register int    len = len1;
7532
7533
    /*
7534
     * len = minimum of len1 and len2 
7535
     */
7536
0
    if (len1 != len2)
7537
0
        return 1;
7538
    /*
7539
     * Handle 'null' OIDs
7540
     */
7541
0
    if (len1 == 0)
7542
0
        return 0;   /* Two null OIDs are (trivially) the same */
7543
0
    if (!name1 || !name2)
7544
0
        return 1;   /* Otherwise something's wrong, so report a non-match */
7545
    /*
7546
     * find first non-matching OID 
7547
     */
7548
0
    while (len-- > 0) {
7549
        /*
7550
         * these must be done in separate comparisons, since
7551
         * subtracting them and using that result has problems with
7552
         * subids > 2^31. 
7553
         */
7554
0
        if (*(name1++) != *(name2++))
7555
0
            return 1;
7556
0
    }
7557
0
    return 0;
7558
0
}
7559
7560
#ifndef NETSNMP_FEATURE_REMOVE_OID_IS_SUBTREE
7561
/** Identical to netsnmp_oid_equals, except only the length up to len1 is compared.
7562
 * Functionally, this determines if in_name2 is equal or a subtree of in_name1
7563
 * @param in_name1 A pointer to the first oid.
7564
 * @param len1     length of the first OID (in segments, not bytes)
7565
 * @param in_name2 A pointer to the second oid.
7566
 * @param len2     length of the second OID (in segments, not bytes)
7567
 * @return 0 if one is a common prefix of the other.
7568
 */ 
7569
int
7570
netsnmp_oid_is_subtree(const oid * in_name1,
7571
                       size_t len1, const oid * in_name2, size_t len2)
7572
0
{
7573
0
    if (len1 > len2)
7574
0
        return 1;
7575
7576
0
    if (memcmp(in_name1, in_name2, len1 * sizeof(oid)))
7577
0
        return 1;
7578
7579
0
    return 0;
7580
0
}
7581
#endif /* NETSNMP_FEATURE_REMOVE_OID_IS_SUBTREE */
7582
7583
/** Given two OIDs, determine the common prefix to them both.
7584
 * @param in_name1 A pointer to the first oid.
7585
 * @param len1     Length of the first oid.
7586
 * @param in_name2 A pointer to the second oid.
7587
 * @param len2     Length of the second oid.
7588
 * @return         length of common prefix
7589
 *                 0 if no common prefix, -1 on error.
7590
 */
7591
int
7592
netsnmp_oid_find_prefix(const oid * in_name1, size_t len1,
7593
                        const oid * in_name2, size_t len2)
7594
0
{
7595
0
    int i;
7596
0
    size_t min_size;
7597
7598
0
    if (!in_name1 || !in_name2 || !len1 || !len2)
7599
0
        return -1;
7600
7601
0
    if (in_name1[0] != in_name2[0])
7602
0
        return 0;   /* No match */
7603
0
    min_size = SNMP_MIN(len1, len2);
7604
0
    for(i = 0; i < (int)min_size; i++) {
7605
0
        if (in_name1[i] != in_name2[i])
7606
0
            return i;    /* 'i' is the first differing subidentifier
7607
                            So the common prefix is 0..(i-1), of length i */
7608
0
    }
7609
0
    return min_size; /* The shorter OID is a prefix of the longer, and
7610
                           hence is precisely the common prefix of the two.
7611
                           Return its length. */
7612
0
}
7613
7614
#ifndef NETSNMP_DISABLE_MIB_LOADING
7615
static int _check_range(struct tree *tp, long ltmp, int *resptr,
7616
                  const char *errmsg)
7617
0
{
7618
0
    char *cp   = NULL;
7619
0
    char *temp = NULL;
7620
0
    int   temp_len = 0;
7621
0
    size_t temp_sz = 0;
7622
0
    int check = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7623
0
                                  NETSNMP_DS_LIB_DONT_CHECK_RANGE);
7624
  
7625
0
    if (check && tp && tp->ranges) {
7626
0
  struct range_list *rp = tp->ranges;
7627
0
  while (rp) {
7628
0
      if (rp->low <= ltmp && ltmp <= rp->high) break;
7629
                                  /* Allow four digits per range value */
7630
0
            temp_len += ((rp->low != rp->high) ? 27 : 15 );
7631
0
      rp = rp->next;
7632
0
  }
7633
0
  if (!rp) {
7634
0
      *resptr = SNMPERR_RANGE;
7635
0
            temp_sz = temp_len + strlen(errmsg) + 7;
7636
0
            temp = (char *)malloc(temp_sz);
7637
0
            if ( temp ) {
7638
                /* Append the Display Hint range information to the error message */
7639
0
                snprintf( temp, temp_sz, "%s :: {", errmsg );
7640
0
                cp = temp+(strlen(temp));
7641
0
                for ( rp = tp->ranges; rp; rp=rp->next ) {
7642
0
                    if ( rp->low != rp->high ) 
7643
0
                        snprintf( cp, temp_sz - (cp - temp), "(%d..%d), ", rp->low, rp->high );
7644
0
                    else
7645
0
                        snprintf( cp, temp_sz - (cp - temp), "(%d), ", rp->low );
7646
0
                    cp += strlen(cp);
7647
0
                }
7648
0
                *(cp-2) = '}';   /* Replace the final comma with a '}' */
7649
0
                *(cp-1) = 0;
7650
0
          snmp_set_detail(temp);
7651
0
          free(temp);
7652
0
            }
7653
0
      return 0;
7654
0
  }
7655
0
    }
7656
0
    free(temp);
7657
0
    return 1;
7658
0
}
7659
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7660
7661
/*
7662
 * Add a variable with the requested name to the end of the list of
7663
 * variables for this pdu.
7664
 */
7665
netsnmp_variable_list *
7666
snmp_pdu_add_variable(netsnmp_pdu *pdu,
7667
                      const oid * name,
7668
                      size_t name_length,
7669
                      u_char type, const void * value, size_t len)
7670
0
{
7671
0
    return snmp_varlist_add_variable(&pdu->variables, name, name_length,
7672
0
                                     type, value, len);
7673
0
}
7674
7675
/*
7676
 * Add a variable with the requested name to the end of the list of
7677
 * variables for this pdu.
7678
 */
7679
netsnmp_variable_list *
7680
snmp_varlist_add_variable(netsnmp_variable_list ** varlist,
7681
                          const oid * name,
7682
                          size_t name_length,
7683
                          u_char type, const void * value, size_t len)
7684
0
{
7685
0
    netsnmp_variable_list *vars, *vtmp;
7686
0
    int rc;
7687
7688
0
    if (varlist == NULL)
7689
0
        return NULL;
7690
7691
0
    vars = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
7692
0
    if (vars == NULL)
7693
0
        return NULL;
7694
7695
0
    vars->type = type;
7696
7697
0
    rc = snmp_set_var_value( vars, value, len );
7698
0
    if (( 0 != rc ) ||
7699
0
        (name != NULL && snmp_set_var_objid(vars, name, name_length))) {
7700
0
        snmp_free_var(vars);
7701
0
        return NULL;
7702
0
    }
7703
7704
    /*
7705
     * put only qualified variable onto varlist 
7706
     */
7707
0
    if (*varlist == NULL) {
7708
0
        *varlist = vars;
7709
0
    } else {
7710
0
        for (vtmp = *varlist; vtmp->next_variable;
7711
0
             vtmp = vtmp->next_variable);
7712
7713
0
        vtmp->next_variable = vars;
7714
0
    }
7715
7716
0
    return vars;
7717
0
}
7718
7719
/*
7720
 * BITS values are encoded as an OCTET STRING and the size of an OCTET STRING
7721
 * is limited to 65535 octets (RFC 2578, section 7.1.2).
7722
 */
7723
0
#define NETSNMP_MAX_BITS_OCTETS 65535
7724
7725
/*
7726
 * Make sure that the BITS buffer *buf is at least @needed bytes large and
7727
 * zero-initialize any newly allocated bytes. Grow the buffer geometrically
7728
 * to avoid quadratic behavior. Returns 1 upon success and 0 upon failure.
7729
 */
7730
static int
7731
_bits_buf_grow(u_char **buf, size_t *buf_len, size_t needed)
7732
0
{
7733
0
    u_char         *new_buf;
7734
0
    size_t          new_len;
7735
7736
0
    if (needed <= *buf_len)
7737
0
        return 1;
7738
0
    if (needed > NETSNMP_MAX_BITS_OCTETS)
7739
0
        return 0;
7740
0
    new_len = *buf_len * 2;
7741
0
    if (new_len < needed)
7742
0
        new_len = needed;
7743
0
    if (new_len > NETSNMP_MAX_BITS_OCTETS)
7744
0
        new_len = NETSNMP_MAX_BITS_OCTETS;
7745
0
    new_buf = realloc(*buf, new_len);
7746
0
    if (!new_buf)
7747
0
        return 0;
7748
0
    memset(new_buf + *buf_len, 0, new_len - *buf_len);
7749
0
    *buf = new_buf;
7750
0
    *buf_len = new_len;
7751
0
    return 1;
7752
0
}
7753
7754
/*
7755
 * Add a variable with the requested name to the end of the list of
7756
 * variables for this pdu.
7757
 * Returns:
7758
 * may set these error types :
7759
 * SNMPERR_RANGE - type, value, or length not found or out of range
7760
 * SNMPERR_VALUE - value is not correct
7761
 * SNMPERR_VAR_TYPE - type is not correct
7762
 * SNMPERR_BAD_NAME - name is not found
7763
 *
7764
 * returns 0 if success, error if failure.
7765
 */
7766
int
7767
snmp_add_var(netsnmp_pdu *pdu,
7768
             const oid * name, size_t name_length, char type, const char *value)
7769
0
{
7770
0
    char           *st;
7771
0
    const char     *cp;
7772
0
    char           *ecp, *vp = NULL;
7773
0
    int             result = SNMPERR_SUCCESS;
7774
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7775
0
    int             check = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7776
0
               NETSNMP_DS_LIB_DONT_CHECK_RANGE);
7777
0
    int             do_hint = !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
7778
0
               NETSNMP_DS_LIB_NO_DISPLAY_HINT);
7779
0
    u_char         *hintptr;
7780
0
    struct tree    *tp;
7781
0
    struct enum_list *ep;
7782
0
    int             itmp;
7783
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7784
0
    u_char         *buf = NULL;
7785
0
    const u_char   *buf_ptr = NULL;
7786
0
    size_t          buf_len = 0, value_len = 0, tint;
7787
0
    in_addr_t       atmp;
7788
0
    long            ltmp;
7789
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
7790
0
    double          dtmp;
7791
0
    float           ftmp;
7792
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
7793
0
    struct counter64 c64tmp;
7794
7795
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7796
0
    tp = get_tree(name, name_length, get_tree_head());
7797
0
    if (!tp || !tp->type || tp->type > TYPE_SIMPLE_LAST) {
7798
0
        check = 0;
7799
0
    }
7800
0
    if (!(tp && tp->hint))
7801
0
  do_hint = 0;
7802
7803
0
    if (tp && type == '=') {
7804
        /*
7805
         * generic assignment - let the tree node decide value format 
7806
         */
7807
0
        switch (tp->type) {
7808
0
        case TYPE_INTEGER:
7809
0
        case TYPE_INTEGER32:
7810
0
            type = 'i';
7811
0
            break;
7812
0
        case TYPE_GAUGE:
7813
0
        case TYPE_UNSIGNED32:
7814
0
            type = 'u';
7815
0
            break;
7816
0
        case TYPE_UINTEGER:
7817
0
            type = '3';
7818
0
            break;
7819
0
        case TYPE_COUNTER:
7820
0
            type = 'c';
7821
0
            break;
7822
0
        case TYPE_COUNTER64:
7823
0
            type = 'C';
7824
0
            break;
7825
0
        case TYPE_TIMETICKS:
7826
0
            type = 't';
7827
0
            break;
7828
0
        case TYPE_OCTETSTR:
7829
0
            type = 's';
7830
0
            break;
7831
0
        case TYPE_BITSTRING:
7832
0
            type = 'b';
7833
0
            break;
7834
0
        case TYPE_IPADDR:
7835
0
            type = 'a';
7836
0
            break;
7837
0
        case TYPE_OBJID:
7838
0
            type = 'o';
7839
0
            break;
7840
0
        }
7841
0
    }
7842
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7843
7844
0
    switch (type) {
7845
0
    case 'i':
7846
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7847
0
        if (check && tp->type != TYPE_INTEGER
7848
0
            && tp->type != TYPE_INTEGER32) {
7849
0
            value = "INTEGER";
7850
0
            result = SNMPERR_VALUE;
7851
0
            goto type_error;
7852
0
        }
7853
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7854
0
        if (!*value)
7855
0
            goto value_error;
7856
0
        ltmp = strtol(value, &ecp, 10);
7857
0
        if (*ecp) {
7858
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7859
0
            ep = tp ? tp->enums : NULL;
7860
0
            while (ep) {
7861
0
                if (strcmp(value, ep->label) == 0) {
7862
0
                    ltmp = ep->value;
7863
0
                    break;
7864
0
                }
7865
0
                ep = ep->next;
7866
0
            }
7867
0
            if (!ep) {
7868
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7869
0
                result = SNMPERR_RANGE;   /* ?? or SNMPERR_VALUE; */
7870
0
                snmp_set_detail(value);
7871
0
                break;
7872
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7873
0
            }
7874
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7875
0
        }
7876
7877
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7878
0
        if (!_check_range(tp, ltmp, &result, value))
7879
0
            break;
7880
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7881
0
        snmp_pdu_add_variable(pdu, name, name_length, ASN_INTEGER,
7882
0
                              &ltmp, sizeof(ltmp));
7883
0
        break;
7884
7885
0
    case 'u':
7886
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7887
0
        if (check && tp->type != TYPE_GAUGE && tp->type != TYPE_UNSIGNED32) {
7888
0
            value = "Unsigned32";
7889
0
            result = SNMPERR_VALUE;
7890
0
            goto type_error;
7891
0
        }
7892
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7893
0
        ltmp = strtoul(value, &ecp, 10);
7894
0
        if (*value && !*ecp)
7895
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_UNSIGNED,
7896
0
                                  &ltmp, sizeof(ltmp));
7897
0
        else
7898
0
            goto value_error;
7899
0
        break;
7900
7901
0
    case '3':
7902
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7903
0
        if (check && tp->type != TYPE_UINTEGER) {
7904
0
            value = "UInteger32";
7905
0
            result = SNMPERR_VALUE;
7906
0
            goto type_error;
7907
0
        }
7908
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7909
0
        ltmp = strtoul(value, &ecp, 10);
7910
0
        if (*value && !*ecp)
7911
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_UINTEGER,
7912
0
                                  &ltmp, sizeof(ltmp));
7913
0
        else
7914
0
            goto value_error;
7915
0
        break;
7916
7917
0
    case 'c':
7918
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7919
0
        if (check && tp->type != TYPE_COUNTER) {
7920
0
            value = "Counter32";
7921
0
            result = SNMPERR_VALUE;
7922
0
            goto type_error;
7923
0
        }
7924
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7925
0
        ltmp = strtoul(value, &ecp, 10);
7926
0
        if (*value && !*ecp)
7927
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER,
7928
0
                                  &ltmp, sizeof(ltmp));
7929
0
        else
7930
0
            goto value_error;
7931
0
        break;
7932
7933
0
    case 'C':
7934
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7935
0
        if (check && tp->type != TYPE_COUNTER64) {
7936
0
            value = "Counter64";
7937
0
            result = SNMPERR_VALUE;
7938
0
            goto type_error;
7939
0
        }
7940
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7941
0
        if (read64(&c64tmp, value))
7942
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER64,
7943
0
                                  &c64tmp, sizeof(c64tmp));
7944
0
        else
7945
0
            goto value_error;
7946
0
        break;
7947
7948
0
    case 't':
7949
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7950
0
        if (check && tp->type != TYPE_TIMETICKS) {
7951
0
            value = "Timeticks";
7952
0
            result = SNMPERR_VALUE;
7953
0
            goto type_error;
7954
0
        }
7955
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7956
0
        ltmp = strtoul(value, &ecp, 10);
7957
0
        if (*value && !*ecp)
7958
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_TIMETICKS,
7959
0
                                  &ltmp, sizeof(long));
7960
0
        else
7961
0
            goto value_error;
7962
0
        break;
7963
7964
0
    case 'a':
7965
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7966
0
        if (check && tp->type != TYPE_IPADDR) {
7967
0
            value = "IpAddress";
7968
0
            result = SNMPERR_VALUE;
7969
0
            goto type_error;
7970
0
        }
7971
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7972
0
        atmp = inet_addr(value);
7973
0
        if (atmp != (in_addr_t) -1 || !strcmp(value, "255.255.255.255"))
7974
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_IPADDRESS,
7975
0
                                  &atmp, sizeof(atmp));
7976
0
        else
7977
0
            goto value_error;
7978
0
        break;
7979
7980
0
    case 'o':
7981
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
7982
0
        if (check && tp->type != TYPE_OBJID) {
7983
0
            value = "OBJECT IDENTIFIER";
7984
0
            result = SNMPERR_VALUE;
7985
0
            goto type_error;
7986
0
        }
7987
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
7988
0
        buf = malloc(sizeof(oid) * MAX_OID_LEN);
7989
0
        if (buf == NULL) {
7990
0
            result = SNMPERR_MALLOC;
7991
0
            break;
7992
0
        }
7993
0
        tint = MAX_OID_LEN;
7994
0
        if (snmp_parse_oid(value, (oid *) buf, &tint)) {
7995
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_OBJECT_ID,
7996
0
                                  buf, sizeof(oid) * tint);
7997
0
        } else {
7998
0
            result = snmp_errno;    /*MTCRITICAL_RESOURCE */
7999
0
        }
8000
0
        break;
8001
8002
0
    case 's':
8003
0
    case 'x':
8004
0
    case 'd':
8005
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8006
0
        if (check && tp->type != TYPE_OCTETSTR && tp->type != TYPE_BITSTRING) {
8007
0
            value = "OCTET STRING";
8008
0
            result = SNMPERR_VALUE;
8009
0
            goto type_error;
8010
0
        }
8011
0
  if ('s' == type && do_hint && !parse_octet_hint(tp->hint, value, &hintptr, &itmp)) {
8012
0
            if (_check_range(tp, itmp, &result, "Value does not match DISPLAY-HINT")) {
8013
0
                snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
8014
0
                                      hintptr, itmp);
8015
0
            }
8016
0
            SNMP_FREE(hintptr);
8017
0
            hintptr = buf;
8018
0
            break;
8019
0
        }
8020
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8021
0
        if (type == 'd') {
8022
0
            if (!snmp_decimal_to_binary
8023
0
                (&buf, &buf_len, &value_len, 1, value)) {
8024
0
                result = SNMPERR_VALUE;
8025
0
                snmp_set_detail(value);
8026
0
                break;
8027
0
            }
8028
0
            buf_ptr = buf;
8029
0
        } else if (type == 'x') {
8030
0
            if (!snmp_hex_to_binary(&buf, &buf_len, &value_len, 1, value)) {
8031
0
                result = SNMPERR_VALUE;
8032
0
                snmp_set_detail(value);
8033
0
                break;
8034
0
            }
8035
0
            buf_ptr = buf;
8036
0
        } else if (type == 's') {
8037
0
            buf_ptr = (const u_char *)value;
8038
0
            value_len = strlen(value);
8039
0
        }
8040
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8041
0
        if (!_check_range(tp, value_len, &result, "Bad string length"))
8042
0
            break;
8043
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8044
0
        snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
8045
0
                              buf_ptr, value_len);
8046
0
        break;
8047
8048
0
    case 'n':
8049
0
        snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, NULL, 0);
8050
0
        break;
8051
8052
0
    case 'b':
8053
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8054
0
        if (check && (tp->type != TYPE_BITSTRING || !tp->enums)) {
8055
0
            value = "BITS";
8056
0
            result = SNMPERR_VALUE;
8057
0
            goto type_error;
8058
0
        }
8059
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8060
0
        tint = 0;
8061
0
        buf_len = 256;
8062
0
        buf = calloc(1, buf_len);
8063
0
        if (buf == NULL) {
8064
0
            result = SNMPERR_MALLOC;
8065
0
            break;
8066
0
        }
8067
8068
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8069
0
        for (ep = tp ? tp->enums : NULL; ep; ep = ep->next) {
8070
0
            if (ep->value / 8 >= (int) tint) {
8071
0
                tint = ep->value / 8 + 1;
8072
0
            }
8073
0
        }
8074
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8075
0
        if (tint > NETSNMP_MAX_BITS_OCTETS) {
8076
0
            result = SNMPERR_RANGE;
8077
0
            snmp_set_detail(value);
8078
0
            goto err;
8079
0
        }
8080
0
        if (!_bits_buf_grow(&buf, &buf_len, tint)) {
8081
0
            result = SNMPERR_MALLOC;
8082
0
            goto err;
8083
0
        }
8084
8085
0
  vp = strdup(value);
8086
0
        if (!vp)
8087
0
            goto value_error;
8088
8089
0
  for (cp = strtok_r(vp, " ,\t", &st); cp; cp = strtok_r(NULL, " ,\t", &st)) {
8090
0
            int             ix, bit;
8091
8092
0
            ltmp = strtoul(cp, &ecp, 0);
8093
0
            if (ltmp < 0) {
8094
0
                result = SNMPERR_VALUE;
8095
0
                snmp_set_detail(cp);
8096
0
                goto err;
8097
0
            }
8098
0
            if (*ecp != 0) {
8099
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8100
0
                for (ep = tp ? tp->enums : NULL; ep != NULL; ep = ep->next) {
8101
0
                    if (strcmp(ep->label, cp) == 0) {
8102
0
                        break;
8103
0
                    }
8104
0
                }
8105
0
                if (ep != NULL) {
8106
0
                    ltmp = ep->value;
8107
0
                } else {
8108
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8109
0
                    result = SNMPERR_RANGE;   /* ?? or SNMPERR_VALUE; */
8110
0
                    snmp_set_detail(cp);
8111
0
                    goto err;
8112
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8113
0
                }
8114
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8115
0
            }
8116
8117
0
            if (ltmp < 0 || ltmp / 8 >= NETSNMP_MAX_BITS_OCTETS) {
8118
0
                result = SNMPERR_RANGE;
8119
0
                snmp_set_detail(cp);
8120
0
                goto err;
8121
0
            }
8122
0
            ix = ltmp / 8;
8123
0
            if (ix >= (int) tint) {
8124
0
                tint = ix + 1;
8125
0
            }
8126
0
            if (!_bits_buf_grow(&buf, &buf_len, ix + 1)) {
8127
0
                result = SNMPERR_MALLOC;
8128
0
                goto err;
8129
0
            }
8130
0
            bit = 0x80 >> ltmp % 8;
8131
0
            buf[ix] |= bit;
8132
      
8133
0
        }
8134
0
  SNMP_FREE(vp);
8135
0
        snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR,
8136
0
                              buf, tint);
8137
0
        break;
8138
8139
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
8140
0
    case 'U':
8141
0
        if (read64(&c64tmp, value))
8142
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_U64,
8143
0
                                  &c64tmp, sizeof(c64tmp));
8144
0
        else
8145
0
            goto value_error;
8146
0
        break;
8147
8148
0
    case 'I':
8149
0
        if (read64(&c64tmp, value))
8150
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_I64,
8151
0
                                  &c64tmp, sizeof(c64tmp));
8152
0
        else
8153
0
            goto value_error;
8154
0
        break;
8155
8156
0
    case 'F':
8157
0
        if (sscanf(value, "%f", &ftmp) == 1)
8158
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_FLOAT,
8159
0
                                  &ftmp, sizeof(ftmp));
8160
0
        else
8161
0
            goto value_error;
8162
0
        break;
8163
8164
0
    case 'D':
8165
0
        if (sscanf(value, "%lf", &dtmp) == 1)
8166
0
            snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_DOUBLE,
8167
0
                                  &dtmp, sizeof(dtmp));
8168
0
        else
8169
0
            goto value_error;
8170
0
        break;
8171
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
8172
8173
0
    default:
8174
0
        result = SNMPERR_VAR_TYPE;
8175
0
  buf = calloc(1, 4);
8176
0
  if (buf != NULL) {
8177
0
      snprintf((char *)buf, 4, "\"%c\"", type);
8178
0
      snmp_set_detail((char *)buf);
8179
0
  }
8180
0
        break;
8181
0
    }
8182
8183
0
    SNMP_FREE(buf);
8184
0
    SET_SNMP_ERROR(result);
8185
0
    return result;
8186
8187
0
#ifndef NETSNMP_DISABLE_MIB_LOADING
8188
0
  type_error:
8189
0
    {
8190
0
        char            error_msg[256];
8191
0
        char            undef_msg[32];
8192
0
        const char     *var_type;
8193
0
        switch (tp->type) {
8194
0
        case TYPE_OBJID:
8195
0
            var_type = "OBJECT IDENTIFIER";
8196
0
            break;
8197
0
        case TYPE_OCTETSTR:
8198
0
            var_type = "OCTET STRING";
8199
0
            break;
8200
0
        case TYPE_INTEGER:
8201
0
            var_type = "INTEGER";
8202
0
            break;
8203
0
        case TYPE_NETADDR:
8204
0
            var_type = "NetworkAddress";
8205
0
            break;
8206
0
        case TYPE_IPADDR:
8207
0
            var_type = "IpAddress";
8208
0
            break;
8209
0
        case TYPE_COUNTER:
8210
0
            var_type = "Counter32";
8211
0
            break;
8212
0
        case TYPE_GAUGE:
8213
0
            var_type = "Gauge32";
8214
0
            break;
8215
0
        case TYPE_TIMETICKS:
8216
0
            var_type = "Timeticks";
8217
0
            break;
8218
0
        case TYPE_OPAQUE:
8219
0
            var_type = "Opaque";
8220
0
            break;
8221
0
        case TYPE_NULL:
8222
0
            var_type = "Null";
8223
0
            break;
8224
0
        case TYPE_COUNTER64:
8225
0
            var_type = "Counter64";
8226
0
            break;
8227
0
        case TYPE_BITSTRING:
8228
0
            var_type = "BITS";
8229
0
            break;
8230
0
        case TYPE_NSAPADDRESS:
8231
0
            var_type = "NsapAddress";
8232
0
            break;
8233
0
        case TYPE_UINTEGER:
8234
0
            var_type = "UInteger";
8235
0
            break;
8236
0
        case TYPE_UNSIGNED32:
8237
0
            var_type = "Unsigned32";
8238
0
            break;
8239
0
        case TYPE_INTEGER32:
8240
0
            var_type = "Integer32";
8241
0
            break;
8242
0
        default:
8243
0
            snprintf(undef_msg, sizeof(undef_msg), "TYPE_%d", tp->type);
8244
0
            var_type = undef_msg;
8245
0
        }
8246
0
        snprintf(error_msg, sizeof(error_msg),
8247
0
                 "Type of attribute is %s, not %s", var_type, value);
8248
0
        result = SNMPERR_VAR_TYPE;
8249
0
        snmp_set_detail(error_msg);
8250
0
        goto out;
8251
0
    }
8252
0
#endif /* NETSNMP_DISABLE_MIB_LOADING */
8253
8254
0
value_error:
8255
0
    result = SNMPERR_VALUE;
8256
0
    snmp_set_detail(value);
8257
8258
0
err:
8259
0
    free(buf);
8260
0
    free(vp);
8261
8262
0
out:
8263
0
    SET_SNMP_ERROR(result);
8264
0
    return result;
8265
0
}
8266
8267
/*
8268
 * returns NULL or internal pointer to session
8269
 * use this pointer for the other snmp_sess* routines,
8270
 * which guarantee action will occur ONLY for this given session.
8271
 */
8272
struct session_list *
8273
snmp_sess_pointer(netsnmp_session * session)
8274
0
{
8275
0
    struct session_list *slp;
8276
8277
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
8278
0
    for (slp = Sessions; slp; slp = slp->next) {
8279
0
        if (slp->session == session) {
8280
0
            break;
8281
0
        }
8282
0
    }
8283
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
8284
8285
0
    if (slp == NULL) {
8286
0
        snmp_errno = SNMPERR_BAD_SESSION;       /*MTCRITICAL_RESOURCE */
8287
0
        return (NULL);
8288
0
    }
8289
0
    return slp;
8290
0
}
8291
8292
/*
8293
 * Input : an opaque pointer, returned by snmp_sess_open.
8294
 * returns NULL or pointer to session.
8295
 */
8296
netsnmp_session *
8297
snmp_sess_session(struct session_list *slp)
8298
0
{
8299
0
    if (slp == NULL)
8300
0
        return (NULL);
8301
0
    return (slp->session);
8302
0
}
8303
8304
/**
8305
 * Look up a session that already may have been closed.
8306
 *
8307
 * @param sessp Opaque pointer, returned by snmp_sess_open.
8308
 *
8309
 * @return Pointer to session upon success or NULL upon failure.
8310
 *
8311
 * @see snmp_sess_session()
8312
 */
8313
netsnmp_session *
8314
snmp_sess_session_lookup(struct session_list *sessp)
8315
0
{
8316
0
    struct session_list *slp;
8317
8318
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
8319
0
    for (slp = Sessions; slp; slp = slp->next) {
8320
0
        if (slp == sessp) {
8321
0
            break;
8322
0
        }
8323
0
    }
8324
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
8325
8326
0
    return (netsnmp_session *)slp;
8327
0
}
8328
8329
8330
/*
8331
 * returns NULL or internal pointer to session
8332
 * use this pointer for the other snmp_sess* routines,
8333
 * which guarantee action will occur ONLY for this given session.
8334
 */
8335
netsnmp_session *
8336
snmp_sess_lookup_by_name(const char *paramName)
8337
0
{
8338
0
    struct session_list *slp;
8339
8340
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
8341
0
    for (slp = Sessions; slp; slp = slp->next) {
8342
0
        if (NULL == slp->session->paramName)
8343
0
            continue;
8344
0
        if (strcmp(paramName, slp->session->paramName)  == 0)
8345
0
            break;
8346
0
    }
8347
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
8348
8349
0
    if (slp == NULL)
8350
0
        return NULL;
8351
8352
0
    return slp->session;
8353
0
}
8354
8355
8356
/*
8357
 * snmp_sess_transport: takes an opaque pointer (as returned by
8358
 * snmp_sess_open or snmp_sess_pointer) and returns the corresponding
8359
 * netsnmp_transport pointer (or NULL if the opaque pointer does not correspond
8360
 * to an active internal session).  
8361
 */
8362
8363
netsnmp_transport *
8364
snmp_sess_transport(struct session_list *slp)
8365
0
{
8366
0
    if (slp == NULL) {
8367
0
        return NULL;
8368
0
    } else {
8369
0
        return slp->transport;
8370
0
    }
8371
0
}
8372
8373
8374
8375
/*
8376
 * snmp_sess_transport_set: set the transport pointer for the
8377
 * session pointer slp.
8378
 */
8379
8380
void
8381
snmp_sess_transport_set(struct session_list *slp, netsnmp_transport *t)
8382
0
{
8383
0
    if (slp != NULL) {
8384
0
        slp->transport = t;
8385
0
    }
8386
0
}
8387
8388
8389
/*
8390
 * snmp_duplicate_objid: duplicates (mallocs) an objid based on the
8391
 * input objid 
8392
 */
8393
oid            *
8394
snmp_duplicate_objid(const oid * objToCopy, size_t objToCopyLen)
8395
0
{
8396
0
    oid            *returnOid;
8397
0
    if (objToCopy != NULL && objToCopyLen != 0) {
8398
0
        returnOid = (oid *) malloc(objToCopyLen * sizeof(oid));
8399
0
        if (returnOid) {
8400
0
            memcpy(returnOid, objToCopy, objToCopyLen * sizeof(oid));
8401
0
        }
8402
0
    } else
8403
0
        returnOid = NULL;
8404
0
    return returnOid;
8405
0
}
8406
8407
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
8408
/*
8409
 * generic statistics counter functions 
8410
 */
8411
static u_int    statistics[NETSNMP_STAT_MAX_STATS];
8412
8413
u_int
8414
snmp_increment_statistic(int which)
8415
0
{
8416
0
    if (which >= 0 && which < NETSNMP_STAT_MAX_STATS) {
8417
0
        statistics[which]++;
8418
0
        return statistics[which];
8419
0
    }
8420
0
    return 0;
8421
0
}
8422
8423
u_int
8424
snmp_increment_statistic_by(int which, int count)
8425
0
{
8426
0
    if (which >= 0 && which < NETSNMP_STAT_MAX_STATS) {
8427
0
        statistics[which] += count;
8428
0
        return statistics[which];
8429
0
    }
8430
0
    return 0;
8431
0
}
8432
8433
u_int
8434
snmp_get_statistic(int which)
8435
0
{
8436
0
    if (which >= 0 && which < NETSNMP_STAT_MAX_STATS)
8437
0
        return statistics[which];
8438
0
    return 0;
8439
0
}
8440
8441
void
8442
snmp_init_statistics(void)
8443
0
{
8444
0
    memset(statistics, 0, sizeof(statistics));
8445
0
}
8446
#endif /* NETSNMP_FEATURE_REMOVE_STATISTICS */
8447
/**  @} */