|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 32952 (0x80b8)
Types: TextFile
Names: »snmpd.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/snmp/snmpd.c«
/* snmpd.c - SNMP agent for 4BSD */
#ifndef lint
static char *rcsid = "$Header: /f/osi/snmp/RCS/snmpd.c,v 7.8 90/01/11 18:34:33 mrose Exp $";
#endif
/*
* $Header: /f/osi/snmp/RCS/snmpd.c,v 7.8 90/01/11 18:34:33 mrose 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 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"
#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
#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
#define IDLE_TIME (3 * 60)
/* \f
DATA */
int debug = 0;
static int nbits = FD_SETSIZE;
static int rflag = 0;
static LLog _pgm_log = {
"snmpd.log", NULLCP, NULLCP, LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE,
LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK
};
static LLog *pgm_log = &_pgm_log;
static char *myname = "snmpd";
static int tcpservice = 1;
static int x25service = 1;
static int tp4service = 1;
#define NTADDRS FD_SETSIZE
static struct TSAPaddr *tz;
static struct TSAPaddr tas[NTADDRS];
static fd_set ifds;
#ifdef COTS
static struct TSAPaddr taddrs[FD_SETSIZE];
static struct timeval lru[FD_SETSIZE];
#endif
void adios (), advise ();
void ts_advise ();
extern int errno;
/* \f
*/
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; /* global check, someday do per-object... */
#define COMM_TRAP (-1)
#define COMM_NONE 0
#define COMM_RDONLY 1
#define COMM_RDWRITE 2
struct qbuf *c_community; /* for traps only... */
#ifdef TCP
struct sockaddr_in c_sin; /* .. */
#endif
};
static struct community commque;
static struct community *CHead = &commque;
struct community *str2comm ();
static struct type_SNMP_Message *trap = NULL;
int nd = NOTOK;
int quantum = 0;
#ifdef TCP
static int udp = NOTOK;
static int traport;
#endif
#ifdef CLTS
static int clts = NOTOK;
#endif
struct snmpstat snmpstat;
/* \f
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_type) {
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_type);
/* 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");
do_trap (int_SNMP_generic__trap_coldStart, 0,
(struct type_SNMP_VarBindList *) 0);
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++) {
#ifdef TCP
if (fd == udp)
continue;
#endif
#ifdef CLTS
if (fd == clts)
continue;
#endif
if (FD_ISSET (fd, &ifds)) {
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);
#ifdef COTS
FD_CLR (udp, &rfds);
#endif
}
#endif
#ifdef CLTS
if (clts != NOTOK && FD_ISSET (clts, &rfds)) {
doit_clts (clts);
#ifdef COTS
FD_CLR (clts, &rfds);
#endif
}
#endif
#ifdef COTS
if (vecp > 0 && start_tsap (vecp, vec) == OK) {
if (fd >= nfds)
nfds = fd + 1;
FD_SET (fd, &ifds);
}
for (fd = 0; fd < nfds; fd++)
if (FD_ISSET (fd, &rfds))
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, &ifds)) {
#ifdef TCP
if (fd == udp)
continue;
#endif
#ifdef CLTS
if (fd == clts)
continue;
#endif
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);
}
}
for (fd = nfds - 1; fd >= 0; fd--)
if (FD_ISSET (fd, &ifds))
break;
nfds = fd + 1;
#endif
}
}
/* \f
*/
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);
}
/* \f
*/
#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");
}
cp = inet_ntoa (isock -> sin_addr);
advise (LLOG_NOTICE, NULLCP, "packet from %s/%d",
cp, (int) ntohs (isock -> sin_port));
bzero ((char *) na, sizeof *na);
na -> na_type = NA_TCP;
na -> na_subnet = 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);
(void) close_udp_socket (fd);
}
#endif
/* \f
*/
#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);
advise (LLOG_NOTICE, NULLCP, "packet from %s", taddr2str (ta));
doit_aux (fd, ta -> ta_addrs, read_clts_socket, write_clts_socket);
(void) close_clts_socket (fd);
}
#endif
/* \f
*/
#ifdef COTS
static 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_NOTICE, 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 OK;
}
/* \f
*/
static doit_cots (fd)
int fd;
{
doit_aux (fd, &(taddrs[fd].ta_addrs[0]), ts_read, ts_write);
(void) gettimeofday (lru + fd, (struct timezone *) 0);
}
#endif
/* \f
*/
static doit_aux (fd, na, rfx, wfx)
int fd;
struct NSAPaddr *na;
IFP rfx,
wfx;
{
PE pe;
PS ps;
struct type_SNMP_Message *msg;
pe = NULLPE;
msg = NULL;
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");
else
advise (LLOG_EXCEPTIONS, NULLCP, "dg_setup: %s",
ps_error (ps -> ps_errno));
goto out;
}
if ((pe = ps2pe (ps)) == NULLPE) {
#ifdef COTS
if (rfx == ts_read) {
FD_CLR (fd, &ifds);
if (ps -> ps_errno == PS_ERR_NONE) {
advise (LLOG_NOTICE, NULLCP,
"T-DISCONNECT.INDICATION: %d (%s)",
fd, taddr2str (taddrs + fd));
goto out;
}
}
#endif
advise (LLOG_EXCEPTIONS, NULLCP, "ps2pe: %s",
ps_error (ps -> ps_errno));
snmpstat.s_inpkts++;
snmpstat.s_asnparseerrs++;
goto out;
}
#ifdef COTS
if (rfx == ts_read)
advise (LLOG_NOTICE, NULLCP, "T-DATA.INDICATION: %d (%s)", fd,
taddr2str (taddrs + fd));
#endif
snmpstat.s_inpkts++;
if (decode_SNMP_Message (pe, 1, NULLIP, NULLVP, &msg) == NOTOK) {
advise (LLOG_EXCEPTIONS, NULLCP, "decode_SNMP_Message: %s", PY_pepy);
snmpstat.s_asnparseerrs++;
#ifdef COTS
if (rfx == ts_read) {
struct TSAPdisconnect tds;
(void) TDiscRequest (fd, NULLCP, 0, &tds);
FD_CLR (fd, &ifds);
}
#endif
goto out;
}
PLOG (pgm_log, print_SNMP_Message, pe, "Message", 1);
process (ps, msg, na);
out: ;
if (msg)
free_SNMP_Message (msg);
if (pe)
pe_free (pe);
if (ps)
ps_free (ps);
}
/* \f
*/
static process (ps, msg, na)
PS ps;
register struct type_SNMP_Message *msg;
struct NSAPaddr *na;
{
char *commname;
struct community *comm;
PE pe;
if (msg -> version != int_SNMP_version_version__1) {
advise (LLOG_EXCEPTIONS, NULLCP, "badVersion: %d", msg -> version);
snmpstat.s_badversions++;
return;
}
if ((commname = qb2str (msg -> community)) == NULLCP) {
advise (LLOG_EXCEPTIONS, NULLCP, "qb2str: out of memory");
return;
}
if ((comm = str2comm (commname, na)) == NULL) {
advise (LLOG_EXCEPTIONS, NULLCP, "badCommunity: %s", commname);
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 (do_operation (msg, comm) == NOTOK)
goto out;
pe = NULLPE;
if (encode_SNMP_Message (&pe, 1, 0, NULLCP, msg) != NOTOK) {
PLOG (pgm_log, print_SNMP_Message, pe, "Message", 0);
if (pe2ps (ps, pe) == NOTOK)
advise (LLOG_EXCEPTIONS, NULLCP, "pe2ps: %s",
ps_error (ps -> ps_errno));
else
snmpstat.s_outpkts++;
}
else
advise (LLOG_EXCEPTIONS, NULLCP, "encode_SNMP_Message: %s", PY_pepy);
if (pe)
pe_free (pe);
out: ;
free (commname);
}
/* \f
*/
static int do_operation (msg, comm)
struct type_SNMP_Message *msg;
struct community *comm;
{
int idx,
offset,
status;
object_instance ois;
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++;
goto do_get;
case type_SNMP_PDUs_get__next__request:
snmpstat.s_ingetnexts++;
do_get: ;
if (comm -> c_permission < COMM_RDONLY) {
snmpstat.s_badcommunityuses++;
parm -> error__status = int_SNMP_error__status_genErr;
goto out;
}
break;
case type_SNMP_PDUs_set__request:
snmpstat.s_insetrequests++;
if (comm -> c_permission < COMM_RDWRITE) {
read_only: ;
snmpstat.s_badcommunityuses++;
parm -> error__status = int_SNMP_error__status_readOnly;
goto out;
}
break;
case type_SNMP_PDUs_get__response:
case type_SNMP_PDUs_trap:
advise (LLOG_EXCEPTIONS, NULLCP,
"unexpectedOperation: %d", pdu -> offset);
snmpstat.s_badtypes++;
return NOTOK;
default:
advise (LLOG_EXCEPTIONS, NULLCP,
"badOperation: %d", pdu -> offset);
snmpstat.s_badtypes++;
return NOTOK;
}
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)
goto get_next;
}
else
if ((oi = name2inst (v -> name)) == NULLOI
|| (ot = oi -> oi_type) -> ot_getfnx == NULLIFP) {
no_name: ;
parm -> error__status = int_SNMP_error__status_noSuchName;
goto out;
}
try_again: ;
switch (ot -> ot_access) {
case OT_NONE:
if (offset == type_SNMP_PDUs_get__next__request)
goto get_next;
goto no_name;
case OT_RDONLY:
if (offset == type_SNMP_PDUs_set__request)
goto read_only;
break;
case OT_RDWRITE:
break;
}
switch (status = (*ot -> ot_getfnx) (oi, v, offset)) {
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)
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 OK;
}
/* \f
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 (c -> c_permission == COMM_TRAP)
continue;
if (lexequ (c -> c_name, name) == 0) {
if (c -> c_addr.na_type == NA_TCP
&& strcmp (c -> c_addr.na_domain, "0.0.0.0") == 0) {
d = c;
continue;
}
else {
if (c -> c_addr.na_type != na -> na_type)
continue;
switch (na -> na_type) {
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_type, name);
/* NOTREACHED */
}
}
d = c;
break;
}
}
if (d) {
remque (d);
insque (d, CHead);
}
return d;
}
/* \f
TRAPS */
static initrap () {
#ifdef TCP
char myhost[BUFSIZ];
register struct community *c;
register struct hostent *hp;
struct type_SNMP_Message *msg;
register struct type_SNMP_PDUs *pdu;
register struct type_SNMP_Trap__PDU *parm;
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw)
if (c -> c_permission == COMM_TRAP)
break;
if (c == CHead)
return;
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;
#endif
}
/* \f
*/
#ifndef TCP
/* ARGSUSED */
#endif
static do_trap (generic, specific, bindings)
int generic,
specific;
struct type_SNMP_VarBindList *bindings;
{
#ifdef TCP
register struct community *c;
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;
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw) {
PE pe;
PS ps;
if (c -> c_permission != COMM_TRAP)
continue;
msg -> community = c -> c_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;
}
PLOG (pgm_log, print_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, (struct sockaddr *) &c -> c_sin)
== 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
}
/* \f
MISCELLANY */
static arginit (vec)
char **vec;
{
register char *ap;
#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_type = NA_TCP;
tcp_na -> na_subnet = ts_comm_tcp_default;
tcp_na -> na_domain[0] = NULL;
tcp_na -> na_port = sp ? sp -> s_port : htons ((u_short) 161);
tz -> ta_naddr = 1;
tz++;
if ((sp = getservbyname ("snmp-trap", "udp")) == NULL)
advise (LLOG_EXCEPTIONS, NULLCP, "udp/snmp-trap: unknown service");
traport = sp ? sp -> s_port : htons ((u_short) 162);
#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_type = NA_X25;
x25_na -> na_subnet = ts_comm_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);
}
x25_na -> na_pidlen = str2sel ("03018200", -1, x25_na -> na_pid, NPSIZE);
tz -> ta_naddr = 1;
tz++;
#endif
#ifdef TP4
if (!(ts_stacks & TS_TP4))
tp4service = 0;
bcopy ("snmp", tz -> ta_selector, tz -> ta_selectlen = sizeof "snmp" - 1);
tz -> ta_naddr = 0;
tz++;
#endif
for (vec++; ap = *vec; vec++) {
if (*ap == '-')
switch (*++ap) {
case 'd':
debug++;
continue;
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;
case 'r':
rflag = 1;
continue;
#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;
}
/* \f
*/
static envinit () {
int i,
sd;
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 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);
if (readobjects () == NOTOK)
adios (NULLCP, "readobjects: %s", PY_pepy);
readmib ();
readconfig ();
checkmib ();
initrap ();
if (fp = fopen ("/etc/snmpd.pid", "w")) {
(void) fprintf (fp, "%d\n", getpid ());
(void) fclose (fp);
}
advise (LLOG_NOTICE, NULLCP, "starting");
}
/* \f
CONFIG */
struct pair {
char *p_name; /* runcom directive */
IFP p_handler; /* dispatch */
};
int f_community (), f_logging (), f_variable ();
static struct pair pairs[] = {
"community", f_community,
"logging", f_logging,
"trap", f_community,
"variable", f_variable,
NULL
};
static readconfig () {
register char *cp;
char buffer[BUFSIZ],
line[BUFSIZ],
*vec[NVEC + NSLACK + 1];
register struct community *c;
register struct pair *p;
struct stat st;
FILE *fp;
CHead -> c_forw = CHead -> c_back = CHead;
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);
for (c = CHead -> c_forw; c != CHead; c = c -> c_forw)
if (c -> c_permission != COMM_TRAP)
break;
if (c == CHead) {
vec[0] = "community";
vec[1] = "public";
vec[2] = "readOnly";
vec[3] = NULL;
(void) f_community (vec);
}
}
/* \f
*/
static int f_community (vec)
char **vec;
{
int istrap;
register struct community *c;
register struct NSAPaddr *na;
istrap = lexequ (*vec++, "trap") == 0;
if ((c = (struct community *) calloc (1, sizeof *c)) == NULL
|| (c -> c_name = strdup (*vec)) == NULL)
adios (NULLCP, "out of memory");
vec++;
if (istrap
&& (c -> c_community = str2qb (c -> c_name, strlen (c -> c_name),
1)) == NULL)
adios (NULLCP, "out of memory");
na = &c -> c_addr;
if (*vec) {
#ifdef TCP
register struct hostent *hp;
#endif
struct TSAPaddr *ta;
#ifdef TCP
if (hp = gethostbystring (*vec)) {
struct sockaddr_in sin;
na -> na_type = NA_TCP;
na -> na_subnet = 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 (*vec)) && ta -> ta_naddr > 0) {
*na = ta -> ta_addrs[0]; /* struct copy */
}
else
adios (NULLCP, "unknown address \"%s\" for %s \"%s\"",
*vec, istrap ? "trap sink" : "community", c -> c_name);
if (istrap) {
if (na -> na_type != NA_TCP) {
advise (LLOG_EXCEPTIONS, NULLCP,
"traps are supported only over UDP");
return NOTOK;
}
#ifdef TCP
c -> c_sin.sin_port = na -> na_port ? na -> na_port : traport;
if ((hp = gethostbystring (na -> na_domain)) == NULL)
adios (NULLCP, "unknown host \"%s\" for trap sink \"%s\"",
na -> na_domain, c -> c_name);
c -> c_sin.sin_family = hp -> h_addrtype;
inaddr_copy (hp, &c -> c_sin);
#endif
}
vec++;
}
else {
if (istrap)
return NOTOK;
na -> na_type = NA_TCP;
na -> na_subnet = ts_comm_tcp_default;
(void) strcpy (na -> na_domain, "0.0.0.0");
}
if (*vec) {
if (istrap)
return NOTOK;
if (lexequ (*vec, "readOnly") == 0)
c -> c_permission = COMM_RDONLY;
else
if (lexequ (*vec, "readWrite") == 0)
c -> c_permission = COMM_RDWRITE;
vec++;
}
else
if (istrap)
c -> c_permission = COMM_TRAP;
insque (c, CHead -> c_back);
return OK;
}
/* \f
*/
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;
}
/* \f
*/
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;
}
/* \f
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