Coverage Report

Created: 2026-02-26 07:08

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