Coverage Report

Created: 2024-09-03 06:48

/src/net-snmp/snmplib/snmp_api.c
Line
Count
Source (jump to first uncovered line)
1
2
/* Portions of this file are subject to the following copyright(s).  See
3
 * the Net-SNMP's COPYING file for more details and other copyrights
4
 * that may apply:
5
 */
6
/******************************************************************
7
  Copyright 1989, 1991, 1992 by Carnegie Mellon University
8
9
                      All Rights Reserved
10
11
Permission to use, copy, modify, and distribute this software and its
12
documentation for any purpose and without fee is hereby granted,
13
provided that the above copyright notice appear in all copies and that
14
both that copyright notice and this permission notice appear in
15
supporting documentation, and that the name of CMU not be
16
used in advertising or publicity pertaining to distribution of the
17
software without specific, written prior permission.
18
19
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25
SOFTWARE.
26
******************************************************************/
27
/*
28
 * Portions of this file are copyrighted by:
29
 * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
30
 * Use is subject to license terms specified in the COPYING file
31
 * distributed with the Net-SNMP package.
32
 *
33
 * Portions of this file are copyrighted by:
34
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
35
 * Use is subject to license terms specified in the COPYING file
36
 * distributed with the Net-SNMP package.
37
 */
38
39
/** @defgroup library The Net-SNMP library
40
 *  @{
41
 */
42
/*
43
 * snmp_api.c - API for access to snmp.
44
 */
45
#include <net-snmp/net-snmp-config.h>
46
#include <net-snmp/net-snmp-features.h>
47
48
#include <stdio.h>
49
#include <ctype.h>
50
#ifdef HAVE_STDLIB_H
51
#include <stdlib.h>
52
#endif
53
#ifdef HAVE_STRING_H
54
#include <string.h>
55
#else
56
#include <strings.h>
57
#endif
58
#ifdef HAVE_UNISTD_H
59
#include <unistd.h>
60
#endif
61
#include <sys/types.h>
62
#ifdef HAVE_SYS_PARAM_H
63
#include <sys/param.h>
64
#endif
65
#ifdef TIME_WITH_SYS_TIME
66
# include <sys/time.h>
67
# include <time.h>
68
#else
69
# ifdef HAVE_SYS_TIME_H
70
#  include <sys/time.h>
71
# else
72
#  include <time.h>
73
# endif
74
#endif
75
#ifdef HAVE_NETINET_IN_H
76
#include <netinet/in.h>
77
#endif
78
#ifdef HAVE_ARPA_INET_H
79
#include <arpa/inet.h>
80
#endif
81
#ifdef HAVE_SYS_SELECT_H
82
#include <sys/select.h>
83
#endif
84
#ifdef HAVE_IO_H
85
#include <io.h>
86
#endif
87
#ifdef HAVE_SYS_SOCKET_H
88
#include <sys/socket.h>
89
#endif
90
#ifdef HAVE_SYS_UN_H
91
#include <sys/un.h>
92
#endif
93
#ifdef HAVE_NETDB_H
94
#include <netdb.h>
95
#endif
96
#ifdef HAVE_NET_IF_DL_H
97
#ifndef dynix
98
#include <net/if_dl.h>
99
#else
100
#include <sys/net/if_dl.h>
101
#endif
102
#endif
103
#include <errno.h>
104
105
#ifdef HAVE_LOCALE_H
106
#include <locale.h>
107
#endif
108
109
#define SNMP_NEED_REQUEST_LIST
110
#include <net-snmp/types.h>
111
#include <net-snmp/output_api.h>
112
#include <net-snmp/config_api.h>
113
#include <net-snmp/utilities.h>
114
#include <net-snmp/agent/agent_callbacks.h>
115
116
#include <net-snmp/library/asn1.h>
117
#include <net-snmp/library/snmp.h>      /* for xdump & {build,parse}_var_op */
118
#include <net-snmp/library/snmp_api.h>
119
#include <net-snmp/library/snmp_client.h>
120
#include <net-snmp/library/parse.h>
121
#include <net-snmp/library/mib.h>
122
#include <net-snmp/library/int64.h>
123
#include <net-snmp/library/snmpv3.h>
124
#include <net-snmp/library/callback.h>
125
#include <net-snmp/library/container.h>
126
#include <net-snmp/library/snmp_secmod.h>
127
#include <net-snmp/library/large_fd_set.h>
128
#ifdef NETSNMP_SECMOD_USM
129
#include <net-snmp/library/snmpusm.h>
130
#endif
131
#ifdef NETSNMP_SECMOD_KSM
132
#include <net-snmp/library/snmpksm.h>
133
#endif
134
#include <net-snmp/library/keytools.h>
135
#include <net-snmp/library/lcd_time.h>
136
#include <net-snmp/library/snmp_alarm.h>
137
#include <net-snmp/library/snmp_transport.h>
138
#include <net-snmp/library/snmp_service.h>
139
#include <net-snmp/library/vacm.h>
140
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL)
141
#include <openssl/ssl.h>
142
#include <net-snmp/library/cert_util.h>
143
#endif
144
145
netsnmp_feature_child_of(statistics, libnetsnmp);
146
netsnmp_feature_child_of(snmp_api, libnetsnmp);
147
netsnmp_feature_child_of(oid_is_subtree, snmp_api);
148
netsnmp_feature_child_of(snmpv3_probe_contextEngineID_rfc5343, snmp_api);
149
150
static void     _init_snmp(void);
151
152
static int      _snmp_store_needed = 0;
153
154
#include "../agent/mibgroup/agentx/protocol.h"
155
#include <net-snmp/library/transform_oids.h>
156
#ifndef timercmp
157
#define timercmp(tvp, uvp, cmp) \
158
  /* CSTYLED */ \
159
  ((tvp)->tv_sec cmp (uvp)->tv_sec || \
160
  ((tvp)->tv_sec == (uvp)->tv_sec && \
161
  /* CSTYLED */ \
162
  (tvp)->tv_usec cmp (uvp)->tv_usec))
163
#endif
164
#ifndef timerclear
165
#define timerclear(tvp)   (tvp)->tv_sec = (tvp)->tv_usec = 0
166
#endif
167
168
/*
169
 * Globals.
170
 */
171
#ifndef NETSNMP_STREAM_QUEUE_LEN
172
#define NETSNMP_STREAM_QUEUE_LEN  5
173
#endif
174
175
#ifndef BSD4_3
176
#define BSD4_2
177
#endif
178
179
static const oid default_enterprise[] = { 1, 3, 6, 1, 4, 1, 3, 1, 1 };
180
/*
181
 * enterprises.cmu.systems.cmuSNMP 
182
 */
183
184
#define DEFAULT_COMMUNITY   "public"
185
2.80k
#define DEFAULT_RETRIES     5
186
4.56k
#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
24.7k
{
361
24.7k
    u_int max = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
362
24.7k
                                   NETSNMP_DS_LIB_MSG_SEND_MAX);
363
24.7k
    if (0 == max)
364
24.7k
        max = SNMP_MAX_PACKET_LEN;
365
0
    else if (max < SNMP_MIN_MAX_LEN)
366
0
        max = SNMP_MIN_MAX_LEN; /* minimum max size per SNMP specs */
367
0
    else if (max > SNMP_MAX_PACKET_LEN)
368
0
        max = SNMP_MAX_PACKET_LEN;
369
370
24.7k
    return max;
371
24.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.59k
{
389
1.59k
    static char unknown[20];
390
1.59k
    switch(type) {
391
70
    case SNMP_MSG_GET:
392
70
        return "GET";
393
58
    case SNMP_MSG_GETNEXT:
394
58
        return "GETNEXT";
395
64
    case SNMP_MSG_GETBULK:
396
64
        return "GETBULK";
397
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
398
166
    case SNMP_MSG_SET:
399
166
        return "SET";
400
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
401
324
    case SNMP_MSG_RESPONSE:
402
324
        return "RESPONSE";
403
804
    case SNMP_MSG_TRAP:
404
804
        return "TRAP";
405
34
    case SNMP_MSG_INFORM:
406
34
        return "INFORM";
407
38
    case SNMP_MSG_TRAP2:
408
38
        return "TRAP2";
409
16
    case SNMP_MSG_REPORT:
410
16
        return "REPORT";
411
16
    default:
412
16
        snprintf(unknown, sizeof(unknown), "?0x%2X?", type);
413
16
  return unknown;
414
1.59k
    }
415
1.59k
}
416
417
#define DEBUGPRINTPDUTYPE(token, type) \
418
603
    DEBUGDUMPSECTION(token, snmp_pdu_type(type))
419
420
long
421
snmp_get_next_reqid(void)
422
0
{
423
0
    long            retVal;
424
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
425
0
    retVal = 1 + Reqid;         /*MTCRITICAL_RESOURCE */
426
0
    if (!retVal)
427
0
        retVal = 2;
428
0
    Reqid = retVal;
429
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
430
0
        retVal &= 0x7fff; /* mask to 15 bits */
431
0
    else
432
0
        retVal &= 0x7fffffff; /* mask to 31 bits */
433
434
0
    if (!retVal) {
435
0
        Reqid = retVal = 2;
436
0
    }
437
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
438
0
    return retVal;
439
0
}
440
441
long
442
snmp_get_next_msgid(void)
443
0
{
444
0
    long            retVal;
445
0
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
446
0
    retVal = 1 + Msgid;         /*MTCRITICAL_RESOURCE */
447
0
    if (!retVal)
448
0
        retVal = 2;
449
0
    Msgid = retVal;
450
0
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
451
0
        retVal &= 0x7fff; /* mask to 15 bits */
452
0
    else
453
0
        retVal &= 0x7fffffff; /* mask to 31 bits */
454
455
0
    if (!retVal) {
456
0
        Msgid = retVal = 2;
457
0
    }
458
0
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
459
0
    return retVal;
460
0
}
461
462
long
463
snmp_get_next_sessid(void)
464
7.36k
{
465
7.36k
    long            retVal;
466
7.36k
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
467
7.36k
    retVal = 1 + Sessid;        /*MTCRITICAL_RESOURCE */
468
7.36k
    if (!retVal)
469
0
        retVal = 2;
470
7.36k
    Sessid = retVal;
471
7.36k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
472
0
        retVal &= 0x7fff; /* mask to 15 bits */
473
7.36k
    else
474
7.36k
        retVal &= 0x7fffffff; /* mask to 31 bits */
475
476
7.36k
    if (!retVal) {
477
0
        Sessid = retVal = 2;
478
0
    }
479
7.36k
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
480
7.36k
    return retVal;
481
7.36k
}
482
483
long
484
snmp_get_next_transid(void)
485
6.29k
{
486
6.29k
    long            retVal;
487
6.29k
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
488
6.29k
    retVal = 1 + Transid;       /*MTCRITICAL_RESOURCE */
489
6.29k
    if (!retVal)
490
0
        retVal = 2;
491
6.29k
    Transid = retVal;
492
6.29k
    if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS))
493
1.98k
        retVal &= 0x7fff;  /* mask to 15 bits */
494
4.30k
    else
495
4.30k
        retVal &= 0x7fffffff; /* mask to 31 bits */
496
497
6.29k
    if (!retVal) {
498
0
        Transid = retVal = 2;
499
0
    }
500
6.29k
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
501
6.29k
    return retVal;
502
6.29k
}
503
504
void
505
snmp_perror(const char *prog_string)
506
0
{
507
0
    const char     *str;
508
0
    int             xerr;
509
0
    xerr = snmp_errno;          /*MTCRITICAL_RESOURCE */
510
0
    str = snmp_api_errstring(xerr);
511
0
    snmp_log(LOG_ERR, "%s: %s\n", prog_string, str);
512
0
}
513
514
void
515
snmp_set_detail(const char *detail_string)
516
78.6k
{
517
78.6k
    if (detail_string != NULL) {
518
78.6k
        strlcpy(snmp_detail, detail_string, sizeof(snmp_detail));
519
78.6k
        snmp_detail_f = 1;
520
78.6k
    }
521
78.6k
}
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.30k
{
532
3.30k
    const char     *msg = "";
533
3.30k
    static char     msg_buf[SPRINT_MAX_LEN];
534
535
3.30k
    if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
536
0
        msg = api_errors[-snmp_errnumber];
537
3.30k
    } else if (snmp_errnumber != SNMPERR_SUCCESS) {
538
0
        msg = NULL;
539
0
    }
540
3.30k
    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.30k
    } else if (snmp_detail_f) {
544
3.25k
        snprintf(msg_buf, sizeof(msg_buf), "%s (%s)", msg, snmp_detail);
545
3.25k
        msg_buf[sizeof(msg_buf)-1] = '\0';
546
3.25k
        snmp_detail_f = 0;
547
3.25k
    } else {
548
47
        strlcpy(msg_buf, msg, sizeof(msg_buf));
549
47
    }
550
551
3.30k
    return (msg_buf);
552
3.30k
}
553
554
/*
555
 * snmp_error - return error data
556
 * Inputs :  address of errno, address of snmp_errno, address of string
557
 * Caller must free the string returned after use.
558
 */
559
void
560
snmp_error(netsnmp_session * psess,
561
           int *p_errno, int *p_snmp_errno, char **p_str)
562
0
{
563
0
    char            buf[SPRINT_MAX_LEN];
564
0
    int             snmp_errnumber;
565
566
0
    if (p_errno)
567
0
        *p_errno = psess->s_errno;
568
0
    if (p_snmp_errno)
569
0
        *p_snmp_errno = psess->s_snmp_errno;
570
0
    if (p_str == NULL)
571
0
        return;
572
573
0
    strcpy(buf, "");
574
0
    snmp_errnumber = psess->s_snmp_errno;
575
0
    if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR) {
576
0
  if (snmp_detail_f) {
577
0
            snprintf(buf, sizeof(buf), "%s (%s)", api_errors[-snmp_errnumber],
578
0
        snmp_detail);
579
0
            buf[sizeof(buf)-1] = '\0';
580
0
      snmp_detail_f = 0;
581
0
  }
582
0
  else
583
0
      strlcpy(buf, api_errors[-snmp_errnumber], sizeof(buf));
584
0
    } else {
585
0
        if (snmp_errnumber) {
586
0
            snprintf(buf, sizeof(buf), "Unknown Error %d", snmp_errnumber);
587
0
            buf[sizeof(buf)-1] = '\0';
588
0
        }
589
0
    }
590
591
    /*
592
     * append a useful system errno interpretation. 
593
     */
594
0
    if (psess->s_errno) {
595
0
        const char* error = strerror(psess->s_errno);
596
0
        if(error == NULL)
597
0
            error = "Unknown Error";
598
0
        snprintf (&buf[strlen(buf)], sizeof(buf)-strlen(buf),
599
0
                 " (%s)", error);
600
0
    }
601
0
    buf[sizeof(buf)-1] = '\0';
602
0
    *p_str = strdup(buf);
603
0
}
604
605
/*
606
 * snmp_sess_error - same as snmp_error for single session API use.
607
 */
608
void
609
snmp_sess_error(struct session_list *slp, int *p_errno, int *p_snmp_errno,
610
                char **p_str)
611
0
{
612
0
    if ((slp) && (slp->session))
613
0
        snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
614
0
}
615
616
/*
617
 * netsnmp_sess_log_error(): print a error stored in a session pointer 
618
 */
619
void
620
netsnmp_sess_log_error(int priority,
621
                       const char *prog_string, netsnmp_session * ss)
622
0
{
623
0
    char           *err;
624
0
    snmp_error(ss, NULL, NULL, &err);
625
0
    snmp_log(priority, "%s: %s\n", prog_string, err);
626
0
    SNMP_FREE(err);
627
0
}
628
629
/*
630
 * snmp_sess_perror(): print a error stored in a session pointer 
631
 */
632
void
633
snmp_sess_perror(const char *prog_string, netsnmp_session * ss)
634
0
{
635
0
    netsnmp_sess_log_error(LOG_ERR, prog_string, ss);
636
0
}
637
638
long int netsnmp_random(void)
639
5.60k
{
640
5.60k
#if defined(HAVE_RANDOM)
641
    /*
642
     * The function random() is a more sophisticated random number generator
643
     * which uses nonlinear feedback and an internal table that is 124 bytes
644
     * (992 bits) long. The function returns random values that are 32 bits in
645
     * length. All of the bits generated by random() are usable. The random()
646
     * function is adequate for simulations and games, but should not be used
647
     * for security related applications such as picking cryptographic keys or
648
     * simulating one-time pads.
649
     */
650
5.60k
    return random();
651
#elif defined(HAVE_LRAND48)
652
    /*
653
     * As with random(), lrand48() provides excellent random numbers for
654
     * simulations and games, but should not be used for security-related
655
     * applications such as picking cryptographic keys or simulating one-time
656
     * pads; linear congruential algorithms are too easy to break.
657
     */
658
    return lrand48();
659
#elif defined(HAVE_RAND)
660
    /*
661
     * The original UNIX random number generator, rand(), is not a very good
662
     * random number generator. It uses a 32-bit seed and maintains a 32-bit
663
     * internal state.
664
     */
665
    return rand();
666
#else
667
#error "Neither random(), nor lrand48() nor rand() are available"
668
#endif
669
5.60k
}
670
671
void netsnmp_srandom(unsigned int seed)
672
2.80k
{
673
2.80k
#if defined(HAVE_SRANDOM)
674
2.80k
    srandom(seed);
675
#elif defined(HAVE_SRAND48)
676
    srand48(seed);
677
#elif defined(HAVE_SRAND)
678
    srand(seed);
679
#else
680
#error "Neither srandom(), nor srand48() nor srand() are available"
681
#endif
682
2.80k
}
683
684
/*
685
 * Primordial SNMP library initialization.
686
 * Initializes mutex locks.
687
 * Invokes minimum required initialization for displaying MIB objects.
688
 * Gets initial request ID for all transactions,
689
 * and finds which port SNMP over UDP uses.
690
 * SNMP over AppleTalk is not currently supported.
691
 *
692
 * Warning: no debug messages here.
693
 */
694
static char _init_snmp_init_done = 0;
695
static void
696
_init_snmp(void)
697
17.5k
{
698
699
17.5k
    struct timeval  tv;
700
17.5k
    long            tmpReqid, tmpMsgid;
701
702
17.5k
    if (_init_snmp_init_done)
703
14.7k
        return;
704
2.80k
    _init_snmp_init_done = 1;
705
2.80k
    Reqid = 1;
706
707
2.80k
    snmp_res_init();            /* initialize the mt locking structures */
708
2.80k
#ifndef NETSNMP_DISABLE_MIB_LOADING
709
2.80k
    netsnmp_init_mib_internals();
710
2.80k
#endif /* NETSNMP_DISABLE_MIB_LOADING */
711
2.80k
    netsnmp_tdomain_init();
712
713
2.80k
    gettimeofday(&tv, (struct timezone *) 0);
714
    /*
715
     * Now = tv;
716
     */
717
718
    /*
719
     * get pseudo-random values for request ID and message ID 
720
     */
721
2.80k
    netsnmp_srandom((unsigned)(tv.tv_sec ^ tv.tv_usec));
722
2.80k
    tmpReqid = netsnmp_random();
723
2.80k
    tmpMsgid = netsnmp_random();
724
725
    /*
726
     * don't allow zero value to repeat init 
727
     */
728
2.80k
    if (tmpReqid == 0)
729
0
        tmpReqid = 1;
730
2.80k
    if (tmpMsgid == 0)
731
0
        tmpMsgid = 1;
732
2.80k
    Reqid = tmpReqid;
733
2.80k
    Msgid = tmpMsgid;
734
735
2.80k
    netsnmp_register_default_domain("snmp", "udp udp6");
736
2.80k
    netsnmp_register_default_domain("snmptrap", "udp udp6");
737
738
2.80k
    netsnmp_register_default_target("snmp", "udp", ":161");
739
2.80k
    netsnmp_register_default_target("snmp", "tcp", ":161");
740
2.80k
    netsnmp_register_default_target("snmp", "udp6", ":161");
741
2.80k
    netsnmp_register_default_target("snmp", "tcp6", ":161");
742
2.80k
    netsnmp_register_default_target("snmp", "dtlsudp", ":10161");
743
2.80k
    netsnmp_register_default_target("snmp", "tlstcp", ":10161");
744
2.80k
    netsnmp_register_default_target("snmp", "ipx", "/36879");
745
746
2.80k
    netsnmp_register_default_target("snmptrap", "udp", ":162");
747
2.80k
    netsnmp_register_default_target("snmptrap", "tcp", ":162");
748
2.80k
    netsnmp_register_default_target("snmptrap", "udp6", ":162");
749
2.80k
    netsnmp_register_default_target("snmptrap", "tcp6", ":162");
750
2.80k
    netsnmp_register_default_target("snmptrap", "dtlsudp", ":10162");
751
2.80k
    netsnmp_register_default_target("snmptrap", "tlstcp", ":10162");
752
2.80k
    netsnmp_register_default_target("snmptrap", "ipx", "/36880");
753
754
2.80k
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, 
755
2.80k
                       NETSNMP_DS_LIB_HEX_OUTPUT_LENGTH, 16);
756
2.80k
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RETRIES,
757
2.80k
                       DEFAULT_RETRIES);
758
2.80k
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
759
2.80k
         NETSNMP_DS_LIB_MIB_ERRORS, 1);
760
761
2.80k
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
762
2.80k
    netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, 
763
2.80k
         NETSNMP_DS_LIB_REVERSE_ENCODE,
764
2.80k
         NETSNMP_DEFAULT_ASNENCODING_DIRECTION);
765
2.80k
#endif
766
2.80k
}
767
768
/*
769
 * Initializes the session structure.
770
 * May perform one time minimal library initialization.
771
 * No MIB file processing is done via this call.
772
 */
773
void
774
snmp_sess_init(netsnmp_session * session)
775
7.36k
{
776
7.36k
    _init_snmp();
777
778
    /*
779
     * initialize session to default values 
780
     */
781
782
7.36k
    memset(session, 0, sizeof(netsnmp_session));
783
7.36k
    session->timeout = SNMP_DEFAULT_TIMEOUT;
784
7.36k
    session->retries = SNMP_DEFAULT_RETRIES;
785
7.36k
    session->version = SNMP_DEFAULT_VERSION;
786
7.36k
    session->securityModel = SNMP_DEFAULT_SECMODEL;
787
7.36k
    session->rcvMsgMaxSize = netsnmp_max_send_msg_size();
788
7.36k
    session->sndMsgMaxSize = netsnmp_max_send_msg_size();
789
7.36k
    session->flags |= SNMP_FLAGS_DONT_PROBE;
790
7.36k
}
791
792
793
static void
794
register_default_handlers(void)
795
2.80k
{
796
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dumpPacket",
797
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET);
798
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "reverseEncodeBER",
799
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_REVERSE_ENCODE);
800
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "defaultPort",
801
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DEFAULT_PORT);
802
2.80k
#ifndef NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION
803
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv3",
804
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V3);
805
2.80k
#endif /* NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION */
806
2.80k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
807
2.80k
#ifndef NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION
808
2.80k
#if !defined(NETSNMP_DISABLE_SNMPV1)
809
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv1",
810
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V1);
811
2.80k
#endif
812
2.80k
#if !defined(NETSNMP_DISABLE_SNMPV2C)
813
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "disableSNMPv2c",
814
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_V2c);
815
2.80k
#endif
816
2.80k
#endif /* NETSNMP_FEATURE_REMOVE_RUNTIME_DISABLE_VERSION */
817
2.80k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "defCommunity",
818
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_COMMUNITY);
819
2.80k
#endif /* !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) */
820
2.80k
    netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
821
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_TOKEN_WARNINGS);
822
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noRangeCheck",
823
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_CHECK_RANGE);
824
2.80k
    netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "persistentDir",
825
2.80k
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PERSISTENT_DIR);
826
2.80k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "tempFilePattern",
827
2.80k
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TEMP_FILE_PATTERN);
828
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noDisplayHint",
829
2.80k
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_NO_DISPLAY_HINT);
830
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "16bitIDs",
831
2.80k
                NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_16BIT_IDS);
832
2.80k
    netsnmp_ds_register_premib(ASN_OCTET_STR, "snmp", "clientaddr",
833
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR);
834
2.80k
    netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "clientaddrUsesPort",
835
2.80k
                      NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENT_ADDR_USES_PORT);
836
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverSendBuf",
837
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERSENDBUF);
838
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "serverRecvBuf",
839
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SERVERRECVBUF);
840
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientSendBuf",
841
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTSENDBUF);
842
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "clientRecvBuf",
843
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_CLIENTRECVBUF);
844
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "sendMessageMaxSize",
845
2.80k
                               NETSNMP_DS_LIBRARY_ID,
846
2.80k
                               NETSNMP_DS_LIB_MSG_SEND_MAX);
847
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentLoad",
848
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD);
849
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "noPersistentSave",
850
2.80k
          NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE);
851
2.80k
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp",
852
2.80k
                               "noContextEngineIDDiscovery",
853
2.80k
                               NETSNMP_DS_LIBRARY_ID,
854
2.80k
                               NETSNMP_DS_LIB_NO_DISCOVERY);
855
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "timeout",
856
2.80k
                   NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_TIMEOUT);
857
2.80k
    netsnmp_ds_register_config(ASN_INTEGER, "snmp", "retries",
858
2.80k
                   NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_RETRIES);
859
2.80k
    netsnmp_ds_register_config(ASN_OCTET_STR, "snmp", "outputPrecision",
860
2.80k
                               NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OUTPUT_PRECISION);
861
862
863
2.80k
    netsnmp_register_service_handlers();
864
2.80k
}
865
866
static int init_snmp_init_done = 0; /* To prevent double init's. */
867
/**
868
 * Calls the functions to do config file loading and  mib module parsing
869
 * in the correct order.
870
 *
871
 * @param type label for the config file "type"
872
 *
873
 * @return void
874
 *
875
 * @see init_agent
876
 */
877
void
878
init_snmp(const char *type)
879
4.56k
{
880
4.56k
    if (init_snmp_init_done) {
881
1.76k
        return;
882
1.76k
    }
883
884
2.80k
    init_snmp_init_done = 1;
885
886
    /*
887
     * make the type available everywhere else 
888
     */
889
2.80k
    if (type && !netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
890
2.80k
               NETSNMP_DS_LIB_APPTYPE)) {
891
1
        netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, 
892
1
            NETSNMP_DS_LIB_APPTYPE, type);
893
1
    }
894
895
2.80k
    _init_snmp();
896
897
    /*
898
     * set our current locale properly to initialize isprint() type functions 
899
     */
900
2.80k
#ifdef HAVE_SETLOCALE
901
2.80k
    setlocale(LC_CTYPE, "");
902
2.80k
#endif
903
904
2.80k
    snmp_debug_init();    /* should be done first, to turn on debugging ASAP */
905
2.80k
    netsnmp_container_init_list();
906
2.80k
    init_callbacks();
907
2.80k
    init_snmp_logging();
908
2.80k
    snmp_init_statistics();
909
2.80k
    register_mib_handlers();
910
2.80k
    register_default_handlers();
911
2.80k
    init_snmp_transport();
912
2.80k
    init_snmpv3(type);
913
2.80k
    init_snmp_alarm();
914
2.80k
    init_snmp_enum(type);
915
2.80k
    init_vacm();
916
2.80k
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
917
2.80k
    netsnmp_certs_init();
918
2.80k
#endif
919
#ifdef DNSSEC_LOCAL_VALIDATION
920
    netsnmp_ds_register_config(ASN_BOOLEAN, "snmp", "dnssecWarnOnly",
921
                               NETSNMP_DS_LIBRARY_ID,
922
                               NETSNMP_DS_LIB_DNSSEC_WARN_ONLY);
923
#endif
924
925
2.80k
    read_premib_configs();
926
2.80k
#ifndef NETSNMP_DISABLE_MIB_LOADING
927
2.80k
    netsnmp_init_mib();
928
2.80k
#endif /* NETSNMP_DISABLE_MIB_LOADING */
929
930
2.80k
    read_configs();
931
932
2.80k
}                               /* end init_snmp() */
933
934
/**
935
 * set a flag indicating that the persistent store needs to be saved.
936
 */
937
void
938
snmp_store_needed(const char *type)
939
0
{
940
0
    DEBUGMSGTL(("snmp_store", "setting needed flag...\n"));
941
0
    _snmp_store_needed = 1;
942
0
}
943
944
void
945
snmp_store_if_needed(void)
946
0
{
947
0
    if (0 == _snmp_store_needed)
948
0
        return;
949
    
950
0
    DEBUGMSGTL(("snmp_store", "store needed...\n"));
951
0
    snmp_store(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
952
0
                                     NETSNMP_DS_LIB_APPTYPE));
953
0
    _snmp_store_needed = 0;
954
0
}
955
956
void
957
snmp_store(const char *type)
958
2.79k
{
959
2.79k
    DEBUGMSGTL(("snmp_store", "storing stuff...\n"));
960
2.79k
    snmp_save_persistent(type);
961
2.79k
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
962
2.79k
    snmp_clean_persistent(type);
963
2.79k
}
964
965
966
/**
967
 * Shuts down the application, saving any needed persistent storage,
968
 * and appropriate clean up.
969
 * 
970
 * @param type Label for the config file "type" used
971
 *
972
 * @return void
973
 */
974
void
975
snmp_shutdown(const char *type)
976
2.79k
{
977
2.79k
    snmp_store(type);
978
2.79k
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
979
2.79k
    shutdown_snmp_logging();
980
2.79k
    snmp_alarm_unregister_all();
981
2.79k
    snmp_close_sessions();
982
2.79k
#ifndef NETSNMP_DISABLE_MIB_LOADING
983
2.79k
    shutdown_mib();
984
2.79k
#endif /* NETSNMP_DISABLE_MIB_LOADING */
985
2.79k
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
986
2.79k
    netsnmp_certs_shutdown();
987
2.79k
#endif
988
2.79k
#if !defined(NETSNMP_FEATURE_REMOVE_FILTER_SOURCE)
989
2.79k
    netsnmp_transport_filter_cleanup();
990
2.79k
#endif
991
2.79k
    unregister_all_config_handlers();
992
2.79k
    netsnmp_container_free_list();
993
2.79k
    clear_sec_mod();
994
2.79k
    clear_snmp_enum();
995
2.79k
    netsnmp_clear_tdomain_list();
996
2.79k
    clear_callback();
997
2.79k
    netsnmp_ds_shutdown();
998
2.79k
    netsnmp_clear_default_target();
999
2.79k
    netsnmp_clear_default_domain();
1000
2.79k
    shutdown_secmod();
1001
2.79k
    shutdown_snmp_transport();
1002
2.79k
    shutdown_data_list();
1003
2.79k
    snmp_debug_shutdown();    /* should be done last */
1004
1005
2.79k
    init_snmp_init_done  = 0;
1006
2.79k
    _init_snmp_init_done = 0;
1007
2.79k
}
1008
1009
/*
1010
 * inserts session into session list
1011
 */
1012
void  snmp_session_insert(struct session_list *slp)
1013
7.36k
{
1014
7.36k
    if (NULL == slp)
1015
0
        return;
1016
1017
7.36k
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
1018
7.36k
    slp->next = Sessions;
1019
7.36k
    Sessions = slp;
1020
7.36k
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
1021
7.36k
}
1022
1023
/*
1024
 * Sets up the session with the snmp_session information provided by the user.
1025
 * Then opens and binds the necessary low-level transport.  A handle to the
1026
 * created session is returned (this is NOT the same as the pointer passed to
1027
 * snmp_open()).  On any error, NULL is returned and snmp_errno is set to the
1028
 * appropriate error code.
1029
 */
1030
netsnmp_session *
1031
snmp_open(netsnmp_session *session)
1032
0
{
1033
0
    struct session_list *slp;
1034
1035
0
    slp = snmp_sess_open(session);
1036
0
    if (!slp) {
1037
0
        return NULL;
1038
0
    }
1039
1040
0
    slp->session->flags &= ~SNMP_FLAGS_SESSION_USER;
1041
1042
0
    snmp_session_insert(slp);
1043
1044
0
    return (slp->session);
1045
0
}
1046
1047
/*
1048
 * extended open 
1049
 */
1050
netsnmp_feature_child_of(snmp_open_ex, netsnmp_unused);
1051
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_OPEN_EX
1052
netsnmp_session *
1053
snmp_open_ex(netsnmp_session *session,
1054
             int (*fpre_parse)  (netsnmp_session *, netsnmp_transport *,
1055
                                void *, int),
1056
             int (*fparse)  (netsnmp_session *, netsnmp_pdu *, u_char *,
1057
         size_t),
1058
       int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
1059
1060
             int (*fbuild)  (netsnmp_session *, netsnmp_pdu *, u_char *,
1061
         size_t *),
1062
       int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
1063
         u_char **, size_t *, size_t *),
1064
             int (*fcheck)  (u_char *, size_t)
1065
       )
1066
0
{
1067
0
    struct session_list *slp;
1068
1069
0
    slp = snmp_sess_open(session);
1070
0
    if (!slp) {
1071
0
        return NULL;
1072
0
    }
1073
0
    slp->internal->hook_pre = fpre_parse;
1074
0
    slp->internal->hook_parse = fparse;
1075
0
    slp->internal->hook_post = fpost_parse;
1076
0
    slp->internal->hook_build = fbuild;
1077
0
    slp->internal->hook_realloc_build = frbuild;
1078
0
    slp->internal->check_packet = fcheck;
1079
1080
0
    slp->session->flags &= ~SNMP_FLAGS_SESSION_USER;
1081
1082
0
    snmp_session_insert(slp);
1083
1084
0
    return (slp->session);
1085
0
}
1086
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_OPEN_EX */
1087
1088
static struct session_list *
1089
_sess_copy(netsnmp_session * in_session)
1090
7.36k
{
1091
7.36k
    struct session_list *slp;
1092
7.36k
    struct snmp_internal_session *isp;
1093
7.36k
    netsnmp_session *session;
1094
7.36k
    struct snmp_secmod_def *sptr;
1095
7.36k
    char           *cp;
1096
7.36k
    u_char         *ucp;
1097
1098
7.36k
    in_session->s_snmp_errno = 0;
1099
7.36k
    in_session->s_errno = 0;
1100
1101
    /*
1102
     * Copy session structure and link into list 
1103
     */
1104
7.36k
    slp = calloc(1, sizeof(struct session_list));
1105
7.36k
    if (slp == NULL) {
1106
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1107
0
        return (NULL);
1108
0
    }
1109
1110
7.36k
    slp->transport = NULL;
1111
1112
7.36k
    isp = calloc(1, sizeof(struct snmp_internal_session));
1113
1114
7.36k
    if (isp == NULL) {
1115
0
        snmp_sess_close(slp);
1116
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1117
0
        return (NULL);
1118
0
    }
1119
1120
7.36k
    slp->internal = isp;
1121
7.36k
    slp->session = netsnmp_memdup(in_session, sizeof(netsnmp_session));
1122
7.36k
    if (slp->session == NULL) {
1123
0
        snmp_sess_close(slp);
1124
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1125
0
        return (NULL);
1126
0
    }
1127
7.36k
    session = slp->session;
1128
1129
    /*
1130
     * zero out pointers so if we have to free the session we wont free mem
1131
     * owned by in_session 
1132
     */
1133
7.36k
    session->localname = NULL;
1134
7.36k
    session->peername = NULL;
1135
7.36k
    session->community = NULL;
1136
7.36k
    session->contextEngineID = NULL;
1137
7.36k
    session->contextName = NULL;
1138
7.36k
    session->securityEngineID = NULL;
1139
7.36k
    session->securityName = NULL;
1140
7.36k
    session->securityAuthProto = NULL;
1141
7.36k
    session->securityAuthLocalKey = NULL;
1142
7.36k
    session->securityPrivProto = NULL;
1143
7.36k
    session->securityPrivLocalKey = NULL;
1144
7.36k
    session->sessUser = NULL;
1145
    /*
1146
     * session now points to the new structure that still contains pointers to
1147
     * data allocated elsewhere.  Some of this data is copied to space malloc'd
1148
     * here, and the pointer replaced with the new one.
1149
     */
1150
1151
7.36k
    if (in_session->peername != NULL) {
1152
1.77k
        session->peername =
1153
1.77k
            netsnmp_strdup_and_null((u_char*)in_session->peername,
1154
1.77k
                                    strlen(in_session->peername));
1155
1.77k
        if (session->peername == NULL) {
1156
0
            snmp_sess_close(slp);
1157
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1158
0
            return (NULL);
1159
0
        }
1160
1.77k
    }
1161
1162
    /*
1163
     * Fill in defaults if necessary 
1164
     */
1165
7.36k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1166
7.36k
    if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN) {
1167
0
        ucp = netsnmp_memdup(in_session->community, in_session->community_len);
1168
7.36k
    } else {
1169
7.36k
        if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1170
7.36k
          NETSNMP_DS_LIB_COMMUNITY)) != NULL) {
1171
0
            session->community_len = strlen(cp);
1172
0
            ucp = (u_char *) strdup(cp);
1173
7.36k
        } else {
1174
#ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
1175
            session->community_len = strlen(DEFAULT_COMMUNITY);
1176
            ucp = netsnmp_memdup(DEFAULT_COMMUNITY, session->community_len);
1177
#else
1178
7.36k
            ucp = (u_char *) strdup("");
1179
7.36k
#endif
1180
7.36k
        }
1181
7.36k
    }
1182
1183
7.36k
    if (ucp == NULL) {
1184
0
        snmp_sess_close(slp);
1185
0
        in_session->s_snmp_errno = SNMPERR_MALLOC;
1186
0
        return (NULL);
1187
0
    }
1188
7.36k
    session->community = ucp;   /* replace pointer with pointer to new data */
1189
7.36k
#endif
1190
1191
7.36k
    if (session->securityLevel <= 0) {
1192
7.36k
        session->securityLevel =
1193
7.36k
            netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECLEVEL);
1194
7.36k
    }
1195
1196
7.36k
    if (in_session->securityEngineIDLen > 0) {
1197
0
        ucp = netsnmp_memdup(in_session->securityEngineID,
1198
0
                             in_session->securityEngineIDLen);
1199
0
        if (ucp == NULL) {
1200
0
            snmp_sess_close(slp);
1201
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1202
0
            return (NULL);
1203
0
        }
1204
0
        session->securityEngineID = ucp;
1205
1206
0
    }
1207
1208
7.36k
    if (in_session->contextEngineIDLen > 0) {
1209
0
        ucp = netsnmp_memdup(in_session->contextEngineID,
1210
0
                             in_session->contextEngineIDLen);
1211
0
        if (ucp == NULL) {
1212
0
            snmp_sess_close(slp);
1213
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1214
0
            return (NULL);
1215
0
        }
1216
0
        session->contextEngineID = ucp;
1217
7.36k
    } else if (in_session->securityEngineIDLen > 0) {
1218
        /*
1219
         * default contextEngineID to securityEngineIDLen if defined 
1220
         */
1221
0
        ucp = netsnmp_memdup(in_session->securityEngineID,
1222
0
                             in_session->securityEngineIDLen);
1223
0
        if (ucp == NULL) {
1224
0
            snmp_sess_close(slp);
1225
0
            in_session->s_snmp_errno = SNMPERR_MALLOC;
1226
0
            return (NULL);
1227
0
        }
1228
0
        session->contextEngineID = ucp;
1229
0
        session->contextEngineIDLen = in_session->securityEngineIDLen;
1230
0
    }
1231
1232
7.36k
    if (in_session->contextName) {
1233
0
        session->contextName = strdup(in_session->contextName);
1234
0
        if (session->contextName == NULL) {
1235
0
            snmp_sess_close(slp);
1236
0
            return (NULL);
1237
0
        }
1238
0
        session->contextNameLen = in_session->contextNameLen;
1239
7.36k
    } else {
1240
7.36k
        if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1241
7.36k
                                        NETSNMP_DS_LIB_CONTEXT)) != NULL)
1242
0
            cp = strdup(cp);
1243
7.36k
        else
1244
7.36k
            cp = strdup(SNMP_DEFAULT_CONTEXT);
1245
7.36k
        if (cp == NULL) {
1246
0
            snmp_sess_close(slp);
1247
0
            return (NULL);
1248
0
        }
1249
7.36k
        session->contextName = cp;
1250
7.36k
        session->contextNameLen = strlen(cp);
1251
7.36k
    }
1252
1253
7.36k
    if (in_session->securityName) {
1254
0
        session->securityName = strdup(in_session->securityName);
1255
0
        if (session->securityName == NULL) {
1256
0
            snmp_sess_close(slp);
1257
0
            return (NULL);
1258
0
        }
1259
7.36k
    } else if ((cp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
1260
7.36k
             NETSNMP_DS_LIB_SECNAME)) != NULL) {
1261
0
        cp = strdup(cp);
1262
0
        if (cp == NULL) {
1263
0
            snmp_sess_close(slp);
1264
0
            return (NULL);
1265
0
        }
1266
0
        session->securityName = cp;
1267
0
        session->securityNameLen = strlen(cp);
1268
0
    }
1269
1270
7.36k
    if (in_session->securityAuthLocalKey) {
1271
0
            session->securityAuthLocalKey =
1272
0
                netsnmp_memdup(in_session->securityAuthLocalKey,
1273
0
                               in_session->securityAuthLocalKeyLen);
1274
0
            session->securityAuthLocalKeyLen =
1275
0
                in_session->securityAuthLocalKeyLen;
1276
0
    }
1277
1278
7.36k
    if (in_session->securityPrivLocalKey) {
1279
0
            session->securityPrivLocalKey =
1280
0
                netsnmp_memdup(in_session->securityPrivLocalKey,
1281
0
                               in_session->securityPrivLocalKeyLen);
1282
0
            session->securityPrivLocalKeyLen =
1283
0
                in_session->securityPrivLocalKeyLen;
1284
0
    }
1285
1286
7.36k
    if (session->retries == SNMP_DEFAULT_RETRIES) {
1287
4.56k
        int retry = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1288
4.56k
                                       NETSNMP_DS_LIB_RETRIES);
1289
4.56k
        if (retry < 0)
1290
0
            session->retries = DEFAULT_RETRIES;
1291
4.56k
        else
1292
4.56k
            session->retries = retry;
1293
4.56k
    }
1294
7.36k
    if (session->timeout == SNMP_DEFAULT_TIMEOUT) {
1295
4.56k
        int timeout = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
1296
4.56k
                                         NETSNMP_DS_LIB_TIMEOUT);
1297
4.56k
        if (timeout <= 0)
1298
4.56k
            session->timeout = DEFAULT_TIMEOUT;
1299
0
        else
1300
0
            session->timeout = timeout * 1000L * 1000L;
1301
4.56k
    }
1302
7.36k
    session->sessid = snmp_get_next_sessid();
1303
1304
7.36k
    snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SESSION_INIT,
1305
7.36k
                        session);
1306
1307
7.36k
    if ((sptr = find_sec_mod(session->securityModel)) != NULL) {
1308
        /*
1309
         * security module specific copying 
1310
         */
1311
4.56k
        if (sptr->session_setup) {
1312
4.56k
            int ret = (*sptr->session_setup) (in_session, session);
1313
4.56k
            if (ret != SNMPERR_SUCCESS) {
1314
0
                snmp_sess_close(slp);
1315
0
                return NULL;
1316
0
            }
1317
4.56k
        }
1318
1319
        /*
1320
         * security module specific opening
1321
         */
1322
4.56k
        if (sptr->session_open) {
1323
0
            int ret = (*sptr->session_open) (session);
1324
0
            if (ret != SNMPERR_SUCCESS) {
1325
0
                snmp_sess_close(slp);
1326
0
                return NULL;
1327
0
            }
1328
0
        }
1329
4.56k
    }
1330
1331
7.36k
#ifndef NETSNMP_NO_WRITE_SUPPORT
1332
7.36k
    if (in_session->sessUser) {
1333
0
        struct usmUser *user;
1334
1335
0
        user = calloc(1, sizeof(struct usmUser));
1336
0
        if (user == NULL) {
1337
0
            snmp_sess_close(slp);
1338
0
            return NULL;
1339
0
        }
1340
0
        session->sessUser = usm_cloneFrom_user(in_session->sessUser, user);
1341
0
    }
1342
7.36k
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1343
1344
    /* Anything below this point should only be done if the transport
1345
       had no say in the matter */
1346
7.36k
    if (session->securityLevel == 0)
1347
7.36k
        session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1348
1349
7.36k
    return (slp);
1350
7.36k
}
1351
1352
static struct session_list *
1353
snmp_sess_copy(netsnmp_session * pss)
1354
7.36k
{
1355
7.36k
    struct session_list *psl;
1356
7.36k
    psl = _sess_copy(pss);
1357
7.36k
    if (!psl) {
1358
0
        if (!pss->s_snmp_errno) {
1359
0
            pss->s_snmp_errno = SNMPERR_GENERR;
1360
0
        }
1361
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
1362
0
    }
1363
7.36k
    return psl;
1364
7.36k
}
1365
1366
/**
1367
 * Allocate a PDU for probing for the engineID
1368
 *
1369
 * The returned PDU can be used to probe synchronously or asynchronously.
1370
 * SNMP_FLAGS_DONT_PROBE must be set to disable internal synchronous probing,
1371
 * when response is received and all callbacks have executed the rest of PDUs
1372
 * can be sent as usual.
1373
 */
1374
netsnmp_pdu *snmpv3_probe_usm_pdu_create(void)
1375
0
{
1376
0
        netsnmp_pdu     *pdu;
1377
1378
0
        pdu = snmp_pdu_create(SNMP_MSG_GET);
1379
0
        if (!pdu)
1380
0
                return NULL;
1381
1382
0
        pdu->version = SNMP_VERSION_3;
1383
0
        pdu->securityName = strdup("");
1384
0
        pdu->securityNameLen = 0;
1385
0
        pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1386
0
        pdu->securityModel = SNMP_SEC_MODEL_USM;
1387
1388
0
        return pdu;
1389
0
}
1390
1391
#ifndef NETSNMP_FEATURE_REMOVE_SNMPV3_PROBE_CONTEXTENGINEID_RFC5343
1392
/**
1393
 * probe for engineID using RFC 5343 probing mechanisms
1394
 *
1395
 * Designed to be a callback for within a security model's probe_engineid hook.
1396
 * Since it's likely multiple security models won't have engineIDs to
1397
 * probe for then this function is a callback likely to be used by
1398
 * multiple future security models.  E.G. both SSH and DTLS.
1399
 */
1400
int
1401
snmpv3_probe_contextEngineID_rfc5343(struct session_list *slp,
1402
                                     netsnmp_session *session)
1403
0
{
1404
0
    netsnmp_pdu    *pdu = NULL, *response = NULL;
1405
0
    static const oid snmpEngineIDoid[]   = { 1,3,6,1,6,3,10,2,1,1,0};
1406
0
    static size_t   snmpEngineIDoid_len = 11;
1407
1408
0
    static char     probeEngineID[] = { (char)0x80, 0, 0, 0, 6 };
1409
0
    static size_t   probeEngineID_len = sizeof(probeEngineID);
1410
    
1411
0
    int status;
1412
1413
0
    pdu = snmp_pdu_create(SNMP_MSG_GET);
1414
0
    if (!pdu)
1415
0
        return SNMP_ERR_GENERR;
1416
0
    pdu->version = SNMP_VERSION_3;
1417
    /* don't require a securityName */
1418
0
    if (session->securityName) {
1419
0
        pdu->securityName = strdup(session->securityName);
1420
0
        pdu->securityNameLen = strlen(pdu->securityName);
1421
0
    }
1422
0
    pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
1423
0
    pdu->securityModel = session->securityModel;
1424
0
    pdu->contextEngineID = netsnmp_memdup(probeEngineID, probeEngineID_len);
1425
0
    if (!pdu->contextEngineID) {
1426
0
        snmp_log(LOG_ERR, "failed to clone memory for rfc5343 probe\n");
1427
0
        snmp_free_pdu(pdu);
1428
0
        return SNMP_ERR_GENERR;
1429
0
    }
1430
0
    pdu->contextEngineIDLen = probeEngineID_len;
1431
    
1432
0
    snmp_add_null_var(pdu, snmpEngineIDoid, snmpEngineIDoid_len);
1433
1434
0
    DEBUGMSGTL(("snmp_api", "probing for engineID using rfc5343 methods...\n"));
1435
0
    session->flags |= SNMP_FLAGS_DONT_PROBE; /* prevent recursion */
1436
0
    status = snmp_sess_synch_response(slp, pdu, &response);
1437
1438
0
    if ((response == NULL) || (status != STAT_SUCCESS)) {
1439
0
        snmp_log(LOG_ERR, "failed rfc5343 contextEngineID probing\n");
1440
0
        return SNMP_ERR_GENERR;
1441
0
    }
1442
1443
    /* check that the response makes sense */
1444
0
    if (NULL != response->variables &&
1445
0
        NULL != response->variables->name &&
1446
0
        snmp_oid_compare(response->variables->name,
1447
0
                         response->variables->name_length,
1448
0
                         snmpEngineIDoid, snmpEngineIDoid_len) == 0 &&
1449
0
        ASN_OCTET_STR == response->variables->type  &&
1450
0
        NULL != response->variables->val.string &&
1451
0
        response->variables->val_len > 0) {
1452
0
        session->contextEngineID =
1453
0
            netsnmp_memdup(response->variables->val.string,
1454
0
                           response->variables->val_len);
1455
0
        if (!session->contextEngineID) {
1456
0
            snmp_log(LOG_ERR, "failed rfc5343 contextEngineID probing: memory allocation failed\n");
1457
0
            return SNMP_ERR_GENERR;
1458
0
        }
1459
        
1460
        /* technically there likely isn't a securityEngineID but just
1461
           in case anyone goes looking we might as well have one */
1462
0
        session->securityEngineID =
1463
0
            netsnmp_memdup(response->variables->val.string,
1464
0
                           response->variables->val_len);
1465
0
        if (!session->securityEngineID) {
1466
0
            snmp_log(LOG_ERR, "failed rfc5343 securityEngineID probing: memory allocation failed\n");
1467
0
            return SNMP_ERR_GENERR;
1468
0
        }
1469
        
1470
0
        session->securityEngineIDLen = session->contextEngineIDLen =
1471
0
            response->variables->val_len;
1472
        
1473
0
        if (snmp_get_do_debugging()) {
1474
0
            size_t i;
1475
0
            DEBUGMSGTL(("snmp_sess_open",
1476
0
                        "  probe found engineID:  "));
1477
0
            for (i = 0; i < session->securityEngineIDLen; i++)
1478
0
                DEBUGMSG(("snmp_sess_open", "%02x",
1479
0
                          session->securityEngineID[i]));
1480
0
            DEBUGMSG(("snmp_sess_open", "\n"));
1481
0
        }
1482
0
    }
1483
0
    return SNMPERR_SUCCESS;
1484
0
}
1485
#endif /* NETSNMP_FEATURE_REMOVE_SNMPV3_PROBE_CONTEXTENGINEID_RFC5343 */
1486
1487
1488
/**
1489
 * probe for peer engineID
1490
 *
1491
 * @param slp         session list pointer.
1492
 * @param in_session  session for errors
1493
 *
1494
 * @note
1495
 *  - called by _sess_open(), snmp_sess_add_ex()
1496
 *  - in_session is the user supplied session provided to those functions.
1497
 *  - the first session in slp should the internal allocated copy of in_session
1498
 *
1499
 * @return 0 : error
1500
 * @return 1 : ok
1501
 *
1502
 */
1503
int
1504
snmpv3_engineID_probe(struct session_list *slp,
1505
                      netsnmp_session * in_session)
1506
0
{
1507
0
    netsnmp_session *session;
1508
0
    int             status;
1509
0
    struct snmp_secmod_def *sptr = NULL;
1510
1511
0
    if (slp == NULL || slp->session == NULL) {
1512
0
        return 0;
1513
0
    }
1514
1515
0
    session = slp->session;
1516
0
    netsnmp_assert_or_return(session != NULL, 0);
1517
0
    sptr = find_sec_mod(session->securityModel);
1518
1519
    /*
1520
     * If we are opening a V3 session and we don't know engineID we must probe
1521
     * it -- this must be done after the session is created and inserted in the
1522
     * list so that the response can handled correctly. 
1523
     */
1524
1525
0
    if (session->version == SNMP_VERSION_3 &&
1526
0
        (0 == (session->flags & SNMP_FLAGS_DONT_PROBE))) {
1527
0
        if (NULL != sptr && NULL != sptr->probe_engineid) {
1528
0
            DEBUGMSGTL(("snmp_api", "probing for engineID using security model callback...\n"));
1529
            /* security model specific mechanism of determining engineID */
1530
0
            status = (*sptr->probe_engineid) (slp, in_session);
1531
0
            if (status != SNMPERR_SUCCESS)
1532
0
                return 0;
1533
0
        } else {
1534
            /* XXX: default to the default RFC5343 contextEngineID Probe? */
1535
0
            return 0;
1536
0
        }
1537
0
    }
1538
1539
    /*
1540
     * see if there is a hook to call now that we're done probing for an
1541
     * engineID
1542
     */
1543
0
    if (sptr && sptr->post_probe_engineid) {
1544
0
        status = (*sptr->post_probe_engineid)(slp, in_session);
1545
0
        if (status != SNMPERR_SUCCESS)
1546
0
            return 0;
1547
0
    }
1548
1549
0
    return 1;
1550
0
}
1551
1552
/*******************************************************************-o-******
1553
 * netsnmp_sess_config_transport
1554
 *
1555
 * Parameters:
1556
 *  *in_session
1557
 *  *in_transport
1558
 *
1559
 * Returns:
1560
 *      SNMPERR_SUCCESS                     - Yay
1561
 *      SNMPERR_GENERR                      - Generic Error
1562
 *      SNMPERR_TRANSPORT_CONFIG_ERROR      - Transport rejected config
1563
 *      SNMPERR_TRANSPORT_NO_CONFIG         - Transport can't config
1564
 */
1565
int
1566
netsnmp_sess_config_transport(netsnmp_container *transport_configuration,
1567
                              netsnmp_transport *transport)
1568
7.36k
{
1569
    /* Optional supplemental transport configuration information and
1570
       final call to actually open the transport */
1571
7.36k
    if (transport_configuration) {
1572
0
        DEBUGMSGTL(("snmp_sess", "configuring transport\n"));
1573
0
        if (transport->f_config) {
1574
0
            netsnmp_iterator *iter;
1575
0
            netsnmp_transport_config *config_data;
1576
0
            int ret = 0;
1577
1578
0
            iter = CONTAINER_ITERATOR(transport_configuration);
1579
0
            if (NULL == iter) {
1580
0
                return SNMPERR_GENERR;
1581
0
            }
1582
1583
0
            for(config_data = (netsnmp_transport_config*)ITERATOR_FIRST(iter); config_data;
1584
0
                config_data = (netsnmp_transport_config*)ITERATOR_NEXT(iter)) {
1585
0
                ret = transport->f_config(transport, config_data->key,
1586
0
                                          config_data->value);
1587
0
                if (ret)
1588
0
                    break;
1589
0
            }
1590
0
            ITERATOR_RELEASE(iter);
1591
0
            if (ret)
1592
0
                return SNMPERR_TRANSPORT_CONFIG_ERROR;
1593
0
        } else {
1594
0
            return SNMPERR_TRANSPORT_NO_CONFIG;
1595
0
        }
1596
0
    }
1597
7.36k
    return SNMPERR_SUCCESS;
1598
7.36k
}
1599
1600
 
1601
/**
1602
 * Copies configuration from the session and calls f_open
1603
 * This function copies any configuration stored in the session
1604
 * pointer to the transport if it has a f_config pointer and then
1605
 * calls the transport's f_open function to actually open the
1606
 * connection.
1607
 *
1608
 * @param in_session A pointer to the session that config information is in.
1609
 * @param transport A pointer to the transport to config/open.
1610
 *
1611
 * @return SNMPERR_SUCCESS : on success
1612
 */
1613
1614
/*******************************************************************-o-******
1615
 * netsnmp_sess_config_transport
1616
 *
1617
 * Parameters:
1618
 *  *in_session
1619
 *  *in_transport
1620
 *
1621
 * Returns:
1622
 *      SNMPERR_SUCCESS                     - Yay
1623
 *      SNMPERR_GENERR                      - Generic Error
1624
 *      SNMPERR_TRANSPORT_CONFIG_ERROR      - Transport rejected config
1625
 *      SNMPERR_TRANSPORT_NO_CONFIG         - Transport can't config
1626
 */
1627
int
1628
netsnmp_sess_config_and_open_transport(netsnmp_session *in_session,
1629
                                       netsnmp_transport *transport)
1630
7.36k
{
1631
7.36k
    int rc;
1632
    
1633
7.36k
    DEBUGMSGTL(("snmp_sess", "opening transport: %x\n", transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED));
1634
1635
    /* don't double open */
1636
7.36k
    if (transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED)
1637
2.79k
        return SNMPERR_SUCCESS;
1638
1639
4.56k
    if ((rc = netsnmp_sess_config_transport(in_session->transport_configuration,
1640
4.56k
                                            transport)) != SNMPERR_SUCCESS) {
1641
0
        in_session->s_snmp_errno = rc;
1642
0
        in_session->s_errno = 0;
1643
0
        return rc;
1644
0
    }
1645
        
1646
4.56k
    if (transport->f_open)
1647
0
        transport = transport->f_open(transport);
1648
1649
4.56k
    if (transport == NULL) {
1650
0
        DEBUGMSGTL(("snmp_sess", "couldn't open transport connection\n"));
1651
0
        in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
1652
0
        in_session->s_errno = errno;
1653
0
        snmp_set_detail(in_session->peername);
1654
0
        return SNMPERR_BAD_ADDRESS;
1655
0
    }
1656
1657
    /** if transport has a max size, make sure session is the same (or less) */
1658
4.56k
    if (in_session->rcvMsgMaxSize > transport->msgMaxSize) {
1659
1.77k
        DEBUGMSGTL(("snmp_sess",
1660
1.77k
                    "limiting session rcv size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1661
1.77k
                    in_session->rcvMsgMaxSize, transport->msgMaxSize));
1662
1.77k
        in_session->rcvMsgMaxSize = transport->msgMaxSize;
1663
1.77k
    }
1664
1665
4.56k
    if (in_session->sndMsgMaxSize > transport->msgMaxSize) {
1666
1.77k
        DEBUGMSGTL(("snmp_sess",
1667
1.77k
                    "limiting session snd size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1668
1.77k
                    in_session->sndMsgMaxSize, transport->msgMaxSize));
1669
1.77k
        in_session->sndMsgMaxSize = transport->msgMaxSize;
1670
1.77k
    }
1671
1672
4.56k
    transport->flags |= NETSNMP_TRANSPORT_FLAG_OPENED;
1673
4.56k
    DEBUGMSGTL(("snmp_sess", "done opening transport: %x\n", transport->flags & NETSNMP_TRANSPORT_FLAG_OPENED));
1674
4.56k
    return SNMPERR_SUCCESS;
1675
4.56k
}
1676
1677
/*******************************************************************-o-******
1678
 * snmp_sess_open
1679
 *
1680
 * Parameters:
1681
 *  *in_session
1682
 *
1683
 * Returns:
1684
 *      Pointer to a session in the session list   -OR-   FIX -- right?
1685
 *  NULL on failure.
1686
 *
1687
 * The "spin-free" version of snmp_open.
1688
 */
1689
static struct session_list *
1690
_sess_open(netsnmp_session * in_session)
1691
0
{
1692
0
    netsnmp_transport *transport = NULL;
1693
0
    int rc;
1694
1695
0
    in_session->s_snmp_errno = 0;
1696
0
    in_session->s_errno = 0;
1697
1698
0
    _init_snmp();
1699
1700
0
    {
1701
0
        char *clientaddr_save = NULL;
1702
1703
0
        if (NULL != in_session->localname) {
1704
0
            clientaddr_save =
1705
0
                netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1706
0
                                      NETSNMP_DS_LIB_CLIENT_ADDR);
1707
0
            if (clientaddr_save)
1708
0
                clientaddr_save = strdup(clientaddr_save);
1709
1710
0
            netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1711
0
                                  NETSNMP_DS_LIB_CLIENT_ADDR,
1712
0
                                  in_session->localname);
1713
0
        }
1714
1715
0
        if (in_session->flags & SNMP_FLAGS_STREAM_SOCKET) {
1716
0
            transport =
1717
0
                netsnmp_tdomain_transport_full("snmp", in_session->peername,
1718
0
                                               in_session->local_port, "tcp,tcp6",
1719
0
                                               NULL);
1720
0
        } else {
1721
0
            transport =
1722
0
                netsnmp_tdomain_transport_full("snmp", in_session->peername,
1723
0
                                               in_session->local_port, "udp,udp6",
1724
0
                                               NULL);
1725
0
        }
1726
1727
0
        if (NULL != in_session->localname)
1728
0
            netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
1729
0
                                  NETSNMP_DS_LIB_CLIENT_ADDR, clientaddr_save);
1730
0
        free(clientaddr_save);
1731
0
    }
1732
1733
0
    if (transport == NULL) {
1734
0
        DEBUGMSGTL(("_sess_open", "couldn't interpret peername\n"));
1735
0
        in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
1736
0
        in_session->s_errno = errno;
1737
0
        snmp_set_detail(in_session->peername);
1738
0
        return NULL;
1739
0
    }
1740
1741
    /* Optional supplemental transport configuration information and
1742
       final call to actually open the transport */
1743
0
    if ((rc = netsnmp_sess_config_and_open_transport(in_session, transport))
1744
0
        != SNMPERR_SUCCESS) {
1745
0
        transport = NULL;
1746
0
        return NULL;
1747
0
    }
1748
1749
0
#if defined(SO_BROADCAST) && defined(SOL_SOCKET)
1750
0
    if ( in_session->flags & SNMP_FLAGS_UDP_BROADCAST) {
1751
0
        int   b = 1;
1752
0
        int   rc;
1753
1754
0
        rc = setsockopt(transport->sock, SOL_SOCKET, SO_BROADCAST,
1755
0
                        (char *)&b, sizeof(b));
1756
1757
0
        if ( rc != 0 ) {
1758
0
            in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS; /* good as any? */
1759
0
            in_session->s_errno = errno;
1760
1761
0
            DEBUGMSGTL(("_sess_open", "couldn't enable UDP_BROADCAST\n"));
1762
0
            return NULL;
1763
0
        }
1764
0
    }
1765
0
#endif
1766
1767
0
    return snmp_sess_add(in_session, transport, NULL, NULL);
1768
0
}
1769
1770
/*
1771
 * EXTENDED SESSION API ------------------------------------------ 
1772
 * 
1773
 * snmp_sess_add_ex, snmp_sess_add, snmp_add 
1774
 * 
1775
 * Analogous to snmp_open family of functions, but taking a netsnmp_transport
1776
 * pointer as an extra argument.  Unlike snmp_open et al. it doesn't attempt
1777
 * to interpret the in_session->peername as a transport endpoint specifier,
1778
 * but instead uses the supplied transport.  JBPN
1779
 * 
1780
 */
1781
1782
netsnmp_session *
1783
snmp_add(netsnmp_session * in_session,
1784
         netsnmp_transport *transport,
1785
         int (*fpre_parse) (netsnmp_session *, netsnmp_transport *, void *,
1786
                            int), int (*fpost_parse) (netsnmp_session *,
1787
                                                      netsnmp_pdu *, int))
1788
4.56k
{
1789
4.56k
    struct session_list *slp;
1790
1791
4.56k
    slp = snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
1792
4.56k
                           fpost_parse, NULL, NULL, NULL, NULL);
1793
4.56k
    if (slp == NULL) {
1794
0
        return NULL;
1795
0
    }
1796
1797
4.56k
    snmp_session_insert(slp);
1798
1799
4.56k
    return (slp->session);
1800
4.56k
}
1801
1802
netsnmp_session *
1803
snmp_add_full(netsnmp_session * in_session,
1804
              netsnmp_transport *transport,
1805
              int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1806
                                 void *, int),
1807
              int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
1808
                             size_t),
1809
              int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int),
1810
              int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
1811
                             size_t *), int (*frbuild) (netsnmp_session *,
1812
                                                        netsnmp_pdu *,
1813
                                                        u_char **,
1814
                                                        size_t *,
1815
                                                        size_t *),
1816
              int (*fcheck) (u_char *, size_t),
1817
              netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
1818
                                           size_t))
1819
2.79k
{
1820
2.79k
    struct session_list *slp;
1821
1822
2.79k
    slp = snmp_sess_add_ex(in_session, transport, fpre_parse, fparse,
1823
2.79k
                           fpost_parse, fbuild, frbuild, fcheck, fcreate_pdu);
1824
2.79k
    if (slp == NULL) {
1825
0
        return NULL;
1826
0
    }
1827
1828
2.79k
    snmp_session_insert(slp);
1829
1830
2.79k
    return (slp->session);
1831
2.79k
}
1832
1833
struct session_list *
1834
snmp_sess_add_ex(netsnmp_session * in_session,
1835
                 netsnmp_transport *transport,
1836
                 int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1837
                                    void *, int),
1838
                 int (*fparse) (netsnmp_session *, netsnmp_pdu *, u_char *,
1839
                                size_t),
1840
                 int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
1841
                                     int),
1842
                 int (*fbuild) (netsnmp_session *, netsnmp_pdu *, u_char *,
1843
                                size_t *),
1844
                 int (*frbuild) (netsnmp_session *, netsnmp_pdu *,
1845
                                 u_char **, size_t *, size_t *),
1846
                 int (*fcheck) (u_char *, size_t),
1847
                 netsnmp_pdu *(*fcreate_pdu) (netsnmp_transport *, void *,
1848
                                              size_t))
1849
7.36k
{
1850
7.36k
    struct session_list *slp;
1851
7.36k
    int rc;
1852
    
1853
7.36k
    _init_snmp();
1854
1855
7.36k
    if (transport == NULL)
1856
0
        return NULL;
1857
1858
7.36k
    if (NULL != in_session && (in_session->rcvMsgMaxSize < SNMP_MIN_MAX_LEN ||
1859
7.36k
                               in_session->sndMsgMaxSize < SNMP_MIN_MAX_LEN)) {
1860
0
        DEBUGMSGTL(("snmp_sess_add",
1861
0
                    "invalid session (msg sizes). need snmp_sess_init"));
1862
0
        in_session = NULL; /* force transport cleanup below */
1863
0
    }
1864
1865
7.36k
    if (in_session == NULL) {
1866
0
        transport->f_close(transport);
1867
0
        netsnmp_transport_free(transport);
1868
0
        return NULL;
1869
0
    }
1870
1871
    /* if the transport hasn't been fully opened yet, open it now */
1872
7.36k
    if ((rc = netsnmp_sess_config_and_open_transport(in_session, transport))
1873
7.36k
        != SNMPERR_SUCCESS) {
1874
0
        return NULL;
1875
0
    }
1876
1877
7.36k
    if (transport->f_setup_session) {
1878
2.79k
        if (SNMPERR_SUCCESS !=
1879
2.79k
            transport->f_setup_session(transport, in_session)) {
1880
0
            netsnmp_transport_free(transport);
1881
0
            return NULL;
1882
0
        }
1883
2.79k
    }
1884
        
1885
            
1886
7.36k
    DEBUGMSGTL(("snmp_sess_add", "fd %d\n", transport->sock));
1887
1888
1889
7.36k
    if ((slp = snmp_sess_copy(in_session)) == NULL) {
1890
0
        transport->f_close(transport);
1891
0
        netsnmp_transport_free(transport);
1892
0
        return (NULL);
1893
0
    }
1894
1895
7.36k
    slp->transport = transport;
1896
7.36k
    slp->internal->hook_pre = fpre_parse;
1897
7.36k
    slp->internal->hook_parse = fparse;
1898
7.36k
    slp->internal->hook_post = fpost_parse;
1899
7.36k
    slp->internal->hook_build = fbuild;
1900
7.36k
    slp->internal->hook_realloc_build = frbuild;
1901
7.36k
    slp->internal->check_packet = fcheck;
1902
7.36k
    slp->internal->hook_create_pdu = fcreate_pdu;
1903
1904
    /** don't let session max exceed transport max */
1905
7.36k
    if (slp->session->rcvMsgMaxSize > transport->msgMaxSize) {
1906
2.79k
        DEBUGMSGTL(("snmp_sess_add",
1907
2.79k
                    "limiting session rcv size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1908
2.79k
                    slp->session->rcvMsgMaxSize, transport->msgMaxSize));
1909
2.79k
        slp->session->rcvMsgMaxSize = transport->msgMaxSize;
1910
2.79k
    }
1911
7.36k
    if (slp->session->sndMsgMaxSize > transport->msgMaxSize) {
1912
2.79k
        DEBUGMSGTL(("snmp_sess_add",
1913
2.79k
                    "limiting session snd size (%" NETSNMP_PRIz "d) to transport max (%" NETSNMP_PRIz "d)\n",
1914
2.79k
                    slp->session->sndMsgMaxSize, transport->msgMaxSize));
1915
2.79k
        slp->session->sndMsgMaxSize = transport->msgMaxSize;
1916
2.79k
    }
1917
1918
7.36k
    if (slp->session->version == SNMP_VERSION_3) {
1919
0
        DEBUGMSGTL(("snmp_sess_add",
1920
0
                    "adding v3 session -- maybe engineID probe now\n"));
1921
0
        if (!snmpv3_engineID_probe(slp, slp->session)) {
1922
0
            DEBUGMSGTL(("snmp_sess_add", "engine ID probe failed\n"));
1923
0
            snmp_sess_close(slp);
1924
0
            return NULL;
1925
0
        }
1926
0
    }
1927
1928
7.36k
    slp->session->flags &= ~SNMP_FLAGS_DONT_PROBE;
1929
1930
7.36k
    return slp;
1931
7.36k
}                               /*  end snmp_sess_add_ex()  */
1932
1933
struct session_list *
1934
snmp_sess_add(netsnmp_session * in_session,
1935
              netsnmp_transport *transport,
1936
              int (*fpre_parse) (netsnmp_session *, netsnmp_transport *,
1937
                                 void *, int),
1938
              int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int))
1939
0
{
1940
0
    return snmp_sess_add_ex(in_session, transport, fpre_parse, NULL,
1941
0
                            fpost_parse, NULL, NULL, NULL, NULL);
1942
0
}
1943
1944
1945
1946
struct session_list *
1947
snmp_sess_open(netsnmp_session * pss)
1948
0
{
1949
0
    struct session_list *slp;
1950
1951
0
    pss->flags |= SNMP_FLAGS_SESSION_USER;
1952
1953
0
    slp = _sess_open(pss);
1954
0
    if (!slp) {
1955
0
        SET_SNMP_ERROR(pss->s_snmp_errno);
1956
0
    }
1957
0
    return slp;
1958
0
}
1959
1960
int
1961
1.77k
create_user_from_session(netsnmp_session * session) {
1962
1.77k
#ifdef NETSNMP_SECMOD_USM
1963
1.77k
    return usm_create_user_from_session(session);
1964
#else
1965
    snmp_log(LOG_ERR, "create_user_from_session called when USM wasn't compiled in");
1966
    netsnmp_assert(0 == 1);
1967
    return SNMP_ERR_GENERR;
1968
#endif
1969
1.77k
}
1970
1971
/* Free the memory owned by a session but not the session object itself. */
1972
void netsnmp_cleanup_session(netsnmp_session *s)
1973
9.08k
{
1974
9.08k
    free(s->localname);
1975
9.08k
    free(s->peername);
1976
9.08k
    free(s->community);
1977
9.08k
    free(s->contextEngineID);
1978
9.08k
    free(s->contextName);
1979
9.08k
    free(s->securityEngineID);
1980
9.08k
    free(s->securityName);
1981
9.08k
    free(s->securityAuthProto);
1982
9.08k
    free(s->securityAuthLocalKey);
1983
9.08k
    free(s->securityPrivProto);
1984
9.08k
    free(s->securityPrivLocalKey);
1985
9.08k
    free(s->paramName);
1986
9.08k
#ifndef NETSNMP_NO_TRAP_STATS
1987
9.08k
    free(s->trap_stats);
1988
9.08k
#endif /* NETSNMP_NO_TRAP_STATS */
1989
9.08k
    usm_free_user(s->sessUser);
1990
9.08k
    memset(s, 0, sizeof(*s));
1991
9.08k
}
1992
1993
/*
1994
 *  Do a "deep free()" of a netsnmp_session.
1995
 *
1996
 *  CAUTION:  SHOULD ONLY BE USED FROM snmp_sess_close() OR SIMILAR.
1997
 *                                                      (hence it is static)
1998
 */
1999
static void
2000
snmp_free_session(netsnmp_session * s)
2001
5.59k
{
2002
5.59k
    if (!s)
2003
0
        return;
2004
2005
5.59k
    netsnmp_cleanup_session(s);
2006
2007
    /*
2008
     * clear session from any callbacks
2009
     */
2010
5.59k
    netsnmp_callback_clear_client_arg(s, 0, 0);
2011
2012
5.59k
    free(s);
2013
5.59k
}
2014
2015
/*
2016
 * Close the input session.  Frees all data allocated for the session,
2017
 * dequeues any pending requests, and closes any sockets allocated for
2018
 * the session.  Returns 0 on error, 1 otherwise.
2019
 */
2020
int
2021
snmp_sess_close(struct session_list *slp)
2022
5.59k
{
2023
5.59k
    netsnmp_transport *transport;
2024
5.59k
    struct snmp_internal_session *isp;
2025
5.59k
    netsnmp_session *sesp = NULL;
2026
5.59k
    struct snmp_secmod_def *sptr;
2027
2028
5.59k
    if (slp == NULL) {
2029
0
        return 0;
2030
0
    }
2031
2032
5.59k
    if (slp->session != NULL &&
2033
5.59k
        (sptr = find_sec_mod(slp->session->securityModel)) != NULL &&
2034
5.59k
        sptr->session_close != NULL) {
2035
0
        (*sptr->session_close) (slp->session);
2036
0
    }
2037
2038
5.59k
    isp = slp->internal;
2039
5.59k
    slp->internal = NULL;
2040
2041
5.59k
    if (isp) {
2042
5.59k
        netsnmp_request_list *rp, *orp;
2043
2044
5.59k
        SNMP_FREE(isp->packet);
2045
2046
        /*
2047
         * Free each element in the input request list.  
2048
         */
2049
5.59k
        rp = isp->requests;
2050
5.59k
        while (rp) {
2051
0
            orp = rp;
2052
0
            rp = rp->next_request;
2053
0
            if (orp->callback) {
2054
0
                orp->callback(NETSNMP_CALLBACK_OP_TIMED_OUT,
2055
0
                              slp->session, orp->pdu->reqid,
2056
0
                              orp->pdu, orp->cb_data);
2057
0
            }
2058
0
            snmp_free_pdu(orp->pdu);
2059
0
            free(orp);
2060
0
        }
2061
2062
5.59k
        free(isp);
2063
5.59k
    }
2064
2065
5.59k
    transport = slp->transport;
2066
5.59k
    slp->transport = NULL;
2067
2068
5.59k
    if (transport) {
2069
5.59k
        transport->f_close(transport);
2070
5.59k
        netsnmp_transport_free(transport);
2071
5.59k
    }
2072
2073
5.59k
    sesp = slp->session;
2074
5.59k
    slp->session = NULL;
2075
2076
    /*
2077
     * The following is necessary to avoid memory leakage when closing AgentX 
2078
     * sessions that may have multiple subsessions.  These hang off the main
2079
     * session at ->subsession, and chain through ->next.  
2080
     */
2081
2082
5.59k
    if (sesp != NULL && sesp->subsession != NULL) {
2083
0
        netsnmp_session *subsession = sesp->subsession, *tmpsub;
2084
2085
0
        while (subsession != NULL) {
2086
0
            DEBUGMSGTL(("snmp_sess_close",
2087
0
                        "closing session %p, subsession %p\n", sesp,
2088
0
                        subsession));
2089
0
            tmpsub = subsession->next;
2090
0
            snmp_free_session(subsession);
2091
0
            subsession = tmpsub;
2092
0
        }
2093
0
    }
2094
2095
5.59k
    snmp_free_session(sesp);
2096
5.59k
    free(slp);
2097
5.59k
    return 1;
2098
5.59k
}
2099
2100
int
2101
snmp_close(netsnmp_session * session)
2102
4.56k
{
2103
4.56k
    struct session_list *slp = NULL, *oslp = NULL;
2104
2105
4.56k
    {                           /*MTCRITICAL_RESOURCE */
2106
4.56k
        snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
2107
4.56k
        if (Sessions && Sessions->session == session) { /* If first entry */
2108
2.79k
            slp = Sessions;
2109
2.79k
            Sessions = slp->next;
2110
2.79k
        } else {
2111
1.56M
            for (slp = Sessions; slp; slp = slp->next) {
2112
1.56M
                if (slp->session == session) {
2113
0
                    if (oslp)   /* if we found entry that points here */
2114
0
                        oslp->next = slp->next; /* link around this entry */
2115
0
                    break;
2116
0
                }
2117
1.56M
                oslp = slp;
2118
1.56M
            }
2119
1.77k
        }
2120
4.56k
        snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
2121
4.56k
    }                           /*END MTCRITICAL_RESOURCE */
2122
4.56k
    if (slp == NULL) {
2123
1.77k
        return 0;
2124
1.77k
    }
2125
2.79k
    return snmp_sess_close(slp);
2126
4.56k
}
2127
2128
int
2129
snmp_close_sessions(void)
2130
2.79k
{
2131
2.79k
    struct session_list *slp;
2132
2133
2.79k
    snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
2134
5.59k
    while (Sessions) {
2135
2.79k
        slp = Sessions;
2136
2.79k
        Sessions = Sessions->next;
2137
2.79k
        snmp_sess_close(slp);
2138
2.79k
    }
2139
2.79k
    snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
2140
2.79k
    return 1;
2141
2.79k
}
2142
2143
static void
2144
snmpv3_calc_msg_flags(int sec_level, int msg_command, u_char * flags)
2145
0
{
2146
0
    *flags = 0;
2147
0
    if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
2148
0
        *flags = SNMP_MSG_FLAG_AUTH_BIT;
2149
0
    else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
2150
0
        *flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
2151
2152
0
    if (SNMP_CMD_CONFIRMED(msg_command))
2153
0
        *flags |= SNMP_MSG_FLAG_RPRT_BIT;
2154
2155
0
    return;
2156
0
}
2157
2158
static int
2159
snmpv3_verify_msg(netsnmp_request_list *rp, netsnmp_pdu *pdu)
2160
0
{
2161
0
    netsnmp_pdu    *rpdu;
2162
2163
    /* XX: This function silently rejects. Add error handling. */
2164
0
    if (!rp || !rp->pdu || !pdu)
2165
0
        return 0;
2166
    /*
2167
     * Reports don't have to match anything according to the spec 
2168
     */
2169
0
    if (pdu->command == SNMP_MSG_REPORT)
2170
0
        return 1;
2171
0
    rpdu = rp->pdu;
2172
0
    if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid)
2173
0
        return 0;
2174
0
    if (rpdu->version != pdu->version)
2175
0
        return 0;
2176
0
    if (rpdu->securityModel != pdu->securityModel)
2177
0
        return 0;
2178
0
    if (rpdu->securityLevel != pdu->securityLevel)
2179
0
        return 0;
2180
2181
0
    if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen)
2182
0
        return 0;
2183
0
    if (pdu->contextEngineIDLen &&
2184
0
        memcmp(rpdu->contextEngineID, pdu->contextEngineID,
2185
0
               pdu->contextEngineIDLen))
2186
0
        return 0;
2187
0
    if (rpdu->contextNameLen != pdu->contextNameLen)
2188
0
        return 0;
2189
0
    if (pdu->contextNameLen &&
2190
0
        memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
2191
0
        return 0;
2192
2193
    /* tunneled transports don't have a securityEngineID...  that's
2194
       USM specific (and maybe other future ones) */
2195
0
    if (pdu->securityModel == SNMP_SEC_MODEL_USM &&
2196
0
        (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
2197
0
         (pdu->securityEngineIDLen &&
2198
0
          memcmp(rpdu->securityEngineID, pdu->securityEngineID,
2199
0
                 pdu->securityEngineIDLen))))
2200
0
        return 0;
2201
2202
    /* the securityName must match though regardless of secmodel */
2203
0
    if (rpdu->securityNameLen != pdu->securityNameLen ||
2204
0
        memcmp(rpdu->securityName, pdu->securityName,
2205
0
               pdu->securityNameLen))
2206
0
        return 0;
2207
0
    return 1;
2208
0
}
2209
2210
2211
/*
2212
 * SNMPv3
2213
 * * Takes a session and a pdu and serializes the ASN PDU into the area
2214
 * * pointed to by packet.  out_length is the size of the data area available.
2215
 * * Returns the length of the completed packet in out_length.  If any errors
2216
 * * occur, -1 is returned.  If all goes well, 0 is returned.
2217
 */
2218
static int
2219
snmpv3_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
2220
             netsnmp_session * session, netsnmp_pdu *pdu)
2221
226
{
2222
226
    int             ret;
2223
2224
226
    session->s_snmp_errno = 0;
2225
226
    session->s_errno = 0;
2226
2227
    /*
2228
     * do validation for PDU types 
2229
     */
2230
226
    switch (pdu->command) {
2231
0
    case SNMP_MSG_RESPONSE:
2232
0
    case SNMP_MSG_TRAP2:
2233
0
    case SNMP_MSG_REPORT:
2234
0
        netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2235
0
        NETSNMP_FALLTHROUGH;
2236
0
    case SNMP_MSG_INFORM:
2237
0
#ifndef NETSNMP_NOTIFY_ONLY
2238
0
    case SNMP_MSG_GET:
2239
0
    case SNMP_MSG_GETNEXT:
2240
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
2241
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
2242
0
    case SNMP_MSG_SET:
2243
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
2244
0
        if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2245
0
            pdu->errstat = 0;
2246
0
        if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2247
0
            pdu->errindex = 0;
2248
0
        break;
2249
2250
0
#ifndef NETSNMP_NOTIFY_ONLY
2251
0
    case SNMP_MSG_GETBULK:
2252
0
        if (pdu->max_repetitions < 0) {
2253
0
            session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
2254
0
            return -1;
2255
0
        }
2256
0
        if (pdu->non_repeaters < 0) {
2257
0
            session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
2258
0
            return -1;
2259
0
        }
2260
0
        break;
2261
0
#endif /* ! NETSNMP_NOTIFY_ONLY */
2262
2263
0
    case SNMP_MSG_TRAP:
2264
0
        session->s_snmp_errno = SNMPERR_V1_IN_V2;
2265
0
        return -1;
2266
2267
226
    default:
2268
226
        session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
2269
226
        return -1;
2270
226
    }
2271
2272
    /* Do we need to set the session security engineid? */
2273
0
    if (pdu->securityEngineIDLen == 0) {
2274
0
        if (session->securityEngineIDLen) {
2275
0
            snmpv3_clone_engineID(&pdu->securityEngineID,
2276
0
                                  &pdu->securityEngineIDLen,
2277
0
                                  session->securityEngineID,
2278
0
                                  session->securityEngineIDLen);
2279
0
        }
2280
0
    }
2281
    
2282
    /* Do we need to set the session context engineid? */
2283
0
    if (pdu->contextEngineIDLen == 0) {
2284
0
        if (session->contextEngineIDLen) {
2285
0
            snmpv3_clone_engineID(&pdu->contextEngineID,
2286
0
                                  &pdu->contextEngineIDLen,
2287
0
                                  session->contextEngineID,
2288
0
                                  session->contextEngineIDLen);
2289
0
        } else if (pdu->securityEngineIDLen) {
2290
0
            snmpv3_clone_engineID(&pdu->contextEngineID,
2291
0
                                  &pdu->contextEngineIDLen,
2292
0
                                  pdu->securityEngineID,
2293
0
                                  pdu->securityEngineIDLen);
2294
0
        }
2295
0
    }
2296
2297
0
    if (pdu->contextName == NULL) {
2298
0
        if (!session->contextName) {
2299
0
            session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
2300
0
            return -1;
2301
0
        }
2302
0
        pdu->contextName = strdup(session->contextName);
2303
0
        if (pdu->contextName == NULL) {
2304
0
            session->s_snmp_errno = SNMPERR_GENERR;
2305
0
            return -1;
2306
0
        }
2307
0
        pdu->contextNameLen = session->contextNameLen;
2308
0
    }
2309
0
    if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
2310
0
        pdu->securityModel = session->securityModel;
2311
0
        if (pdu->securityModel == SNMP_DEFAULT_SECMODEL) {
2312
0
            pdu->securityModel = se_find_value_in_slist("snmp_secmods", netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SECMODEL));
2313
            
2314
0
            if (pdu->securityModel <= 0) {
2315
0
                pdu->securityModel = SNMP_SEC_MODEL_USM;
2316
0
            }
2317
0
        }
2318
0
    }
2319
0
    if (pdu->securityNameLen == 0 && pdu->securityName == NULL) {
2320
0
        if (session->securityModel != SNMP_SEC_MODEL_TSM &&
2321
0
            session->securityNameLen == 0) {
2322
0
            session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
2323
0
            return -1;
2324
0
        }
2325
0
        if (session->securityName) {
2326
0
            pdu->securityName = strdup(session->securityName);
2327
0
            if (pdu->securityName == NULL) {
2328
0
                session->s_snmp_errno = SNMPERR_GENERR;
2329
0
                return -1;
2330
0
            }
2331
0
            pdu->securityNameLen = session->securityNameLen;
2332
0
        } else {
2333
0
            pdu->securityName = strdup("");
2334
0
            session->securityName = strdup("");
2335
0
        }
2336
0
    }
2337
0
    if (pdu->securityLevel == 0) {
2338
0
        if (session->securityLevel == 0) {
2339
0
            session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
2340
0
            return -1;
2341
0
        }
2342
0
        pdu->securityLevel = session->securityLevel;
2343
0
    }
2344
0
    DEBUGMSGTL(("snmp_build",
2345
0
                "Building SNMPv3 message (secName:\"%s\", secLevel:%s)...\n",
2346
0
                ((session->securityName) ? (char *) session->securityName :
2347
0
                 ((pdu->securityName) ? (char *) pdu->securityName :
2348
0
                  "ERROR: undefined")), secLevelName[pdu->securityLevel]));
2349
2350
0
    DEBUGDUMPSECTION("send", "SNMPv3 Message");
2351
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2352
0
    if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
2353
0
        ret = snmpv3_packet_realloc_rbuild(pkt, pkt_len, offset,
2354
0
                                           session, pdu, NULL, 0);
2355
0
    } else {
2356
0
#endif
2357
0
        ret = snmpv3_packet_build(session, pdu, *pkt, pkt_len, NULL, 0);
2358
0
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2359
0
    }
2360
0
#endif
2361
0
    DEBUGINDENTLESS();
2362
0
    if (-1 != ret) {
2363
0
        session->s_snmp_errno = ret;
2364
0
    }
2365
2366
0
    return ret;
2367
2368
0
}                               /* end snmpv3_build() */
2369
2370
2371
2372
2373
static u_char  *
2374
snmpv3_header_build(netsnmp_session * session, const netsnmp_pdu *pdu,
2375
                    u_char * packet, size_t * out_length,
2376
                    size_t length, u_char ** msg_hdr_e)
2377
0
{
2378
0
    u_char         *global_hdr, *global_hdr_e;
2379
0
    u_char         *cp;
2380
0
    u_char          msg_flags;
2381
0
    long            max_size;
2382
0
    long            sec_model;
2383
0
    u_char         *pb, *pb0e;
2384
2385
    /*
2386
     * Save current location and build SEQUENCE tag and length placeholder
2387
     * * for SNMP message sequence (actual length inserted later)
2388
     */
2389
0
    cp = asn_build_sequence(packet, out_length,
2390
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2391
0
                            length);
2392
0
    if (cp == NULL)
2393
0
        return NULL;
2394
0
    if (msg_hdr_e != NULL)
2395
0
        *msg_hdr_e = cp;
2396
0
    pb0e = cp;
2397
2398
2399
    /*
2400
     * store the version field - msgVersion
2401
     */
2402
0
    DEBUGDUMPHEADER("send", "SNMP Version Number");
2403
0
    cp = asn_build_int(cp, out_length,
2404
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2405
0
                                 ASN_INTEGER), (const long *) &pdu->version,
2406
0
                       sizeof(pdu->version));
2407
0
    DEBUGINDENTLESS();
2408
0
    if (cp == NULL)
2409
0
        return NULL;
2410
2411
0
    global_hdr = cp;
2412
    /*
2413
     * msgGlobalData HeaderData 
2414
     */
2415
0
    DEBUGDUMPSECTION("send", "msgGlobalData");
2416
0
    cp = asn_build_sequence(cp, out_length,
2417
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
2418
0
    if (cp == NULL)
2419
0
        return NULL;
2420
0
    global_hdr_e = cp;
2421
2422
2423
    /*
2424
     * msgID 
2425
     */
2426
0
    DEBUGDUMPHEADER("send", "msgID");
2427
0
    cp = asn_build_int(cp, out_length,
2428
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2429
0
                                 ASN_INTEGER), &pdu->msgid,
2430
0
                       sizeof(pdu->msgid));
2431
0
    DEBUGINDENTLESS();
2432
0
    if (cp == NULL)
2433
0
        return NULL;
2434
2435
    /*
2436
     * msgMaxSize 
2437
     */
2438
0
    max_size = netsnmp_max_send_msg_size();
2439
0
    if (session->rcvMsgMaxSize < max_size)
2440
0
        max_size = session->rcvMsgMaxSize;
2441
0
    DEBUGDUMPHEADER("send:msgMaxSize1", "msgMaxSize");
2442
0
    cp = asn_build_int(cp, out_length,
2443
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2444
0
                                 ASN_INTEGER), &max_size,
2445
0
                       sizeof(max_size));
2446
0
    DEBUGINDENTLESS();
2447
0
    if (cp == NULL)
2448
0
        return NULL;
2449
2450
    /*
2451
     * msgFlags 
2452
     */
2453
0
    snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
2454
0
    DEBUGDUMPHEADER("send", "msgFlags");
2455
0
    cp = asn_build_string(cp, out_length,
2456
0
                          (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2457
0
                                    ASN_OCTET_STR), &msg_flags,
2458
0
                          sizeof(msg_flags));
2459
0
    DEBUGINDENTLESS();
2460
0
    if (cp == NULL)
2461
0
        return NULL;
2462
2463
    /*
2464
     * msgSecurityModel 
2465
     */
2466
0
    sec_model = pdu->securityModel;
2467
0
    DEBUGDUMPHEADER("send", "msgSecurityModel");
2468
0
    cp = asn_build_int(cp, out_length,
2469
0
                       (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2470
0
                                 ASN_INTEGER), &sec_model,
2471
0
                       sizeof(sec_model));
2472
0
    DEBUGINDENTADD(-4);         /* return from global data indent */
2473
0
    if (cp == NULL)
2474
0
        return NULL;
2475
2476
2477
    /*
2478
     * insert actual length of globalData
2479
     */
2480
0
    pb = asn_build_sequence(global_hdr, out_length,
2481
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2482
0
                            cp - global_hdr_e);
2483
0
    if (pb == NULL)
2484
0
        return NULL;
2485
2486
2487
    /*
2488
     * insert the actual length of the entire packet
2489
     */
2490
0
    pb = asn_build_sequence(packet, out_length,
2491
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2492
0
                            length + (cp - pb0e));
2493
0
    if (pb == NULL)
2494
0
        return NULL;
2495
2496
0
    return cp;
2497
2498
0
}                               /* end snmpv3_header_build() */
2499
2500
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2501
2502
int
2503
snmpv3_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2504
                             size_t * offset, netsnmp_session * session,
2505
                             netsnmp_pdu *pdu)
2506
0
{
2507
0
    size_t          start_offset = *offset;
2508
0
    u_char          msg_flags;
2509
0
    long            max_size, sec_model;
2510
0
    int             rc = 0;
2511
2512
    /*
2513
     * msgSecurityModel.  
2514
     */
2515
0
    sec_model = pdu->securityModel;
2516
0
    DEBUGDUMPHEADER("send", "msgSecurityModel");
2517
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2518
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2519
0
                                          ASN_INTEGER), &sec_model,
2520
0
                                sizeof(sec_model));
2521
0
    DEBUGINDENTLESS();
2522
0
    if (rc == 0) {
2523
0
        return 0;
2524
0
    }
2525
2526
    /*
2527
     * msgFlags.  
2528
     */
2529
0
    snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
2530
0
    DEBUGDUMPHEADER("send", "msgFlags");
2531
0
    rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2532
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2533
0
                                             | ASN_OCTET_STR), &msg_flags,
2534
0
                                   sizeof(msg_flags));
2535
0
    DEBUGINDENTLESS();
2536
0
    if (rc == 0) {
2537
0
        return 0;
2538
0
    }
2539
2540
    /*
2541
     * msgMaxSize.  
2542
     */
2543
0
    max_size = netsnmp_max_send_msg_size();
2544
0
    if (session->rcvMsgMaxSize < max_size)
2545
0
        max_size = session->rcvMsgMaxSize;
2546
0
    DEBUGDUMPHEADER("send:msgMaxSize2", "msgMaxSize");
2547
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2548
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2549
0
                                          ASN_INTEGER), &max_size,
2550
0
                                sizeof(max_size));
2551
0
    DEBUGINDENTLESS();
2552
0
    if (rc == 0) {
2553
0
        return 0;
2554
0
    }
2555
2556
    /*
2557
     * msgID.  
2558
     */
2559
0
    DEBUGDUMPHEADER("send", "msgID");
2560
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2561
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2562
0
                                          ASN_INTEGER), &pdu->msgid,
2563
0
                                sizeof(pdu->msgid));
2564
0
    DEBUGINDENTLESS();
2565
0
    if (rc == 0) {
2566
0
        return 0;
2567
0
    }
2568
2569
    /*
2570
     * Global data sequence.  
2571
     */
2572
0
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
2573
0
                                     (u_char) (ASN_SEQUENCE |
2574
0
                                               ASN_CONSTRUCTOR),
2575
0
                                     *offset - start_offset);
2576
0
    if (rc == 0) {
2577
0
        return 0;
2578
0
    }
2579
2580
    /*
2581
     * Store the version field - msgVersion.  
2582
     */
2583
0
    DEBUGDUMPHEADER("send", "SNMP Version Number");
2584
0
    rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
2585
0
                                (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
2586
0
                                          ASN_INTEGER),
2587
0
                                (long *) &pdu->version,
2588
0
                                sizeof(pdu->version));
2589
0
    DEBUGINDENTLESS();
2590
0
    return rc;
2591
0
}                               /* end snmpv3_header_realloc_rbuild() */
2592
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2593
2594
static u_char  *
2595
snmpv3_scopedPDU_header_build(const netsnmp_pdu *pdu,
2596
                              u_char * packet, size_t * out_length,
2597
                              u_char ** spdu_e)
2598
0
{
2599
0
    u_char         *scopedPdu, *pb;
2600
2601
0
    pb = scopedPdu = packet;
2602
0
    pb = asn_build_sequence(pb, out_length,
2603
0
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
2604
0
    if (pb == NULL)
2605
0
        return NULL;
2606
0
    if (spdu_e)
2607
0
        *spdu_e = pb;
2608
2609
0
    DEBUGDUMPHEADER("send", "contextEngineID");
2610
0
    pb = asn_build_string(pb, out_length,
2611
0
                          (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
2612
0
                          pdu->contextEngineID, pdu->contextEngineIDLen);
2613
0
    DEBUGINDENTLESS();
2614
0
    if (pb == NULL)
2615
0
        return NULL;
2616
2617
0
    DEBUGDUMPHEADER("send", "contextName");
2618
0
    pb = asn_build_string(pb, out_length,
2619
0
                          (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
2620
0
                          (u_char *) pdu->contextName,
2621
0
                          pdu->contextNameLen);
2622
0
    DEBUGINDENTLESS();
2623
0
    if (pb == NULL)
2624
0
        return NULL;
2625
2626
0
    return pb;
2627
2628
0
}                               /* end snmpv3_scopedPDU_header_build() */
2629
2630
2631
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2632
int
2633
snmpv3_scopedPDU_header_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2634
                                       size_t * offset, netsnmp_pdu *pdu,
2635
                                       size_t body_len)
2636
0
{
2637
0
    size_t          start_offset = *offset;
2638
0
    int             rc = 0;
2639
2640
    /*
2641
     * contextName.  
2642
     */
2643
0
    DEBUGDUMPHEADER("send", "contextName");
2644
0
    rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2645
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2646
0
                                             | ASN_OCTET_STR),
2647
0
                                   (u_char *) pdu->contextName,
2648
0
                                   pdu->contextNameLen);
2649
0
    DEBUGINDENTLESS();
2650
0
    if (rc == 0) {
2651
0
        return 0;
2652
0
    }
2653
2654
    /*
2655
     * contextEngineID.  
2656
     */
2657
0
    DEBUGDUMPHEADER("send", "contextEngineID");
2658
0
    rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
2659
0
                                   (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
2660
0
                                             | ASN_OCTET_STR),
2661
0
                                   pdu->contextEngineID,
2662
0
                                   pdu->contextEngineIDLen);
2663
0
    DEBUGINDENTLESS();
2664
0
    if (rc == 0) {
2665
0
        return 0;
2666
0
    }
2667
2668
0
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
2669
0
                                     (u_char) (ASN_SEQUENCE |
2670
0
                                               ASN_CONSTRUCTOR),
2671
0
                                     *offset - start_offset + body_len);
2672
2673
0
    return rc;
2674
0
}                               /* end snmpv3_scopedPDU_header_realloc_rbuild() */
2675
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2676
2677
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2678
/*
2679
 * returns 0 if success, -1 if fail, not 0 if SM build failure 
2680
 */
2681
int
2682
snmpv3_packet_realloc_rbuild(u_char ** pkt, size_t * pkt_len,
2683
                             size_t * offset, netsnmp_session * session,
2684
                             netsnmp_pdu *pdu, u_char * pdu_data,
2685
                             size_t pdu_data_len)
2686
0
{
2687
0
    u_char         *scoped_pdu, *hdrbuf = NULL, *hdr = NULL;
2688
0
    size_t          hdrbuf_len = SNMP_MAX_MSG_V3_HDRS, hdr_offset =
2689
0
        0, spdu_offset = 0;
2690
0
    size_t          body_end_offset = *offset, body_len = 0;
2691
0
    struct snmp_secmod_def *sptr = NULL;
2692
0
    int             rc = 0;
2693
2694
    /*
2695
     * Build a scopedPDU structure into the packet buffer.  
2696
     */
2697
0
    DEBUGPRINTPDUTYPE("send", pdu->command);
2698
0
    if (pdu_data) {
2699
0
        while ((*pkt_len - *offset) < pdu_data_len) {
2700
0
            if (!asn_realloc(pkt, pkt_len)) {
2701
0
                return -1;
2702
0
            }
2703
0
        }
2704
2705
0
        *offset += pdu_data_len;
2706
0
        memcpy(*pkt + *pkt_len - *offset, pdu_data, pdu_data_len);
2707
0
    } else {
2708
0
        rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
2709
0
        if (rc == 0) {
2710
0
            return -1;
2711
0
        }
2712
0
    }
2713
0
    body_len = *offset - body_end_offset;
2714
2715
0
    DEBUGDUMPSECTION("send", "ScopedPdu");
2716
0
    rc = snmpv3_scopedPDU_header_realloc_rbuild(pkt, pkt_len, offset,
2717
0
                                                pdu, body_len);
2718
0
    if (rc == 0) {
2719
0
        return -1;
2720
0
    }
2721
0
    spdu_offset = *offset;
2722
0
    DEBUGINDENTADD(-4);         /*  Return from Scoped PDU.  */
2723
2724
0
    if ((hdrbuf = (u_char *) malloc(hdrbuf_len)) == NULL) {
2725
0
        return -1;
2726
0
    }
2727
2728
0
    rc = snmpv3_header_realloc_rbuild(&hdrbuf, &hdrbuf_len, &hdr_offset,
2729
0
                                      session, pdu);
2730
0
    if (rc == 0) {
2731
0
        SNMP_FREE(hdrbuf);
2732
0
        return -1;
2733
0
    }
2734
0
    hdr = hdrbuf + hdrbuf_len - hdr_offset;
2735
0
    scoped_pdu = *pkt + *pkt_len - spdu_offset;
2736
2737
    /*
2738
     * Call the security module to possibly encrypt and authenticate the
2739
     * message---the entire message to transmitted on the wire is returned.  
2740
     */
2741
2742
0
    sptr = find_sec_mod(pdu->securityModel);
2743
0
    DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
2744
0
    if (sptr && sptr->encode_reverse) {
2745
0
        struct snmp_secmod_outgoing_params parms;
2746
2747
0
        parms.msgProcModel = pdu->msgParseModel;
2748
0
        parms.globalData = hdr;
2749
0
        parms.globalDataLen = hdr_offset;
2750
0
        parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
2751
0
        parms.secModel = pdu->securityModel;
2752
0
        parms.secEngineID = pdu->securityEngineID;
2753
0
        parms.secEngineIDLen = pdu->securityEngineIDLen;
2754
0
        parms.secName = pdu->securityName;
2755
0
        parms.secNameLen = pdu->securityNameLen;
2756
0
        parms.secLevel = pdu->securityLevel;
2757
0
        parms.scopedPdu = scoped_pdu;
2758
0
        parms.scopedPduLen = spdu_offset;
2759
0
        parms.secStateRef = pdu->securityStateRef;
2760
0
        parms.wholeMsg = pkt;
2761
0
        parms.wholeMsgLen = pkt_len;
2762
0
        parms.wholeMsgOffset = offset;
2763
0
        parms.session = session;
2764
0
        parms.pdu = pdu;
2765
2766
0
        rc = (*sptr->encode_reverse) (&parms);
2767
0
    } else {
2768
0
        if (!sptr) {
2769
0
            snmp_log(LOG_ERR,
2770
0
                     "no such security service available: %d\n",
2771
0
                     pdu->securityModel);
2772
0
        } else if (!sptr->encode_reverse) {
2773
0
            snmp_log(LOG_ERR,
2774
0
                     "security service %d doesn't support reverse encoding.\n",
2775
0
                     pdu->securityModel);
2776
0
        }
2777
0
        rc = -1;
2778
0
    }
2779
2780
0
    DEBUGINDENTLESS();
2781
0
    SNMP_FREE(hdrbuf);
2782
0
    return rc;
2783
0
}                               /* end snmpv3_packet_realloc_rbuild() */
2784
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
2785
2786
/*
2787
 * returns 0 if success, -1 if fail, not 0 if SM build failure 
2788
 */
2789
int
2790
snmpv3_packet_build(netsnmp_session * session, netsnmp_pdu *pdu,
2791
                    u_char * packet, size_t * out_length,
2792
                    u_char * pdu_data, size_t pdu_data_len)
2793
0
{
2794
0
    u_char         *global_data, *sec_params, *spdu_hdr_e;
2795
0
    size_t          global_data_len, sec_params_len;
2796
0
    u_char          spdu_buf[SNMP_MAX_MSG_SIZE];
2797
0
    size_t          spdu_buf_len, spdu_len;
2798
0
    u_char         *cp;
2799
0
    int             result;
2800
0
    struct snmp_secmod_def *sptr;
2801
2802
0
    global_data = packet;
2803
2804
    /*
2805
     * build the headers for the packet, returned addr = start of secParams
2806
     */
2807
0
    sec_params = snmpv3_header_build(session, pdu, global_data,
2808
0
                                     out_length, 0, NULL);
2809
0
    if (sec_params == NULL)
2810
0
        return -1;
2811
0
    global_data_len = sec_params - global_data;
2812
0
    sec_params_len = *out_length;       /* length left in packet buf for sec_params */
2813
2814
2815
    /*
2816
     * build a scopedPDU structure into spdu_buf
2817
     */
2818
0
    spdu_buf_len = sizeof(spdu_buf);
2819
0
    DEBUGDUMPSECTION("send", "ScopedPdu");
2820
0
    cp = snmpv3_scopedPDU_header_build(pdu, spdu_buf, &spdu_buf_len,
2821
0
                                       &spdu_hdr_e);
2822
0
    if (cp == NULL)
2823
0
        return -1;
2824
2825
    /*
2826
     * build the PDU structure onto the end of spdu_buf 
2827
     */
2828
0
    DEBUGPRINTPDUTYPE("send", ((pdu_data) ? *pdu_data : 0x00));
2829
0
    if (pdu_data) {
2830
0
        if (cp + pdu_data_len > spdu_buf + sizeof(spdu_buf)) {
2831
0
            snmp_log(LOG_ERR, "%s: PDU too big (%" NETSNMP_PRIz "d > %" NETSNMP_PRIz "d)\n",
2832
0
                     NETSNMP_FUNCTION, pdu_data_len, sizeof(spdu_buf));
2833
0
            return -1;
2834
0
        }
2835
0
        memcpy(cp, pdu_data, pdu_data_len);
2836
0
        cp += pdu_data_len;
2837
0
    } else {
2838
0
        cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
2839
0
        if (cp == NULL)
2840
0
            return -1;
2841
0
    }
2842
0
    DEBUGINDENTADD(-4);         /* return from Scoped PDU */
2843
2844
    /*
2845
     * re-encode the actual ASN.1 length of the scopedPdu
2846
     */
2847
0
    spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
2848
0
    spdu_buf_len = sizeof(spdu_buf);
2849
0
    if (asn_build_sequence(spdu_buf, &spdu_buf_len,
2850
0
                           (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
2851
0
                           spdu_len) == NULL)
2852
0
        return -1;
2853
0
    spdu_len = cp - spdu_buf;   /* the length of the entire scopedPdu */
2854
2855
2856
    /*
2857
     * call the security module to possibly encrypt and authenticate the
2858
     * message - the entire message to transmitted on the wire is returned
2859
     */
2860
0
    cp = NULL;
2861
0
    *out_length = sizeof(spdu_buf);
2862
0
    DEBUGDUMPSECTION("send", "SM msgSecurityParameters");
2863
0
    sptr = find_sec_mod(pdu->securityModel);
2864
0
    if (sptr && sptr->encode_forward) {
2865
0
        struct snmp_secmod_outgoing_params parms;
2866
0
        parms.msgProcModel = pdu->msgParseModel;
2867
0
        parms.globalData = global_data;
2868
0
        parms.globalDataLen = global_data_len;
2869
0
        parms.maxMsgSize = SNMP_MAX_MSG_SIZE;
2870
0
        parms.secModel = pdu->securityModel;
2871
0
        parms.secEngineID = pdu->securityEngineID;
2872
0
        parms.secEngineIDLen = pdu->securityEngineIDLen;
2873
0
        parms.secName = pdu->securityName;
2874
0
        parms.secNameLen = pdu->securityNameLen;
2875
0
        parms.secLevel = pdu->securityLevel;
2876
0
        parms.scopedPdu = spdu_buf;
2877
0
        parms.scopedPduLen = spdu_len;
2878
0
        parms.secStateRef = pdu->securityStateRef;
2879
0
        parms.secParams = sec_params;
2880
0
        parms.secParamsLen = &sec_params_len;
2881
0
        parms.wholeMsg = &cp;
2882
0
        parms.wholeMsgLen = out_length;
2883
0
        parms.session = session;
2884
0
        parms.pdu = pdu;
2885
0
        result = (*sptr->encode_forward) (&parms);
2886
0
    } else {
2887
0
        if (!sptr) {
2888
0
            snmp_log(LOG_ERR, "no such security service available: %d\n",
2889
0
                     pdu->securityModel);
2890
0
        } else if (!sptr->encode_forward) {
2891
0
            snmp_log(LOG_ERR,
2892
0
                     "security service %d doesn't support forward out encoding.\n",
2893
0
                     pdu->securityModel);
2894
0
        }
2895
0
        result = -1;
2896
0
    }
2897
0
    DEBUGINDENTLESS();
2898
0
    return result;
2899
2900
0
}                               /* end snmpv3_packet_build() */
2901
2902
2903
/*
2904
 * Takes a session and a pdu and serializes the ASN PDU into the area
2905
 * pointed to by *pkt.  *pkt_len is the size of the data area available.
2906
 * Returns the length of the completed packet in *offset.  If any errors
2907
 * occur, -1 is returned.  If all goes well, 0 is returned.
2908
 */
2909
2910
static int
2911
_snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
2912
            netsnmp_session * session, netsnmp_pdu *pdu)
2913
2.93k
{
2914
2.93k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
2915
2.93k
    u_char         *h0e = NULL;
2916
2.93k
    size_t          start_offset = *offset;
2917
2.93k
    long            version;
2918
2.93k
    int             rc = 0;
2919
2.93k
    size_t          length;
2920
2.93k
#endif /* support for community based SNMP */
2921
2922
2.93k
    u_char         *cp;
2923
2924
2.93k
    if (NETSNMP_RUNTIME_PROTOCOL_SKIP(pdu->version)) {
2925
920
        DEBUGMSGTL(("snmp_send", "build packet (version 0x%02x disabled)\n",
2926
920
                    (u_int)pdu->version));
2927
920
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
2928
920
        return -1;
2929
920
    }
2930
2931
2.01k
    session->s_snmp_errno = 0;
2932
2.01k
    session->s_errno = 0;
2933
2934
2.01k
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2935
2.01k
    if ((pdu->flags & UCD_MSG_FLAG_BULK_TOOBIG) ||
2936
2.01k
        (0 == netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
2937
2.01k
                                     NETSNMP_DS_LIB_REVERSE_ENCODE))) {
2938
702
        pdu->flags |= UCD_MSG_FLAG_FORWARD_ENCODE;
2939
702
    }
2940
2.01k
#endif /* NETSNMP_USE_REVERSE_ASNENCODING */
2941
2942
2.01k
    if (pdu->version == SNMP_VERSION_3) {
2943
226
        return snmpv3_build(pkt, pkt_len, offset, session, pdu);
2944
226
    }
2945
2946
1.78k
    switch (pdu->command) {
2947
79
    case SNMP_MSG_RESPONSE:
2948
79
        netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2949
79
#ifndef NETSNMP_NOTIFY_ONLY
2950
79
        NETSNMP_FALLTHROUGH;
2951
131
    case SNMP_MSG_GET:
2952
221
    case SNMP_MSG_GETNEXT:
2953
221
        NETSNMP_FALLTHROUGH;
2954
221
#endif /* ! NETSNMP_NOTIFY_ONLY */
2955
221
#ifndef NETSNMP_NO_WRITE_SUPPORT
2956
291
    case SNMP_MSG_SET:
2957
291
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
2958
        /*
2959
         * all versions support these PDU types 
2960
         */
2961
        /*
2962
         * initialize defaulted PDU fields 
2963
         */
2964
2965
291
        if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2966
1
            pdu->errstat = 0;
2967
291
        if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2968
2
            pdu->errindex = 0;
2969
291
        break;
2970
2971
141
    case SNMP_MSG_TRAP2:
2972
141
        netsnmp_assert(0 == (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE));
2973
141
        NETSNMP_FALLTHROUGH;
2974
284
    case SNMP_MSG_INFORM:
2975
284
#ifndef NETSNMP_DISABLE_SNMPV1
2976
        /*
2977
         * not supported in SNMPv1 and SNMPsec 
2978
         */
2979
284
        if (pdu->version == SNMP_VERSION_1) {
2980
0
            session->s_snmp_errno = SNMPERR_V2_IN_V1;
2981
0
            return -1;
2982
0
        }
2983
284
#endif
2984
284
        if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
2985
1
            pdu->errstat = 0;
2986
284
        if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
2987
3
            pdu->errindex = 0;
2988
284
        break;
2989
2990
0
#ifndef NETSNMP_NOTIFY_ONLY
2991
124
    case SNMP_MSG_GETBULK:
2992
        /*
2993
         * not supported in SNMPv1 and SNMPsec 
2994
         */
2995
124
#ifndef NETSNMP_DISABLE_SNMPV1
2996
124
        if (pdu->version == SNMP_VERSION_1) {
2997
0
            session->s_snmp_errno = SNMPERR_V2_IN_V1;
2998
0
            return -1;
2999
0
        }
3000
124
#endif
3001
124
        if (pdu->max_repetitions < 0) {
3002
52
            session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
3003
52
            return -1;
3004
52
        }
3005
72
        if (pdu->non_repeaters < 0) {
3006
42
            session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
3007
42
            return -1;
3008
42
        }
3009
30
        break;
3010
30
#endif /* ! NETSNMP_NOTIFY_ONLY */
3011
3012
111
    case SNMP_MSG_TRAP:
3013
        /*
3014
         * *only* supported in SNMPv1 and SNMPsec 
3015
         */
3016
111
#ifndef NETSNMP_DISABLE_SNMPV1
3017
111
        if (pdu->version != SNMP_VERSION_1) {
3018
111
            session->s_snmp_errno = SNMPERR_V1_IN_V2;
3019
111
            return -1;
3020
111
        }
3021
0
#endif
3022
        /*
3023
         * initialize defaulted Trap PDU fields 
3024
         */
3025
0
        pdu->reqid = 1;         /* give a bogus non-error reqid for traps */
3026
0
        if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH) {
3027
0
            pdu->enterprise = netsnmp_memdup(DEFAULT_ENTERPRISE,
3028
0
                                             sizeof(DEFAULT_ENTERPRISE));
3029
0
            if (pdu->enterprise == NULL) {
3030
0
                session->s_snmp_errno = SNMPERR_MALLOC;
3031
0
                return -1;
3032
0
            }
3033
0
            pdu->enterprise_length =
3034
0
                OID_LENGTH(DEFAULT_ENTERPRISE);
3035
0
        }
3036
0
        if (pdu->time == SNMP_DEFAULT_TIME)
3037
0
            pdu->time = DEFAULT_TIME;
3038
        /*
3039
         * don't expect a response 
3040
         */
3041
0
        pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
3042
0
        break;
3043
3044
7
    case SNMP_MSG_REPORT:      /* SNMPv3 only */
3045
979
    default:
3046
979
        session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
3047
979
        return -1;
3048
1.78k
    }
3049
3050
    /*
3051
     * save length 
3052
     */
3053
605
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3054
605
    length = *pkt_len;
3055
605
#endif
3056
3057
    /*
3058
     * setup administrative fields based on version 
3059
     */
3060
    /*
3061
     * build the message wrapper and all the administrative fields
3062
     * upto the PDU sequence
3063
     * (note that actual length of message will be inserted later) 
3064
     */
3065
605
    switch (pdu->version) {
3066
0
#ifndef NETSNMP_DISABLE_SNMPV1
3067
0
    case SNMP_VERSION_1:
3068
0
#endif
3069
0
#ifndef NETSNMP_DISABLE_SNMPV2C
3070
603
    case SNMP_VERSION_2c:
3071
603
#endif
3072
603
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3073
#ifdef NETSNMP_NO_ZEROLENGTH_COMMUNITY
3074
        if (pdu->community_len == 0) {
3075
            if (session->community_len == 0) {
3076
                session->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
3077
                return -1;
3078
            }
3079
            pdu->community = netsnmp_memdup(session->community,
3080
                                            session->community_len);
3081
            if (pdu->community == NULL) {
3082
                session->s_snmp_errno = SNMPERR_MALLOC;
3083
                return -1;
3084
            }
3085
            pdu->community_len = session->community_len;
3086
        }
3087
#else                           /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
3088
603
        if (pdu->community_len == 0 && pdu->command != SNMP_MSG_RESPONSE) {
3089
            /*
3090
             * copy session community exactly to pdu community 
3091
             */
3092
0
            if (0 == session->community_len) {
3093
0
                SNMP_FREE(pdu->community);
3094
0
            } else if (pdu->community_len == session->community_len) {
3095
0
                memmove(pdu->community,
3096
0
                        session->community, session->community_len);
3097
0
            } else {
3098
0
                SNMP_FREE(pdu->community);
3099
0
                pdu->community = netsnmp_memdup(session->community,
3100
0
                                                session->community_len);
3101
0
                if (pdu->community == NULL) {
3102
0
                    session->s_snmp_errno = SNMPERR_MALLOC;
3103
0
                    return -1;
3104
0
                }
3105
0
            }
3106
0
            pdu->community_len = session->community_len;
3107
0
        }
3108
603
#endif                          /* !NETSNMP_NO_ZEROLENGTH_COMMUNITY */
3109
3110
603
        DEBUGMSGTL(("snmp_send", "Building SNMPv%ld message...\n",
3111
603
                    (1 + pdu->version)));
3112
603
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3113
603
        if (!(pdu->flags & UCD_MSG_FLAG_FORWARD_ENCODE)) {
3114
434
            DEBUGPRINTPDUTYPE("send", pdu->command);
3115
434
            rc = snmp_pdu_realloc_rbuild(pkt, pkt_len, offset, pdu);
3116
434
            if (rc == 0) {
3117
0
                return -1;
3118
0
            }
3119
3120
434
            DEBUGDUMPHEADER("send", "Community String");
3121
434
            rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
3122
434
                                           (u_char) (ASN_UNIVERSAL |
3123
434
                                                     ASN_PRIMITIVE |
3124
434
                                                     ASN_OCTET_STR),
3125
434
                                           pdu->community,
3126
434
                                           pdu->community_len);
3127
434
            DEBUGINDENTLESS();
3128
434
            if (rc == 0) {
3129
0
                return -1;
3130
0
            }
3131
3132
3133
            /*
3134
             * Store the version field.  
3135
             */
3136
434
            DEBUGDUMPHEADER("send", "SNMP Version Number");
3137
3138
434
            version = pdu->version;
3139
434
            rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3140
434
                                        (u_char) (ASN_UNIVERSAL |
3141
434
                                                  ASN_PRIMITIVE |
3142
434
                                                  ASN_INTEGER),
3143
434
                                        (long *) &version,
3144
434
                                        sizeof(version));
3145
434
            DEBUGINDENTLESS();
3146
434
            if (rc == 0) {
3147
0
                return -1;
3148
0
            }
3149
3150
            /*
3151
             * Build the final sequence.  
3152
             */
3153
434
#ifndef NETSNMP_DISABLE_SNMPV1
3154
434
            if (pdu->version == SNMP_VERSION_1) {
3155
0
                DEBUGDUMPSECTION("send", "SNMPv1 Message");
3156
434
            } else {
3157
434
#endif
3158
434
                DEBUGDUMPSECTION("send", "SNMPv2c Message");
3159
434
#ifndef NETSNMP_DISABLE_SNMPV1
3160
434
            }
3161
434
#endif
3162
434
            rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3163
434
                                             (u_char) (ASN_SEQUENCE |
3164
434
                                                       ASN_CONSTRUCTOR),
3165
434
                                             *offset - start_offset);
3166
434
            DEBUGINDENTLESS();
3167
3168
434
            if (rc == 0) {
3169
0
                return -1;
3170
0
            }
3171
434
            return 0;
3172
434
        } else {
3173
3174
169
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3175
            /*
3176
             * Save current location and build SEQUENCE tag and length
3177
             * placeholder for SNMP message sequence
3178
             * (actual length will be inserted later) 
3179
             */
3180
169
            cp = asn_build_sequence(*pkt, pkt_len,
3181
169
                                    (u_char) (ASN_SEQUENCE |
3182
169
                                              ASN_CONSTRUCTOR), 0);
3183
169
            if (cp == NULL) {
3184
0
                return -1;
3185
0
            }
3186
169
            h0e = cp;
3187
3188
169
#ifndef NETSNMP_DISABLE_SNMPV1
3189
169
            if (pdu->version == SNMP_VERSION_1) {
3190
0
                DEBUGDUMPSECTION("send", "SNMPv1 Message");
3191
169
            } else {
3192
169
#endif
3193
169
                DEBUGDUMPSECTION("send", "SNMPv2c Message");
3194
169
#ifndef NETSNMP_DISABLE_SNMPV1
3195
169
            }
3196
169
#endif
3197
3198
            /*
3199
             * store the version field 
3200
             */
3201
169
            DEBUGDUMPHEADER("send", "SNMP Version Number");
3202
3203
169
            version = pdu->version;
3204
169
            cp = asn_build_int(cp, pkt_len,
3205
169
                               (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3206
169
                                         ASN_INTEGER), (long *) &version,
3207
169
                               sizeof(version));
3208
169
            DEBUGINDENTLESS();
3209
169
            if (cp == NULL)
3210
0
                return -1;
3211
3212
            /*
3213
             * store the community string 
3214
             */
3215
169
            DEBUGDUMPHEADER("send", "Community String");
3216
169
            cp = asn_build_string(cp, pkt_len,
3217
169
                                  (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3218
169
                                            ASN_OCTET_STR), pdu->community,
3219
169
                                  pdu->community_len);
3220
169
            DEBUGINDENTLESS();
3221
169
            if (cp == NULL)
3222
0
                return -1;
3223
169
            break;
3224
3225
169
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3226
169
        }
3227
0
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3228
0
        break;
3229
0
#endif /* support for community based SNMP */
3230
0
    case SNMP_VERSION_2p:
3231
0
    case SNMP_VERSION_sec:
3232
0
    case SNMP_VERSION_2u:
3233
0
    case SNMP_VERSION_2star:
3234
2
    default:
3235
2
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
3236
2
        return -1;
3237
605
    }
3238
3239
169
    DEBUGPRINTPDUTYPE("send", pdu->command);
3240
169
    cp = snmp_pdu_build(pdu, cp, pkt_len);
3241
169
    DEBUGINDENTADD(-4);         /* return from entire v1/v2c message */
3242
169
    if (cp == NULL)
3243
0
        return -1;
3244
3245
    /*
3246
     * insert the actual length of the message sequence 
3247
     */
3248
169
    switch (pdu->version) {
3249
0
#ifndef NETSNMP_DISABLE_SNMPV1
3250
0
    case SNMP_VERSION_1:
3251
0
#endif
3252
0
#ifndef NETSNMP_DISABLE_SNMPV2C
3253
169
    case SNMP_VERSION_2c:
3254
169
#endif
3255
169
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
3256
169
        asn_build_sequence(*pkt, &length,
3257
169
                           (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3258
169
                           cp - h0e);
3259
169
        break;
3260
0
#endif /* support for community based SNMP */
3261
3262
0
    case SNMP_VERSION_2p:
3263
0
    case SNMP_VERSION_sec:
3264
0
    case SNMP_VERSION_2u:
3265
0
    case SNMP_VERSION_2star:
3266
0
    default:
3267
0
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
3268
0
        return -1;
3269
169
    }
3270
169
    *pkt_len = cp - *pkt;
3271
169
    return 0;
3272
169
}
3273
3274
/**
3275
 * Serialize a PDU into ASN format.
3276
 * @param pkt     [out] Serialized PDU.
3277
 * @param pkt_len [out] Size of pkt.
3278
 * @param offset  [out] Number of bytes written into *pkt.
3279
 * @param pss     [in]  Session pointer.
3280
 * @param pdu     [in]  PDU to serialize.
3281
 *
3282
 * @returns 0 upon success; -1 upon failure.
3283
 */
3284
int
3285
snmp_build(u_char ** pkt, size_t * pkt_len, size_t * offset,
3286
           netsnmp_session * pss, netsnmp_pdu *pdu)
3287
2.93k
{
3288
2.93k
    int             rc;
3289
3290
2.93k
    rc = _snmp_build(pkt, pkt_len, offset, pss, pdu);
3291
2.93k
    if (rc) {
3292
2.33k
        if (!pss->s_snmp_errno) {
3293
0
            snmp_log(LOG_ERR, "snmp_build: unknown failure\n");
3294
0
            pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
3295
0
        }
3296
2.33k
        SET_SNMP_ERROR(pss->s_snmp_errno);
3297
2.33k
        rc = -1;
3298
2.33k
    }
3299
2.93k
    return rc;
3300
2.93k
}
3301
3302
/*
3303
 * on error, returns NULL (likely an encoding problem). 
3304
 */
3305
u_char         *
3306
snmp_pdu_build(const netsnmp_pdu *pdu, u_char * cp, size_t * out_length)
3307
3.10k
{
3308
3.10k
    u_char         *h1, *h1e, *h2, *h2e, *save_ptr;
3309
3.10k
    netsnmp_variable_list *vp, *save_vp = NULL;
3310
3.10k
    size_t          length, save_length;
3311
3312
3.10k
    length = *out_length;
3313
    /*
3314
     * Save current location and build PDU tag and length placeholder
3315
     * (actual length will be inserted later) 
3316
     */
3317
3.10k
    h1 = cp;
3318
3.10k
    cp = asn_build_sequence(cp, out_length, (u_char) pdu->command, 0);
3319
3.10k
    if (cp == NULL)
3320
803
        return NULL;
3321
2.30k
    h1e = cp;
3322
3323
    /*
3324
     * store fields in the PDU preceding the variable-bindings sequence
3325
     */
3326
2.30k
    if (pdu->command != SNMP_MSG_TRAP) {
3327
        /*
3328
         * PDU is not an SNMPv1 trap 
3329
         */
3330
3331
2.24k
        DEBUGDUMPHEADER("send", "request_id");
3332
        /*
3333
         * request id 
3334
         */
3335
2.24k
        cp = asn_build_int(cp, out_length,
3336
2.24k
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3337
2.24k
                                     ASN_INTEGER), &pdu->reqid,
3338
2.24k
                           sizeof(pdu->reqid));
3339
2.24k
        DEBUGINDENTLESS();
3340
2.24k
        if (cp == NULL)
3341
267
            return NULL;
3342
3343
        /*
3344
         * error status (getbulk non-repeaters) 
3345
         */
3346
1.98k
        DEBUGDUMPHEADER("send", "error status");
3347
1.98k
        cp = asn_build_int(cp, out_length,
3348
1.98k
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3349
1.98k
                                     ASN_INTEGER), &pdu->errstat,
3350
1.98k
                           sizeof(pdu->errstat));
3351
1.98k
        DEBUGINDENTLESS();
3352
1.98k
        if (cp == NULL)
3353
81
            return NULL;
3354
3355
        /*
3356
         * error index (getbulk max-repetitions) 
3357
         */
3358
1.90k
        DEBUGDUMPHEADER("send", "error index");
3359
1.90k
        cp = asn_build_int(cp, out_length,
3360
1.90k
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3361
1.90k
                                     ASN_INTEGER), &pdu->errindex,
3362
1.90k
                           sizeof(pdu->errindex));
3363
1.90k
        DEBUGINDENTLESS();
3364
1.90k
        if (cp == NULL)
3365
69
            return NULL;
3366
1.90k
    } else {
3367
        /*
3368
         * an SNMPv1 trap PDU 
3369
         */
3370
3371
        /*
3372
         * enterprise 
3373
         */
3374
53
        DEBUGDUMPHEADER("send", "enterprise OBJID");
3375
53
        cp = asn_build_objid(cp, out_length,
3376
53
                             (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3377
53
                                       ASN_OBJECT_ID),
3378
53
                             pdu->enterprise, pdu->enterprise_length);
3379
53
        DEBUGINDENTLESS();
3380
53
        if (cp == NULL)
3381
3
            return NULL;
3382
3383
        /*
3384
         * agent-addr 
3385
         */
3386
50
        DEBUGDUMPHEADER("send", "agent Address");
3387
50
        cp = asn_build_string(cp, out_length,
3388
50
                              (u_char) (ASN_IPADDRESS | ASN_PRIMITIVE),
3389
50
                              (const u_char *) pdu->agent_addr, 4);
3390
50
        DEBUGINDENTLESS();
3391
50
        if (cp == NULL)
3392
3
            return NULL;
3393
3394
        /*
3395
         * generic trap 
3396
         */
3397
47
        DEBUGDUMPHEADER("send", "generic trap number");
3398
47
        cp = asn_build_int(cp, out_length,
3399
47
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3400
47
                                     ASN_INTEGER),
3401
47
                           (const long *) &pdu->trap_type,
3402
47
                           sizeof(pdu->trap_type));
3403
47
        DEBUGINDENTLESS();
3404
47
        if (cp == NULL)
3405
2
            return NULL;
3406
3407
        /*
3408
         * specific trap 
3409
         */
3410
45
        DEBUGDUMPHEADER("send", "specific trap number");
3411
45
        cp = asn_build_int(cp, out_length,
3412
45
                           (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
3413
45
                                     ASN_INTEGER),
3414
45
                           (const long *) &pdu->specific_type,
3415
45
                           sizeof(pdu->specific_type));
3416
45
        DEBUGINDENTLESS();
3417
45
        if (cp == NULL)
3418
4
            return NULL;
3419
3420
        /*
3421
         * timestamp  
3422
         */
3423
41
        DEBUGDUMPHEADER("send", "timestamp");
3424
41
        cp = asn_build_unsigned_int(cp, out_length,
3425
41
                                    (u_char) (ASN_TIMETICKS |
3426
41
                                              ASN_PRIMITIVE), &pdu->time,
3427
41
                                    sizeof(pdu->time));
3428
41
        DEBUGINDENTLESS();
3429
41
        if (cp == NULL)
3430
1
            return NULL;
3431
41
    }
3432
3433
    /*
3434
     * Save current location and build SEQUENCE tag and length placeholder
3435
     * for variable-bindings sequence
3436
     * (actual length will be inserted later) 
3437
     */
3438
1.87k
    h2 = cp;
3439
1.87k
    cp = asn_build_sequence(cp, out_length,
3440
1.87k
                            (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
3441
1.87k
    if (cp == NULL)
3442
131
        return NULL;
3443
1.74k
    h2e = cp;
3444
3445
    /*
3446
     * Store variable-bindings 
3447
     */
3448
1.74k
    DEBUGDUMPSECTION("send", "VarBindList");
3449
2.90k
    for (vp = pdu->variables; vp; vp = vp->next_variable) {
3450
        /*
3451
         * if estimated getbulk response size exceeded packet max size,
3452
         * processing was stopped before bulk cache was filled and type
3453
         * was set to ASN_PRIV_STOP, indicating that the rest of the varbinds
3454
         * in the cache are empty and we can stop encoding them.
3455
         */
3456
1.62k
        if (ASN_PRIV_STOP == vp->type)
3457
0
            break;
3458
3459
        /*
3460
         * save current ptr and length so that if we exceed the packet length
3461
         * encoding this varbind and this is a bulk response, we can drop
3462
         * the failed varbind (and any that follow it) and continue encoding
3463
         * the (shorter) bulk response.
3464
         */
3465
1.62k
        save_ptr = cp;
3466
1.62k
        save_length = *out_length;
3467
3468
1.62k
        DEBUGDUMPSECTION("send", "VarBind");
3469
1.62k
        cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
3470
1.62k
                               vp->val_len, vp->val.string, out_length);
3471
1.62k
        DEBUGINDENTLESS();
3472
1.62k
        if (cp == NULL) {
3473
457
            if (save_vp && (pdu->flags & UCD_MSG_FLAG_BULK_TOOBIG)) {
3474
0
                DEBUGDUMPSECTION("send",
3475
0
                                 "VarBind would exceed packet size; dropped");
3476
0
                cp = save_ptr;
3477
0
                *out_length = save_length;
3478
0
                break;
3479
0
            } else
3480
457
                return NULL;
3481
457
        }
3482
1.16k
        save_vp = vp;
3483
1.16k
    }
3484
1.28k
    DEBUGINDENTLESS();
3485
3486
    /** did we run out of room? (should only happen for bulk responses) */
3487
1.28k
    if (vp && save_vp) {
3488
0
        save_vp->next_variable = NULL; /* truncate variable list */
3489
        /** count remaining varbinds in list, then free them */
3490
0
        save_vp = vp;
3491
0
        for(save_length = 0; save_vp; save_vp = save_vp->next_variable)
3492
0
            ++save_length;
3493
0
        DEBUGMSGTL(("send", "trimmed %" NETSNMP_PRIz "d variables\n", save_length));
3494
0
        snmp_free_varbind(vp);
3495
0
    }
3496
3497
    /*
3498
     * insert actual length of variable-bindings sequence 
3499
     */
3500
1.28k
    asn_build_sequence(h2, &length,
3501
1.28k
                       (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3502
1.28k
                       cp - h2e);
3503
3504
    /*
3505
     * insert actual length of PDU sequence 
3506
     */
3507
1.28k
    asn_build_sequence(h1, &length, (u_char) pdu->command, cp - h1e);
3508
3509
1.28k
    return cp;
3510
1.74k
}
3511
3512
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
3513
/*
3514
 * On error, returns 0 (likely an encoding problem).  
3515
 */
3516
int
3517
snmp_pdu_realloc_rbuild(u_char ** pkt, size_t * pkt_len, size_t * offset,
3518
                        const netsnmp_pdu *pdu)
3519
434
{
3520
434
#ifndef VPCACHE_SIZE
3521
2.05k
#define VPCACHE_SIZE 50
3522
434
#endif
3523
434
    netsnmp_variable_list *vpcache[VPCACHE_SIZE];
3524
434
    netsnmp_variable_list *vp, *tmpvp;
3525
434
    size_t          start_offset = *offset;
3526
434
    int             i, wrapped = 0, notdone, final, rc = 0;
3527
3528
434
    DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "starting\n"));
3529
1.62k
    for (vp = pdu->variables, i = VPCACHE_SIZE - 1; vp;
3530
1.18k
         vp = vp->next_variable, i--) {
3531
        /*
3532
         * if estimated getbulk response size exceeded packet max size,
3533
         * processing was stopped before bulk cache was filled and type
3534
         * was set to ASN_PRIV_STOP, indicating that the rest of the varbinds
3535
         * in the cache are empty and we can stop encoding them.
3536
         */
3537
1.18k
        if (ASN_PRIV_STOP == vp->type)
3538
0
            break;
3539
1.18k
        if (i < 0) {
3540
0
            wrapped = notdone = 1;
3541
0
            i = VPCACHE_SIZE - 1;
3542
0
            DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
3543
0
        }
3544
1.18k
        vpcache[i] = vp;
3545
1.18k
    }
3546
434
    final = i + 1;
3547
3548
434
    do {
3549
1.62k
        for (i = final; i < VPCACHE_SIZE; i++) {
3550
1.18k
            vp = vpcache[i];
3551
1.18k
            DEBUGDUMPSECTION("send", "VarBind");
3552
1.18k
            rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
3553
1.18k
                                            vp->name, &vp->name_length,
3554
1.18k
                                            vp->type,
3555
1.18k
                                            (u_char *) vp->val.string,
3556
1.18k
                                            vp->val_len);
3557
1.18k
            DEBUGINDENTLESS();
3558
1.18k
            if (rc == 0) {
3559
0
                return 0;
3560
0
            }
3561
1.18k
        }
3562
3563
434
        DEBUGINDENTLESS();
3564
434
        if (wrapped) {
3565
0
            notdone = 1;
3566
0
            for (i = 0; i < final; i++) {
3567
0
                vp = vpcache[i];
3568
0
                DEBUGDUMPSECTION("send", "VarBind");
3569
0
                rc = snmp_realloc_rbuild_var_op(pkt, pkt_len, offset, 1,
3570
0
                                                vp->name, &vp->name_length,
3571
0
                                                vp->type,
3572
0
                                                (u_char *) vp->val.string,
3573
0
                                                vp->val_len);
3574
0
                DEBUGINDENTLESS();
3575
0
                if (rc == 0) {
3576
0
                    return 0;
3577
0
                }
3578
0
            }
3579
3580
0
            if (final == 0) {
3581
0
                tmpvp = vpcache[VPCACHE_SIZE - 1];
3582
0
            } else {
3583
0
                tmpvp = vpcache[final - 1];
3584
0
            }
3585
0
            wrapped = 0;
3586
3587
0
            for (vp = pdu->variables, i = VPCACHE_SIZE - 1;
3588
0
                 vp && vp != tmpvp; vp = vp->next_variable, i--) {
3589
0
                if (i < 0) {
3590
0
                    wrapped = 1;
3591
0
                    i = VPCACHE_SIZE - 1;
3592
0
                    DEBUGMSGTL(("snmp_pdu_realloc_rbuild", "wrapped\n"));
3593
0
                }
3594
0
                vpcache[i] = vp;
3595
0
            }
3596
0
            final = i + 1;
3597
434
        } else {
3598
434
            notdone = 0;
3599
434
        }
3600
434
    } while (notdone);
3601
3602
    /*
3603
     * Save current location and build SEQUENCE tag and length placeholder for
3604
     * variable-bindings sequence (actual length will be inserted later).  
3605
     */
3606
3607
434
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3608
434
                                     (u_char) (ASN_SEQUENCE |
3609
434
                                               ASN_CONSTRUCTOR),
3610
434
                                     *offset - start_offset);
3611
3612
    /*
3613
     * Store fields in the PDU preceding the variable-bindings sequence.
3614
     */
3615
434
    if (pdu->command != SNMP_MSG_TRAP) {
3616
        /*
3617
         * Error index (getbulk max-repetitions).  
3618
         */
3619
434
        DEBUGDUMPHEADER("send", "error index");
3620
434
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3621
434
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3622
434
                                              | ASN_INTEGER),
3623
434
                                    &pdu->errindex, sizeof(pdu->errindex));
3624
434
        DEBUGINDENTLESS();
3625
434
        if (rc == 0) {
3626
0
            return 0;
3627
0
        }
3628
3629
        /*
3630
         * Error status (getbulk non-repeaters).  
3631
         */
3632
434
        DEBUGDUMPHEADER("send", "error status");
3633
434
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3634
434
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3635
434
                                              | ASN_INTEGER),
3636
434
                                    &pdu->errstat, sizeof(pdu->errstat));
3637
434
        DEBUGINDENTLESS();
3638
434
        if (rc == 0) {
3639
0
            return 0;
3640
0
        }
3641
3642
        /*
3643
         * Request ID.  
3644
         */
3645
434
        DEBUGDUMPHEADER("send", "request_id");
3646
434
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3647
434
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3648
434
                                              | ASN_INTEGER), &pdu->reqid,
3649
434
                                    sizeof(pdu->reqid));
3650
434
        DEBUGINDENTLESS();
3651
434
        if (rc == 0) {
3652
0
            return 0;
3653
0
        }
3654
434
    } else {
3655
        /*
3656
         * An SNMPv1 trap PDU.  
3657
         */
3658
3659
        /*
3660
         * Timestamp.  
3661
         */
3662
0
        DEBUGDUMPHEADER("send", "timestamp");
3663
0
        rc = asn_realloc_rbuild_unsigned_int(pkt, pkt_len, offset, 1,
3664
0
                                             (u_char) (ASN_TIMETICKS |
3665
0
                                                       ASN_PRIMITIVE),
3666
0
                                             &pdu->time,
3667
0
                                             sizeof(pdu->time));
3668
0
        DEBUGINDENTLESS();
3669
0
        if (rc == 0) {
3670
0
            return 0;
3671
0
        }
3672
3673
        /*
3674
         * Specific trap.  
3675
         */
3676
0
        DEBUGDUMPHEADER("send", "specific trap number");
3677
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3678
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3679
0
                                              | ASN_INTEGER),
3680
0
                                    (const long *) &pdu->specific_type,
3681
0
                                    sizeof(pdu->specific_type));
3682
0
        DEBUGINDENTLESS();
3683
0
        if (rc == 0) {
3684
0
            return 0;
3685
0
        }
3686
3687
        /*
3688
         * Generic trap.  
3689
         */
3690
0
        DEBUGDUMPHEADER("send", "generic trap number");
3691
0
        rc = asn_realloc_rbuild_int(pkt, pkt_len, offset, 1,
3692
0
                                    (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
3693
0
                                              | ASN_INTEGER),
3694
0
                                    (const long *) &pdu->trap_type,
3695
0
                                    sizeof(pdu->trap_type));
3696
0
        DEBUGINDENTLESS();
3697
0
        if (rc == 0) {
3698
0
            return 0;
3699
0
        }
3700
3701
        /*
3702
         * Agent-addr.  
3703
         */
3704
0
        DEBUGDUMPHEADER("send", "agent Address");
3705
0
        rc = asn_realloc_rbuild_string(pkt, pkt_len, offset, 1,
3706
0
                                       (u_char) (ASN_IPADDRESS |
3707
0
                                                 ASN_PRIMITIVE),
3708
0
                                       (const u_char *) pdu->agent_addr, 4);
3709
0
        DEBUGINDENTLESS();
3710
0
        if (rc == 0) {
3711
0
            return 0;
3712
0
        }
3713
3714
        /*
3715
         * Enterprise.  
3716
         */
3717
0
        DEBUGDUMPHEADER("send", "enterprise OBJID");
3718
0
        rc = asn_realloc_rbuild_objid(pkt, pkt_len, offset, 1,
3719
0
                                      (u_char) (ASN_UNIVERSAL |
3720
0
                                                ASN_PRIMITIVE |
3721
0
                                                ASN_OBJECT_ID),
3722
0
                                      (oid *) pdu->enterprise,
3723
0
                                      pdu->enterprise_length);
3724
0
        DEBUGINDENTLESS();
3725
0
        if (rc == 0) {
3726
0
            return 0;
3727
0
        }
3728
0
    }
3729
3730
    /*
3731
     * Build the PDU sequence.  
3732
     */
3733
434
    rc = asn_realloc_rbuild_sequence(pkt, pkt_len, offset, 1,
3734
434
                                     (u_char) pdu->command,
3735
434
                                     *offset - start_offset);
3736
434
    return rc;
3737
434
}
3738
#endif                          /* NETSNMP_USE_REVERSE_ASNENCODING */
3739
3740
/*
3741
 * Parses the packet received to determine version, either directly
3742
 * from packets version field or inferred from ASN.1 construct.
3743
 */
3744
static int
3745
snmp_parse_version(u_char * data, size_t length)
3746
1.01k
{
3747
1.01k
    u_char          type;
3748
1.01k
    long            version = SNMPERR_BAD_VERSION;
3749
3750
1.01k
    data = asn_parse_sequence(data, &length, &type,
3751
1.01k
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
3752
1.01k
    if (data) {
3753
997
        DEBUGDUMPHEADER("recv", "SNMP Version");
3754
997
        data =
3755
997
            asn_parse_int(data, &length, &type, &version, sizeof(version));
3756
997
        DEBUGINDENTLESS();
3757
997
        if (!data || type != ASN_INTEGER) {
3758
3
            return SNMPERR_BAD_VERSION;
3759
3
        }
3760
997
    }
3761
1.00k
    return version;
3762
1.01k
}
3763
3764
3765
int
3766
snmpv3_parse(netsnmp_pdu *pdu,
3767
             u_char * data,
3768
             size_t * length,
3769
             u_char ** after_header, netsnmp_session * sess)
3770
2.71k
{
3771
2.71k
    u_char          type, msg_flags;
3772
2.71k
    long            ver, msg_sec_model;
3773
2.71k
    size_t          max_size_response;
3774
2.71k
    u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
3775
2.71k
    size_t          tmp_buf_len;
3776
2.71k
    u_char          pdu_buf[SNMP_MAX_MSG_SIZE];
3777
2.71k
    u_char         *mallocbuf = NULL;
3778
2.71k
    size_t          pdu_buf_len = SNMP_MAX_MSG_SIZE;
3779
2.71k
    u_char         *sec_params;
3780
2.71k
    u_char         *msg_data;
3781
2.71k
    u_char         *cp;
3782
2.71k
    size_t          asn_len, msg_len;
3783
2.71k
    int             ret, ret_val;
3784
2.71k
    struct snmp_secmod_def *sptr;
3785
3786
3787
2.71k
    msg_data = data;
3788
2.71k
    msg_len = *length;
3789
3790
3791
    /*
3792
     * message is an ASN.1 SEQUENCE  
3793
     */
3794
2.71k
    DEBUGDUMPSECTION("recv", "SNMPv3 Message");
3795
2.71k
    data = asn_parse_sequence(data, length, &type,
3796
2.71k
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
3797
2.71k
    if (data == NULL) {
3798
        /*
3799
         * error msg detail is set 
3800
         */
3801
298
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3802
298
        DEBUGINDENTLESS();
3803
298
        return SNMPERR_ASN_PARSE_ERR;
3804
298
    }
3805
3806
    /*
3807
     * parse msgVersion  
3808
     */
3809
2.41k
    DEBUGDUMPHEADER("recv", "SNMP Version Number");
3810
2.41k
    data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
3811
2.41k
    DEBUGINDENTLESS();
3812
2.41k
    if (data == NULL) {
3813
161
        ERROR_MSG("bad parse of version");
3814
161
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3815
161
        DEBUGINDENTLESS();
3816
161
        return SNMPERR_ASN_PARSE_ERR;
3817
161
    }
3818
2.25k
    pdu->version = ver;
3819
3820
    /*
3821
     * parse msgGlobalData sequence  
3822
     */
3823
2.25k
    cp = data;
3824
2.25k
    asn_len = *length;
3825
2.25k
    DEBUGDUMPSECTION("recv", "msgGlobalData");
3826
2.25k
    data = asn_parse_sequence(data, &asn_len, &type,
3827
2.25k
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
3828
2.25k
                              "msgGlobalData");
3829
2.25k
    if (data == NULL) {
3830
        /*
3831
         * error msg detail is set 
3832
         */
3833
1.77k
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3834
1.77k
        DEBUGINDENTADD(-4);
3835
1.77k
        return SNMPERR_ASN_PARSE_ERR;
3836
1.77k
    }
3837
479
    *length -= data - cp;       /* subtract off the length of the header */
3838
3839
    /*
3840
     * msgID 
3841
     */
3842
479
    DEBUGDUMPHEADER("recv", "msgID");
3843
479
    data =
3844
479
        asn_parse_int(data, length, &type, &pdu->msgid,
3845
479
                      sizeof(pdu->msgid));
3846
479
    DEBUGINDENTLESS();
3847
479
    if (data == NULL || type != ASN_INTEGER) {
3848
20
        ERROR_MSG("error parsing msgID");
3849
20
        DEBUGINDENTADD(-4);
3850
20
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3851
20
        return SNMPERR_ASN_PARSE_ERR;
3852
20
    }
3853
3854
    /*
3855
     * Check the msgID we received is a legal value.  If not, then increment
3856
     * snmpInASNParseErrs and return the appropriate error (see RFC 2572,
3857
     * para. 7.2, section 2 -- note that a bad msgID means that the received
3858
     * message is NOT a serialization of an SNMPv3Message, since the msgID
3859
     * field is out of bounds).  
3860
     */
3861
3862
459
    if (pdu->msgid < 0 || pdu->msgid > SNMP_MAX_PACKET_LEN) {
3863
70
        snmp_log(LOG_ERR, "Received bad msgID (%ld %s %s).\n", pdu->msgid,
3864
70
                 (pdu->msgid < 0) ? "<" : ">",
3865
70
                 (pdu->msgid < 0) ? "0" : "2^31 - 1");
3866
70
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3867
70
        DEBUGINDENTADD(-4);
3868
70
        return SNMPERR_ASN_PARSE_ERR;
3869
70
    }
3870
3871
    /*
3872
     * msgMaxSize 
3873
     */
3874
389
    DEBUGDUMPHEADER("recv:msgMaxSize", "msgMaxSize");
3875
389
    data = asn_parse_int(data, length, &type, &pdu->msgMaxSize,
3876
389
                         sizeof(pdu->msgMaxSize));
3877
389
    DEBUGINDENTLESS();
3878
389
    if (data == NULL || type != ASN_INTEGER) {
3879
75
        ERROR_MSG("error parsing msgMaxSize");
3880
75
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3881
75
        DEBUGINDENTADD(-4);
3882
75
        return SNMPERR_ASN_PARSE_ERR;
3883
75
    }
3884
3885
    /*
3886
     * Check the msgMaxSize we received is a legal value.  If not, then
3887
     * increment snmpInASNParseErrs and return the appropriate error (see RFC
3888
     * 2572, para. 7.2, section 2 -- note that a bad msgMaxSize means that the
3889
     * received message is NOT a serialization of an SNMPv3Message, since the
3890
     * msgMaxSize field is out of bounds).
3891
     */
3892
3893
314
    if (pdu->msgMaxSize < SNMP_MIN_MAX_LEN) {
3894
22
        snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu < 484).\n",
3895
22
                 pdu->msgMaxSize);
3896
22
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3897
22
        DEBUGINDENTADD(-4);
3898
22
        return SNMPERR_ASN_PARSE_ERR;
3899
292
    } else if (pdu->msgMaxSize > SNMP_MAX_PACKET_LEN) {
3900
5
        snmp_log(LOG_ERR, "Received bad msgMaxSize (%lu > 2^31 - 1).\n",
3901
5
                 pdu->msgMaxSize);
3902
5
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3903
5
        DEBUGINDENTADD(-4);
3904
5
        return SNMPERR_ASN_PARSE_ERR;
3905
287
    } else {
3906
287
        DEBUGMSGTL(("snmpv3_parse:msgMaxSize", "msgMaxSize %lu received\n",
3907
287
                    pdu->msgMaxSize));
3908
        /** don't increase max msg size if we've already got one */
3909
287
        if (sess->sndMsgMaxSize < pdu->msgMaxSize) {
3910
287
            DEBUGMSGTL(("snmpv3_parse:msgMaxSize",
3911
287
                        "msgMaxSize %" NETSNMP_PRIz "d greater than session max %ld; reducing\n",
3912
287
                        sess->sndMsgMaxSize, pdu->msgMaxSize));
3913
287
            pdu->msgMaxSize = sess->sndMsgMaxSize;
3914
287
        }
3915
287
    }
3916
3917
    /*
3918
     * msgFlags 
3919
     */
3920
287
    tmp_buf_len = SNMP_MAX_MSG_SIZE;
3921
287
    DEBUGDUMPHEADER("recv", "msgFlags");
3922
287
    data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
3923
287
    DEBUGINDENTLESS();
3924
287
    if (data == NULL || type != ASN_OCTET_STR || tmp_buf_len != 1) {
3925
99
        ERROR_MSG("error parsing msgFlags");
3926
99
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3927
99
        DEBUGINDENTADD(-4);
3928
99
        return SNMPERR_ASN_PARSE_ERR;
3929
99
    }
3930
188
    msg_flags = *tmp_buf;
3931
188
    if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
3932
70
        pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
3933
118
    else
3934
118
        pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
3935
3936
    /*
3937
     * msgSecurityModel 
3938
     */
3939
188
    DEBUGDUMPHEADER("recv", "msgSecurityModel");
3940
188
    data = asn_parse_int(data, length, &type, &msg_sec_model,
3941
188
                         sizeof(msg_sec_model));
3942
188
    DEBUGINDENTADD(-4);         /* return from global data indent */
3943
188
    if (data == NULL || type != ASN_INTEGER ||
3944
188
        msg_sec_model < 1 || msg_sec_model > 0x7fffffff) {
3945
91
        ERROR_MSG("error parsing msgSecurityModel");
3946
91
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
3947
91
        DEBUGINDENTLESS();
3948
91
        return SNMPERR_ASN_PARSE_ERR;
3949
91
    }
3950
97
    sptr = find_sec_mod(msg_sec_model);
3951
97
    if (!sptr) {
3952
97
        snmp_log(LOG_WARNING, "unknown security model: %ld\n",
3953
97
                 msg_sec_model);
3954
97
        snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
3955
97
        DEBUGINDENTLESS();
3956
97
        return SNMPERR_UNKNOWN_SEC_MODEL;
3957
97
    }
3958
0
    pdu->securityModel = msg_sec_model;
3959
3960
0
    if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT &&
3961
0
        !(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
3962
0
        ERROR_MSG("invalid message, illegal msgFlags");
3963
0
        snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
3964
0
        DEBUGINDENTLESS();
3965
0
        return SNMPERR_INVALID_MSG;
3966
0
    }
3967
0
    pdu->securityLevel = ((msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
3968
0
                          ? ((msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
3969
0
                             ? SNMP_SEC_LEVEL_AUTHPRIV
3970
0
                             : SNMP_SEC_LEVEL_AUTHNOPRIV)
3971
0
                          : SNMP_SEC_LEVEL_NOAUTH);
3972
    /*
3973
     * end of msgGlobalData 
3974
     */
3975
3976
    /*
3977
     * securtityParameters OCTET STRING begins after msgGlobalData 
3978
     */
3979
0
    sec_params = data;
3980
0
    pdu->contextEngineID = calloc(1, SNMP_MAX_ENG_SIZE);
3981
0
    pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
3982
3983
    /*
3984
     * Note: there is no length limit on the msgAuthoritativeEngineID field,
3985
     * although we would EXPECT it to be limited to 32 (the SnmpEngineID TC
3986
     * limit).  We'll use double that here to be on the safe side.  
3987
     */
3988
3989
0
    pdu->securityEngineID = calloc(1, SNMP_MAX_ENG_SIZE * 2);
3990
0
    pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE * 2;
3991
0
    pdu->securityName = calloc(1, SNMP_MAX_SEC_NAME_SIZE);
3992
0
    pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
3993
3994
0
    if ((pdu->securityName == NULL) ||
3995
0
        (pdu->securityEngineID == NULL) ||
3996
0
        (pdu->contextEngineID == NULL)) {
3997
0
        return SNMPERR_MALLOC;
3998
0
    }
3999
4000
0
    if (pdu_buf_len < msg_len
4001
0
        && pdu->securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
4002
        /*
4003
         * space needed is larger than we have in the default buffer 
4004
         */
4005
0
        mallocbuf = calloc(1, msg_len);
4006
0
        pdu_buf_len = msg_len;
4007
0
        cp = mallocbuf;
4008
0
    } else {
4009
0
        memset(pdu_buf, 0, pdu_buf_len);
4010
0
        cp = pdu_buf;
4011
0
    }
4012
4013
0
    DEBUGDUMPSECTION("recv", "SM msgSecurityParameters");
4014
0
    if (sptr->decode) {
4015
0
        struct snmp_secmod_incoming_params parms;
4016
0
        parms.msgProcModel = pdu->msgParseModel;
4017
0
        parms.maxMsgSize = pdu->msgMaxSize;
4018
0
        parms.secParams = sec_params;
4019
0
        parms.secModel = msg_sec_model;
4020
0
        parms.secLevel = pdu->securityLevel;
4021
0
        parms.wholeMsg = msg_data;
4022
0
        parms.wholeMsgLen = msg_len;
4023
0
        parms.secEngineID = pdu->securityEngineID;
4024
0
        parms.secEngineIDLen = &pdu->securityEngineIDLen;
4025
0
        parms.secName = pdu->securityName;
4026
0
        parms.secNameLen = &pdu->securityNameLen;
4027
0
        parms.scopedPdu = &cp;
4028
0
        parms.scopedPduLen = &pdu_buf_len;
4029
0
        parms.maxSizeResponse = &max_size_response;
4030
0
        parms.secStateRef = &pdu->securityStateRef;
4031
0
        parms.sess = sess;
4032
0
        parms.pdu = pdu;
4033
0
        parms.msg_flags = msg_flags;
4034
0
        ret_val = (*sptr->decode) (&parms);
4035
0
    } else {
4036
0
        SNMP_FREE(mallocbuf);
4037
0
        DEBUGINDENTLESS();
4038
0
        snmp_log(LOG_WARNING, "security service %ld can't decode packets\n",
4039
0
                 msg_sec_model);
4040
0
        return (-1);
4041
0
    }
4042
4043
0
    if (ret_val != SNMPERR_SUCCESS) {
4044
0
        DEBUGDUMPSECTION("recv", "ScopedPDU");
4045
        /*
4046
         * Parse as much as possible -- though I don't see the point? [jbpn].  
4047
         */
4048
0
        if (cp) {
4049
0
            cp = snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len);
4050
0
        }
4051
0
        if (cp) {
4052
0
            DEBUGPRINTPDUTYPE("recv", *cp);
4053
0
            snmp_pdu_parse(pdu, cp, &pdu_buf_len);
4054
0
            DEBUGINDENTADD(-8);
4055
0
        } else {
4056
0
            DEBUGINDENTADD(-4);
4057
0
        }
4058
4059
0
        SNMP_FREE(mallocbuf);
4060
0
        return ret_val;
4061
0
    }
4062
4063
    /*
4064
     * parse plaintext ScopedPDU sequence 
4065
     */
4066
0
    *length = pdu_buf_len;
4067
0
    DEBUGDUMPSECTION("recv", "ScopedPDU");
4068
0
    data = snmpv3_scopedPDU_parse(pdu, cp, length);
4069
0
    if (data == NULL) {
4070
0
        snmp_log(LOG_WARNING, "security service %ld error parsing ScopedPDU\n",
4071
0
                 msg_sec_model);
4072
0
        ERROR_MSG("error parsing PDU");
4073
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4074
0
        DEBUGINDENTADD(-4);
4075
0
        SNMP_FREE(mallocbuf);
4076
0
        return SNMPERR_ASN_PARSE_ERR;
4077
0
    }
4078
4079
    /*
4080
     * parse the PDU.  
4081
     */
4082
0
    if (after_header != NULL) {
4083
0
        *after_header = data;
4084
0
        tmp_buf_len = *length;
4085
0
    }
4086
4087
0
    DEBUGPRINTPDUTYPE("recv", *data);
4088
0
    ret = snmp_pdu_parse(pdu, data, length);
4089
0
    DEBUGINDENTADD(-8);
4090
4091
0
    if (after_header != NULL) {
4092
0
        *length = tmp_buf_len;
4093
0
    }
4094
4095
0
    if (ret != SNMPERR_SUCCESS) {
4096
0
        snmp_log(LOG_WARNING, "security service %ld error parsing ScopedPDU\n",
4097
0
                 msg_sec_model);
4098
0
        ERROR_MSG("error parsing PDU");
4099
0
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4100
0
        SNMP_FREE(mallocbuf);
4101
0
        return SNMPERR_ASN_PARSE_ERR;
4102
0
    }
4103
4104
0
    SNMP_FREE(mallocbuf);
4105
0
    return SNMPERR_SUCCESS;
4106
0
}                               /* end snmpv3_parse() */
4107
4108
static void
4109
free_securityStateRef(netsnmp_pdu* pdu)
4110
51.4k
{
4111
51.4k
    struct snmp_secmod_def *sptr;
4112
4113
51.4k
    if (!pdu->securityStateRef)
4114
51.4k
        return;
4115
4116
0
    sptr = find_sec_mod(pdu->securityModel);
4117
0
    if (sptr) {
4118
0
        if (sptr->pdu_free_state_ref) {
4119
0
            (*sptr->pdu_free_state_ref) (pdu->securityStateRef);
4120
0
        } else {
4121
0
            snmp_log(LOG_ERR,
4122
0
                     "Security Model %d can't free state references\n",
4123
0
                     pdu->securityModel);
4124
0
  }
4125
0
    } else {
4126
0
  snmp_log(LOG_ERR,
4127
0
     "Can't find security model to free ptr: %d\n",
4128
0
     pdu->securityModel);
4129
0
    }
4130
0
    pdu->securityStateRef = NULL;
4131
0
}
4132
4133
6
#define ERROR_STAT_LENGTH 11
4134
4135
int
4136
snmpv3_make_report(netsnmp_pdu *pdu, int error)
4137
2.93k
{
4138
4139
2.93k
    long            ltmp;
4140
2.93k
    static const oid unknownSecurityLevel[] =
4141
2.93k
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
4142
2.93k
    static const oid notInTimeWindow[] =
4143
2.93k
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
4144
2.93k
    static const oid unknownUserName[] =
4145
2.93k
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
4146
2.93k
    static const oid unknownEngineID[] =
4147
2.93k
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
4148
2.93k
    static const oid wrongDigest[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
4149
2.93k
    static const oid decryptionError[] =
4150
2.93k
        { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
4151
2.93k
    const oid      *err_var;
4152
2.93k
    int             err_var_len;
4153
2.93k
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4154
2.93k
    int             stat_ind;
4155
2.93k
#endif
4156
4157
2.93k
    switch (error) {
4158
1
    case SNMPERR_USM_UNKNOWNENGINEID:
4159
1
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4160
1
        stat_ind = STAT_USMSTATSUNKNOWNENGINEIDS;
4161
1
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4162
1
        err_var = unknownEngineID;
4163
1
        err_var_len = ERROR_STAT_LENGTH;
4164
1
        break;
4165
1
    case SNMPERR_USM_UNKNOWNSECURITYNAME:
4166
1
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4167
1
        stat_ind = STAT_USMSTATSUNKNOWNUSERNAMES;
4168
1
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4169
1
        err_var = unknownUserName;
4170
1
        err_var_len = ERROR_STAT_LENGTH;
4171
1
        break;
4172
1
    case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
4173
1
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4174
1
        stat_ind = STAT_USMSTATSUNSUPPORTEDSECLEVELS;
4175
1
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4176
1
        err_var = unknownSecurityLevel;
4177
1
        err_var_len = ERROR_STAT_LENGTH;
4178
1
        break;
4179
1
    case SNMPERR_USM_AUTHENTICATIONFAILURE:
4180
1
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4181
1
        stat_ind = STAT_USMSTATSWRONGDIGESTS;
4182
1
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4183
1
        err_var = wrongDigest;
4184
1
        err_var_len = ERROR_STAT_LENGTH;
4185
1
        break;
4186
1
    case SNMPERR_USM_NOTINTIMEWINDOW:
4187
1
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4188
1
        stat_ind = STAT_USMSTATSNOTINTIMEWINDOWS;
4189
1
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4190
1
        err_var = notInTimeWindow;
4191
1
        err_var_len = ERROR_STAT_LENGTH;
4192
1
        break;
4193
1
    case SNMPERR_USM_DECRYPTIONERROR:
4194
1
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4195
1
        stat_ind = STAT_USMSTATSDECRYPTIONERRORS;
4196
1
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4197
1
        err_var = decryptionError;
4198
1
        err_var_len = ERROR_STAT_LENGTH;
4199
1
        break;
4200
2.92k
    default:
4201
2.92k
        return SNMPERR_GENERR;
4202
2.93k
    }
4203
4204
6
    snmp_free_varbind(pdu->variables);  /* free the current varbind */
4205
4206
6
    pdu->variables = NULL;
4207
6
    SNMP_FREE(pdu->securityEngineID);
4208
6
    pdu->securityEngineID =
4209
6
        snmpv3_generate_engineID(&pdu->securityEngineIDLen);
4210
6
    SNMP_FREE(pdu->contextEngineID);
4211
6
    pdu->contextEngineID =
4212
6
        snmpv3_generate_engineID(&pdu->contextEngineIDLen);
4213
6
    pdu->command = SNMP_MSG_REPORT;
4214
6
    pdu->errstat = 0;
4215
6
    pdu->errindex = 0;
4216
6
    SNMP_FREE(pdu->contextName);
4217
6
    pdu->contextName = strdup("");
4218
6
    pdu->contextNameLen = strlen(pdu->contextName);
4219
4220
    /*
4221
     * reports shouldn't cache previous data. 
4222
     */
4223
    /*
4224
     * FIX - yes they should but USM needs to follow new EoP to determine
4225
     * which cached values to use 
4226
     */
4227
6
    free_securityStateRef(pdu);
4228
4229
6
    if (error == SNMPERR_USM_NOTINTIMEWINDOW) {
4230
1
        pdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
4231
5
    } else {
4232
5
        pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
4233
5
    }
4234
4235
    /*
4236
     * find the appropriate error counter  
4237
     */
4238
6
#ifndef NETSNMP_FEATURE_REMOVE_STATISTICS
4239
6
    ltmp = snmp_get_statistic(stat_ind);
4240
#else /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4241
    ltmp = 1;
4242
#endif /* !NETSNMP_FEATURE_REMOVE_STATISTICS */
4243
4244
    /*
4245
     * return the appropriate error counter  
4246
     */
4247
6
    snmp_pdu_add_variable(pdu, err_var, err_var_len,
4248
6
                          ASN_COUNTER, & ltmp, sizeof(ltmp));
4249
4250
6
    return SNMPERR_SUCCESS;
4251
2.93k
}                               /* end snmpv3_make_report() */
4252
4253
4254
int
4255
snmpv3_get_report_type(netsnmp_pdu *pdu)
4256
2.93k
{
4257
2.93k
    static const oid snmpMPDStats[] = { 1, 3, 6, 1, 6, 3, 11, 2, 1 };
4258
2.93k
    static const oid targetStats[]  = { 1, 3, 6, 1, 6, 3, 12, 1    };
4259
2.93k
    static const oid usmStats[]     = { 1, 3, 6, 1, 6, 3, 15, 1, 1 };
4260
2.93k
    netsnmp_variable_list *vp;
4261
2.93k
    int             rpt_type = SNMPERR_UNKNOWN_REPORT;
4262
4263
2.93k
    if (pdu == NULL || pdu->variables == NULL)
4264
2.46k
        return rpt_type;
4265
470
    vp = pdu->variables;
4266
    /* MPD or USM based report statistics objects have the same length prefix
4267
     *   so the actual statistics OID will have this length,
4268
     *   plus one subidentifier for the scalar MIB object itself,
4269
     *   and one for the instance subidentifier
4270
     */
4271
470
    if (vp->name_length == REPORT_STATS_LEN + 2) {
4272
67
        if (memcmp(snmpMPDStats, vp->name, REPORT_STATS_LEN * sizeof(oid)) == 0) {
4273
15
            switch (vp->name[REPORT_STATS_LEN]) {
4274
0
            case REPORT_snmpUnknownSecurityModels_NUM:
4275
0
                rpt_type = SNMPERR_UNKNOWN_SEC_MODEL;
4276
0
                break;
4277
1
            case REPORT_snmpInvalidMsgs_NUM:
4278
1
                rpt_type = SNMPERR_INVALID_MSG;
4279
1
                break;
4280
1
            case REPORT_snmpUnknownPDUHandlers_NUM:
4281
1
                rpt_type = SNMPERR_BAD_VERSION;
4282
1
                break;
4283
15
            }
4284
52
        } else if (memcmp(usmStats, vp->name, REPORT_STATS_LEN * sizeof(oid)) == 0) {
4285
19
            switch (vp->name[REPORT_STATS_LEN]) {
4286
1
            case REPORT_usmStatsUnsupportedSecLevels_NUM:
4287
1
                rpt_type = SNMPERR_UNSUPPORTED_SEC_LEVEL;
4288
1
                break;
4289
1
            case REPORT_usmStatsNotInTimeWindows_NUM:
4290
1
                rpt_type = SNMPERR_NOT_IN_TIME_WINDOW;
4291
1
                break;
4292
1
            case REPORT_usmStatsUnknownUserNames_NUM:
4293
1
                rpt_type = SNMPERR_UNKNOWN_USER_NAME;
4294
1
                break;
4295
1
            case REPORT_usmStatsUnknownEngineIDs_NUM:
4296
1
                rpt_type = SNMPERR_UNKNOWN_ENG_ID;
4297
1
                break;
4298
1
            case REPORT_usmStatsWrongDigests_NUM:
4299
1
                rpt_type = SNMPERR_AUTHENTICATION_FAILURE;
4300
1
                break;
4301
1
            case REPORT_usmStatsDecryptionErrors_NUM:
4302
1
                rpt_type = SNMPERR_DECRYPTION_ERR;
4303
1
                break;
4304
19
            }
4305
19
        }
4306
67
    }
4307
    /* Context-based report statistics from the Target MIB are similar
4308
     *   but the OID prefix has a different length
4309
     */
4310
470
    if (vp->name_length == REPORT_STATS_LEN2 + 2) {
4311
38
        if (memcmp(targetStats, vp->name, REPORT_STATS_LEN2 * sizeof(oid)) == 0) {
4312
3
            switch (vp->name[REPORT_STATS_LEN2]) {
4313
1
            case REPORT_snmpUnavailableContexts_NUM:
4314
1
                rpt_type = SNMPERR_BAD_CONTEXT;
4315
1
                break;
4316
1
            case REPORT_snmpUnknownContexts_NUM:
4317
1
                rpt_type = SNMPERR_BAD_CONTEXT;
4318
1
                break;
4319
3
            }
4320
3
        }
4321
38
    }
4322
470
    DEBUGMSGTL(("report", "Report type: %d\n", rpt_type));
4323
470
    return rpt_type;
4324
470
}
4325
4326
/*
4327
 * Parses the packet received on the input session, and places the data into
4328
 * the input pdu.  length is the length of the input packet.
4329
 * If any errors are encountered, -1 or USM error is returned.
4330
 * Otherwise, a 0 is returned.
4331
 */
4332
static int
4333
_snmp_parse(struct session_list *slp,
4334
            netsnmp_session * session,
4335
            netsnmp_pdu *pdu, u_char * data, size_t length)
4336
6.29k
{
4337
6.29k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
4338
6.29k
    u_char          community[COMMUNITY_MAX_LEN];
4339
6.29k
    size_t          community_length = COMMUNITY_MAX_LEN;
4340
6.29k
#endif
4341
6.29k
    int             result = -1;
4342
4343
6.29k
    static const oid snmpEngineIDoid[]   = { 1,3,6,1,6,3,10,2,1,1,0};
4344
6.29k
    static size_t   snmpEngineIDoid_len = 11;
4345
4346
6.29k
    static char     ourEngineID[SNMP_SEC_PARAM_BUF_SIZE];
4347
6.29k
    static size_t   ourEngineID_len = sizeof(ourEngineID);
4348
4349
6.29k
    netsnmp_pdu    *pdu2 = NULL;
4350
4351
6.29k
    session->s_snmp_errno = 0;
4352
6.29k
    session->s_errno = 0;
4353
4354
    /*
4355
     * Ensure all incoming PDUs have a unique means of identification 
4356
     * (This is not restricted to AgentX handling,
4357
     * though that is where the need becomes visible)   
4358
     */
4359
6.29k
    pdu->transid = snmp_get_next_transid();
4360
4361
6.29k
    if (session->version != SNMP_DEFAULT_VERSION) {
4362
5.27k
        pdu->version = session->version;
4363
5.27k
    } else {
4364
1.01k
        pdu->version = snmp_parse_version(data, length);
4365
1.01k
    }
4366
4367
6.29k
    switch (pdu->version) {
4368
0
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
4369
0
#ifndef NETSNMP_DISABLE_SNMPV1
4370
3.12k
    case SNMP_VERSION_1:
4371
3.12k
#endif
4372
3.12k
#ifndef NETSNMP_DISABLE_SNMPV2C
4373
5.68k
    case SNMP_VERSION_2c:
4374
5.68k
#endif
4375
5.68k
        NETSNMP_RUNTIME_PROTOCOL_CHECK_V1V2(pdu->version,unsupported_version);
4376
5.63k
        DEBUGMSGTL(("snmp_api", "Parsing SNMPv%ld message...\n",
4377
5.63k
                    (1 + pdu->version)));
4378
4379
        /*
4380
         * authenticates message and returns length if valid 
4381
         */
4382
5.63k
#ifndef NETSNMP_DISABLE_SNMPV1
4383
5.63k
        if (pdu->version == SNMP_VERSION_1) {
4384
3.07k
            DEBUGDUMPSECTION("recv", "SNMPv1 message\n");
4385
3.07k
        } else {
4386
2.56k
#endif
4387
2.56k
            DEBUGDUMPSECTION("recv", "SNMPv2c message\n");
4388
2.56k
#ifndef NETSNMP_DISABLE_SNMPV1
4389
2.56k
        }
4390
5.63k
#endif
4391
5.63k
        data = snmp_comstr_parse(data, &length,
4392
5.63k
                                 community, &community_length,
4393
5.63k
                                 &pdu->version);
4394
5.63k
        if (data == NULL)
4395
2.33k
            return -1;
4396
4397
3.30k
        if (pdu->version != session->version &&
4398
3.30k
            session->version != SNMP_DEFAULT_VERSION) {
4399
316
            session->s_snmp_errno = SNMPERR_BAD_VERSION;
4400
316
            return -1;
4401
316
        }
4402
4403
        /*
4404
         * maybe get the community string. 
4405
         */
4406
2.99k
        pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
4407
2.99k
        pdu->securityModel = 
4408
2.99k
#ifndef NETSNMP_DISABLE_SNMPV1
4409
2.99k
            (pdu->version == SNMP_VERSION_1) ? SNMP_SEC_MODEL_SNMPv1 : 
4410
2.99k
#endif
4411
2.99k
                                               SNMP_SEC_MODEL_SNMPv2c;
4412
2.99k
        SNMP_FREE(pdu->community);
4413
2.99k
        pdu->community_len = 0;
4414
2.99k
        pdu->community = (u_char *) 0;
4415
2.99k
        if (community_length) {
4416
1.27k
            pdu->community_len = community_length;
4417
1.27k
            pdu->community = netsnmp_memdup(community, community_length);
4418
1.27k
            if (pdu->community == NULL) {
4419
0
                session->s_snmp_errno = SNMPERR_MALLOC;
4420
0
                return -1;
4421
0
            }
4422
1.27k
        }
4423
2.99k
        if (session->authenticator) {
4424
0
            data = session->authenticator(data, &length,
4425
0
                                          community, community_length);
4426
0
            if (data == NULL) {
4427
0
                session->s_snmp_errno = SNMPERR_AUTHENTICATION_FAILURE;
4428
0
                return -1;
4429
0
            }
4430
0
        }
4431
4432
2.99k
        DEBUGDUMPSECTION("recv", "PDU");
4433
2.99k
        result = snmp_pdu_parse(pdu, data, &length);
4434
2.99k
        if (result < 0) {
4435
            /*
4436
             * This indicates a parse error.  
4437
             */
4438
2.76k
            snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4439
2.76k
        }
4440
2.99k
        DEBUGINDENTADD(-6);
4441
2.99k
        break;
4442
0
#endif /* support for community based SNMP */
4443
4444
180
    case SNMP_VERSION_3:
4445
180
        NETSNMP_RUNTIME_PROTOCOL_CHECK_V3(SNMP_VERSION_3,unsupported_version);
4446
179
        result = snmpv3_parse(pdu, data, &length, NULL, session);
4447
179
        DEBUGMSGTL(("snmp_parse",
4448
179
                    "Parsed SNMPv3 message (secName:%s, secLevel:%s): %s\n",
4449
179
                    pdu->securityName, secLevelName[pdu->securityLevel],
4450
179
                    snmp_api_errstring(result)));
4451
4452
179
        if (result == SNMPERR_USM_UNKNOWNSECURITYNAME) {
4453
0
            snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
4454
0
                                SNMPD_CALLBACK_AUTH_FAILURE, pdu);
4455
0
        }
4456
        
4457
179
        if (result) {
4458
179
            struct snmp_secmod_def *secmod =
4459
179
                find_sec_mod(pdu->securityModel);
4460
179
            if (!slp) {
4461
179
                session->s_snmp_errno = result;
4462
179
            } else {
4463
                /*
4464
                 * Call the security model to special handle any errors
4465
                 */
4466
4467
0
                if (secmod && secmod->handle_report) {
4468
0
                    (*secmod->handle_report)(slp, slp->transport, session,
4469
0
                                             result, pdu);
4470
0
                }
4471
0
            }
4472
179
            free_securityStateRef(pdu);
4473
179
        }
4474
4475
        /* Implement RFC5343 here for two reasons:
4476
           1) From a security perspective it handles this otherwise
4477
              always approved request earlier.  It bypasses the need
4478
              for authorization to the snmpEngineID scalar, which is
4479
              what is what RFC3415 appendix A species as ok.  Note
4480
              that we haven't bypassed authentication since if there
4481
              was an authentication error it would have been handled
4482
              above in the if(result) part at the latest.
4483
           2) From an application point of view if we let this request
4484
              get all the way to the application, it'd require that
4485
              all application types supporting discovery also fire up
4486
              a minimal agent in order to handle just this request
4487
              which seems like overkill.  Though there is no other
4488
              application types that currently need discovery (NRs
4489
              accept notifications from contextEngineIDs that derive
4490
              from the NO not the NR).  Also a lame excuse for doing
4491
              it here.
4492
           3) Less important technically, but the net-snmp agent
4493
              doesn't currently handle registrations of different
4494
              engineIDs either and it would have been a lot more work
4495
              to implement there since we'd need to support that
4496
              first. :-/ Supporting multiple context engineIDs should
4497
              be done anyway, so it's not a valid excuse here.
4498
           4) There is a lot less to do if we trump the agent at this
4499
              point; IE, the agent does a lot more unnecessary
4500
              processing when the only thing that should ever be in
4501
              this context by definition is the single scalar.
4502
        */
4503
4504
        /* special RFC5343 engineID discovery engineID check */
4505
179
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
4506
179
                                    NETSNMP_DS_LIB_NO_DISCOVERY) &&
4507
179
            SNMP_MSG_RESPONSE       != pdu->command &&
4508
179
            NULL                    != pdu->contextEngineID &&
4509
179
            pdu->contextEngineIDLen == 5 &&
4510
179
            pdu->contextEngineID[0] == 0x80 &&
4511
179
            pdu->contextEngineID[1] == 0x00 &&
4512
179
            pdu->contextEngineID[2] == 0x00 &&
4513
179
            pdu->contextEngineID[3] == 0x00 &&
4514
179
            pdu->contextEngineID[4] == 0x06) {
4515
4516
            /* define a result so it doesn't get past us at this point
4517
               and gets dropped by future parts of the stack */
4518
0
            result = SNMPERR_JUST_A_CONTEXT_PROBE;
4519
4520
0
            DEBUGMSGTL(("snmpv3_contextid", "starting context ID discovery\n"));
4521
            /* ensure exactly one variable */
4522
0
            if (NULL != pdu->variables &&
4523
0
                NULL == pdu->variables->next_variable &&
4524
4525
                /* if it's a GET, match it exactly */
4526
0
                ((SNMP_MSG_GET == pdu->command &&
4527
0
                  snmp_oid_compare(snmpEngineIDoid,
4528
0
                                   snmpEngineIDoid_len,
4529
0
                                   pdu->variables->name,
4530
0
                                   pdu->variables->name_length) == 0)
4531
                 /* if it's a GETNEXT ensure it's less than the engineID oid */
4532
0
                 ||
4533
0
                 (SNMP_MSG_GETNEXT == pdu->command &&
4534
0
                  snmp_oid_compare(snmpEngineIDoid,
4535
0
                                   snmpEngineIDoid_len,
4536
0
                                   pdu->variables->name,
4537
0
                                   pdu->variables->name_length) > 0)
4538
0
                    )) {
4539
4540
0
                DEBUGMSGTL(("snmpv3_contextid",
4541
0
                            "  One correct variable found\n"));
4542
4543
                /* Note: we're explicitly not handling a GETBULK.  Deal. */
4544
4545
                /* set up the response */
4546
0
                pdu2 = snmp_clone_pdu(pdu);
4547
4548
                /* free the current varbind */
4549
0
                snmp_free_varbind(pdu2->variables);
4550
4551
                /* set the variables */
4552
0
                pdu2->variables = NULL;
4553
0
                pdu2->command = SNMP_MSG_RESPONSE;
4554
0
                pdu2->errstat = 0;
4555
0
                pdu2->errindex = 0;
4556
4557
0
                ourEngineID_len =
4558
0
                    snmpv3_get_engineID((u_char*)ourEngineID, ourEngineID_len);
4559
0
                if (0 != ourEngineID_len) {
4560
4561
0
                    DEBUGMSGTL(("snmpv3_contextid",
4562
0
                                "  responding with our engineID\n"));
4563
4564
0
                    snmp_pdu_add_variable(pdu2,
4565
0
                                          snmpEngineIDoid, snmpEngineIDoid_len,
4566
0
                                          ASN_OCTET_STR,
4567
0
                                          ourEngineID, ourEngineID_len);
4568
                    
4569
                    /* send the response */
4570
0
                    if (0 == snmp_sess_send(slp, pdu2)) {
4571
4572
0
                        DEBUGMSGTL(("snmpv3_contextid",
4573
0
                                    "  sent it off!\n"));
4574
4575
0
                        snmp_free_pdu(pdu2);
4576
                        
4577
0
                        snmp_log(LOG_ERR, "sending a response to the context engineID probe failed\n");
4578
0
                    }
4579
0
                } else {
4580
0
                    snmp_log(LOG_ERR, "failed to get our own engineID!\n");
4581
0
                }
4582
0
            } else {
4583
0
                snmp_log(LOG_WARNING,
4584
0
                         "received an odd context engineID probe\n");
4585
0
            }
4586
0
        }
4587
4588
179
        break;
4589
17
    case SNMPERR_BAD_VERSION:
4590
17
        ERROR_MSG("error parsing snmp message version");
4591
17
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4592
17
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
4593
17
        break;
4594
4595
49
        unsupported_version:  /* goto label */
4596
50
    case SNMP_VERSION_sec:
4597
50
    case SNMP_VERSION_2u:
4598
51
    case SNMP_VERSION_2star:
4599
51
    case SNMP_VERSION_2p:
4600
456
    default:
4601
456
        ERROR_MSG("unsupported snmp message version");
4602
456
        snmp_increment_statistic(STAT_SNMPINBADVERSIONS);
4603
4604
        /*
4605
         * need better way to determine OS independent
4606
         * INT32_MAX value, for now hardcode
4607
         */
4608
456
        if (pdu->version < 0 || pdu->version > 2147483647) {
4609
115
            snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4610
115
        }
4611
456
        session->s_snmp_errno = SNMPERR_BAD_VERSION;
4612
456
        break;
4613
6.29k
    }
4614
4615
3.64k
    return result;
4616
6.29k
}
4617
4618
/**
4619
 * Parse a PDU.
4620
 * @param slp    [in]  Session pointer (struct session_list).
4621
 * @param pss    [in]  Session pointer (netsnmp_session).
4622
 * @param pdu    [out] Parsed PDU.
4623
 * @param data   [in]  PDU to parse.
4624
 * @param length [in]  Length of data.
4625
 *
4626
 * @returns 0 upon success; -1 upon failure.
4627
 */
4628
int
4629
snmp_parse(struct session_list *slp, netsnmp_session *pss,
4630
           netsnmp_pdu *pdu, u_char *data, size_t length)
4631
6.29k
{
4632
6.29k
    int             rc;
4633
4634
6.29k
    rc = _snmp_parse(slp, pss, pdu, data, length);
4635
6.29k
    if (rc) {
4636
6.06k
        if (!pss->s_snmp_errno) {
4637
5.09k
            pss->s_snmp_errno = SNMPERR_BAD_PARSE;
4638
5.09k
        }
4639
6.06k
        SET_SNMP_ERROR(pss->s_snmp_errno);
4640
6.06k
    }
4641
4642
6.29k
    return rc;
4643
6.29k
}
4644
4645
int
4646
snmp_pdu_parse(netsnmp_pdu *pdu, u_char * data, size_t * length)
4647
16.5k
{
4648
16.5k
    u_char          type;
4649
16.5k
    u_char          msg_type;
4650
16.5k
    u_char         *var_val;
4651
16.5k
    size_t          len;
4652
16.5k
    size_t          four;
4653
16.5k
    netsnmp_variable_list *vp = NULL, *vplast = NULL;
4654
16.5k
    oid             objid[MAX_OID_LEN];
4655
16.5k
    u_char         *p;
4656
4657
    /*
4658
     * Get the PDU type 
4659
     */
4660
16.5k
    data = asn_parse_header(data, length, &msg_type);
4661
16.5k
    if (data == NULL)
4662
7.54k
        return -1;
4663
9.01k
    DEBUGMSGTL(("dumpv_recv","    Command %s\n", snmp_pdu_type(msg_type)));
4664
9.01k
    pdu->command = msg_type;
4665
9.01k
    pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
4666
4667
    /*
4668
     * get the fields in the PDU preceding the variable-bindings sequence
4669
     */
4670
9.01k
    switch (pdu->command) {
4671
3.24k
    case SNMP_MSG_TRAP:
4672
        /*
4673
         * enterprise 
4674
         */
4675
3.24k
        pdu->enterprise_length = MAX_OID_LEN;
4676
3.24k
        data = asn_parse_objid(data, length, &type, objid,
4677
3.24k
                               &pdu->enterprise_length);
4678
3.24k
        if (data == NULL)
4679
715
            return -1;
4680
2.52k
        pdu->enterprise = netsnmp_memdup(objid,
4681
2.52k
                                         pdu->enterprise_length * sizeof(oid));
4682
2.52k
        if (pdu->enterprise == NULL) {
4683
0
            return -1;
4684
0
        }
4685
4686
        /*
4687
         * agent-addr 
4688
         */
4689
2.52k
        four = 4;
4690
2.52k
        data = asn_parse_string(data, length, &type,
4691
2.52k
                                (u_char *) pdu->agent_addr, &four);
4692
2.52k
        if (data == NULL)
4693
625
            return -1;
4694
4695
        /*
4696
         * generic trap 
4697
         */
4698
1.90k
        data = asn_parse_int(data, length, &type, (long *) &pdu->trap_type,
4699
1.90k
                             sizeof(pdu->trap_type));
4700
1.90k
        if (data == NULL)
4701
82
            return -1;
4702
        /*
4703
         * specific trap 
4704
         */
4705
1.82k
        data =
4706
1.82k
            asn_parse_int(data, length, &type,
4707
1.82k
                          (long *) &pdu->specific_type,
4708
1.82k
                          sizeof(pdu->specific_type));
4709
1.82k
        if (data == NULL)
4710
37
            return -1;
4711
4712
        /*
4713
         * timestamp  
4714
         */
4715
1.78k
        data = asn_parse_unsigned_int(data, length, &type, &pdu->time,
4716
1.78k
                                      sizeof(pdu->time));
4717
1.78k
        if (data == NULL)
4718
743
            return -1;
4719
4720
1.04k
        break;
4721
4722
1.04k
    case SNMP_MSG_RESPONSE:
4723
575
    case SNMP_MSG_REPORT:
4724
575
        pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
4725
575
        NETSNMP_FALLTHROUGH;
4726
4727
936
    case SNMP_MSG_TRAP2:
4728
1.28k
    case SNMP_MSG_INFORM:
4729
1.28k
#ifndef NETSNMP_NOTIFY_ONLY
4730
1.64k
    case SNMP_MSG_GET:
4731
1.99k
    case SNMP_MSG_GETNEXT:
4732
2.92k
    case SNMP_MSG_GETBULK:
4733
2.92k
#endif /* ! NETSNMP_NOTIFY_ONLY */
4734
2.92k
#ifndef NETSNMP_NO_WRITE_SUPPORT
4735
3.58k
    case SNMP_MSG_SET:
4736
3.58k
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
4737
        /*
4738
         * PDU is not an SNMPv1 TRAP 
4739
         */
4740
4741
        /*
4742
         * request id 
4743
         */
4744
3.58k
        DEBUGDUMPHEADER("recv", "request_id");
4745
3.58k
        data = asn_parse_int(data, length, &type, &pdu->reqid,
4746
3.58k
                             sizeof(pdu->reqid));
4747
3.58k
        DEBUGINDENTLESS();
4748
3.58k
        if (data == NULL) {
4749
307
            return -1;
4750
307
        }
4751
4752
        /*
4753
         * error status (getbulk non-repeaters) 
4754
         */
4755
3.27k
        DEBUGDUMPHEADER("recv", "error status");
4756
3.27k
        data = asn_parse_int(data, length, &type, &pdu->errstat,
4757
3.27k
                             sizeof(pdu->errstat));
4758
3.27k
        DEBUGINDENTLESS();
4759
3.27k
        if (data == NULL) {
4760
239
            return -1;
4761
239
        }
4762
4763
        /*
4764
         * error index (getbulk max-repetitions) 
4765
         */
4766
3.03k
        DEBUGDUMPHEADER("recv", "error index");
4767
3.03k
        data = asn_parse_int(data, length, &type, &pdu->errindex,
4768
3.03k
                             sizeof(pdu->errindex));
4769
3.03k
        DEBUGINDENTLESS();
4770
3.03k
        if (data == NULL) {
4771
177
            return -1;
4772
177
        }
4773
2.85k
  break;
4774
4775
2.85k
    default:
4776
2.19k
        snmp_log(LOG_ERR, "Bad PDU type received: 0x%.2x\n", pdu->command);
4777
2.19k
        snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
4778
2.19k
        return -1;
4779
9.01k
    }
4780
4781
    /*
4782
     * get header for variable-bindings sequence 
4783
     */
4784
3.89k
    DEBUGDUMPSECTION("recv", "VarBindList");
4785
3.89k
    data = asn_parse_sequence(data, length, &type,
4786
3.89k
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
4787
3.89k
                              "varbinds");
4788
3.89k
    if (data == NULL)
4789
556
        goto fail;
4790
4791
    /*
4792
     * get each varBind sequence 
4793
     */
4794
33.5k
    while ((int) *length > 0) {
4795
32.9k
        vp = SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
4796
32.9k
        if (NULL == vp)
4797
0
            goto fail;
4798
4799
32.9k
        vp->name_length = MAX_OID_LEN;
4800
32.9k
        DEBUGDUMPSECTION("recv", "VarBind");
4801
32.9k
        data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
4802
32.9k
                                 &vp->val_len, &var_val, length);
4803
32.9k
        if (data == NULL)
4804
1.92k
            goto fail;
4805
30.9k
        if (snmp_set_var_objid(vp, objid, vp->name_length))
4806
0
            goto fail;
4807
4808
30.9k
        len = SNMP_MAX_PACKET_LEN;
4809
30.9k
        DEBUGDUMPHEADER("recv", "Value");
4810
30.9k
        switch ((short) vp->type) {
4811
1.96k
        case ASN_INTEGER:
4812
1.96k
            vp->val.integer = (long *) vp->buf;
4813
1.96k
            vp->val_len = sizeof(long);
4814
1.96k
            p = asn_parse_int(var_val, &len, &vp->type,
4815
1.96k
                          (long *) vp->val.integer,
4816
1.96k
                          sizeof(*vp->val.integer));
4817
1.96k
            if (!p)
4818
26
                goto fail;
4819
1.93k
            break;
4820
1.93k
        case ASN_COUNTER:
4821
2.60k
        case ASN_GAUGE:
4822
3.71k
        case ASN_TIMETICKS:
4823
5.04k
        case ASN_UINTEGER:
4824
5.04k
            vp->val.integer = (long *) vp->buf;
4825
5.04k
            vp->val_len = sizeof(u_long);
4826
5.04k
            p = asn_parse_unsigned_int(var_val, &len, &vp->type,
4827
5.04k
                                   (u_long *) vp->val.integer,
4828
5.04k
                                   vp->val_len);
4829
5.04k
            if (!p)
4830
97
                goto fail;
4831
4.95k
            break;
4832
4.95k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
4833
4.95k
        case ASN_OPAQUE_COUNTER64:
4834
2.03k
        case ASN_OPAQUE_U64:
4835
2.03k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
4836
4.77k
        case ASN_COUNTER64:
4837
4.77k
            vp->val.counter64 = (struct counter64 *) vp->buf;
4838
4.77k
            vp->val_len = sizeof(struct counter64);
4839
4.77k
            p = asn_parse_unsigned_int64(var_val, &len, &vp->type,
4840
4.77k
                                     (struct counter64 *) vp->val.
4841
4.77k
                                     counter64, vp->val_len);
4842
4.77k
            if (!p)
4843
145
                goto fail;
4844
4.62k
            break;
4845
4.62k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
4846
4.62k
        case ASN_OPAQUE_FLOAT:
4847
1.47k
            vp->val.floatVal = (float *) vp->buf;
4848
1.47k
            vp->val_len = sizeof(float);
4849
1.47k
            p = asn_parse_float(var_val, &len, &vp->type,
4850
1.47k
                            vp->val.floatVal, vp->val_len);
4851
1.47k
            if (!p)
4852
115
                goto fail;
4853
1.36k
            break;
4854
1.53k
        case ASN_OPAQUE_DOUBLE:
4855
1.53k
            vp->val.doubleVal = (double *) vp->buf;
4856
1.53k
            vp->val_len = sizeof(double);
4857
1.53k
            p = asn_parse_double(var_val, &len, &vp->type,
4858
1.53k
                             vp->val.doubleVal, vp->val_len);
4859
1.53k
            if (!p)
4860
145
                goto fail;
4861
1.38k
            break;
4862
2.90k
        case ASN_OPAQUE_I64:
4863
2.90k
            vp->val.counter64 = (struct counter64 *) vp->buf;
4864
2.90k
            vp->val_len = sizeof(struct counter64);
4865
2.90k
            p = asn_parse_signed_int64(var_val, &len, &vp->type,
4866
2.90k
                                   (struct counter64 *) vp->val.counter64,
4867
2.90k
                                   sizeof(*vp->val.counter64));
4868
4869
2.90k
            if (!p)
4870
156
                goto fail;
4871
2.74k
            break;
4872
2.74k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
4873
2.74k
        case ASN_IPADDRESS:
4874
623
            if (vp->val_len != 4)
4875
49
                goto fail;
4876
623
            NETSNMP_FALLTHROUGH;
4877
1.84k
        case ASN_OCTET_STR:
4878
3.99k
        case ASN_OPAQUE:
4879
5.54k
        case ASN_NSAP:
4880
5.54k
            if (vp->val_len < sizeof(vp->buf)) {
4881
5.11k
                vp->val.string = (u_char *) vp->buf;
4882
5.11k
            } else {
4883
430
                vp->val.string = (u_char *) malloc(vp->val_len);
4884
430
            }
4885
5.54k
            if (vp->val.string == NULL) {
4886
0
                goto fail;
4887
0
            }
4888
5.54k
            p = asn_parse_string(var_val, &len, &vp->type, vp->val.string,
4889
5.54k
                             &vp->val_len);
4890
5.54k
            if (!p)
4891
0
                goto fail;
4892
5.54k
            break;
4893
5.54k
        case ASN_OBJECT_ID:
4894
2.23k
            vp->val_len = MAX_OID_LEN;
4895
2.23k
            p = asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
4896
2.23k
            if (!p)
4897
19
                goto fail;
4898
2.22k
            vp->val_len *= sizeof(oid);
4899
2.22k
            vp->val.objid = netsnmp_memdup(objid, vp->val_len);
4900
2.22k
            if (vp->val.objid == NULL)
4901
0
                goto fail;
4902
2.22k
            break;
4903
2.22k
        case SNMP_NOSUCHOBJECT:
4904
2.22k
        case SNMP_NOSUCHINSTANCE:
4905
3.14k
        case SNMP_ENDOFMIBVIEW:
4906
3.94k
        case ASN_NULL:
4907
3.94k
            break;
4908
1.46k
        case ASN_BIT_STR:
4909
1.46k
            vp->val.bitstring = (u_char *) malloc(vp->val_len);
4910
1.46k
            if (vp->val.bitstring == NULL) {
4911
0
                goto fail;
4912
0
            }
4913
1.46k
            p = asn_parse_bitstring(var_val, &len, &vp->type,
4914
1.46k
                                vp->val.bitstring, &vp->val_len);
4915
1.46k
            if (!p)
4916
21
                goto fail;
4917
1.44k
            break;
4918
1.44k
        default:
4919
47
            snmp_log(LOG_ERR, "bad type returned (%x)\n", vp->type);
4920
47
            goto fail;
4921
0
            break;
4922
30.9k
        }
4923
30.1k
        DEBUGINDENTADD(-4);
4924
4925
30.1k
        if (NULL == vplast) {
4926
2.54k
            pdu->variables = vp;
4927
27.6k
        } else {
4928
27.6k
            vplast->next_variable = vp;
4929
27.6k
        }
4930
30.1k
        vplast = vp;
4931
30.1k
        vp = NULL;
4932
30.1k
    }
4933
593
    return 0;
4934
4935
3.30k
  fail:
4936
3.30k
    {
4937
3.30k
        const char *errstr = snmp_api_errstring(SNMPERR_SUCCESS);
4938
3.30k
        DEBUGMSGTL(("recv", "error while parsing VarBindList:%s\n", errstr));
4939
3.30k
    }
4940
    /** if we were parsing a var, remove it from the pdu and free it */
4941
3.30k
    if (vp)
4942
2.74k
        snmp_free_var(vp);
4943
4944
3.30k
    return -1;
4945
3.34k
}
4946
4947
/*
4948
 * snmp v3 utility function to parse into the scopedPdu. stores contextName
4949
 * and contextEngineID in pdu struct. Also stores pdu->command (handy for 
4950
 * Report generation).
4951
 * 
4952
 * returns pointer to begining of PDU or NULL on error.
4953
 */
4954
u_char         *
4955
snmpv3_scopedPDU_parse(netsnmp_pdu *pdu, u_char * cp, size_t * length)
4956
481
{
4957
481
    u_char          tmp_buf[SNMP_MAX_MSG_SIZE];
4958
481
    size_t          tmp_buf_len;
4959
481
    u_char          type;
4960
481
    size_t          asn_len;
4961
481
    u_char         *data;
4962
4963
481
    pdu->command = 0;           /* initialize so we know if it got parsed */
4964
481
    asn_len = *length;
4965
481
    data = asn_parse_sequence(cp, &asn_len, &type,
4966
481
                              (ASN_SEQUENCE | ASN_CONSTRUCTOR),
4967
481
                              "plaintext scopedPDU");
4968
481
    if (data == NULL) {
4969
480
        return NULL;
4970
480
    }
4971
1
    *length -= data - cp;
4972
4973
    /*
4974
     * contextEngineID from scopedPdu  
4975
     */
4976
1
    DEBUGDUMPHEADER("recv", "contextEngineID");
4977
1
    data = asn_parse_string(data, length, &type, pdu->contextEngineID,
4978
1
                            &pdu->contextEngineIDLen);
4979
1
    DEBUGINDENTLESS();
4980
1
    if (data == NULL) {
4981
1
        ERROR_MSG("error parsing contextEngineID from scopedPdu");
4982
1
        return NULL;
4983
1
    }
4984
4985
    /*
4986
     * parse contextName from scopedPdu
4987
     */
4988
0
    tmp_buf_len = SNMP_MAX_CONTEXT_SIZE;
4989
0
    DEBUGDUMPHEADER("recv", "contextName");
4990
0
    data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
4991
0
    DEBUGINDENTLESS();
4992
0
    if (data == NULL) {
4993
0
        ERROR_MSG("error parsing contextName from scopedPdu");
4994
0
        return NULL;
4995
0
    }
4996
4997
0
    if (tmp_buf_len) {
4998
0
        pdu->contextName = netsnmp_memdup(tmp_buf, tmp_buf_len);
4999
0
        pdu->contextNameLen = tmp_buf_len;
5000
0
    } else {
5001
0
        pdu->contextName = strdup("");
5002
0
        pdu->contextNameLen = 0;
5003
0
    }
5004
0
    if (pdu->contextName == NULL) {
5005
0
        ERROR_MSG("error copying contextName from scopedPdu");
5006
0
        return NULL;
5007
0
    }
5008
5009
    /*
5010
     * Get the PDU type 
5011
     */
5012
0
    asn_len = *length;</