Coverage Report

Created: 2026-08-28 09:48

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