Coverage Report

Created: 2025-12-27 06:42

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