OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [snmp/] [lib/] [v2_0/] [src/] [snmp_api.c] - Blame information for rev 307

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
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 *) &ltmp, 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", &ltmp) != 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 *) &ltmp, sizeof(ltmp));
4395
        break;
4396
 
4397
      case 'u':
4398
        if (sscanf(value, "%lu", &ltmp) == 1)
4399
            snmp_pdu_add_variable(pdu, name, name_length, ASN_UNSIGNED,
4400
                                  (u_char *) &ltmp, sizeof(ltmp));
4401
        else goto fail;
4402
        break;
4403
 
4404
      case 'c':
4405
        if (sscanf(value, "%lu", &ltmp) == 1)
4406
            snmp_pdu_add_variable(pdu, name, name_length, ASN_COUNTER,
4407
                                  (u_char *) &ltmp, sizeof(ltmp));
4408
        else goto fail;
4409
        break;
4410
 
4411
      case 't':
4412
        if (sscanf(value, "%lu", &ltmp) == 1)
4413
            snmp_pdu_add_variable(pdu, name, name_length, ASN_TIMETICKS,
4414
                                  (u_char *) &ltmp, 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 *) &ltmp, 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
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.