|
|
Initial revision
/* snmpd.c - SNMP agent for 4BSD/ISODE */
#ifndef lint
static char *rcsid = "$Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/snmp/snmpd.c,v 1.1 2018/04/24 16:12:56 root Exp $";
#endif
/*
* $Header: /var/lib/cvsd/repos/CSRG/43BSDReno/contrib/isode-beta/snmp/snmpd.c,v 1.1 2018/04/24 16:12:56 root Exp $
*
* Contributed by NYSERNet Inc. This work was partially supported by the
* U.S. Defense Advanced Research Projects Agency and the Rome Air Development
* Center of the U.S. Air Force Systems Command under contract number
* F30602-88-C-0016.
*
*
* $Log: snmpd.c,v $
* Revision 1.1 2018/04/24 16:12:56 root
* Initial revision
*
* Revision 7.35 90/07/09 14:49:04 mrose
* sync
*
* Revision 7.34 90/07/01 21:07:26 mrose
* pepsy
*
* Revision 7.33 90/06/23 17:07:38 mrose
* loopback
*
* Revision 7.32 90/06/23 17:01:24 mrose
* update
*
* Revision 7.31 90/06/23 01:33:12 mrose
* proxy again
*
* Revision 7.30 90/06/21 21:27:14 mrose
* proxy and snmpt
*
* Revision 7.29 90/06/20 23:52:57 mrose
* again
*
* Revision 7.28 90/06/20 21:38:33 mrose
* update
*
* Revision 7.27 90/06/15 16:58:39 mrose
* update
*
* Revision 7.26 90/06/13 17:58:44 mrose
* defaultView
*
* Revision 7.25 90/06/12 05:19:03 mrose
* again
*
* Revision 7.24 90/06/12 02:21:43 mrose
* again
*
* Revision 7.23 90/06/12 02:05:33 mrose
* views ...
*
* Revision 7.22 90/06/05 20:47:10 mrose
* touch-up
*
* Revision 7.21 90/05/21 10:07:39 mrose
* bug-fix
*
* Revision 7.20 90/05/15 16:56:20 mrose
* bump COMM_RDWRITE
*
* Revision 7.19 90/05/14 19:55:48 mrose
* optimize views
*
* Revision 7.18 90/05/13 18:13:46 mrose
* update
*
* Revision 7.17 90/05/13 17:54:39 mrose
* views again
*
* Revision 7.16 90/05/13 16:18:17 mrose
* views
*
* Revision 7.15 90/04/18 08:51:53 mrose
* oid_normalize
*
* Revision 7.14 90/04/09 08:50:16 mrose
* update
*
* Revision 7.13 90/02/27 18:49:55 mrose
* unix stuff
*
* Revision 7.12 90/02/23 17:47:49 mrose
* update
*
* Revision 7.11 90/02/19 16:25:56 mrose
* typo
*
* Revision 7.10 90/02/19 15:38:50 mrose
* one more time
*
* Revision 7.9 90/02/17 17:18:48 mrose
* touch-up
*
* Revision 7.8 90/01/11 18:34:33 mrose
* real-sync
*
* Revision 7.7 89/12/19 22:01:52 mrose
* touch-up
*
* Revision 7.6 89/12/19 16:18:23 mrose
* dgram
*
* Revision 7.5 89/12/11 16:22:29 mrose
* more clts
*
* Revision 7.4 89/12/09 21:07:41 mrose
* touch-up
*
* Revision 7.3 89/12/08 14:20:27 mrose
* touch-up
*
* Revision 7.2 89/12/07 22:15:12 mrose
* touch-up
*
* Revision 7.1 89/12/01 10:42:15 mrose
* clts
*
* Revision 7.0 89/11/23 22:23:26 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
* this agreement.
*
*/
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <varargs.h>
#include "mib.h"
#include <sys/ioctl.h>
#ifdef BSD42
#include <sys/file.h>
#endif
#ifdef SYS5
#include <fcntl.h>
#endif
#include <sys/stat.h>
#include "tailor.h"
#include "dgram.h"
#include "tsap.h"
#ifdef TCP
#define SMUX
#include "internet.h"
#endif
#ifdef X25
#include "x25.h"
#define COTS
#endif
#ifdef TP4
#include "tp4.h"
#if !defined(CLTS) && !defined(COTS)
#define COTS
#endif
#endif
#ifdef SNMPT
#undef SMUX
#endif
#define IDLE_TIME (3 * 60)
/* DATA */
int debug = 0;
static int nbits = FD_SETSIZE;
#ifndef SNMPT
static int rflag = 0;
#endif
#define LLOG_XXX (LLOG_PDUS | LLOG_DEBUG)
static LLog _pgm_log = {
#ifndef SNMPT
"snmpd.log",
#else
"snmpt.log",
#endif
NULLCP, NULLCP, LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE,
LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK
};
static LLog *pgm_log = &_pgm_log;
#ifndef SNMPT
static char *myname = "snmpd";
#else
static char *myname = "snmpt";
#endif
static int tcpservice = 1;
static int x25service = 1;
static int tp4service = 1;
#define NTADDRS FD_SETSIZE
static fd_set ifds;
static struct TSAPaddr *tz;
static struct TSAPaddr tas[NTADDRS];
#ifdef COTS
static fd_set cfds;
static struct TSAPaddr taddrs[FD_SETSIZE];
static struct timeval lru[FD_SETSIZE];
#endif
static char source[BUFSIZ];
void adios (), advise ();
void ts_advise ();
extern int errno;
/* */
int nd = NOTOK;
#ifdef TCP
static int udp = NOTOK;
#ifndef SNMPT
static int udport;
static int traport;
#endif
#endif
#ifdef CLTS
static int clts = NOTOK;
#endif
/* */
#ifndef SNMPT
int quantum = 0;
struct subtree {
struct subtree *s_forw; /* doubly-linked list */
struct subtree *s_back; /* doubly-linked list */
OID s_subtree; /* subtree */
};
struct view {
struct view *v_forw; /* doubly-linked list */
struct view *v_back; /* .. */
OID v_name; /* view name */
u_long v_mask; /* view mask */
struct subtree v_subtree; /* list of subtrees */
struct qbuf *v_community; /* for proxy, traps... */
struct sockaddr v_sa;
};
static struct view viewque;
static struct view *VHead = &viewque;
static int viewmask = 0x1;
static OID localAgent = NULLOID;
static OID rfc1157Domain = NULLOID;
struct community {
struct community *c_forw; /* doubly-linked list */
struct community *c_back; /* .. */
char *c_name; /* community name */
struct NSAPaddr c_addr; /* network address */
int c_permission; /* same as ot_access */
#define OT_YYY 0x08
OID c_vu; /* associated view */
struct view *c_view; /* .. */
unsigned int *c_instance; /* object instance */
int c_insize; /* .. */
struct community *c_next; /* next in lexi-order */
};
static struct community commque;
static struct community *CHead = &commque;
static struct community *CLex;
struct community *str2comm ();
struct trap {
struct trap *t_forw; /* doubly-linked list */
struct trap *t_back; /* .. */
char *t_name; /* trap name */
struct view t_vu; /* associated view */
struct view *t_view; /* .. */
u_long t_generics; /* generic traps enabled */
};
static struct trap trapque;
static struct trap *UHead = &trapque;
static OID trapview = NULLOID;
#ifdef TCP
static struct type_SNMP_Message *trap = NULL;
#endif
#ifdef SMUX
static struct qbuf *loopback_addr = NULL;
#endif
#define NPQ 10
static struct proxyque {
integer pq_quantum;
int pq_age;
int pq_fd;
IFP pq_closefnx;
PS pq_ps;
struct qbuf pq_community;
integer pq_request;
} pips[NPQ];
static int pqs = 0;
static struct proxyque *pqr = NULL;
/* */
struct snmpstat {
integer s_inpkts;
integer s_outpkts;
integer s_badversions;
integer s_badcommunitynames;
integer s_badcommunityuses;
integer s_asnparseerrs;
integer s_badtypes;
integer s_totalreqvars;
integer s_totalsetvars;
integer s_ingetrequests;
integer s_ingetnexts;
integer s_insetrequests;
integer s_ingetresponses;
integer s_intraps;
integer s_outgetresponses;
integer s_outtraps;
integer s_toobigs;
integer s_nosuchnames;
integer s_badvalues;
integer s_readonlys;
integer s_generrs;
integer s_enableauthtraps;
#define TRAPS_ENABLED 1 /* snmpEnableAuthTraps */
#define TRAPS_DISABLED 2 /* .. */
};
static struct snmpstat snmpstat;
static int unix_netstat = 1;
#else /* SNMPT */
/* */
static PS audit = NULLPS;
#endif /* SNMPT */
/* */
#ifdef SMUX
static int smux_enabled = 1;
static int smux = NOTOK;
static fd_set sfds;
struct smuxPeer {
struct smuxPeer *pb_forw; /* doubly-linked list */
struct smuxPeer *pb_back; /* .. */
int pb_fd; /* smuxPindex */
struct sockaddr_in pb_address;
char pb_source[30];
OID pb_identity; /* smuxPidentity */
char *pb_description; /* smuxPdescription */
PS pb_ps;
int pb_priority; /* minimum allowed priority */
};
static struct smuxPeer peerque;
static struct smuxPeer *PHead = &peerque;
struct smuxTree {
struct smuxTree *tb_forw; /* doubly-linked list */
struct smuxTree *tb_back; /* .. */
#define TB_SIZE 30 /* object instance */
unsigned int tb_instance[TB_SIZE + 1];
int tb_insize;
OT tb_subtree; /* smuxTsubtree */
int tb_priority; /* smuxTpriority */
struct smuxPeer *tb_peer; /* smuxTindex */
struct smuxTree *tb_next; /* linked list for ot_smux */
};
static struct smuxTree treeque;
static struct smuxTree *THead = &treeque;
static struct smuxReserved {
char *rb_text;
OID rb_name;
} reserved[] = {
"snmp", NULLOID,
"smux", NULLOID,
NULL
};
#endif
/* MAIN */
/* ARGSUSED */
main (argc, argv, envp)
int argc;
char **argv,
**envp;
{
int failed,
listening,
nfds;
register struct TSAPaddr *ta;
struct TSAPdisconnect tds;
register struct TSAPdisconnect *td = &tds;
arginit (argv);
envinit ();
failed = listening = 0;
nfds = 0;
FD_ZERO (&ifds);
for (ta = tas; ta < tz; ta++) {
if (ta -> ta_naddr == 0) {
if (!tp4service)
continue;
#ifdef CLTS
goto do_clts;
#endif
}
else {
register struct NSAPaddr *na = ta -> ta_addrs;
switch (na -> na_stack) {
case NA_TCP:
if (!tcpservice)
continue;
#ifdef TCP
{
struct sockaddr_in lo_socket;
register struct sockaddr_in *lsock = &lo_socket;
bzero ((char *) lsock, sizeof *lsock);
lsock -> sin_family = AF_INET;
lsock -> sin_port = na -> na_port;
if ((udp = start_udp_server (lsock, 0, 0, 0))
== NOTOK) {
advise (LLOG_EXCEPTIONS, "failed",
"start_udp_server");
failed++;
continue;
}
if (udp >= nfds)
nfds = udp + 1;
FD_SET (udp, &ifds);
if (nd == NOTOK)
nd = udp;
advise (LLOG_NOTICE, NULLCP,
"listening on UDP port %d",
(int) ntohs (na -> na_port));
listening++;
continue;
}
#else
advise (LLOG_EXCEPTIONS, NULLCP,
"UDP support not configured");
failed++;
continue;
#endif
case NA_X25:
if (!x25service)
continue;
break;
case NA_NSAP:
if (!tp4service)
continue;
#ifdef CLTS
do_clts: ;
{
union sockaddr_osi lo_socket;
register union sockaddr_osi *lsock = &lo_socket;
(void) gen2tp4 (ta, lsock);
if ((clts = start_clts_server (lsock, 0, 0, 0))
== NOTOK) {
advise (LLOG_EXCEPTIONS, "failed",
"start_clts_server");
failed++;
continue;
}
if (clts >= nfds)
nfds = clts + 1;
FD_SET (clts, &ifds);
if (nd == NOTOK)
nd = clts;
advise (LLOG_NOTICE, NULLCP,
"listening on %s", taddr2str (ta));
listening++;
continue;
}
#else
break;
#endif
default:
adios (NULLCP, "unknown network type 0x%x", na -> na_stack);
/* NOT REACHED */
}
}
advise (LLOG_NOTICE, NULLCP, "listening on %s", taddr2str (ta));
if (TNetListen (ta, td) == NOTOK) {
ts_advise (td, LLOG_EXCEPTIONS, "listen failed");
failed++;
}
else
listening++;
}
if (!listening)
adios (NULLCP, failed ? "no successful listens"
: "no network services selected");
#ifndef SNMPT
do_trap (int_SNMP_generic__trap_coldStart, 0,
(struct type_SNMP_VarBindList *) 0);
#endif
#ifdef SMUX
{
struct sockaddr_in lo_socket;
register struct sockaddr_in *lsock = &lo_socket;
register struct servent *sp;
register struct smuxReserved *sr;
OT ot;
PHead -> pb_forw = PHead -> pb_back = PHead;
THead -> tb_forw = THead -> tb_back = THead;
for (sr = reserved; sr -> rb_text; sr++)
if (ot = text2obj (sr -> rb_text))
sr -> rb_name = ot -> ot_name;
bzero ((char *) lsock, sizeof *lsock);
lsock -> sin_family = AF_INET;
lsock -> sin_port = (sp = getservbyname ("smux", "tcp"))
? sp -> s_port
: htons ((u_short) 199);
if (smux_enabled) {
if ((smux = start_tcp_server (lsock, SOMAXCONN, 0, 0)) == NOTOK)
adios ("failed", "start_tcp_server for SMUX");
if (smux >= nfds)
nfds = smux + 1;
FD_SET (smux, &ifds);
}
}
FD_ZERO (&sfds);
#endif
#ifdef COTS
FD_ZERO (&cfds);
#endif
for (;;) {
int fd,
secs;
#ifdef COTS
struct timeval tvs;
register struct timeval *tv = &tvs;
#endif
int vecp;
fd_set rfds;
char *vec[4];
secs = NOTOK;
#ifdef COTS
for (fd = 0; fd < nfds; fd++)
if (FD_ISSET (fd, &cfds)) {
secs = IDLE_TIME + 10;
break;
}
#endif
rfds = ifds; /* struct copy */
if (TNetAcceptAux (&vecp, vec, &fd, NULLTA, nfds, &rfds, NULLFD,
NULLFD, secs, td) == NOTOK) {
ts_advise (td, LLOG_EXCEPTIONS, "TNetAccept failed");
continue;
}
#ifdef TCP
if (udp != NOTOK && FD_ISSET (udp, &rfds))
doit_udp (udp);
#endif
#ifdef SMUX
if (smux != NOTOK
&& FD_ISSET (smux, &rfds)
&& (fd = start_smux ()) != NOTOK) {
if (fd >= nfds)
nfds = fd + 1;
FD_SET (fd, &ifds);
FD_SET (fd, &sfds);
}
for (fd = 0; fd < nfds; fd++)
if (FD_ISSET (fd, &rfds) && FD_ISSET (fd, &sfds))
doit_smux (fd);
#endif
#ifdef CLTS
if (clts != NOTOK && FD_ISSET (clts, &rfds))
doit_clts (clts);
#endif
#ifdef COTS
if (vecp > 0 && (fd = start_tsap (vecp, vec)) != NOTOK) {
if (fd >= nfds)
nfds = fd + 1;
FD_SET (fd, &ifds);
FD_SET (fd, &cfds);
}
for (fd = 0; fd < nfds; fd++)
if (FD_ISSET (fd, &rfds) && FD_ISSET (fd, &cfds))
doit_cots (fd);
(void) gettimeofday (tv, (struct timezone *) 0);
tv -> tv_sec -= (long) IDLE_TIME;
for (fd = 0; fd < nfds; fd++)
if (FD_ISSET (fd, &cfds)) {
if (timercmp (tv, &lru[fd], >)) {
advise (LLOG_EXCEPTIONS, NULLCP,
"clearing connection from %d: %s", fd,
taddr2str (taddrs + fd));
(void) TDiscRequest (fd, NULLCP, 0, td);
FD_CLR (fd, &ifds);
FD_CLR (fd, &cfds);
proxy_clear (fd);
}
}
for (fd = nfds - 1; fd >= 0; fd--)
if (FD_ISSET (fd, &ifds))
break;
nfds = fd + 1;
#endif
}
}
/* */
static void ts_advise (td, code, event)
register struct TSAPdisconnect *td;
int code;
char *event;
{
char buffer[BUFSIZ];
if (td -> td_cc > 0)
(void) sprintf (buffer, "[%s] %*.*s",
TErrString (td -> td_reason),
td -> td_cc, td -> td_cc, td -> td_data);
else
(void) sprintf (buffer, "[%s]", TErrString (td -> td_reason));
advise (code, NULLCP, "%s: %s", event, buffer);
}
/* DOIT */
#ifdef TCP
static doit_udp (pd)
int pd;
{
int fd;
char *cp;
struct sockaddr_in in_socket;
register struct sockaddr_in *isock = &in_socket;
struct NSAPaddr nas;
register struct NSAPaddr *na = &nas;
if ((fd = join_udp_client (pd, isock)) == NOTOK) {
if (errno == EWOULDBLOCK)
return;
adios ("failed", "join_udp_client");
}
(void) sprintf (source, "Internet=%s+%d+2",
cp = inet_ntoa (isock -> sin_addr),
(int) ntohs (isock -> sin_port));
bzero ((char *) na, sizeof *na);
na -> na_stack = NA_TCP;
na -> na_community = ts_comm_tcp_default;
(void) strncpy (na -> na_domain, cp, sizeof na -> na_domain - 1);
na -> na_port = isock -> sin_port;
doit_aux (fd, na, read_udp_socket, write_udp_socket);
#ifndef SNMPT
if (pqr)
pqr -> pq_fd = fd, pqr -> pq_closefnx = close_udp_socket;
else
#endif
(void) close_udp_socket (fd);
}
#endif
/* */
#ifdef CLTS
static doit_clts (pd)
int pd;
{
int fd;
char *cp;
union sockaddr_osi in_socket;
register union sockaddr_osi *isock = &in_socket;
struct TSAPaddr tas;
register struct TSAPaddr *ta = &tas;
if ((fd = join_clts_client (pd, isock)) == NOTOK) {
if (errno == EWOULDBLOCK)
return;
adios ("failed", "join_tcp_client");
}
(void) tp42gen (ta, isock);
(void) strcpy (source, taddr2str (ta));
doit_aux (fd, ta -> ta_addrs, read_clts_socket, write_clts_socket);
#ifndef SNMPT
if (pqr)
pqr -> pq_fd = fd, pqr -> pq_closefnx = close_clts_socket;
else
#endif
(void) close_clts_socket (fd);
}
#endif
/* */
#ifdef COTS
static int start_tsap (vecp, vec)
int vecp;
char **vec;
{
struct TSAPstart tss;
register struct TSAPstart *ts = &tss;
struct TSAPdisconnect tds;
register struct TSAPdisconnect *td = &tds;
if (TInit (vecp, vec, ts, td) == NOTOK) {
ts_advise (td, LLOG_EXCEPTIONS, "T-CONNECT.INDICATION");
return NOTOK;
}
advise (LLOG_XXX, NULLCP,
"T-CONNECT.INDICATION: <%d, %s, %s, %d, %d>",
ts -> ts_sd,
taddr2str (&ts -> ts_calling), taddr2str (&ts -> ts_called),
ts -> ts_expedited, ts -> ts_tsdusize);
if (TConnResponse (ts -> ts_sd, NULLTA, 0, NULLCP, 0, NULLQOS, td)
== NOTOK) {
ts_advise (td, LLOG_EXCEPTIONS, "T-CONNECT.RESPONSE");
return NOTOK;
}
taddrs[ts -> ts_sd] = ts -> ts_calling; /* struct copy */
(void) gettimeofday (lru + ts -> ts_sd, (struct timezone *) 0);
return ts -> ts_sd;
}
/* */
static doit_cots (fd)
int fd;
{
(void) strcpy (source, taddr2str (taddrs + fd));
doit_aux (fd, &(taddrs[fd].ta_addrs[0]), ts_read, ts_write);
#ifndef SNMPT
if (pqr)
pqr -> pq_fd = fd, pqr -> pq_closefnx = NULLIFP;
#endif
(void) gettimeofday (lru + fd, (struct timezone *) 0);
}
#endif
/* */
static doit_aux (fd, na, rfx, wfx)
int fd;
struct NSAPaddr *na;
IFP rfx,
wfx;
{
int result;
PE pe;
PS ps;
struct type_SNMP_Message *msg;
result = NOTOK;
pe = NULLPE;
msg = NULL;
#ifndef SNMPT
pqr = NULL;
#endif
if ((ps = ps_alloc (dg_open)) == NULLPS
|| dg_setup (ps, fd, MAXDGRAM, rfx, wfx) == NOTOK) {
if (ps == NULLPS)
advise (LLOG_EXCEPTIONS, NULLCP, "ps_alloc: out of memory (%s)",
source);
else
advise (LLOG_EXCEPTIONS, NULLCP, "dg_setup: %s (%s)",
ps_error (ps -> ps_errno), source);
goto out;
}
if ((pe = ps2pe (ps)) == NULLPE) {
#ifdef COTS
if (rfx == ts_read) {
FD_CLR (fd, &ifds);
FD_CLR (fd, &cfds);
proxy_clear (fd);
if (ps -> ps_errno == PS_ERR_NONE) {
advise (LLOG_XXX, NULLCP,
"T-DISCONNECT.INDICATION: %d (%s)", fd, source);
goto out;
}
}
#endif
advise (LLOG_EXCEPTIONS, NULLCP, "ps2pe: %s (%s)",
ps_error (ps -> ps_errno), source);
#ifndef SNMPT
snmpstat.s_inpkts++;
snmpstat.s_asnparseerrs++;
#endif
goto out;
}
#ifdef COTS
if (rfx == ts_read)
advise (LLOG_XXX, NULLCP, "T-DATA.INDICATION: %d (%s)", fd, source);
else
#endif
advise (LLOG_XXX, NULLCP, "packet from %s", source);
#ifndef SNMPT
snmpstat.s_inpkts++;
#endif
if (decode_SNMP_Message (pe, 1, NULLIP, NULLVP, &msg) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "decode_SNMP_Message: %s (%s)",
PY_pepy, source);
#ifndef SNMPT
snmpstat.s_asnparseerrs++;
#endif
#ifdef COTS
if (rfx == ts_read) {
struct TSAPdisconnect tds;
advise (LLOG_EXCEPTIONS, NULLCP,
"clearing connection from %d: %s", fd,
taddr2str (taddrs + fd));
(void) TDiscRequest (fd, NULLCP, 0, &tds);
FD_CLR (fd, &ifds);
FD_CLR (fd, &cfds);
proxy_clear (fd);
}
#endif
goto out;
}
PLOGP (pgm_log,SNMP_Message, pe, "Message", 1);
result = process (ps, msg, na);
out: ;
if (msg)
free_SNMP_Message (msg);
if (pe)
pe_free (pe);
if (result != OK && ps)
ps_free (ps);
}
/* PROCESS */
#ifndef SNMPT
static int process (ps, msg, na)
PS ps;
register struct type_SNMP_Message *msg;
struct NSAPaddr *na;
{
int result;
char *commname;
struct community *comm;
PE pe;
if (msg -> version != int_SNMP_version_version__1) {
advise (LLOG_EXCEPTIONS, NULLCP, "badVersion: %d (%s)",
msg -> version, source);
snmpstat.s_badversions++;
return DONE;
}
if ((commname = qb2str (msg -> community)) == NULLCP) {
advise (LLOG_EXCEPTIONS, NULLCP, "qb2str: out of memory (%s)", source);
return DONE;
}
result = NOTOK;
if ((comm = str2comm (commname, na)) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "badCommunity: %s (%s)",
commname, source);
snmpstat.s_badcommunitynames++;
if (snmpstat.s_enableauthtraps == TRAPS_ENABLED)
do_trap (int_SNMP_generic__trap_authenticationFailure, 0,
(struct type_SNMP_VarBindList *) 0);
goto out;
}
if ((result = do_operation (ps, msg, comm)) != DONE)
goto out;
pe = NULLPE;
if (encode_SNMP_Message (&pe, 1, 0, NULLCP, msg) != NOTOK) {
PLOGP (pgm_log,SNMP_Message, pe, "Message", 0);
if (pe2ps (ps, pe) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s (%s)",
ps_error (ps -> ps_errno), source);
else
snmpstat.s_outpkts++;
}
else
advise (LLOG_EXCEPTIONS, NULLCP, "encode_SNMP_Message: %s (%s)",
PY_pepy, source);
if (pe)
pe_free (pe);
out: ;
free (commname);
return result;
}
/* */
static int do_operation (ps, msg, comm)
PS ps;
struct type_SNMP_Message *msg;
struct community *comm;
{
int idx,
offset,
status;
object_instance ois;
struct view *vu = comm -> c_view;
register struct type_SNMP_PDUs *pdu = msg -> data;
register struct type_SNMP_VarBindList *vp;
register struct type_SNMP_GetResponse__PDU *parm = pdu -> un.get__response;
idx = 0;
switch (pdu -> offset) {
case type_SNMP_PDUs_get__request:
snmpstat.s_ingetrequests++;
if (vu == NULL || !(comm -> c_permission & OT_RDONLY)) {
access_denied: ;
advise (LLOG_EXCEPTIONS, NULLCP,
"authorizationFailure: %d (%s)", pdu -> offset,
source);
/* no trap for this... */
idx = 0;
offset = pdu -> offset;
pdu -> offset = type_SNMP_PDUs_get__response;
parm -> error__status = int_SNMP_error__status_noSuchName;
goto out;
}
break;
case type_SNMP_PDUs_get__next__request:
snmpstat.s_ingetnexts++;
if (vu == NULL || !(comm -> c_permission & OT_RDONLY))
goto access_denied;
break;
case type_SNMP_PDUs_set__request:
snmpstat.s_insetrequests++;
if (vu == NULL || !(comm -> c_permission & OT_WRONLY))
goto access_denied;
break;
case type_SNMP_PDUs_get__response:
snmpstat.s_ingetresponses++;
if (vu == NULL)
goto access_denied;
if ((comm -> c_permission & OT_YYY) && proxy2 (msg) != OK)
return NOTOK;
/* else fall... */
case type_SNMP_PDUs_trap:
snmpstat.s_intraps++;
if (vu == NULL)
goto access_denied;
advise (LLOG_EXCEPTIONS, NULLCP,
"unexpectedOperation: %d (%s)", pdu -> offset, source);
snmpstat.s_badtypes++;
return NOTOK;
default:
if (vu == NULL)
goto access_denied;
advise (LLOG_EXCEPTIONS, NULLCP,
"badOperation: %d (%s)", pdu -> offset, source);
snmpstat.s_badtypes++;
return NOTOK;
}
if (vu -> v_community)
return proxy1 (ps, msg, comm);
offset = pdu -> offset;
pdu -> offset = type_SNMP_PDUs_get__response;
quantum++;
for (vp = msg -> data -> un.get__request -> variable__bindings;
vp;
vp = vp -> next) {
register OI oi;
register OT ot;
register struct type_SNMP_VarBind *v = vp -> VarBind;
idx++;
if (offset == type_SNMP_PDUs_get__next__request) {
if ((oi = name2inst (v -> name)) == NULLOI
&& (oi = next2inst (v -> name)) == NULLOI)
goto no_name;
if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP
&& ot -> ot_smux == NULL)
goto get_next;
}
else
if ((oi = name2inst (v -> name)) == NULLOI
|| ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP
&& ot -> ot_smux == NULL)) {
no_name: ;
parm -> error__status = int_SNMP_error__status_noSuchName;
goto out;
}
try_again: ;
switch (offset) {
case type_SNMP_PDUs_get__request:
if (!(vu -> v_mask & ot -> ot_views)) {
snmpstat.s_badcommunityuses++;
parm -> error__status = int_SNMP_error__status_noSuchName;
goto out;
}
break;
case type_SNMP_PDUs_get__next__request:
if (!(vu -> v_mask & ot -> ot_views))
goto get_next;
break;
case type_SNMP_PDUs_set__request:
if (!(vu -> v_mask & ot -> ot_views)) {
snmpstat.s_badcommunityuses++;
parm -> error__status = int_SNMP_error__status_readOnly;
goto out;
}
break;
}
#ifdef SMUX
if (ot -> ot_smux)
status = smux_getfnx (pdu, ot,
((struct smuxTree *) ot -> ot_smux)
-> tb_peer,
v, offset);
else
#endif
status = (*ot -> ot_getfnx) (oi, v, offset);
switch (status) {
case NOTOK: /* get-next wants a bump */
get_next: ;
oi = &ois;
for (;;) {
if ((ot = ot -> ot_next) == NULLOT) {
parm -> error__status =
int_SNMP_error__status_noSuchName;
goto out;
}
oi -> oi_name = (oi -> oi_type = ot) -> ot_name;
if (ot -> ot_getfnx || ot -> ot_smux)
goto try_again;
}
case int_SNMP_error__status_noError:
break;
default:
parm -> error__status = status;
goto out;
}
}
idx = 0;
out: ;
parm -> error__index = idx;
switch (parm -> error__status) {
case int_SNMP_error__status_noError:
idx = 0;
for (vp = msg -> data -> un.get__request -> variable__bindings;
vp;
vp = vp -> next)
idx++;
switch (offset) {
case type_SNMP_PDUs_get__request:
case type_SNMP_PDUs_get__next__request:
snmpstat.s_totalreqvars += idx;
break;
case type_SNMP_PDUs_set__request:
snmpstat.s_totalsetvars += idx;
break;
}
break;
case int_SNMP_error__status_tooBig:
snmpstat.s_toobigs++;
break;
case int_SNMP_error__status_noSuchName:
snmpstat.s_nosuchnames++;
break;
case int_SNMP_error__status_badValue:
snmpstat.s_badvalues++;
break;
case int_SNMP_error__status_readOnly:
snmpstat.s_readonlys++;
break;
case int_SNMP_error__status_genErr:
snmpstat.s_generrs++;
break;
default:
break;
}
snmpstat.s_outgetresponses++;
return DONE;
}
/* PROXY */
static int proxy1 (psp, msg, comm)
PS psp;
struct type_SNMP_Message *msg;
struct community *comm;
{
int result;
register struct view *v = comm -> c_view;
register struct proxyque *pq;
PE pe;
PS ps;
if (qb_pullup (msg -> community) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "qb_pullup: out of memory (proxy %s)",
source);
return NOTOK;
}
if (pqs >= NPQ) {
register struct proxyque *qp;
for (qp = (pq = pips) + NPQ; pq < qp; pq++)
if (pq -> pq_age < quantum) {
advise (LLOG_NOTICE, NULLCP, "proxy flush");
if (pq -> pq_closefnx) {
ps_free (pq -> pq_ps);
(void) (*pq -> pq_closefnx) (pq -> pq_fd);
}
QBFREE (&pq -> pq_community);
break;
}
if (pq >= qp) {
advise (LLOG_EXCEPTIONS, NULLCP,
"proxy for view %s, but no proxyque slots available (%s)",
oid2ode (v -> v_name), source);
return NOTOK;
}
}
else
pq = pips + pqs++;
pq -> pq_quantum = quantum;
pq -> pq_age = quantum + 20; /* who knows what a good value is?!? */
pq -> pq_ps = psp;
pq -> pq_community.qb_forw = pq -> pq_community.qb_back
= &pq -> pq_community;
insque (msg -> community -> qb_forw, &pq -> pq_community);
free ((char *) msg -> community);
pq -> pq_request = msg -> data -> un.get__request -> request__id;
msg -> community = v -> v_community;
msg -> data -> un.get__request -> request__id = pq -> pq_quantum;
result = NOTOK;
pe = NULLPE;
if (encode_SNMP_Message (&pe, 1, 0, NULLCP, msg) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "encode_SNMP_Message: %s (proxy %s)",
PY_pepy, source);
if (pe)
pe_free (pe);
goto out;
}
PLOGP (pgm_log,SNMP_Message, pe, "Message", 0);
if ((ps = ps_alloc (dg_open)) == NULLPS
|| dg_setup (ps, udp, MAXDGRAM, read_udp_socket, write_udp_socket)
== NOTOK) {
if (ps == NULLPS)
advise (LLOG_EXCEPTIONS, NULLCP,
"ps_alloc: out of memory (proxy %s)", source);
else
advise (LLOG_EXCEPTIONS, NULLCP, "dg_setup: %s (proxy %s)",
ps_error (ps -> ps_errno), source);
}
else
if (hack_dgram_socket (udp, &v -> v_sa) == NOTOK)
advise (LLOG_EXCEPTIONS, "failed",
"hack_dgram_socket(1) (proxy %s)", source);
else
if (pe2ps (ps, pe) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s (proxy %s)",
ps_error (ps -> ps_errno), source);
else {
result = OK;
if (hack_dgram_socket (udp, (struct sockaddr *) NULL) == NOTOK)
advise (LLOG_EXCEPTIONS, "failed",
"hack_dgram_socket(2) (proxy %s)", source);
}
pe_free (pe);
if (ps)
ps_free (ps);
out: ;
msg -> community = NULL;
if (result == NOTOK) {
register struct proxyque *qp = pips + --pqs;
if (pq -> pq_closefnx) {
ps_free (pq -> pq_ps);
(void) (*pq -> pq_closefnx) (pq -> pq_fd);
}
QBFREE (&pq -> pq_community);
if (pq != qp)
*pq = *qp; /* struct copy */
}
else
pqr = pq;
return result;
}
/* */
static int proxy2 (msg)
struct type_SNMP_Message *msg;
{
integer request;
register struct proxyque *pq,
*qp;
PE pe;
request = msg -> data -> un.get__request -> request__id;
for (qp = (pq = pips) + pqs; pq < qp; pq++)
if (pq -> pq_quantum == request)
break;
if (pq >= qp)
return OK;
qb_free (msg -> community);
msg -> community = &pq -> pq_community;
msg -> data -> un.get__request -> request__id = pq -> pq_request;
pe = NULLPE;
if (encode_SNMP_Message (&pe, 1, 0, NULLCP, msg) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "encode_SNMP_Message: %s (proxy %s)",
PY_pepy, source);
if (pe)
pe_free (pe);
goto out;
}
PLOGP (pgm_log,SNMP_Message, pe, "Message", 0);
if (pe2ps (pq -> pq_ps, pe) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s (proxy %s)",
ps_error (pq -> pq_ps -> ps_errno), source);
snmpstat.s_outgetresponses++;
pe_free (pe);
out: ;
msg -> community = NULL;
qp = pips + --pqs;
if (pq -> pq_closefnx) {
ps_free (pq -> pq_ps);
(void) (*pq -> pq_closefnx) (pq -> pq_fd);
}
QBFREE (&pq -> pq_community);
if (pq != qp)
*pq = *qp; /* struct copy */
return DONE;
}
/* */
#ifdef COTS
static proxy_clear (fd)
int fd;
{
register struct proxyque *pq,
*qp;
again: ;
for (qp = (pq = pips) + pqs; pq < qp; pq++)
if (pq -> pq_fd == fd) {
qp = pips + --pqs;
if (pq -> pq_closefnx) {
ps_free (pq -> pq_ps);
(void) (*pq -> pq_closefnx) (pq -> pq_fd);
}
QBFREE (&pq -> pq_community);
if (pq != qp)
*pq = *qp;
goto again;
}
}
#endif
/* SMUX */
#ifdef SMUX
#include "smux.h"
static int start_smux ()
{
int fd;
struct sockaddr_in in_socket;
register struct sockaddr_in *isock = &in_socket;
register struct smuxPeer *pb,
*qb;
if ((fd = join_tcp_client (smux, isock)) == NOTOK) {
if (errno == EWOULDBLOCK)
return NOTOK;
adios ("failed", "join_tcp_client");
}
if ((pb = (struct smuxPeer *) calloc (1, sizeof *pb)) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "doit_smux: out of memory");
out: ;
(void) close_tcp_socket (fd);
return NOTOK;
}
pb -> pb_address = *isock; /* struct copy */
(void) sprintf (pb -> pb_source, "%s/%d",
inet_ntoa (pb -> pb_address.sin_addr),
(int) ntohs (pb -> pb_address.sin_port));
(void) strcpy (source, pb -> pb_source);
if ((pb -> pb_ps = ps_alloc (fdx_open)) == NULLPS
|| fdx_setup (pb -> pb_ps, fd) == NOTOK) {
if (pb -> pb_ps == NULLPS)
advise (LLOG_EXCEPTIONS, NULLCP,
"ps_alloc: out of memory (SMUX %s)", source);
else
advise (LLOG_EXCEPTIONS, NULLCP, "fdx_setup: %s (SMUX %s)",
ps_error (pb -> pb_ps -> ps_errno), source);
pb_free (pb);
goto out;
}
for (qb = PHead -> pb_forw; qb != PHead; qb = qb -> pb_forw)
if (qb -> pb_fd > fd)
break;
insque (pb, qb != PHead ? qb -> pb_forw : qb -> pb_back);
return (pb -> pb_fd = fd);
}
/* */
static int doit_smux (fd)
int fd;
{
PE pe;
register struct smuxPeer *pb;
struct type_SNMP_SMUX__PDUs *pdu;
for (pb = PHead -> pb_forw; pb != PHead; pb = pb -> pb_forw)
if (pb -> pb_fd == fd)
break;
if (pb == PHead) {
advise (LLOG_EXCEPTIONS, NULLCP, "lost smuxPeer block for %d", fd);
FD_CLR (fd, &ifds);
FD_CLR (fd, &sfds);
return;
}
(void) strcpy (source, pb -> pb_source);
if ((pe = ps2pe (pb -> pb_ps)) == NULLPE) {
advise (LLOG_EXCEPTIONS, NULLCP, "ps2pe: %s (SMUX %s)",
ps_error (pb -> pb_ps -> ps_errno), source);
out: ;
if (pe)
pe_free (pe);
pb_free (pb);
return;
}
advise (LLOG_XXX, NULLCP, "SMUX packet from %s", source);
pdu = NULL;
if (decode_SNMP_SMUX__PDUs (pe, 1, NULLIP, NULLVP, &pdu) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP,
"decode_SNMP_SMUX__PDUs: %s (SMUX %s)", PY_pepy, source);
goto out;
}
PLOGP (pgm_log,SNMP_SMUX__PDUs, pe, "SMUX Message", 1);
if (smux_process (pb, pdu) == NOTOK)
pb_free (pb);
if (pdu)
free_SNMP_SMUX__PDUs (pdu);
if (pe)
pe_free (pe);
}
/* */
static smux_process (pb, pdu)
register struct smuxPeer *pb;
struct type_SNMP_SMUX__PDUs *pdu;
{
int result = OK;
switch (pdu -> offset) {
case type_SNMP_SMUX__PDUs_simple:
if (pb -> pb_identity)
goto unexpected;
{
register struct type_SNMP_SimpleOpen *simple =
pdu -> un.simple;
register struct smuxEntry *se;
if (simple -> version != int_SNMP_version_version__1) {
advise (LLOG_EXCEPTIONS, NULLCP,
"badVersion: %d (SMUX %s)",
simple -> version, source);
return NOTOK;
}
pb -> pb_identity = simple -> identity;
simple -> identity = NULL;
if ((pb -> pb_description = qb2str (simple -> description))
== NULL) {
advise (LLOG_EXCEPTIONS, NULLCP,
"qb2str: out of memory (SMUX %s)", source);
return NOTOK;
}
if (qb_pullup (simple -> password) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP,
"qb_pullup: out of memory (SMUX %s)", source);
return NOTOK;
}
if ((se = getsmuxEntrybyidentity (pb -> pb_identity)) == NULL
|| strcmp (se -> se_password,
simple -> password -> qb_forw -> qb_data)) {
advise (LLOG_EXCEPTIONS, NULLCP,
"%s: %s (SMUX %s)",
se ? "badPassword" : "badIdentity",
oid2ode (simple -> identity), source);
if (snmpstat.s_enableauthtraps == TRAPS_ENABLED)
do_trap (int_SNMP_generic__trap_authenticationFailure,
0, (struct type_SNMP_VarBindList *) 0);
return NOTOK;
}
if ((pb -> pb_priority = se -> se_priority) < 0)
pb -> pb_priority = 0;
advise (LLOG_NOTICE, NULLCP,
"SMUX open: %d %s \"%s\" (%s)",
pb -> pb_fd, oid2ode (pb -> pb_identity),
pb -> pb_description, source);
}
break;
case type_SNMP_SMUX__PDUs_close:
if (!pb -> pb_identity)
goto unexpected;
advise (LLOG_NOTICE, NULLCP,
"SMUX close: %s (%s)",
smux_error (pdu -> un.close -> parm), source);
return NOTOK;
case type_SNMP_SMUX__PDUs_registerRequest:
if (!pb -> pb_identity)
goto unexpected;
{
register struct type_SNMP_RReqPDU *rreq =
pdu -> un.registerRequest;
struct type_SNMP_RRspPDU rrsp;
struct type_SNMP_SMUX__PDUs rsp;
register struct smuxReserved *sr;
register struct smuxTree *tb = NULL;
register struct smuxTree *qb;
register OID oid = rreq -> subtree;
OT ot = NULLOT;
PE pe;
for (sr = reserved; sr -> rb_text; sr++)
if (sr -> rb_name
&& bcmp ((char *) sr -> rb_name -> oid_elements,
(char *) oid -> oid_elements,
(sr -> rb_name -> oid_nelem
<= oid -> oid_nelem
? sr -> rb_name -> oid_nelem
: oid -> oid_nelem)
* sizeof oid -> oid_elements[0])
== 0) {
advise (LLOG_EXCEPTIONS, NULLCP,
"reservedSubTree: %s %s %s (SMUX %s)",
oid2ode (oid),
sr -> rb_name -> oid_nelem
<= oid -> oid_nelem
? "under" : "contains",
sr -> rb_text, source);
goto no_dice;
}
if ((ot = name2obj (oid)) == NULLOT) {
if (rreq -> operation == int_SNMP_operation_delete) {
advise (LLOG_EXCEPTIONS, NULLCP,
"noSuchSubTree: %s (SMUX %s)",
oid2ode (oid), source);
goto no_dice;
}
if ((ot = (OT) calloc (1, sizeof *ot)) == NULL
|| (ot -> ot_text = ot -> ot_id =
strdup (sprintoid (oid)))
== NULL) {
advise (LLOG_EXCEPTIONS, NULLCP,
"out of memory (SMUX %s)", source);
if (ot)
free ((char *) ot);
return NOTOK;
}
ot -> ot_name = rreq -> subtree;
rreq -> subtree = NULL;
ot -> ot_access = rreq -> operation;
ot -> ot_status = OT_OPTIONAL;
export_view (ot);
add_objects (ot);
}
else {
if (rreq -> operation == int_SNMP_operation_delete) {
for (tb = (struct smuxTree *) ot -> ot_smux;
tb;
tb = tb -> tb_next)
if (tb -> tb_peer == pb
&& (rreq -> priority < 0
|| rreq -> priority
== tb -> tb_priority))
break;
if (tb)
tb_free (tb);
else {
advise (LLOG_EXCEPTIONS, NULLCP,
"noSuchRegistration: %s (SMUX %s)",
oid2ode (oid), source);
ot = NULLOT;
}
goto no_dice;
}
if (ot -> ot_name -> oid_nelem > oid -> oid_nelem) {
advise (LLOG_EXCEPTIONS, NULLCP,
"badSubTree: %s (SMUX %s)",
oid2ode (oid), source);
ot = NULL;
goto no_dice;
}
}
if ((tb = (struct smuxTree *) calloc (1, sizeof *tb))
== NULL) {
advise (LLOG_EXCEPTIONS, NULLCP,
"out of memory (SMUX %s)", source);
return NOTOK;
}
if ((tb -> tb_priority = rreq -> priority) < pb -> pb_priority)
tb -> tb_priority = pb -> pb_priority;
for (qb = (struct smuxTree *) ot -> ot_smux;
qb;
qb = qb -> tb_next)
if (qb -> tb_priority > tb -> tb_priority)
break;
else
if (qb -> tb_priority == tb -> tb_priority)
tb -> tb_priority++;
tb -> tb_peer = pb;
no_dice: ;
bzero ((char *) &rsp, sizeof rsp);
rsp.offset = type_SNMP_SMUX__PDUs_registerResponse;
rsp.un.registerResponse = &rrsp;
bzero ((char *) &rrsp, sizeof rrsp);
rrsp.parm = tb ? tb -> tb_priority
: int_SNMP_RRspPDU_failure;
pe = NULLPE;
if (encode_SNMP_SMUX__PDUs (&pe, 1, 0, NULLCP, &rsp)
!= NOTOK) {
PLOGP (pgm_log,SNMP_SMUX__PDUs, pe, "SMUX Message", 0);
if (pe2ps (pb -> pb_ps, pe) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s (SMUX %s)",
ps_error (pb -> pb_ps -> ps_errno), source);
result = NOTOK;
}
else {
if (ot)
advise (LLOG_NOTICE, NULLCP,
"SMUX register: %s %s in=%d out=%d (%s)",
rreq -> operation
== int_SNMP_operation_delete ? "delete"
: rreq -> operation
== int_SNMP_operation_readOnly
? "readOnly" : "readWrite",
oid2ode (ot -> ot_name),
rreq -> priority,
tb ? tb -> tb_priority : -1, source);
if (tb
&& rreq -> operation
!= int_SNMP_operation_delete) {
register int i;
register unsigned int *ip,
*jp;
register struct smuxTree **qpp;
tb -> tb_subtree = ot;
for (qb = ot -> ot_smux
? (struct smuxTree *) ot -> ot_smux
: THead -> tb_forw;
qb != THead;
qb = qb -> tb_forw)
if ((i = oid_cmp (qb -> tb_subtree -> ot_name,
ot -> ot_name)) > 0
|| (i == 0
&& qb -> tb_priority
> tb -> tb_priority))
break;
insque (tb, qb != THead ? qb -> tb_forw
: qb -> tb_back);
for (qpp = (struct smuxTree **) &ot -> ot_smux;
qb = *qpp;
qpp = &qb -> tb_next)
if (qb -> tb_priority > tb -> tb_priority)
break;
tb -> tb_next = qb;
*qpp = tb;
ip = tb -> tb_instance;
jp = ot -> ot_name -> oid_elements;
for (*ip++ = (i = ot -> ot_name -> oid_nelem);
i > 0;
i--)
*ip++ = *jp++;
*ip++ = tb -> tb_priority;
tb -> tb_insize = ip - tb -> tb_instance;
}
}
}
else {
advise (LLOG_EXCEPTIONS, NULLCP,
"encode_SNMP_SMUX__PDUs: %s (SMUX %s)",
PY_pepy, source);
result = NOTOK;
}
if (pe)
pe_free (pe);
}
break;
case type_SNMP_SMUX__PDUs_trap:
if (!pb -> pb_identity)
goto unexpected;
{
struct qbuf *qb;
struct type_SNMP_Message msgs;
register struct type_SNMP_Message *msg = &msgs;
struct type_SNMP_PDUs datas;
register struct type_SNMP_PDUs *data = &datas;
register struct type_SNMP_Trap__PDU *parm = pdu -> un.trap;
advise (LLOG_NOTICE, NULLCP,
"SMUX trap: %d %d (%s)",
parm -> generic__trap, parm -> specific__trap, source);
bzero ((char *) msg, sizeof *msg);
msg -> version = int_SNMP_version_version__1;
msg -> data = data;
bzero ((char *) data, sizeof *data);
data -> offset = type_SNMP_PDUs_trap;
data -> un.trap = parm;
if (loopback_addr
&& qb_pullup (qb = parm -> agent__addr) != NOTOK
&& qb -> qb_len == loopback_addr -> qb_len
&& bcmp (qb -> qb_forw -> qb_data,
loopback_addr -> qb_forw -> qb_data,
qb -> qb_len) == 0)
parm -> agent__addr = trap -> data -> un.trap->agent__addr;
do_traps (msg, parm -> generic__trap, parm -> specific__trap);
parm -> agent__addr = qb;
}
break;
case type_SNMP_SMUX__PDUs_registerResponse:
case type_SNMP_SMUX__PDUs_get__request:
case type_SNMP_SMUX__PDUs_get__next__request:
case type_SNMP_SMUX__PDUs_get__response:
case type_SNMP_SMUX__PDUs_set__request:
unexpected: ;
advise (LLOG_EXCEPTIONS, NULLCP,
"unexpectedOperation: %d (SMUX %s)", pdu -> offset,
source);
return NOTOK;
default:
advise (LLOG_EXCEPTIONS, NULLCP,
"badOperation: %d (SMUX %s)", pdu -> offset, source);
return NOTOK;
}
return result;
}
/* */
static int smux_getfnx (pdu, ot, pb, v, offset)
struct type_SNMP_PDUs *pdu;
OT ot;
register struct smuxPeer *pb;
register struct type_SNMP_VarBind *v;
int offset;
{
int status,
orig_id;
struct type_SNMP_VarBindList *orig_bindings,
vps;
struct type_SNMP_SMUX__PDUs req,
*rsp;
register struct type_SNMP_GetResponse__PDU *get;
PE pe;
status = int_SNMP_error__status_noError;
orig_id = pdu -> un.get__request -> request__id;
orig_bindings = pdu -> un.get__request -> variable__bindings;
bzero ((char *) &req, sizeof req);
req.offset = offset == type_SNMP_PDUs_get__request
? type_SNMP_SMUX__PDUs_get__request
: type_SNMP_SMUX__PDUs_get__next__request;
req.un.get__request = pdu -> un.get__request;
pdu -> un.get__request -> request__id = quantum;
bzero ((char *) &vps, sizeof vps);
vps.VarBind = v;
pdu -> un.get__request -> variable__bindings = &vps;
pe = NULLPE;
if (encode_SNMP_SMUX__PDUs (&pe, 1, 0, NULLCP, &req) != NOTOK) {
PLOGP (pgm_log,SNMP_SMUX__PDUs, pe, "SMUX Message", 0);
if (pe2ps (pb -> pb_ps, pe) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s (%s, SMUX %s)",
ps_error (pb -> pb_ps -> ps_errno), source,
pb -> pb_source);
lost_peer: ;
pb_free (pb);
status = int_SNMP_error__status_genErr;
}
}
else {
advise (LLOG_EXCEPTIONS, NULLCP,
"encode_SNMP_SMUX__PDUs: %s (%s)", PY_pepy, source);
status = int_SNMP_error__status_genErr;
}
if (pe)
pe_free (pe);
pdu -> un.get__request -> request__id = orig_id;
pdu -> un.get__request -> variable__bindings = orig_bindings;
if (status != int_SNMP_error__status_noError)
return status;
if ((pe = ps2pe (pb -> pb_ps)) == NULLPE) {
advise (LLOG_EXCEPTIONS, NULLCP, "ps2pe: %s (%s, SMUX %s)",
ps_error (pb -> pb_ps -> ps_errno), source,
pb -> pb_source);
goto lost_peer;
}
rsp = NULL;
if (decode_SNMP_SMUX__PDUs (pe, 1, NULLIP, NULLVP, &rsp) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP,
"decode_SNMP_SMUX__PDUs: %s (%s, SMUX %s)", PY_pepy, source,
pb -> pb_source);
lost_peer_again: ;
pb_free (pb);
status = int_SNMP_error__status_genErr;
goto out;
}
PLOGP (pgm_log,SNMP_SMUX__PDUs, pe, "SMUX Message", 1);
if (rsp -> offset != type_SNMP_SMUX__PDUs_get__response) {
advise (LLOG_EXCEPTIONS, NULLCP,
"unexpectedOperation: %d (%s, SMUX %s)", rsp -> offset,
source, pb -> pb_source);
goto lost_peer_again;
}
get = rsp -> un.get__response;
switch (status = get -> error__status) {
case int_SNMP_error__status_noError:
{
register struct type_SNMP_VarBindList *vp;
register struct type_SNMP_VarBind *v2;
if ((vp = get -> variable__bindings) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP,
"missing variable in get response (%s, SMUX %s)",
source, pb -> pb_source);
goto lost_peer_again;
}
v2 = vp -> VarBind;
if (offset == type_SNMP_PDUs_get__next__request
&& (ot -> ot_name -> oid_nelem
> v2 -> name -> oid_nelem
|| bcmp ((char *) ot -> ot_name ->oid_elements,
(char *) v2 -> name -> oid_elements,
ot -> ot_name -> oid_nelem
* sizeof ot -> ot_name ->
oid_elements[0]))) {
status = NOTOK;
break;
}
free_SNMP_ObjectName (v -> name);
v -> name = v2 -> name;
v2 -> name = NULL;
free_SNMP_ObjectSyntax (v -> value);
v -> value = v2 -> value;
v2 -> value = NULL;
}
break;
case int_SNMP_error__status_noSuchName:
if (offset == type_SNMP_PDUs_get__next__request) {
status = NOTOK;
break;
}
/* else fall */
default:
break;
}
out: ;
if (rsp)
free_SNMP_SMUX__PDUs (rsp);
if (pe)
pe_free (pe);
return status;
}
/* */
static pb_free (pb)
register struct smuxPeer *pb;
{
register struct smuxTree *tb,
*ub;
if (pb == NULL)
return;
for (tb = THead -> tb_forw; tb != THead; tb = ub) {
ub = tb -> tb_forw;
if (tb -> tb_peer == pb)
tb_free (tb);
}
if (pb -> pb_ps)
ps_free (pb -> pb_ps);
if (pb -> pb_fd != NOTOK) {
(void) close_tcp_socket (pb -> pb_fd);
FD_CLR (pb -> pb_fd, &ifds);
FD_CLR (pb -> pb_fd, &sfds);
}
if (pb -> pb_identity)
oid_free (pb -> pb_identity);
if (pb -> pb_description)
free (pb -> pb_description);
remque (pb);
free ((char *) pb);
}
/* */
static tb_free (tb)
register struct smuxTree *tb;
{
register struct smuxTree *tp,
**tpp;
if (tb == NULL)
return;
for (tpp = (struct smuxTree **) &tb -> tb_subtree -> ot_smux;
tp = *tpp;
tpp = &tp -> tb_next)
if (tp == tb) {
*tpp = tb -> tb_next;
break;
}
remque (tb);
free ((char *) tb);
}
#endif
/* SNMP GROUP */
static init_snmp ()
{
register OT ot;
if (ot = text2obj ("snmpInPkts"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_inpkts;
if (ot = text2obj ("snmpOutPkts"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_outpkts;
if (ot = text2obj ("snmpInBadVersions"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_badversions;
if (ot = text2obj ("snmpInBadCommunityNames"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_badcommunitynames;
if (ot = text2obj ("snmpInBadCommunityUses"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_badcommunityuses;
if (ot = text2obj ("snmpInASNParseErrs"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_asnparseerrs;
if (ot = text2obj ("snmpInBadTypes"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_badtypes;
if (ot = text2obj ("snmpInTotalReqVars"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_totalreqvars;
if (ot = text2obj ("snmpInTotalSetVars"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_totalsetvars;
if (ot = text2obj ("snmpInGetRequests"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_ingetrequests;
if (ot = text2obj ("snmpInGetNexts"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_ingetnexts;
if (ot = text2obj ("snmpInSetRequests"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_insetrequests;
if (ot = text2obj ("snmpInGetResponses"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_ingetresponses;
if (ot = text2obj ("snmpInTraps"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_intraps;
if (ot = text2obj ("snmpOutTooBigs"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_toobigs;
if (ot = text2obj ("snmpOutNoSuchNames"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_nosuchnames;
if (ot = text2obj ("snmpOutBadValues"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_badvalues;
if (ot = text2obj ("snmpOutReadOnlys"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_readonlys;
if (ot = text2obj ("snmpOutGenErrs"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_generrs;
if (ot = text2obj ("snmpOutGetResponses"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_outgetresponses;
if (ot = text2obj ("snmpOutTraps"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_outtraps;
if (ot = text2obj ("snmpEnableAuthTraps"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &snmpstat.s_enableauthtraps;
if (ot = text2obj ("unixNetstat"))
ot -> ot_getfnx = o_generic,
ot -> ot_info = (caddr_t) &unix_netstat;
}
/* SMUX GROUP */
#ifdef SMUX
#define smuxPindex 0
#define smuxPidentity 1
#define smuxPdescription 2
#define smuxPstatus 3
#define PB_VALID 1 /* smuxPstatus */
#define PB_CONNECTING 2 /* .. */
static int o_smuxPeer (oi, v, offset)
OI oi;
register struct type_SNMP_VarBind *v;
int offset;
{
int ifnum,
ifvar;
register struct smuxPeer *pb;
register OID oid = oi -> oi_name;
register OT ot = oi -> oi_type;
ifvar = (int) ot -> ot_info;
switch (offset) {
case type_SNMP_PDUs_get__request:
if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
return int_SNMP_error__status_noSuchName;
ifnum = oid -> oid_elements[oid -> oid_nelem - 1];
for (pb = PHead -> pb_forw; pb != PHead; pb = pb -> pb_forw)
if (pb -> pb_fd == ifnum)
break;
if (pb == PHead
|| ((ifvar == smuxPidentity || ifvar == smuxPdescription)
&& pb -> pb_identity == NULL))
return int_SNMP_error__status_noSuchName;
break;
case type_SNMP_PDUs_get__next__request:
again: ;
if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
OID new;
if ((pb = PHead -> pb_forw) == PHead)
return NOTOK;
ifnum = pb -> pb_fd;
if ((new = oid_extend (oid, 1)) == NULLOID)
return int_SNMP_error__status_genErr;
new -> oid_elements[new -> oid_nelem - 1] = ifnum;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
}
else {
int i = ot -> ot_name -> oid_nelem;
ifnum = oid -> oid_elements[i];
for (pb = PHead -> pb_forw; pb != PHead; pb = pb -> pb_forw)
if (pb -> pb_fd >= ifnum)
break;
if (pb == PHead
|| ((pb -> pb_fd == ifnum)
&& (pb = pb -> pb_forw) == PHead))
return NOTOK;
ifnum = pb -> pb_fd;
oid -> oid_elements[i] = ifnum;
oid -> oid_nelem = i + 1;
}
if ((ifvar == smuxPidentity || ifvar == smuxPdescription)
&& pb -> pb_identity == NULL)
goto again;
break;
default:
return int_SNMP_error__status_genErr;
}
switch (ifvar) {
case smuxPindex:
return o_integer (oi, v, pb -> pb_fd);
case smuxPidentity:
return o_specific (oi, v, (caddr_t) pb -> pb_identity);
case smuxPdescription:
return o_string (oi, v, pb -> pb_description,
strlen (pb -> pb_description));
case smuxPstatus:
return o_integer (oi, v, pb -> pb_identity ? PB_VALID
: PB_CONNECTING);
default:
return int_SNMP_error__status_noSuchName;
}
}
/* */
static struct smuxTree *get_tbent (ip, len, isnext)
register unsigned int *ip;
int len;
int isnext;
{
register struct smuxTree *tb;
for (tb = THead -> tb_forw; tb != THead; tb = tb -> tb_forw)
switch (elem_cmp (tb -> tb_instance, tb -> tb_insize, ip, len)) {
case 0:
if (!isnext)
return tb;
if ((tb = tb -> tb_forw) == THead)
return NULL;
/* else fall... */
case 1:
return (isnext ? tb : NULL);
}
return NULL;
}
/* */
#define smuxTsubtree 0
#define smuxTpriority 1
#define smuxTindex 2
#define smuxTstatus 3
#define TB_VALID 1 /* smuxTstatus */
static int o_smuxTree (oi, v, offset)
OI oi;
register struct type_SNMP_VarBind *v;
int offset;
{
int ifvar;
register int i;
register unsigned int *ip,
*jp;
register struct smuxTree *tb;
register OID oid = oi -> oi_name;
register OT ot = oi -> oi_type;
ifvar = (int) ot -> ot_info;
switch (offset) {
case type_SNMP_PDUs_get__request:
if (oid -> oid_nelem <= ot -> ot_name -> oid_nelem)
return int_SNMP_error__status_noSuchName;
if ((tb = get_tbent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 0)) == NULL)
return int_SNMP_error__status_noSuchName;
break;
case type_SNMP_PDUs_get__next__request:
if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
OID new;
if ((tb = THead -> tb_forw) == THead)
return NOTOK;
if ((new = oid_extend (oid, tb -> tb_insize)) == NULLOID)
return int_SNMP_error__status_genErr;
ip = new -> oid_elements + new -> oid_nelem - tb -> tb_insize;
jp = tb -> tb_instance;
for (i = tb -> tb_insize; i > 0; i--)
*ip++ = *jp++;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
}
else {
int j;
if ((tb = get_tbent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
j = oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 1))
== NULL)
return NOTOK;
if ((i = j - tb -> tb_insize) < 0) {
OID new;
if ((new = oid_extend (oid, -i)) == NULLOID)
return int_SNMP_error__status_genErr;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
oid = new;
}
else
if (i > 0)
oid -> oid_nelem -= i;
ip = oid -> oid_elements + ot -> ot_name -> oid_nelem;
jp = tb -> tb_instance;
for (i = tb -> tb_insize; i > 0; i--)
*ip++ = *jp++;
}
break;
default:
return int_SNMP_error__status_genErr;
}
switch (ifvar) {
case smuxTsubtree:
return o_specific (oi, v, (caddr_t) tb -> tb_subtree -> ot_name);
case smuxTpriority:
return o_integer (oi, v, tb -> tb_priority);
case smuxTindex:
return o_integer (oi, v, tb -> tb_peer -> pb_fd);
case smuxTstatus:
return o_integer (oi, v, TB_VALID);
default:
return int_SNMP_error__status_noSuchName;
}
}
/* */
static init_smux ()
{
register OT ot;
if (ot = text2obj ("smuxPindex"))
ot -> ot_getfnx = o_smuxPeer,
ot -> ot_info = (caddr_t) smuxPindex;
if (ot = text2obj ("smuxPidentity"))
ot -> ot_getfnx = o_smuxPeer,
ot -> ot_info = (caddr_t) smuxPidentity;
if (ot = text2obj ("smuxPdescription"))
ot -> ot_getfnx = o_smuxPeer,
ot -> ot_info = (caddr_t) smuxPdescription;
if (ot = text2obj ("smuxPstatus"))
ot -> ot_getfnx = o_smuxPeer,
ot -> ot_info = (caddr_t) smuxPstatus;
if (ot = text2obj ("smuxTsubtree"))
ot -> ot_getfnx = o_smuxTree,
ot -> ot_info = (caddr_t) smuxTsubtree;
if (ot = text2obj ("smuxTpriority"))
ot -> ot_getfnx = o_smuxTree,
ot -> ot_info = (caddr_t) smuxTpriority;
if (ot = text2obj ("smuxTindex"))
ot -> ot_getfnx = o_smuxTree,
ot -> ot_info = (caddr_t) smuxTindex;
if (ot = text2obj ("smuxTstatus"))
ot -> ot_getfnx = o_smuxTree,
ot -> ot_info = (caddr_t) smuxTstatus;
}
#endif
/* VIEW MIB */
#define viewPrimName 0
#define viewPrimTDomain 1
#define viewPrimTAddr 2
#define viewPrimUser 3
#define viewPrimCommunity 4
#define viewPrimType 5
#define P_VALID 1 /* viewPrimType */
struct view *get_prent ();
static int o_viewPrim (oi, v, offset)
OI oi;
register struct type_SNMP_VarBind *v;
int offset;
{
int ifvar;
register int i;
register unsigned int *ip,
*jp;
register struct view *vu;
register OID oid = oi -> oi_name;
register OT ot = oi -> oi_type;
ifvar = (int) ot -> ot_info;
switch (offset) {
case type_SNMP_PDUs_get__request:
if (oid -> oid_nelem <= ot -> ot_name -> oid_nelem)
return int_SNMP_error__status_noSuchName;
if ((vu = get_prent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 0)) == NULL)
return int_SNMP_error__status_noSuchName;
break;
case type_SNMP_PDUs_get__next__request:
if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
OID new;
if ((vu = VHead -> v_forw) == VHead)
return NOTOK;
i = vu -> v_name -> oid_nelem + 1;
if ((new = oid_extend (oid, i)) == NULLOID)
return int_SNMP_error__status_genErr;
ip = new -> oid_elements + new -> oid_nelem - i;
jp = vu -> v_name -> oid_elements;
*ip++ = i;
for (i--; i > 0; i--)
*ip++ = *jp++;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
}
else {
int j,
k;
if ((vu = get_prent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
j = oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 1))
== NULL)
return NOTOK;
k = vu -> v_name -> oid_nelem + 1;
if ((i = j - k) < 0) {
OID new;
if ((new = oid_extend (oid, -i)) == NULLOID)
return int_SNMP_error__status_genErr;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
oid = new;
}
else
if (i > 0)
oid -> oid_nelem -= i;
ip = oid -> oid_elements + ot -> ot_name -> oid_nelem;
jp = vu -> v_name -> oid_elements;
*ip++ = k;
for (k--; k > 0; k--)
*ip++ = *jp++;
}
break;
default:
return int_SNMP_error__status_genErr;
}
switch (ifvar) {
case viewPrimName:
return o_specific (oi, v, (caddr_t) vu -> v_name);
case viewPrimTDomain:
return o_specific (oi, v,
(caddr_t) (vu -> v_community ? rfc1157Domain
: localAgent));
case viewPrimTAddr:
#ifdef TCP
if (vu -> v_community) {
struct sockaddr_in *sin = (struct sockaddr_in *) &vu -> v_sa;
return o_string (oi, v, (char *) &sin -> sin_addr, 4);
}
else
#endif
return o_string (oi, v, NULLCP, 0);
case viewPrimUser:
#ifdef TCP
if (vu -> v_community)
return o_qbstring (oi, v,
trap -> data -> un.trap -> agent__addr);
else
#endif
return o_string (oi, v, NULLCP, 0);
case viewPrimCommunity:
if (vu -> v_community)
return o_qbstring (oi, v, vu -> v_community);
else
return o_string (oi, v, NULLCP, 0);
case viewPrimType:
return o_integer (oi, v, P_VALID);
default:
return int_SNMP_error__status_noSuchName;
}
}
/* */
static struct view *get_prent (ip, len, isnext)
register unsigned int *ip;
int len;
int isnext;
{
register struct view *v;
ip++, len--;
for (v = VHead -> v_forw; v != VHead; v = v -> v_forw)
switch (elem_cmp (v -> v_name -> oid_elements,v -> v_name -> oid_nelem,
ip, len)) {
case 0:
if (!isnext)
return v;
if ((v = v -> v_forw) == VHead)
return NULL;
/* else fall... */
case 1:
return (isnext ? v : NULL);
}
return NULL;
}
/* */
#define viewAclView 0
#define viewAclCommunity 1
#define viewAclUser 2
#define viewAclPrivileges 3
#define viewAclType 4
#define A_VALID 1 /* viewAclType */
struct community *get_acent ();
static int o_viewAcl (oi, v, offset)
OI oi;
register struct type_SNMP_VarBind *v;
int offset;
{
int ifvar;
register int i;
register unsigned int *ip,
*jp;
register struct community *c;
register OID oid = oi -> oi_name;
register OT ot = oi -> oi_type;
ifvar = (int) ot -> ot_info;
switch (offset) {
case type_SNMP_PDUs_get__request:
if (oid -> oid_nelem <= ot -> ot_name -> oid_nelem)
return int_SNMP_error__status_noSuchName;
if ((c = get_acent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 0)) == NULL)
return int_SNMP_error__status_noSuchName;
break;
case type_SNMP_PDUs_get__next__request:
if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
OID new;
if ((c = CLex) == NULL)
return NOTOK;
if ((new = oid_extend (oid, c -> c_insize)) == NULLOID)
return int_SNMP_error__status_genErr;
ip = new -> oid_elements + new -> oid_nelem - c -> c_insize;
jp = c -> c_instance;
for (i = c -> c_insize; i > 0; i--)
*ip++ = *jp++;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
}
else {
int j;
if ((c = get_acent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
j = oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 1))
== NULL)
return NOTOK;
if ((i = j - c -> c_insize) < 0) {
OID new;
if ((new = oid_extend (oid, -i)) == NULLOID)
return int_SNMP_error__status_genErr;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
oid = new;
}
else
if (i > 0)
oid -> oid_nelem -= i;
ip = oid -> oid_elements + ot -> ot_name -> oid_nelem;
jp = c -> c_instance;
for (i = c -> c_insize; i > 0; i--)
*ip++ = *jp++;
}
break;
default:
return int_SNMP_error__status_genErr;
}
switch (ifvar) {
case viewAclView:
return o_specific (oi, v, (caddr_t) c -> c_view -> v_name);
case viewAclCommunity:
return o_string (oi, v, c -> c_name, strlen (c -> c_name));
case viewAclUser:
switch (c -> c_addr.na_type) {
case NA_TCP:
{ /* hard to believe this is the easiest way of doing it */
register char *bp,
*ep;
char buf[4];
ip = c -> c_instance + 1 + strlen (c -> c_name) + 1;
for (ep = (bp = buf + sizeof buf); bp < ep; )
*bp++ = *ip++ & 0xff;
return o_string (oi, v, buf, sizeof buf);
}
case NA_X25:
return o_string (oi, v, c -> c_addr.na_dte,
(int) c -> c_addr.na_dtelen);
case NA_NSAP:
return o_string (oi, v, c -> c_addr.na_address,
(int) c -> c_addr.na_addrlen);
default:
return o_string (oi, v, NULLCP, 0);
}
case viewAclPrivileges:
return o_integer (oi, v,
((c -> c_permission & OT_RDONLY) ? 3 : 0)
+ ((c -> c_permission & OT_WRONLY) ? 8 : 0)
+ ((c -> c_permission & OT_YYY) ? 4 : 0));
case viewAclType:
return o_integer (oi, v, A_VALID);
default:
return int_SNMP_error__status_noSuchName;
}
}
/* */
static struct community *get_acent (ip, len, isnext)
register unsigned int *ip;
int len;
int isnext;
{
register struct community *c;
for (c = CLex; c; c = c -> c_next)
switch (elem_cmp (c -> c_instance, c -> c_insize, ip, len)) {
case 0:
return (isnext ? c -> c_next : c);
case 1:
return (isnext ? c : NULL);
}
return NULL;
}
/* */
#define viewTrapView 0
#define viewTrapGenerics 1
#define viewTrapSpecifics 2
#define viewTrapType 3
#define T_VALID 1 /* viewTrapType */
struct trap *get_trent ();
static int o_viewTrap (oi, v, offset)
OI oi;
register struct type_SNMP_VarBind *v;
int offset;
{
int ifvar;
register int i;
register unsigned int *ip,
*jp;
register struct trap *t;
register OID oid = oi -> oi_name;
register OT ot = oi -> oi_type;
ifvar = (int) ot -> ot_info;
switch (offset) {
case type_SNMP_PDUs_get__request:
if (oid -> oid_nelem <= ot -> ot_name -> oid_nelem)
return int_SNMP_error__status_noSuchName;
if ((t = get_trent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 0)) == NULL)
return int_SNMP_error__status_noSuchName;
break;
case type_SNMP_PDUs_get__next__request:
if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
OID new;
if ((t = UHead -> t_forw) == UHead)
return NOTOK;
i = t -> t_view -> v_name -> oid_nelem + 1;
if ((new = oid_extend (oid, i)) == NULLOID)
return int_SNMP_error__status_genErr;
ip = new -> oid_elements + new -> oid_nelem - i;
jp = t -> t_view -> v_name -> oid_elements;
*ip++ = i;
for (i--; i > 0; i--)
*ip++ = *jp++;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
}
else {
int j,
k;
if ((t = get_trent (oid -> oid_elements
+ ot -> ot_name -> oid_nelem,
j = oid -> oid_nelem
- ot -> ot_name -> oid_nelem, 1))
== NULL)
return NOTOK;
k = t -> t_view -> v_name -> oid_nelem + 1;
if ((i = j - k) < 0) {
OID new;
if ((new = oid_extend (oid, -i)) == NULLOID)
return int_SNMP_error__status_genErr;
if (v -> name)
free_SNMP_ObjectName (v -> name);
v -> name = new;
oid = new;
}
else
if (i > 0)
oid -> oid_nelem -= i;
ip = oid -> oid_elements + ot -> ot_name -> oid_nelem;
jp = t -> t_view -> v_name -> oid_elements;
*ip++ = k;
for (k--; k > 0; k--)
*ip++ = *jp++;
}
break;
default:
return int_SNMP_error__status_genErr;
}
switch (ifvar) {
case viewTrapView:
return o_specific (oi, v, (caddr_t) t -> t_view -> v_name);
case viewTrapGenerics:
{
char c = t -> t_generics & 0xff;
return o_string (oi, v, &c, sizeof c);
}
case viewTrapSpecifics:
return o_string (oi, v, NULLCP, 0);
case viewTrapType:
return o_integer (oi, v, T_VALID);
default:
return int_SNMP_error__status_noSuchName;
}
}
/* */
static struct trap *get_trent (ip, len, isnext)
register unsigned int *ip;
int len;
int isnext;
{
register struct trap *t;
ip++, len--;
for (t = UHead -> t_forw; t != UHead; t = t -> t_forw)
switch (elem_cmp (t -> t_view -> v_name -> oid_elements,
t -> t_view -> v_name -> oid_nelem,
ip, len)) {
case 0:
if (!isnext)
return t;
if ((t = t -> t_forw) == UHead)
return NULL;
/* else fall... */
case 1:
return (isnext ? t : NULL);
}
return NULL;
}
/* */
static int view_compar (a, b)
struct view **a,
**b;
{
return oid_cmp ((*a) -> v_name, (*b) -> v_name);
}
static int comm_compar (a, b)
struct community **a,
**b;
{
return elem_cmp ((*a) -> c_instance, (*a) -> c_insize,
(*b) -> c_instance, (*b) -> c_insize);
}
static int trap_compar (a, b)
struct trap **a,
**b;
{
return oid_cmp ((*a) -> t_view -> v_name, (*b) -> t_view -> v_name);
}
static init_view ()
{
register int i;
register OT ot;
register struct community *c;
register struct view *v;
register struct trap *t;
if (ot = text2obj ("viewPrimName"))
ot -> ot_getfnx = o_viewPrim,
ot -> ot_info = (caddr_t) viewPrimName;
if (ot = text2obj ("viewPrimTDomain"))
ot -> ot_getfnx = o_viewPrim,
ot -> ot_info = (caddr_t) viewPrimTDomain;
if (ot = text2obj ("viewPrimTAddr"))
ot -> ot_getfnx = o_viewPrim,
ot -> ot_info = (caddr_t) viewPrimTAddr;
if (ot = text2obj ("viewPrimUser"))
ot -> ot_getfnx = o_viewPrim,
ot -> ot_info = (caddr_t) viewPrimUser;
if (ot = text2obj ("viewPrimCommunity"))
ot -> ot_getfnx = o_viewPrim,
ot -> ot_info = (caddr_t) viewPrimCommunity;
if (ot = text2obj ("viewPrimType"))
ot -> ot_getfnx = o_viewPrim,
ot -> ot_info = (caddr_t) viewPrimType;
if (ot = text2obj ("viewAclView"))
ot -> ot_getfnx = o_viewAcl,
ot -> ot_info = (caddr_t) viewAclView;
if (ot = text2obj ("viewAclCommunity"))
ot -> ot_getfnx = o_viewAcl,
ot -> ot_info = (caddr_t) viewAclCommunity;
if (ot = text2obj ("viewAclUser"))
ot -> ot_getfnx = o_viewAcl,
ot -> ot_info = (caddr_t) viewAclUser;
if (ot = text2obj ("viewAclPrivileges"))
ot -> ot_getfnx = o_viewAcl,
ot -> ot_info = (caddr_t) viewAclPrivileges;
if (ot = text2obj ("viewAclType"))
ot -> ot_getfnx = o_viewAcl,
ot -> ot_info = (caddr_t) viewAclType;
if (ot = text2obj ("viewTrapView"))
ot -> ot_getfnx = o_viewTrap,
ot -> ot_info = (caddr_t) viewTrapView;
if (ot = text2obj ("viewTrapGenerics"))
ot -> ot_getfnx = o_viewTrap,
ot -> ot_info = (caddr_t) viewTrapGenerics;
if (ot = text2obj ("viewTrapSpecifics"))
ot -> ot_getfnx = o_viewTrap,
ot -> ot_info = (caddr_t) viewTrapSpecifics;
if (ot = text2obj ("viewTrapType"))
ot -> ot_getfnx = o_viewTrap,
ot -> ot_info = (caddr_t) viewTrapType;
i = 0;
for (v = VHead -> v_forw; v != VHead; v = v -> v_forw)
i++;
if (i > 1) {
register struct view **base,
**bp,
**ep;
if ((base = (struct view **) malloc ((unsigned) (i * sizeof *base)))
== NULL)
adios (NULLCP, "out of memory");
ep = base;
for (v = VHead -> v_forw; v != VHead; v = v -> v_forw)
remque (*ep++ = v);
VHead -> v_forw = VHead -> v_back = VHead;
qsort ((char *) base, i, sizeof *base, view_compar);
bp = base;
while (bp < ep)
insque (*bp++, VHead -> v_back);
free ((char *) base);
}
i = 0;
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw)
i++;
if (i > 0) {
int j;
register struct community **base,
**bp,
**ep;
if ((base = (struct community **)
malloc ((unsigned) (i * sizeof *base))) == NULL)
adios (NULLCP, "out of memory");
ep = base;
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw) {
register char *cp,
*dp;
register unsigned int *ip;
switch (c -> c_addr.na_stack) {
case NA_TCP:
j = 4;
break;
case NA_X25:
j = c -> c_addr.na_dtelen;
break;
case NA_NSAP:
j = c -> c_addr.na_addrlen;
break;
default:
j = 0;
break;
}
c -> c_insize = 1 + strlen (c -> c_name) + 1 + j;
if ((c -> c_instance =
(unsigned int *) calloc ((unsigned) c -> c_insize,
sizeof *c -> c_instance)) == NULL)
adios (NULLCP, "out of memory");
ip = c -> c_instance;
*ip++ = strlen (c -> c_name);
for (cp = c -> c_name; *cp; cp++)
*ip++ = *cp & 0xff;
*ip++ = j;
switch (c -> c_addr.na_stack) {
case NA_TCP:
(void) sscanf (c -> c_addr.na_domain, "%u.%u.%u.%u",
ip, ip + 1, ip + 2, ip + 3);
break;
case NA_X25:
dp = (cp = c -> c_addr.na_dte) + c -> c_addr.na_dtelen;
goto stuff_it;
case NA_NSAP:
dp = (cp = c -> c_addr.na_address) + c ->c_addr.na_addrlen;
stuff_it: ;
while (cp < dp)
*ip++ = *cp++ & 0xff;
break;
default:
break;
}
*ep++ = c;
}
if (i > 1)
qsort ((char *) base, i, sizeof *base, comm_compar);
bp = base;
c = CLex = *bp++;
while (bp < ep) {
c -> c_next = *bp;
c = *bp++;
}
c -> c_next = NULL;
free ((char *) base);
}
else
CLex = NULL;
i = 0;
for (t = UHead -> t_forw; t != UHead; t = t -> t_forw)
i++;
if (i > 1) {
register struct trap **base,
**bp,
**ep;
if ((base = (struct trap **) malloc ((unsigned) (i * sizeof *base)))
== NULL)
adios (NULLCP, "out of memory");
ep = base;
for (t = UHead -> t_forw; t != UHead; t = t -> t_forw)
remque (*ep++ = t);
UHead -> t_forw = UHead -> t_back = UHead;
qsort ((char *) base, i, sizeof *base, trap_compar);
bp = base;
while (bp < ep)
insque (*bp++, UHead -> t_back);
free ((char *) base);
}
if (debug) {
fprintf (stderr, "///////\nprimitive view table\n");
for (v = VHead -> v_forw; v != VHead; v = v -> v_forw) {
fprintf (stderr, "name=%s ", sprintoid (v -> v_name));
if (v -> v_community) {
register char *cp,
*ep;
char *p;
register struct qbuf *qb;
#ifdef TCP
struct qbuf *x = trap -> data -> un.trap -> agent__addr;
struct sockaddr_in *sin = (struct sockaddr_in *) &v -> v_sa;
#endif
fprintf (stderr, "tDomain=%s tAddr=", sprintoid (rfc1157Domain));
#ifdef TCP
p = "0x";
for (ep = (cp = (char *) &sin -> sin_addr) + 4; cp < ep; cp++) {
fprintf (stderr, "%s%02x", p, *cp & 0xff);
p = ":";
}
for (ep = (cp = (char *) &sin -> sin_port) + 2; cp < ep; cp++)
fprintf (stderr, ":%02x", *cp & 0xff);
#else
fprintf (stderr, "\"\"");
#endif
fprintf (stderr, " user=");
#ifdef TCP
p = "0x";
for (qb = x -> qb_forw; qb != x; qb = qb -> qb_forw)
for (ep = (cp = qb -> qb_data) + qb -> qb_len; cp < ep; cp++) {
fprintf (stderr, "%s%02x", p, *cp & 0xff);
p = ":";
}
#else
fprintf (stderr, "\"\"");
#endif
fprintf (stderr," community=\"");
for (qb = v -> v_community -> qb_forw;
qb != v -> v_community;
qb = qb -> qb_forw)
fprintf (stderr, "%*.*s", qb -> qb_len, qb -> qb_len,
qb -> qb_data);
fprintf (stderr, "\"");
}
else
fprintf (stderr, "tDomain=%s ...", sprintoid (localAgent));
fprintf (stderr, "\n");
}
fprintf(stderr,"\nview access table\n");
for (c = CLex; c; c = c -> c_next) {
OIDentifier oids;
oids.oid_elements = c -> c_instance, oids.oid_nelem = c -> c_insize;
fprintf (stderr,"acl=%s ", sprintoid (&oids));
fprintf (stderr, "view=%s community=%s user=%s privileges=%d\n",
sprintoid (c -> c_view -> v_name), c -> c_name,
na2str (&c -> c_addr),
((c -> c_permission & OT_RDONLY) ? 3 : 0)
+ ((c -> c_permission & OT_WRONLY) ? 8 : 0)
+ ((c -> c_permission & OT_YYY) ? 4 : 0));
}
fprintf(stderr,"\ntrap table\n");
for (t = UHead -> t_forw; t != UHead; t = t -> t_forw) {
v = t -> t_view;
fprintf (stderr, "view=%s generics=0x%x specifics=null\n",
sprintoid (v -> v_name), t -> t_generics);
}
fprintf(stderr,"///////\n");
compat_log -> ll_events |= LLOG_TRACE;
compat_log -> ll_stat |= LLOGTTY;
}
}
/* VIEWS */
static initview () {
register OT ot;
for (ot = text2obj ("ccitt"); ot; ot = ot -> ot_next)
if (ot -> ot_getfnx != NULL && ot -> ot_access != OT_NONE)
export_view (ot);
}
/* */
#define inSubtree(tree,object) \
((tree) -> oid_nelem <= (object) -> oid_nelem \
&& bcmp ((char *) (tree) -> oid_elements, \
(char *) (object) -> oid_elements, \
(tree) -> oid_nelem \
* sizeof ((tree) -> oid_elements[0])) == 0)
static export_view (ot)
register OT ot;
{
register struct subtree *s;
register struct view *v;
OID name = ot -> ot_name;
ot -> ot_views = 0;
for (v = VHead -> v_forw; v != VHead; v = v -> v_forw)
if ((s = v -> v_subtree.s_forw) != &v -> v_subtree) {
for (; s != &v -> v_subtree; s = s -> s_forw)
if (inSubtree (s -> s_subtree, name))
goto mark_it;
}
else {
mark_it: ;
ot -> ot_views |= v -> v_mask;
}
}
/* COMMUNITIES */
struct community *str2comm (name, na)
char *name;
register struct NSAPaddr *na;
{
register struct community *c,
*d;
d = NULL;
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw)
if (strcmp (c -> c_name, name) == 0) {
if (c -> c_addr.na_stack == NA_TCP
&& strcmp (c -> c_addr.na_domain, "0.0.0.0") == 0) {
d = c;
continue;
}
else {
if (c -> c_addr.na_stack != na -> na_stack)
continue;
switch (na -> na_stack) {
case NA_TCP:
if (strcmp (c -> c_addr.na_domain, na -> na_domain))
continue;
break;
case NA_X25:
if (c -> c_addr.na_dtelen != na -> na_dtelen
|| bcmp (c -> c_addr.na_dte,
na -> na_dte, na -> na_dtelen))
continue;
break;
case NA_NSAP:
if (c -> c_addr.na_addrlen != na -> na_addrlen
|| bcmp (c -> c_addr.na_address,
na -> na_address, na -> na_addrlen))
continue;
break;
default:
adios (NULLCP,
"unknown network type (0x%x) for community \"%s\"",
na -> na_stack, name);
/* NOTREACHED */
}
}
d = c;
break;
}
if (d) {
remque (d);
insque (d, CHead);
}
return d;
}
/* TRAPS */
static initrap () {
#ifdef TCP
char myhost[BUFSIZ];
register struct hostent *hp;
struct type_SNMP_Message *msg;
register struct type_SNMP_PDUs *pdu;
register struct type_SNMP_Trap__PDU *parm;
if ((msg = (struct type_SNMP_Message *) calloc (1, sizeof *msg)) == NULL) {
no_mem: ;
advise (LLOG_EXCEPTIONS, NULLCP,
"unable to initialize trap structure: out of memory");
out: ;
if (msg)
free_SNMP_Message (msg);
return;
}
msg -> version = int_SNMP_version_version__1;
if ((pdu = (struct type_SNMP_PDUs *) calloc (1, sizeof *pdu)) == NULL)
goto no_mem;
msg -> data = pdu;
pdu -> offset = type_SNMP_PDUs_trap;
if ((parm = (struct type_SNMP_Trap__PDU *) calloc (1, sizeof *parm))
== NULL)
goto no_mem;
pdu -> un.trap = parm;
(void) strcpy (myhost, TLocalHostName ());
if (hp = gethostbystring (myhost)) {
struct sockaddr_in sin;
inaddr_copy (hp, &sin);
if ((parm -> agent__addr = str2qb ((char *) &sin.sin_addr, 4, 1))
== NULL)
goto no_mem;
}
else {
advise (LLOG_EXCEPTIONS, NULLCP,
"%s: unknown host, so no traps", myhost);
goto out;
}
if ((parm -> time__stamp = (struct type_SNMP_TimeTicks *)
calloc (1, sizeof *parm -> time__stamp)) == NULL)
goto no_mem;
trap = msg;
#ifdef SMUX
if (hp = gethostbystring ("localhost")) {
struct sockaddr_in sin;
inaddr_copy (hp, &sin);
if ((loopback_addr = str2qb ((char *) &sin.sin_addr, 4, 1)) == NULL)
advise (LLOG_EXCEPTIONS, NULLCP,
"unable to initialize loopback address: out of memory");
}
#endif
#endif
}
/* */
#ifndef TCP
/* ARGSUSED */
#endif
static do_trap (generic, specific, bindings)
int generic,
specific;
struct type_SNMP_VarBindList *bindings;
{
#ifdef TCP
struct type_SNMP_Message *msg;
register struct type_SNMP_Trap__PDU *parm;
OT ot;
if ((msg = trap) == NULL)
return;
parm = msg -> data -> un.trap;
if ((ot = text2obj ("sysObjectID")) == NULLOT) {
advise (LLOG_EXCEPTIONS, NULLCP,
"unable to send trap: no such object: \"%s\"",
"sysObjectID");
return;
}
if ((parm -> enterprise = (OID) ot -> ot_info) == NULLOID) {
advise (LLOG_EXCEPTIONS, NULLCP,
"unable to send trap: no value defined for object \"%s\"",
"sysObjectID");
return;
}
parm -> generic__trap = generic;
parm -> specific__trap = specific;
{
struct timeval boottime,
now;
if (getkmem (nl + N_BOOTTIME, (caddr_t) &boottime, sizeof boottime)
== NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP,
"unable to send trap: read of boottime failed");
return;
}
if (gettimeofday (&now, (struct timezone *) 0) == NOTOK) {
advise (LLOG_EXCEPTIONS, "failed", "gettimeofday");
return;
}
parm -> time__stamp -> parm = (now.tv_sec - boottime.tv_sec) * 100
+ ((now.tv_usec - boottime.tv_usec)
/ 10000);
}
parm -> variable__bindings = bindings;
do_traps (msg, generic, specific);
#endif
}
/* */
#ifdef TCP
static do_traps (msg, generic, specific)
register struct type_SNMP_Message *msg;
int generic,
specific;
{
int mask = 1 << 7 - generic;
register struct trap *t;
for (t = UHead -> t_forw; t != UHead; t = t -> t_forw) {
register struct view *v = t -> t_view;
PE pe;
PS ps;
if (specific == 0 && !(t -> t_generics & mask))
continue;
msg -> community = v -> v_community;
pe = NULLPE;
if (encode_SNMP_Message (&pe, 1, 0, NULLCP, msg) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP,
"encode_SNMP_Message: %s", PY_pepy);
if (pe)
pe_free (pe);
continue;
}
PLOGP (pgm_log,SNMP_Message, pe, "Message", 0);
if ((ps = ps_alloc (dg_open)) == NULLPS
|| dg_setup (ps, udp, MAXDGRAM, read_udp_socket,
write_udp_socket) == NOTOK) {
if (ps == NULLPS)
advise (LLOG_EXCEPTIONS, NULLCP, "ps_alloc: out of memory");
else
advise (LLOG_EXCEPTIONS, NULLCP, "dg_setup: %s",
ps_error (ps -> ps_errno));
}
else
if (hack_dgram_socket (udp, &v -> v_sa)
== NOTOK)
advise (LLOG_EXCEPTIONS, "failed", "hack_dgram_socket(1)");
else
if (pe2ps (ps, pe) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s",
ps_error (ps -> ps_errno));
else {
snmpstat.s_outpkts++, snmpstat.s_outtraps++;
if (hack_dgram_socket (udp, (struct sockaddr *) NULL)
== NOTOK)
advise (LLOG_EXCEPTIONS, "failed",
"hack_dgram_socket(2)");
}
pe_free (pe);
if (ps)
ps_free (ps);
else
break;
}
}
#endif
#else /* SNMPT */
/* */
/* ARGSUSED */
static int process (ps, msg, na)
PS ps;
register struct type_SNMP_Message *msg;
struct NSAPaddr *na;
{
char *cp;
long now;
PE pe,
p;
register struct type_SNMP_PDUs *pdu = msg -> data;
register struct tm *tm;
struct UTCtime uts;
register struct UTCtime *ut = &uts;
register struct type_SNMP_Audit *au;
if (msg -> version != int_SNMP_version_version__1) {
advise (LLOG_EXCEPTIONS, NULLCP, "badVersion: %d (%s)",
msg -> version, source);
return NOTOK;
}
if (pdu -> offset != type_SNMP_PDUs_trap) {
advise (LLOG_EXCEPTIONS, NULLCP,
"unexpectedOperation: %d (%s)", pdu -> offset, source);
return NOTOK;
}
pe = p = NULLPE;
au = NULL;
if (encode_SNMP_Message (&p, 1, 0, NULLCP, msg) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "encode_SNMP_Message: %s (%s)",
PY_pepy, source);
goto out;
}
if ((au = (struct type_SNMP_Audit *) calloc (1, sizeof *au)) == NULL)
goto no_mem;
au -> sizeOfEncodingWhichFollows = ps_get_abs (p);
if ((au -> source = str2qb (source, strlen (source), 1)) == NULL) {
no_mem: ;
advise (LLOG_EXCEPTIONS, NULLCP, "out of memory for audit (%s)",
source);
goto out;
}
(void) time (&now);
if (tm = gmtime (&now))
tm2ut (tm, ut);
else {
advise (LLOG_EXCEPTIONS, NULLCP, "gmtime failed");
bzero ((char *) ut, sizeof *ut);
}
if ((cp = gent2str (ut)) == NULL
|| (au -> dateAndTime = str2qb (cp, strlen (cp), 1)) == NULL)
goto no_mem;
if (encode_SNMP_Audit (&pe, 1, 0, NULLCP, au) != NOTOK) {
PLOGP (pgm_log,SNMP_Audit, pe, "Audit", 0);
PLOGP (pgm_log,SNMP_Message, p, "Message", 0);
if (pe2ps (audit, pe) == NOTOK || pe2ps (audit, p) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s (%s)",
ps_error (audit -> ps_errno), source);
(void) ps_flush (audit);
}
else
advise (LLOG_EXCEPTIONS, NULLCP, "encode_SNMP_Audit: %s (%s)",
PY_pepy, source);
out: ;
if (au)
free_SNMP_Audit (au);
if (pe)
pe_free (pe);
if (p)
pe_free (p);
return DONE;
}
#endif /* SNMPT */
/* MISCELLANY */
static arginit (vec)
char **vec;
{
register char *ap;
#ifdef SNMPT
char *file = "snmp.traps";
FILE *fp;
#endif
#ifdef TCP
int port;
struct NSAPaddr *tcp_na;
register struct servent *sp;
#endif
#ifdef X25
struct NSAPaddr *x25_na;
#endif
if (myname = rindex (*vec, '/'))
myname++;
if (myname == NULL || *myname == NULL)
myname = *vec;
isodetailor (myname, 0);
ll_hdinit (pgm_log, myname);
bzero ((char *) tas, sizeof tas);
tz = tas;
#ifdef TCP
if (!(ts_stacks & TS_TCP))
tcpservice = 0;
if ((sp = getservbyname ("snmp", "udp")) == NULL)
advise (LLOG_EXCEPTIONS, NULLCP, "udp/snmp: unknown service");
tcp_na = tz -> ta_addrs;
tcp_na -> na_stack = NA_TCP;
tcp_na -> na_community = ts_comm_tcp_default;
tcp_na -> na_domain[0] = NULL;
#ifndef SNMPT
tcp_na -> na_port = sp ? sp -> s_port : htons ((u_short) 161);
udport = tcp_na -> na_port;
#endif
tz -> ta_naddr = 1;
tz++;
if ((sp = getservbyname ("snmp-trap", "udp")) == NULL)
advise (LLOG_EXCEPTIONS, NULLCP, "udp/snmp-trap: unknown service");
#ifndef SNMPT
traport = sp ? sp -> s_port : htons ((u_short) 162);
#else
tcp_na -> na_port = sp ? sp -> s_port : htons ((u_short) 162);
#endif
#endif
#ifdef COTS
bzero ((char *) taddrs, sizeof taddrs);
bzero ((char *) lru, sizeof lru);
#endif
#ifdef X25
if (!(ts_stacks & TS_X25))
x25service = 0;
x25_na = tz -> ta_addrs;
x25_na -> na_stack = NA_X25;
x25_na -> na_community = ts_c_x25_default;
if (x25_local_dte && *x25_local_dte) {
(void) strcpy (x25_na -> na_dte, x25_local_dte);
x25_na -> na_dtelen = strlen (x25_na -> na_dte);
}
#ifndef SNMPT
x25_na -> na_pidlen = str2sel ("03018200", -1, x25_na -> na_pid, NPSIZE);
#else
x25_na -> na_pidlen = str2sel ("03019000", -1, x25_na -> na_pid, NPSIZE);
#endif
tz -> ta_naddr = 1;
tz++;
#endif
#ifdef TP4
if (!(ts_stacks & TS_TP4))
tp4service = 0;
#ifndef SNMPT
bcopy ("snmp", tz -> ta_selector, tz -> ta_selectlen = sizeof "snmp" - 1);
#else
bcopy ("snmp-trap", tz -> ta_selector,
tz -> ta_selectlen = sizeof "snmp-trap" - 1);
#endif
tz -> ta_naddr = 0;
tz++;
#endif
for (vec++; ap = *vec; vec++) {
if (*ap == '-')
switch (*++ap) {
case 'd':
debug++;
continue;
#ifndef SNMPT
case 's':
#ifdef SMUX
smux_enabled = 0;
#endif
continue;
#endif
case 't':
ts_stacks = TS_TCP;
tcpservice = 1;
x25service = tp4service = 0;
continue;
case 'x':
ts_stacks = TS_X25;
x25service = 1;
tcpservice = tp4service = 0;
continue;
case 'z':
ts_stacks = TS_TP4;
tp4service = 1;
tcpservice = x25service = 0;
continue;
#ifndef SNMPT
case 'r':
rflag = 1;
continue;
#else
case 'f':
if ((file = *++vec) == NULL || *file == '-')
adios (NULLCP, "usage: %s -f audit-file", myname);
continue;
#endif
#ifdef TCP
case 'p':
if ((ap = *++vec) == NULL
|| *ap == '-'
|| (port = atoi (ap)) <= 0)
adios (NULLCP, "usage: %s -p portno", myname);
tcp_na -> na_port = htons ((u_short) port);
continue;
#endif
#ifdef X25
/* This permits listening on a specific subaddress. */
case 'a':
if ((ap = *++vec) == NULL || *ap == '-')
adios (NULLCP, "usage: %s -a x121address", myname);
(void) strcpy (x25_na -> na_dte, ap);
x25_na -> na_dtelen = strlen (ap);
continue;
/* This permits listening on a specific protocol id.
In fact, SunLink X.25 lets you listen on a protocol
id mask, but let's keep it simple. */
case 'i':
if ((ap = *++vec) == NULL || *ap == '-' )
adios (NULLCP, "usage: %s -i pid", myname);
x25_na -> na_pidlen =
str2sel (ap, -1, x25_na -> na_pid, NPSIZE);
continue;
#endif
default:
adios (NULLCP, "-%s: unknown switch", ap);
}
adios (NULLCP, "usage: %s [switches]", myname);
}
ps_len_strategy = PS_LEN_LONG;
#ifdef SNMPT
file = _isodefile (isodelogpath, file);
if ((fp = fopen (file, "a")) == NULL)
adios (file, "unable to append to");
if ((audit = ps_alloc (std_open)) == NULLPS)
adios (NULLCP, "ps_alloc(std_open): you lose");
if (std_setup (audit, fp) == NOTOK)
adios (NULLCP, "std_setup: %s", ps_error (audit -> ps_errno));
#endif
}
/* */
static envinit () {
int i,
sd;
char file[BUFSIZ];
FILE *fp;
nbits = getdtablesize ();
if (debug == 0 && !(debug = isatty (2))) {
for (i = 0; i < 5; i++) {
switch (fork ()) {
case NOTOK:
sleep (5);
continue;
case OK:
break;
default:
_exit (0);
}
break;
}
(void) chdir ("/");
if ((sd = open ("/dev/null", O_RDWR)) == NOTOK)
adios ("/dev/null", "unable to read");
if (sd != 0)
(void) dup2 (sd, 0), (void) close (sd);
(void) dup2 (0, 1);
(void) dup2 (0, 2);
#ifdef SETSID
if (setsid () == NOTOK)
advise (LLOG_EXCEPTIONS, "failed", "setsid");
#endif
#ifdef TIOCNOTTY
if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
(void) ioctl (sd, TIOCNOTTY, NULLCP);
(void) close (sd);
}
#else
#ifdef SYS5
(void) setpgrp ();
(void) signal (SIGINT, SIG_IGN);
(void) signal (SIGQUIT, SIG_IGN);
#endif
#endif
}
else
ll_dbinit (pgm_log, myname);
#ifndef sun /* damn YP... */
for (sd = 3; sd < nbits; sd++)
if (pgm_log -> ll_fd != sd)
(void) close (sd);
#endif
(void) signal (SIGPIPE, SIG_IGN);
ll_hdinit (pgm_log, myname);
#ifndef SNMPT
if (readobjects ("snmpd.defs") == NOTOK)
adios (NULLCP, "readobjects: %s", PY_pepy);
readmib ();
readconfig ();
init_snmp ();
#ifdef SMUX
init_smux ();
#endif
init_view ();
initrap ();
initview ();
checkmib ();
o_advise = (IFP) advise;
#endif
(void) sprintf (file, "/etc/%s.pid", myname);
if (fp = fopen (file, "w")) {
(void) fprintf (fp, "%d\n", getpid ());
(void) fclose (fp);
}
advise (LLOG_NOTICE, NULLCP, "starting");
}
/* CONFIG */
#ifndef SNMPT
int f_community (), f_logging (), f_proxy (), f_trap (), f_variable (),
f_view ();
static struct pair {
char *p_name; /* runcom directive */
IFP p_handler; /* dispatch */
} pairs[] = {
"community", f_community,
"logging", f_logging,
"proxy", f_proxy,
"trap", f_trap,
"variable", f_variable,
"view", f_view,
NULL
};
static struct wired {
char *w_args1;
char *w_args2;
} wired[] = {
"defViewWholeRW", NULL,
"defViewWholeRO", NULL,
"defViewStandardRW", "mgmt",
"defViewStandardRO", "mgmt",
NULL
};
static readconfig () {
register char *cp;
char buffer[BUFSIZ],
line[BUFSIZ],
*vec[NVEC + NSLACK + 1];
register struct community *c;
register struct view *v;
register struct pair *p;
register struct wired *w;
struct stat st;
FILE *fp;
CHead -> c_forw = CHead -> c_back = CHead;
UHead -> t_forw = UHead -> t_back = UHead;
VHead -> v_forw = VHead -> v_back = VHead;
if ((localAgent = text2oid ("localAgent")) == NULLOID)
adios (NULLCP, "unknown OID \"localAgent\"");
if ((rfc1157Domain = text2oid ("rfc1157Domain")) == NULLOID)
adios (NULLCP, "unknown OID \"rfc1157Domain\"");
vec[0] = "view";
for (w = wired; w -> w_args1; w++) {
vec[1] = w -> w_args1;
if (vec[2] = w -> w_args2)
vec[3] = NULL;
if (f_view (vec) == NOTOK)
adios (NULLCP, "you lose");
}
(void) strcpy (buffer, "defViewTrapDest.0");
if ((trapview = text2oid (buffer)) == NULLOID)
adios (NULLCP, "unknown OID \"defViewTrapDest.0\" for traps");
trapview -> oid_nelem--;
bzero ((char *) &snmpstat, sizeof snmpstat);
snmpstat.s_enableauthtraps = TRAPS_ENABLED;
if ((fp = fopen (cp = "snmpd.rc", "r")) == NULL
&& (fp = fopen (cp = isodefile ("snmpd.rc", 0), "r")) == NULL)
adios (cp, "unable to read");
if (!rflag
&& getuid () == 0
&& fstat (fileno (fp), &st) != NOTOK
&& st.st_uid != 0)
adios (NULLCP, "%s not owned by root", cp);
while (fgets (buffer, sizeof buffer, fp)) {
if (*buffer == '#')
continue;
if (cp = index (buffer, '\n'))
*cp = NULL;
(void) strcpy (line, buffer);
bzero ((char *) vec, sizeof vec);
if (str2vec (buffer, vec) < 1)
continue;
for (p = pairs; p -> p_name; p++)
if (lexequ (p -> p_name, vec[0]) == 0) {
if ((*p -> p_handler) (vec) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP,
"malformed directive: \"%s\"", line);
break;
}
if (!p -> p_name)
advise (LLOG_EXCEPTIONS, NULLCP, "unknown directive: \"%s\"",
line);
}
(void) fclose (fp);
if (CHead -> c_forw == CHead) {
vec[0] = "community";
vec[1] = "public";
vec[2] = NULL;
(void) f_community (vec);
}
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw) {
for (v = VHead -> v_forw; v != VHead; v = v -> v_forw)
if (oid_cmp (v -> v_name, c -> c_vu) == 0) {
c -> c_view = v;
break;
}
if (v == VHead)
advise (LLOG_EXCEPTIONS, NULLCP,
"no such view as %s for community \"%s\"",
sprintoid (c -> c_vu), c -> c_name);
}
}
/* */
static int f_community (vec)
char **vec;
{
register struct community *c;
register struct NSAPaddr *na;
vec++;
if ((c = (struct community *) calloc (1, sizeof *c)) == NULL
|| (c -> c_name = strdup (*vec)) == NULL)
adios (NULLCP, "out of memory");
vec++;
na = &c -> c_addr;
if (*vec) {
if (str2sa (*vec, na, (struct sockaddr *) NULL, 0) == NOTOK)
adios (NULLCP, "unknown address \"%s\" for community \"%s\"",
*vec, c -> c_name);
vec++;
}
else {
na -> na_stack = NA_TCP;
na -> na_community = ts_comm_tcp_default;
(void) strcpy (na -> na_domain, "0.0.0.0");
}
if (*vec) {
if (lexequ (*vec, "readOnly") == 0)
c -> c_permission = OT_RDONLY;
else
if (lexequ (*vec, "readWrite") == 0)
c -> c_permission = OT_RDWRITE;
else
if (lexequ (*vec, "writeOnly") == 0)
c -> c_permission = OT_WRONLY;
else
if (lexequ (*vec, "none")) {
advise (LLOG_EXCEPTIONS, NULLCP,
"invalid access mode \"%s\"", *vec);
goto you_lose;
}
vec++;
}
else
c -> c_permission = OT_RDONLY;
if (*vec) {
char buffer[BUFSIZ];
(void) strcpy (buffer, *vec);
if ((c -> c_vu = text2oid (buffer)) == NULLOID) {
advise (LLOG_EXCEPTIONS, NULLCP, "unknown OID \"%s\"", *vec);
goto you_lose;
}
if (*++vec)
goto you_lose;
}
else
if ((c -> c_vu = text2oid ("defViewWholeRO")) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "unknown OID \"defViewWholeRO\"");
goto you_lose;
}
insque (c, CHead -> c_back);
return OK;
you_lose: ;
free (c -> c_name);
free ((char *) c);
return NOTOK;
}
/* */
static int f_logging (vec)
char **vec;
{
register char **vp;
for (vp = ++vec; *vp; vp++)
continue;
log_tai (pgm_log, vec, vp - vec);
return OK;
}
/* */
static int f_proxy (vec)
char **vec;
{
char buffer[BUFSIZ];
register struct community *c;
register struct view *v,
*u;
register struct NSAPaddr *na;
if ((v = (struct view *) calloc (1, sizeof *v)) == NULL)
adios (NULLCP, "out of memory");
v -> v_subtree.s_forw = v -> v_subtree.s_back = &v -> v_subtree;
if ((c = (struct community *) calloc (1, sizeof *c)) == NULL)
adios (NULLCP, "out of memory");
c -> c_permission = OT_YYY;
vec++;
(void) strcpy (buffer, *vec);
if ((v -> v_name = text2oid (buffer)) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "unknown OID \"%s\"", *vec);
goto you_lose;
}
c -> c_vu = v -> v_name;
if (trapview && inSubtree (trapview, v -> v_name)) {
advise (LLOG_EXCEPTIONS, NULLCP, "view \"%s\" is for traps", *vec);
goto you_lose;
}
for (u = VHead -> v_forw; u != VHead; u = u -> v_forw)
if (oid_cmp (u -> v_name, v -> v_name) == 0) {
advise (LLOG_EXCEPTIONS, NULLCP, "duplicate view \"%s\"", *vec);
goto you_lose;
}
vec++;
if (lexequ (*vec, "rfc1157")) {
advise (LLOG_EXCEPTIONS, NULLCP, "unsupported proxy domain \"%s\"",
*vec);
goto you_lose;
}
vec++;
na = &c -> c_addr;
if (*vec) {
if (str2sa (*vec, na, &v -> v_sa, 1) == NOTOK)
adios (NULLCP, "unknown address \"%s\" for proxy %s",
*vec, oid2ode (v -> v_name));
vec++;
}
else
goto you_lose;
if (*vec) {
if ((v -> v_community = str2qb (*vec, strlen (*vec), 1)) == NULL)
adios (NULLCP, "out of memory");
if ((c -> c_name = strdup (*vec)) == NULL)
adios (NULLCP, "out of memory");
if (*++vec)
goto you_lose;
}
else
goto you_lose;
insque (v, VHead -> v_back);
insque (c, CHead -> c_back);
return OK;
you_lose: ;
if (c -> c_name)
free (c -> c_name);
free ((char *) c);
if (v -> v_name)
oid_free (v -> v_name);
if (v -> v_community)
qb_free (v -> v_community);
free ((char *) v);
return NOTOK;
}
/* */
static int f_trap (vec)
char **vec;
{
register struct trap *t;
register struct view *v;
struct NSAPaddr nas;
register struct NSAPaddr *na = &nas;
static int trapno = 1;
vec++;
if ((t = (struct trap *) calloc (1, sizeof *t)) == NULL
|| (t -> t_name = strdup (*vec)) == NULL)
adios (NULLCP, "out of memory");
v = t -> t_view = &t -> t_vu;
v -> v_subtree.s_forw = v -> v_subtree.s_back = &v -> v_subtree;
t -> t_generics = 0xfe;
vec++;
trapview -> oid_elements[trapview -> oid_nelem++] = trapno;
v -> v_name = oid_cpy (trapview);
trapview -> oid_nelem--;
if (v -> v_name == NULLOID)
adios (NULLCP, "out of memory");
if ((v -> v_community = str2qb (t -> t_name, strlen (t -> t_name), 1))
== NULL)
adios (NULLCP, "out of memory");
bzero ((char *) na, sizeof *na);
if (*vec) {
if (str2sa (*vec, na, &v -> v_sa, 0) == NOTOK)
adios (NULLCP, "unknown address \"%s\" for trap sink \"%s\"",
*vec, t -> t_name);
vec++;
}
else
goto you_lose;
if (*vec) {
char buffer[BUFSIZ];
OID name;
register struct view *u;
(void) strcpy (buffer, *vec);
if ((name = text2oid (buffer)) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "unknown OID \"%s\"", *vec);
goto you_lose;
}
oid_free (v -> v_name);
v -> v_name = name;
for (u = VHead -> v_forw; u != VHead; u = u -> v_forw)
if (oid_cmp (u -> v_name, v -> v_name) == 0) {
advise (LLOG_EXCEPTIONS, NULLCP,
"duplicate view \"%s\" for trap sink \"%s\"",
*vec, t -> t_name);
goto you_lose;
}
vec++;
}
else
trapno++;
if (*vec) {
if (sscanf (*vec, "%lx", &t -> t_generics) != 1)
goto you_lose;
if (*++vec)
goto you_lose;
}
insque (t, UHead -> t_back);
insque (v, VHead -> v_back);
return OK;
you_lose: ;
oid_free (v -> v_name);
qb_free (v -> v_community);
free (t -> t_name);
free ((char *) t);
return NOTOK;
}
/* */
static int f_variable (vec)
char **vec;
{
if (*++vec == NULL)
return NOTOK;
if (lexequ (*vec, "interface") == 0) {
char *name;
if ((name = *++vec) == NULL)
return NOTOK;
for (vec++; *vec; vec++)
if (index (*vec, '='))
set_interface (name, *vec);
else
return NOTOK;
return OK;
}
if (lexequ (*vec, "snmpEnableAuthTraps") == 0) {
++vec;
if (lexequ (*vec, "enabled") == 0)
snmpstat.s_enableauthtraps = TRAPS_ENABLED;
else
if (lexequ (*vec, "disabled") == 0)
snmpstat.s_enableauthtraps = TRAPS_DISABLED;
return OK;
}
if (!vec[0] || !vec[1] || vec[2])
return NOTOK;
set_variable (vec[0], vec[1]);
return OK;
}
/* */
static int f_view (vec)
char **vec;
{
char buffer[BUFSIZ];
register struct subtree *s,
*x,
*y;
register struct view *v,
*u;
if (viewmask == 0) {
advise (LLOG_EXCEPTIONS, NULLCP,
"too many views starting with \"%s\"", *vec);
return NOTOK;
}
if ((v = (struct view *) calloc (1, sizeof *v)) == NULL)
adios (NULLCP, "out of memory");
s = &v -> v_subtree;
v -> v_subtree.s_forw = v -> v_subtree.s_back = s;
vec++;
(void) strcpy (buffer, *vec);
if ((v -> v_name = text2oid (buffer)) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "unknown OID \"%s\"", *vec);
goto you_lose;
}
if (trapview && inSubtree (trapview, v -> v_name)) {
advise (LLOG_EXCEPTIONS, NULLCP, "view \"%s\" is for traps", *vec);
goto you_lose;
}
for (u = VHead -> v_forw; u != VHead; u = u -> v_forw)
if (oid_cmp (u -> v_name, v -> v_name) == 0) {
advise (LLOG_EXCEPTIONS, NULLCP, "duplicate view \"%s\"", *vec);
goto you_lose;
}
for (vec++; *vec; vec++) {
register struct subtree *z;
OID name;
(void) strcpy (buffer, *vec);
if ((name = text2oid (buffer)) == NULLOID) {
advise (LLOG_EXCEPTIONS, NULLCP, "unknown OID \"%s\"", *vec);
goto you_lose;
}
for (x = s -> s_forw; x != s; x = y) {
register int i,
j;
y = x -> s_forw;
if (bcmp ((char *) x -> s_subtree -> oid_elements,
(char *) name -> oid_elements,
((i = x -> s_subtree -> oid_nelem)
<= (j = name -> oid_nelem) ? i : j)
* sizeof name -> oid_elements[0]) == 0) {
advise (LLOG_EXCEPTIONS, NULLCP,
"%s %s %s",
*vec,
i <= j ? "already under" : "superceding",
oid2ode (x -> s_subtree));
if (i <= j)
goto another;
remque (x);
oid_free (x -> s_subtree);
free ((char *) x);
}
}
if ((z = (struct subtree *) calloc (1, sizeof *z)) == NULL)
adios (NULLCP, "out of memory");
z -> s_subtree = name;
insque (z, s -> s_back);
another: ;
}
v -> v_mask = viewmask;
viewmask <<= 1;
insque (v, VHead -> v_back);
return OK;
you_lose: ;
for (x = s -> s_forw; x != s; x = y) {
y = x -> s_forw;
remque (x);
oid_free (x -> s_subtree);
free ((char *) x);
}
if (v -> v_name)
oid_free (v -> v_name);
free ((char *) v);
return NOTOK;
}
/* */
static int str2sa (s, na, sock, proxy)
char *s;
struct NSAPaddr *na;
struct sockaddr *sock;
int proxy;
{
#ifdef TCP
register struct hostent *hp;
#endif
struct TSAPaddr *ta;
#ifdef TCP
if (hp = gethostbystring (s)) {
struct sockaddr_in sin;
na -> na_stack = NA_TCP;
na -> na_community = ts_comm_tcp_default;
inaddr_copy (hp, &sin);
(void) strncpy (na -> na_domain, inet_ntoa (sin.sin_addr),
sizeof na -> na_domain - 1);
}
else
#endif
if ((ta = str2taddr (s)) && ta -> ta_naddr > 0) {
*na = ta -> ta_addrs[0]; /* struct copy */
}
else
return NOTOK;
if (sock == NULL)
return OK;
switch (na -> na_stack) {
#ifdef TCP
case NA_TCP:
if (!tcpservice)
goto you_lose;
{
struct sockaddr_in sin;
sin.sin_port = na -> na_port ? na -> na_port
: proxy ? udport : traport;
if ((hp = gethostbystring (na -> na_domain)) == NULL)
return NOTOK;
sin.sin_family = hp -> h_addrtype;
inaddr_copy (hp, &sin);
*((struct sockaddr_in *) sock) = sin; /* struct copy */
}
break;
#endif
default:
you_lose: ;
advise (LLOG_EXCEPTIONS, NULLCP, "address type unsupported");
return NOTOK;
}
return OK;
}
#endif /* SNMPT */
/* ERRORS */
#ifndef lint
void adios (va_alist)
va_dcl
{
va_list ap;
va_start (ap);
_ll_log (pgm_log, LLOG_FATAL, ap);
va_end (ap);
_exit (1);
}
#else
/* VARARGS */
void adios (what, fmt)
char *what,
*fmt;
{
adios (what, fmt);
}
#endif
#ifndef lint
void advise (va_alist)
va_dcl
{
int code;
va_list ap;
va_start (ap);
code = va_arg (ap, int);
_ll_log (pgm_log, code, ap);
va_end (ap);
}
#else
/* VARARGS */
void advise (code, what, fmt)
char *what,
*fmt;
int code;
{
advise (code, what, fmt);
}
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.