|
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