Coverage Report

Created: 2023-09-25 06:06

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