Coverage Report

Created: 2026-05-30 06:40

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