1 |
27 |
unneback |
//==========================================================================
|
2 |
|
|
//
|
3 |
|
|
// ./lib/current/src/snmp_api.c
|
4 |
|
|
//
|
5 |
|
|
//
|
6 |
|
|
//==========================================================================
|
7 |
|
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
8 |
|
|
// -------------------------------------------
|
9 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
10 |
|
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
11 |
|
|
//
|
12 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
13 |
|
|
// the terms of the GNU General Public License as published by the Free
|
14 |
|
|
// Software Foundation; either version 2 or (at your option) any later version.
|
15 |
|
|
//
|
16 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
17 |
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
18 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
19 |
|
|
// for more details.
|
20 |
|
|
//
|
21 |
|
|
// You should have received a copy of the GNU General Public License along
|
22 |
|
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
23 |
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
24 |
|
|
//
|
25 |
|
|
// As a special exception, if other files instantiate templates or use macros
|
26 |
|
|
// or inline functions from this file, or you compile this file and link it
|
27 |
|
|
// with other works to produce a work based on this file, this file does not
|
28 |
|
|
// by itself cause the resulting work to be covered by the GNU General Public
|
29 |
|
|
// License. However the source code for this file must still be made available
|
30 |
|
|
// in accordance with section (3) of the GNU General Public License.
|
31 |
|
|
//
|
32 |
|
|
// This exception does not invalidate any other reasons why a work based on
|
33 |
|
|
// this file might be covered by the GNU General Public License.
|
34 |
|
|
//
|
35 |
|
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
36 |
|
|
// at http://sources.redhat.com/ecos/ecos-license/
|
37 |
|
|
// -------------------------------------------
|
38 |
|
|
//####ECOSGPLCOPYRIGHTEND####
|
39 |
|
|
//####UCDSNMPCOPYRIGHTBEGIN####
|
40 |
|
|
//
|
41 |
|
|
// -------------------------------------------
|
42 |
|
|
//
|
43 |
|
|
// Portions of this software may have been derived from the UCD-SNMP
|
44 |
|
|
// project, <http://ucd-snmp.ucdavis.edu/> from the University of
|
45 |
|
|
// California at Davis, which was originally based on the Carnegie Mellon
|
46 |
|
|
// University SNMP implementation. Portions of this software are therefore
|
47 |
|
|
// covered by the appropriate copyright disclaimers included herein.
|
48 |
|
|
//
|
49 |
|
|
// The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
|
50 |
|
|
// -------------------------------------------
|
51 |
|
|
//
|
52 |
|
|
//####UCDSNMPCOPYRIGHTEND####
|
53 |
|
|
//==========================================================================
|
54 |
|
|
//#####DESCRIPTIONBEGIN####
|
55 |
|
|
//
|
56 |
|
|
// Author(s): hmt
|
57 |
|
|
// Contributors: hmt
|
58 |
|
|
// Date: 2000-05-30
|
59 |
|
|
// Purpose: Port of UCD-SNMP distribution to eCos.
|
60 |
|
|
// Description:
|
61 |
|
|
//
|
62 |
|
|
//
|
63 |
|
|
//####DESCRIPTIONEND####
|
64 |
|
|
//
|
65 |
|
|
//==========================================================================
|
66 |
|
|
/********************************************************************
|
67 |
|
|
Copyright 1989, 1991, 1992 by Carnegie Mellon University
|
68 |
|
|
|
69 |
|
|
Derivative Work -
|
70 |
|
|
Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
|
71 |
|
|
|
72 |
|
|
All Rights Reserved
|
73 |
|
|
|
74 |
|
|
Permission to use, copy, modify and distribute this software and its
|
75 |
|
|
documentation for any purpose and without fee is hereby granted,
|
76 |
|
|
provided that the above copyright notice appears in all copies and
|
77 |
|
|
that both that copyright notice and this permission notice appear in
|
78 |
|
|
supporting documentation, and that the name of CMU and The Regents of
|
79 |
|
|
the University of California not be used in advertising or publicity
|
80 |
|
|
pertaining to distribution of the software without specific written
|
81 |
|
|
permission.
|
82 |
|
|
|
83 |
|
|
CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
|
84 |
|
|
WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
|
85 |
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR
|
86 |
|
|
THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
|
87 |
|
|
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
88 |
|
|
FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
89 |
|
|
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
90 |
|
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
91 |
|
|
*********************************************************************/
|
92 |
|
|
/******************************************************************
|
93 |
|
|
Copyright 1989, 1991, 1992 by Carnegie Mellon University
|
94 |
|
|
|
95 |
|
|
All Rights Reserved
|
96 |
|
|
|
97 |
|
|
Permission to use, copy, modify, and distribute this software and its
|
98 |
|
|
documentation for any purpose and without fee is hereby granted,
|
99 |
|
|
provided that the above copyright notice appear in all copies and that
|
100 |
|
|
both that copyright notice and this permission notice appear in
|
101 |
|
|
supporting documentation, and that the name of CMU not be
|
102 |
|
|
used in advertising or publicity pertaining to distribution of the
|
103 |
|
|
software without specific, written prior permission.
|
104 |
|
|
|
105 |
|
|
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
106 |
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
107 |
|
|
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
108 |
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
109 |
|
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
110 |
|
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
111 |
|
|
SOFTWARE.
|
112 |
|
|
******************************************************************/
|
113 |
|
|
/*
|
114 |
|
|
* snmp_api.c - API for access to snmp.
|
115 |
|
|
*/
|
116 |
|
|
#include <config.h>
|
117 |
|
|
|
118 |
|
|
#include <stdio.h>
|
119 |
|
|
#include <ctype.h>
|
120 |
|
|
#if HAVE_STDLIB_H
|
121 |
|
|
#include <stdlib.h>
|
122 |
|
|
#endif
|
123 |
|
|
#if HAVE_STRING_H
|
124 |
|
|
#include <string.h>
|
125 |
|
|
#else
|
126 |
|
|
#include <strings.h>
|
127 |
|
|
#endif
|
128 |
|
|
#if HAVE_UNISTD_H
|
129 |
|
|
#include <unistd.h>
|
130 |
|
|
#endif
|
131 |
|
|
#include <sys/types.h>
|
132 |
|
|
#if HAVE_SYS_PARAM_H
|
133 |
|
|
#include <sys/param.h>
|
134 |
|
|
#endif
|
135 |
|
|
#if TIME_WITH_SYS_TIME
|
136 |
|
|
# ifdef WIN32
|
137 |
|
|
# include <sys/timeb.h>
|
138 |
|
|
# else
|
139 |
|
|
# include <sys/time.h>
|
140 |
|
|
# endif
|
141 |
|
|
# include <time.h>
|
142 |
|
|
#else
|
143 |
|
|
# if HAVE_SYS_TIME_H
|
144 |
|
|
# include <sys/time.h>
|
145 |
|
|
# else
|
146 |
|
|
# include <time.h>
|
147 |
|
|
# endif
|
148 |
|
|
#endif
|
149 |
|
|
#if HAVE_NETINET_IN_H
|
150 |
|
|
#include <netinet/in.h>
|
151 |
|
|
#endif
|
152 |
|
|
#if HAVE_ARPA_INET_H
|
153 |
|
|
#include <arpa/inet.h>
|
154 |
|
|
#endif
|
155 |
|
|
#if HAVE_SYS_SELECT_H
|
156 |
|
|
#include <sys/select.h>
|
157 |
|
|
#endif
|
158 |
|
|
#if HAVE_WINSOCK_H
|
159 |
|
|
#include <winsock.h>
|
160 |
|
|
#endif
|
161 |
|
|
#if HAVE_SYS_SOCKET_H
|
162 |
|
|
#include <sys/socket.h>
|
163 |
|
|
|
164 |
|
|
#ifdef __ECOS
|
165 |
|
|
# ifdef AF_UNIX
|
166 |
|
|
# undef AF_UNIX // eCos does not support local sockets
|
167 |
|
|
# endif // AF_UNIX
|
168 |
|
|
#endif // __ECOS
|
169 |
|
|
|
170 |
|
|
#endif
|
171 |
|
|
#if HAVE_SYS_UN_H
|
172 |
|
|
#include <sys/un.h>
|
173 |
|
|
#endif
|
174 |
|
|
#if HAVE_NETDB_H
|
175 |
|
|
#include <netdb.h>
|
176 |
|
|
#endif
|
177 |
|
|
#if HAVE_NET_IF_DL_H
|
178 |
|
|
#include <net/if_dl.h>
|
179 |
|
|
#endif
|
180 |
|
|
#include <errno.h>
|
181 |
|
|
|
182 |
|
|
#if HAVE_LOCALE_H
|
183 |
|
|
#include <locale.h>
|
184 |
|
|
#endif
|
185 |
|
|
|
186 |
|
|
#if HAVE_DMALLOC_H
|
187 |
|
|
#include <dmalloc.h>
|
188 |
|
|
#endif
|
189 |
|
|
|
190 |
|
|
#include "asn1.h"
|
191 |
|
|
#include "snmp.h"
|
192 |
|
|
#define SNMP_NEED_REQUEST_LIST
|
193 |
|
|
#include "snmp_api.h"
|
194 |
|
|
#include "snmp_client.h"
|
195 |
|
|
#include "snmp_impl.h"
|
196 |
|
|
#include "parse.h"
|
197 |
|
|
#include "mib.h"
|
198 |
|
|
#include "system.h"
|
199 |
|
|
#include "int64.h"
|
200 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
201 |
|
|
#include "snmpv3.h"
|
202 |
|
|
#endif
|
203 |
|
|
#include "read_config.h"
|
204 |
|
|
#include "snmp_debug.h"
|
205 |
|
|
#include "callback.h"
|
206 |
|
|
#include "tools.h"
|
207 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
208 |
|
|
#include "snmpusm.h"
|
209 |
|
|
#include "keytools.h"
|
210 |
|
|
#include "lcd_time.h"
|
211 |
|
|
#endif
|
212 |
|
|
#include "snmp_alarm.h"
|
213 |
|
|
#include "snmp_logging.h"
|
214 |
|
|
#include "default_store.h"
|
215 |
|
|
#include "mt_support.h"
|
216 |
|
|
|
217 |
|
|
static void _init_snmp (void);
|
218 |
|
|
|
219 |
|
|
#include "transform_oids.h"
|
220 |
|
|
#ifndef timercmp
|
221 |
|
|
#define timercmp(tvp, uvp, cmp) \
|
222 |
|
|
/* CSTYLED */ \
|
223 |
|
|
((tvp)->tv_sec cmp (uvp)->tv_sec || \
|
224 |
|
|
((tvp)->tv_sec == (uvp)->tv_sec && \
|
225 |
|
|
/* CSTYLED */ \
|
226 |
|
|
(tvp)->tv_usec cmp (uvp)->tv_usec))
|
227 |
|
|
#endif
|
228 |
|
|
#ifndef timerclear
|
229 |
|
|
#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
|
230 |
|
|
#endif
|
231 |
|
|
|
232 |
|
|
/*
|
233 |
|
|
* Globals.
|
234 |
|
|
*/
|
235 |
|
|
#define PACKET_LENGTH (8 * 1024)
|
236 |
|
|
#define MAX_PACKET_LENGTH (32768)
|
237 |
|
|
#ifndef SNMP_STREAM_QUEUE_LEN
|
238 |
|
|
#define SNMP_STREAM_QUEUE_LEN 5
|
239 |
|
|
#endif
|
240 |
|
|
|
241 |
|
|
#ifndef BSD4_3
|
242 |
|
|
#define BSD4_2
|
243 |
|
|
#endif
|
244 |
|
|
|
245 |
|
|
#ifndef FD_SET
|
246 |
|
|
|
247 |
|
|
typedef long fd_mask;
|
248 |
|
|
#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */
|
249 |
|
|
|
250 |
|
|
#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
|
251 |
|
|
#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
|
252 |
|
|
#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
|
253 |
|
|
#define FD_ZERO(p) memset((p), 0, sizeof(*(p)))
|
254 |
|
|
#endif
|
255 |
|
|
|
256 |
|
|
static oid default_enterprise[] = {1, 3, 6, 1, 4, 1, 3, 1, 1};
|
257 |
|
|
/* enterprises.cmu.systems.cmuSNMP */
|
258 |
|
|
|
259 |
|
|
#define DEFAULT_COMMUNITY "public"
|
260 |
|
|
#define DEFAULT_RETRIES 5
|
261 |
|
|
#define DEFAULT_TIMEOUT 1000000L
|
262 |
|
|
#define DEFAULT_REMPORT SNMP_PORT
|
263 |
|
|
#define DEFAULT_ENTERPRISE default_enterprise
|
264 |
|
|
#define DEFAULT_TIME 0
|
265 |
|
|
|
266 |
|
|
/*
|
267 |
|
|
* Internal information about the state of the snmp session.
|
268 |
|
|
*/
|
269 |
|
|
struct snmp_internal_session {
|
270 |
|
|
int sd; /* socket descriptor for this connection */
|
271 |
|
|
snmp_ipaddr addr; /* address of connected peer */
|
272 |
|
|
snmp_ipaddr me; /* address of local socket */
|
273 |
|
|
struct request_list *requests;/* Info about outstanding requests */
|
274 |
|
|
struct request_list *requestsEnd; /* ptr to end of list */
|
275 |
|
|
int (*hook_pre) ( struct snmp_session*, snmp_ipaddr);
|
276 |
|
|
int (*hook_parse)( struct snmp_session *, struct snmp_pdu *, u_char *, size_t);
|
277 |
|
|
int (*hook_post) ( struct snmp_session*, struct snmp_pdu*, int );
|
278 |
|
|
int (*hook_build)( struct snmp_session *, struct snmp_pdu *, u_char *, size_t *);
|
279 |
|
|
int (*check_packet) ( u_char *, size_t );
|
280 |
|
|
u_char *packet;
|
281 |
|
|
long packet_len, proper_len;
|
282 |
|
|
size_t packet_size;
|
283 |
|
|
char newpkt;
|
284 |
|
|
};
|
285 |
|
|
|
286 |
|
|
/*
|
287 |
|
|
* The list of active/open sessions.
|
288 |
|
|
*/
|
289 |
|
|
struct session_list {
|
290 |
|
|
struct session_list *next;
|
291 |
|
|
struct snmp_session *session;
|
292 |
|
|
struct snmp_internal_session *internal;
|
293 |
|
|
};
|
294 |
|
|
|
295 |
|
|
|
296 |
|
|
|
297 |
|
|
static const char *api_errors[-SNMPERR_MAX+1] = {
|
298 |
|
|
"No error", /* SNMPERR_SUCCESS */
|
299 |
|
|
"Generic error", /* SNMPERR_GENERR */
|
300 |
|
|
"Invalid local port", /* SNMPERR_BAD_LOCPORT */
|
301 |
|
|
"Unknown host", /* SNMPERR_BAD_ADDRESS */
|
302 |
|
|
"Unknown session", /* SNMPERR_BAD_SESSION */
|
303 |
|
|
"Too long", /* SNMPERR_TOO_LONG */
|
304 |
|
|
"No socket", /* SNMPERR_NO_SOCKET */
|
305 |
|
|
"Cannot send V2 PDU on V1 session", /* SNMPERR_V2_IN_V1 */
|
306 |
|
|
"Cannot send V1 PDU on V2 session", /* SNMPERR_V1_IN_V2 */
|
307 |
|
|
"Bad value for non-repeaters", /* SNMPERR_BAD_REPEATERS */
|
308 |
|
|
"Bad value for max-repetitions", /* SNMPERR_BAD_REPETITIONS */
|
309 |
|
|
"Error building ASN.1 representation", /* SNMPERR_BAD_ASN1_BUILD */
|
310 |
|
|
"Failure in sendto", /* SNMPERR_BAD_SENDTO */
|
311 |
|
|
"Bad parse of ASN.1 type", /* SNMPERR_BAD_PARSE */
|
312 |
|
|
"Bad version specified", /* SNMPERR_BAD_VERSION */
|
313 |
|
|
"Bad source party specified", /* SNMPERR_BAD_SRC_PARTY */
|
314 |
|
|
"Bad destination party specified", /* SNMPERR_BAD_DST_PARTY */
|
315 |
|
|
"Bad context specified", /* SNMPERR_BAD_CONTEXT */
|
316 |
|
|
"Bad community specified", /* SNMPERR_BAD_COMMUNITY */
|
317 |
|
|
"Cannot send noAuth/desPriv", /* SNMPERR_NOAUTH_DESPRIV */
|
318 |
|
|
"Bad ACL definition", /* SNMPERR_BAD_ACL */
|
319 |
|
|
"Bad Party definition", /* SNMPERR_BAD_PARTY */
|
320 |
|
|
"Session abort failure", /* SNMPERR_ABORT */
|
321 |
|
|
"Unknown PDU type", /* SNMPERR_UNKNOWN_PDU */
|
322 |
|
|
"Timeout", /* SNMPERR_TIMEOUT */
|
323 |
|
|
"Failure in recvfrom", /* SNMPERR_BAD_RECVFROM */
|
324 |
|
|
"Unable to determine contextEngineID", /* SNMPERR_BAD_ENG_ID */
|
325 |
|
|
"Unable to determine securityName", /* SNMPERR_BAD_SEC_NAME */
|
326 |
|
|
"Unable to determine securityLevel", /* SNMPERR_BAD_SEC_LEVEL */
|
327 |
|
|
"ASN.1 parse error in message", /* SNMPERR_ASN_PARSE_ERR */
|
328 |
|
|
"Unknown security model in message", /* SNMPERR_UNKNOWN_SEC_MODEL */
|
329 |
|
|
"Invalid message (e.g. msgFlags)", /* SNMPERR_INVALID_MSG */
|
330 |
|
|
"Unknown engine ID", /* SNMPERR_UNKNOWN_ENG_ID */
|
331 |
|
|
"Unknown user name", /* SNMPERR_UNKNOWN_USER_NAME */
|
332 |
|
|
"Unsupported security level", /* SNMPERR_UNSUPPORTED_SEC_LEVEL */
|
333 |
|
|
"Authentication failure", /* SNMPERR_AUTHENTICATION_FAILURE */
|
334 |
|
|
"Not in time window", /* SNMPERR_NOT_IN_TIME_WINDOW */
|
335 |
|
|
"Decryption error", /* SNMPERR_DECRYPTION_ERR */
|
336 |
|
|
"SCAPI general failure", /* SNMPERR_SC_GENERAL_FAILURE */
|
337 |
|
|
"SCAPI sub-system not configured", /* SNMPERR_SC_NOT_CONFIGURED */
|
338 |
|
|
"Key tools not available", /* SNMPERR_KT_NOT_AVAILABLE */
|
339 |
|
|
"Unknown Report message", /* SNMPERR_UNKNOWN_REPORT */
|
340 |
|
|
"USM generic error", /* SNMPERR_USM_GENERICERROR */
|
341 |
|
|
"USM unknown security name", /* SNMPERR_USM_UNKNOWNSECURITYNAME */
|
342 |
|
|
"USM unsupported security level", /* SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL */
|
343 |
|
|
"USM encryption error", /* SNMPERR_USM_ENCRYPTIONERROR */
|
344 |
|
|
"USM authentication failure", /* SNMPERR_USM_AUTHENTICATIONFAILURE */
|
345 |
|
|
"USM parse error", /* SNMPERR_USM_PARSEERROR */
|
346 |
|
|
"USM unknown engineID", /* SNMPERR_USM_UNKNOWNENGINEID */
|
347 |
|
|
"USM not in time window", /* SNMPERR_USM_NOTINTIMEWINDOW */
|
348 |
|
|
"USM decryption error", /* SNMPERR_USM_DECRYPTIONERROR */
|
349 |
|
|
"MIB not initialized", /* SNMPERR_NOMIB */
|
350 |
|
|
"Value out of range", /* SNMPERR_RANGE */
|
351 |
|
|
"Sub-id out of range", /* SNMPERR_MAX_SUBID */
|
352 |
|
|
"Bad sub-id in object identifier", /* SNMPERR_BAD_SUBID */
|
353 |
|
|
"Object identifier too long", /* SNMPERR_LONG_OID */
|
354 |
|
|
"Bad value name", /* SNMPERR_BAD_NAME */
|
355 |
|
|
"Bad value notation", /* SNMPERR_VALUE */
|
356 |
|
|
"Unknown Object Identifier", /* SNMPERR_UNKNOWN_OBJID */
|
357 |
|
|
"No PDU in snmp_send", /* SNMPERR_NULL_PDU */
|
358 |
|
|
"Missing variables in PDU", /* SNMPERR_NO_VARS */
|
359 |
|
|
"Bad variable type", /* SNMPERR_VAR_TYPE */
|
360 |
|
|
"Out of memory (malloc failure)", /* SNMPERR_MALLOC */
|
361 |
|
|
};
|
362 |
|
|
|
363 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
364 |
|
|
static const char * usmSecLevelName[] =
|
365 |
|
|
{
|
366 |
|
|
"BAD_SEC_LEVEL",
|
367 |
|
|
"noAuthNoPriv",
|
368 |
|
|
"authNoPriv",
|
369 |
|
|
"authPriv"
|
370 |
|
|
};
|
371 |
|
|
#endif
|
372 |
|
|
|
373 |
|
|
/*
|
374 |
|
|
* Multiple threads may changes these variables.
|
375 |
|
|
* Suggest using the Single API, which does not use Sessions.
|
376 |
|
|
*
|
377 |
|
|
* Reqid may need to be protected. Time will tell...
|
378 |
|
|
*
|
379 |
|
|
*/
|
380 |
|
|
/*MTCRITICAL_RESOURCE*/
|
381 |
|
|
/* use token in comments to individually protect these resources */
|
382 |
|
|
struct session_list *Sessions = NULL; /* MT_LIB_SESSION */
|
383 |
|
|
static long Reqid = 0; /* MT_LIB_REQUESTID */
|
384 |
|
|
static long Msgid = 0; /* MT_LIB_MESSAGEID */
|
385 |
|
|
static long Sessid = 0; /* MT_LIB_SESSIONID */
|
386 |
|
|
static long Transid = 0; /* MT_LIB_TRANSID */
|
387 |
|
|
int snmp_errno = 0;
|
388 |
|
|
/*END MTCRITICAL_RESOURCE*/
|
389 |
|
|
|
390 |
|
|
/*struct timeval Now;*/
|
391 |
|
|
|
392 |
|
|
/*
|
393 |
|
|
* global error detail storage
|
394 |
|
|
*/
|
395 |
|
|
static char snmp_detail[192];
|
396 |
|
|
static int snmp_detail_f = 0;
|
397 |
|
|
|
398 |
|
|
/*
|
399 |
|
|
* Prototypes.
|
400 |
|
|
*/
|
401 |
|
|
int snmp_build (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *);
|
402 |
|
|
static int snmp_parse (void *, struct snmp_session *, struct snmp_pdu *, u_char *, size_t);
|
403 |
|
|
static void * snmp_sess_pointer (struct snmp_session *);
|
404 |
|
|
|
405 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
406 |
|
|
static void snmpv3_calc_msg_flags (int, int, u_char *);
|
407 |
|
|
static int snmpv3_verify_msg (struct request_list *, struct snmp_pdu *);
|
408 |
|
|
static int snmpv3_build_probe_pdu (struct snmp_pdu **);
|
409 |
|
|
static int snmpv3_build (struct snmp_session *, struct snmp_pdu *,
|
410 |
|
|
u_char *, size_t *);
|
411 |
|
|
#endif
|
412 |
|
|
|
413 |
|
|
static int snmp_parse_version (u_char *, size_t);
|
414 |
|
|
static int snmp_resend_request (struct session_list *slp,
|
415 |
|
|
struct request_list *rp,
|
416 |
|
|
int incr_retries);
|
417 |
|
|
|
418 |
|
|
#ifndef HAVE_STRERROR
|
419 |
|
|
const char *strerror(int err)
|
420 |
|
|
{
|
421 |
|
|
extern const char *sys_errlist[];
|
422 |
|
|
extern int sys_nerr;
|
423 |
|
|
|
424 |
|
|
if (err < 0 || err >= sys_nerr) return "Unknown error";
|
425 |
|
|
return sys_errlist[err];
|
426 |
|
|
}
|
427 |
|
|
#endif
|
428 |
|
|
|
429 |
|
|
|
430 |
|
|
long
|
431 |
|
|
snmp_get_next_reqid (void)
|
432 |
|
|
{
|
433 |
|
|
long retVal;
|
434 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
|
435 |
|
|
retVal = 1 + Reqid; /*MTCRITICAL_RESOURCE*/
|
436 |
|
|
if (!retVal) retVal = 2;
|
437 |
|
|
Reqid = retVal;
|
438 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_REQUESTID);
|
439 |
|
|
return retVal;
|
440 |
|
|
}
|
441 |
|
|
|
442 |
|
|
long
|
443 |
|
|
snmp_get_next_msgid (void)
|
444 |
|
|
{
|
445 |
|
|
long retVal;
|
446 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
|
447 |
|
|
retVal = 1 + Msgid; /*MTCRITICAL_RESOURCE*/
|
448 |
|
|
if (!retVal) retVal = 2;
|
449 |
|
|
Msgid = retVal;
|
450 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_MESSAGEID);
|
451 |
|
|
return retVal;
|
452 |
|
|
}
|
453 |
|
|
|
454 |
|
|
long
|
455 |
|
|
snmp_get_next_sessid (void)
|
456 |
|
|
{
|
457 |
|
|
long retVal;
|
458 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
|
459 |
|
|
retVal = 1 + Sessid; /*MTCRITICAL_RESOURCE*/
|
460 |
|
|
if (!retVal) retVal = 2;
|
461 |
|
|
Sessid = retVal;
|
462 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSIONID);
|
463 |
|
|
return retVal;
|
464 |
|
|
}
|
465 |
|
|
|
466 |
|
|
long
|
467 |
|
|
snmp_get_next_transid (void)
|
468 |
|
|
{
|
469 |
|
|
long retVal;
|
470 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_TRANSID);
|
471 |
|
|
retVal = 1 + Transid; /*MTCRITICAL_RESOURCE*/
|
472 |
|
|
if (!retVal) retVal = 2;
|
473 |
|
|
Transid = retVal;
|
474 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_TRANSID);
|
475 |
|
|
return retVal;
|
476 |
|
|
}
|
477 |
|
|
|
478 |
|
|
void
|
479 |
|
|
snmp_perror(const char *prog_string)
|
480 |
|
|
{
|
481 |
|
|
const char *str;
|
482 |
|
|
int xerr;
|
483 |
|
|
xerr = snmp_errno; /*MTCRITICAL_RESOURCE*/
|
484 |
|
|
str = snmp_api_errstring(xerr);
|
485 |
|
|
snmp_log(LOG_ERR,"%s: %s\n",prog_string, str);
|
486 |
|
|
}
|
487 |
|
|
|
488 |
|
|
void
|
489 |
|
|
snmp_set_detail(const char *detail_string)
|
490 |
|
|
{
|
491 |
|
|
if (detail_string != NULL) {
|
492 |
|
|
strncpy((char *)snmp_detail, detail_string, sizeof(snmp_detail));
|
493 |
|
|
snmp_detail[sizeof(snmp_detail)-1] = '\0';
|
494 |
|
|
snmp_detail_f = 1;
|
495 |
|
|
}
|
496 |
|
|
}
|
497 |
|
|
|
498 |
|
|
/* returns pointer to static data */
|
499 |
|
|
/* results not guaranteed in multi-threaded use */
|
500 |
|
|
const char *
|
501 |
|
|
snmp_api_errstring(int snmp_errnumber)
|
502 |
|
|
{
|
503 |
|
|
const char *msg = "";
|
504 |
|
|
static char msg_buf [256];
|
505 |
|
|
if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR){
|
506 |
|
|
msg = api_errors[-snmp_errnumber];
|
507 |
|
|
} else if (snmp_errnumber != SNMPERR_SUCCESS) {
|
508 |
|
|
msg = "Unknown Error";
|
509 |
|
|
}
|
510 |
|
|
if (snmp_detail_f) {
|
511 |
|
|
sprintf (msg_buf, "%s (%s)", msg, snmp_detail);
|
512 |
|
|
snmp_detail_f = 0;
|
513 |
|
|
}
|
514 |
|
|
else
|
515 |
|
|
strcpy(msg_buf,msg);
|
516 |
|
|
|
517 |
|
|
return (msg_buf);
|
518 |
|
|
}
|
519 |
|
|
|
520 |
|
|
/*
|
521 |
|
|
* snmp_error - return error data
|
522 |
|
|
* Inputs : address of errno, address of snmp_errno, address of string
|
523 |
|
|
* Caller must free the string returned after use.
|
524 |
|
|
*/
|
525 |
|
|
void
|
526 |
|
|
snmp_error(struct snmp_session *psess,
|
527 |
|
|
int *p_errno,
|
528 |
|
|
int *p_snmp_errno,
|
529 |
|
|
char **p_str)
|
530 |
|
|
{
|
531 |
|
|
char buf[SPRINT_MAX_LEN];
|
532 |
|
|
int snmp_errnumber;
|
533 |
|
|
|
534 |
|
|
if (p_errno) *p_errno = psess->s_errno;
|
535 |
|
|
if (p_snmp_errno) *p_snmp_errno = psess->s_snmp_errno;
|
536 |
|
|
if (p_str == NULL) return;
|
537 |
|
|
|
538 |
|
|
strcpy(buf, "");
|
539 |
|
|
snmp_errnumber = psess->s_snmp_errno;
|
540 |
|
|
if (snmp_errnumber >= SNMPERR_MAX && snmp_errnumber <= SNMPERR_GENERR){
|
541 |
|
|
strcpy(buf, api_errors[-snmp_errnumber]);
|
542 |
|
|
} else {
|
543 |
|
|
if (snmp_errnumber)
|
544 |
|
|
sprintf(buf, "Unknown Error %d", snmp_errnumber);
|
545 |
|
|
}
|
546 |
|
|
|
547 |
|
|
/* append a useful system errno interpretation. */
|
548 |
|
|
if (psess->s_errno)
|
549 |
|
|
sprintf (&buf[strlen(buf)], " (%s)", strerror(psess->s_errno));
|
550 |
|
|
*p_str = strdup(buf);
|
551 |
|
|
}
|
552 |
|
|
|
553 |
|
|
/*
|
554 |
|
|
* snmp_sess_error - same as snmp_error for single session API use.
|
555 |
|
|
*/
|
556 |
|
|
void
|
557 |
|
|
snmp_sess_error(void *sessp,
|
558 |
|
|
int *p_errno,
|
559 |
|
|
int *p_snmp_errno,
|
560 |
|
|
char **p_str)
|
561 |
|
|
{
|
562 |
|
|
struct session_list *slp = (struct session_list*)sessp;
|
563 |
|
|
|
564 |
|
|
if ((slp) && (slp->session))
|
565 |
|
|
snmp_error(slp->session, p_errno, p_snmp_errno, p_str);
|
566 |
|
|
}
|
567 |
|
|
|
568 |
|
|
/* snmp_sess_perror(): print a error stored in a session pointer */
|
569 |
|
|
void
|
570 |
|
|
snmp_sess_perror(const char *prog_string, struct snmp_session *ss) {
|
571 |
|
|
char *err;
|
572 |
|
|
snmp_error(ss, NULL, NULL, &err);
|
573 |
|
|
snmp_log(LOG_ERR, "%s: %s\n", prog_string, err);
|
574 |
|
|
free(err);
|
575 |
|
|
}
|
576 |
|
|
|
577 |
|
|
|
578 |
|
|
/*
|
579 |
|
|
* Primordial SNMP library initialization.
|
580 |
|
|
* Initializes mutex locks.
|
581 |
|
|
* Invokes minimum required initialization for displaying MIB objects.
|
582 |
|
|
* Gets initial request ID for all transactions,
|
583 |
|
|
* and finds which port SNMP over UDP uses.
|
584 |
|
|
* SNMP over AppleTalk or IPX is not currently supported.
|
585 |
|
|
*
|
586 |
|
|
* Warning: no debug messages here.
|
587 |
|
|
*/
|
588 |
|
|
static void
|
589 |
|
|
_init_snmp (void)
|
590 |
|
|
{
|
591 |
|
|
#ifdef HAVE_GETSERVBYNAME
|
592 |
|
|
struct servent *servp;
|
593 |
|
|
#endif
|
594 |
|
|
|
595 |
|
|
struct timeval tv;
|
596 |
|
|
long tmpReqid, tmpMsgid;
|
597 |
|
|
u_short s_port = SNMP_PORT;
|
598 |
|
|
|
599 |
|
|
if (Reqid) return;
|
600 |
|
|
Reqid = 1; /* quick set to avoid multiple inits */
|
601 |
|
|
|
602 |
|
|
snmp_res_init(); /* initialize the mt locking structures */
|
603 |
|
|
init_mib_internals();
|
604 |
|
|
|
605 |
|
|
gettimeofday(&tv,(struct timezone *)0);
|
606 |
|
|
/*Now = tv;*/
|
607 |
|
|
|
608 |
|
|
/* get pseudo-random values for request ID and message ID */
|
609 |
|
|
/* don't allow zero value to repeat init */
|
610 |
|
|
#ifdef SVR4
|
611 |
|
|
srand48(tv.tv_sec ^ tv.tv_usec);
|
612 |
|
|
tmpReqid = lrand48();
|
613 |
|
|
tmpMsgid = lrand48();
|
614 |
|
|
#else
|
615 |
|
|
srandom(tv.tv_sec ^ tv.tv_usec);
|
616 |
|
|
tmpReqid = random();
|
617 |
|
|
tmpMsgid = random();
|
618 |
|
|
#endif
|
619 |
|
|
|
620 |
|
|
if (tmpReqid == 0) tmpReqid = 1;
|
621 |
|
|
if (tmpMsgid == 0) tmpMsgid = 1;
|
622 |
|
|
Reqid = tmpReqid;
|
623 |
|
|
Msgid = tmpMsgid;
|
624 |
|
|
|
625 |
|
|
#ifdef HAVE_GETSERVBYNAME
|
626 |
|
|
servp = getservbyname("snmp", "udp");
|
627 |
|
|
if (servp) {
|
628 |
|
|
/* store it in host byte order */
|
629 |
|
|
s_port = ntohs(servp->s_port);
|
630 |
|
|
}
|
631 |
|
|
#endif
|
632 |
|
|
ds_set_int(DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT, s_port);
|
633 |
|
|
}
|
634 |
|
|
|
635 |
|
|
/*
|
636 |
|
|
* Initializes the session structure.
|
637 |
|
|
* May perform one time minimal library initialization.
|
638 |
|
|
* No MIB file processing is done via this call.
|
639 |
|
|
*/
|
640 |
|
|
void
|
641 |
|
|
snmp_sess_init(struct snmp_session *session)
|
642 |
|
|
{
|
643 |
|
|
_init_snmp();
|
644 |
|
|
|
645 |
|
|
/* initialize session to default values */
|
646 |
|
|
|
647 |
|
|
memset(session, 0, sizeof(struct snmp_session));
|
648 |
|
|
session->remote_port = SNMP_DEFAULT_REMPORT;
|
649 |
|
|
session->timeout = SNMP_DEFAULT_TIMEOUT;
|
650 |
|
|
session->retries = SNMP_DEFAULT_RETRIES;
|
651 |
|
|
session->version = SNMP_DEFAULT_VERSION;
|
652 |
|
|
}
|
653 |
|
|
|
654 |
|
|
|
655 |
|
|
void
|
656 |
|
|
register_default_handlers(void) {
|
657 |
|
|
ds_register_config(ASN_BOOLEAN, "snmp","dumpPacket",
|
658 |
|
|
DS_LIBRARY_ID, DS_LIB_DUMP_PACKET);
|
659 |
|
|
ds_register_config(ASN_INTEGER, "snmp","defaultPort",
|
660 |
|
|
DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
|
661 |
|
|
ds_register_config(ASN_OCTET_STR, "snmp","defCommunity",
|
662 |
|
|
DS_LIBRARY_ID, DS_LIB_COMMUNITY);
|
663 |
|
|
ds_register_premib(ASN_BOOLEAN, "snmp", "noTokenWarnings",
|
664 |
|
|
DS_LIBRARY_ID, DS_LIB_NO_TOKEN_WARNINGS);
|
665 |
|
|
ds_register_config(ASN_OCTET_STR, "snmp","noRangeCheck",
|
666 |
|
|
DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE );
|
667 |
|
|
}
|
668 |
|
|
|
669 |
|
|
|
670 |
|
|
/*******************************************************************-o-******
|
671 |
|
|
* init_snmp
|
672 |
|
|
*
|
673 |
|
|
* Parameters:
|
674 |
|
|
* *type Label for the config file "type" used by calling entity.
|
675 |
|
|
*
|
676 |
|
|
* Call appropriately the functions to do config file loading and
|
677 |
|
|
* mib module parsing in the correct order.
|
678 |
|
|
*/
|
679 |
|
|
void
|
680 |
|
|
init_snmp(const char *type)
|
681 |
|
|
{
|
682 |
|
|
static int done_init = 0; /* To prevent double init's. */
|
683 |
|
|
|
684 |
|
|
if (done_init) {
|
685 |
|
|
return;
|
686 |
|
|
}
|
687 |
|
|
|
688 |
|
|
done_init = 1;
|
689 |
|
|
|
690 |
|
|
_init_snmp();
|
691 |
|
|
|
692 |
|
|
/* set our current locale properly to initialize isprint() type functions */
|
693 |
|
|
#ifdef HAVE_SETLOCALE
|
694 |
|
|
setlocale(LC_CTYPE, "");
|
695 |
|
|
#endif
|
696 |
|
|
|
697 |
|
|
snmp_debug_init(); /* should be done first, to turn on debugging ASAP */
|
698 |
|
|
if ( type != NULL )
|
699 |
|
|
ds_set_string(DS_LIBRARY_ID, DS_LIB_APPTYPE, type);
|
700 |
|
|
init_callbacks();
|
701 |
|
|
init_snmp_logging();
|
702 |
|
|
snmp_init_statistics();
|
703 |
|
|
register_mib_handlers();
|
704 |
|
|
register_default_handlers();
|
705 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
706 |
|
|
init_snmpv3(type);
|
707 |
|
|
#endif
|
708 |
|
|
init_snmp_alarm();
|
709 |
|
|
|
710 |
|
|
read_premib_configs();
|
711 |
|
|
init_mib();
|
712 |
|
|
|
713 |
|
|
read_configs();
|
714 |
|
|
|
715 |
|
|
} /* end init_snmp() */
|
716 |
|
|
|
717 |
|
|
void
|
718 |
|
|
snmp_store(const char *type) {
|
719 |
|
|
DEBUGMSGTL(("snmp_store","storing stuff...\n"));
|
720 |
|
|
snmp_save_persistent(type);
|
721 |
|
|
snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, NULL);
|
722 |
|
|
snmp_clean_persistent(type);
|
723 |
|
|
}
|
724 |
|
|
|
725 |
|
|
|
726 |
|
|
/* snmp_shutdown(const char *type):
|
727 |
|
|
|
728 |
|
|
Parameters:
|
729 |
|
|
*type Label for the config file "type" used by calling entity.
|
730 |
|
|
|
731 |
|
|
Does the appropriate shutdown calls for the library, saving
|
732 |
|
|
persistent data, clean up, etc...
|
733 |
|
|
*/
|
734 |
|
|
void
|
735 |
|
|
snmp_shutdown(const char *type) {
|
736 |
|
|
snmp_store(type);
|
737 |
|
|
snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN, NULL);
|
738 |
|
|
snmp_close_sessions();
|
739 |
|
|
}
|
740 |
|
|
|
741 |
|
|
|
742 |
|
|
/*
|
743 |
|
|
* Sets up the session with the snmp_session information provided
|
744 |
|
|
* by the user. Then opens and binds the necessary UDP port.
|
745 |
|
|
* A handle to the created session is returned (this is different than
|
746 |
|
|
* the pointer passed to snmp_open()). On any error, NULL is returned
|
747 |
|
|
* and snmp_errno is set to the appropriate error code.
|
748 |
|
|
*/
|
749 |
|
|
struct snmp_session *
|
750 |
|
|
snmp_open(struct snmp_session *session)
|
751 |
|
|
{
|
752 |
|
|
struct session_list *slp;
|
753 |
|
|
slp = (struct session_list *)snmp_sess_open(session);
|
754 |
|
|
if (!slp) return NULL;
|
755 |
|
|
|
756 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
757 |
|
|
slp->next = Sessions;
|
758 |
|
|
Sessions = slp;
|
759 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
760 |
|
|
|
761 |
|
|
return (slp->session);
|
762 |
|
|
}
|
763 |
|
|
|
764 |
|
|
/* extended open */
|
765 |
|
|
struct snmp_session *snmp_open_ex (
|
766 |
|
|
struct snmp_session *session,
|
767 |
|
|
int (*fpre_parse) (struct snmp_session *, snmp_ipaddr),
|
768 |
|
|
int (*fparse) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t),
|
769 |
|
|
int (*fpost_parse) (struct snmp_session *, struct snmp_pdu *, int),
|
770 |
|
|
int (*fbuild) (struct snmp_session *, struct snmp_pdu *, u_char *, size_t *),
|
771 |
|
|
int (*fcheck) (u_char *, size_t )
|
772 |
|
|
)
|
773 |
|
|
{
|
774 |
|
|
struct session_list *slp;
|
775 |
|
|
slp = (struct session_list *)snmp_sess_open(session);
|
776 |
|
|
if (!slp) return NULL;
|
777 |
|
|
slp->internal->hook_pre = fpre_parse;
|
778 |
|
|
slp->internal->hook_parse = fparse;
|
779 |
|
|
slp->internal->hook_post = fpost_parse;
|
780 |
|
|
slp->internal->hook_build = fbuild;
|
781 |
|
|
slp->internal->check_packet = fcheck;
|
782 |
|
|
|
783 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
784 |
|
|
slp->next = Sessions;
|
785 |
|
|
Sessions = slp;
|
786 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
787 |
|
|
|
788 |
|
|
return (slp->session);
|
789 |
|
|
}
|
790 |
|
|
|
791 |
|
|
static struct session_list *
|
792 |
|
|
_sess_copy( struct snmp_session *in_session)
|
793 |
|
|
{
|
794 |
|
|
struct session_list *slp;
|
795 |
|
|
struct snmp_internal_session *isp;
|
796 |
|
|
struct snmp_session *session;
|
797 |
|
|
char *cp;
|
798 |
|
|
u_char *ucp;
|
799 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
800 |
|
|
size_t i;
|
801 |
|
|
#endif
|
802 |
|
|
|
803 |
|
|
in_session->s_snmp_errno = 0;
|
804 |
|
|
in_session->s_errno = 0;
|
805 |
|
|
|
806 |
|
|
/* Copy session structure and link into list */
|
807 |
|
|
slp = (struct session_list *)calloc(1,sizeof(struct session_list));
|
808 |
|
|
if (slp == NULL) {
|
809 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
810 |
|
|
return(NULL);
|
811 |
|
|
}
|
812 |
|
|
|
813 |
|
|
isp = (struct snmp_internal_session *)calloc(1,sizeof(struct snmp_internal_session));
|
814 |
|
|
if (isp == NULL) {
|
815 |
|
|
snmp_sess_close(slp);
|
816 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
817 |
|
|
return(NULL);
|
818 |
|
|
}
|
819 |
|
|
|
820 |
|
|
slp->internal = isp;
|
821 |
|
|
slp->internal->sd = -1; /* mark it not set */
|
822 |
|
|
slp->session = (struct snmp_session *)malloc(sizeof(struct snmp_session));
|
823 |
|
|
if (slp->session == NULL) {
|
824 |
|
|
snmp_sess_close(slp);
|
825 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
826 |
|
|
return(NULL);
|
827 |
|
|
}
|
828 |
|
|
memmove(slp->session, in_session, sizeof(struct snmp_session));
|
829 |
|
|
session = slp->session;
|
830 |
|
|
|
831 |
|
|
/* zero out pointers so if we have to free the session we wont free mem
|
832 |
|
|
owned by in_session */
|
833 |
|
|
session->peername = NULL;
|
834 |
|
|
session->community = NULL;
|
835 |
|
|
session->contextEngineID = NULL;
|
836 |
|
|
session->contextName = NULL;
|
837 |
|
|
session->securityEngineID = NULL;
|
838 |
|
|
session->securityName = NULL;
|
839 |
|
|
session->securityAuthProto = NULL;
|
840 |
|
|
session->securityPrivProto = NULL;
|
841 |
|
|
/*
|
842 |
|
|
* session now points to the new structure that still contains pointers to
|
843 |
|
|
* data allocated elsewhere. Some of this data is copied to space malloc'd
|
844 |
|
|
* here, and the pointer replaced with the new one.
|
845 |
|
|
*/
|
846 |
|
|
|
847 |
|
|
if (in_session->peername != NULL){
|
848 |
|
|
session->peername = (char *)malloc(strlen(in_session->peername) + 1);
|
849 |
|
|
if (session->peername == NULL) {
|
850 |
|
|
snmp_sess_close(slp);
|
851 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
852 |
|
|
return(NULL);
|
853 |
|
|
}
|
854 |
|
|
strcpy(session->peername, in_session->peername);
|
855 |
|
|
}
|
856 |
|
|
|
857 |
|
|
/* Fill in defaults if necessary */
|
858 |
|
|
if (in_session->community_len != SNMP_DEFAULT_COMMUNITY_LEN){
|
859 |
|
|
ucp = (u_char *)malloc(in_session->community_len);
|
860 |
|
|
if (ucp != NULL)
|
861 |
|
|
memmove(ucp, in_session->community, in_session->community_len);
|
862 |
|
|
} else {
|
863 |
|
|
if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_COMMUNITY)) != NULL) {
|
864 |
|
|
session->community_len = strlen(cp);
|
865 |
|
|
ucp = (u_char *)malloc(session->community_len);
|
866 |
|
|
if (ucp)
|
867 |
|
|
memmove(ucp, cp, session->community_len);
|
868 |
|
|
}
|
869 |
|
|
else {
|
870 |
|
|
#ifdef NO_ZEROLENGTH_COMMUNITY
|
871 |
|
|
session->community_len = strlen(DEFAULT_COMMUNITY);
|
872 |
|
|
ucp = (u_char *)malloc(session->community_len);
|
873 |
|
|
if (ucp)
|
874 |
|
|
memmove(ucp, DEFAULT_COMMUNITY, session->community_len);
|
875 |
|
|
#else
|
876 |
|
|
ucp = (u_char *)strdup("");
|
877 |
|
|
#endif
|
878 |
|
|
}
|
879 |
|
|
}
|
880 |
|
|
|
881 |
|
|
if (ucp == NULL) {
|
882 |
|
|
snmp_sess_close(slp);
|
883 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
884 |
|
|
return(NULL);
|
885 |
|
|
}
|
886 |
|
|
session->community = ucp; /* replace pointer with pointer to new data */
|
887 |
|
|
|
888 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
889 |
|
|
if (session->securityLevel <= 0)
|
890 |
|
|
session->securityLevel = ds_get_int(DS_LIBRARY_ID, DS_LIB_SECLEVEL);
|
891 |
|
|
|
892 |
|
|
if (session->securityLevel == 0)
|
893 |
|
|
session->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
|
894 |
|
|
|
895 |
|
|
if (in_session->securityAuthProtoLen > 0) {
|
896 |
|
|
session->securityAuthProto =
|
897 |
|
|
(oid*)malloc(in_session->securityAuthProtoLen * sizeof(oid));
|
898 |
|
|
if (session->securityAuthProto == NULL) {
|
899 |
|
|
snmp_sess_close(slp);
|
900 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
901 |
|
|
return(NULL);
|
902 |
|
|
}
|
903 |
|
|
memmove(session->securityAuthProto, in_session->securityAuthProto,
|
904 |
|
|
in_session->securityAuthProtoLen * sizeof(oid));
|
905 |
|
|
} else if (get_default_authtype(&i) != NULL) {
|
906 |
|
|
session->securityAuthProto =
|
907 |
|
|
snmp_duplicate_objid(get_default_authtype(NULL), i);
|
908 |
|
|
session->securityAuthProtoLen = i;
|
909 |
|
|
}
|
910 |
|
|
|
911 |
|
|
if (in_session->securityPrivProtoLen > 0) {
|
912 |
|
|
session->securityPrivProto =
|
913 |
|
|
(oid*)malloc((unsigned)in_session->securityPrivProtoLen * sizeof(oid));
|
914 |
|
|
if (session->securityPrivProto == NULL) {
|
915 |
|
|
snmp_sess_close(slp);
|
916 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
917 |
|
|
return(NULL);
|
918 |
|
|
}
|
919 |
|
|
memmove(session->securityPrivProto, in_session->securityPrivProto,
|
920 |
|
|
in_session->securityPrivProtoLen * sizeof(oid));
|
921 |
|
|
} else if (get_default_privtype(&i) != NULL) {
|
922 |
|
|
session->securityPrivProto =
|
923 |
|
|
snmp_duplicate_objid(get_default_privtype(NULL), i);
|
924 |
|
|
session->securityPrivProtoLen = i;
|
925 |
|
|
}
|
926 |
|
|
|
927 |
|
|
if (in_session->securityEngineIDLen > 0) {
|
928 |
|
|
ucp = (u_char*)malloc((unsigned)in_session->securityEngineIDLen *
|
929 |
|
|
sizeof(u_char));
|
930 |
|
|
if (ucp == NULL) {
|
931 |
|
|
snmp_sess_close(slp);
|
932 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
933 |
|
|
return(NULL);
|
934 |
|
|
}
|
935 |
|
|
memmove(ucp, in_session->securityEngineID,
|
936 |
|
|
in_session->securityEngineIDLen * sizeof(u_char));
|
937 |
|
|
session->securityEngineID = ucp;
|
938 |
|
|
|
939 |
|
|
}
|
940 |
|
|
|
941 |
|
|
if (in_session->contextEngineIDLen > 0) {
|
942 |
|
|
ucp = (u_char*)malloc((unsigned)in_session->contextEngineIDLen *
|
943 |
|
|
sizeof(u_char));
|
944 |
|
|
if (ucp == NULL) {
|
945 |
|
|
snmp_sess_close(slp);
|
946 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
947 |
|
|
return(NULL);
|
948 |
|
|
}
|
949 |
|
|
memmove(ucp, in_session->contextEngineID,
|
950 |
|
|
in_session->contextEngineIDLen * sizeof(u_char));
|
951 |
|
|
session->contextEngineID = ucp;
|
952 |
|
|
} else if (in_session->securityEngineIDLen > 0) {
|
953 |
|
|
/* default contextEngineID to securityEngineIDLen if defined */
|
954 |
|
|
ucp = (u_char*)malloc((unsigned)in_session->securityEngineIDLen *
|
955 |
|
|
sizeof(u_char));
|
956 |
|
|
if (ucp == NULL) {
|
957 |
|
|
snmp_sess_close(slp);
|
958 |
|
|
in_session->s_snmp_errno = SNMPERR_MALLOC;
|
959 |
|
|
return(NULL);
|
960 |
|
|
}
|
961 |
|
|
memmove(ucp, in_session->securityEngineID,
|
962 |
|
|
in_session->securityEngineIDLen * sizeof(u_char));
|
963 |
|
|
session->contextEngineID = ucp;
|
964 |
|
|
session->contextEngineIDLen = in_session->securityEngineIDLen;
|
965 |
|
|
}
|
966 |
|
|
|
967 |
|
|
if (in_session->contextName) {
|
968 |
|
|
session->contextName = strdup(in_session->contextName);
|
969 |
|
|
if (session->contextName == NULL) {
|
970 |
|
|
snmp_sess_close(slp);
|
971 |
|
|
return(NULL);
|
972 |
|
|
}
|
973 |
|
|
} else if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_CONTEXT)) != NULL) {
|
974 |
|
|
cp = strdup(cp);
|
975 |
|
|
if (cp == NULL) {
|
976 |
|
|
snmp_sess_close(slp);
|
977 |
|
|
return(NULL);
|
978 |
|
|
}
|
979 |
|
|
session->contextName = cp;
|
980 |
|
|
session->contextNameLen = strlen(cp);
|
981 |
|
|
} else {
|
982 |
|
|
cp = strdup(SNMP_DEFAULT_CONTEXT);
|
983 |
|
|
session->contextName = cp;
|
984 |
|
|
session->contextNameLen = strlen(cp);
|
985 |
|
|
}
|
986 |
|
|
|
987 |
|
|
if (in_session->securityName) {
|
988 |
|
|
session->securityName = strdup(in_session->securityName);
|
989 |
|
|
if (session->securityName == NULL) {
|
990 |
|
|
snmp_sess_close(slp);
|
991 |
|
|
return(NULL);
|
992 |
|
|
}
|
993 |
|
|
} else if ((cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_SECNAME)) != NULL) {
|
994 |
|
|
cp = strdup(cp);
|
995 |
|
|
if (cp == NULL) {
|
996 |
|
|
snmp_sess_close(slp);
|
997 |
|
|
return(NULL);
|
998 |
|
|
}
|
999 |
|
|
session->securityName = cp;
|
1000 |
|
|
session->securityNameLen = strlen(cp);
|
1001 |
|
|
}
|
1002 |
|
|
|
1003 |
|
|
if ((in_session->securityAuthKeyLen <= 0) &&
|
1004 |
|
|
(cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_AUTHPASSPHRASE))) {
|
1005 |
|
|
session->securityAuthKeyLen = USM_AUTH_KU_LEN;
|
1006 |
|
|
if (generate_Ku(session->securityAuthProto,
|
1007 |
|
|
session->securityAuthProtoLen,
|
1008 |
|
|
(u_char*)cp, strlen(cp),
|
1009 |
|
|
session->securityAuthKey,
|
1010 |
|
|
&session->securityAuthKeyLen) != SNMPERR_SUCCESS) {
|
1011 |
|
|
snmp_set_detail("Error generating Ku from authentication pass phrase.");
|
1012 |
|
|
snmp_sess_close(slp);
|
1013 |
|
|
return NULL;
|
1014 |
|
|
}
|
1015 |
|
|
}
|
1016 |
|
|
|
1017 |
|
|
if ((in_session->securityPrivKeyLen <= 0) &&
|
1018 |
|
|
(cp = ds_get_string(DS_LIBRARY_ID, DS_LIB_PRIVPASSPHRASE))) {
|
1019 |
|
|
session->securityPrivKeyLen = USM_PRIV_KU_LEN;
|
1020 |
|
|
if (generate_Ku(session->securityAuthProto,
|
1021 |
|
|
session->securityAuthProtoLen,
|
1022 |
|
|
(u_char *)cp, strlen(cp),
|
1023 |
|
|
session->securityPrivKey,
|
1024 |
|
|
&session->securityPrivKeyLen) != SNMPERR_SUCCESS) {
|
1025 |
|
|
snmp_set_detail("Error generating Ku from privacy pass phrase.");
|
1026 |
|
|
snmp_sess_close(slp);
|
1027 |
|
|
return NULL;
|
1028 |
|
|
}
|
1029 |
|
|
}
|
1030 |
|
|
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
|
1031 |
|
|
|
1032 |
|
|
if (session->retries == SNMP_DEFAULT_RETRIES)
|
1033 |
|
|
session->retries = DEFAULT_RETRIES;
|
1034 |
|
|
if (session->timeout == SNMP_DEFAULT_TIMEOUT)
|
1035 |
|
|
session->timeout = DEFAULT_TIMEOUT;
|
1036 |
|
|
session->sessid = snmp_get_next_sessid();
|
1037 |
|
|
|
1038 |
|
|
return( slp );
|
1039 |
|
|
}
|
1040 |
|
|
|
1041 |
|
|
struct session_list *
|
1042 |
|
|
snmp_sess_copy( struct snmp_session *pss)
|
1043 |
|
|
{
|
1044 |
|
|
struct session_list * psl;
|
1045 |
|
|
psl = _sess_copy(pss);
|
1046 |
|
|
if ( !psl) {
|
1047 |
|
|
if ( !pss->s_snmp_errno)
|
1048 |
|
|
pss->s_snmp_errno = SNMPERR_GENERR;
|
1049 |
|
|
SET_SNMP_ERROR(pss->s_snmp_errno);
|
1050 |
|
|
}
|
1051 |
|
|
return psl;
|
1052 |
|
|
}
|
1053 |
|
|
|
1054 |
|
|
/*******************************************************************-o-******
|
1055 |
|
|
* snmp_sess_open
|
1056 |
|
|
*
|
1057 |
|
|
* Parameters:
|
1058 |
|
|
* *in_session
|
1059 |
|
|
*
|
1060 |
|
|
* Returns:
|
1061 |
|
|
* Pointer to a session in the session list -OR- FIX -- right?
|
1062 |
|
|
* NULL on failure.
|
1063 |
|
|
*
|
1064 |
|
|
* The "spin-free" version of snmp_open.
|
1065 |
|
|
*/
|
1066 |
|
|
static void *
|
1067 |
|
|
_sess_open(struct snmp_session *in_session)
|
1068 |
|
|
{
|
1069 |
|
|
struct session_list *slp;
|
1070 |
|
|
struct snmp_internal_session *isp;
|
1071 |
|
|
struct snmp_session *session;
|
1072 |
|
|
int sd;
|
1073 |
|
|
in_addr_t addr;
|
1074 |
|
|
struct sockaddr_in *isp_addr, *meIp;
|
1075 |
|
|
#ifdef HAVE_GETHOSTBYNAME
|
1076 |
|
|
struct hostent *hp;
|
1077 |
|
|
#endif
|
1078 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
1079 |
|
|
struct snmp_pdu *pdu, *response;
|
1080 |
|
|
int status;
|
1081 |
|
|
#endif
|
1082 |
|
|
size_t i, addr_size;
|
1083 |
|
|
char *cp = NULL;
|
1084 |
|
|
|
1085 |
|
|
in_session->s_snmp_errno = 0;
|
1086 |
|
|
in_session->s_errno = 0;
|
1087 |
|
|
|
1088 |
|
|
if (Reqid == 0)
|
1089 |
|
|
_init_snmp();
|
1090 |
|
|
|
1091 |
|
|
if ((slp = snmp_sess_copy( in_session )) == NULL )
|
1092 |
|
|
return( NULL );
|
1093 |
|
|
isp = slp->internal;
|
1094 |
|
|
session = slp->session;
|
1095 |
|
|
|
1096 |
|
|
if ( isp->addr.sa_family == AF_UNSPEC ) {
|
1097 |
|
|
if ( session->peername && session->peername[0] == '/' ) {
|
1098 |
|
|
#ifdef AF_UNIX
|
1099 |
|
|
isp->addr.sa_family = AF_UNIX;
|
1100 |
|
|
strcpy( isp->addr.sa_data, session->peername);
|
1101 |
|
|
#else /* AF_UNIX */
|
1102 |
|
|
snmp_log(LOG_ERR,"%s:%d: _sess_open invalid session name %s- unix sockets not supported \n",
|
1103 |
|
|
__FILE__,__LINE__,
|
1104 |
|
|
session->peername);
|
1105 |
|
|
return(NULL);
|
1106 |
|
|
#endif /* AF_UNIX */
|
1107 |
|
|
|
1108 |
|
|
} else {
|
1109 |
|
|
isp->addr.sa_family = AF_INET;
|
1110 |
|
|
isp_addr = (struct sockaddr_in *)&(isp->addr);
|
1111 |
|
|
if (session->peername != SNMP_DEFAULT_PEERNAME) {
|
1112 |
|
|
|
1113 |
|
|
/* Try and extract an appended port number */
|
1114 |
|
|
cp = strchr( session->peername, ':' );
|
1115 |
|
|
if ( cp ) {
|
1116 |
|
|
*cp = '\0';
|
1117 |
|
|
cp++;
|
1118 |
|
|
session->remote_port = atoi( cp );
|
1119 |
|
|
if ( session->local_port ) /* i.e. server */
|
1120 |
|
|
session->local_port = session->remote_port;
|
1121 |
|
|
}
|
1122 |
|
|
|
1123 |
|
|
/* Interpret the peername as an IP port ... */
|
1124 |
|
|
cp = strchr( session->peername, '.' );
|
1125 |
|
|
if ( !cp && (( i = atoi( session->peername )) != 0 )) {
|
1126 |
|
|
session->remote_port = i;
|
1127 |
|
|
if ( session->local_port ) /* i.e. server */
|
1128 |
|
|
session->local_port = session->remote_port;
|
1129 |
|
|
}
|
1130 |
|
|
|
1131 |
|
|
/* ... failing that, as an IP address ... */
|
1132 |
|
|
else if ((int)(addr = inet_addr(session->peername)) != -1){
|
1133 |
|
|
memmove(&isp_addr->sin_addr, &addr, sizeof(isp_addr->sin_addr));
|
1134 |
|
|
} else {
|
1135 |
|
|
/* .... failing that, as a hostname */
|
1136 |
|
|
#ifdef HAVE_GETHOSTBYNAME
|
1137 |
|
|
hp = gethostbyname(session->peername);
|
1138 |
|
|
if (hp == NULL){
|
1139 |
|
|
in_session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
|
1140 |
|
|
in_session->s_errno = errno;
|
1141 |
|
|
snmp_set_detail(session->peername);
|
1142 |
|
|
snmp_sess_close(slp);
|
1143 |
|
|
return 0;
|
1144 |
|
|
} else {
|
1145 |
|
|
memmove(&isp_addr->sin_addr, hp->h_addr, hp->h_length);
|
1146 |
|
|
}
|
1147 |
|
|
|
1148 |
|
|
#else /* HAVE_GETHOSTBYNAME */
|
1149 |
|
|
snmp_log(LOG_ERR,"%s:%d: _sess_open do not have get host by name - cannot resolve %s \n",
|
1150 |
|
|
__FILE__,__LINE__,
|
1151 |
|
|
session->peername);
|
1152 |
|
|
return(0);
|
1153 |
|
|
#endif /* HAVE_GETHOSTBYNAME */
|
1154 |
|
|
|
1155 |
|
|
}
|
1156 |
|
|
if (session->remote_port == SNMP_DEFAULT_REMPORT){
|
1157 |
|
|
short iport = ds_get_int(DS_LIBRARY_ID, DS_LIB_DEFAULT_PORT);
|
1158 |
|
|
isp_addr->sin_port = htons(iport);
|
1159 |
|
|
} else {
|
1160 |
|
|
isp_addr->sin_port = htons(session->remote_port);
|
1161 |
|
|
}
|
1162 |
|
|
} else {
|
1163 |
|
|
isp_addr->sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
|
1164 |
|
|
}
|
1165 |
|
|
}
|
1166 |
|
|
}
|
1167 |
|
|
|
1168 |
|
|
|
1169 |
|
|
if ( session->local_port ) {
|
1170 |
|
|
/*
|
1171 |
|
|
* If the session structure includes a non-null value for
|
1172 |
|
|
* local_port, then this session is intended as a server.
|
1173 |
|
|
* This means that the isp->addr structure will not be
|
1174 |
|
|
* needed to contact a remote entity.
|
1175 |
|
|
*
|
1176 |
|
|
* By using this address as the local address to bind to,
|
1177 |
|
|
* we can provide a facility for listening on selected
|
1178 |
|
|
* (rather than all) interfaces.
|
1179 |
|
|
*/
|
1180 |
|
|
memcpy( &isp->me, &isp->addr, sizeof(isp->me));
|
1181 |
|
|
|
1182 |
|
|
if ( isp->addr.sa_family == AF_INET ) {
|
1183 |
|
|
/*
|
1184 |
|
|
* Remember to use the specified local port,
|
1185 |
|
|
* rather than the (default?) remote one.
|
1186 |
|
|
* If no local interface address is specified,
|
1187 |
|
|
* default to listening on all interfaces,
|
1188 |
|
|
* rather than the default connection host
|
1189 |
|
|
* (SNMP_DEFAULT_ADDRESS)
|
1190 |
|
|
*/
|
1191 |
|
|
meIp = (struct sockaddr_in*)&(isp->me);
|
1192 |
|
|
meIp->sin_port = htons(session->local_port);
|
1193 |
|
|
if (session->peername == SNMP_DEFAULT_PEERNAME)
|
1194 |
|
|
meIp->sin_addr.s_addr = INADDR_ANY;
|
1195 |
|
|
}
|
1196 |
|
|
}
|
1197 |
|
|
else {
|
1198 |
|
|
memset(&isp->me, '\0', sizeof(isp->me));
|
1199 |
|
|
isp->me.sa_family = isp->addr.sa_family;
|
1200 |
|
|
if ( isp->me.sa_family == AF_INET ) {
|
1201 |
|
|
meIp = (struct sockaddr_in*)&(isp->me);
|
1202 |
|
|
meIp->sin_addr.s_addr = INADDR_ANY;
|
1203 |
|
|
meIp->sin_port = htons(session->local_port);
|
1204 |
|
|
}
|
1205 |
|
|
#ifdef AF_UNIX
|
1206 |
|
|
else if ( isp->me.sa_family == AF_UNIX ) {
|
1207 |
|
|
/* Need a unique socket name */
|
1208 |
|
|
#ifndef UNIX_SOCKET_BASE_NAME
|
1209 |
|
|
#define UNIX_SOCKET_BASE_NAME "/tmp/s."
|
1210 |
|
|
#endif
|
1211 |
|
|
|
1212 |
|
|
#ifndef WIN32
|
1213 |
|
|
strcpy( isp->me.sa_data, UNIX_SOCKET_BASE_NAME );
|
1214 |
|
|
strcat( isp->me.sa_data, "XXXXXX" );
|
1215 |
|
|
mktemp( isp->me.sa_data );
|
1216 |
|
|
#endif
|
1217 |
|
|
}
|
1218 |
|
|
#endif /* AF_UNIX */
|
1219 |
|
|
}
|
1220 |
|
|
addr_size = snmp_socket_length(isp->me.sa_family);
|
1221 |
|
|
|
1222 |
|
|
/* Set up connections */
|
1223 |
|
|
if ( session->flags & SNMP_FLAGS_STREAM_SOCKET ) {
|
1224 |
|
|
if ( session->local_port != 0 )
|
1225 |
|
|
session->flags |= SNMP_FLAGS_LISTENING;
|
1226 |
|
|
sd = socket(isp->me.sa_family, SOCK_STREAM, 0);
|
1227 |
|
|
}
|
1228 |
|
|
else
|
1229 |
|
|
sd = socket(isp->me.sa_family, SOCK_DGRAM, 0);
|
1230 |
|
|
if (sd < 0){
|
1231 |
|
|
in_session->s_snmp_errno = SNMPERR_NO_SOCKET;
|
1232 |
|
|
in_session->s_errno = errno;
|
1233 |
|
|
snmp_set_detail(strerror(errno));
|
1234 |
|
|
snmp_sess_close(slp);
|
1235 |
|
|
return 0;
|
1236 |
|
|
}
|
1237 |
|
|
isp->sd = sd;
|
1238 |
|
|
|
1239 |
|
|
#ifdef SO_BSDCOMPAT
|
1240 |
|
|
/* Patch for Linux. Without this, UDP packets that fail get an ICMP
|
1241 |
|
|
* response. Linux turns the failed ICMP response into an error message
|
1242 |
|
|
* and return value, unlike all other OS's.
|
1243 |
|
|
*/
|
1244 |
|
|
{
|
1245 |
|
|
int one=1;
|
1246 |
|
|
setsockopt(sd, SOL_SOCKET, SO_BSDCOMPAT, &one, sizeof(one));
|
1247 |
|
|
}
|
1248 |
|
|
#endif /* SO_BSDCOMPAT */
|
1249 |
|
|
|
1250 |
|
|
//#ifndef __ECOS
|
1251 |
|
|
#ifndef SERVER_REQUIRES_CLIENT_SOCKET
|
1252 |
|
|
if (!(( session->flags & SNMP_FLAGS_STREAM_SOCKET ) &&
|
1253 |
|
|
#ifdef AF_UNIX
|
1254 |
|
|
( isp->me.sa_family == AF_UNIX ) &&
|
1255 |
|
|
#endif /* AF_UNIX */
|
1256 |
|
|
( session->local_port == 0 ))) {
|
1257 |
|
|
|
1258 |
|
|
/* Client Unix-domain stream sockets don't need to 'bind' */
|
1259 |
|
|
#endif
|
1260 |
|
|
if (bind(sd, (struct sockaddr *)&isp->me, addr_size) != 0){
|
1261 |
|
|
in_session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
|
1262 |
|
|
in_session->s_errno = errno;
|
1263 |
|
|
snmp_set_detail(strerror(errno));
|
1264 |
|
|
snmp_sess_close(slp);
|
1265 |
|
|
return 0;
|
1266 |
|
|
}
|
1267 |
|
|
#ifndef SERVER_REQUIRES_CLIENT_SOCKET
|
1268 |
|
|
}
|
1269 |
|
|
#endif
|
1270 |
|
|
//#endif // not __ECOS
|
1271 |
|
|
|
1272 |
|
|
if ( session->flags & SNMP_FLAGS_STREAM_SOCKET ) {
|
1273 |
|
|
if ( session->local_port == 0 ) { /* Client session */
|
1274 |
|
|
|
1275 |
|
|
if ( connect( sd, (struct sockaddr *)&(isp->addr),
|
1276 |
|
|
snmp_socket_length(isp->addr.sa_family)) != 0 ) {
|
1277 |
|
|
in_session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
|
1278 |
|
|
in_session->s_errno = errno;
|
1279 |
|
|
snmp_set_detail(strerror(errno));
|
1280 |
|
|
snmp_sess_close(slp);
|
1281 |
|
|
return 0;
|
1282 |
|
|
}
|
1283 |
|
|
} else { /* Server session */
|
1284 |
|
|
|
1285 |
|
|
if ( listen( sd, SNMP_STREAM_QUEUE_LEN ) != 0 ) {
|
1286 |
|
|
in_session->s_snmp_errno = SNMPERR_BAD_LOCPORT;
|
1287 |
|
|
in_session->s_errno = errno;
|
1288 |
|
|
snmp_set_detail(strerror(errno));
|
1289 |
|
|
snmp_sess_close(slp);
|
1290 |
|
|
return 0;
|
1291 |
|
|
}
|
1292 |
|
|
}
|
1293 |
|
|
}
|
1294 |
|
|
|
1295 |
|
|
/* if we are opening a V3 session and we don't know engineID
|
1296 |
|
|
we must probe it - this must be done after the session is
|
1297 |
|
|
created and inserted in the list so that the response can
|
1298 |
|
|
handled correctly */
|
1299 |
|
|
|
1300 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
1301 |
|
|
|
1302 |
|
|
if (session->version == SNMP_VERSION_3) {
|
1303 |
|
|
if (session->securityEngineIDLen == 0 &&
|
1304 |
|
|
(session->securityEngineIDLen & SNMP_FLAGS_DONT_PROBE) !=
|
1305 |
|
|
SNMP_FLAGS_DONT_PROBE) {
|
1306 |
|
|
snmpv3_build_probe_pdu(&pdu);
|
1307 |
|
|
DEBUGMSGTL(("snmp_api","probing for engineID...\n"));
|
1308 |
|
|
status = snmp_sess_synch_response(slp, pdu, &response);
|
1309 |
|
|
|
1310 |
|
|
if ((response == NULL) && (status == STAT_SUCCESS)) status = STAT_ERROR;
|
1311 |
|
|
|
1312 |
|
|
switch (status) {
|
1313 |
|
|
case STAT_SUCCESS:
|
1314 |
|
|
in_session->s_snmp_errno = SNMPERR_INVALID_MSG; /* XX?? */
|
1315 |
|
|
DEBUGMSGTL(("snmp_sess_open",
|
1316 |
|
|
"error: expected Report as response to probe: %s (%d)\n",
|
1317 |
|
|
snmp_errstring(response->errstat), response->errstat));
|
1318 |
|
|
break;
|
1319 |
|
|
case STAT_ERROR: /* this is what we expected -> Report == STAT_ERROR */
|
1320 |
|
|
in_session->s_snmp_errno = SNMPERR_UNKNOWN_ENG_ID;
|
1321 |
|
|
break;
|
1322 |
|
|
case STAT_TIMEOUT:
|
1323 |
|
|
in_session->s_snmp_errno = SNMPERR_TIMEOUT;
|
1324 |
|
|
default:
|
1325 |
|
|
DEBUGMSGTL(("snmp_sess_open",
|
1326 |
|
|
"unable to connect with remote engine: %s (%d)\n",
|
1327 |
|
|
snmp_api_errstring(session->s_snmp_errno),
|
1328 |
|
|
session->s_snmp_errno));
|
1329 |
|
|
break;
|
1330 |
|
|
}
|
1331 |
|
|
if (slp->session->securityEngineIDLen == 0) {
|
1332 |
|
|
DEBUGMSGTL(("snmp_api","unable to determine remote engine ID\n"));
|
1333 |
|
|
snmp_sess_close(slp);
|
1334 |
|
|
return NULL;
|
1335 |
|
|
}
|
1336 |
|
|
in_session->s_snmp_errno = SNMPERR_SUCCESS;
|
1337 |
|
|
if (snmp_get_do_debugging()) {
|
1338 |
|
|
DEBUGMSGTL(("snmp_sess_open", " probe found engineID: "));
|
1339 |
|
|
for(i = 0; i < slp->session->securityEngineIDLen; i++)
|
1340 |
|
|
DEBUGMSG(("snmp_sess_open", "%02x",
|
1341 |
|
|
slp->session->securityEngineID[i]));
|
1342 |
|
|
DEBUGMSG(("snmp_sess_open","\n"));
|
1343 |
|
|
}
|
1344 |
|
|
}
|
1345 |
|
|
/* if boot/time supplied set it for this engineID */
|
1346 |
|
|
if (session->engineBoots || session->engineTime) {
|
1347 |
|
|
set_enginetime(session->securityEngineID, session->securityEngineIDLen,
|
1348 |
|
|
session->engineBoots, session->engineTime, TRUE);
|
1349 |
|
|
}
|
1350 |
|
|
if (create_user_from_session(slp->session) != SNMPERR_SUCCESS) {
|
1351 |
|
|
in_session->s_snmp_errno = SNMPERR_UNKNOWN_USER_NAME; /* XX?? */
|
1352 |
|
|
DEBUGMSGTL(("snmp_api","snmp_sess_open(): failed(2) to create a new user from session\n"));
|
1353 |
|
|
snmp_sess_close(slp);
|
1354 |
|
|
return NULL;
|
1355 |
|
|
}
|
1356 |
|
|
}
|
1357 |
|
|
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
|
1358 |
|
|
|
1359 |
|
|
|
1360 |
|
|
return (void *)slp;
|
1361 |
|
|
} /* end snmp_sess_open() */
|
1362 |
|
|
|
1363 |
|
|
void *
|
1364 |
|
|
snmp_sess_open(struct snmp_session *pss)
|
1365 |
|
|
{
|
1366 |
|
|
void * pvoid;
|
1367 |
|
|
pvoid = _sess_open(pss);
|
1368 |
|
|
if ( !pvoid) {
|
1369 |
|
|
SET_SNMP_ERROR(pss->s_snmp_errno);
|
1370 |
|
|
}
|
1371 |
|
|
return pvoid;
|
1372 |
|
|
}
|
1373 |
|
|
|
1374 |
|
|
|
1375 |
|
|
|
1376 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
1377 |
|
|
/* create_user_from_session(struct snmp_session *session):
|
1378 |
|
|
|
1379 |
|
|
creates a user in the usm table from the information in a session
|
1380 |
|
|
|
1381 |
|
|
Parameters:
|
1382 |
|
|
session -- IN: pointer to the session to use when creating the user.
|
1383 |
|
|
|
1384 |
|
|
Returns:
|
1385 |
|
|
SNMPERR_SUCCESS
|
1386 |
|
|
SNMPERR_GENERR
|
1387 |
|
|
*/
|
1388 |
|
|
int
|
1389 |
|
|
create_user_from_session(struct snmp_session *session)
|
1390 |
|
|
{
|
1391 |
|
|
struct usmUser *user;
|
1392 |
|
|
|
1393 |
|
|
|
1394 |
|
|
/* now that we have the engineID, create an entry in the USM list
|
1395 |
|
|
for this user using the information in the session */
|
1396 |
|
|
user = usm_get_user_from_list(session->securityEngineID,
|
1397 |
|
|
session->securityEngineIDLen,
|
1398 |
|
|
session->securityName,
|
1399 |
|
|
usm_get_userList(), 0);
|
1400 |
|
|
if (user == NULL) {
|
1401 |
|
|
DEBUGMSGTL(("snmp_api","Building user %s...\n",session->securityName));
|
1402 |
|
|
/* user doesn't exist so we create and add it */
|
1403 |
|
|
user = (struct usmUser *) calloc(1,sizeof(struct usmUser));
|
1404 |
|
|
if (user == NULL)
|
1405 |
|
|
return SNMPERR_GENERR;
|
1406 |
|
|
|
1407 |
|
|
/* copy in the securityName */
|
1408 |
|
|
if (session->securityName) {
|
1409 |
|
|
user->name = strdup(session->securityName);
|
1410 |
|
|
user->secName = strdup(session->securityName);
|
1411 |
|
|
if (user->name == NULL || user->secName == NULL) {
|
1412 |
|
|
usm_free_user(user);
|
1413 |
|
|
return SNMPERR_GENERR;
|
1414 |
|
|
}
|
1415 |
|
|
}
|
1416 |
|
|
|
1417 |
|
|
/* copy in the engineID */
|
1418 |
|
|
if (memdup(&user->engineID, session->securityEngineID,
|
1419 |
|
|
session->securityEngineIDLen) != SNMPERR_SUCCESS) {
|
1420 |
|
|
usm_free_user(user);
|
1421 |
|
|
return SNMPERR_GENERR;
|
1422 |
|
|
}
|
1423 |
|
|
user->engineIDLen = session->securityEngineIDLen;
|
1424 |
|
|
|
1425 |
|
|
/* copy the auth protocol */
|
1426 |
|
|
if (session->securityAuthProto != NULL) {
|
1427 |
|
|
user->authProtocol =
|
1428 |
|
|
snmp_duplicate_objid(session->securityAuthProto,
|
1429 |
|
|
session->securityAuthProtoLen);
|
1430 |
|
|
if (user->authProtocol == NULL) {
|
1431 |
|
|
usm_free_user(user);
|
1432 |
|
|
return SNMPERR_GENERR;
|
1433 |
|
|
}
|
1434 |
|
|
user->authProtocolLen = session->securityAuthProtoLen;
|
1435 |
|
|
}
|
1436 |
|
|
|
1437 |
|
|
/* copy the priv protocol */
|
1438 |
|
|
if (session->securityPrivProto != NULL) {
|
1439 |
|
|
user->privProtocol =
|
1440 |
|
|
snmp_duplicate_objid(session->securityPrivProto,
|
1441 |
|
|
session->securityPrivProtoLen);
|
1442 |
|
|
if (user->privProtocol == NULL) {
|
1443 |
|
|
usm_free_user(user);
|
1444 |
|
|
return SNMPERR_GENERR;
|
1445 |
|
|
}
|
1446 |
|
|
user->privProtocolLen = session->securityPrivProtoLen;
|
1447 |
|
|
}
|
1448 |
|
|
|
1449 |
|
|
/* copy in the authentication Key, and convert to the localized version */
|
1450 |
|
|
if (session->securityAuthKey != NULL && session->securityAuthKeyLen != 0) {
|
1451 |
|
|
user->authKey = (u_char *)malloc (USM_LENGTH_KU_HASHBLOCK);
|
1452 |
|
|
user->authKeyLen = USM_LENGTH_KU_HASHBLOCK;
|
1453 |
|
|
if (generate_kul( user->authProtocol, user->authProtocolLen,
|
1454 |
|
|
session->securityEngineID, session->securityEngineIDLen,
|
1455 |
|
|
session->securityAuthKey, session->securityAuthKeyLen,
|
1456 |
|
|
user->authKey, &user->authKeyLen ) != SNMPERR_SUCCESS) {
|
1457 |
|
|
usm_free_user(user);
|
1458 |
|
|
return SNMPERR_GENERR;
|
1459 |
|
|
}
|
1460 |
|
|
}
|
1461 |
|
|
|
1462 |
|
|
/* copy in the privacy Key, and convert to the localized version */
|
1463 |
|
|
if (session->securityPrivKey != NULL && session->securityPrivKeyLen != 0) {
|
1464 |
|
|
user->privKey = (u_char *)malloc (USM_LENGTH_KU_HASHBLOCK);
|
1465 |
|
|
user->privKeyLen = USM_LENGTH_KU_HASHBLOCK;
|
1466 |
|
|
if (generate_kul( user->authProtocol, user->authProtocolLen,
|
1467 |
|
|
session->securityEngineID, session->securityEngineIDLen,
|
1468 |
|
|
session->securityPrivKey, session->securityPrivKeyLen,
|
1469 |
|
|
user->privKey, &user->privKeyLen ) != SNMPERR_SUCCESS) {
|
1470 |
|
|
usm_free_user(user);
|
1471 |
|
|
return SNMPERR_GENERR;
|
1472 |
|
|
}
|
1473 |
|
|
}
|
1474 |
|
|
|
1475 |
|
|
/* add the user into the database */
|
1476 |
|
|
usm_add_user(user);
|
1477 |
|
|
}
|
1478 |
|
|
|
1479 |
|
|
return SNMPERR_SUCCESS;
|
1480 |
|
|
|
1481 |
|
|
|
1482 |
|
|
} /* end create_user_from_session() */
|
1483 |
|
|
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
|
1484 |
|
|
|
1485 |
|
|
/*
|
1486 |
|
|
* Close the input session. Frees all data allocated for the session,
|
1487 |
|
|
* dequeues any pending requests, and closes any sockets allocated for
|
1488 |
|
|
* the session. Returns 0 on error, 1 otherwise.
|
1489 |
|
|
*/
|
1490 |
|
|
int
|
1491 |
|
|
snmp_sess_close(void *sessp)
|
1492 |
|
|
{
|
1493 |
|
|
struct session_list *slp = (struct session_list *)sessp;
|
1494 |
|
|
struct snmp_internal_session *isp;
|
1495 |
|
|
struct snmp_session *sesp;
|
1496 |
|
|
|
1497 |
|
|
if (slp == NULL)
|
1498 |
|
|
return 0;
|
1499 |
|
|
|
1500 |
|
|
isp = slp->internal; slp->internal = 0;
|
1501 |
|
|
if (isp) {
|
1502 |
|
|
struct request_list *rp, *orp;
|
1503 |
|
|
|
1504 |
|
|
SNMP_FREE(isp->packet);
|
1505 |
|
|
|
1506 |
|
|
if (isp->sd != -1)
|
1507 |
|
|
{
|
1508 |
|
|
#ifndef HAVE_CLOSESOCKET
|
1509 |
|
|
close(isp->sd);
|
1510 |
|
|
#else
|
1511 |
|
|
closesocket(isp->sd);
|
1512 |
|
|
#endif
|
1513 |
|
|
#ifdef AF_UNIX
|
1514 |
|
|
if ( isp->me.sa_family == AF_UNIX )
|
1515 |
|
|
unlink( isp->me.sa_data );
|
1516 |
|
|
#endif /* AF_UNIX */
|
1517 |
|
|
}
|
1518 |
|
|
|
1519 |
|
|
/* Free each element in the input request list. */
|
1520 |
|
|
rp = isp->requests;
|
1521 |
|
|
while(rp){
|
1522 |
|
|
orp = rp;
|
1523 |
|
|
rp = rp->next_request;
|
1524 |
|
|
snmp_free_pdu(orp->pdu);
|
1525 |
|
|
free((char *)orp);
|
1526 |
|
|
}
|
1527 |
|
|
|
1528 |
|
|
free((char *)isp);
|
1529 |
|
|
}
|
1530 |
|
|
|
1531 |
|
|
sesp = slp->session; slp->session = 0;
|
1532 |
|
|
if (sesp) {
|
1533 |
|
|
SNMP_FREE(sesp->peername);
|
1534 |
|
|
SNMP_FREE(sesp->community);
|
1535 |
|
|
SNMP_FREE(sesp->contextEngineID);
|
1536 |
|
|
SNMP_FREE(sesp->contextName);
|
1537 |
|
|
SNMP_FREE(sesp->securityEngineID);
|
1538 |
|
|
SNMP_FREE(sesp->securityName);
|
1539 |
|
|
SNMP_FREE(sesp->securityAuthProto);
|
1540 |
|
|
SNMP_FREE(sesp->securityPrivProto);
|
1541 |
|
|
free((char *)sesp);
|
1542 |
|
|
}
|
1543 |
|
|
|
1544 |
|
|
free((char *)slp);
|
1545 |
|
|
|
1546 |
|
|
return 1;
|
1547 |
|
|
}
|
1548 |
|
|
|
1549 |
|
|
int
|
1550 |
|
|
snmp_close(struct snmp_session *session)
|
1551 |
|
|
{
|
1552 |
|
|
struct session_list *slp = NULL, *oslp = NULL;
|
1553 |
|
|
|
1554 |
|
|
{ /*MTCRITICAL_RESOURCE*/
|
1555 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
1556 |
|
|
if (Sessions && Sessions->session == session){ /* If first entry */
|
1557 |
|
|
slp = Sessions;
|
1558 |
|
|
Sessions = slp->next;
|
1559 |
|
|
} else {
|
1560 |
|
|
for(slp = Sessions; slp; slp = slp->next){
|
1561 |
|
|
if (slp->session == session){
|
1562 |
|
|
if (oslp) /* if we found entry that points here */
|
1563 |
|
|
oslp->next = slp->next; /* link around this entry */
|
1564 |
|
|
break;
|
1565 |
|
|
}
|
1566 |
|
|
oslp = slp;
|
1567 |
|
|
}
|
1568 |
|
|
}
|
1569 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
1570 |
|
|
} /*END MTCRITICAL_RESOURCE*/
|
1571 |
|
|
if (slp == NULL){
|
1572 |
|
|
return 0;
|
1573 |
|
|
}
|
1574 |
|
|
return snmp_sess_close((void *)slp);
|
1575 |
|
|
}
|
1576 |
|
|
|
1577 |
|
|
int
|
1578 |
|
|
snmp_close_sessions( void )
|
1579 |
|
|
{
|
1580 |
|
|
struct session_list *slp;
|
1581 |
|
|
|
1582 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
1583 |
|
|
while ( Sessions ) {
|
1584 |
|
|
slp = Sessions;
|
1585 |
|
|
Sessions = Sessions->next;
|
1586 |
|
|
snmp_sess_close((void *)slp);
|
1587 |
|
|
}
|
1588 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
1589 |
|
|
return 1;
|
1590 |
|
|
}
|
1591 |
|
|
|
1592 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
1593 |
|
|
static int
|
1594 |
|
|
snmpv3_build_probe_pdu (struct snmp_pdu **pdu)
|
1595 |
|
|
{
|
1596 |
|
|
struct usmUser *user;
|
1597 |
|
|
|
1598 |
|
|
/* create the pdu */
|
1599 |
|
|
if (!pdu) return -1;
|
1600 |
|
|
*pdu = snmp_pdu_create(SNMP_MSG_GET);
|
1601 |
|
|
(*pdu)->version = SNMP_VERSION_3;
|
1602 |
|
|
(*pdu)->securityName = strdup("");
|
1603 |
|
|
(*pdu)->securityNameLen = strlen((*pdu)->securityName);
|
1604 |
|
|
(*pdu)->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
|
1605 |
|
|
(*pdu)->securityModel = SNMP_SEC_MODEL_USM;
|
1606 |
|
|
|
1607 |
|
|
/* create the empty user */
|
1608 |
|
|
user = usm_get_user(NULL, 0, (*pdu)->securityName);
|
1609 |
|
|
if (user == NULL) {
|
1610 |
|
|
user = (struct usmUser *) calloc(1,sizeof(struct usmUser));
|
1611 |
|
|
user->name = strdup((*pdu)->securityName);
|
1612 |
|
|
user->secName = strdup((*pdu)->securityName);
|
1613 |
|
|
user->authProtocolLen = sizeof(usmNoAuthProtocol)/sizeof(oid);
|
1614 |
|
|
user->authProtocol =
|
1615 |
|
|
snmp_duplicate_objid(usmNoAuthProtocol, user->authProtocolLen);
|
1616 |
|
|
user->privProtocolLen = sizeof(usmNoPrivProtocol)/sizeof(oid);
|
1617 |
|
|
user->privProtocol =
|
1618 |
|
|
snmp_duplicate_objid(usmNoPrivProtocol, user->privProtocolLen);
|
1619 |
|
|
usm_add_user(user);
|
1620 |
|
|
}
|
1621 |
|
|
return 0;
|
1622 |
|
|
}
|
1623 |
|
|
|
1624 |
|
|
static void
|
1625 |
|
|
snmpv3_calc_msg_flags (int sec_level, int msg_command, u_char *flags)
|
1626 |
|
|
{
|
1627 |
|
|
*flags = 0;
|
1628 |
|
|
if (sec_level == SNMP_SEC_LEVEL_AUTHNOPRIV)
|
1629 |
|
|
*flags = SNMP_MSG_FLAG_AUTH_BIT;
|
1630 |
|
|
else if (sec_level == SNMP_SEC_LEVEL_AUTHPRIV)
|
1631 |
|
|
*flags = SNMP_MSG_FLAG_AUTH_BIT | SNMP_MSG_FLAG_PRIV_BIT;
|
1632 |
|
|
|
1633 |
|
|
if (SNMP_CMD_CONFIRMED(msg_command)) *flags |= SNMP_MSG_FLAG_RPRT_BIT;
|
1634 |
|
|
|
1635 |
|
|
return;
|
1636 |
|
|
}
|
1637 |
|
|
|
1638 |
|
|
static int
|
1639 |
|
|
snmpv3_verify_msg(struct request_list *rp, struct snmp_pdu *pdu)
|
1640 |
|
|
{
|
1641 |
|
|
struct snmp_pdu *rpdu;
|
1642 |
|
|
|
1643 |
|
|
if (!rp || !rp->pdu || !pdu) return 0;
|
1644 |
|
|
/* Reports don't have to match anything according to the spec */
|
1645 |
|
|
if (pdu->command == SNMP_MSG_REPORT) return 1;
|
1646 |
|
|
rpdu = rp->pdu;
|
1647 |
|
|
if (rp->request_id != pdu->reqid || rpdu->reqid != pdu->reqid) return 0;
|
1648 |
|
|
if (rpdu->version != pdu->version) return 0;
|
1649 |
|
|
if (rpdu->securityModel != pdu->securityModel) return 0;
|
1650 |
|
|
if (rpdu->securityLevel != pdu->securityLevel) return 0;
|
1651 |
|
|
|
1652 |
|
|
if (rpdu->contextEngineIDLen != pdu->contextEngineIDLen ||
|
1653 |
|
|
memcmp(rpdu->contextEngineID, pdu->contextEngineID,
|
1654 |
|
|
pdu->contextEngineIDLen))
|
1655 |
|
|
return 0;
|
1656 |
|
|
if (rpdu->contextNameLen != pdu->contextNameLen ||
|
1657 |
|
|
memcmp(rpdu->contextName, pdu->contextName, pdu->contextNameLen))
|
1658 |
|
|
return 0;
|
1659 |
|
|
if (rpdu->securityEngineIDLen != pdu->securityEngineIDLen ||
|
1660 |
|
|
memcmp(rpdu->securityEngineID, pdu->securityEngineID,
|
1661 |
|
|
pdu->securityEngineIDLen))
|
1662 |
|
|
return 0;
|
1663 |
|
|
if (rpdu->securityNameLen != pdu->securityNameLen ||
|
1664 |
|
|
memcmp(rpdu->securityName, pdu->securityName, pdu->securityNameLen))
|
1665 |
|
|
return 0;
|
1666 |
|
|
return 1;
|
1667 |
|
|
}
|
1668 |
|
|
|
1669 |
|
|
|
1670 |
|
|
/* SNMPv3
|
1671 |
|
|
* Takes a session and a pdu and serializes the ASN PDU into the area
|
1672 |
|
|
* pointed to by packet. out_length is the size of the data area available.
|
1673 |
|
|
* Returns the length of the completed packet in out_length. If any errors
|
1674 |
|
|
* occur, -1 is returned. If all goes well, 0 is returned.
|
1675 |
|
|
*/
|
1676 |
|
|
static int
|
1677 |
|
|
snmpv3_build(struct snmp_session *session,
|
1678 |
|
|
struct snmp_pdu *pdu,
|
1679 |
|
|
u_char *packet,
|
1680 |
|
|
size_t *out_length)
|
1681 |
|
|
{
|
1682 |
|
|
int ret;
|
1683 |
|
|
|
1684 |
|
|
session->s_snmp_errno = 0;
|
1685 |
|
|
session->s_errno = 0;
|
1686 |
|
|
|
1687 |
|
|
/* do validation for PDU types */
|
1688 |
|
|
switch (pdu->command) {
|
1689 |
|
|
case SNMP_MSG_RESPONSE:
|
1690 |
|
|
case SNMP_MSG_TRAP2:
|
1691 |
|
|
case SNMP_MSG_REPORT:
|
1692 |
|
|
pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
|
1693 |
|
|
/* Fallthrough */
|
1694 |
|
|
case SNMP_MSG_GET:
|
1695 |
|
|
case SNMP_MSG_GETNEXT:
|
1696 |
|
|
case SNMP_MSG_SET:
|
1697 |
|
|
case SNMP_MSG_INFORM:
|
1698 |
|
|
if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
|
1699 |
|
|
pdu->errstat = 0;
|
1700 |
|
|
if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
|
1701 |
|
|
pdu->errindex = 0;
|
1702 |
|
|
break;
|
1703 |
|
|
|
1704 |
|
|
case SNMP_MSG_GETBULK:
|
1705 |
|
|
if (pdu->max_repetitions < 0) {
|
1706 |
|
|
session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
|
1707 |
|
|
return -1;
|
1708 |
|
|
}
|
1709 |
|
|
if (pdu->non_repeaters < 0) {
|
1710 |
|
|
session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
|
1711 |
|
|
return -1;
|
1712 |
|
|
}
|
1713 |
|
|
break;
|
1714 |
|
|
|
1715 |
|
|
case SNMP_MSG_TRAP:
|
1716 |
|
|
session->s_snmp_errno = SNMPERR_V1_IN_V2;
|
1717 |
|
|
return -1;
|
1718 |
|
|
|
1719 |
|
|
default:
|
1720 |
|
|
session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
|
1721 |
|
|
return -1;
|
1722 |
|
|
}
|
1723 |
|
|
|
1724 |
|
|
if (pdu->securityEngineIDLen == 0) {
|
1725 |
|
|
if (session->securityEngineIDLen) {
|
1726 |
|
|
snmpv3_clone_engineID(&pdu->securityEngineID,
|
1727 |
|
|
&pdu->securityEngineIDLen,
|
1728 |
|
|
session->securityEngineID,
|
1729 |
|
|
session->securityEngineIDLen);
|
1730 |
|
|
}
|
1731 |
|
|
}
|
1732 |
|
|
|
1733 |
|
|
if (pdu->contextEngineIDLen == 0) {
|
1734 |
|
|
if (session->contextEngineIDLen) {
|
1735 |
|
|
snmpv3_clone_engineID(&pdu->contextEngineID,
|
1736 |
|
|
&pdu->contextEngineIDLen,
|
1737 |
|
|
session->contextEngineID,
|
1738 |
|
|
session->contextEngineIDLen);
|
1739 |
|
|
} else if (pdu->securityEngineIDLen) {
|
1740 |
|
|
snmpv3_clone_engineID(&pdu->contextEngineID,
|
1741 |
|
|
&pdu->contextEngineIDLen,
|
1742 |
|
|
pdu->securityEngineID,
|
1743 |
|
|
pdu->securityEngineIDLen);
|
1744 |
|
|
}
|
1745 |
|
|
}
|
1746 |
|
|
|
1747 |
|
|
if (pdu->contextName == NULL) {
|
1748 |
|
|
if (!session->contextName){
|
1749 |
|
|
session->s_snmp_errno = SNMPERR_BAD_CONTEXT;
|
1750 |
|
|
return -1;
|
1751 |
|
|
}
|
1752 |
|
|
pdu->contextName = strdup(session->contextName);
|
1753 |
|
|
if (pdu->contextName == NULL) {
|
1754 |
|
|
session->s_snmp_errno = SNMPERR_GENERR;
|
1755 |
|
|
return -1;
|
1756 |
|
|
}
|
1757 |
|
|
pdu->contextNameLen = session->contextNameLen;
|
1758 |
|
|
}
|
1759 |
|
|
pdu->securityModel = SNMP_SEC_MODEL_USM;
|
1760 |
|
|
if (pdu->securityNameLen == 0 && pdu->securityName == 0) {
|
1761 |
|
|
if (session->securityNameLen == 0){
|
1762 |
|
|
session->s_snmp_errno = SNMPERR_BAD_SEC_NAME;
|
1763 |
|
|
return -1;
|
1764 |
|
|
}
|
1765 |
|
|
pdu->securityName = strdup(session->securityName);
|
1766 |
|
|
if (pdu->securityName == NULL) {
|
1767 |
|
|
session->s_snmp_errno = SNMPERR_GENERR;
|
1768 |
|
|
return -1;
|
1769 |
|
|
}
|
1770 |
|
|
pdu->securityNameLen = session->securityNameLen;
|
1771 |
|
|
}
|
1772 |
|
|
if (pdu->securityLevel == 0) {
|
1773 |
|
|
if (session->securityLevel == 0) {
|
1774 |
|
|
session->s_snmp_errno = SNMPERR_BAD_SEC_LEVEL;
|
1775 |
|
|
return -1;
|
1776 |
|
|
}
|
1777 |
|
|
pdu->securityLevel = session->securityLevel;
|
1778 |
|
|
}
|
1779 |
|
|
DEBUGMSGTL(("snmp_build",
|
1780 |
|
|
"Building SNMPv3 message (secName:\"%s\", secLevel:%s)...\n",
|
1781 |
|
|
((session->securityName) ? (char *)session->securityName :
|
1782 |
|
|
((pdu->securityName) ? (char *)pdu->securityName :
|
1783 |
|
|
"ERROR: undefined")),
|
1784 |
|
|
usmSecLevelName[pdu->securityLevel]));
|
1785 |
|
|
|
1786 |
|
|
ret = snmpv3_packet_build(pdu, packet, out_length, NULL, 0);
|
1787 |
|
|
if (-1 != ret) {
|
1788 |
|
|
session->s_snmp_errno = ret;
|
1789 |
|
|
}
|
1790 |
|
|
|
1791 |
|
|
return ret;
|
1792 |
|
|
|
1793 |
|
|
} /* end snmpv3_build() */
|
1794 |
|
|
|
1795 |
|
|
|
1796 |
|
|
|
1797 |
|
|
|
1798 |
|
|
static u_char *
|
1799 |
|
|
snmpv3_header_build(struct snmp_pdu *pdu, u_char *packet,
|
1800 |
|
|
size_t *out_length, size_t length, u_char **msg_hdr_e)
|
1801 |
|
|
|
1802 |
|
|
{
|
1803 |
|
|
u_char *global_hdr, *global_hdr_e;
|
1804 |
|
|
u_char *cp;
|
1805 |
|
|
u_char msg_flags;
|
1806 |
|
|
long max_size;
|
1807 |
|
|
long sec_model;
|
1808 |
|
|
u_char *pb, *pb0e;
|
1809 |
|
|
|
1810 |
|
|
/* Save current location and build SEQUENCE tag and length placeholder
|
1811 |
|
|
* for SNMP message sequence (actual length inserted later)
|
1812 |
|
|
*/
|
1813 |
|
|
cp = asn_build_sequence(packet, out_length,
|
1814 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), length);
|
1815 |
|
|
if (cp == NULL) return NULL;
|
1816 |
|
|
if (msg_hdr_e != NULL)
|
1817 |
|
|
*msg_hdr_e = cp;
|
1818 |
|
|
pb0e = cp;
|
1819 |
|
|
|
1820 |
|
|
|
1821 |
|
|
/* store the version field - msgVersion
|
1822 |
|
|
*/
|
1823 |
|
|
cp = asn_build_int(cp, out_length,
|
1824 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
1825 |
|
|
(long *) &pdu->version, sizeof(pdu->version));
|
1826 |
|
|
if (cp == NULL) return NULL;
|
1827 |
|
|
|
1828 |
|
|
global_hdr = cp;
|
1829 |
|
|
/* msgGlobalData HeaderData */
|
1830 |
|
|
cp = asn_build_sequence(cp, out_length,
|
1831 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
|
1832 |
|
|
if (cp == NULL) return NULL;
|
1833 |
|
|
global_hdr_e = cp;
|
1834 |
|
|
|
1835 |
|
|
|
1836 |
|
|
/* msgID */
|
1837 |
|
|
cp = asn_build_int(cp, out_length,
|
1838 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
1839 |
|
|
&pdu->msgid, sizeof(pdu->msgid));
|
1840 |
|
|
if (cp == NULL) return NULL;
|
1841 |
|
|
|
1842 |
|
|
/* msgMaxSize */
|
1843 |
|
|
max_size = SNMP_MAX_MSG_SIZE;
|
1844 |
|
|
cp = asn_build_int(cp, out_length,
|
1845 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
1846 |
|
|
&max_size, sizeof(max_size));
|
1847 |
|
|
if (cp == NULL) return NULL;
|
1848 |
|
|
|
1849 |
|
|
/* msgFlags */
|
1850 |
|
|
snmpv3_calc_msg_flags(pdu->securityLevel, pdu->command, &msg_flags);
|
1851 |
|
|
cp = asn_build_string(cp, out_length,
|
1852 |
|
|
(u_char)(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
|
1853 |
|
|
&msg_flags, sizeof(msg_flags));
|
1854 |
|
|
if (cp == NULL) return NULL;
|
1855 |
|
|
|
1856 |
|
|
/* msgSecurityModel */
|
1857 |
|
|
sec_model = SNMP_SEC_MODEL_USM;
|
1858 |
|
|
cp = asn_build_int(cp, out_length,
|
1859 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
1860 |
|
|
&sec_model, sizeof(sec_model));
|
1861 |
|
|
if (cp == NULL) return NULL;
|
1862 |
|
|
|
1863 |
|
|
|
1864 |
|
|
/* insert actual length of globalData
|
1865 |
|
|
*/
|
1866 |
|
|
pb = asn_build_sequence(global_hdr, out_length,
|
1867 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
|
1868 |
|
|
cp - global_hdr_e);
|
1869 |
|
|
if (pb == NULL) return NULL;
|
1870 |
|
|
|
1871 |
|
|
|
1872 |
|
|
/* insert the actual length of the entire packet
|
1873 |
|
|
*/
|
1874 |
|
|
pb = asn_build_sequence(packet, out_length,
|
1875 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
|
1876 |
|
|
length + (cp - pb0e));
|
1877 |
|
|
if (pb == NULL) return NULL;
|
1878 |
|
|
|
1879 |
|
|
return cp;
|
1880 |
|
|
|
1881 |
|
|
} /* end snmpv3_header_build() */
|
1882 |
|
|
|
1883 |
|
|
|
1884 |
|
|
|
1885 |
|
|
static u_char *
|
1886 |
|
|
snmpv3_scopedPDU_header_build(struct snmp_pdu *pdu,
|
1887 |
|
|
u_char *packet, size_t *out_length,
|
1888 |
|
|
u_char **spdu_e)
|
1889 |
|
|
|
1890 |
|
|
{
|
1891 |
|
|
size_t init_length;
|
1892 |
|
|
u_char *scopedPdu, *pb;
|
1893 |
|
|
|
1894 |
|
|
|
1895 |
|
|
init_length = *out_length;
|
1896 |
|
|
|
1897 |
|
|
pb = scopedPdu = packet;
|
1898 |
|
|
pb = asn_build_sequence(pb, out_length,
|
1899 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0);
|
1900 |
|
|
if (pb == NULL) return NULL;
|
1901 |
|
|
if (spdu_e)
|
1902 |
|
|
*spdu_e = pb;
|
1903 |
|
|
|
1904 |
|
|
pb = asn_build_string(pb, out_length,
|
1905 |
|
|
(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
|
1906 |
|
|
pdu->contextEngineID, pdu->contextEngineIDLen);
|
1907 |
|
|
if (pb == NULL) return NULL;
|
1908 |
|
|
|
1909 |
|
|
pb = asn_build_string(pb, out_length,
|
1910 |
|
|
(ASN_UNIVERSAL|ASN_PRIMITIVE|ASN_OCTET_STR),
|
1911 |
|
|
(u_char *)pdu->contextName, pdu->contextNameLen);
|
1912 |
|
|
if (pb == NULL) return NULL;
|
1913 |
|
|
|
1914 |
|
|
return pb;
|
1915 |
|
|
|
1916 |
|
|
} /* end snmpv3_scopedPDU_header_build() */
|
1917 |
|
|
|
1918 |
|
|
|
1919 |
|
|
/* returns 0 if success, -1 if fail, not 0 if USM build failure */
|
1920 |
|
|
int
|
1921 |
|
|
snmpv3_packet_build(struct snmp_pdu *pdu, u_char *packet, size_t *out_length,
|
1922 |
|
|
u_char *pdu_data, size_t pdu_data_len)
|
1923 |
|
|
{
|
1924 |
|
|
u_char *global_data, *sec_params, *spdu_hdr_e;
|
1925 |
|
|
size_t global_data_len, sec_params_len;
|
1926 |
|
|
u_char spdu_buf[SNMP_MAX_MSG_SIZE];
|
1927 |
|
|
size_t spdu_buf_len, spdu_len;
|
1928 |
|
|
u_char *cp;
|
1929 |
|
|
int result;
|
1930 |
|
|
|
1931 |
|
|
global_data = packet;
|
1932 |
|
|
|
1933 |
|
|
/*
|
1934 |
|
|
* build the headers for the packet, returned addr = start of secParams
|
1935 |
|
|
*/
|
1936 |
|
|
sec_params = snmpv3_header_build(pdu, global_data, out_length, 0, NULL);
|
1937 |
|
|
if (sec_params == NULL) return -1;
|
1938 |
|
|
global_data_len = sec_params - global_data;
|
1939 |
|
|
sec_params_len = *out_length; /* length left in packet buf for sec_params */
|
1940 |
|
|
|
1941 |
|
|
|
1942 |
|
|
/*
|
1943 |
|
|
* build a scopedPDU structure into spdu_buf
|
1944 |
|
|
*/
|
1945 |
|
|
spdu_buf_len = SNMP_MAX_MSG_SIZE;
|
1946 |
|
|
cp = snmpv3_scopedPDU_header_build(pdu,spdu_buf,&spdu_buf_len,&spdu_hdr_e);
|
1947 |
|
|
if (cp == NULL) return -1;
|
1948 |
|
|
|
1949 |
|
|
/* build the PDU structure onto the end of spdu_buf
|
1950 |
|
|
*/
|
1951 |
|
|
if (pdu_data) {
|
1952 |
|
|
memcpy(cp, pdu_data, pdu_data_len);
|
1953 |
|
|
cp += pdu_data_len;
|
1954 |
|
|
} else {
|
1955 |
|
|
cp = snmp_pdu_build(pdu, cp, &spdu_buf_len);
|
1956 |
|
|
if (cp == NULL) return -1;
|
1957 |
|
|
}
|
1958 |
|
|
|
1959 |
|
|
|
1960 |
|
|
/*
|
1961 |
|
|
* re-encode the actual ASN.1 length of the scopedPdu
|
1962 |
|
|
*/
|
1963 |
|
|
spdu_len = cp - spdu_hdr_e; /* length of scopedPdu minus ASN.1 headers */
|
1964 |
|
|
spdu_buf_len = SNMP_MAX_MSG_SIZE;
|
1965 |
|
|
if (asn_build_sequence(spdu_buf, &spdu_buf_len,
|
1966 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
|
1967 |
|
|
spdu_len) == NULL)
|
1968 |
|
|
return -1;
|
1969 |
|
|
spdu_len = cp - spdu_buf; /* the length of the entire scopedPdu */
|
1970 |
|
|
|
1971 |
|
|
|
1972 |
|
|
/*
|
1973 |
|
|
* call the security module to possibly encrypt and authenticate the
|
1974 |
|
|
* message - the entire message to transmitted on the wire is returned
|
1975 |
|
|
*/
|
1976 |
|
|
cp = NULL; *out_length = SNMP_MAX_MSG_SIZE;
|
1977 |
|
|
result =
|
1978 |
|
|
usm_generate_out_msg(
|
1979 |
|
|
SNMP_VERSION_3,
|
1980 |
|
|
global_data, global_data_len,
|
1981 |
|
|
SNMP_MAX_MSG_SIZE,
|
1982 |
|
|
SNMP_SEC_MODEL_USM,
|
1983 |
|
|
pdu->securityEngineID, pdu->securityEngineIDLen,
|
1984 |
|
|
pdu->securityName, pdu->securityNameLen,
|
1985 |
|
|
pdu->securityLevel,
|
1986 |
|
|
spdu_buf, spdu_len,
|
1987 |
|
|
pdu->securityStateRef,
|
1988 |
|
|
sec_params, &sec_params_len,
|
1989 |
|
|
&cp, out_length);
|
1990 |
|
|
|
1991 |
|
|
return result;
|
1992 |
|
|
|
1993 |
|
|
} /* end snmpv3_packet_build() */
|
1994 |
|
|
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
|
1995 |
|
|
|
1996 |
|
|
|
1997 |
|
|
/*
|
1998 |
|
|
* Takes a session and a pdu and serializes the ASN PDU into the area
|
1999 |
|
|
* pointed to by packet. out_length is the size of the data area available.
|
2000 |
|
|
* Returns the length of the completed packet in out_length. If any errors
|
2001 |
|
|
* occur, -1 is returned. If all goes well, 0 is returned.
|
2002 |
|
|
*/
|
2003 |
|
|
static int
|
2004 |
|
|
_snmp_build(struct snmp_session *session,
|
2005 |
|
|
struct snmp_pdu *pdu,
|
2006 |
|
|
u_char *packet,
|
2007 |
|
|
size_t *out_length)
|
2008 |
|
|
{
|
2009 |
|
|
u_char *h0, *h0e = 0, *h1;
|
2010 |
|
|
u_char *cp;
|
2011 |
|
|
size_t length;
|
2012 |
|
|
long version;
|
2013 |
|
|
|
2014 |
|
|
session->s_snmp_errno = 0;
|
2015 |
|
|
session->s_errno = 0;
|
2016 |
|
|
|
2017 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
2018 |
|
|
if (pdu->version == SNMP_VERSION_3)
|
2019 |
|
|
return snmpv3_build(session, pdu, packet, out_length);
|
2020 |
|
|
#endif
|
2021 |
|
|
|
2022 |
|
|
switch (pdu->command) {
|
2023 |
|
|
case SNMP_MSG_RESPONSE:
|
2024 |
|
|
pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
|
2025 |
|
|
/* Fallthrough */
|
2026 |
|
|
case SNMP_MSG_GET:
|
2027 |
|
|
case SNMP_MSG_GETNEXT:
|
2028 |
|
|
case SNMP_MSG_SET:
|
2029 |
|
|
/* all versions support these PDU types */
|
2030 |
|
|
/* initialize defaulted PDU fields */
|
2031 |
|
|
|
2032 |
|
|
if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
|
2033 |
|
|
pdu->errstat = 0;
|
2034 |
|
|
if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
|
2035 |
|
|
pdu->errindex = 0;
|
2036 |
|
|
break;
|
2037 |
|
|
|
2038 |
|
|
case SNMP_MSG_TRAP2:
|
2039 |
|
|
pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
|
2040 |
|
|
/* Fallthrough */
|
2041 |
|
|
case SNMP_MSG_INFORM:
|
2042 |
|
|
/* not supported in SNMPv1 and SNMPsec */
|
2043 |
|
|
if (pdu->version == SNMP_VERSION_1) {
|
2044 |
|
|
session->s_snmp_errno = SNMPERR_V2_IN_V1;
|
2045 |
|
|
return -1;
|
2046 |
|
|
}
|
2047 |
|
|
if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
|
2048 |
|
|
pdu->errstat = 0;
|
2049 |
|
|
if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
|
2050 |
|
|
pdu->errindex = 0;
|
2051 |
|
|
break;
|
2052 |
|
|
|
2053 |
|
|
case SNMP_MSG_GETBULK:
|
2054 |
|
|
/* not supported in SNMPv1 and SNMPsec */
|
2055 |
|
|
if (pdu->version == SNMP_VERSION_1) {
|
2056 |
|
|
session->s_snmp_errno = SNMPERR_V2_IN_V1;
|
2057 |
|
|
return -1;
|
2058 |
|
|
}
|
2059 |
|
|
if (pdu->max_repetitions < 0) {
|
2060 |
|
|
session->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
|
2061 |
|
|
return -1;
|
2062 |
|
|
}
|
2063 |
|
|
if (pdu->non_repeaters < 0) {
|
2064 |
|
|
session->s_snmp_errno = SNMPERR_BAD_REPEATERS;
|
2065 |
|
|
return -1;
|
2066 |
|
|
}
|
2067 |
|
|
break;
|
2068 |
|
|
|
2069 |
|
|
case SNMP_MSG_TRAP:
|
2070 |
|
|
/* *only* supported in SNMPv1 and SNMPsec */
|
2071 |
|
|
if (pdu->version != SNMP_VERSION_1) {
|
2072 |
|
|
session->s_snmp_errno = SNMPERR_V1_IN_V2;
|
2073 |
|
|
return -1;
|
2074 |
|
|
}
|
2075 |
|
|
/* initialize defaulted Trap PDU fields */
|
2076 |
|
|
pdu->reqid = 1; /* give a bogus non-error reqid for traps */
|
2077 |
|
|
if (pdu->enterprise_length == SNMP_DEFAULT_ENTERPRISE_LENGTH){
|
2078 |
|
|
pdu->enterprise = (oid *)malloc(sizeof(DEFAULT_ENTERPRISE));
|
2079 |
|
|
memmove(pdu->enterprise, DEFAULT_ENTERPRISE,
|
2080 |
|
|
sizeof(DEFAULT_ENTERPRISE));
|
2081 |
|
|
pdu->enterprise_length = sizeof(DEFAULT_ENTERPRISE)/sizeof(oid);
|
2082 |
|
|
}
|
2083 |
|
|
if (pdu->time == SNMP_DEFAULT_TIME)
|
2084 |
|
|
pdu->time = DEFAULT_TIME;
|
2085 |
|
|
/* don't expect a response */
|
2086 |
|
|
pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
|
2087 |
|
|
break;
|
2088 |
|
|
|
2089 |
|
|
case SNMP_MSG_REPORT: /* SNMPv3 only */
|
2090 |
|
|
default:
|
2091 |
|
|
session->s_snmp_errno = SNMPERR_UNKNOWN_PDU;
|
2092 |
|
|
return -1;
|
2093 |
|
|
}
|
2094 |
|
|
|
2095 |
|
|
/* save length */
|
2096 |
|
|
length = *out_length;
|
2097 |
|
|
|
2098 |
|
|
/* setup administrative fields based on version */
|
2099 |
|
|
/* build the message wrapper and all the administrative fields
|
2100 |
|
|
upto the PDU sequence
|
2101 |
|
|
(note that actual length of message will be inserted later) */
|
2102 |
|
|
h0 = packet;
|
2103 |
|
|
switch (pdu->version) {
|
2104 |
|
|
case SNMP_VERSION_1:
|
2105 |
|
|
case SNMP_VERSION_2c:
|
2106 |
|
|
#ifdef NO_ZEROLENGTH_COMMUNITY
|
2107 |
|
|
if (pdu->community_len == 0){
|
2108 |
|
|
if (session->community_len == 0){
|
2109 |
|
|
session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
|
2110 |
|
|
return -1;
|
2111 |
|
|
}
|
2112 |
|
|
pdu->community = (u_char *)malloc(session->community_len);
|
2113 |
|
|
memmove(pdu->community, session->community,
|
2114 |
|
|
session->community_len);
|
2115 |
|
|
pdu->community_len = session->community_len;
|
2116 |
|
|
}
|
2117 |
|
|
#else /* !NO_ZEROLENGTH_COMMUNITY */
|
2118 |
|
|
if (! (pdu->community_len != 0 &&
|
2119 |
|
|
pdu->command == SNMP_MSG_RESPONSE )) {
|
2120 |
|
|
/* copy session community exactly to pdu community */
|
2121 |
|
|
if (0 == session->community_len) {
|
2122 |
|
|
SNMP_FREE(pdu->community); pdu->community = 0;
|
2123 |
|
|
}
|
2124 |
|
|
else if (pdu->community_len == session->community_len) {
|
2125 |
|
|
memmove(pdu->community, session->community,
|
2126 |
|
|
session->community_len);
|
2127 |
|
|
}
|
2128 |
|
|
else {
|
2129 |
|
|
SNMP_FREE(pdu->community);
|
2130 |
|
|
pdu->community = (u_char *)malloc(session->community_len);
|
2131 |
|
|
memmove(pdu->community, session->community,
|
2132 |
|
|
session->community_len);
|
2133 |
|
|
}
|
2134 |
|
|
pdu->community_len = session->community_len;
|
2135 |
|
|
}
|
2136 |
|
|
#endif /* !NO_ZEROLENGTH_COMMUNITY */
|
2137 |
|
|
|
2138 |
|
|
DEBUGMSGTL(("snmp_send","Building SNMPv%d message...\n", (1 + pdu->version)));
|
2139 |
|
|
/* Save current location and build SEQUENCE tag and length
|
2140 |
|
|
placeholder for SNMP message sequence
|
2141 |
|
|
(actual length will be inserted later) */
|
2142 |
|
|
cp = asn_build_sequence(packet, out_length,
|
2143 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
|
2144 |
|
|
0);
|
2145 |
|
|
if (cp == NULL)
|
2146 |
|
|
return -1;
|
2147 |
|
|
h0e = cp;
|
2148 |
|
|
|
2149 |
|
|
/* store the version field */
|
2150 |
|
|
version = pdu->version;
|
2151 |
|
|
cp = asn_build_int(cp, out_length,
|
2152 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
2153 |
|
|
(long *) &version, sizeof(version));
|
2154 |
|
|
if (cp == NULL)
|
2155 |
|
|
return -1;
|
2156 |
|
|
|
2157 |
|
|
/* store the community string */
|
2158 |
|
|
cp = asn_build_string(cp, out_length,
|
2159 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
|
2160 |
|
|
pdu->community, pdu->community_len);
|
2161 |
|
|
if (cp == NULL)
|
2162 |
|
|
return -1;
|
2163 |
|
|
break;
|
2164 |
|
|
|
2165 |
|
|
case SNMP_VERSION_2p:
|
2166 |
|
|
case SNMP_VERSION_sec:
|
2167 |
|
|
case SNMP_VERSION_2u:
|
2168 |
|
|
case SNMP_VERSION_2star:
|
2169 |
|
|
default:
|
2170 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
2171 |
|
|
return -1;
|
2172 |
|
|
}
|
2173 |
|
|
|
2174 |
|
|
h1 = cp;
|
2175 |
|
|
cp = snmp_pdu_build(pdu, cp, out_length);
|
2176 |
|
|
if (cp == NULL)
|
2177 |
|
|
return -1;
|
2178 |
|
|
|
2179 |
|
|
/* insert the actual length of the message sequence */
|
2180 |
|
|
switch (pdu->version) {
|
2181 |
|
|
case SNMP_VERSION_1:
|
2182 |
|
|
case SNMP_VERSION_2c:
|
2183 |
|
|
asn_build_sequence(packet, &length,
|
2184 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
|
2185 |
|
|
cp - h0e);
|
2186 |
|
|
break;
|
2187 |
|
|
|
2188 |
|
|
case SNMP_VERSION_2p:
|
2189 |
|
|
case SNMP_VERSION_sec:
|
2190 |
|
|
case SNMP_VERSION_2u:
|
2191 |
|
|
case SNMP_VERSION_2star:
|
2192 |
|
|
default:
|
2193 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
2194 |
|
|
return -1;
|
2195 |
|
|
}
|
2196 |
|
|
*out_length = cp - packet;
|
2197 |
|
|
return 0;
|
2198 |
|
|
}
|
2199 |
|
|
|
2200 |
|
|
int
|
2201 |
|
|
snmp_build(struct snmp_session *pss,
|
2202 |
|
|
struct snmp_pdu *pdu,
|
2203 |
|
|
u_char *packet,
|
2204 |
|
|
size_t *out_length)
|
2205 |
|
|
{
|
2206 |
|
|
int rc;
|
2207 |
|
|
rc = _snmp_build(pss,pdu,packet,out_length);
|
2208 |
|
|
if (rc) {
|
2209 |
|
|
if ( !pss->s_snmp_errno)
|
2210 |
|
|
pss->s_snmp_errno = SNMPERR_BAD_ASN1_BUILD;
|
2211 |
|
|
SET_SNMP_ERROR(pss->s_snmp_errno);
|
2212 |
|
|
rc = -1;
|
2213 |
|
|
}
|
2214 |
|
|
return rc;
|
2215 |
|
|
}
|
2216 |
|
|
|
2217 |
|
|
/* on error, returns NULL (likely an encoding problem). */
|
2218 |
|
|
u_char *
|
2219 |
|
|
snmp_pdu_build (struct snmp_pdu *pdu, u_char *cp, size_t *out_length)
|
2220 |
|
|
{
|
2221 |
|
|
u_char *h1, *h1e, *h2, *h2e;
|
2222 |
|
|
struct variable_list *vp;
|
2223 |
|
|
struct sockaddr_in *pduIp = (struct sockaddr_in *)&(pdu->agent_addr);
|
2224 |
|
|
size_t length;
|
2225 |
|
|
|
2226 |
|
|
length = *out_length;
|
2227 |
|
|
/* Save current location and build PDU tag and length placeholder
|
2228 |
|
|
(actual length will be inserted later) */
|
2229 |
|
|
h1 = cp;
|
2230 |
|
|
cp = asn_build_sequence(cp, out_length, (u_char)pdu->command, 0);
|
2231 |
|
|
if (cp == NULL)
|
2232 |
|
|
return NULL;
|
2233 |
|
|
h1e = cp;
|
2234 |
|
|
|
2235 |
|
|
/* store fields in the PDU preceeding the variable-bindings sequence */
|
2236 |
|
|
if (pdu->command != SNMP_MSG_TRAP){
|
2237 |
|
|
/* PDU is not an SNMPv1 trap */
|
2238 |
|
|
|
2239 |
|
|
/* request id */
|
2240 |
|
|
cp = asn_build_int(cp, out_length,
|
2241 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
2242 |
|
|
&pdu->reqid, sizeof(pdu->reqid));
|
2243 |
|
|
if (cp == NULL)
|
2244 |
|
|
return NULL;
|
2245 |
|
|
|
2246 |
|
|
/* error status (getbulk non-repeaters) */
|
2247 |
|
|
cp = asn_build_int(cp, out_length,
|
2248 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
2249 |
|
|
&pdu->errstat, sizeof(pdu->errstat));
|
2250 |
|
|
if (cp == NULL)
|
2251 |
|
|
return NULL;
|
2252 |
|
|
|
2253 |
|
|
/* error index (getbulk max-repetitions) */
|
2254 |
|
|
cp = asn_build_int(cp, out_length,
|
2255 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
2256 |
|
|
&pdu->errindex, sizeof(pdu->errindex));
|
2257 |
|
|
if (cp == NULL)
|
2258 |
|
|
return NULL;
|
2259 |
|
|
} else {
|
2260 |
|
|
/* an SNMPv1 trap PDU */
|
2261 |
|
|
|
2262 |
|
|
/* enterprise */
|
2263 |
|
|
cp = asn_build_objid(cp, out_length,
|
2264 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
|
2265 |
|
|
(oid *)pdu->enterprise, pdu->enterprise_length);
|
2266 |
|
|
if (cp == NULL)
|
2267 |
|
|
return NULL;
|
2268 |
|
|
|
2269 |
|
|
/* agent-addr */
|
2270 |
|
|
cp = asn_build_string(cp, out_length,
|
2271 |
|
|
(u_char)(ASN_IPADDRESS | ASN_PRIMITIVE),
|
2272 |
|
|
(u_char *)&pduIp->sin_addr.s_addr,
|
2273 |
|
|
sizeof(pduIp->sin_addr.s_addr));
|
2274 |
|
|
if (cp == NULL)
|
2275 |
|
|
return NULL;
|
2276 |
|
|
|
2277 |
|
|
/* generic trap */
|
2278 |
|
|
cp = asn_build_int(cp, out_length,
|
2279 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
2280 |
|
|
(long *)&pdu->trap_type, sizeof(pdu->trap_type));
|
2281 |
|
|
if (cp == NULL)
|
2282 |
|
|
return NULL;
|
2283 |
|
|
|
2284 |
|
|
/* specific trap */
|
2285 |
|
|
cp = asn_build_int(cp, out_length,
|
2286 |
|
|
(u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
|
2287 |
|
|
(long *)&pdu->specific_type, sizeof(pdu->specific_type));
|
2288 |
|
|
if (cp == NULL)
|
2289 |
|
|
return NULL;
|
2290 |
|
|
|
2291 |
|
|
/* timestamp */
|
2292 |
|
|
cp = asn_build_unsigned_int(cp, out_length,
|
2293 |
|
|
(u_char)(ASN_TIMETICKS | ASN_PRIMITIVE),
|
2294 |
|
|
&pdu->time, sizeof(pdu->time));
|
2295 |
|
|
if (cp == NULL)
|
2296 |
|
|
return NULL;
|
2297 |
|
|
}
|
2298 |
|
|
|
2299 |
|
|
/* Save current location and build SEQUENCE tag and length placeholder
|
2300 |
|
|
for variable-bindings sequence
|
2301 |
|
|
(actual length will be inserted later) */
|
2302 |
|
|
h2 = cp;
|
2303 |
|
|
cp = asn_build_sequence(cp, out_length,
|
2304 |
|
|
(u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
|
2305 |
|
|
0);
|
2306 |
|
|
if (cp == NULL)
|
2307 |
|
|
return NULL;
|
2308 |
|
|
h2e = cp;
|
2309 |
|
|
|
2310 |
|
|
/* Store variable-bindings */
|
2311 |
|
|
for(vp = pdu->variables; vp; vp = vp->next_variable){
|
2312 |
|
|
cp = snmp_build_var_op(cp, vp->name, &vp->name_length, vp->type,
|
2313 |
|
|
vp->val_len, (u_char *)vp->val.string,
|
2314 |
|
|
out_length);
|
2315 |
|
|
if (cp == NULL)
|
2316 |
|
|
return NULL;
|
2317 |
|
|
}
|
2318 |
|
|
|
2319 |
|
|
/* insert actual length of variable-bindings sequence */
|
2320 |
|
|
asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),cp-h2e);
|
2321 |
|
|
|
2322 |
|
|
/* insert actual length of PDU sequence */
|
2323 |
|
|
asn_build_sequence(h1, &length, (u_char)pdu->command, cp - h1e);
|
2324 |
|
|
|
2325 |
|
|
return cp;
|
2326 |
|
|
}
|
2327 |
|
|
|
2328 |
|
|
|
2329 |
|
|
/*
|
2330 |
|
|
* Parses the packet received to determine version, either directly
|
2331 |
|
|
* from packets version field or inferred from ASN.1 construct.
|
2332 |
|
|
*/
|
2333 |
|
|
static int
|
2334 |
|
|
snmp_parse_version (u_char *data, size_t length)
|
2335 |
|
|
{
|
2336 |
|
|
u_char type;
|
2337 |
|
|
long version = SNMPERR_BAD_VERSION;
|
2338 |
|
|
|
2339 |
|
|
data = asn_parse_sequence(data, &length, &type,
|
2340 |
|
|
(ASN_SEQUENCE | ASN_CONSTRUCTOR), "version");
|
2341 |
|
|
if (data) {
|
2342 |
|
|
data = asn_parse_int(data, &length, &type, &version, sizeof(version));
|
2343 |
|
|
if (!data) return SNMPERR_BAD_VERSION;
|
2344 |
|
|
}
|
2345 |
|
|
return version;
|
2346 |
|
|
}
|
2347 |
|
|
|
2348 |
|
|
|
2349 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
2350 |
|
|
int
|
2351 |
|
|
snmpv3_parse(
|
2352 |
|
|
struct snmp_pdu *pdu,
|
2353 |
|
|
u_char *data,
|
2354 |
|
|
size_t *length,
|
2355 |
|
|
u_char **after_header)
|
2356 |
|
|
{
|
2357 |
|
|
u_char type, msg_flags;
|
2358 |
|
|
long ver, msg_max_size, msg_sec_model;
|
2359 |
|
|
size_t max_size_response;
|
2360 |
|
|
u_char tmp_buf[SNMP_MAX_MSG_SIZE];
|
2361 |
|
|
size_t tmp_buf_len;
|
2362 |
|
|
u_char pdu_buf[SNMP_MAX_MSG_SIZE];
|
2363 |
|
|
size_t pdu_buf_len = SNMP_MAX_MSG_SIZE;
|
2364 |
|
|
u_char *sec_params;
|
2365 |
|
|
u_char *msg_data;
|
2366 |
|
|
u_char *cp;
|
2367 |
|
|
size_t asn_len, msg_len;
|
2368 |
|
|
int ret, ret_val;
|
2369 |
|
|
|
2370 |
|
|
|
2371 |
|
|
msg_data = data;
|
2372 |
|
|
msg_len = *length;
|
2373 |
|
|
|
2374 |
|
|
|
2375 |
|
|
/* message is an ASN.1 SEQUENCE
|
2376 |
|
|
*/
|
2377 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing SNMPv3 Message\n");
|
2378 |
|
|
data = asn_parse_sequence(data, length, &type,
|
2379 |
|
|
(ASN_SEQUENCE | ASN_CONSTRUCTOR), "message");
|
2380 |
|
|
if (data == NULL){
|
2381 |
|
|
/* error msg detail is set */
|
2382 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2383 |
|
|
DEBUGINDENTLESS();
|
2384 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2385 |
|
|
}
|
2386 |
|
|
|
2387 |
|
|
/* parse msgVersion
|
2388 |
|
|
*/
|
2389 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing SNMPv3 Version Number\n");
|
2390 |
|
|
data = asn_parse_int(data, length, &type, &ver, sizeof(ver));
|
2391 |
|
|
DEBUGINDENTLESS();
|
2392 |
|
|
if (data == NULL){
|
2393 |
|
|
ERROR_MSG("bad parse of version");
|
2394 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2395 |
|
|
DEBUGINDENTLESS();
|
2396 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2397 |
|
|
}
|
2398 |
|
|
pdu->version = ver;
|
2399 |
|
|
|
2400 |
|
|
/* parse msgGlobalData sequence
|
2401 |
|
|
*/
|
2402 |
|
|
cp = data;
|
2403 |
|
|
asn_len = *length;
|
2404 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing msgGlobalData\n");
|
2405 |
|
|
data = asn_parse_sequence(data, &asn_len, &type,
|
2406 |
|
|
(ASN_SEQUENCE | ASN_CONSTRUCTOR), "msgGlobalData");
|
2407 |
|
|
if (data == NULL){
|
2408 |
|
|
/* error msg detail is set */
|
2409 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2410 |
|
|
DEBUGINDENTADD(-4);
|
2411 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2412 |
|
|
}
|
2413 |
|
|
*length -= data - cp; /* subtract off the length of the header */
|
2414 |
|
|
|
2415 |
|
|
/* msgID */
|
2416 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing msgID\n");
|
2417 |
|
|
data = asn_parse_int(data, length, &type, &pdu->msgid, sizeof(pdu->msgid));
|
2418 |
|
|
DEBUGINDENTLESS();
|
2419 |
|
|
if (data == NULL) {
|
2420 |
|
|
ERROR_MSG("error parsing msgID");
|
2421 |
|
|
DEBUGINDENTADD(-4);
|
2422 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2423 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2424 |
|
|
}
|
2425 |
|
|
|
2426 |
|
|
/* msgMaxSize */
|
2427 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing msgMaxSize\n");
|
2428 |
|
|
data = asn_parse_int(data, length, &type, &msg_max_size,
|
2429 |
|
|
sizeof(msg_max_size));
|
2430 |
|
|
DEBUGINDENTLESS();
|
2431 |
|
|
if (data == NULL) {
|
2432 |
|
|
ERROR_MSG("error parsing msgMaxSize");
|
2433 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2434 |
|
|
DEBUGINDENTADD(-4);
|
2435 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2436 |
|
|
}
|
2437 |
|
|
|
2438 |
|
|
/* msgFlags */
|
2439 |
|
|
tmp_buf_len = SNMP_MAX_MSG_SIZE;
|
2440 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing msgFlags\n");
|
2441 |
|
|
data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
|
2442 |
|
|
DEBUGINDENTLESS();
|
2443 |
|
|
if (data == NULL || tmp_buf_len != 1) {
|
2444 |
|
|
ERROR_MSG("error parsing msgFlags");
|
2445 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2446 |
|
|
DEBUGINDENTADD(-4);
|
2447 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2448 |
|
|
}
|
2449 |
|
|
msg_flags = *tmp_buf;
|
2450 |
|
|
if (msg_flags & SNMP_MSG_FLAG_RPRT_BIT)
|
2451 |
|
|
pdu->flags |= SNMP_MSG_FLAG_RPRT_BIT;
|
2452 |
|
|
else
|
2453 |
|
|
pdu->flags &= (~SNMP_MSG_FLAG_RPRT_BIT);
|
2454 |
|
|
|
2455 |
|
|
/* msgSecurityModel */
|
2456 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing msgSecurityModel\n");
|
2457 |
|
|
data = asn_parse_int(data, length, &type, &msg_sec_model,
|
2458 |
|
|
sizeof(msg_sec_model));
|
2459 |
|
|
DEBUGINDENTADD(-4); /* return from global data indent */
|
2460 |
|
|
if (data == NULL) {
|
2461 |
|
|
ERROR_MSG("error parsing msgSecurityModel");
|
2462 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2463 |
|
|
DEBUGINDENTLESS();
|
2464 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2465 |
|
|
}
|
2466 |
|
|
if (msg_sec_model != SNMP_SEC_MODEL_USM) {
|
2467 |
|
|
ERROR_MSG("unknown security model");
|
2468 |
|
|
snmp_increment_statistic(STAT_SNMPUNKNOWNSECURITYMODELS);
|
2469 |
|
|
DEBUGINDENTLESS();
|
2470 |
|
|
return SNMPERR_UNKNOWN_SEC_MODEL;
|
2471 |
|
|
}
|
2472 |
|
|
pdu->securityModel = msg_sec_model;
|
2473 |
|
|
|
2474 |
|
|
if (msg_flags & SNMP_MSG_FLAG_PRIV_BIT &&
|
2475 |
|
|
!(msg_flags & SNMP_MSG_FLAG_AUTH_BIT)) {
|
2476 |
|
|
ERROR_MSG("invalid message, illegal msgFlags");
|
2477 |
|
|
snmp_increment_statistic(STAT_SNMPINVALIDMSGS);
|
2478 |
|
|
DEBUGINDENTLESS();
|
2479 |
|
|
return SNMPERR_INVALID_MSG;
|
2480 |
|
|
}
|
2481 |
|
|
pdu->securityLevel = ( (msg_flags & SNMP_MSG_FLAG_AUTH_BIT)
|
2482 |
|
|
? ( (msg_flags & SNMP_MSG_FLAG_PRIV_BIT)
|
2483 |
|
|
? SNMP_SEC_LEVEL_AUTHPRIV
|
2484 |
|
|
: SNMP_SEC_LEVEL_AUTHNOPRIV )
|
2485 |
|
|
: SNMP_SEC_LEVEL_NOAUTH );
|
2486 |
|
|
/* end of msgGlobalData */
|
2487 |
|
|
|
2488 |
|
|
/* securtityParameters OCTET STRING begins after msgGlobalData */
|
2489 |
|
|
sec_params = data;
|
2490 |
|
|
pdu->contextEngineID = (u_char *)calloc(1,SNMP_MAX_ENG_SIZE);
|
2491 |
|
|
pdu->contextEngineIDLen = SNMP_MAX_ENG_SIZE;
|
2492 |
|
|
pdu->securityEngineID = (u_char *)calloc(1,SNMP_MAX_ENG_SIZE);
|
2493 |
|
|
pdu->securityEngineIDLen = SNMP_MAX_ENG_SIZE;
|
2494 |
|
|
pdu->securityName = (char *)calloc(1,SNMP_MAX_SEC_NAME_SIZE);
|
2495 |
|
|
pdu->securityNameLen = SNMP_MAX_SEC_NAME_SIZE;
|
2496 |
|
|
|
2497 |
|
|
memset(pdu_buf, 0, pdu_buf_len);
|
2498 |
|
|
cp = pdu_buf;
|
2499 |
|
|
|
2500 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing USM msgSecurityParameters\n");
|
2501 |
|
|
ret_val = usm_process_in_msg(SNMP_VERSION_3, msg_max_size,
|
2502 |
|
|
sec_params, msg_sec_model, pdu->securityLevel,
|
2503 |
|
|
msg_data, msg_len,
|
2504 |
|
|
pdu->securityEngineID, &pdu->securityEngineIDLen,
|
2505 |
|
|
pdu->securityName, &pdu->securityNameLen,
|
2506 |
|
|
&cp,
|
2507 |
|
|
&pdu_buf_len, &max_size_response,
|
2508 |
|
|
&pdu->securityStateRef);
|
2509 |
|
|
DEBUGINDENTLESS();
|
2510 |
|
|
|
2511 |
|
|
if (ret_val != SNMPERR_SUCCESS) {
|
2512 |
|
|
snmpv3_scopedPDU_parse(pdu, cp, &pdu_buf_len); /* DO ignore return code */
|
2513 |
|
|
DEBUGINDENTLESS();
|
2514 |
|
|
return ret_val;
|
2515 |
|
|
}
|
2516 |
|
|
|
2517 |
|
|
/* parse plaintext ScopedPDU sequence */
|
2518 |
|
|
*length = pdu_buf_len;
|
2519 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing ScopedPdu\n");
|
2520 |
|
|
data = snmpv3_scopedPDU_parse(pdu, cp, length);
|
2521 |
|
|
if (data == NULL) {
|
2522 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2523 |
|
|
DEBUGINDENTADD(-4);
|
2524 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2525 |
|
|
}
|
2526 |
|
|
|
2527 |
|
|
/* parse the PDU.
|
2528 |
|
|
*/
|
2529 |
|
|
if (after_header != NULL) {
|
2530 |
|
|
tmp_buf_len = *length;
|
2531 |
|
|
*after_header = data;
|
2532 |
|
|
}
|
2533 |
|
|
|
2534 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing PDU\n");
|
2535 |
|
|
ret = snmp_pdu_parse(pdu, data, length);
|
2536 |
|
|
DEBUGINDENTADD(-8);
|
2537 |
|
|
|
2538 |
|
|
if (after_header != NULL)
|
2539 |
|
|
*length = tmp_buf_len;
|
2540 |
|
|
|
2541 |
|
|
if (ret != SNMPERR_SUCCESS) {
|
2542 |
|
|
ERROR_MSG("error parsing PDU");
|
2543 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2544 |
|
|
return SNMPERR_ASN_PARSE_ERR;
|
2545 |
|
|
}
|
2546 |
|
|
|
2547 |
|
|
return SNMPERR_SUCCESS;
|
2548 |
|
|
} /* end snmpv3_parse() */
|
2549 |
|
|
|
2550 |
|
|
#define ERROR_STAT_LENGTH 11
|
2551 |
|
|
|
2552 |
|
|
int
|
2553 |
|
|
snmpv3_make_report(struct snmp_pdu *pdu, int error)
|
2554 |
|
|
{
|
2555 |
|
|
|
2556 |
|
|
long ltmp;
|
2557 |
|
|
static oid unknownSecurityLevel[] = {1,3,6,1,6,3,15,1,1,1,0};
|
2558 |
|
|
static oid notInTimeWindow[] = {1,3,6,1,6,3,15,1,1,2,0};
|
2559 |
|
|
static oid unknownUserName[] = {1,3,6,1,6,3,15,1,1,3,0};
|
2560 |
|
|
static oid unknownEngineID[] = {1,3,6,1,6,3,15,1,1,4,0};
|
2561 |
|
|
static oid wrongDigest[] = {1,3,6,1,6,3,15,1,1,5,0};
|
2562 |
|
|
static oid decryptionError[] = {1,3,6,1,6,3,15,1,1,6,0};
|
2563 |
|
|
oid *err_var;
|
2564 |
|
|
int err_var_len;
|
2565 |
|
|
int stat_ind;
|
2566 |
|
|
|
2567 |
|
|
switch (error) {
|
2568 |
|
|
case SNMPERR_USM_UNKNOWNENGINEID:
|
2569 |
|
|
stat_ind = STAT_USMSTATSUNKNOWNENGINEIDS;
|
2570 |
|
|
err_var = unknownEngineID;
|
2571 |
|
|
err_var_len = ERROR_STAT_LENGTH;
|
2572 |
|
|
break;
|
2573 |
|
|
case SNMPERR_USM_UNKNOWNSECURITYNAME:
|
2574 |
|
|
stat_ind = STAT_USMSTATSUNKNOWNUSERNAMES;
|
2575 |
|
|
err_var = unknownUserName;
|
2576 |
|
|
err_var_len = ERROR_STAT_LENGTH;
|
2577 |
|
|
break;
|
2578 |
|
|
case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
|
2579 |
|
|
stat_ind = STAT_USMSTATSUNSUPPORTEDSECLEVELS;
|
2580 |
|
|
err_var = unknownSecurityLevel;
|
2581 |
|
|
err_var_len = ERROR_STAT_LENGTH;
|
2582 |
|
|
break;
|
2583 |
|
|
case SNMPERR_USM_AUTHENTICATIONFAILURE:
|
2584 |
|
|
stat_ind = STAT_USMSTATSWRONGDIGESTS;
|
2585 |
|
|
err_var = wrongDigest;
|
2586 |
|
|
err_var_len = ERROR_STAT_LENGTH;
|
2587 |
|
|
break;
|
2588 |
|
|
case SNMPERR_USM_NOTINTIMEWINDOW:
|
2589 |
|
|
stat_ind = STAT_USMSTATSNOTINTIMEWINDOWS;
|
2590 |
|
|
err_var = notInTimeWindow;
|
2591 |
|
|
err_var_len = ERROR_STAT_LENGTH;
|
2592 |
|
|
break;
|
2593 |
|
|
case SNMPERR_USM_DECRYPTIONERROR:
|
2594 |
|
|
stat_ind = STAT_USMSTATSDECRYPTIONERRORS;
|
2595 |
|
|
err_var = decryptionError;
|
2596 |
|
|
err_var_len = ERROR_STAT_LENGTH;
|
2597 |
|
|
break;
|
2598 |
|
|
default:
|
2599 |
|
|
return SNMPERR_GENERR;
|
2600 |
|
|
break;
|
2601 |
|
|
}
|
2602 |
|
|
|
2603 |
|
|
snmp_free_varbind(pdu->variables); /* free the current varbind */
|
2604 |
|
|
|
2605 |
|
|
pdu->variables = NULL;
|
2606 |
|
|
SNMP_FREE(pdu->securityEngineID);
|
2607 |
|
|
pdu->securityEngineID = snmpv3_generate_engineID(&pdu->securityEngineIDLen);
|
2608 |
|
|
SNMP_FREE(pdu->contextEngineID);
|
2609 |
|
|
pdu->contextEngineID = snmpv3_generate_engineID(&pdu->contextEngineIDLen);
|
2610 |
|
|
pdu->command = SNMP_MSG_REPORT;
|
2611 |
|
|
pdu->errstat = 0;
|
2612 |
|
|
pdu->errindex = 0;
|
2613 |
|
|
pdu->contextName = strdup("");
|
2614 |
|
|
pdu->contextNameLen = strlen(pdu->contextName);
|
2615 |
|
|
|
2616 |
|
|
/* reports shouldn't cache previous data. */
|
2617 |
|
|
/* FIX - yes they should but USM needs to follow new EoP to determine
|
2618 |
|
|
which cached values to use
|
2619 |
|
|
*/
|
2620 |
|
|
if (pdu->securityStateRef) {
|
2621 |
|
|
usm_free_usmStateReference(pdu->securityStateRef);
|
2622 |
|
|
pdu->securityStateRef = NULL;
|
2623 |
|
|
}
|
2624 |
|
|
|
2625 |
|
|
if (error != SNMPERR_USM_NOTINTIMEWINDOW)
|
2626 |
|
|
pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
|
2627 |
|
|
else
|
2628 |
|
|
pdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
|
2629 |
|
|
|
2630 |
|
|
/* find the appropriate error counter
|
2631 |
|
|
*/
|
2632 |
|
|
ltmp = snmp_get_statistic(stat_ind);
|
2633 |
|
|
|
2634 |
|
|
/* return the appropriate error counter
|
2635 |
|
|
*/
|
2636 |
|
|
snmp_pdu_add_variable(pdu, err_var, err_var_len,
|
2637 |
|
|
ASN_COUNTER, (u_char *) <mp, sizeof(ltmp));
|
2638 |
|
|
|
2639 |
|
|
return SNMPERR_SUCCESS;
|
2640 |
|
|
} /* end snmpv3_make_report() */
|
2641 |
|
|
|
2642 |
|
|
|
2643 |
|
|
int
|
2644 |
|
|
snmpv3_get_report_type(struct snmp_pdu *pdu)
|
2645 |
|
|
{
|
2646 |
|
|
static oid snmpMPDStats[] = {1,3,6,1,6,3,11,2,1};
|
2647 |
|
|
static oid usmStats[] = {1,3,6,1,6,3,15,1,1};
|
2648 |
|
|
struct variable_list *vp;
|
2649 |
|
|
int rpt_type = SNMPERR_UNKNOWN_REPORT;
|
2650 |
|
|
|
2651 |
|
|
if (pdu == NULL || pdu->variables == NULL) return rpt_type;
|
2652 |
|
|
vp = pdu->variables;
|
2653 |
|
|
if (vp->name_length == REPORT_STATS_LEN+2) {
|
2654 |
|
|
if (memcmp(snmpMPDStats,vp->name,REPORT_STATS_LEN*sizeof(oid)) == 0) {
|
2655 |
|
|
switch (vp->name[REPORT_STATS_LEN]) {
|
2656 |
|
|
case REPORT_snmpUnknownSecurityModels_NUM:
|
2657 |
|
|
rpt_type = SNMPERR_UNKNOWN_SEC_MODEL;
|
2658 |
|
|
break;
|
2659 |
|
|
case REPORT_snmpInvalidMsgs_NUM:
|
2660 |
|
|
rpt_type = SNMPERR_INVALID_MSG;
|
2661 |
|
|
break;
|
2662 |
|
|
}
|
2663 |
|
|
} else if (memcmp(usmStats,vp->name,REPORT_STATS_LEN*sizeof(oid)) == 0) {
|
2664 |
|
|
switch (vp->name[REPORT_STATS_LEN]) {
|
2665 |
|
|
case REPORT_usmStatsUnsupportedSecLevels_NUM:
|
2666 |
|
|
rpt_type = SNMPERR_UNSUPPORTED_SEC_LEVEL;
|
2667 |
|
|
break;
|
2668 |
|
|
case REPORT_usmStatsNotInTimeWindows_NUM:
|
2669 |
|
|
rpt_type = SNMPERR_NOT_IN_TIME_WINDOW;
|
2670 |
|
|
break;
|
2671 |
|
|
case REPORT_usmStatsUnknownUserNames_NUM:
|
2672 |
|
|
rpt_type = SNMPERR_UNKNOWN_USER_NAME;
|
2673 |
|
|
break;
|
2674 |
|
|
case REPORT_usmStatsUnknownEngineIDs_NUM:
|
2675 |
|
|
rpt_type = SNMPERR_UNKNOWN_ENG_ID;
|
2676 |
|
|
break;
|
2677 |
|
|
case REPORT_usmStatsWrongDigests_NUM:
|
2678 |
|
|
rpt_type = SNMPERR_AUTHENTICATION_FAILURE;
|
2679 |
|
|
break;
|
2680 |
|
|
case REPORT_usmStatsDecryptionErrors_NUM:
|
2681 |
|
|
rpt_type = SNMPERR_DECRYPTION_ERR;
|
2682 |
|
|
break;
|
2683 |
|
|
}
|
2684 |
|
|
}
|
2685 |
|
|
}
|
2686 |
|
|
DEBUGMSGTL(("report", "Report type: %d\n", rpt_type));
|
2687 |
|
|
return rpt_type;
|
2688 |
|
|
}
|
2689 |
|
|
|
2690 |
|
|
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
|
2691 |
|
|
|
2692 |
|
|
/*
|
2693 |
|
|
* Parses the packet received on the input session, and places the data into
|
2694 |
|
|
* the input pdu. length is the length of the input packet.
|
2695 |
|
|
* If any errors are encountered, -1 or USM error is returned.
|
2696 |
|
|
* Otherwise, a 0 is returned.
|
2697 |
|
|
*/
|
2698 |
|
|
static int
|
2699 |
|
|
_snmp_parse(void * sessp,
|
2700 |
|
|
struct snmp_session *session,
|
2701 |
|
|
struct snmp_pdu *pdu,
|
2702 |
|
|
u_char *data,
|
2703 |
|
|
size_t length)
|
2704 |
|
|
{
|
2705 |
|
|
u_char community[COMMUNITY_MAX_LEN];
|
2706 |
|
|
size_t community_length = COMMUNITY_MAX_LEN;
|
2707 |
|
|
int result = -1;
|
2708 |
|
|
|
2709 |
|
|
session->s_snmp_errno = 0;
|
2710 |
|
|
session->s_errno = 0;
|
2711 |
|
|
|
2712 |
|
|
/* Ensure all incoming PDUs have a unique means of identification
|
2713 |
|
|
(This is not restricted to AgentX handling,
|
2714 |
|
|
though that is where the need becomes visible) */
|
2715 |
|
|
pdu->transid = snmp_get_next_transid();
|
2716 |
|
|
|
2717 |
|
|
if (session->version != SNMP_DEFAULT_VERSION)
|
2718 |
|
|
pdu->version = session->version;
|
2719 |
|
|
else
|
2720 |
|
|
pdu->version = snmp_parse_version(data,length);
|
2721 |
|
|
|
2722 |
|
|
switch (pdu->version) {
|
2723 |
|
|
case SNMP_VERSION_1:
|
2724 |
|
|
case SNMP_VERSION_2c:
|
2725 |
|
|
DEBUGMSGTL(("snmp_api","Parsing SNMPv%d message...\n", (1 + pdu->version)));
|
2726 |
|
|
|
2727 |
|
|
/* authenticates message and returns length if valid */
|
2728 |
|
|
DEBUGDUMPSETUP("dump_recv", data, 4);
|
2729 |
|
|
DEBUGMSG(("dump_recv", "SNMPv%d message\n", (1+pdu->version)));
|
2730 |
|
|
|
2731 |
|
|
DEBUGINDENTMORE();
|
2732 |
|
|
data = snmp_comstr_parse(data, &length,
|
2733 |
|
|
community, &community_length,
|
2734 |
|
|
&pdu->version);
|
2735 |
|
|
DEBUGINDENTLESS();
|
2736 |
|
|
if (data == NULL)
|
2737 |
|
|
return -1;
|
2738 |
|
|
|
2739 |
|
|
if (pdu->version != session->version &&
|
2740 |
|
|
session->version != SNMP_DEFAULT_VERSION)
|
2741 |
|
|
{
|
2742 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
2743 |
|
|
return -1;
|
2744 |
|
|
}
|
2745 |
|
|
|
2746 |
|
|
/* maybe get the community string. */
|
2747 |
|
|
pdu->securityLevel = SNMP_SEC_LEVEL_NOAUTH;
|
2748 |
|
|
pdu->securityModel = (pdu->version == SNMP_VERSION_1) ?
|
2749 |
|
|
SNMP_SEC_MODEL_SNMPv1 : SNMP_SEC_MODEL_SNMPv2c;
|
2750 |
|
|
SNMP_FREE(pdu->community);
|
2751 |
|
|
pdu->community_len = 0;
|
2752 |
|
|
pdu->community = (u_char *)0;
|
2753 |
|
|
if (community_length) {
|
2754 |
|
|
pdu->community_len = community_length;
|
2755 |
|
|
pdu->community = (u_char *)malloc(community_length);
|
2756 |
|
|
memmove(pdu->community, community, community_length);
|
2757 |
|
|
}
|
2758 |
|
|
if (session->authenticator){
|
2759 |
|
|
data = session->authenticator(data, &length,
|
2760 |
|
|
community,
|
2761 |
|
|
community_length);
|
2762 |
|
|
if (data == NULL)
|
2763 |
|
|
{
|
2764 |
|
|
session->s_snmp_errno = SNMPERR_AUTHENTICATION_FAILURE;
|
2765 |
|
|
return -1;
|
2766 |
|
|
}
|
2767 |
|
|
}
|
2768 |
|
|
result = snmp_pdu_parse(pdu, data, &length);
|
2769 |
|
|
break;
|
2770 |
|
|
|
2771 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
2772 |
|
|
case SNMP_VERSION_3:
|
2773 |
|
|
result = snmpv3_parse(pdu, data, &length, NULL);
|
2774 |
|
|
DEBUGMSGTL(("snmp_parse",
|
2775 |
|
|
"Parsed SNMPv3 message (secName:%s, secLevel:%s): %s\n",
|
2776 |
|
|
pdu->securityName, usmSecLevelName[pdu->securityLevel],
|
2777 |
|
|
snmp_api_errstring(result)));
|
2778 |
|
|
|
2779 |
|
|
if (result) {
|
2780 |
|
|
if (!sessp)
|
2781 |
|
|
session->s_snmp_errno = result;
|
2782 |
|
|
else
|
2783 |
|
|
|
2784 |
|
|
/* handle reportable errors */
|
2785 |
|
|
switch (result) {
|
2786 |
|
|
case SNMPERR_USM_UNKNOWNENGINEID:
|
2787 |
|
|
case SNMPERR_USM_UNKNOWNSECURITYNAME:
|
2788 |
|
|
case SNMPERR_USM_UNSUPPORTEDSECURITYLEVEL:
|
2789 |
|
|
case SNMPERR_USM_AUTHENTICATIONFAILURE:
|
2790 |
|
|
case SNMPERR_USM_NOTINTIMEWINDOW:
|
2791 |
|
|
case SNMPERR_USM_DECRYPTIONERROR:
|
2792 |
|
|
if (SNMP_CMD_CONFIRMED(pdu->command) ||
|
2793 |
|
|
(pdu->command == 0 &&
|
2794 |
|
|
(pdu->flags & SNMP_MSG_FLAG_RPRT_BIT ))) {
|
2795 |
|
|
struct snmp_pdu *pdu2;
|
2796 |
|
|
int flags = pdu->flags;
|
2797 |
|
|
pdu->flags |= UCD_MSG_FLAG_FORCE_PDU_COPY;
|
2798 |
|
|
pdu2 = snmp_clone_pdu(pdu);
|
2799 |
|
|
pdu->flags = pdu2->flags = flags;
|
2800 |
|
|
snmpv3_make_report(pdu2, result);
|
2801 |
|
|
snmp_sess_send(sessp, pdu2);
|
2802 |
|
|
}
|
2803 |
|
|
break;
|
2804 |
|
|
default:
|
2805 |
|
|
session->s_snmp_errno = result;
|
2806 |
|
|
break;
|
2807 |
|
|
}
|
2808 |
|
|
}
|
2809 |
|
|
break;
|
2810 |
|
|
#endif
|
2811 |
|
|
case SNMPERR_BAD_VERSION:
|
2812 |
|
|
ERROR_MSG("error parsing snmp message version");
|
2813 |
|
|
snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
|
2814 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
2815 |
|
|
break;
|
2816 |
|
|
case SNMP_VERSION_sec:
|
2817 |
|
|
case SNMP_VERSION_2u:
|
2818 |
|
|
case SNMP_VERSION_2star:
|
2819 |
|
|
case SNMP_VERSION_2p:
|
2820 |
|
|
default:
|
2821 |
|
|
ERROR_MSG("unsupported snmp message version");
|
2822 |
|
|
snmp_increment_statistic(STAT_SNMPINBADVERSIONS);
|
2823 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
2824 |
|
|
break;
|
2825 |
|
|
}
|
2826 |
|
|
|
2827 |
|
|
return result;
|
2828 |
|
|
}
|
2829 |
|
|
|
2830 |
|
|
static int
|
2831 |
|
|
snmp_parse(void *sessp,
|
2832 |
|
|
struct snmp_session *pss,
|
2833 |
|
|
struct snmp_pdu *pdu,
|
2834 |
|
|
u_char *data,
|
2835 |
|
|
size_t length)
|
2836 |
|
|
{
|
2837 |
|
|
int rc;
|
2838 |
|
|
|
2839 |
|
|
rc = _snmp_parse(sessp,pss,pdu,data,length);
|
2840 |
|
|
if (rc) {
|
2841 |
|
|
if ( !pss->s_snmp_errno)
|
2842 |
|
|
pss->s_snmp_errno = SNMPERR_BAD_PARSE;
|
2843 |
|
|
SET_SNMP_ERROR(pss->s_snmp_errno);
|
2844 |
|
|
}
|
2845 |
|
|
|
2846 |
|
|
return rc;
|
2847 |
|
|
}
|
2848 |
|
|
|
2849 |
|
|
int
|
2850 |
|
|
snmp_pdu_parse(struct snmp_pdu *pdu, u_char *data, size_t *length) {
|
2851 |
|
|
u_char type;
|
2852 |
|
|
u_char msg_type;
|
2853 |
|
|
u_char *var_val;
|
2854 |
|
|
int badtype;
|
2855 |
|
|
size_t len;
|
2856 |
|
|
size_t four;
|
2857 |
|
|
struct variable_list *vp = NULL;
|
2858 |
|
|
struct sockaddr_in *pduIp = (struct sockaddr_in *)&(pdu->agent_addr);
|
2859 |
|
|
oid objid[MAX_OID_LEN];
|
2860 |
|
|
|
2861 |
|
|
badtype = 0;
|
2862 |
|
|
|
2863 |
|
|
DEBUGPRINTINDENT("dump_recv");
|
2864 |
|
|
DEBUGINDENTMORE();
|
2865 |
|
|
DEBUGMSG(("dump_recv", "PDU\n"));
|
2866 |
|
|
/* Get the PDU type */
|
2867 |
|
|
data = asn_parse_header(data, length, &msg_type);
|
2868 |
|
|
if (data == NULL)
|
2869 |
|
|
return -1;
|
2870 |
|
|
pdu->command = msg_type;
|
2871 |
|
|
pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
|
2872 |
|
|
|
2873 |
|
|
/* get the fields in the PDU preceeding the variable-bindings sequence */
|
2874 |
|
|
switch (pdu->command) {
|
2875 |
|
|
case SNMP_MSG_TRAP:
|
2876 |
|
|
/* enterprise */
|
2877 |
|
|
pdu->enterprise_length = MAX_OID_LEN;
|
2878 |
|
|
data = asn_parse_objid(data, length, &type, objid,
|
2879 |
|
|
&pdu->enterprise_length);
|
2880 |
|
|
if (data == NULL)
|
2881 |
|
|
return -1;
|
2882 |
|
|
pdu->enterprise = (oid *)malloc(pdu->enterprise_length * sizeof(oid));
|
2883 |
|
|
memmove(pdu->enterprise, objid, pdu->enterprise_length * sizeof(oid));
|
2884 |
|
|
|
2885 |
|
|
/* agent-addr */
|
2886 |
|
|
four = 4;
|
2887 |
|
|
pduIp->sin_family = AF_INET;
|
2888 |
|
|
pduIp->sin_len = sizeof(*pduIp);
|
2889 |
|
|
data = asn_parse_string(data, length, &type,
|
2890 |
|
|
(u_char *)&pduIp->sin_addr.s_addr,
|
2891 |
|
|
&four);
|
2892 |
|
|
if (data == NULL)
|
2893 |
|
|
return -1;
|
2894 |
|
|
|
2895 |
|
|
/* generic trap */
|
2896 |
|
|
data = asn_parse_int(data, length, &type, (long *)&pdu->trap_type,
|
2897 |
|
|
sizeof(pdu->trap_type));
|
2898 |
|
|
if (data == NULL)
|
2899 |
|
|
return -1;
|
2900 |
|
|
/* specific trap */
|
2901 |
|
|
data = asn_parse_int(data, length, &type, (long *)&pdu->specific_type,
|
2902 |
|
|
sizeof(pdu->specific_type));
|
2903 |
|
|
if (data == NULL)
|
2904 |
|
|
return -1;
|
2905 |
|
|
|
2906 |
|
|
/* timestamp */
|
2907 |
|
|
data = asn_parse_unsigned_int(data, length, &type, &pdu->time,
|
2908 |
|
|
sizeof(pdu->time));
|
2909 |
|
|
if (data == NULL)
|
2910 |
|
|
return -1;
|
2911 |
|
|
|
2912 |
|
|
break;
|
2913 |
|
|
|
2914 |
|
|
case SNMP_MSG_RESPONSE:
|
2915 |
|
|
case SNMP_MSG_REPORT:
|
2916 |
|
|
pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
|
2917 |
|
|
/* fallthrough */
|
2918 |
|
|
|
2919 |
|
|
default:
|
2920 |
|
|
/* PDU is not an SNMPv1 TRAP */
|
2921 |
|
|
|
2922 |
|
|
/* request id */
|
2923 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing request_id\n");
|
2924 |
|
|
data = asn_parse_int(data, length, &type, &pdu->reqid,
|
2925 |
|
|
sizeof(pdu->reqid));
|
2926 |
|
|
DEBUGINDENTLESS();
|
2927 |
|
|
if (data == NULL) {
|
2928 |
|
|
return -1;
|
2929 |
|
|
}
|
2930 |
|
|
|
2931 |
|
|
/* error status (getbulk non-repeaters) */
|
2932 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing error status\n");
|
2933 |
|
|
data = asn_parse_int(data, length, &type, &pdu->errstat,
|
2934 |
|
|
sizeof(pdu->errstat));
|
2935 |
|
|
DEBUGINDENTLESS();
|
2936 |
|
|
if (data == NULL) {
|
2937 |
|
|
return -1;
|
2938 |
|
|
}
|
2939 |
|
|
|
2940 |
|
|
/* error index (getbulk max-repetitions) */
|
2941 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing error index\n");
|
2942 |
|
|
data = asn_parse_int(data, length, &type, &pdu->errindex,
|
2943 |
|
|
sizeof(pdu->errindex));
|
2944 |
|
|
DEBUGINDENTLESS();
|
2945 |
|
|
if (data == NULL) {
|
2946 |
|
|
return -1;
|
2947 |
|
|
}
|
2948 |
|
|
}
|
2949 |
|
|
|
2950 |
|
|
/* get header for variable-bindings sequence */
|
2951 |
|
|
DEBUGDUMPHEADER("dump_recv", "VarBindList:\n");
|
2952 |
|
|
data = asn_parse_sequence(data, length, &type,
|
2953 |
|
|
(ASN_SEQUENCE | ASN_CONSTRUCTOR), "varbinds");
|
2954 |
|
|
if (data == NULL)
|
2955 |
|
|
return -1;
|
2956 |
|
|
|
2957 |
|
|
/* get each varBind sequence */
|
2958 |
|
|
while((int)*length > 0){
|
2959 |
|
|
struct variable_list *vptemp;
|
2960 |
|
|
vptemp = (struct variable_list *)malloc(sizeof(*vptemp));
|
2961 |
|
|
if (0 == vptemp) {
|
2962 |
|
|
return -1;
|
2963 |
|
|
}
|
2964 |
|
|
if (0 == vp){
|
2965 |
|
|
pdu->variables = vptemp;
|
2966 |
|
|
} else {
|
2967 |
|
|
vp->next_variable = vptemp;
|
2968 |
|
|
}
|
2969 |
|
|
vp = vptemp;
|
2970 |
|
|
|
2971 |
|
|
vp->next_variable = NULL;
|
2972 |
|
|
vp->val.string = NULL;
|
2973 |
|
|
vp->name_length = MAX_OID_LEN;
|
2974 |
|
|
vp->name = 0;
|
2975 |
|
|
DEBUGDUMPHEADER("dump_recv", "VarBind:\n");
|
2976 |
|
|
data = snmp_parse_var_op(data, objid, &vp->name_length, &vp->type,
|
2977 |
|
|
&vp->val_len, &var_val, length);
|
2978 |
|
|
if (data == NULL)
|
2979 |
|
|
return -1;
|
2980 |
|
|
if (snmp_set_var_objid(vp, objid, vp->name_length))
|
2981 |
|
|
return -1;
|
2982 |
|
|
|
2983 |
|
|
len = PACKET_LENGTH;
|
2984 |
|
|
switch((short)vp->type){
|
2985 |
|
|
case ASN_INTEGER:
|
2986 |
|
|
vp->val.integer = (long *)vp->buf;
|
2987 |
|
|
vp->val_len = sizeof(long);
|
2988 |
|
|
asn_parse_int(var_val, &len, &vp->type,
|
2989 |
|
|
(long *)vp->val.integer,
|
2990 |
|
|
sizeof(vp->val.integer));
|
2991 |
|
|
break;
|
2992 |
|
|
case ASN_COUNTER:
|
2993 |
|
|
case ASN_GAUGE:
|
2994 |
|
|
case ASN_TIMETICKS:
|
2995 |
|
|
case ASN_UINTEGER:
|
2996 |
|
|
vp->val.integer = (long *)vp->buf;
|
2997 |
|
|
vp->val_len = sizeof(u_long);
|
2998 |
|
|
asn_parse_unsigned_int(var_val, &len, &vp->type,
|
2999 |
|
|
(u_long *)vp->val.integer,
|
3000 |
|
|
sizeof(vp->val.integer));
|
3001 |
|
|
break;
|
3002 |
|
|
#ifdef OPAQUE_SPECIAL_TYPES
|
3003 |
|
|
case ASN_OPAQUE_COUNTER64:
|
3004 |
|
|
case ASN_OPAQUE_U64:
|
3005 |
|
|
#endif /* OPAQUE_SPECIAL_TYPES */
|
3006 |
|
|
case ASN_COUNTER64:
|
3007 |
|
|
vp->val.counter64 = (struct counter64 *)vp->buf;
|
3008 |
|
|
vp->val_len = sizeof(struct counter64);
|
3009 |
|
|
asn_parse_unsigned_int64(var_val, &len, &vp->type,
|
3010 |
|
|
(struct counter64 *)vp->val.counter64,
|
3011 |
|
|
sizeof(*vp->val.counter64));
|
3012 |
|
|
break;
|
3013 |
|
|
#ifdef OPAQUE_SPECIAL_TYPES
|
3014 |
|
|
case ASN_OPAQUE_FLOAT:
|
3015 |
|
|
vp->val.floatVal = (float *)vp->buf;
|
3016 |
|
|
vp->val_len = sizeof(float);
|
3017 |
|
|
asn_parse_float(var_val, &len, &vp->type,
|
3018 |
|
|
vp->val.floatVal,
|
3019 |
|
|
vp->val_len);
|
3020 |
|
|
break;
|
3021 |
|
|
case ASN_OPAQUE_DOUBLE:
|
3022 |
|
|
vp->val.doubleVal = (double *)vp->buf;
|
3023 |
|
|
vp->val_len = sizeof(double);
|
3024 |
|
|
asn_parse_double(var_val, &len, &vp->type,
|
3025 |
|
|
vp->val.doubleVal,
|
3026 |
|
|
vp->val_len);
|
3027 |
|
|
break;
|
3028 |
|
|
case ASN_OPAQUE_I64:
|
3029 |
|
|
vp->val.counter64 = (struct counter64 *)vp->buf;
|
3030 |
|
|
vp->val_len = sizeof(struct counter64);
|
3031 |
|
|
asn_parse_signed_int64(var_val, &len, &vp->type,
|
3032 |
|
|
(struct counter64 *)vp->val.counter64,
|
3033 |
|
|
sizeof(*vp->val.counter64));
|
3034 |
|
|
|
3035 |
|
|
break;
|
3036 |
|
|
#endif /* OPAQUE_SPECIAL_TYPES */
|
3037 |
|
|
case ASN_OCTET_STR:
|
3038 |
|
|
case ASN_IPADDRESS:
|
3039 |
|
|
case ASN_OPAQUE:
|
3040 |
|
|
case ASN_NSAP:
|
3041 |
|
|
if (vp->val_len < sizeof(vp->buf)){
|
3042 |
|
|
vp->val.string = (u_char *)vp->buf;
|
3043 |
|
|
} else {
|
3044 |
|
|
vp->val.string = (u_char *)malloc((unsigned)vp->val_len);
|
3045 |
|
|
}
|
3046 |
|
|
asn_parse_string(var_val, &len, &vp->type, vp->val.string,
|
3047 |
|
|
&vp->val_len);
|
3048 |
|
|
break;
|
3049 |
|
|
case ASN_OBJECT_ID:
|
3050 |
|
|
vp->val_len = MAX_OID_LEN;
|
3051 |
|
|
asn_parse_objid(var_val, &len, &vp->type, objid, &vp->val_len);
|
3052 |
|
|
vp->val_len *= sizeof(oid);
|
3053 |
|
|
vp->val.objid = (oid *)malloc((unsigned)vp->val_len);
|
3054 |
|
|
memmove(vp->val.objid, objid, vp->val_len);
|
3055 |
|
|
break;
|
3056 |
|
|
case SNMP_NOSUCHOBJECT:
|
3057 |
|
|
case SNMP_NOSUCHINSTANCE:
|
3058 |
|
|
case SNMP_ENDOFMIBVIEW:
|
3059 |
|
|
case ASN_NULL:
|
3060 |
|
|
break;
|
3061 |
|
|
case ASN_BIT_STR:
|
3062 |
|
|
vp->val.bitstring = (u_char *)malloc(vp->val_len);
|
3063 |
|
|
asn_parse_bitstring(var_val, &len, &vp->type,
|
3064 |
|
|
vp->val.bitstring, &vp->val_len);
|
3065 |
|
|
break;
|
3066 |
|
|
default:
|
3067 |
|
|
snmp_log(LOG_ERR,"bad type returned (%x)\n", vp->type);
|
3068 |
|
|
badtype = 1;
|
3069 |
|
|
break;
|
3070 |
|
|
}
|
3071 |
|
|
DEBUGINDENTLESS();
|
3072 |
|
|
}
|
3073 |
|
|
DEBUGINDENTLESS();
|
3074 |
|
|
DEBUGINDENTLESS();
|
3075 |
|
|
return badtype;
|
3076 |
|
|
}
|
3077 |
|
|
|
3078 |
|
|
/* snmp v3 utility function to parse into the scopedPdu. stores contextName
|
3079 |
|
|
and contextEngineID in pdu struct. Also stores pdu->command (handy for
|
3080 |
|
|
Report generation).
|
3081 |
|
|
|
3082 |
|
|
returns pointer to begining of PDU or NULL on error.
|
3083 |
|
|
*/
|
3084 |
|
|
|
3085 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3086 |
|
|
u_char *
|
3087 |
|
|
snmpv3_scopedPDU_parse(struct snmp_pdu *pdu,
|
3088 |
|
|
u_char *cp,
|
3089 |
|
|
size_t *length)
|
3090 |
|
|
{
|
3091 |
|
|
u_char tmp_buf[SNMP_MAX_MSG_SIZE];
|
3092 |
|
|
size_t tmp_buf_len;
|
3093 |
|
|
u_char type;
|
3094 |
|
|
size_t asn_len;
|
3095 |
|
|
u_char* data;
|
3096 |
|
|
|
3097 |
|
|
pdu->command = 0; /* initialize so we know if it got parsed */
|
3098 |
|
|
asn_len = *length;
|
3099 |
|
|
data = asn_parse_sequence(cp, &asn_len, &type,
|
3100 |
|
|
(ASN_SEQUENCE | ASN_CONSTRUCTOR), "plaintext scopedPDU");
|
3101 |
|
|
if (data == NULL){
|
3102 |
|
|
return NULL;
|
3103 |
|
|
}
|
3104 |
|
|
*length -= data - cp;
|
3105 |
|
|
|
3106 |
|
|
/* contextEngineID from scopedPdu */
|
3107 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing contextEngineID\n");
|
3108 |
|
|
data = asn_parse_string(data, length, &type, pdu->contextEngineID,
|
3109 |
|
|
&pdu->contextEngineIDLen);
|
3110 |
|
|
DEBUGINDENTLESS();
|
3111 |
|
|
if (data == NULL) {
|
3112 |
|
|
ERROR_MSG("error parsing contextEngineID from scopedPdu");
|
3113 |
|
|
return NULL;
|
3114 |
|
|
}
|
3115 |
|
|
|
3116 |
|
|
/* check that it agrees with engineID returned from USM above
|
3117 |
|
|
* only a warning because this could be legal if we are a proxy
|
3118 |
|
|
*/
|
3119 |
|
|
if (pdu->securityEngineIDLen != pdu->contextEngineIDLen ||
|
3120 |
|
|
memcmp(pdu->securityEngineID, pdu->contextEngineID,
|
3121 |
|
|
pdu->securityEngineIDLen) != 0) {
|
3122 |
|
|
DEBUGMSGTL(("scopedPDU_parse",
|
3123 |
|
|
"inconsistent engineID information in message\n"));
|
3124 |
|
|
}
|
3125 |
|
|
|
3126 |
|
|
/* parse contextName from scopedPdu
|
3127 |
|
|
*/
|
3128 |
|
|
tmp_buf_len = SNMP_MAX_CONTEXT_SIZE;
|
3129 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing contextName\n");
|
3130 |
|
|
data = asn_parse_string(data, length, &type, tmp_buf, &tmp_buf_len);
|
3131 |
|
|
DEBUGINDENTLESS();
|
3132 |
|
|
if (data == NULL) {
|
3133 |
|
|
ERROR_MSG("error parsing contextName from scopedPdu");
|
3134 |
|
|
return NULL;
|
3135 |
|
|
}
|
3136 |
|
|
|
3137 |
|
|
if (tmp_buf_len) {
|
3138 |
|
|
pdu->contextName = (char *)malloc(tmp_buf_len);
|
3139 |
|
|
memmove(pdu->contextName, tmp_buf, tmp_buf_len);
|
3140 |
|
|
pdu->contextNameLen = tmp_buf_len;
|
3141 |
|
|
} else {
|
3142 |
|
|
pdu->contextName = strdup("");
|
3143 |
|
|
pdu->contextNameLen = 0;
|
3144 |
|
|
}
|
3145 |
|
|
|
3146 |
|
|
/* Get the PDU type */
|
3147 |
|
|
asn_len = *length;
|
3148 |
|
|
DEBUGDUMPHEADER("dump_recv", "Parsing PDU type\n");
|
3149 |
|
|
cp = asn_parse_header(data, &asn_len, &type);
|
3150 |
|
|
DEBUGINDENTLESS();
|
3151 |
|
|
if (cp == NULL)
|
3152 |
|
|
return NULL;
|
3153 |
|
|
|
3154 |
|
|
pdu->command = type;
|
3155 |
|
|
|
3156 |
|
|
return data;
|
3157 |
|
|
}
|
3158 |
|
|
#endif /* CYGPKG_SNMPAGENT_V3_SUPPORT */
|
3159 |
|
|
|
3160 |
|
|
/*
|
3161 |
|
|
* Sends the input pdu on the session after calling snmp_build to create
|
3162 |
|
|
* a serialized packet. If necessary, set some of the pdu data from the
|
3163 |
|
|
* session defaults. Add a request corresponding to this pdu to the list
|
3164 |
|
|
* of outstanding requests on this session, then send the pdu.
|
3165 |
|
|
* Returns the request id of the generated packet if applicable, otherwise 1.
|
3166 |
|
|
* On any error, 0 is returned.
|
3167 |
|
|
* The pdu is freed by snmp_send() unless a failure occured.
|
3168 |
|
|
*/
|
3169 |
|
|
int
|
3170 |
|
|
snmp_send(struct snmp_session *session,
|
3171 |
|
|
struct snmp_pdu *pdu)
|
3172 |
|
|
{
|
3173 |
|
|
return snmp_async_send(session, pdu, NULL, NULL);
|
3174 |
|
|
}
|
3175 |
|
|
|
3176 |
|
|
int
|
3177 |
|
|
snmp_sess_send(void *sessp,
|
3178 |
|
|
struct snmp_pdu *pdu)
|
3179 |
|
|
{
|
3180 |
|
|
return snmp_sess_async_send(sessp, pdu, NULL, NULL);
|
3181 |
|
|
}
|
3182 |
|
|
|
3183 |
|
|
/*
|
3184 |
|
|
* int snmp_async_send(session, pdu, callback, cb_data)
|
3185 |
|
|
* struct snmp_session *session;
|
3186 |
|
|
* struct snmp_pdu *pdu;
|
3187 |
|
|
* snmp_callback callback;
|
3188 |
|
|
* void *cb_data;
|
3189 |
|
|
*
|
3190 |
|
|
* Sends the input pdu on the session after calling snmp_build to create
|
3191 |
|
|
* a serialized packet. If necessary, set some of the pdu data from the
|
3192 |
|
|
* session defaults. Add a request corresponding to this pdu to the list
|
3193 |
|
|
* of outstanding requests on this session and store callback and data,
|
3194 |
|
|
* then send the pdu.
|
3195 |
|
|
* Returns the request id of the generated packet if applicable, otherwise 0.
|
3196 |
|
|
* On any error, 0 is returned.
|
3197 |
|
|
* The pdu is freed by snmp_send() unless a failure occurred.
|
3198 |
|
|
*/
|
3199 |
|
|
int
|
3200 |
|
|
snmp_async_send(struct snmp_session *session,
|
3201 |
|
|
struct snmp_pdu *pdu,
|
3202 |
|
|
snmp_callback callback,
|
3203 |
|
|
void *cb_data)
|
3204 |
|
|
{
|
3205 |
|
|
void *sessp = snmp_sess_pointer(session);
|
3206 |
|
|
return snmp_sess_async_send(sessp, pdu, callback, cb_data);
|
3207 |
|
|
}
|
3208 |
|
|
|
3209 |
|
|
static int
|
3210 |
|
|
_sess_async_send(void *sessp,
|
3211 |
|
|
struct snmp_pdu *pdu,
|
3212 |
|
|
snmp_callback callback,
|
3213 |
|
|
void *cb_data)
|
3214 |
|
|
{
|
3215 |
|
|
struct session_list *slp = (struct session_list *)sessp;
|
3216 |
|
|
struct snmp_session *session;
|
3217 |
|
|
struct snmp_internal_session *isp;
|
3218 |
|
|
u_char packet[PACKET_LENGTH];
|
3219 |
|
|
size_t length = PACKET_LENGTH;
|
3220 |
|
|
struct sockaddr_in *isp_addr;
|
3221 |
|
|
struct sockaddr_in *pduIp;
|
3222 |
|
|
int result, addr_size;
|
3223 |
|
|
long reqid;
|
3224 |
|
|
|
3225 |
|
|
session = slp->session; isp = slp->internal;
|
3226 |
|
|
if (!session || !isp) {
|
3227 |
|
|
DEBUGMSGTL(("sess_read","send fail: closing...\n"));
|
3228 |
|
|
return 0;
|
3229 |
|
|
}
|
3230 |
|
|
|
3231 |
|
|
session->s_snmp_errno = 0;
|
3232 |
|
|
session->s_errno = 0;
|
3233 |
|
|
|
3234 |
|
|
if (pdu == NULL) {
|
3235 |
|
|
session->s_snmp_errno = SNMPERR_NULL_PDU;
|
3236 |
|
|
return 0;
|
3237 |
|
|
}
|
3238 |
|
|
#if TEMPORARILY_DISABLED
|
3239 |
|
|
/*
|
3240 |
|
|
* NULL variable are allowed in certain PDU types.
|
3241 |
|
|
* In particular, SNMPv3 engineID probes are of this form.
|
3242 |
|
|
* There is an internal PDU flag to indicate that this
|
3243 |
|
|
* is acceptable, but until the construction of engineID
|
3244 |
|
|
* probes can be amended to set this flag, we'll simply
|
3245 |
|
|
* skip this test altogether.
|
3246 |
|
|
*/
|
3247 |
|
|
if (pdu->variables == NULL) {
|
3248 |
|
|
switch (pdu->command) {
|
3249 |
|
|
case SNMP_MSG_GET:
|
3250 |
|
|
case SNMP_MSG_SET:
|
3251 |
|
|
case SNMP_MSG_GETNEXT:
|
3252 |
|
|
case SNMP_MSG_GETBULK:
|
3253 |
|
|
case SNMP_MSG_RESPONSE:
|
3254 |
|
|
case SNMP_MSG_TRAP2:
|
3255 |
|
|
case SNMP_MSG_REPORT:
|
3256 |
|
|
case SNMP_MSG_INFORM:
|
3257 |
|
|
session->s_snmp_errno = snmp_errno = SNMPERR_NO_VARS;
|
3258 |
|
|
return 0;
|
3259 |
|
|
case SNMP_MSG_TRAP:
|
3260 |
|
|
break;
|
3261 |
|
|
}
|
3262 |
|
|
}
|
3263 |
|
|
#endif
|
3264 |
|
|
|
3265 |
|
|
pduIp = (struct sockaddr_in *)&(pdu->address);
|
3266 |
|
|
pdu->flags |= UCD_MSG_FLAG_EXPECT_RESPONSE;
|
3267 |
|
|
|
3268 |
|
|
/* check/setup the version */
|
3269 |
|
|
if (pdu->version == SNMP_DEFAULT_VERSION) {
|
3270 |
|
|
if (session->version == SNMP_DEFAULT_VERSION) {
|
3271 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
3272 |
|
|
return 0;
|
3273 |
|
|
}
|
3274 |
|
|
pdu->version = session->version;
|
3275 |
|
|
} else if (session->version == SNMP_DEFAULT_VERSION) {
|
3276 |
|
|
/* It's OK */
|
3277 |
|
|
} else if (pdu->version != session->version) {
|
3278 |
|
|
/* ENHANCE: we should support multi-lingual sessions */
|
3279 |
|
|
session->s_snmp_errno = SNMPERR_BAD_VERSION;
|
3280 |
|
|
return 0;
|
3281 |
|
|
}
|
3282 |
|
|
|
3283 |
|
|
if (pdu->address.sa_family == AF_UNSPEC){
|
3284 |
|
|
isp_addr = (struct sockaddr_in *)&(isp->addr);
|
3285 |
|
|
if (isp->addr.sa_family == AF_UNSPEC ||
|
3286 |
|
|
(isp->addr.sa_family == AF_INET &&
|
3287 |
|
|
isp_addr->sin_addr.s_addr == SNMP_DEFAULT_ADDRESS)){
|
3288 |
|
|
session->s_snmp_errno = SNMPERR_BAD_ADDRESS;
|
3289 |
|
|
return 0;
|
3290 |
|
|
}
|
3291 |
|
|
memmove(&pdu->address, &(isp->addr), sizeof(isp->addr));
|
3292 |
|
|
}
|
3293 |
|
|
|
3294 |
|
|
addr_size = snmp_socket_length(pdu->address.sa_family);
|
3295 |
|
|
|
3296 |
|
|
/* build the message to send */
|
3297 |
|
|
if (isp->hook_build)
|
3298 |
|
|
result = isp->hook_build(session, pdu, packet, &length);
|
3299 |
|
|
else
|
3300 |
|
|
result = snmp_build(session, pdu, packet, &length);
|
3301 |
|
|
if (result < 0){
|
3302 |
|
|
return 0;
|
3303 |
|
|
}
|
3304 |
|
|
if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET)){
|
3305 |
|
|
snmp_log(LOG_DEBUG, "\nSending %u bytes to %s:%hu\n", length,
|
3306 |
|
|
inet_ntoa(pduIp->sin_addr), ntohs(pduIp->sin_port));
|
3307 |
|
|
xdump(packet, length, "");
|
3308 |
|
|
}
|
3309 |
|
|
|
3310 |
|
|
/* send the message */
|
3311 |
|
|
#if !defined(__ECOS)
|
3312 |
|
|
if ( session->flags & SNMP_FLAGS_STREAM_SOCKET ) {
|
3313 |
|
|
result = send(isp->sd, (char *)packet, length, 0);
|
3314 |
|
|
}
|
3315 |
|
|
else
|
3316 |
|
|
#endif
|
3317 |
|
|
result = sendto(isp->sd, (char *)packet, length, 0,
|
3318 |
|
|
(struct sockaddr *)&pdu->address, addr_size);
|
3319 |
|
|
if ( result < 0){
|
3320 |
|
|
session->s_snmp_errno = SNMPERR_BAD_SENDTO;
|
3321 |
|
|
session->s_errno = errno;
|
3322 |
|
|
return 0;
|
3323 |
|
|
}
|
3324 |
|
|
|
3325 |
|
|
reqid = pdu->reqid;
|
3326 |
|
|
|
3327 |
|
|
/* add to pending requests list if expect a response */
|
3328 |
|
|
if (pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) {
|
3329 |
|
|
struct request_list *rp;
|
3330 |
|
|
struct timeval tv;
|
3331 |
|
|
|
3332 |
|
|
rp = (struct request_list *)calloc( 1, sizeof(struct request_list));
|
3333 |
|
|
if (rp == NULL) {
|
3334 |
|
|
session->s_snmp_errno = SNMPERR_GENERR;
|
3335 |
|
|
return 0;
|
3336 |
|
|
}
|
3337 |
|
|
|
3338 |
|
|
gettimeofday(&tv, (struct timezone *)0);
|
3339 |
|
|
rp->pdu = pdu;
|
3340 |
|
|
rp->request_id = pdu->reqid;
|
3341 |
|
|
rp->message_id = pdu->msgid;
|
3342 |
|
|
rp->callback = callback;
|
3343 |
|
|
rp->cb_data = cb_data;
|
3344 |
|
|
rp->retries = 0;
|
3345 |
|
|
rp->timeout = session->timeout;
|
3346 |
|
|
rp->time = tv;
|
3347 |
|
|
tv.tv_usec += rp->timeout;
|
3348 |
|
|
tv.tv_sec += tv.tv_usec / 1000000L;
|
3349 |
|
|
tv.tv_usec %= 1000000L;
|
3350 |
|
|
rp->expire = tv;
|
3351 |
|
|
|
3352 |
|
|
/* XX lock should be per session ! */
|
3353 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
3354 |
|
|
if (isp->requestsEnd){
|
3355 |
|
|
rp->next_request = isp->requestsEnd->next_request;
|
3356 |
|
|
isp->requestsEnd->next_request = rp;
|
3357 |
|
|
isp->requestsEnd = rp;
|
3358 |
|
|
} else {
|
3359 |
|
|
rp->next_request = isp->requests;
|
3360 |
|
|
isp->requests = rp;
|
3361 |
|
|
isp->requestsEnd = rp;
|
3362 |
|
|
}
|
3363 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
3364 |
|
|
}
|
3365 |
|
|
else
|
3366 |
|
|
snmp_free_pdu(pdu); /* free v1 or v2 TRAP PDU */
|
3367 |
|
|
|
3368 |
|
|
return reqid;
|
3369 |
|
|
}
|
3370 |
|
|
|
3371 |
|
|
int
|
3372 |
|
|
snmp_sess_async_send(void *sessp,
|
3373 |
|
|
struct snmp_pdu *pdu,
|
3374 |
|
|
snmp_callback callback,
|
3375 |
|
|
void *cb_data)
|
3376 |
|
|
{
|
3377 |
|
|
int rc;
|
3378 |
|
|
|
3379 |
|
|
if (sessp == NULL){
|
3380 |
|
|
snmp_errno = SNMPERR_BAD_SESSION; /*MTCRITICAL_RESOURCE*/
|
3381 |
|
|
return(0);
|
3382 |
|
|
}
|
3383 |
|
|
rc = _sess_async_send(sessp,pdu,callback,cb_data);
|
3384 |
|
|
if (rc == 0) {
|
3385 |
|
|
struct session_list *psl;
|
3386 |
|
|
struct snmp_session *pss;
|
3387 |
|
|
psl = (struct session_list *)sessp;
|
3388 |
|
|
pss = psl->session;
|
3389 |
|
|
SET_SNMP_ERROR(pss->s_snmp_errno);
|
3390 |
|
|
}
|
3391 |
|
|
return rc;
|
3392 |
|
|
}
|
3393 |
|
|
|
3394 |
|
|
|
3395 |
|
|
/*
|
3396 |
|
|
* Frees the variable and any malloc'd data associated with it.
|
3397 |
|
|
*/
|
3398 |
|
|
void
|
3399 |
|
|
snmp_free_var(struct variable_list *var)
|
3400 |
|
|
{
|
3401 |
|
|
if (!var) return;
|
3402 |
|
|
|
3403 |
|
|
if (var->name != var->name_loc)
|
3404 |
|
|
SNMP_FREE(var->name);
|
3405 |
|
|
if (var->val.string != var->buf)
|
3406 |
|
|
SNMP_FREE(var->val.string);
|
3407 |
|
|
|
3408 |
|
|
free((char *)var);
|
3409 |
|
|
}
|
3410 |
|
|
|
3411 |
|
|
void snmp_free_varbind(struct variable_list *var)
|
3412 |
|
|
{
|
3413 |
|
|
struct variable_list *ptr;
|
3414 |
|
|
while(var) {
|
3415 |
|
|
ptr = var->next_variable;
|
3416 |
|
|
snmp_free_var(var);
|
3417 |
|
|
var = ptr;
|
3418 |
|
|
}
|
3419 |
|
|
}
|
3420 |
|
|
|
3421 |
|
|
/*
|
3422 |
|
|
* Frees the pdu and any malloc'd data associated with it.
|
3423 |
|
|
*/
|
3424 |
|
|
void
|
3425 |
|
|
snmp_free_pdu(struct snmp_pdu *pdu)
|
3426 |
|
|
{
|
3427 |
|
|
if (!pdu) return;
|
3428 |
|
|
|
3429 |
|
|
snmp_free_varbind(pdu->variables);
|
3430 |
|
|
SNMP_FREE(pdu->enterprise);
|
3431 |
|
|
SNMP_FREE(pdu->community);
|
3432 |
|
|
SNMP_FREE(pdu->contextEngineID);
|
3433 |
|
|
SNMP_FREE(pdu->securityEngineID);
|
3434 |
|
|
SNMP_FREE(pdu->contextName);
|
3435 |
|
|
SNMP_FREE(pdu->securityName);
|
3436 |
|
|
free((char *)pdu);
|
3437 |
|
|
}
|
3438 |
|
|
|
3439 |
|
|
/*
|
3440 |
|
|
* Checks to see if any of the fd's set in the fdset belong to
|
3441 |
|
|
* snmp. Each socket with it's fd set has a packet read from it
|
3442 |
|
|
* and snmp_parse is called on the packet received. The resulting pdu
|
3443 |
|
|
* is passed to the callback routine for that session. If the callback
|
3444 |
|
|
* routine returns successfully, the pdu and it's request are deleted.
|
3445 |
|
|
*/
|
3446 |
|
|
void
|
3447 |
|
|
snmp_read(fd_set *fdset)
|
3448 |
|
|
{
|
3449 |
|
|
struct session_list *slp;
|
3450 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
3451 |
|
|
for(slp = Sessions; slp; slp = slp->next){
|
3452 |
|
|
snmp_sess_read((void *)slp, fdset);
|
3453 |
|
|
}
|
3454 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
3455 |
|
|
}
|
3456 |
|
|
|
3457 |
|
|
/* Same as snmp_read, but works just one session. */
|
3458 |
|
|
/* returns 0 if success, -1 if fail */
|
3459 |
|
|
/* MTR: can't lock here and at snmp_read */
|
3460 |
|
|
/* Beware recursive send maybe inside snmp_read callback function. */
|
3461 |
|
|
int
|
3462 |
|
|
_sess_read(void *sessp,
|
3463 |
|
|
fd_set *fdset)
|
3464 |
|
|
{
|
3465 |
|
|
struct session_list *slp = (struct session_list *)sessp;
|
3466 |
|
|
struct snmp_session *sp;
|
3467 |
|
|
struct snmp_internal_session *isp;
|
3468 |
|
|
u_char packet[PACKET_LENGTH], *packetptr = packet, *ucp = 0;
|
3469 |
|
|
snmp_ipaddr from;
|
3470 |
|
|
struct sockaddr_in *fromIp = (struct sockaddr_in *)&from;
|
3471 |
|
|
size_t length = 0;
|
3472 |
|
|
struct snmp_pdu *pdu;
|
3473 |
|
|
struct request_list *rp, *orp = NULL;
|
3474 |
|
|
int ret;
|
3475 |
|
|
int addrlen;
|
3476 |
|
|
int fromlength;
|
3477 |
|
|
|
3478 |
|
|
sp = slp->session; isp = slp->internal;
|
3479 |
|
|
if (!sp || !isp) {
|
3480 |
|
|
DEBUGMSGTL(("sess_read","read fail: closing...\n"));
|
3481 |
|
|
return 0;
|
3482 |
|
|
}
|
3483 |
|
|
|
3484 |
|
|
if ((!isp->newpkt && !(FD_ISSET(isp->sd, fdset)))) {
|
3485 |
|
|
DEBUGMSGTL(("sess_read","not reading...\n"));
|
3486 |
|
|
return 0;
|
3487 |
|
|
}
|
3488 |
|
|
|
3489 |
|
|
sp->s_snmp_errno = 0;
|
3490 |
|
|
sp->s_errno = 0;
|
3491 |
|
|
|
3492 |
|
|
if ( sp->flags & SNMP_FLAGS_STREAM_SOCKET ) {
|
3493 |
|
|
if ( sp->flags & SNMP_FLAGS_LISTENING ) {
|
3494 |
|
|
/*
|
3495 |
|
|
* Accept the new stream based connection,
|
3496 |
|
|
* and create a new session for it.
|
3497 |
|
|
*/
|
3498 |
|
|
struct session_list *new_slp;
|
3499 |
|
|
int new_sd;
|
3500 |
|
|
|
3501 |
|
|
addrlen = sizeof(struct sockaddr);
|
3502 |
|
|
new_sd = accept(isp->sd, (struct sockaddr *)&(isp->addr), &addrlen);
|
3503 |
|
|
if ( new_sd == -1 ) {
|
3504 |
|
|
sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
|
3505 |
|
|
sp->s_errno = errno;
|
3506 |
|
|
snmp_set_detail(strerror(errno));
|
3507 |
|
|
return -1;
|
3508 |
|
|
}
|
3509 |
|
|
|
3510 |
|
|
new_slp = snmp_sess_copy( sp );
|
3511 |
|
|
if ( new_slp == NULL )
|
3512 |
|
|
return -1;
|
3513 |
|
|
{ /*MTCRITICAL_RESOURCE*/
|
3514 |
|
|
/* indirectly accesses the Sessions list */
|
3515 |
|
|
/* MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION); */
|
3516 |
|
|
new_slp->next = slp->next;
|
3517 |
|
|
slp->next = new_slp;
|
3518 |
|
|
|
3519 |
|
|
sp = new_slp->session;
|
3520 |
|
|
isp = new_slp->internal;
|
3521 |
|
|
memcpy((u_char *)isp,
|
3522 |
|
|
(u_char *)slp->internal,
|
3523 |
|
|
sizeof(*slp->internal));
|
3524 |
|
|
isp->sd = new_sd;
|
3525 |
|
|
isp->addr.sa_family = isp->me.sa_family;
|
3526 |
|
|
sp->flags &= (~SNMP_FLAGS_LISTENING);
|
3527 |
|
|
/* MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION); */
|
3528 |
|
|
} /*END MTCRITICAL_RESOURCE*/
|
3529 |
|
|
}
|
3530 |
|
|
memcpy((u_char *)&from, (u_char *)&(isp->addr), sizeof( isp->addr ));
|
3531 |
|
|
}
|
3532 |
|
|
else
|
3533 |
|
|
memset(&from, 0, sizeof(from));
|
3534 |
|
|
fromlength = sizeof from;
|
3535 |
|
|
#if !defined(__ECOS)
|
3536 |
|
|
if ( sp->flags & SNMP_FLAGS_STREAM_SOCKET ) {
|
3537 |
|
|
if (!isp->newpkt)
|
3538 |
|
|
length = recv(isp->sd, (char *)packet, PACKET_LENGTH, 0);
|
3539 |
|
|
} else {
|
3540 |
|
|
#endif
|
3541 |
|
|
length = recvfrom(isp->sd, (char *)packet, PACKET_LENGTH, 0,
|
3542 |
|
|
(struct sockaddr *)&from, &fromlength);
|
3543 |
|
|
if (from.sa_family == AF_UNSPEC)
|
3544 |
|
|
from.sa_family = AF_INET; /* bad bad bad OS, no bone! */
|
3545 |
|
|
#if !defined(__ECOS)
|
3546 |
|
|
}
|
3547 |
|
|
#endif
|
3548 |
|
|
|
3549 |
|
|
if (length == -1) {
|
3550 |
|
|
sp->s_snmp_errno = SNMPERR_BAD_RECVFROM;
|
3551 |
|
|
sp->s_errno = errno;
|
3552 |
|
|
snmp_set_detail(strerror(errno));
|
3553 |
|
|
return -1;
|
3554 |
|
|
}
|
3555 |
|
|
|
3556 |
|
|
/* Remote end closed connection */
|
3557 |
|
|
if ((length == 0 && !isp->newpkt) &&
|
3558 |
|
|
(sp->flags & SNMP_FLAGS_STREAM_SOCKET )) {
|
3559 |
|
|
isp->sd = -1; /* Mark session for deletion */
|
3560 |
|
|
/* XXX: its not properly closing... */
|
3561 |
|
|
/* Don't unlink the server listening socket prematurely */
|
3562 |
|
|
#ifdef AF_UNIX
|
3563 |
|
|
if (( isp->me.sa_family == AF_UNIX ) &&
|
3564 |
|
|
!( sp->flags & SNMP_FLAGS_LISTENING ))
|
3565 |
|
|
isp->me.sa_family = AF_UNSPEC;
|
3566 |
|
|
#endif /*AF_UNIX */
|
3567 |
|
|
return -1;
|
3568 |
|
|
}
|
3569 |
|
|
|
3570 |
|
|
if (sp->flags & SNMP_FLAGS_STREAM_SOCKET ) {
|
3571 |
|
|
|
3572 |
|
|
if (isp->newpkt == 1) {
|
3573 |
|
|
/* move the old memory down, if we have saved data */
|
3574 |
|
|
memmove(isp->packet, isp->packet+isp->proper_len, isp->proper_len);
|
3575 |
|
|
isp->newpkt = 0;
|
3576 |
|
|
isp->packet_len -= isp->proper_len;
|
3577 |
|
|
isp->proper_len = 0;
|
3578 |
|
|
}
|
3579 |
|
|
|
3580 |
|
|
/* malloc the save space if needed */
|
3581 |
|
|
if (isp->packet == NULL) {
|
3582 |
|
|
isp->packet_size = (PACKET_LENGTH < length)?length:PACKET_LENGTH;
|
3583 |
|
|
isp->packet = (u_char *) malloc(isp->packet_size);
|
3584 |
|
|
}
|
3585 |
|
|
|
3586 |
|
|
/* do we have enough space? */
|
3587 |
|
|
if (isp->packet_size < (isp->packet_len + length)) {
|
3588 |
|
|
if (isp->packet_size+length > MAX_PACKET_LENGTH) {
|
3589 |
|
|
/* maximum length exceeded, drop connection */
|
3590 |
|
|
snmp_log(LOG_ERR,"Maximum saved packet size exceeded.\n");
|
3591 |
|
|
isp->sd = -1;
|
3592 |
|
|
/* Don't unlink the server listening socket prematurely */
|
3593 |
|
|
/* XXX: do this?? */
|
3594 |
|
|
#ifdef AF_UNIX
|
3595 |
|
|
if (( isp->me.sa_family == AF_UNIX ) &&
|
3596 |
|
|
!( sp->flags & SNMP_FLAGS_LISTENING ))
|
3597 |
|
|
isp->me.sa_family = AF_UNSPEC;
|
3598 |
|
|
#endif /*AF_UNIX */
|
3599 |
|
|
return -1;
|
3600 |
|
|
}
|
3601 |
|
|
isp->packet_size = isp->packet_size*2;
|
3602 |
|
|
if (isp->packet_size < (isp->packet_len + length))
|
3603 |
|
|
isp->packet_size = (isp->packet_len + length); /* shouldn't happen */
|
3604 |
|
|
isp->packet = (u_char *) realloc(isp->packet, isp->packet_size);
|
3605 |
|
|
}
|
3606 |
|
|
|
3607 |
|
|
/* add the new data to the end of our buffer */
|
3608 |
|
|
memcpy(isp->packet+isp->packet_len, packet, length);
|
3609 |
|
|
isp->packet_len += length;
|
3610 |
|
|
|
3611 |
|
|
/* check for agentx length parser */
|
3612 |
|
|
if (isp->proper_len == 0) {
|
3613 |
|
|
/* get the total data length we're expecting (and need to wait for) */
|
3614 |
|
|
if (isp->check_packet)
|
3615 |
|
|
isp->proper_len = isp->check_packet(isp->packet, isp->packet_len);
|
3616 |
|
|
else
|
3617 |
|
|
isp->proper_len = asn_check_packet(isp->packet, isp->packet_len);
|
3618 |
|
|
|
3619 |
|
|
if (isp->proper_len > MAX_PACKET_LENGTH) {
|
3620 |
|
|
/* illegal length, drop the connection */
|
3621 |
|
|
snmp_log(LOG_ERR,"Maximum packet size exceeded in a request.\n");
|
3622 |
|
|
isp->sd = -1;
|
3623 |
|
|
/* Don't unlink the server listening socket prematurely */
|
3624 |
|
|
/* XXX: do this?? */
|
3625 |
|
|
#ifdef AF_UNIX
|
3626 |
|
|
if (( isp->me.sa_family == AF_UNIX ) &&
|
3627 |
|
|
!( sp->flags & SNMP_FLAGS_LISTENING ))
|
3628 |
|
|
isp->me.sa_family = AF_UNSPEC;
|
3629 |
|
|
#endif /*AF_UNIX */
|
3630 |
|
|
return -1;
|
3631 |
|
|
}
|
3632 |
|
|
}
|
3633 |
|
|
|
3634 |
|
|
/* if its not long enough now, give up and contiune waiting */
|
3635 |
|
|
if (isp->proper_len == 0 || isp->packet_len < isp->proper_len) {
|
3636 |
|
|
DEBUGMSGTL(("sess_read", "short packet! (%d/%d)\n",
|
3637 |
|
|
isp->packet_len, isp->proper_len));
|
3638 |
|
|
return 0;
|
3639 |
|
|
}
|
3640 |
|
|
|
3641 |
|
|
/* else we need to continue, and process the saved data.
|
3642 |
|
|
Careful though, we may have more than is needed! save it! */
|
3643 |
|
|
packetptr = isp->packet;
|
3644 |
|
|
length = isp->proper_len;
|
3645 |
|
|
if (isp->packet_len - isp->proper_len == 0) {
|
3646 |
|
|
isp->packet_len -= isp->proper_len;
|
3647 |
|
|
isp->proper_len = 0;
|
3648 |
|
|
} else if (isp->packet_len - isp->proper_len < 0) {
|
3649 |
|
|
snmp_log(LOG_ERR,"something seriously wrong, packet size calculations are negative.\n");
|
3650 |
|
|
isp->packet_len = 0;
|
3651 |
|
|
isp->proper_len = 0;
|
3652 |
|
|
} else if (isp->packet_len - isp->proper_len > 0) {
|
3653 |
|
|
isp->newpkt = 1;
|
3654 |
|
|
}
|
3655 |
|
|
}
|
3656 |
|
|
|
3657 |
|
|
if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET)){
|
3658 |
|
|
snmp_log(LOG_DEBUG, "\nReceived %d bytes from %s:%hu\n", length,
|
3659 |
|
|
inet_ntoa(fromIp->sin_addr), ntohs(fromIp->sin_port));
|
3660 |
|
|
xdump(packetptr, length, "");
|
3661 |
|
|
}
|
3662 |
|
|
if ( isp->hook_pre ) {
|
3663 |
|
|
if ( isp->hook_pre( sp, from ) == 0 )
|
3664 |
|
|
return -1;
|
3665 |
|
|
}
|
3666 |
|
|
|
3667 |
|
|
pdu = (struct snmp_pdu *)malloc(sizeof(struct snmp_pdu));
|
3668 |
|
|
memset (pdu, 0, sizeof(*pdu));
|
3669 |
|
|
pdu->address = from;
|
3670 |
|
|
|
3671 |
|
|
if ( isp->hook_parse )
|
3672 |
|
|
ret = isp->hook_parse(sp, pdu, packetptr, length);
|
3673 |
|
|
else
|
3674 |
|
|
ret = snmp_parse(sessp, sp, pdu, packetptr, length);
|
3675 |
|
|
if ( isp->hook_post ) {
|
3676 |
|
|
if ( isp->hook_post( sp, pdu, ret ) == 0 ) {
|
3677 |
|
|
snmp_free_pdu(pdu);
|
3678 |
|
|
return -1;
|
3679 |
|
|
}
|
3680 |
|
|
}
|
3681 |
|
|
if (ret != SNMP_ERR_NOERROR) {
|
3682 |
|
|
snmp_free_pdu(pdu);
|
3683 |
|
|
return -1;
|
3684 |
|
|
}
|
3685 |
|
|
|
3686 |
|
|
if (pdu->flags & UCD_MSG_FLAG_RESPONSE_PDU) {
|
3687 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3688 |
|
|
/* call USM to free any securityStateRef supplied with the message */
|
3689 |
|
|
if (pdu->securityStateRef) {
|
3690 |
|
|
usm_free_usmStateReference(pdu->securityStateRef);
|
3691 |
|
|
pdu->securityStateRef = NULL;
|
3692 |
|
|
}
|
3693 |
|
|
#endif
|
3694 |
|
|
for(rp = isp->requests; rp; orp = rp, rp = rp->next_request) {
|
3695 |
|
|
snmp_callback callback;
|
3696 |
|
|
void *magic;
|
3697 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3698 |
|
|
if (pdu->version == SNMP_VERSION_3) {
|
3699 |
|
|
/* msgId must match for V3 messages */
|
3700 |
|
|
if (rp->message_id != pdu->msgid) continue;
|
3701 |
|
|
/* check that message fields match original,
|
3702 |
|
|
* if not, no further processing */
|
3703 |
|
|
if (!snmpv3_verify_msg(rp,pdu)) break;
|
3704 |
|
|
} else {
|
3705 |
|
|
#endif
|
3706 |
|
|
if (rp->request_id != pdu->reqid) continue;
|
3707 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3708 |
|
|
}
|
3709 |
|
|
#endif
|
3710 |
|
|
if (rp->callback) {
|
3711 |
|
|
callback = rp->callback;
|
3712 |
|
|
magic = rp->cb_data;
|
3713 |
|
|
} else {
|
3714 |
|
|
callback = sp->callback;
|
3715 |
|
|
magic = sp->callback_magic;
|
3716 |
|
|
}
|
3717 |
|
|
|
3718 |
|
|
/* MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION); ?* XX lock should be per session ! */
|
3719 |
|
|
if (callback == NULL ||
|
3720 |
|
|
callback(RECEIVED_MESSAGE,sp,pdu->reqid,pdu,magic) == 1){
|
3721 |
|
|
if (pdu->command == SNMP_MSG_REPORT) {
|
3722 |
|
|
if (sp->s_snmp_errno == SNMPERR_NOT_IN_TIME_WINDOW) {
|
3723 |
|
|
/* trigger immediate retry on recoverable Reports
|
3724 |
|
|
* (notInTimeWindow), incr_retries == TRUE to prevent
|
3725 |
|
|
* inifinite resend */
|
3726 |
|
|
if (rp->retries <= sp->retries) {
|
3727 |
|
|
snmp_resend_request(slp, rp, TRUE);
|
3728 |
|
|
break;
|
3729 |
|
|
}
|
3730 |
|
|
} else {
|
3731 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3732 |
|
|
if (SNMPV3_IGNORE_UNAUTH_REPORTS) break;
|
3733 |
|
|
#endif
|
3734 |
|
|
}
|
3735 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3736 |
|
|
/* handle engineID discovery - */
|
3737 |
|
|
if (!sp->securityEngineIDLen && pdu->securityEngineIDLen) {
|
3738 |
|
|
sp->securityEngineID = (u_char *)malloc(pdu->securityEngineIDLen);
|
3739 |
|
|
memcpy(sp->securityEngineID, pdu->securityEngineID,
|
3740 |
|
|
pdu->securityEngineIDLen);
|
3741 |
|
|
sp->securityEngineIDLen = pdu->securityEngineIDLen;
|
3742 |
|
|
if (!sp->contextEngineIDLen) {
|
3743 |
|
|
sp->contextEngineID = (u_char *)malloc(pdu->securityEngineIDLen);
|
3744 |
|
|
memcpy(sp->contextEngineID, pdu->securityEngineID,
|
3745 |
|
|
pdu->securityEngineIDLen);
|
3746 |
|
|
sp->contextEngineIDLen = pdu->securityEngineIDLen;
|
3747 |
|
|
}
|
3748 |
|
|
}
|
3749 |
|
|
#endif
|
3750 |
|
|
}
|
3751 |
|
|
/* successful, so delete request */
|
3752 |
|
|
if (isp->requests == rp){
|
3753 |
|
|
/* first in list */
|
3754 |
|
|
isp->requests = rp->next_request;
|
3755 |
|
|
if (isp->requestsEnd == rp)
|
3756 |
|
|
isp->requestsEnd = NULL;
|
3757 |
|
|
} else {
|
3758 |
|
|
orp->next_request = rp->next_request;
|
3759 |
|
|
if (isp->requestsEnd == rp)
|
3760 |
|
|
isp->requestsEnd = orp;
|
3761 |
|
|
}
|
3762 |
|
|
snmp_free_pdu(rp->pdu);
|
3763 |
|
|
free((char *)rp);
|
3764 |
|
|
/* there shouldn't be any more requests with the
|
3765 |
|
|
same reqid */
|
3766 |
|
|
break;
|
3767 |
|
|
}
|
3768 |
|
|
/* MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION); ?* XX lock should be per session ! */
|
3769 |
|
|
}
|
3770 |
|
|
} else {
|
3771 |
|
|
if (sp->callback)
|
3772 |
|
|
{
|
3773 |
|
|
/* MTR snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION); */
|
3774 |
|
|
sp->callback(RECEIVED_MESSAGE, sp, pdu->reqid, pdu,
|
3775 |
|
|
sp->callback_magic);
|
3776 |
|
|
/* MTR snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION); */
|
3777 |
|
|
}
|
3778 |
|
|
}
|
3779 |
|
|
#ifdef CYGPKG_SNMPAGENT_V3_SUPPORT
|
3780 |
|
|
/* call USM to free any securityStateRef supplied with the message */
|
3781 |
|
|
if (pdu->securityStateRef && pdu->command == SNMP_MSG_TRAP2) {
|
3782 |
|
|
usm_free_usmStateReference(pdu->securityStateRef);
|
3783 |
|
|
pdu->securityStateRef = NULL;
|
3784 |
|
|
}
|
3785 |
|
|
#endif
|
3786 |
|
|
snmp_free_pdu(pdu);
|
3787 |
|
|
return 0;
|
3788 |
|
|
}
|
3789 |
|
|
|
3790 |
|
|
/* returns 0 if success, -1 if fail */
|
3791 |
|
|
int
|
3792 |
|
|
snmp_sess_read(void *sessp,
|
3793 |
|
|
fd_set *fdset)
|
3794 |
|
|
{
|
3795 |
|
|
struct session_list *psl;
|
3796 |
|
|
struct snmp_session *pss;
|
3797 |
|
|
int rc;
|
3798 |
|
|
|
3799 |
|
|
rc = _sess_read(sessp, fdset);
|
3800 |
|
|
psl = (struct session_list *)sessp;
|
3801 |
|
|
pss = psl->session;
|
3802 |
|
|
if (rc && pss->s_snmp_errno) {
|
3803 |
|
|
SET_SNMP_ERROR(pss->s_snmp_errno);
|
3804 |
|
|
}
|
3805 |
|
|
return rc;
|
3806 |
|
|
}
|
3807 |
|
|
|
3808 |
|
|
|
3809 |
|
|
/*
|
3810 |
|
|
* Returns info about what snmp requires from a select statement.
|
3811 |
|
|
* numfds is the number of fds in the list that are significant.
|
3812 |
|
|
* All file descriptors opened for SNMP are OR'd into the fdset.
|
3813 |
|
|
* If activity occurs on any of these file descriptors, snmp_read
|
3814 |
|
|
* should be called with that file descriptor set
|
3815 |
|
|
*
|
3816 |
|
|
* The timeout is the latest time that SNMP can wait for a timeout. The
|
3817 |
|
|
* select should be done with the minimum time between timeout and any other
|
3818 |
|
|
* timeouts necessary. This should be checked upon each invocation of select.
|
3819 |
|
|
* If a timeout is received, snmp_timeout should be called to check if the
|
3820 |
|
|
* timeout was for SNMP. (snmp_timeout is idempotent)
|
3821 |
|
|
*
|
3822 |
|
|
* The value of block indicates how the timeout value is interpreted.
|
3823 |
|
|
* If block is true on input, the timeout value will be treated as undefined,
|
3824 |
|
|
* but it must be available for setting in snmp_select_info. On return,
|
3825 |
|
|
* block is set to true if the value returned for timeout is undefined;
|
3826 |
|
|
* when block is set to false, timeout may be used as a parmeter to 'select'.
|
3827 |
|
|
*
|
3828 |
|
|
* snmp_select_info returns the number of open sockets. (i.e. The number of
|
3829 |
|
|
* sessions open)
|
3830 |
|
|
*/
|
3831 |
|
|
|
3832 |
|
|
int
|
3833 |
|
|
snmp_select_info(int *numfds,
|
3834 |
|
|
fd_set *fdset,
|
3835 |
|
|
struct timeval *timeout,
|
3836 |
|
|
int *block)
|
3837 |
|
|
/* input: set to 1 if input timeout value is undefined */
|
3838 |
|
|
/* set to 0 if input timeout value is defined */
|
3839 |
|
|
/* output: set to 1 if output timeout value is undefined */
|
3840 |
|
|
/* set to 0 if output rimeout vlaue id defined */
|
3841 |
|
|
{
|
3842 |
|
|
return snmp_sess_select_info((void *)0, numfds, fdset, timeout, block);
|
3843 |
|
|
}
|
3844 |
|
|
|
3845 |
|
|
/* Same as snmp_select_info, but works just one session. */
|
3846 |
|
|
int
|
3847 |
|
|
snmp_sess_select_info(void *sessp,
|
3848 |
|
|
int *numfds,
|
3849 |
|
|
fd_set *fdset,
|
3850 |
|
|
struct timeval *timeout,
|
3851 |
|
|
int *block)
|
3852 |
|
|
{
|
3853 |
|
|
struct session_list *slptest = (struct session_list *)sessp;
|
3854 |
|
|
struct session_list *slp, *next=NULL, *prev=NULL;
|
3855 |
|
|
struct snmp_internal_session *isp;
|
3856 |
|
|
struct request_list *rp;
|
3857 |
|
|
struct timeval now, earliest;
|
3858 |
|
|
int timer_set = 0;
|
3859 |
|
|
int active = 0, requests = 0;
|
3860 |
|
|
int next_alarm = 0;
|
3861 |
|
|
|
3862 |
|
|
timerclear(&earliest);
|
3863 |
|
|
/*
|
3864 |
|
|
* For each request outstanding, add it's socket to the fdset,
|
3865 |
|
|
* and if it is the earliest timeout to expire, mark it as lowest.
|
3866 |
|
|
* If a single session is specified, do just for that session.
|
3867 |
|
|
*/
|
3868 |
|
|
if (sessp) slp = slptest; else slp = Sessions;
|
3869 |
|
|
for(; slp; slp = next){
|
3870 |
|
|
isp = slp->internal;
|
3871 |
|
|
if (!isp) {
|
3872 |
|
|
DEBUGMSGTL(("sess_select","select fail: closing...\n"));
|
3873 |
|
|
continue; /* close in progress - skip this one */
|
3874 |
|
|
}
|
3875 |
|
|
|
3876 |
|
|
if (isp->sd == -1) {
|
3877 |
|
|
if (sessp == NULL) {
|
3878 |
|
|
/* This session was marked for deletion */
|
3879 |
|
|
if ( prev == NULL )
|
3880 |
|
|
Sessions = slp->next;
|
3881 |
|
|
else
|
3882 |
|
|
prev->next = slp->next;
|
3883 |
|
|
next = slp->next;
|
3884 |
|
|
}
|
3885 |
|
|
snmp_sess_close( slp );
|
3886 |
|
|
continue;
|
3887 |
|
|
}
|
3888 |
|
|
if ((isp->sd + 1) > *numfds)
|
3889 |
|
|
*numfds = (isp->sd + 1);
|
3890 |
|
|
FD_SET(isp->sd, fdset);
|
3891 |
|
|
if (isp->requests){
|
3892 |
|
|
/* found another session with outstanding requests */
|
3893 |
|
|
requests++;
|
3894 |
|
|
for(rp = isp->requests; rp; rp = rp->next_request){
|
3895 |
|
|
if ((!timerisset(&earliest)
|
3896 |
|
|
|| (timercmp(&rp->expire, &earliest, <))))
|
3897 |
|
|
earliest = rp->expire;
|
3898 |
|
|
}
|
3899 |
|
|
}
|
3900 |
|
|
if (isp->newpkt) {
|
3901 |
|
|
/* don't block at all, more data waiting to be processed */
|
3902 |
|
|
DEBUGMSGTL(("sess_select","more data in buffer, not blocking\n"));
|
3903 |
|
|
requests++;
|
3904 |
|
|
timer_set = 1;
|
3905 |
|
|
*block = 0;
|
3906 |
|
|
}
|
3907 |
|
|
active++;
|
3908 |
|
|
if (slp == slptest) break;
|
3909 |
|
|
prev = slp;
|
3910 |
|
|
next = slp->next;
|
3911 |
|
|
}
|
3912 |
|
|
|
3913 |
|
|
if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_ALARM_DONT_USE_SIG)) {
|
3914 |
|
|
next_alarm = get_next_alarm_delay_time();
|
3915 |
|
|
}
|
3916 |
|
|
if (next_alarm == 0 && requests == 0) { /* if none are active, skip arithmetic */
|
3917 |
|
|
*block = 1; /* can block - timeout value is undefined if no requests*/
|
3918 |
|
|
return active;
|
3919 |
|
|
}
|
3920 |
|
|
|
3921 |
|
|
/*
|
3922 |
|
|
* Now find out how much time until the earliest timeout. This
|
3923 |
|
|
* transforms earliest from an absolute time into a delta time, the
|
3924 |
|
|
* time left until the select should timeout.
|
3925 |
|
|
*/
|
3926 |
|
|
gettimeofday(&now,(struct timezone *)0);
|
3927 |
|
|
/*Now = now;*/
|
3928 |
|
|
|
3929 |
|
|
if (next_alarm != 0 && earliest.tv_sec > next_alarm) {
|
3930 |
|
|
earliest.tv_sec = next_alarm;
|
3931 |
|
|
earliest.tv_usec = 0;
|
3932 |
|
|
}
|
3933 |
|
|
|
3934 |
|
|
if (timer_set || earliest.tv_sec < now.tv_sec) {
|
3935 |
|
|
earliest.tv_sec = 0;
|
3936 |
|
|
earliest.tv_usec = 100;
|
3937 |
|
|
}
|
3938 |
|
|
else if (earliest.tv_sec == now.tv_sec) {
|
3939 |
|
|
earliest.tv_sec = 0;
|
3940 |
|
|
earliest.tv_usec = (earliest.tv_usec - now.tv_usec);
|
3941 |
|
|
if (earliest.tv_usec < 0) {
|
3942 |
|
|
earliest.tv_usec = 100;
|
3943 |
|
|
}
|
3944 |
|
|
}
|
3945 |
|
|
else {
|
3946 |
|
|
earliest.tv_sec = (earliest.tv_sec - now.tv_sec);
|
3947 |
|
|
earliest.tv_usec = (earliest.tv_usec - now.tv_usec);
|
3948 |
|
|
if (earliest.tv_usec < 0) {
|
3949 |
|
|
earliest.tv_sec --;
|
3950 |
|
|
earliest.tv_usec = (1000000L + earliest.tv_usec);
|
3951 |
|
|
}
|
3952 |
|
|
}
|
3953 |
|
|
|
3954 |
|
|
/* if it was blocking before or our delta time is less, reset timeout */
|
3955 |
|
|
if ((*block || (timercmp(&earliest, timeout, <)))){
|
3956 |
|
|
*timeout = earliest;
|
3957 |
|
|
*block = 0;
|
3958 |
|
|
}
|
3959 |
|
|
return active;
|
3960 |
|
|
}
|
3961 |
|
|
|
3962 |
|
|
/*
|
3963 |
|
|
* snmp_timeout should be called whenever the timeout from snmp_select_info
|
3964 |
|
|
* expires, but it is idempotent, so snmp_timeout can be polled (probably a
|
3965 |
|
|
* cpu expensive proposition). snmp_timeout checks to see if any of the
|
3966 |
|
|
* sessions have an outstanding request that has timed out. If it finds one
|
3967 |
|
|
* (or more), and that pdu has more retries available, a new packet is formed
|
3968 |
|
|
* from the pdu and is resent. If there are no more retries available, the
|
3969 |
|
|
* callback for the session is used to alert the user of the timeout.
|
3970 |
|
|
*/
|
3971 |
|
|
void
|
3972 |
|
|
snmp_timeout (void)
|
3973 |
|
|
{
|
3974 |
|
|
struct session_list *slp;
|
3975 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
3976 |
|
|
for(slp = Sessions; slp; slp = slp->next){
|
3977 |
|
|
snmp_sess_timeout((void *)slp);
|
3978 |
|
|
}
|
3979 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
3980 |
|
|
}
|
3981 |
|
|
|
3982 |
|
|
static int
|
3983 |
|
|
snmp_resend_request(struct session_list *slp, struct request_list *rp,
|
3984 |
|
|
int incr_retries)
|
3985 |
|
|
{
|
3986 |
|
|
u_char packet[PACKET_LENGTH];
|
3987 |
|
|
size_t length = PACKET_LENGTH;
|
3988 |
|
|
struct timeval tv;
|
3989 |
|
|
struct snmp_session *sp;
|
3990 |
|
|
struct snmp_internal_session *isp;
|
3991 |
|
|
struct timeval now;
|
3992 |
|
|
int result, addr_size;
|
3993 |
|
|
|
3994 |
|
|
sp = slp->session; isp = slp->internal;
|
3995 |
|
|
if (!sp || !isp) {
|
3996 |
|
|
DEBUGMSGTL(("sess_read","resend fail: closing...\n"));
|
3997 |
|
|
return 0;
|
3998 |
|
|
}
|
3999 |
|
|
|
4000 |
|
|
if (incr_retries) rp->retries++;
|
4001 |
|
|
|
4002 |
|
|
/* always increment msgId for resent messages */
|
4003 |
|
|
rp->pdu->msgid = rp->message_id = snmp_get_next_msgid();
|
4004 |
|
|
|
4005 |
|
|
/* retransmit this pdu */
|
4006 |
|
|
if (snmp_build(sp, rp->pdu, packet, &length) < 0){
|
4007 |
|
|
/* this should never happen */
|
4008 |
|
|
return -1;
|
4009 |
|
|
}
|
4010 |
|
|
if (ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET)){
|
4011 |
|
|
struct sockaddr_in *pduIp;
|
4012 |
|
|
pduIp = (struct sockaddr_in *)&(rp->pdu->address);
|
4013 |
|
|
snmp_log(LOG_DEBUG, "\nResending %d bytes to %s:%hu\n", length,
|
4014 |
|
|
inet_ntoa(pduIp->sin_addr), ntohs(pduIp->sin_port));
|
4015 |
|
|
xdump(packet, length, "");
|
4016 |
|
|
}
|
4017 |
|
|
|
4018 |
|
|
addr_size = snmp_socket_length(rp->pdu->address.sa_family);
|
4019 |
|
|
|
4020 |
|
|
#if !defined(__ECOS)
|
4021 |
|
|
if ( sp->flags & SNMP_FLAGS_STREAM_SOCKET )
|
4022 |
|
|
result = send(isp->sd, (char *)packet, length, 0);
|
4023 |
|
|
else
|
4024 |
|
|
#endif
|
4025 |
|
|
result = sendto(isp->sd, (char *)packet, length, 0,
|
4026 |
|
|
(struct sockaddr *)&rp->pdu->address, addr_size);
|
4027 |
|
|
if ( result < 0){
|
4028 |
|
|
sp->s_snmp_errno = SNMPERR_BAD_SENDTO;
|
4029 |
|
|
sp->s_errno = errno;
|
4030 |
|
|
snmp_set_detail(strerror(errno));
|
4031 |
|
|
return -1;
|
4032 |
|
|
}
|
4033 |
|
|
else {
|
4034 |
|
|
gettimeofday(&now, (struct timezone *)0);
|
4035 |
|
|
tv = now;
|
4036 |
|
|
rp->time = tv;
|
4037 |
|
|
tv.tv_usec += rp->timeout;
|
4038 |
|
|
tv.tv_sec += tv.tv_usec / 1000000L;
|
4039 |
|
|
tv.tv_usec %= 1000000L;
|
4040 |
|
|
rp->expire = tv;
|
4041 |
|
|
}
|
4042 |
|
|
return 0;
|
4043 |
|
|
}
|
4044 |
|
|
|
4045 |
|
|
void
|
4046 |
|
|
snmp_sess_timeout(void *sessp)
|
4047 |
|
|
{
|
4048 |
|
|
struct session_list *slp = (struct session_list*)sessp;
|
4049 |
|
|
struct snmp_session *sp;
|
4050 |
|
|
struct snmp_internal_session *isp;
|
4051 |
|
|
struct request_list *rp, *orp = NULL, *freeme = NULL;
|
4052 |
|
|
struct timeval now;
|
4053 |
|
|
snmp_callback callback;
|
4054 |
|
|
void *magic;
|
4055 |
|
|
|
4056 |
|
|
sp = slp->session; isp = slp->internal;
|
4057 |
|
|
if (!sp || !isp) {
|
4058 |
|
|
DEBUGMSGTL(("sess_read","timeout fail: closing...\n"));
|
4059 |
|
|
return;
|
4060 |
|
|
}
|
4061 |
|
|
|
4062 |
|
|
gettimeofday(&now,(struct timezone *)0);
|
4063 |
|
|
|
4064 |
|
|
/*
|
4065 |
|
|
* For each request outstanding, check to see if it has expired.
|
4066 |
|
|
*/
|
4067 |
|
|
for(rp = isp->requests; rp; rp = rp->next_request){
|
4068 |
|
|
if (freeme != NULL){
|
4069 |
|
|
/* frees rp's after the for loop goes on to the next_request */
|
4070 |
|
|
free((char *)freeme);
|
4071 |
|
|
freeme = NULL;
|
4072 |
|
|
}
|
4073 |
|
|
if ((timercmp(&rp->expire, &now, <))){
|
4074 |
|
|
/* this timer has expired */
|
4075 |
|
|
if (rp->retries >= sp->retries){
|
4076 |
|
|
if (rp->callback) {
|
4077 |
|
|
callback = rp->callback;
|
4078 |
|
|
magic = rp->cb_data;
|
4079 |
|
|
} else {
|
4080 |
|
|
callback = sp->callback;
|
4081 |
|
|
magic = sp->callback_magic;
|
4082 |
|
|
}
|
4083 |
|
|
/* No more chances, delete this entry */
|
4084 |
|
|
if (callback)
|
4085 |
|
|
callback(TIMED_OUT, sp, rp->pdu->reqid, rp->pdu, magic);
|
4086 |
|
|
if (isp->requests == rp){
|
4087 |
|
|
isp->requests = rp->next_request;
|
4088 |
|
|
if (isp->requestsEnd == rp)
|
4089 |
|
|
isp->requestsEnd = NULL;
|
4090 |
|
|
} else {
|
4091 |
|
|
orp->next_request = rp->next_request;
|
4092 |
|
|
if (isp->requestsEnd == rp)
|
4093 |
|
|
isp->requestsEnd = orp;
|
4094 |
|
|
}
|
4095 |
|
|
snmp_free_pdu(rp->pdu); /* FIX rp is already free'd! */
|
4096 |
|
|
freeme = rp;
|
4097 |
|
|
continue; /* don't update orp below */
|
4098 |
|
|
} else {
|
4099 |
|
|
if (snmp_resend_request(slp, rp, TRUE)) break;
|
4100 |
|
|
}
|
4101 |
|
|
}
|
4102 |
|
|
orp = rp;
|
4103 |
|
|
}
|
4104 |
|
|
if (freeme != NULL){
|
4105 |
|
|
free((char *)freeme);
|
4106 |
|
|
freeme = NULL;
|
4107 |
|
|
}
|
4108 |
|
|
}
|
4109 |
|
|
|
4110 |
|
|
/* lexicographical compare two object identifiers.
|
4111 |
|
|
* Returns -1 if name1 < name2,
|
4112 |
|
|
* 0 if name1 = name2,
|
4113 |
|
|
* 1 if name1 > name2
|
4114 |
|
|
*
|
4115 |
|
|
* Caution: this method is called often by
|
4116 |
|
|
* command responder applications (ie, agent).
|
4117 |
|
|
*/
|
4118 |
|
|
int
|
4119 |
|
|
snmp_oid_compare(const oid *in_name1,
|
4120 |
|
|
size_t len1,
|
4121 |
|
|
const oid *in_name2,
|
4122 |
|
|
size_t len2)
|
4123 |
|
|
{
|
4124 |
|
|
register int len, res;
|
4125 |
|
|
register const oid * name1 = in_name1;
|
4126 |
|
|
register const oid * name2 = in_name2;
|
4127 |
|
|
|
4128 |
|
|
/* len = minimum of len1 and len2 */
|
4129 |
|
|
if (len1 < len2)
|
4130 |
|
|
len = len1;
|
4131 |
|
|
else
|
4132 |
|
|
len = len2;
|
4133 |
|
|
/* find first non-matching OID */
|
4134 |
|
|
while(len-- > 0){
|
4135 |
|
|
res = *(name1++) - *(name2++);
|
4136 |
|
|
if (res < 0)
|
4137 |
|
|
return -1;
|
4138 |
|
|
if (res > 0)
|
4139 |
|
|
return 1;
|
4140 |
|
|
}
|
4141 |
|
|
/* both OIDs equal up to length of shorter OID */
|
4142 |
|
|
if (len1 < len2)
|
4143 |
|
|
return -1;
|
4144 |
|
|
if (len2 < len1)
|
4145 |
|
|
return 1;
|
4146 |
|
|
return 0;
|
4147 |
|
|
}
|
4148 |
|
|
|
4149 |
|
|
/*
|
4150 |
|
|
* Add a variable with the requested name to the end of the list of
|
4151 |
|
|
* variables for this pdu.
|
4152 |
|
|
*/
|
4153 |
|
|
struct variable_list *
|
4154 |
|
|
snmp_pdu_add_variable(struct snmp_pdu *pdu,
|
4155 |
|
|
oid *name,
|
4156 |
|
|
size_t name_length,
|
4157 |
|
|
u_char type,
|
4158 |
|
|
u_char *value,
|
4159 |
|
|
size_t len)
|
4160 |
|
|
{
|
4161 |
|
|
return snmp_varlist_add_variable(&pdu->variables, name, name_length, type,
|
4162 |
|
|
value, len);
|
4163 |
|
|
}
|
4164 |
|
|
|
4165 |
|
|
/*
|
4166 |
|
|
* Add a variable with the requested name to the end of the list of
|
4167 |
|
|
* variables for this pdu.
|
4168 |
|
|
*/
|
4169 |
|
|
struct variable_list *
|
4170 |
|
|
snmp_varlist_add_variable(struct variable_list **varlist,
|
4171 |
|
|
oid *name,
|
4172 |
|
|
size_t name_length,
|
4173 |
|
|
u_char type,
|
4174 |
|
|
u_char *value,
|
4175 |
|
|
size_t len)
|
4176 |
|
|
{
|
4177 |
|
|
struct variable_list *vars, *vtmp;
|
4178 |
|
|
int largeval = 1;
|
4179 |
|
|
|
4180 |
|
|
if (varlist == NULL)
|
4181 |
|
|
return NULL;
|
4182 |
|
|
|
4183 |
|
|
vars = (struct variable_list *)malloc(sizeof(struct variable_list));
|
4184 |
|
|
if (vars == NULL)
|
4185 |
|
|
return NULL;
|
4186 |
|
|
|
4187 |
|
|
vars->next_variable = 0; vars->name = 0; vars->val.string = 0;
|
4188 |
|
|
|
4189 |
|
|
/* use built-in storage for smaller values */
|
4190 |
|
|
if (len <= sizeof(vars->buf)) {
|
4191 |
|
|
vars->val.string = (u_char *)vars->buf;
|
4192 |
|
|
largeval = 0;
|
4193 |
|
|
}
|
4194 |
|
|
|
4195 |
|
|
vars->type = type;
|
4196 |
|
|
vars->val_len = len;
|
4197 |
|
|
switch(type){
|
4198 |
|
|
case ASN_INTEGER:
|
4199 |
|
|
case ASN_UNSIGNED:
|
4200 |
|
|
case ASN_TIMETICKS:
|
4201 |
|
|
case ASN_IPADDRESS:
|
4202 |
|
|
case ASN_COUNTER:
|
4203 |
|
|
memmove(vars->val.integer, value, vars->val_len);
|
4204 |
|
|
vars->val_len = sizeof(long);
|
4205 |
|
|
break;
|
4206 |
|
|
|
4207 |
|
|
case ASN_OBJECT_ID:
|
4208 |
|
|
case ASN_PRIV_INCL_RANGE:
|
4209 |
|
|
case ASN_PRIV_EXCL_RANGE:
|
4210 |
|
|
if (largeval) {
|
4211 |
|
|
vars->val.objid = (oid *)malloc(vars->val_len);
|
4212 |
|
|
}
|
4213 |
|
|
memmove(vars->val.objid, value, vars->val_len);
|
4214 |
|
|
break;
|
4215 |
|
|
|
4216 |
|
|
case ASN_OCTET_STR:
|
4217 |
|
|
case ASN_OPAQUE:
|
4218 |
|
|
case ASN_NSAP:
|
4219 |
|
|
if (largeval) {
|
4220 |
|
|
vars->val.string = (u_char *)malloc(vars->val_len);
|
4221 |
|
|
}
|
4222 |
|
|
memmove(vars->val.string, value, vars->val_len);
|
4223 |
|
|
break;
|
4224 |
|
|
|
4225 |
|
|
case SNMP_NOSUCHOBJECT:
|
4226 |
|
|
case SNMP_NOSUCHINSTANCE:
|
4227 |
|
|
case SNMP_ENDOFMIBVIEW:
|
4228 |
|
|
case ASN_NULL:
|
4229 |
|
|
vars->val_len = 0;
|
4230 |
|
|
vars->val.string = NULL;
|
4231 |
|
|
break;
|
4232 |
|
|
|
4233 |
|
|
#ifdef OPAQUE_SPECIAL_TYPES
|
4234 |
|
|
case ASN_OPAQUE_U64:
|
4235 |
|
|
case ASN_OPAQUE_I64:
|
4236 |
|
|
#endif /* OPAQUE_SPECIAL_TYPES */
|
4237 |
|
|
case ASN_COUNTER64:
|
4238 |
|
|
vars->val_len = sizeof(struct counter64);
|
4239 |
|
|
memmove(vars->val.counter64, value, vars->val_len);
|
4240 |
|
|
break;
|
4241 |
|
|
|
4242 |
|
|
#ifdef OPAQUE_SPECIAL_TYPES
|
4243 |
|
|
case ASN_OPAQUE_FLOAT:
|
4244 |
|
|
vars->val_len = sizeof(float);
|
4245 |
|
|
memmove(vars->val.floatVal, value, vars->val_len);
|
4246 |
|
|
break;
|
4247 |
|
|
|
4248 |
|
|
case ASN_OPAQUE_DOUBLE:
|
4249 |
|
|
vars->val_len = sizeof(double);
|
4250 |
|
|
memmove(vars->val.doubleVal, value, vars->val_len);
|
4251 |
|
|
|
4252 |
|
|
#endif /* OPAQUE_SPECIAL_TYPES */
|
4253 |
|
|
|
4254 |
|
|
default:
|
4255 |
|
|
snmp_set_detail("Internal error in type switching\n");
|
4256 |
|
|
snmp_free_var(vars);
|
4257 |
|
|
return (0);
|
4258 |
|
|
}
|
4259 |
|
|
|
4260 |
|
|
if (name != NULL && snmp_set_var_objid(vars, name, name_length)) {
|
4261 |
|
|
snmp_free_var(vars);
|
4262 |
|
|
return (0);
|
4263 |
|
|
}
|
4264 |
|
|
|
4265 |
|
|
/* put only qualified variable onto varlist */
|
4266 |
|
|
if (*varlist == NULL){
|
4267 |
|
|
*varlist = vars;
|
4268 |
|
|
} else {
|
4269 |
|
|
for(vtmp = *varlist;
|
4270 |
|
|
vtmp->next_variable;
|
4271 |
|
|
vtmp = vtmp->next_variable)
|
4272 |
|
|
;
|
4273 |
|
|
|
4274 |
|
|
vtmp->next_variable = vars;
|
4275 |
|
|
}
|
4276 |
|
|
|
4277 |
|
|
return vars;
|
4278 |
|
|
}
|
4279 |
|
|
|
4280 |
|
|
/*
|
4281 |
|
|
* Parses dotted notation object identifier
|
4282 |
|
|
* into unsigned character array.
|
4283 |
|
|
* Returns: SNMPERR_RANGE if any sub-identifier > 255.
|
4284 |
|
|
* Returns: SNMPERR_VALUE if input string is not octet string.
|
4285 |
|
|
* Returns: non-negative number of sub-identifiers parsed,
|
4286 |
|
|
*/
|
4287 |
|
|
int
|
4288 |
|
|
ascii_to_binary(const char *cp,
|
4289 |
|
|
u_char *bufp)
|
4290 |
|
|
{
|
4291 |
|
|
int subidentifier;
|
4292 |
|
|
u_char *bp = bufp;
|
4293 |
|
|
|
4294 |
|
|
for(; *cp != '\0'; cp++){
|
4295 |
|
|
if (isspace(*cp) || *cp == '.')
|
4296 |
|
|
continue;
|
4297 |
|
|
if (!isdigit(*cp)){
|
4298 |
|
|
return SNMPERR_VALUE;
|
4299 |
|
|
}
|
4300 |
|
|
subidentifier = atoi(cp);
|
4301 |
|
|
if (subidentifier > 255){
|
4302 |
|
|
return SNMPERR_RANGE;
|
4303 |
|
|
}
|
4304 |
|
|
*bp++ = (u_char)subidentifier;
|
4305 |
|
|
while(isdigit(*cp))
|
4306 |
|
|
cp++;
|
4307 |
|
|
cp--;
|
4308 |
|
|
}
|
4309 |
|
|
return bp - bufp;
|
4310 |
|
|
}
|
4311 |
|
|
|
4312 |
|
|
int
|
4313 |
|
|
hex_to_binary(const char *str,
|
4314 |
|
|
u_char *bufp)
|
4315 |
|
|
{
|
4316 |
|
|
int len, itmp;
|
4317 |
|
|
if (!bufp) return -1;
|
4318 |
|
|
if (*str && *str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) str += 2;
|
4319 |
|
|
for (len = 0; *str; str++) {
|
4320 |
|
|
if (isspace(*str)) continue;
|
4321 |
|
|
if (!isxdigit(*str)) return -1;
|
4322 |
|
|
len++;
|
4323 |
|
|
if (sscanf(str++, "%2x", &itmp) == 0) return -1;
|
4324 |
|
|
*bufp++ = itmp;
|
4325 |
|
|
if (!*str) return -1; /* odd number of chars is an error */
|
4326 |
|
|
}
|
4327 |
|
|
return len;
|
4328 |
|
|
}
|
4329 |
|
|
|
4330 |
|
|
|
4331 |
|
|
/*
|
4332 |
|
|
* Add a variable with the requested name to the end of the list of
|
4333 |
|
|
* variables for this pdu.
|
4334 |
|
|
* Returns:
|
4335 |
|
|
* may set these error types :
|
4336 |
|
|
* SNMPERR_RANGE - type, value, or length not found or out of range
|
4337 |
|
|
* SNMPERR_VALUE - value is not correct
|
4338 |
|
|
* SNMPERR_BAD_NAME - name is not found
|
4339 |
|
|
*
|
4340 |
|
|
* returns 0 if success, error if failure.
|
4341 |
|
|
*/
|
4342 |
|
|
int
|
4343 |
|
|
snmp_add_var(struct snmp_pdu *pdu,
|
4344 |
|
|
oid *name,
|
4345 |
|
|
size_t name_length,
|
4346 |
|
|
char type,
|
4347 |
|
|
const char *value)
|
4348 |
|
|
{
|
4349 |
|
|
int result = 0;
|
4350 |
|
|
u_char buf[SPRINT_MAX_LEN];
|
4351 |
|
|
size_t tint;
|
4352 |
|
|
long ltmp;
|
4353 |
|
|
struct tree *tp;
|
4354 |
|
|
struct enum_list *ep;
|
4355 |
|
|
struct range_list *rp;
|
4356 |
|
|
#ifdef OPAQUE_SPECIAL_TYPES
|
4357 |
|
|
double dtmp;
|
4358 |
|
|
float ftmp;
|
4359 |
|
|
struct counter64 c64tmp;
|
4360 |
|
|
#endif /* OPAQUE_SPECIAL_TYPES */
|
4361 |
|
|
|
4362 |
|
|
switch(type){
|
4363 |
|
|
case 'i':
|
4364 |
|
|
tp = get_tree(name, name_length, get_tree_head());
|
4365 |
|
|
if (sscanf(value, "%ld", <mp) != 1) {
|
4366 |
|
|
ep = tp ? tp->enums : NULL;
|
4367 |
|
|
while (ep) {
|
4368 |
|
|
if (strcmp(value, ep->label) == 0) {
|
4369 |
|
|
ltmp = ep->value;
|
4370 |
|
|
break;
|
4371 |
|
|
}
|
4372 |
|
|
ep = ep->next;
|
4373 |
|
|
}
|
4374 |
|
|
if (!ep) {
|
4375 |
|
|
result = SNMPERR_BAD_NAME;
|
4376 |
|
|
snmp_set_detail(value);
|
4377 |
|
|
break;
|
4378 |
|
|
}
|
4379 |
|
|
}
|
4380 |
|
|
|
4381 |
|
|
if (tp && tp->ranges && !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE)) {
|
4382 |
|
|
rp = tp->ranges;
|
4383 |
|
|
while (rp) {
|
4384 |
|
|
if (rp->low <= ltmp && ltmp <= rp->high) break;
|
4385 |
|
|
rp = rp->next;
|
4386 |
|
|
}
|
4387 |
|
|
if (!rp) {
|
4388 |
|
|
result = SNMPERR_RANGE;
|
4389 |
|
|
snmp_set_detail("Value");
|
4390 |
|
|
break;
|
4391 |
|
|
}
|
4392 |
|
|
}
|
4393 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_INTEGER,
|
4394 |
|
|
(u_char *) <mp, sizeof(ltmp));
|
4395 |
|
|
break;
|
4396 |
|
|
|
4397 |
|
|
case 'u':
|
4398 |
|
|
if (sscanf(value, "%lu", <mp) == 1)
|
4399 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_UNSIGNED,
|
4400 |
|
|
(u_char *) <mp, sizeof(ltmp));
|
4401 |
|
|
else goto fail;
|
4402 |
|
|
break;
|
4403 |
|
|
|
4404 |
|
|
case 'c':
|
4405 |
|
|
if (sscanf(value, "%lu", <mp) == 1)
|
4406 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER,
|
4407 |
|
|
(u_char *) <mp, sizeof(ltmp));
|
4408 |
|
|
else goto fail;
|
4409 |
|
|
break;
|
4410 |
|
|
|
4411 |
|
|
case 't':
|
4412 |
|
|
if (sscanf(value, "%lu", <mp) == 1)
|
4413 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_TIMETICKS,
|
4414 |
|
|
(u_char *) <mp, sizeof(long));
|
4415 |
|
|
else goto fail;
|
4416 |
|
|
break;
|
4417 |
|
|
|
4418 |
|
|
case 'a':
|
4419 |
|
|
if ((ltmp = inet_addr(value)) != (long)-1)
|
4420 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_IPADDRESS,
|
4421 |
|
|
(u_char *) <mp, sizeof(long));
|
4422 |
|
|
else goto fail;
|
4423 |
|
|
break;
|
4424 |
|
|
|
4425 |
|
|
case 'o':
|
4426 |
|
|
tint = sizeof(buf) / sizeof(oid);
|
4427 |
|
|
if (read_objid(value, (oid *)buf, &tint))
|
4428 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_OBJECT_ID, buf,
|
4429 |
|
|
sizeof(oid)*tint);
|
4430 |
|
|
else result = snmp_errno;
|
4431 |
|
|
break;
|
4432 |
|
|
|
4433 |
|
|
case 's':
|
4434 |
|
|
case 'x':
|
4435 |
|
|
case 'd':
|
4436 |
|
|
if (type == 'd'){
|
4437 |
|
|
ltmp = ascii_to_binary(value, buf);
|
4438 |
|
|
} else if (type == 's'){
|
4439 |
|
|
strcpy((char*)buf, value);
|
4440 |
|
|
ltmp = strlen((char*)buf);
|
4441 |
|
|
} else if (type == 'x'){
|
4442 |
|
|
ltmp = hex_to_binary(value, buf);
|
4443 |
|
|
}
|
4444 |
|
|
if (ltmp < 0) {
|
4445 |
|
|
result = SNMPERR_VALUE;
|
4446 |
|
|
snmp_set_detail(value);
|
4447 |
|
|
break;
|
4448 |
|
|
}
|
4449 |
|
|
tp = get_tree(name, name_length, get_tree_head());
|
4450 |
|
|
if (tp && tp->ranges && !ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DONT_CHECK_RANGE)) {
|
4451 |
|
|
rp = tp->ranges;
|
4452 |
|
|
while (rp) {
|
4453 |
|
|
if (rp->low <= ltmp && ltmp <= rp->high) break;
|
4454 |
|
|
rp = rp->next;
|
4455 |
|
|
}
|
4456 |
|
|
if (!rp) {
|
4457 |
|
|
result = SNMPERR_RANGE;
|
4458 |
|
|
snmp_set_detail("Length");
|
4459 |
|
|
break;
|
4460 |
|
|
}
|
4461 |
|
|
}
|
4462 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_OCTET_STR, buf, ltmp);
|
4463 |
|
|
break;
|
4464 |
|
|
|
4465 |
|
|
case 'n':
|
4466 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, 0, 0);
|
4467 |
|
|
break;
|
4468 |
|
|
|
4469 |
|
|
#ifdef OPAQUE_SPECIAL_TYPES
|
4470 |
|
|
case 'U':
|
4471 |
|
|
if (read64(&c64tmp, value))
|
4472 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_U64,
|
4473 |
|
|
(u_char *) &c64tmp, sizeof(c64tmp));
|
4474 |
|
|
else goto fail;
|
4475 |
|
|
break;
|
4476 |
|
|
|
4477 |
|
|
case 'I':
|
4478 |
|
|
if (read64(&c64tmp, value))
|
4479 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_I64,
|
4480 |
|
|
(u_char *) &c64tmp, sizeof(c64tmp));
|
4481 |
|
|
else goto fail;
|
4482 |
|
|
break;
|
4483 |
|
|
|
4484 |
|
|
case 'F':
|
4485 |
|
|
if (sscanf(value, "%f", &ftmp) == 1)
|
4486 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_FLOAT,
|
4487 |
|
|
(u_char *) &ftmp, sizeof(ftmp));
|
4488 |
|
|
else goto fail;
|
4489 |
|
|
break;
|
4490 |
|
|
|
4491 |
|
|
case 'D':
|
4492 |
|
|
if (sscanf(value, "%lf", &dtmp) == 1)
|
4493 |
|
|
snmp_pdu_add_variable(pdu, name, name_length, ASN_OPAQUE_DOUBLE,
|
4494 |
|
|
(u_char *) &dtmp, sizeof(dtmp));
|
4495 |
|
|
else goto fail;
|
4496 |
|
|
break;
|
4497 |
|
|
#endif /* OPAQUE_SPECIAL_TYPES */
|
4498 |
|
|
|
4499 |
|
|
default:
|
4500 |
|
|
result = SNMPERR_VAR_TYPE;
|
4501 |
|
|
sprintf((char *)buf, "%c", type);
|
4502 |
|
|
snmp_set_detail((const char *)buf);
|
4503 |
|
|
break;
|
4504 |
|
|
}
|
4505 |
|
|
|
4506 |
|
|
SET_SNMP_ERROR(result);
|
4507 |
|
|
return result;
|
4508 |
|
|
|
4509 |
|
|
fail:
|
4510 |
|
|
result = SNMPERR_VALUE;
|
4511 |
|
|
snmp_set_detail(value);
|
4512 |
|
|
SET_SNMP_ERROR(result);
|
4513 |
|
|
return result;
|
4514 |
|
|
}
|
4515 |
|
|
|
4516 |
|
|
/*
|
4517 |
|
|
* returns NULL or internal pointer to session
|
4518 |
|
|
* use this pointer for the other snmp_sess* routines,
|
4519 |
|
|
* which guarantee action will occur ONLY for this given session.
|
4520 |
|
|
*/
|
4521 |
|
|
void *
|
4522 |
|
|
snmp_sess_pointer(struct snmp_session *session)
|
4523 |
|
|
{
|
4524 |
|
|
struct session_list *slp;
|
4525 |
|
|
|
4526 |
|
|
snmp_res_lock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
4527 |
|
|
for(slp = Sessions; slp; slp = slp->next){
|
4528 |
|
|
if (slp->session == session){
|
4529 |
|
|
break;
|
4530 |
|
|
}
|
4531 |
|
|
}
|
4532 |
|
|
snmp_res_unlock(MT_LIBRARY_ID, MT_LIB_SESSION);
|
4533 |
|
|
|
4534 |
|
|
if (slp == NULL){
|
4535 |
|
|
snmp_errno = SNMPERR_BAD_SESSION; /*MTCRITICAL_RESOURCE*/
|
4536 |
|
|
return(NULL);
|
4537 |
|
|
}
|
4538 |
|
|
return((void *)slp);
|
4539 |
|
|
}
|
4540 |
|
|
|
4541 |
|
|
/*
|
4542 |
|
|
* Input : an opaque pointer, returned by snmp_sess_open.
|
4543 |
|
|
* returns NULL or pointer to session.
|
4544 |
|
|
*/
|
4545 |
|
|
struct snmp_session *
|
4546 |
|
|
snmp_sess_session(void *sessp)
|
4547 |
|
|
{
|
4548 |
|
|
struct session_list *slp = (struct session_list *)sessp;
|
4549 |
|
|
if (slp == NULL) return(NULL);
|
4550 |
|
|
return (slp->session);
|
4551 |
|
|
}
|
4552 |
|
|
#ifdef CMU_COMPATIBLE
|
4553 |
|
|
|
4554 |
|
|
char *
|
4555 |
|
|
snmp_pdu_type(struct snmp_pdu *PDU)
|
4556 |
|
|
{
|
4557 |
|
|
switch(PDU->command) {
|
4558 |
|
|
case SNMP_MSG_GET:
|
4559 |
|
|
return("GET");
|
4560 |
|
|
break;
|
4561 |
|
|
case SNMP_MSG_GETNEXT:
|
4562 |
|
|
return("GETNEXT");
|
4563 |
|
|
break;
|
4564 |
|
|
case SNMP_MSG_RESPONSE:
|
4565 |
|
|
return("RESPONSE");
|
4566 |
|
|
break;
|
4567 |
|
|
case SNMP_MSG_SET:
|
4568 |
|
|
return("SET");
|
4569 |
|
|
break;
|
4570 |
|
|
case SNMP_MSG_GETBULK:
|
4571 |
|
|
return("GETBULK");
|
4572 |
|
|
break;
|
4573 |
|
|
case SNMP_MSG_INFORM:
|
4574 |
|
|
return("INFORM");
|
4575 |
|
|
break;
|
4576 |
|
|
case SNMP_MSG_TRAP2:
|
4577 |
|
|
return("V2TRAP");
|
4578 |
|
|
break;
|
4579 |
|
|
case SNMP_MSG_REPORT:
|
4580 |
|
|
return("REPORT");
|
4581 |
|
|
break;
|
4582 |
|
|
|
4583 |
|
|
case SNMP_MSG_TRAP:
|
4584 |
|
|
return("V1TRAP");
|
4585 |
|
|
break;
|
4586 |
|
|
default:
|
4587 |
|
|
return("Unknown");
|
4588 |
|
|
break;
|
4589 |
|
|
}
|
4590 |
|
|
}
|
4591 |
|
|
|
4592 |
|
|
/*
|
4593 |
|
|
* cmu_snmp_parse - emulate CMU library's snmp_parse.
|
4594 |
|
|
*
|
4595 |
|
|
* Parse packet, storing results into PDU.
|
4596 |
|
|
* Returns community string if success, NULL if fail.
|
4597 |
|
|
* WARNING: may return a zero length community string.
|
4598 |
|
|
*
|
4599 |
|
|
* Note:
|
4600 |
|
|
* Some CMU-aware apps call init_mib(), but do not
|
4601 |
|
|
* initialize a session.
|
4602 |
|
|
* Check Reqid to make sure that this module is initialized.
|
4603 |
|
|
*/
|
4604 |
|
|
|
4605 |
|
|
u_char *
|
4606 |
|
|
cmu_snmp_parse (struct snmp_session *session,
|
4607 |
|
|
struct snmp_pdu *pdu,
|
4608 |
|
|
u_char *data,
|
4609 |
|
|
size_t length)
|
4610 |
|
|
{
|
4611 |
|
|
u_char *bufp = NULL;
|
4612 |
|
|
|
4613 |
|
|
if (Reqid == 0) {
|
4614 |
|
|
snmp_sess_init(session); /* gimme a break! */
|
4615 |
|
|
}
|
4616 |
|
|
|
4617 |
|
|
switch(pdu->version) {
|
4618 |
|
|
case SNMP_VERSION_1:
|
4619 |
|
|
case SNMP_VERSION_2c:
|
4620 |
|
|
case SNMP_DEFAULT_VERSION:
|
4621 |
|
|
break;
|
4622 |
|
|
default:
|
4623 |
|
|
return NULL;
|
4624 |
|
|
}
|
4625 |
|
|
#ifndef NO_INTERNAL_VARLIST
|
4626 |
|
|
if (snmp_parse( 0, session, pdu, data, length) != SNMP_ERR_NOERROR){
|
4627 |
|
|
return NULL;
|
4628 |
|
|
}
|
4629 |
|
|
#else
|
4630 |
|
|
/*
|
4631 |
|
|
* while there are two versions of variable_list:
|
4632 |
|
|
* use an internal variable list for snmp_parse;
|
4633 |
|
|
* clone the result.
|
4634 |
|
|
*/
|
4635 |
|
|
if (1) {
|
4636 |
|
|
struct snmp_pdu *snmp_clone_pdu (struct snmp_pdu *);
|
4637 |
|
|
struct snmp_pdu *snmp_2clone_pdu(struct snmp_pdu *from_pdu, struct snmp_pdu *to_pdu);
|
4638 |
|
|
|
4639 |
|
|
struct snmp_pdu *ipdu;
|
4640 |
|
|
ipdu = snmp_clone_pdu(pdu);
|
4641 |
|
|
if (snmp_parse( 0, session, ipdu, data, length) != SNMP_ERR_NOERROR){
|
4642 |
|
|
snmp_free_internal_pdu(ipdu);
|
4643 |
|
|
return NULL;
|
4644 |
|
|
}
|
4645 |
|
|
pdu = snmp_2clone_pdu(ipdu, pdu);
|
4646 |
|
|
snmp_free_internal_pdu(ipdu);
|
4647 |
|
|
}
|
4648 |
|
|
#endif /* NO_INTERNAL_VAR_LIST */
|
4649 |
|
|
|
4650 |
|
|
/* Add a null to meet the caller's expectations. */
|
4651 |
|
|
|
4652 |
|
|
bufp = (u_char *)malloc(1+pdu->community_len);
|
4653 |
|
|
if (bufp && pdu->community_len) {
|
4654 |
|
|
memcpy(bufp, pdu->community, pdu->community_len);
|
4655 |
|
|
bufp[pdu->community_len] = '\0';
|
4656 |
|
|
}
|
4657 |
|
|
return(bufp);
|
4658 |
|
|
}
|
4659 |
|
|
|
4660 |
|
|
|
4661 |
|
|
#endif /* CMU_COMPATIBLE */
|
4662 |
|
|
|
4663 |
|
|
/* snmp_duplicate_objid: duplicates (mallocs) an objid based on the
|
4664 |
|
|
input objid */
|
4665 |
|
|
oid *
|
4666 |
|
|
snmp_duplicate_objid(oid *objToCopy, size_t objToCopyLen)
|
4667 |
|
|
{
|
4668 |
|
|
oid *returnOid;
|
4669 |
|
|
returnOid = (oid *) malloc(objToCopyLen*sizeof(oid));
|
4670 |
|
|
if (returnOid) {
|
4671 |
|
|
memmove(returnOid, objToCopy, objToCopyLen*sizeof(oid));
|
4672 |
|
|
}
|
4673 |
|
|
return returnOid;
|
4674 |
|
|
}
|
4675 |
|
|
|
4676 |
|
|
/* generic statistics counter functions */
|
4677 |
|
|
static u_int statistics[MAX_STATS];
|
4678 |
|
|
|
4679 |
|
|
u_int
|
4680 |
|
|
snmp_increment_statistic(int which)
|
4681 |
|
|
{
|
4682 |
|
|
if (which >= 0 && which < MAX_STATS) {
|
4683 |
|
|
statistics[which]++;
|
4684 |
|
|
return statistics[which];
|
4685 |
|
|
}
|
4686 |
|
|
return 0;
|
4687 |
|
|
}
|
4688 |
|
|
|
4689 |
|
|
u_int
|
4690 |
|
|
snmp_increment_statistic_by(int which, int count)
|
4691 |
|
|
{
|
4692 |
|
|
if (which >= 0 && which < MAX_STATS) {
|
4693 |
|
|
statistics[which] += count;
|
4694 |
|
|
return statistics[which];
|
4695 |
|
|
}
|
4696 |
|
|
return 0;
|
4697 |
|
|
}
|
4698 |
|
|
|
4699 |
|
|
u_int
|
4700 |
|
|
snmp_get_statistic(int which)
|
4701 |
|
|
{
|
4702 |
|
|
if (which >= 0 && which < MAX_STATS)
|
4703 |
|
|
return statistics[which];
|
4704 |
|
|
return 0;
|
4705 |
|
|
}
|
4706 |
|
|
|
4707 |
|
|
void
|
4708 |
|
|
snmp_init_statistics(void)
|
4709 |
|
|
{
|
4710 |
|
|
memset(statistics, 0, sizeof(statistics));
|
4711 |
|
|
}
|
4712 |
|
|
|
4713 |
|
|
/* returns the length of a socket structure */
|
4714 |
|
|
|
4715 |
|
|
size_t snmp_socket_length( int family)
|
4716 |
|
|
{
|
4717 |
|
|
size_t length;
|
4718 |
|
|
switch (family)
|
4719 |
|
|
{
|
4720 |
|
|
#ifndef cygwin
|
4721 |
|
|
#ifndef WIN32
|
4722 |
|
|
#ifdef AF_UNIX
|
4723 |
|
|
case AF_UNIX:
|
4724 |
|
|
length = sizeof (struct sockaddr_un);
|
4725 |
|
|
break;
|
4726 |
|
|
#endif /* AF_UNIX */
|
4727 |
|
|
#endif
|
4728 |
|
|
#endif
|
4729 |
|
|
|
4730 |
|
|
#ifndef aix3
|
4731 |
|
|
#ifdef AF_LINK
|
4732 |
|
|
case AF_LINK:
|
4733 |
|
|
#ifdef _MAX_SA_LEN
|
4734 |
|
|
length = _MAX_SA_LEN;
|
4735 |
|
|
#elif SOCK_MAXADDRLEN
|
4736 |
|
|
length = SOCK_MAXADDRLEN;
|
4737 |
|
|
#else
|
4738 |
|
|
length = sizeof (struct sockaddr_dl);
|
4739 |
|
|
#endif
|
4740 |
|
|
break;
|
4741 |
|
|
#endif /* AF_LINK */
|
4742 |
|
|
#endif
|
4743 |
|
|
|
4744 |
|
|
case AF_INET:
|
4745 |
|
|
length = sizeof (struct sockaddr_in);
|
4746 |
|
|
break;
|
4747 |
|
|
default:
|
4748 |
|
|
length = sizeof (struct sockaddr);
|
4749 |
|
|
break;
|
4750 |
|
|
}
|
4751 |
|
|
|
4752 |
|
|
return length;
|
4753 |
|
|
}
|
4754 |
|
|
|
4755 |
|
|
/*
|
4756 |
|
|
* For compatibility with applications built using
|
4757 |
|
|
* previous versions only.
|
4758 |
|
|
*/
|
4759 |
|
|
|
4760 |
|
|
/* use <struct snmp_session *)->s_snmp_errno instead */
|
4761 |
|
|
int snmp_get_errno (void) { return SNMPERR_SUCCESS; }
|
4762 |
|
|
|
4763 |
|
|
/* synch_reset and synch_setup are no longer used. */
|
4764 |
|
|
void snmp_synch_reset (struct snmp_session * notused) {}
|
4765 |
|
|
void snmp_synch_setup (struct snmp_session * notused) {}
|
4766 |
|
|
|
4767 |
|
|
/* provide for backwards compatibility */
|
4768 |
|
|
void
|
4769 |
|
|
snmp_set_dump_packet(int x) {
|
4770 |
|
|
ds_set_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET, x);
|
4771 |
|
|
}
|
4772 |
|
|
|
4773 |
|
|
int
|
4774 |
|
|
snmp_get_dump_packet(void) {
|
4775 |
|
|
return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_DUMP_PACKET);
|
4776 |
|
|
}
|
4777 |
|
|
|
4778 |
|
|
void
|
4779 |
|
|
snmp_set_quick_print(int x) {
|
4780 |
|
|
ds_set_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT, x);
|
4781 |
|
|
}
|
4782 |
|
|
|
4783 |
|
|
int
|
4784 |
|
|
snmp_get_quick_print(void) {
|
4785 |
|
|
return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_QUICK_PRINT);
|
4786 |
|
|
}
|
4787 |
|
|
|
4788 |
|
|
|
4789 |
|
|
void
|
4790 |
|
|
snmp_set_suffix_only(int x) {
|
4791 |
|
|
ds_set_int(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY, x);
|
4792 |
|
|
}
|
4793 |
|
|
|
4794 |
|
|
int
|
4795 |
|
|
snmp_get_suffix_only(void) {
|
4796 |
|
|
return ds_get_int(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY);
|
4797 |
|
|
}
|
4798 |
|
|
|
4799 |
|
|
void
|
4800 |
|
|
snmp_set_full_objid(int x) {
|
4801 |
|
|
ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID, x);
|
4802 |
|
|
}
|
4803 |
|
|
|
4804 |
|
|
int
|
4805 |
|
|
snmp_get_full_objid(void) {
|
4806 |
|
|
return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_SUFFIX_ONLY);
|
4807 |
|
|
}
|
4808 |
|
|
|
4809 |
|
|
void
|
4810 |
|
|
snmp_set_random_access(int x) {
|
4811 |
|
|
ds_set_boolean(DS_LIBRARY_ID, DS_LIB_RANDOM_ACCESS, x);
|
4812 |
|
|
}
|
4813 |
|
|
|
4814 |
|
|
int
|
4815 |
|
|
snmp_get_random_access(void) {
|
4816 |
|
|
return ds_get_boolean(DS_LIBRARY_ID, DS_LIB_RANDOM_ACCESS);
|
4817 |
|
|
}
|
4818 |
|
|
|