Coverage Report

Created: 2025-01-09 06:26

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